Oauth2 Mobile Client for NetIQ Access Manager 4.1 using Implicit Flow

Oauth2 Mobile Client for NetIQ Access Manager 4.1 using Implicit Flow

Author: Sureshkumar Thangavel



Introduction


This article shows how to write a sample mobile application utilizing Oauth2.0 Implicit Grant to get an access token and ID token. Also, this shows how to get a user's claim information using UserInfo endpoint of OpenId Connect Core 1.0 protocol.

Dependencies


This solution uses the following libraries. Use appropriate build dependencies format for your project.



















































LibraryLanguageVersionDescription
google-oauth-clientJava1.20.0For using Oauth2 Implicit Grant
jackson-coreJava2.5.3For JSON Parsing
jackson- databindJava2.5.3For JSON Parsing
jackson- annotationsJava2.5.3For JSON Parsing
google-http-clientJava1.20.0For HTTP Headless Client
google-http-client-jackson2Java1.20.0For HTTP Headless Client
Jose4jJava0.4.1For OpenID Connect Json Processing and JWT handling

 

If you are developing android application using Android studio with Gradle, you can put the following in your app/build.gradle.
android {
compileSdkVersion 21
buildToolsVersion "21.1.2"

packagingOptions {
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE'
}

defaultConfig {
applicationId "mobile.sample.oauth.nam.netiq.com.nam_aws_sample"
minSdkVersion 15
targetSdkVersion 21
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])

compile 'com.android.support:appcompat-v7:22.0.0'
compile 'com.amazonaws:aws-android-sdk-cognito:2.2.1'
compile 'com.google.oauth-client:google-oauth-client:1.20.0'
compile 'com.fasterxml.jackson.core:jackson-core:2.5.3'
compile 'com.fasterxml.jackson.core:jackson-databind:2.5.3'
compile 'com.fasterxml.jackson.core:jackson-annotations:2.5.3'
compile 'com.google.http-client:google-http-client:1.20.0'
compile 'com.google.http-client:google-http-client-jackson2:1.20.0'
compile 'org.bitbucket.b_c:jose4j:0.4.1'

}

General Steps involved in Developing and Deploying Oauth2 enabled applications


 

For general overview of how to develop and deploy Oauth2 Applications using NetIQ Access Manager, refer this link.

Registering Client Application with NetIQ Access Manager


 

Refer the NetIQ Access Manger 4.1 Documentation for how to register a client application. The screen shot is given below.

 


  1. Client Name: Implicit Sample




  2. Client Type: Native




  3. Redirect URI: x-nam-aws-sample://aws




  4. Grants Required: Implicit




  5. Token Types: ID Token, Access Token




  6. ID Token Signed Response Algorith: RS256




  7. ID Token Encrypted Response Algorithm: None




Leave the rest of the fields empty.


 

client1

client2

Getting ID Token and Access Token


 

To get ID Token and Access Token, the client application has to invoke a http request with necessary request parameter for Implicit Grant to Authorization Endpoint.

Getting Authorization Endpoint Locations


 

NetIQ Access Manager 4.1 implements OpenID Connect Core 1.0 Service Discovery mechanism with metadata. You just need to ask the user where the Identity Provider is hosted and you can discover all details about the Identity Server Oauth2 capabilities from this Metadata.

aws-login

And, you need to automatically append the path and scheme, to match like “https://nam.com/nidp/oauth/nam/.


The following piece of code invokes the metadata by appending “.well-known/openid-configuration” path to the above created url. This is a standard way to get the metadata. This converts the response into a Map with keys mapped to the Keys of Json object returned from metadata url.



        private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
private static final JsonFactory JSON_FACTORY = new JacksonFactory();

/*
* gets resolver object from openid connect metadata for later verification
*/
private VerificationKeyResolver getVerificationKey(Map jsonMetadata) throws IOException, JoseException {
HttpsJwks httpsJwks = new HttpsJwks((String) jsonMetadata.get("jwks_uri"));
List<JsonWebKey> keys = httpsJwks.getJsonWebKeys();
JwksVerificationKeyResolver resolver = new JwksVerificationKeyResolver(keys);
return resolver;
}

/*
* gets openid connect metadata from given well known url. Save the metadata and key
* in a singleton for later access
*/
private Map getOpenIDMetadata(String host) throws IOException, JoseException {
HttpRequest req = HTTP_TRANSPORT.createRequestFactory()
.buildGetRequest(new GenericUrl(host + ".well-known/openid-configuration"))
.setParser(new JsonObjectParser(JSON_FACTORY));
HttpResponse resp = req.execute();
Map metadata = resp.parseAs(Map.class);
Singleton.getInstance().setMetadata(metadata);
Singleton.getInstance().setVerificationKey(getVerificationKey(metadata));
return metadata;
}

Using the returned object, you can get the necessary endpoints as below.



	String authz_endpoint = (String) jsonMetadata.get("authorization_endpoint");

Forming Request URL for Implicit Grant


Next step involves way to form the URL so that the URL can be given to a browser to launch. The browser launches the URL and authenticates the user. If the user is not already authenticated with browser, the Identity Server redirects the User to login page. After the user is logged in, the server will redirect to a native application scheme so that control is transferred back to the native application from browser.

 

