Revamping WSO2 API Manager Key Management Architecture around Open Standards

WSO2 API Manager is a complete solution for designing and publishing APIs, creating and managing a developer community, and for scalably routing API traffic. It leverages proven, production-ready integration, security, and governance components from the WSO2 Enterprise Service Bus, WSO2 Identity Server, and WSO2 Governance Registry. In addition, it leverages the WSO2 Business Activity Monitor for Big Data analytics, giving you instant insight into APIs behavior.

One of the limitation we had in API Manager so far is its tight integration with the WSO2 Identity Server. WSO2 Identity Server acts as the key manager, which issues and validates OAuth tokens.

With the revamped architecture (still under discussion) we plan to make all integration points with the key manager, extensible - so you can bring in your own OAuth authorizations server. And also - we will ship the product with standard extension points. These extension points are built around corresponding OAuth 2.0 profiles. In case, your authorization server deviates from the standard, you need to implement the KeyManager interface and plug in your own implementation.

Screen Shot 2014-08-27 at 12.08.49 AM.png 

API Publisher 

API Developer first logs-in to the API Publisher and creates an API with all the related metadata and publishes it to the API Store and the API Gateway.

API Publisher will also publish API metadata into the external authorization server via OAuth Resource Set Registration endpoint [1].

Sample Request:


"name": "Photo Album", 
"icon_uri": "http://www.example.com/icons/flower.png", 
"scopes": [ "http://photoz.example.com/dev/scopes/view", 
                  "http://photoz.example.com/dev/scopes/all" ], 
"type": "http://www.example.com/rsets/photoalbum" 


name REQUIRED. A human-readable string describing a set of one or more resources. This name MAY be used by the authorization server in its resource owner user interface for the resource owner.

icon_uri OPTIONAL. A URI for a graphic icon representing the resource set. The referenced icon MAY be used by the authorization server in its resource owner user interface for the resource owner.

scopes REQUIRED. An array providing the URI references of scope descriptions that are available for this resource set.

type OPTIONAL. A string uniquely identifying the semantics of the resource set. For example, if the resource set consists of a single resource that is an identity claim that leverages standardized claim semantics for "verified email address", the value of this property could be an identifying URI for this claim.

Sample Response:

HTTP/1.1 201 
Created Content-Type: application/json 
ETag: (matches "_rev" property in returned object) ... 

