Wednesday, November 30, 2016

Securing API access in AdroitLogic Management API

Securing the API access with JWT based Authentication

Management server REST API requests can be secured with JWT authentication. By default authentication is disabled and you can enable it by changing the ''console.auth.jwt.on" property to "true" in management.properties file.   
 
Following diagram shows the main authentication flow of application.


1. Receive username, password from web interface on user login
2. Authenticate the user from shiro realm (Supported file based user store realm)
3. Successful authentication by the ldap server
4. Create a JWT token including the following claims
    - username, user_permissions, user_ldap_groups, issuer (configurable), expiration_date (configurable)
5. Signs this JWS token with the specified Message Authentication Code (MAC) signer using a shared key
6. Encrypt the token with Base64 with a hashkey
7. Save the encrypted token over username in in-memory cache(This is to avoid disk access on later for token validation)
8. Return the encrypted token to the user
After user get a valid token at the first login, he can use the same token in next logins until the token expires. Following diagram shows the authentication flow when user request come with a JWT token.

 


 

1. Request is filtered by JWTAuthorizationFilter.
2. JWT token extracted from AUTHORIZATION header
3. Verify the token whether the token is expired and similar to the token issued by the application earlier. (first compares with token saved in the cache)
4. Decrypt the token
5. Token values are fed to AuthDataContainer object (these information is used over the application for authorization purpose and this is valid only for a one session)
6. Authentication success returned to the user

Following table explains how the token request and a sample api call (get request) is done.

Authentication
Request
Response
Token request
POST /management/auth HTTP/1.0
Connection: close
Content-Length: 42
Content-Type: application/json; charset=UTF-8
Host: localhost:8011
User-Agent: <>




{"username":"admin","password":"password"}
HTTP/1.1 200 OK
Set-Cookie: JSESSIONID=1qj32rt2mppjfjhnah8zre3st;Path=/
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Set-Cookie: rememberMe=deleteMe; Path=/; Max-Age=0; Expires=Tue, 29-Nov-2016 06:55:02 GMT
Content-Type: application/json
Content-Length: 982
Server: Jetty(9.2.3.v20140905)

 {"msg":"bDd6RllXSX……..."}
API call (GET)
GET /management/project HTTP/1.0
Connection: close
Authorization: bDd6RllXSX……...
Host: localhost:8011
User-Agent: <>


HTTP/1.1 200 OK
Set-Cookie: JSESSIONID=17n23j1souoiraqsompt9jah5;Path=/
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Set-Cookie: rememberMe=deleteMe; Path=/; Max-Age=0; Expires=Tue, 29-Nov-2016 09:16:21 GMT
Content-Type: application/json
Content-Length: 164
Server: Jetty(9.2.3.v20140905)

<response body...>

Security related properties in management.properties file


Property
Description
console.auth.jwt.on
‘True’ or ‘false’ to enable or disable api security
jwt.lifetime
JWT token lifetime in milliseconds
console.auth.url
Authentication request URL
console.auth.unauthorized
Path to direct for unauthorized requests
shiro.users
Users and password file location. Each user need to be added in a new line with the format <user><SPACE><password>
shiro.permissions
Users and permission file location. Each user permission need be added in a new line with the format ‘<username><SPACE><comma separated permissions>’
jwt.encryption.key
JWT token encryption key
jwt.shared.key
JWT shared key

1 comment: