Learn About Authentication Between Java Applications and Oracle Identity Cloud Service

You’re ready to learn about authentication between Java web applications and Oracle Identity Cloud Service. This includes understanding the following:

  • The three-legged authentication flow that Oracle Identity Cloud Service supports for the Java SDK

  • Use cases for using an SDK with a Java application to authenticate with Oracle Identity Cloud Service

  • Methods and functions of the Java SDK

Learn About Three-Legged Authentication Flows

Oracle Identity Cloud Service supports the three-legged authentication flow for the Java SDK. In this flow, users interact directly with Oracle Identity Cloud Service. After a user signs in, Oracle Identity Cloud Service issues an authorization code that the SDK exchanges for a user access token. The Java web application uses this access token to grant users access to the protected resources in the application. The three-legged flow uses the authorization code grant type.

For increased security, Oracle recommends that you use the three-legged flow to integrate your Java web applications with Oracle Identity Cloud Service for authentication. By using the authorization code grant type, you can also access other applications that are protected by Oracle Identity Cloud Service without having to reauthenticate.

Learn About the Primary Use Cases for Using an SDK with a Java Application

The Java web application implements two use cases: one for authenticating users, and the other for accessing detailed information about the logged-in user.

The following data flow diagrams illustrate the flow of events, calls, and responses between the web browser, the web application, and Oracle Identity Cloud Service for each use case.

Use Case #1: Authenticate a User

The data flow happens this way:

  1. The user requests a protected resource.

  2. The authentication module uses the SDK to generate a request-authorization-code URL for Oracle Identity Cloud Service and send this URL as a redirect response to the web browser.

  3. The web browser calls the URL.

  4. The Oracle Identity Cloud Service Sign In page appears.

  5. The user submits their Oracle Identity Cloud Service sign-in credentials.

  6. After the user signs in, Oracle Identity Cloud Service creates a session for the user and issues an authorization code.

  7. The web application makes a back-end (or server-to-server) call to exchange the authorization code for an access token.

  8. Oracle Identity Cloud Service issues an access token and an id token.

  9. A session is established, and the user is redirected to the Home page.

  10. The Home page of the web application appears.

Use Case #2: Get Details About the User

The data flow happens this way:

  1. The user requests the /myProfile resource.

  2. The web application uses Oracle Identity Cloud Service's SDK to validate the id token.

  3. The data that returns from id token validation contains user's details in the format of a JSON object.

  4. The My Profile page renders the JSON object as HTML content.

Learn About Methods and Functions

The Java SDK is a JAR file that you load as a web application library. This JAR file requires these third-party libraries which you also must load to the library:

The Java SDK zip file contains the following required third-party libraries necessary for the SDK. You can load them into your application.

  • ASM Helper Minidev 1.0.2

  • Apache Commons Collections 4.1

  • Apache Commons Lang 3.7

  • JSON Small And Fast Parser 2.3

  • Nimbus LangTag 1.4.3

  • Nimbus JOSE+JWT 5.14

  • OAuth 2.0 SDK With OpenID Connect Extensions 5.30

Oracle provides a sample Java web application to demonstrate how to use the Java SDK. This application was built using Servlet technology to simplify the learning experience to understand how the Java SDK works. The application uses Maven to get all of the libraries and to generate a Web Application Resource (WAR) file.

The Java SDK requires a HashMap object instance loaded with Oracle Identity Cloud Service connection information. The Java web application implements this HashMap instance as a class attribute in the ConnectionOptions.java class.

//Instance of a HashMap.
    private Map<String,Object> options = new HashMap<>();
  
public ConnectionOptions(){
        this.options = new HashMap<>();
}
  
public Map<String,Object> getOptions(){
        //Adding Oracle Identity Cloud Service connection parameters to the HashMap instance.
        this.options.put(IDCSTokenAssertionConfiguration.IDCS_HOST, "identity.oraclecloud.com");
        this.options.put(IDCSTokenAssertionConfiguration.IDCS_PORT, "443");
        this.options.put(IDCSTokenAssertionConfiguration.IDCS_CLIENT_ID, "123456789abcdefghij");
        this.options.put(IDCSTokenAssertionConfiguration.IDCS_CLIENT_SECRET, "abcde-12345-zyxvu-98765-qwerty");
        this.options.put(IDCSTokenAssertionConfiguration.IDCS_CLIENT_TENANT, "idcs-abcd1234");
        this.options.put(Constants.AUDIENCE_SERVICE_URL, "https://idcs-abcd1234.identity.oraclecloud.com");
        this.options.put(Constants.TOKEN_ISSUER, "https://identity.oraclecloud.com/");
        this.options.put(Constants.TOKEN_CLAIM_SCOPE, "urn:opc:idm:t.user.me openid");
        this.options.put("SSLEnabled", "true");
        this.options.put("redirectURL", "http://localhost:8080/callback");
        this.options.put("logoutSufix", "/oauth2/v1/userlogout");
        this.options.put(Constants.CONSOLE_LOG, "True");
        this.options.put(Constants.LOG_LEVEL, "DEBUG");
        return this.options;
    }

