Authentication, Authorization and Accounting (AAA) Services

The Boron AAA services are based on the Apache Shiro Java Security Framework. The main configuration file for AAA is located at “etc/shiro.ini” relative to the ODL karaf home directory.

Terms And Definitions

Token
A claim of access to a group of resources on the controller
Domain
A group of resources, direct or indirect, physical, logical, or virtual, for the purpose of access control. ODL recommends using the default “sdn” domain in the Boron release.
User
A person who either owns or has access to a resource or group of resources on the controller
Role
Opaque representation of a set of permissions, which is merely a unique string as admin or guest
Credential
Proof of identity such as username and password, OTP, biometrics, or others
Client
A service or application that requires access to the controller
Claim
A data set of validated assertions regarding a user, e.g. the role, domain, name, etc.

How to enable AAA

AAA is enabled through installing the odl-aaa-shiro feature. odl-aaa-shiro is automatically installed as part of the odl-restconf offering.

How to disable AAA

Edit the “etc/shiro.ini” file and replace the following:

/** = authcBasic

with

/** = anon

Then restart the karaf process.

How application developers can leverage AAA to provide servlet security

In order to provide security to a servlet, add the following to the servlet’s web.xml file as the first filter definition:

<context-param>
  <param-name>shiroEnvironmentClass</param-name>
  <param-value>org.opendaylight.aaa.shiro.web.env.KarafIniWebEnvironment</param-value>
</context-param>

<listener>
    <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>

<filter>
    <filter-name>ShiroFilter</filter-name>
    <filter-class>org.opendaylight.aaa.shiro.filters.AAAShiroFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>AAAShiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Note

It is very important to place this AAAShiroFilter as the first javax.servlet.Filter, as Jersey applies Filters in the order they appear within web.xml. Placing the AAAShiroFilter first ensures incoming HTTP/HTTPS requests have proper credentials before any other filtering is attempted.

AAA Realms

AAA plugin utilizes realms to support pluggable authentication & authorization schemes. There are two parent types of realms:

  • AuthenticatingRealm
    • Provides no Authorization capability.
    • Users authenticated through this type of realm are treated equally.
  • AuthorizingRealm
    • AuthorizingRealm is a more sophisticated AuthenticatingRealm, which provides the additional mechanisms to distinguish users based on roles.
    • Useful for applications in which roles determine allowed cabilities.

ODL Contains Four Implementations

  • TokenAuthRealm
    • An AuthorizingRealm built to bridge the Shiro-based AAA service with the h2-based AAA implementation.
    • Exposes a RESTful web service to manipulate IdM policy on a per-node basis. If identical AAA policy is desired across a cluster, the backing data store must be synchronized using an out of band method.
    • A python script located at “etc/idmtool” is included to help manipulate data contained in the TokenAuthRealm.
    • Enabled out of the box.
  • ODLJndiLdapRealm
    • An AuthorizingRealm built to extract identity information from IdM data contained on an LDAP server.
    • Extracts group information from LDAP, which is translated into ODL roles.
    • Useful when federating against an existing LDAP server, in which only certain types of users should have certain access privileges.
    • Disabled out of the box.
  • ODLJndiLdapRealmAuthNOnly
    • The same as ODLJndiLdapRealm, except without role extraction. Thus, all LDAP users have equal authentication and authorization rights.
    • Disabled out of the box.
  • ActiveDirectoryRealm

Note

More than one Realm implementation can be specified. Realms are attempted in order until authentication succeeds or all realm sources are exhausted.

TokenAuthRealm Configuration

TokenAuthRealm stores IdM data in an h2 database on each node. Thus, configuration of a cluster currently requires configuring the desired IdM policy on each node. There are two supported methods to manipulate the TokenAuthRealm IdM configuration:

  • idmtool Configuration
  • RESTful Web Service Configuration

idmtool Configuration

A utility script located at “etc/idmtool” is used to manipulate the TokenAuthRealm IdM policy. idmtool assumes a single domain (sdn), since multiple domains are not leveraged in the Boron release. General usage information for idmtool is derived through issuing the following command:

$ python etc/idmtool -h
usage: idmtool [-h] [--target-host TARGET_HOST]
               user
               {list-users,add-user,change-password,delete-user,list-domains,list-roles,add-role,delete-role,add-grant,get-grants,delete-grant}
               ...

positional arguments:
  user                  username for BSC node
  {list-users,add-user,change-password,delete-user,list-domains,list-roles,add-role,delete-role,add-grant,get-grants,delete-grant}
                        sub-command help
    list-users          list all users
    add-user            add a user
    change-password     change a password
    delete-user         delete a user
    list-domains        list all domains
    list-roles          list all roles
    add-role            add a role
    delete-role         delete a role
    add-grant           add a grant
    get-grants          get grants for userid on sdn
    delete-grant        delete a grant

optional arguments:
  -h, --help            show this help message and exit
  --target-host TARGET_HOST
                        target host node
Add a user
python etc/idmtool admin add-user newUser
Password:
Enter new password:
Re-enter password:
add_user(admin)

command succeeded!

json:
{
    "description": "",
    "domainid": "sdn",
    "email": "",
    "enabled": true,
    "name": "newUser",
    "password": "**********",
    "salt": "**********",
    "userid": "newUser@sdn"
}

Note

AAA redacts the password and salt fields for security purposes.

Delete a user
$ python etc/idmtool admin delete-user newUser@sdn
Password:
delete_user(newUser@sdn)

command succeeded!
List all users
$ python etc/idmtool admin list-users
Password:
list_users

command succeeded!

json:
{
    "users": [
        {
            "description": "user user",
            "domainid": "sdn",
            "email": "",
            "enabled": true,
            "name": "user",
            "password": "**********",
            "salt": "**********",
            "userid": "user@sdn"
        },
        {
            "description": "admin user",
            "domainid": "sdn",
            "email": "",
            "enabled": true,
            "name": "admin",
            "password": "**********",
            "salt": "**********",
            "userid": "admin@sdn"
        }
    ]
}
Change a user’s password
$ python etc/idmtool admin change-password admin@sdn
Password:
Enter new password:
Re-enter password:
change_password(admin)

command succeeded!

json:
{
    "description": "admin user",
    "domainid": "sdn",
    "email": "",
    "enabled": true,
    "name": "admin",
    "password": "**********",
    "salt": "**********",
    "userid": "admin@sdn"
}
Add a role
$ python etc/idmtool admin add-role network-admin
Password:
add_role(network-admin)

command succeeded!

json:
{
    "description": "",
    "domainid": "sdn",
    "name": "network-admin",
    "roleid": "network-admin@sdn"
}
Delete a role
$ python etc/idmtool admin delete-role network-admin@sdn
Password:
delete_role(network-admin@sdn)

command succeeded!
List all roles
$ python etc/idmtool admin list-roles
Password:
list_roles

command succeeded!

json:
{
    "roles": [
        {
            "description": "a role for admins",
            "domainid": "sdn",
            "name": "admin",
            "roleid": "admin@sdn"
        },
        {
            "description": "a role for users",
            "domainid": "sdn",
            "name": "user",
            "roleid": "user@sdn"
        }
    ]
}
List all domains
$ python etc/idmtool admin list-domains
Password:
list_domains

command succeeded!

json:
{
    "domains": [
        {
            "description": "default odl sdn domain",
            "domainid": "sdn",
            "enabled": true,
            "name": "sdn"
        }
    ]
}
Add a grant
$ python etc/idmtool admin add-grant user@sdn admin@sdn
Password:
add_grant(userid=user@sdn,roleid=admin@sdn)

command succeeded!

json:
{
    "domainid": "sdn",
    "grantid": "user@sdn@admin@sdn@sdn",
    "roleid": "admin@sdn",
    "userid": "user@sdn"
}
Delete a grant
$ python etc/idmtool admin delete-grant user@sdn admin@sdn
Password:
http://localhost:8181/auth/v1/domains/sdn/users/user@sdn/roles/admin@sdn
delete_grant(userid=user@sdn,roleid=admin@sdn)

command succeeded!
Get grants for a user
python etc/idmtool admin get-grants admin@sdn
Password:
get_grants(admin@sdn)

command succeeded!

json:
{
    "roles": [
        {
            "description": "a role for users",
            "domainid": "sdn",
            "name": "user",
            "roleid": "user@sdn"
        },
        {
            "description": "a role for admins",
            "domainid": "sdn",
            "name": "admin",
            "roleid": "admin@sdn"
        }
    ]
}

RESTful Web Service

The TokenAuthRealm IdM policy is fully configurable through a RESTful web service. Full documentation for manipulating AAA IdM data is located online (https://wiki.opendaylight.org/images/0/00/AAA_Test_Plan.docx), and a few examples are included in this guide:

Get All Users
curl -u admin:admin http://localhost:8181/auth/v1/users
OUTPUT:
{
    "users": [
        {
            "description": "user user",
            "domainid": "sdn",
            "email": "",
            "enabled": true,
            "name": "user",
            "password": "**********",
            "salt": "**********",
            "userid": "user@sdn"
        },
        {
            "description": "admin user",
            "domainid": "sdn",
            "email": "",
            "enabled": true,
            "name": "admin",
            "password": "**********",
            "salt": "**********",
            "userid": "admin@sdn"
        }
    ]
}
Create a User
curl -u admin:admin -X POST -H "Content-Type: application/json" --data-binary @./user.json http://localhost:8181/auth/v1/users
PAYLOAD:
{
    "name": "ryan",
    "userid": "ryan@sdn",
    "password": "ryan",
    "domainid": "sdn",
    "description": "Ryan's User Account",
    "email": "ryandgoulding@gmail.com"
}

OUTPUT:
{
    "userid":"ryan@sdn",
    "name":"ryan",
    "description":"Ryan's User Account",
    "enabled":true,
    "email":"ryandgoulding@gmail.com",
    "password":"**********",
    "salt":"**********",
    "domainid":"sdn"
}
Create an OAuth2 Token For Admin Scoped to SDN
curl -d 'grant_type=password&username=admin&password=a&scope=sdn' http://localhost:8181/oauth2/token

OUTPUT:
{
    "expires_in":3600,
    "token_type":"Bearer",
    "access_token":"5a615fbc-bcad-3759-95f4-ad97e831c730"
}
Use an OAuth2 Token
curl -H "Authorization: Bearer 5a615fbc-bcad-3759-95f4-ad97e831c730" http://localhost:8181/auth/v1/domains
{
    "domains":
    [
        {
            "domainid":"sdn",
            "name":"sdn”,
            "description":"default odl sdn domain",
            "enabled":true
        }
    ]
}

ODLJndiLdapRealm Configuration

LDAP integration is provided in order to externalize identity management. To configure LDAP parameters, modify “etc/shiro.ini” parameters to include the ODLJndiLdapRealm:

# ODL provides a few LDAP implementations, which are disabled out of the box.
# ODLJndiLdapRealm includes authorization functionality based on LDAP elements
# extracted through and LDAP search.  This requires a bit of knowledge about
# how your LDAP system is setup.  An example is provided below:
ldapRealm = org.opendaylight.aaa.shiro.realm.ODLJndiLdapRealm
ldapRealm.userDnTemplate = uid={0},ou=People,dc=DOMAIN,dc=TLD
ldapRealm.contextFactory.url = ldap://<URL>:389
ldapRealm.searchBase = dc=DOMAIN,dc=TLD
ldapRealm.ldapAttributeForComparison = objectClass
ldapRealm.groupRolesMap = "Person":"admin"
# ...
# further down in the file...
# Stacked realm configuration;  realms are round-robbined until authentication succeeds or realm sources are exhausted.
securityManager.realms = $tokenAuthRealm, $ldapRealm

This configuration allows federation with an external LDAP server, and the user’s ODL role parameters are mapped to corresponding LDAP attributes as specified by the groupRolesMap. Thus, an LDAP operator can provision attributes for LDAP users that support different ODL role structures.

ODLJndiLdapRealmAuthNOnly Configuration

Edit the “etc/shiro.ini” file and modify the following:

ldapRealm = org.opendaylight.aaa.shiro.realm.ODLJndiLdapRealm
ldapRealm.userDnTemplate = uid={0},ou=People,dc=DOMAIN,dc=TLD
ldapRealm.contextFactory.url = ldap://<URL>:389
# ...
# further down in the file...
# Stacked realm configuration;  realms are round-robbined until authentication succeeds or realm sources are exhausted.
securityManager.realms = $tokenAuthRealm, $ldapRealm

This is useful for setups where all LDAP users are allowed equal access.

Token Store Configuration Parameters

Edit the file “etc/opendaylight/karaf/08-authn-config.xml” and edit the following: .timeToLive: Configure the maximum time, in milliseconds, that tokens are to be cached. Default is 360000. Save the file.

Authorization Configuration

Shiro-Based Authorization

OpenDaylight AAA has support for Role Based Access Control based on the Apache Shiro permissions system. Configuration of the authorization system is done offline; authorization currently cannot be configured after the controller is started. Thus, Authorization in this release is aimed towards supporting coarse-grained security policies, with the aim to provide more robust configuration capabilities in the future. Shiro-based Authorization is documented on the Apache Shiro website (http://shiro.apache.org/web.html#Web-%7B%7B%5Curls%5C%7D%7D).

Enable “admin” Role Based Access to the IdMLight RESTful web service

Edit the “etc/shiro.ini” configuration file and add “/auth/v1/= authcBasic, roles[admin]” above the line “/ = authcBasic” within the “urls” section.

/auth/v1/** = authcBasic, roles[admin]
/** = authcBasic

This will restrict the idmlight rest endpoints so that a grant for admin role must be present for the requesting user.

Note

The ordering of the authorization rules above is important!

AuthZ Broker Facade

ODL includes an experimental Authorization Broker Facade, which allows finer grained access control for REST endpoints. Since this feature was not well tested in the Boron release, it is recommended to use the Shiro-based mechanism instead, and rely on the Authorization Broker Facade for POC use only.

AuthZ Broker Facade Feature Installation

To install the authorization broker facade, please issue the following command in the karaf shell:

feature:install odl-restconf odl-aaa-authz

Add an Authorization Rule

The following shows how one might go about securing the controller so that only admins can access restconf.

curl -u admin:admin -H “Content-Type: application/xml” --data-binary @./rule.json http://localhost:8181/restconf/config/authorization-schema:simple-authorization/policies/RestConfService/
cat ./rule.json
{
    "policies": {
        "resource": "*",
        "service":"RestConfService",
        "role": "admin"
    }
}

Accounting Configuration

All AAA logging is output to the standard karaf.log file.

log:set TRACE org.opendaylight.aaa

This command enables the most verbose level of logging for AAA components.