Show TOC

Procedure documentationImplementing the Login Module Source Code Locate this document in the navigation structure

Procedure

Open the MyLoginModuleClass.java file. Implement the Java class:

  1. Define the class package:

    Syntax Syntax

    1. package com.sap.example;
    End of the code.
  2. Import the classes and packages required for the compilation of the class:

    Syntax Syntax

    1. import java.util.Map;
      
      import java.io.IOException;
      
      
      
      import javax.security.auth.login.LoginException;
      
      import javax.security.auth.Subject;
      
      import javax.security.auth.callback.CallbackHandler;
      
      import javax.security.auth.callback.Callback;
      
      import javax.security.auth.callback.NameCallback;
      
      import javax.security.auth.callback.UnsupportedCallbackException;
      
      
      
      import com.sap.engine.interfaces.security.auth.AbstractLoginModule;
      
      import com.sap.engine.lib.security.http.HttpGetterCallback;
      
      import com.sap.engine.lib.security.http.HttpCallback;
      
      import com.sap.engine.lib.security.LoginExceptionDetails;
      
      import com.sap.engine.lib.security.Principal;
      
    End of the code.
  3. Use the following syntax to specify that the class MyLoginModuleClass extends AbstractLoginModule class:

    Syntax Syntax

    1. public class MyLoginModuleClass extends AbstractLoginModule {
      
      ...
      
    End of the code.
    1. Define the variables for the tutorials example. These are used only for the tutorial:

      Syntax Syntax

      1. // Define the variables that will be used later on
        
        // in this example
        
        private CallbackHandler callbackHandler = null;
        
        private Subject subject = null;
        
        private Map sharedState = null;
        
        private Map options = null;
        
        
        
        // This is the name of the user you have created on 
        
        // the AS Java so you can test the login module
        
        private String userName = null;
        
        
        
        private boolean successful;
        
        private boolean nameSet;
        
      End of the code.
    2. Create the initialize() method to initialize the login module with the relevant authentication and state information:

      Syntax Syntax

      1. /**
        
            * The method initialize the login module with the 
        
            * relevant authentication and state information.
        
            */
        
           public void initialize(
        
              Subject subject,
        
              CallbackHandler callbackHandler,
        
              Map sharedState,
        
              Map options) {
        
              ...
        
      End of the code.
      1. In the initialize() method, define the following obligatory source code:

        Syntax Syntax

        1. super.initialize(subject, callbackHandler, sharedState, options);
        End of the code.
      2. Also initialize the values of the variables for the login module.

        Syntax Syntax

        1. // Initializing the values of the variables
          
          this.callbackHandler = callbackHandler;
          
          this.subject = subject;
          
          this.sharedState = sharedState;
          
          this.options = options;
          
          this.successful = false;
          
          this.nameSet = false;
          
        End of the code.
    3. Implement the login() method:

      Syntax Syntax

      1. /**
        
          * Retrieves the user credentials and checks them. This is 
        
          * the first part of the authentication process.
        
          */
        
        public boolean login() throws LoginException {
        
           ...
        
      End of the code.
      1. In the login() method, retrieve the user's credentials using a callback handler.

        The type and the name specify which part of the HTTP request should be retrieved. For Web container authentication, the supported types are defined in the interface com.sap.engine.lib.security.http.HttpCallback. For programmatic authentication with a custom callback handler, the supported types depend on the callback handler used.

        Syntax Syntax

        1. // In this case we get the user name from the HTTP 
          
          // NameCallback.
          
          
          
          NameCallback nameCallback = new NameCallback("User name: ");
          
          
          
          /* The type and the name specify which part of the HTTP request 
          
           * should be retrieved. For Web container authentication, the 
          
           * supported types are defined in the interface
          
           * com.sap.engine.lib.security.http.HttpCallback.
          
           * For programmatic authentication with custom callback 
          
           * handler the supported types depend on the callback handler used.
          
           */
          
          
          
          try {
          
           callbackHandler.handle(new Callback[] {nameCallback});
          
          }
          
          catch (UnsupportedCallbackException e) {
          
           return false;
          
          }
          
          catch (IOException e) {
          
           throwUserLoginException(e, LoginExceptionDetails.IO_EXCEPTION);
          
          }
          
          
          
          userName = nameCallback.getName();
          
          
          
          if( userName == null || userName.length() == 0 ) {
          
             return false;   
          
          }
          
        End of the code.
      2. Update the user information using data from the persistence once the user name is available from the user. This operation must be done before the checks for the user credentials. This way the login() method verifies the existence of the user name. If the provided user name does not exist in the active user store, the method throws a java.lang.SecurityException:

        Syntax Syntax

        1. try {
          
             refreshUserInfo(userName);
          
          } catch (SecurityException e) {
          
             throwUserLoginException(e);
          
          }
          
        End of the code.
      3. Perform a check of the user's credentials.

        Syntax Syntax

        1. /* Checks if the given user name starts with the specified 
          
           * prefix in the login module options. If no prefix is specified, 
          
           * then all users are trusted.
          
           */
          
          String prefix = (String) options.get("user_name_prefix");
          
          if ((prefix != null) && !userName.startsWith(prefix)) {
          
             throwNewLoginException("The user is not trusted.");
          
          }
          
        End of the code.
      4. If the authentication is successful, put the user name in a shared state.

        One and only one login module from the stack must put the user name in the shared state to represent the authenticated user. For example, if the login is successful, method getRemoteUser() of the HTTP request will retrieve this name. In the example shown below, we also set the variable successful to true and return the value true for the login module.

        Syntax Syntax

        1. if (sharedState.get(AbstractLoginModule.NAME) == null) {
          
             sharedState.put(AbstractLoginModule.NAME, userName);
          
             nameSet = true;
          
          }
          
          
          
          successful = true;
          
          return true;
          
        End of the code.
    4. Implement the commit() method.

      In this method you commit the log on. This is the second part of the authentication process. If a user's name has been stored by the login() method, then this user name is added to the subject of a new principal.

      Syntax Syntax

      1. public boolean commit() throws LoginException {
        
        ...
        
      End of the code.
      1. The principals that are added to the subject should implement com.sap.engine.lib.security.Principal:

        Syntax Syntax

        1. if (successful) {
          
          
          
             /* The principals that are added to the subject should 
          
              * implement java.security.Principal. You can use the class 
          
              * com.sap.engine.lib.security.Principal for this purpose. 
          
              */
          
             Principal principal = new Principal(userName);
          
             subject.getPrincipals().add(principal);
          
          
          
             /* If the login is successful, then the principal corresponding 
          
              * to the <userName> (the same user name that has been added 
          
              * to the shared state) must be added in the shared state too. 
          
              * This principal is considered to be the main principal 
          
              * representing the user.
          
              * For example, this principal will be retrieved from method 
          
              * getUserPrincipal() of the HTTP request. 
          
              */
          
          
          
             if (nameSet) {
          
                sharedState.put(AbstractLoginModule.PRINCIPAL, principal);
          
             }
          
          } else {
          
             userName = null;
          
          }
          
          return true;
          
        End of the code.
    5. Implement the abort() method. This method is used for aborting the authentication process:

      Syntax Syntax

      1. public boolean abort() throws LoginException {
        
        
        
          if (successful) {
        
            userName = null;
        
            successful = false;
        
          }
        
        
        
           return true;
        
        }
        
      End of the code.
    6. Implement the logout() method: the method logs out the user and also removes the principals and destroys or removes the credentials that were associated with the user during the commit phase.

      Syntax Syntax

      1. public boolean logout() throws LoginException {
        
        
        
           // Remove principals and credentials from subject 
        
           if (successful) {
        
              subject.getPrincipals(Principal.class).clear();
        
              successful = false;
        
           }
        
        
        
           return true;
        
        }
        
      End of the code.

Result

The login module class is implemented.

Example

Example Login Module.

More Information

More information about using SAP specific callbacks:

Using the HTTP Callback Classes