Below is a brief explanation of each required attribute for this SDK:

Name Description
IDCSTokenAssertionConfiguration.IDCS_HOST The domain suffix of your Oracle Identity Cloud Service instance.
IDCSTokenAssertionConfiguration.IDCS_PORT The HTTPS port number that’s reserved for your Oracle Identity Cloud Service instance (usually 443).
IDCSTokenAssertionConfiguration.IDCS_CLIENT_ID The value of the Client ID that’s generated after you register the Java web application in the Identity Cloud Service console.
IDCSTokenAssertionConfiguration.IDCS_CLIENT_SECRET The value of the Client Secret that’s generated after you register the Java web application in the Identity Cloud Service console.
IDCSTokenAssertionConfiguration.IDCS_CLIENT_TENANT The domain prefix of your Oracle Identity Cloud Service instance. This prefix is usually a value similar to idcs-abcd1234.
Constants.AUDIENCE_SERVICE_URL The fully-qualified domain name URL of your Oracle Identity Cloud Service instance.
Constants.TOKEN_ISSUER For this attribute, Oracle recommends that you keep the value https://identity.oraclecloud.com.
Constants.TOKEN_CLAIM_SCOPE

The scope controls the data that the application can access or process on behalf of the Oracle Identity Cloud Service user.

If the application uses the SDK to authenticate a user, then the scope is openid. If the application also uses the SDK to get details about the user, then the scope is urn:opc:idm:t.user.me openid.

SSLEnabled Indicates whether Oracle Identity Cloud Service responds to HTTPS or HTTP requests. For this attribute, Oracle recommends that you keep the value true.
Constants.CONSOLE_LOG Enables SDK log.
Constants.LOG_LEVEL Indicates the log level of the SDK.

The application uses both the logoutSufix and redirectURL attributes to avoid hard code these values. The SDK doesn’t require them.

The Java web application implements the AuthServlet class, which maps the /auth URL. When a user decides to authenticate with Oracle Identity Cloud Service, the web browser makes a request to this URL. The AuthServlet class initializes the Authentication Manager object, uses the Java SDK to generate Oracle Identity Cloud Service's authorization code URL, and then redirects the web browser to this URL.

public class AuthServlet extends HttpServlet {
    protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //Loading the configurations
        Map<String, Object> options = new ConnectionOptions().getOptions();
        //Configuration object instance with the parameters loaded.
        IDCSTokenAssertionConfiguration config = new IDCSTokenAssertionConfiguration(options);
	String redirectUrl = (String)options.get("redirectURL");
        String scope = (String)options.get(Constants.TOKEN_CLAIM_SCOPE);
        //Authentication Manager loaded with the configurations.
        AuthenticationManager am = AuthenticationManagerFactory.getInstance(config);
        //Using Authentication Manager to generate the Authorization Code URL, passing the
        //application's callback URL as parameter, along with code value and code parameter.
        String authzURL = am.getAuthorizationCodeUrl(redirectUrl, scope, "1234", "code");
        //Redirecting the browser to the Oracle Identity Cloud Service Authorization URL.
        response.sendRedirect(authzURL);
    }
}

The following parameters are used to generate the authorization code URL:

Name Description
redirectUrl After a user signs in, Oracle Identity Cloud Service redirects the user’s web browser to this URL. This URL must match the one you’ll configure for the trusted application in the Identity Cloud Service console. See Register the Java Application for more information about specifying a redirect URL for the Java web application.
scope The OAuth or OpenID Connect scope of authentication. This application requires only openid authentication.
state The OAuth protocol defines this parameter. The sample Java web application uses this code to check whether communication can be established to Oracle Identity Cloud Service. For this example, the value for this parameter is 1234.
response_type The parameter required by the authorization code grant type. For this example, the value for this parameter is code.

After the user signs in, Oracle Identity Cloud Service redirects the user’s web browser to a callback URL, which the developer must implement. The Java web application uses the CallbackServlet to handle this request.

public class CallbackServlet extends HttpServlet {
    protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //Loading the configurations
        Map<String, Object> options = new ConnectionOptions().getOptions();
        //After Oracle Identity Cloud Service authenticates the user, the browser is redirected to the
        //callback URL, implemented as a Servlet.
        IDCSTokenAssertionConfiguration config = new IDCSTokenAssertionConfiguration(options);
        //Authentication Manager loaded with the configurations.
        AuthenticationManager am = AuthenticationManagerFactory.getInstance(config);
        //Getting the authorization code from the "code" parameter
        String authzCode = request.getParameter("code");
        //Using the Authentication Manager to exchange the Authorization Code to an Access Token.
        AuthenticationResult ar = am.authorizationCode(authzCode);
        //Getting the Access Token object and its String value.
        AccessToken access_token = ar.getToken(OAuthToken.TokenType.ACCESS_TOKEN);
        String access_token_string = access_token.getToken();
        //Getting the ID Token object and its String value.
        IdToken id_token = ar.getToken(OAuthToken.TokenType.ID_TOKEN);
        String id_token_string = id_token.getToken();
        //Validating both Tokens to acquire information for User such as UserID, 
        //DisplayName, list of groups and AppRoles assigned to the user.
        IdToken id_token_validated = am.validateIdToken(id_token_string);
        //Storing information into the HTTP Session.
        HttpSession session=request.getSession();
        session.setAttribute("access_token", access_token_string);
        session.setAttribute("id_token", id_token_string);
        session.setAttribute("userId", id_token_validated.getUserId());
        session.setAttribute("displayName", id_token_validated.getDisplayName());
	//Forwarding the request to the Home page.
        request.getRequestDispatcher("private/home.jsp").forward(request, response);
    }
}	

