You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 10 Next »

Motivation

  • get rid of the insecure basic authentication of opendaylight for Restconf
  • instead implement JsonWebToken(JWT) authorization
    • JWT is stateless because its signed
    • so roles can be put inside of the token and the token only has to be verified (checked signature) to get the roles of the user)

Problems

  • Opendaylight AAA project for aluminium-SR1 is only supporting authorization header starting with "Basic" and JWT is a Bearer token
  • So we had to patch the org.opendaylight.aaa:aaa-shiro:0.12.1 bundle with
    • some backported classes from org.apache.shiro:shiro-core:1.7 package
    • two modifications on the Authenticator to Accept also Bearer tokens
  • we realized that an entry in aaa-app-config.xml like
    <urls>
        <pair-key>/**</pair-key>
        <pair-value>authcBasic, roles["admin,provision"]</pair-value>
    </urls>

means that the user which wants to access this url pattern needs to have both roles, which does not really make sense. Therefor we also implemented a so called AnyRolesAuthenticationFilter which accepts the connection if one of the given roles matches.


OAuth Provider bundle

API

requestparamsresponsedescription
GET /oauth/providers
OAuthProvider arraylist of configured identity providers
GET /oauth/redirect

code={}&state={}

or

session_state={}

or

token={}

TokenResponsecalled by the 301 Response from the identity provider
POST /oauth/loginusername={}&password={}TokenResponse

Environment Vars

envdefault valuedescription
TOKEN_SECRETsecretkey to sign the token
TOKEN_ISSUERONAP SDNC
HOST_URLnull => autodetectedimportant for reverse proxy use case
ODLUX_REDIRECT_URI/odlux/index.html#/oauth?token=OAuth redirect will be responded
SUPPORT_ODLUSERStruelogin interface enabled for internal odl configured users


Dataflow example

for Login with external Identity Provider (KeyCloak)


User User GUI GUI SDNC SDNC OAUthProvider OAUthProvider 1GET /oauth/providers 2providers array 3Select OAuth provider 4/loginForm with params 5loginForm 6fill login form 7POST /login with credentials 8[301] to redirectURI 9GET /oauth/redirect with params 10POST /oauth2/token with params 11OAuthToken with roles 12create odl bearer token with with roles 13odl bearer token

2:

[{
  "id":"keycloak",
  "title":"OSNL Keycloak Provider",
  "loginUrl":"http://10.20.11.160:8080/auth/realms/onap/protocol/openid-connect/auth?client_id=odlux.app&response_type=code&scope=openid&redirect_uri=http%3A%2F%10.20.11.159%3A8181%2Foauth%2Fredirect%2Fkeycloak"
}]

8:

301 Location: http://10.20.11.159:8181/oauth/redirect/keycloak?state=odlux.app&code=4e4b717f-4a23-4f75-8bf1-76514f4b65dc.b0270d58-d281-4533-910f-19cb938ea189.dbd662ad-e959-44c9-bd18-859ca0142927

10:

POST /auth/realms/onap/protocol/openid-connect/token
grant_type: "authorization_code"
code: "4e4b717f-4a23-4f75-8bf1-76514f4b65dc.b0270d58-d281-4533-910f-19cb938ea189.dbd662ad-e959-44c9-bd18-859ca0142927"
client_id: "odlux.app"
client_secret: "5da4ea3d-8cc9-4669-bd7e-3ecb91d120cd"
redirect_uri: "http://10.20.11.159:8181/oauth/redirect"

11:

{
    "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJkbWFSWXRkaHFkVXFDV2lmRWdNRHFBcWVBcU8tMnFoTDBjdnByelRGdWRRIn0.eyJleHAiOjE2MTExMzU5MjEsImlhdCI6MTYxMTEzNDEyMSwiYXV0aF90aW1lIjoxNjExMTM0MDkxLCJqdGkiOiIzYzFlZmMzZi1lMjFiLTQ3MzktYTY1YS1jNjY1M2ZhOGRjNTQiLCJpc3MiOiJodHRwOi8vMTAuMjAuMTEuMTYwOjgwODAvYXV0aC9yZWFsbXMvb25hcCIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiI0NDZhMjRiYy1kOGEwLTQzZGQtYWZhNS1lNTZlZWQ3NWRlYjgiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJvZGx1eC5hcHAiLCJzZXNzaW9uX3N0YXRlIjoiMTI5YjRhNjMtNzBhMS00MjFmLWEzM2YtOWFjZDkyZTIzM2ZmIiwiYWNyIjoiMSIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJwcm92aXNpb24iLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwibmFtZSI6Ikx1a2UgU2t5d2Fsa2VyIiwicHJlZmVycmVkX3VzZXJuYW1lIjoibHVrZS5za3l3YWxrZXIiLCJnaXZlbl9uYW1lIjoiTHVrZSIsImZhbWlseV9uYW1lIjoiU2t5d2Fsa2VyIiwiZW1haWwiOiJsdWtlLnNreXdhbGtlckBzZG5yLm9uYXAub3JnIn0.tn2NrEGYLRq1u0DkqxD2iDM72hFrDBPGA_q23S-htiRH113yt14a0CzJxU9El0YDobbzog9xm0ELbx6W4jYsGguMABqIi4W5wtTqfbaCh7gmF208CqNpwzA7nG2palMLbBPpmGXiagUm4qLWQxrBP_VOaeW_kK0VHLaiTRJ-4vHuOXSNPYEDQZNCI2QCJQS_dn83K_JI4ecBHl8UeHFLB65BqmocpDHUvf2h835xuNFFQpXJWMcPM_j_FmFQeOSUDM4HmqgdVU9_b4APnDEVFiUezQdoEOfEYNsNlhCoXlaEEn2tCZfEkZ7k72DlhqJMQzomdaGKPk2g8XhKJNwMJg",
    "expires_in": 1800,
    "refresh_expires_in": 1800,
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJhOGUzMDUwZS0wZmQxLTRjYjQtYjRiZS1jMDVlOGY4OGJhZGUifQ.eyJleHAiOjE2MTExMzU5MjEsImlhdCI6MTYxMTEzNDEyMSwianRpIjoiZmZiYWE3NDktZGVkNi00ZWMzLWI4MjYtYTI4NWY0ODY1ZGI0IiwiaXNzIjoiaHR0cDovLzEwLjIwLjExLjE2MDo4MDgwL2F1dGgvcmVhbG1zL29uYXAiLCJhdWQiOiJodHRwOi8vMTAuMjAuMTEuMTYwOjgwODAvYXV0aC9yZWFsbXMvb25hcCIsInN1YiI6IjQ0NmEyNGJjLWQ4YTAtNDNkZC1hZmE1LWU1NmVlZDc1ZGViOCIsInR5cCI6IlJlZnJlc2giLCJhenAiOiJvZGx1eC5hcHAiLCJzZXNzaW9uX3N0YXRlIjoiMTI5YjRhNjMtNzBhMS00MjFmLWEzM2YtOWFjZDkyZTIzM2ZmIiwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSBlbWFpbCJ9.mt9VHtiBZycHcEuVCOZVjjtyoOGYNaDVvtcA1NPScIQ",
    "token_type": "bearer",
    "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJkbWFSWXRkaHFkVXFDV2lmRWdNRHFBcWVBcU8tMnFoTDBjdnByelRGdWRRIn0.eyJleHAiOjE2MTExMzU5MjEsImlhdCI6MTYxMTEzNDEyMSwiYXV0aF90aW1lIjoxNjExMTM0MDkxLCJqdGkiOiJjZjUzZTc0ZC1kYjZiLTQ4YTUtODkyOS1jYzU3YjY3YjAxN2QiLCJpc3MiOiJodHRwOi8vMTAuMjAuMTEuMTYwOjgwODAvYXV0aC9yZWFsbXMvb25hcCIsImF1ZCI6Im9kbHV4LmFwcCIsInN1YiI6IjQ0NmEyNGJjLWQ4YTAtNDNkZC1hZmE1LWU1NmVlZDc1ZGViOCIsInR5cCI6IklEIiwiYXpwIjoib2RsdXguYXBwIiwic2Vzc2lvbl9zdGF0ZSI6IjEyOWI0YTYzLTcwYTEtNDIxZi1hMzNmLTlhY2Q5MmUyMzNmZiIsImF0X2hhc2giOiJSUXdDclpkQmFKV0VFdmxsRVNxRjV3IiwiYWNyIjoiMSIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwibmFtZSI6Ikx1a2UgU2t5d2Fsa2VyIiwicHJlZmVycmVkX3VzZXJuYW1lIjoibHVrZS5za3l3YWxrZXIiLCJnaXZlbl9uYW1lIjoiTHVrZSIsImZhbWlseV9uYW1lIjoiU2t5d2Fsa2VyIiwiZW1haWwiOiJsdWtlLnNreXdhbGtlckBzZG5yLm9uYXAub3JnIn0.rueTNrnvRa4PMo7NS8l4xxRhhNiGzXLmtcUeyWnj3AjFaUoNKuS9l85K3KjRT3zjq494YsepIGuK33I20rvFwDLclcJNHuumAgBnR5dRBi5fLhm7x8YkebhdTHPiYL4hfygpZ7APN1PtcDZnb-uEjjT-RAtjnfk3r-oP6CtqWzI5MjOPnf5HaEwWpkuTjmJf3kyyf_pdhhVkgTwuC-kD8iMjyRIzuZJxVwWVA3S43eL0R7MaIDlpJrOp9EBRfMlObAypc1bLtKwopT0sBla1CM9GmUU2ZYbQb79-hey0rd7CWx1uBkZUxt5myiExBm3pI46boXLP7dzjzxHUKg0m-A",
    "not-before-policy": 1611134054,
    "session_state": "129b4a63-70a1-421f-a33f-9acd92e233ff",
    "scope": "openid profile email"
}

which can be decoded to:

{
  "exp": 1611135921,
  "iat": 1611134121,
  "auth_time": 1611134091,
  "jti": "3c1efc3f-e21b-4739-a65a-c6653fa8dc54",
  "iss": "http://10.20.11.160:8080/auth/realms/onap",
  "aud": "account",
  "sub": "446a24bc-d8a0-43dd-afa5-e56eed75deb8",
  "typ": "Bearer",
  "azp": "odlux.app",
  "session_state": "129b4a63-70a1-421f-a33f-9acd92e233ff",
  "acr": "1",
  "realm_access": {
    "roles": [
      "provision",
      "offline_access",
      "uma_authorization"
    ]
  },
  "resource_access": {
    "account": {
      "roles": [
        "manage-account",
        "manage-account-links",
        "view-profile"
      ]
    }
  },
  "scope": "openid profile email",
  "email_verified": false,
  "name": "Luke Skywalker",
  "preferred_username": "luke.skywalker",
  "given_name": "Luke",
  "family_name": "Skywalker",
  "email": "luke.skywalker@sdnr.onap.org"
}

where /real_access/roles are the important ones for us which were configured in the keycloak backend. 
Hint: offline_access and uma_authorization are built-in keycloak roles. These ones are filtered by oauth-provider bundle. So delivered role in this case is only provision.

The Opendaylight Roles access problem

As described on top we found out that an entry in aaa-app-config.xml like

    <urls>
        <pair-key>/**</pair-key>
        <pair-value>authcBasic, roles["admin,provision"]</pair-value>
    </urls>

results in a restriction for the configured url that the user has to be in both rules. That's why we implement a new Filter AnyRoleHttpAuthenticationFilter. That means if you enable it for a url you just have to be in at least one of this groups to get access.

    <main>
        <pair-key>anyroles</pair-key>
        <pair-value>org.opendaylight.aaa.shiro.filters.AnyRoleHttpAuthenticationFilter</pair-value>
    </main>

So usage changes to: 

    <urls>
        <pair-key>/**</pair-key>
        <pair-value>authcBasic, anyroles["admin,provision"]</pair-value>
    </urls>
  • No labels