The following code snippet creates the URL to be launched.
        private String getUrlToLaunch(String host) throws IOException {
Map jsonMetadata = getOpenIDMetadata(host);
String authz_endpoint = (String) jsonMetadata.get("authorization_endpoint");
BrowserClientRequestUrl bc = new BrowserClientRequestUrl(authz_endpoint, Singleton.getInstance().getClientID())
.setResponseTypes(Arrays.asList("token", "id_token"))
.setRedirectUri("x-nam-aws-sample://aws")
.setScopes(Arrays.asList("openid", "email", "profile"))
.set("nonce", new BigInteger(130, new Random()).toString(32))
.setState("/first");
String url = bc.build();
Log.d(LOG_ID, url);
return url;
}

With the returned URL, the stock browser should be opened. An example for Android is given below, you can do similar thing for iOS.
        String url = getUrlToLaunch(host);
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(browserIntent);

nam-login

After login, the Identity Server will redirect browser to the requested url “x-nam-aws-sample://aws”. This scheme is registered with the mobile device, hence the system will load the application with activity configured for the scheme. The URL will also contain the token and id_token in fragment.

Extracting Tokens from fragment


The token and id_token should be extracted from the URL. The URL is passed in different ways according to the mobile device. For Android, the URL is passed as Intent's Data. This can be extracted as below.

 
        Intent intent = getIntent();
Uri data = intent.getData();

String id_token = null;
String token = null;
if (data != null && data.getFragment() != null) {
Uri uri = Uri.parse("x-nam-if-sample://test?" + data.getFragment()); // convert fragment to query string for easy parsing
id_token = uri.getQueryParameter("id_token");
token = uri.getQueryParameter("access_token");
}


In our example, the same Activity which launched the browser is itself configured for the scheme. Hence, during loading of the activity, we parse the data and save the token and id_token in preference or can pass the token to other activities.

Validating ID Token


Id Token should be validated so that the token is not issued from a vulnerable host machine. Using jose4j library, the ID Token can be parsed and validated as below.

 
        String subject = "unknown";
try {
// https://bitbucket.org/b_c/jose4j/wiki/JWT%20Examples
JwtConsumer jwtb = new JwtConsumerBuilder()
.setVerificationKeyResolver(Singleton.getInstance().getVerificationKey())
.setExpectedIssuer(false, Singleton.getInstance().getIssuer())
.setExpectedAudience(Singleton.getInstance().getClientID())
.build();
JwtContext jwtc = jwtb.process(idToken);
JwtClaims claims = jwtc.getJwtClaims();
subject = claims.getSubject();
} catch (InvalidJwtException e) {
e.printStackTrace();
} catch (MalformedClaimException e) {
e.printStackTrace();
}

if (subject == null) {
// invalid token
}

Getting additional User claims


NetIQ Access Manager 4.1 release does not send all claims through ID Token. Instead, the client has to make another http request to UserInfo endpoint to get the claims that user authorized through scope. If user has authorized scopes “email”, then the UserInfo endpoint request will send email_id in the returned claim. To invoke a userinfo endpoint, use the following code snippet. This email and other claims will be used later for storing or displaying user specific information in your client application.

 
                String email = null;
try {
String userinfo_endpoint = Singleton.getInstance().getUserInfoEndpoint();
Log.d(LOG_ID, "invoking userinfo with " + token + ": endpoint " + userinfo_endpoint);
HttpResponse resp = HTTP_TRANSPORT.createRequestFactory(new Credential(BearerToken.authorizationHeaderAccessMethod()).setAccessToken(token))
.buildGetRequest(new GenericUrl(userinfo_endpoint))
.setParser(new JsonObjectParser(JSON_FACTORY))
.execute();
Map userinfo = resp.parseAs(Map.class);
email = (String) userinfo.get("email");
Log.d(LOG_ID, "got email " + email);
} catch (IOException e) {
e.printStackTrace();
}

Invoking RESTful APIs (Resource Servers)


Now we have got Access Token, we can use it to invoke any Resource Servers similar to the one above for getting UserInfo claims of the user. ID Token is useful to client application for verifying the Identity by validating the signature and other authentication parameters like issuer, audience and authentication time. Most resource servers will only require Access Token, whereas ID Token is useful for passing to additional Identity Providers to get another kind of Identity Tokens. For example, Amazon Web Service APIs accept only Amazon issued keys. But, Amazon Idenity Provider exposes an API to exchange OpenID Connect ID Tokens for Amazon Web Service API Keys. We will cover that aspect in another article.

 
         String resource_endpoint = “http://weather.com/....”;
HttpResponse resp = HTTP_TRANSPORT.createRequestFactory(new Credential(BearerToken.authorizationHeaderAccessMethod()).setAccessToken(token))
.buildGetRequest(new GenericUrl(resource_endpoint))
.setParser(new JsonObjectParser(JSON_FACTORY))
.execute();

Now the application can display Identity Specific messages in its User Interface as below.

nam-message
Labels (1)

DISCLAIMER:

Some content on Community Tips & Information pages is not officially supported by Micro Focus. Please refer to our Terms of Use for more detail.
Comments
Hi dears,

have you released some sample implementation on github, for example?
Regards
Top Contributors
Version history
Revision #:
3 of 3
Last update:
‎2020-01-31 22:06
Updated by:
 
The opinions expressed above are the personal opinions of the authors, not of Micro Focus. By using this site, you accept the Terms of Use and Rules of Participation. Certain versions of content ("Material") accessible here may contain branding from Hewlett-Packard Company (now HP Inc.) and Hewlett Packard Enterprise Company. As of September 1, 2017, the Material is now offered by Micro Focus, a separately owned and operated company. Any reference to the HP and Hewlett Packard Enterprise/HPE marks is historical in nature, and the HP and Hewlett Packard Enterprise/HPE marks are the property of their respective owners.