The application requests the authorization code parameter and uses it to call the AuthenticationManager.authorizationCode() method of the Java SDK to request both an access token and an id token. The servlet then uses the AuthenticationManager instance to validate the id token. The AuthenticationManager.validateIdToken() methods returns an instance of the IdToken object that contains user information such as display name, user id, and the list of groups and application roles assigned to the user. Both access token and id token values, and some user information are stored in the HTTP session object so that the request can be forwarded to a protected URL within the application called /private/home.jsp. In addition to /private/home.jsp, the Java web application has another protected URLs: /private/myProfile.jsp.

The myProfile.jsp page uses the following code sample to get more information about the user who’s signed in to Oracle Identity Cloud Service:


<%if(session.getAttribute("access_token")==null) response.sendRedirect("/login.html");%>
<!DOCTYPE html>
<%
/**
 * The /private/myProfile.jsp page accesses the user's access token previously set in the session, 
 * calls the getAuthenticatedUser method to retrieve the user's information, and then formats it as HTML.
 * @author felippe.oliveira@oracle.com
 * @Copyright Oracle
*/
  java.util.Map<String, Object> options = new sampleapp.util.ConnectionOptions().getOptions();
  //Configuration object instance with the parameters loaded.
  oracle.security.jps.idcsbinding.shared.IDCSTokenAssertionConfiguration configuration = new oracle.security.jps.idcsbinding.shared.IDCSTokenAssertionConfiguration(options);
  oracle.security.jps.idcsbinding.shared.AuthenticationManager am = oracle.security.jps.idcsbinding.shared.AuthenticationManagerFactory.getInstance(configuration);
  
  //Getting the Access Token and the Id Token from the session object
  String access_token_string = (String)session.getAttribute("access_token");
  String id_token_string = (String)session.getAttribute("id_token");

  //Validating the ID Token to get user information, groups and app roles associated with the user.
  oracle.security.jps.idcsbinding.api.AccessToken access_token_validated = am.validateAccessToken(access_token_string);
  oracle.security.jps.idcsbinding.api.IdToken id_token_validated = am.validateIdToken(id_token_string);
%>

The /private/myProfile.jsp page accesses the id token value that was set in the session, calls the AuthenticationManager.validateIdToken() method to retrieve user's information, and then presents it as HTML content.


<p><b>Information from the Identity Token:</b></p><p><%
out.println("DisplayName = "+ id_token_validated.getDisplayName() +"<br>");
out.println("IdentityDomain = "+ id_token_validated.getIdentityDomain() +"<br>");
out.println("UserName = "+ id_token_validated.getUserName()+"<br>");
out.println("UserId = "+ id_token_validated.getUserId()+"<br>");
out.println("Issuer = "+ id_token_validated.getIssuer()+"<br>");

java.util.List<oracle.security.jps.idcsbinding.api.IDCSAppRole> appRoles = id_token_validated.getAppRoles();
if(!appRoles.isEmpty()){
   out.println("App Roles:<br>");
   for(oracle.security.jps.idcsbinding.api.IDCSAppRole appRole: appRoles){
      out.println("&nbsp;appRole = "+ appRole.getName() +"<br>");
   }//for
}//if

java.util.List<oracle.security.jps.idcsbinding.api.IDCSGroup> groups = id_token_validated.getGroupMembership();
if(!groups.isEmpty()){
   out.println("Groups:<br>");
   for(oracle.security.jps.idcsbinding.api.IDCSGroup group: groups){
      out.println("&nbsp;group = "+ group.getName() +"<br>");
   }//for
}//if
%>
</p>
<p><b>Access Token:</b></p><p><%=access_token_string%></p>

To sign the user out from single sign-on between the application and Oracle Identity Cloud Service, the Java web application implements the LogoutServlet, which maps the /logout URL:

public class LogoutServlet extends HttpServlet {
    protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session=request.getSession();
        String id_token = (String)session.getAttribute("id_token");
        session.invalidate();
        Map options = new ConnectionOptions().getOptions();
        String logoutURL = (String)options.get(Constants.AUDIENCE_SERVICE_URL) + (String)options.get("logoutSufix") +"?post_logout_redirect_uri=http%3A//localhost%3A8080&id_token_hint="+ id_token;
        response.sendRedirect(logoutURL);
    }
}

This servlet invalidates the application’s session, and then redirects the user’s web browser to Oracle Identity Cloud Service's OAuth log out URL.