{ "status": "created", "_id": (id of created resource set), 
  "_rev": (ETag of created resource set) 


The objective of publishing the resources to the authorization server is to make it aware of the available resources and the scopes associated with them. An identity administrator can build the relationship between these scopes and the enterprise roles. Basically you can associate scopes with enterprise roles.

API Store 

Application Developer logs-in to the API Store and discovers the APIs he/she wants for his application and subscribes to those - and finally creates an application. Each application is uniquely identified by its client id. There are two ways to associate a client id with an application created in API Store.

1. Application developer brings in the client id.

Application developer creates a client id out-of-band with the authorization server, and associates the client id with the application he just created in the API Store. In this case, Dynamic Client Registration endpoint of the Authorization Serve is not used (No step 3 & 4).

2. API Store calls Dynamic Client Registration endpoint of the external Authorization Server.

Once the application is created by the application developer (by grouping a set of APIs) - API Store will call the Dynamic Client Registration endpoint of the authorization server.

Sample Request (Step 3):

POST /register HTTP/1.1 
Content-Type: application/json 
Accept: application/json 
Host: authz.server.com 


"client_name": "My Application”, 
"redirect_uris":[" https://client.org/callback","https://client.org/callback2 "], "token_endpoint_auth_method":"client_secret_basic", 
"grant_types": ["authorization_code" , "implicit"], 
"response_types": ["code" , "token"], 
"scope": ["sc1" , "sc2"], 


client_name: Human-readable name of the client to be presented to the user during authorization. If omitted, the authorization server MAY display the raw "client_id" value to the user instead. It is RECOMMENDED that clients always send this field.

client_uri: URL of a web page providing information about the client. If present, the server SHOULD display this URL to the end user in a clickable fashion. It is RECOMMENDED that clients always send this field.

 logo_uri: URL that references a logo for the client. If present, the server SHOULD display this image to the end user during approval. The value of this field MUST point to a valid image file.

scope :Space separated list of scope values that the client can use when requesting access tokens. The semantics of values in this list is service specific. If omitted, an authorization server MAY register a client with a default set of scopes.

grant_types: Array of OAuth 2.0 grant types that the client may use.

response_types: Array of the OAuth 2.0 response types that the client may use.

token_endpoint_auth_method: The requested authentication method for the token endpoint.

redirect_uris: Array of redirection URI values for use in redirect-based flows such as the authorization code and implicit flows.

Sample Response (Step 4):

HTTP/1.1 200 OK 
Content-Type: application/json 
Cache-Control: no-store 
Pragma: no-cache 


"client_id":"iuyiSgfgfhffgfh", 
"client_secret": "hkjhkiiu89hknhkjhuyjhk", 
"client_id_issued_at":2343276600, 
"client_secret_expires_at":2503286900, 
"redirect_uris":[" https://client.org/callback ", " https://client.org/callback2 "], 
"grant_types": "authorization_code", 
"token_endpoint_auth_method": "client_secret_basic"

OAuth Client Application 

This is outside the scope of the API Manager. The client application can talk to the external authorization server via any of the grant types it supports and obtain an access token [3]. The scope parameter is optional in all the token requests - when omitted by the client, the authorization server can associate a default scope with the access token. If no scopes used at all - then the API Gateway can do an authorization check based on other parameters associated with OAuth client, end user, resource and action.

If the client sends a set of scopes with the OAuth grant request, then these scopes will be meaningful to the authorization server only if we have published API metadata into the external authorization server via the OAuth Resource Set Registration endpoint - from the API Publisher. Based on the user's role and the scopes associated with role, authorization server can issue the access token, only for a subset of the scopes request by the OAuth client.

Client Credentials Grant Type Sample Request:

POST /token HTTP/1.1 
Host: server.example.com Authorization: Basic Base64Encode(Client ID:Client Secret) Content-Type: application/x-www-form-urlencoded 

grant_type=client_credentials 

Sample Response:

HTTP/1.1 200 OK 
Content-Type: application/json;charset=UTF-8 
Cache-Control: no-store Pragma: no-cache 


"access_token":"2YotnFZFEjr1zCsicMWpAA", 
"token_type":"example", 
"expires_in":3600, 
"example_parameter":"example_value" 


Resource Owner Password Grant Type Sample Request:

POST /token HTTP/1.1 Host: server.example.com 
Authorization: Basic Base64Encode(Client ID:Client Secret) 
Content-Type: application/x-www-form-urlencoded 

grant_type=password&username=johndoe&password=A3ddj3w

Sample Response:

HTTP/1.1 200 OK 
Content-Type: application/json;charset=UTF-8 
Cache-Control: no-store Pragma: no-cache 


"access_token":"2YotnFZFEjr1zCsicMWpAA", 
"token_type":"example", "expires_in":3600, 
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", 
"example_parameter":"example_value" 

API Gateway 

The API Gateway will intercept all the messages flowing between the OAuth client application and the API - and extract out the access token comes in the HTTP Authorization header. Once the access token is extracted out, API Gateway will call the Token Introspection endpoint[4] of the authorization server.

Sample Request:

POST /introspect HTTP/1.1
Host: authserver.example.com
Content-type: application/x-www-form-urlencoded
Accept: application/json
Authorization: Basic czZCaGRSa3F0Mzo3RmpmcDBaQnIxS3REUmJuZlZkbUl3

token=X3241Affw.4233-99JXJ

Sample Response:


"active": true, 
"client_id":"s6BhdRkqt3", 
"scope": "read write dolphin", 
"sub": "2309fj32kl", 
"user_id": "jdoe", 
"aud": "https://example.org/protected-resource/*", 
"iss": "https://authserver.example.com/" 


active REQUIRED. Boolean indicator of whether or not the presented token is currently active.

exp OPTIONAL. Integer timestamp, measured in the number of seconds since January 1 1970 UTC, indicating when this token will expire.

iat OPTIONAL. Integer timestamp, measured in the number of seconds since January 1 1970 UTC, indicating when this token was originally issued.

scope OPTIONAL. A space-separated list of strings representing the scopes associated with this token.

client_id REQUIRED. Client Identifier for the OAuth Client that requested this token.

sub OPTIONAL. Machine-readable identifier local to the AS of the Resource Owner who authorized this token.

user_id REQUIRED. Human-readable identifier for the user who authorized this token.

aud OPTIONAL. Service-specific string identifier or list of string identifiers representing the intended audience for this token.

iss OPTIONAL. String representing the issuer of this token.

token_type OPTIONAL. Type of the token as defined in OAuth 2.0

Once the API Gateway gets the token introspection response from the authorization server, it will check whether the client application (client id) has subscribed to the corresponding API and then also will validate the scope. API Gateway knows the required scopes for the API and the introspection response returns back the scopes associated with access token.

If everything is fine, API Gateway will generate a JWT and send it  to the downstream API. The generated JWT can optionally include user attributes as well. In that case API Gateway will  talk to the UserInfo endpoint of the authorization server.

Also - the API Gateway can simply pass-thru the access token as well - without validating the access token and its associated scopes. In that case API Gateway will only do throttling and monitoring.

Secured Endpoints

In this proposed revamped architecture, WSO2 API Manager has to talk to following endpoints exposed by the key manager.
  • Resource set registration
  • Dynamic client registration endpoint
  • Introspection endpoint
  • UserInfo endpoint
For the first three endpoints, the API Manager will just act as a trusted system. The corresponding KeyManager implementation should know how to authenticate to those endpoints. The OpenID Connect UserInfo endpoint will be invoked with the user provided access token, in run-time. This will work only if the corresponding access token has the privileges to read user's profile from the authorization server.

References

[1]: http://tools.ietf.org/html/draft-hardjono-oauth-resource-reg-02
[2]: http://tools.ietf.org/html/draft-ietf-oauth-dyn-reg-19
[3]: http://tools.ietf.org/html/rfc6749
[4]: http://tools.ietf.org/html/draft-richer-oauth-introspection-06