Show TOC Entering content frame

This graphic is explained in the accompanying text Example SAML Mapping Module Used by the SAML Test Application Locate the document in its SAP Library structure

The following example shows the mapping module that is used by the SAML test application. It shows how to read the user data from the SAMLLoginModule and map it to a user on the SAP J2EE Engine.

Example SAML Mapping Module

package com.sap.security.core.server.saml.app.ssotest.dest;

import java.security.Principal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;

import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
    
import javax.security.auth.login.LoginException;

    
import com.sap.engine.interfaces.security.auth.AbstractLoginModule;
    
import com.sap.security.core.server.saml.jaas.SAMLAuthenticationData;
    
import com.sap.security.core.server.saml.jaas.SAMLAuthenticationDataCarrier;
    
import com.sap.security.core.server.saml.jaas.SAMLLoginModule;
    
import com.sap.tc.logging.Location;

    /**
     * This JAAS login module is used in the SAML SSO Test application to 
     * demonstrate that the data stored by the SAMLLoginModule can be read
     * out and used for user-mapping.
     

     * This code serves demonstration purposes only. It is not part of the 
     * SAP product maintenance process. Coding techniques used in this module
     * must not be understood as SAP's recommendations for writing login modules.
     * 
     * <p>Copyright (c) 2003 SAP AG.
     
*/
    public class SAMLMappingModule extends AbstractLoginModule {

        /** Location for tracing */
        
private static final Location LOCATION =
            Location.getLocation(SAMLMappingModule.
class);

        /** The <code>Subject</code> passed from the login context */
        
private Subject _subject;

        /** Callback handler needed for "change Password" callback */
        
private CallbackHandler _callbackHander;

        /** 
         * The map in which the data from the <code>SAMLLoginModule</code> can 
         * be found.
         */

        
private Map _sharedState;

       
 /** The map with the options for this module */
        
private Map _options;

        
/** Option "Mapping" */
        
private static final String OPTION_MAPPING = "Mapping";

        
/** Additional data from the login process */
        
private SAMLMappingModulePrincipal _newPrincipal = null;

        
/**
         * Store the data passed from the login context.
         */

        
public void initialize(
            Subject subject,
            CallbackHandler callbackHandler,
            Map sharedState,
            Map options) {

            _subject = subject;
            _callbackHander = callbackHandler;
            _sharedState = sharedState;
            _options = options;

        }

        /**
         * Login phase of JAAS. 
         * 
         * In this step, the module checks whether the <code>SAMLLoginModule</code>
         * has stored some data in the shared state. 
         * 
         * If this is the case, the module checks whether it can find a 
         * mapping entry for this user and remembers the internal user name.
         * 
         * 
@return
         *   <code>false</code>, if no data were found in the shared state. In this
         *   case, the mapping module can be ignored.
         *   <code>true</code>, if data were found and a mapping could be 
         *   determined.
         * 
         * 
@throws
         *   LoginException
         *     Error in the configuration of the mapping, or failure to find the
         *     incoming external user name.
         */
        public boolean login() throws LoginException {

            
final String METHOD = "login()";

            
boolean result = false;

            
/* "try...catch...finally" for logging */
            try {

                LOCATION.entering(METHOD);

                _newPrincipal = 
null;

                
/* Read the mapping from the options */
                String mappingString = (String) _options.get(OPTION_MAPPING);

                
/* The option must be specified */
                
if ((mappingString == null) || ("".equals(mappingString.trim()))) {

                    
throw new Exception(
                        "The SAMLMappingModule did not find the "
                            + "required option \""
                            + OPTION_MAPPING
                            + "\"");

                }

                
/* Evaluate the options value and create the mapping */
                HashMap userMapping = new HashMap();

                
try {

                    StringTokenizer tokenizer =
                        
new StringTokenizer(mappingString, ","false);

                    
while (tokenizer.hasMoreTokens()) {

                        String singleMapping = tokenizer.nextToken().trim();

                        
/* Split into external and internal name */
                        StringTokenizer mapTokens =
                            
new StringTokenizer(singleMapping, ":"false);

                        String from = 
null;
                        String to = 
null;

                        from = mapTokens.nextToken().trim();
                        to = mapTokens.nextToken().trim();

                        
if (((from == null) || ("".equals(from)))
                            || ((to == 
null) || ("".equals(to)))) {

                            
throw new Exception();

                        }

                        userMapping.put(from, to);

                    }

                } 
catch (Exception e) {

                    /
* Any error in between --> wrong mapping format */
                    
throw new Exception(
                        "The SAMLMappingModule found in option \""
                            + OPTION_MAPPING
                            + "\" a non-interpretable "
                            + "mapping information \""
                            + mappingString
                            + "\". Specify mappings like this: "
                            + "\"ext1 : int1, ext2 : int2\".");

                }

                /* 
                 * After the check of correct configuration, we evaluate the 
                 * shared state for the information that the SAMLLoginModule might
                 * have placed there.
                 */

                SAMLAuthenticationData authData;

                
try {

                    authData =
                        (SAMLAuthenticationData) _sharedState.get(
                            SAMLLoginModule.KEY_AUTH_DATA);

                } 
catch (Exception e) {

                    
/* Class cast of something like this */
                    
throw new Exception(
                        "The SAMLMappingModule could not interpret "
                            + "a data item in the "
                            + "shared state: \""
                            + e.getLocalizedMessage()
                            + "\".");

                }

                /* If no data present, the module can be ignored. */
                
if (authData == null) {

                    result = 
false;
                    
return result;

                }

                /* 
                 * If the incoming user name is not known to the mapping, this is 
                 * worth an exception.
                 */

                String nameIdentifier = authData.getNameIdentifier();

                
if (!userMapping.containsKey(nameIdentifier)) {

                    
throw new Exception(
                        "The SAMLMappingModule received user name \""
                            + nameIdentifier
                            + "\" from the "
                            + "SAMLLoginModule, but this user name is not present "
                            + "in the mapping data.");

                }

                String newUserName = (String) userMapping.get(nameIdentifier);

                /* 
                 * Check user lock status.
                 * See documentation of "AbstractLoginModule" for details.
                 * 
                 * This code accesses the user management of the engine
                 * which requires permissions to be granted in the 
                 * "Security Provider" service.
                 * Domain: "SAP-J2EE-Engine", Resource "user-management". Grant
                 * "all" for action "ALL".
                 * 
                 * As this is not done within this demo application, the code
                 * is left out here. 
                 */

                
// checkUserLockStatus(newUserName);

                /*
                 * Check "user must change password" status.
                 * See documentation of "AbstractLoginModule" for details.
                 * 
                 * See comment above why this code is now commented out.
                 */

              
  // changePasswordIfNeeded(newUserName, _callbackHander);

                /* Prepare new principal to be appended in commit() 
                 * phase 
                 */

                _newPrincipal =
                    
new SAMLMappingModulePrincipal(newUserName, authData);
                
                /* 
                 * Write user name to shared state for a possibly following
                 * TicketCreator module.
                 */

                _sharedState.put(AbstractLoginModule.NAME, newUserName);

                result = 
true;
                
return result;

            } 
catch (Exception e) {

                LoginException exceptionToBeThrown;

                
if (e instanceof LoginException) {

                    /*
                     * LoginExceptions are thrown only from the methods of the base
                     * class. The example code in AbstractLoginModule indicates
                     * that these exceptions need not to be wrapped, but are 
                     * thrown directly.
                     */

                    exceptionToBeThrown = (LoginException) e;

                } 
else {

                    /* Other exceptions are traced from this class */
                    LOCATION.errorT(
                        METHOD,
                        "An error occurred in the SAMLMappingModule:\n{0}\n",
                        
new Object[] { e.getMessage()});

                    /* 
                     * The AbstractLoginModule offers a method to be used to 
                     * indicate any exception in login phase. This method is not 
                     * used directly but wrapped into the following try...catch 
                     * block because the resulting exception shall be traced by 
                     * the mapping module (annotation: the method from 
                     * AbstractLoginModule also performs some tracing, but it 
                     * probably is not the same location as this mapping module
                     * has, so the program flow information would be split.
                     */

                    
try {

                        
/* For compiler happiness only */
                        exceptionToBeThrown = 
new LoginException(e.getMessage());
                        throwUserLoginException(e);

                    } 
catch (LoginException f) {

                        
/* Will always be executed */
                        exceptionToBeThrown = f;

                    }

                }

                LOCATION.throwing(METHOD, exceptionToBeThrown);
                
throw exceptionToBeThrown;

            } 
finally {

                LOCATION.exiting(
new Boolean(result));

            }

        }

        /**
         * If a user name was stored, append it to the subject.
         */

        
public boolean commit() throws LoginException {

            
final String METHOD = "commit()";

            
boolean result = false;

            
try {

                LOCATION.entering(METHOD);

                
if (_newPrincipal != null) {

                    _subject.getPrincipals().add(_newPrincipal);

                    /* See documentation of "AbstractLoginModule" */
                    writeLogonStatistics(
                        
true,
                        _newPrincipal.getName(),
                        
new Date().getTime(),
                        _sharedState);

                    result = 
true;
                    
return result;

                } 
else {

                    result = 
false;
                    
return result;

                }

            } 
catch (Exception e) {

                LOCATION.throwing(METHOD, e);
                _sharedState.remove(AbstractLoginModule.NAME);
                
throw new LoginException(e.getMessage());

            } 
finally {

                LOCATION.exiting(
new Boolean(result));

            }

        }

        /**
         * Destroy user name.
         */

        
public boolean abort() throws LoginException {

            String userName =
                (_newPrincipal != 
null) ? _newPrincipal.getName() : "Unknown";

            /* See documentation of "AbstractLoginModule" */
            writeLogonStatistics(
                
false,
                userName,
                
new Date().getTime(),
                _sharedState);

            _newPrincipal = 
null;
            
return true;

        }

        /**
         * Remove stored principal.
         */

        
public boolean logout() throws LoginException {

            
if (_newPrincipal != null) {

                _subject.getPrincipals().remove(_newPrincipal);
                _newPrincipal = 
null;

                
return true;

            } 
else {

                
return false;

            }

        }

        
/**
         * Inner class for the principal that is appended by this login module.
         */

        
private static class SAMLMappingModulePrincipal
            
implements Principal, SAMLAuthenticationDataCarrier {

            
private String _name;
            
private SAMLAuthenticationData _authData;

            
/**
             * Constructor for SAMLMappingModulePrincipal.
             */

            
public SAMLMappingModulePrincipal(
                String name,
                SAMLAuthenticationData authData) {
                _name = name;
                _authData = authData;
            }

            /**
             * 
@see java.security.Principal#getName()
             */

            
public String getName() {
                
return _name;
            }

            /**
             * 
@see SAMLAuthenticationDataCarrier#getSAMLAuthenticationData()
             */

            
public SAMLAuthenticationData getSAMLAuthenticationData() {
                
return _authData;
            }

        }

    }

 

 

Leaving content frame