WAS v8.5 > Secure applications > Secure the Liberty profile and its applications > Develop extensions to the Liberty profile security infrastructureDevelop JAAS custom login modules for a system login configuration
For a Liberty profile server, multiple Java™ Authentication and Authorization Service (JAAS) plug-in points exist for configuring system logins. The Liberty profile uses system login configurations to authenticate incoming requests. We can develop a custom JAAS login module to add information to the Subject of a system login configuration. Application login configurations are called by servlet applications for obtaining a Subject based on specific authentication information. When you write a login module that plugs into a Liberty profile application login or system login configuration, you must develop login configuration logic that knows when specific information is present, and how to use the information. See JAAS configuration and JAAS login modules for more details.
Avoid trouble: If we use the developer tools to configure the JAAS custom login module, refer to the sample JAAS configuration jaasConfig.xml file in the ${ wlp.install.dir}/templates/config directory, and make sure the configuration in your server.xml file is similar to the one in the sample file. See Configuring JAAS on the Liberty profile using WebSphere Studio.
To develop a JAAS custom login module for a system login configuration, follow the steps in the procedure:
- Understand usable callbacks and how they work.
See Programmatic login for JAAS for more information about usable callbacks.
The Liberty profile only supports the following callbacks:
callbacks[0] = new javax.security.auth.callback.NameCallback("Username: "); callbacks[1] = new javax.security.auth.callback.PasswordCallback("Password: ", false); callbacks[2] = new com.ibm.websphere.security.auth.callback.WSCredTokenCallbackImpl("Credential Token: "); callbacks[3] = new com.ibm.websphere.security.auth.callback.WSServletRequestCallback("HttpServletRequest: ") callbacks[4] = new com.ibm.websphere.security.auth.callback.WSServletResponseCallback("HttpServletResponse: "); callbacks[5] = new com.ibm.websphere.security.auth.callback.WSAppContextCallback("ApplicationContextCallback: "); callbacks[6] = new WSRealmNameCallbackImpl("Realm Name: ", default_realm); callbacks[7] = new WSX509CertificateChainCallback("X509Certificate[]: "); callbacks[8] = wsAuthMechOidCallback = new WSAuthMechOidCallbackImpl("AuthMechOid: ");- Understand shared state variables and how they work.
To access the objects the WebSphere Application Server full profile creates during a login, refer to the following shared state variables. For more information about these variables, see the "System Programming Interfaces" subtopic of Programming Interfaces.
- com.ibm.wsspi.security.auth.callback.Constants.WSPRINCIPAL_KEY
- Specifies an implemented object of the java.security.Principal interface. This shared state variable is for read-only purposes. Do not set this variable in the shared state for custom login modules. The default login module sets this variable.
- com.ibm.wsspi.security.auth.callback.Constants.WSCREDENTIAL_KEY
- Com.ibm.websphere.security.cred.WSCredential object. This shared state variable is for read-only purposes. Do not set this variable in the shared state for custom login modules. The default login module will set this variable.
- com.ibm.wsspi.security.auth.callback.Constants.WSSSOTOKEN_KEY
- Specifies the com.ibm.wsspi.security.token.SingleSignonToken object. Do not set this variable in the shared state for custom login modules. The default login module sets this variable.
- Optional: Understand hashtables for custom JAAS login modules in the Liberty profile. See Hashtable login module for more details.
- Develop a sample custom login module using callbacks and shared state.
We can use the following sample to learn on how to use some of the callbacks and shared state variables.
public class CustomCallbackLoginModule implements LoginModule { protected Map<String, ?> _sharedState; protected Subject _subject = null; protected CallbackHandler _callbackHandler; private final String customPrivateCredential = "CustomLoginModuleCredential"; /** * Initialization of login module */ public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options) { _sharedState = sharedState; _subject = subject; _callbackHandler = callbackHandler; } public boolean login() throws LoginException { try { AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { public Object run() throws Exception { _subject.getPrivateCredentials().add(customPrivateCredential); return null; } }); } catch (PrivilegedActionException e) { throw new LoginException(e.getLocalizedMessage()); } String username = null; char passwordChar[] = null; byte[] credToken = null; HttpServletRequest request = null; HttpServletResponse response = null; Map appContext = null; String realm = null; String authMechOid = null; java.security.cert.X509Certificate[] certChain = null; NameCallback nameCallback = null; PasswordCallback passwordCallback = null; WSCredTokenCallbackImpl wsCredTokenCallback = null; WSServletRequestCallback wsServletRequestCallback = null; WSServletResponseCallback wsServletResponseCallback = null; WSAppContextCallback wsAppContextCallback = null; WSRealmNameCallbackImpl wsRealmNameCallback = null; WSX509CertificateChainCallback wsX509CertificateCallback = null; WSAuthMechOidCallbackImpl wsAuthMechOidCallback = null; Callback[] callbacks = new Callback[9]; callbacks[0] = nameCallback = new NameCallback("Username: "); callbacks[1] = passwordCallback = new PasswordCallback("Password: ", false); callbacks[2] = wsCredTokenCallback = new WSCredTokenCallbackImpl("Credential Token: "); callbacks[3] = wsServletRequestCallback = new WSServletRequestCallback("HttpServletRequest: "); callbacks[4] = wsServletResponseCallback = new WSServletResponseCallback("HttpServletResponse: "); callbacks[5] = wsAppContextCallback = new WSAppContextCallback("ApplicationContextCallback: "); callbacks[6] = wsRealmNameCallback = new WSRealmNameCallbackImpl("Realm name:"); callbacks[7] = wsX509CertificateCallback = new WSX509CertificateChainCallback("X509Certificate[]: "); callbacks[8] = wsAuthMechOidCallback = new WSAuthMechOidCallbackImpl("AuthMechOid: "); try { _callbackHandler.handle(callbacks); } catch (Exception e) { // handle exception } if (nameCallback != null) username = nameCallback.getName(); if (passwordCallback != null) passwordChar = passwordCallback.getPassword(); if (wsCredTokenCallback != null) credToken = wsCredTokenCallback.getCredToken(); if (wsServletRequestCallback != null) request = wsServletRequestCallback.getHttpServletRequest(); if (wsServletResponseCallback != null) response = wsServletResponseCallback.getHttpServletResponse(); if (wsAppContextCallback != null) appContext = wsAppContextCallback.getContext(); if (wsRealmNameCallback != null) realm = wsRealmNameCallback.getRealmName(); if (wsX509CertificateCallback != null) certChain = wsX509CertificateCallback.getX509CertificateChain(); if (wsAuthMechOidCallback != null) authMechOid = wsAuthMechOidCallback.getAuthMechOid(); _subject.getPrivateCredentials().add("username = " + username); _subject.getPrivateCredentials().add("password = " + String.valueOf(passwordChar)); _subject.getPrivateCredentials().add("realm = " + realm); _subject.getPrivateCredentials().add("authMechOid = " + authMechOid.toString()); return true; } public boolean commit() throws LoginException { return true; } public boolean abort() { return true; } public boolean logout() { return true; } }- Optional: Develop a sample custom login module using hashtable login.
We can use the following sample to learn on how to use hashtable login.
package com.ibm.websphere.security.sample; import java.util.Map; import javax.security.auth.Subject; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.login.LoginException; import javax.security.auth.spi.LoginModule; import com.ibm.wsspi.security.token.AttributeNameConstants; /** * Custom login module that adds another PublicCredential to the subject */ @SuppressWarnings("unchecked") public class CustomHashtableLoginModule implements LoginModule { protected Map<String, ?> _sharedState; protected Map<String, ?> _options; /** * Initialization of login module */ public void initialize( Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options) { _sharedState = sharedState; _options = options; } public boolean login() throws LoginException { try { java.util.Hashtable<String, Object> customProperties = (java.util.Hashtable<String, Object>) _sharedState.get(AttributeNameConstants.WSCREDENTIAL_PROPERTIES_KEY); if (customProperties == null) { customProperties = new java.util.Hashtable<String, Object>(); } customProperties.put(AttributeNameConstants.WSCREDENTIAL_USERID, "userId"); // Sample of creating custom cache key customProperties.put(AttributeNameConstants.WSCREDENTIAL_CACHE_KEY, "customCacheKey"); /* * Sample for creating user ID and security name * customProperties.put(AttributeNameConstants.WSCREDENTIAL_UNIQUEID, "userId"); * customProperties.put(AttributeNameConstants.WSCREDENTIAL_SECURITYNAME, "securityName"); * customProperties.put(AttributeNameConstants.WSCREDENTIAL_REALM, "realm"); * customProperties.put(AttributeNameConstants.WSCREDENTIAL_GROUPS, "groupList"); */ /* * Sample for creating user ID and password * customProperties.put(AttributeNameConstants.WSCREDENTIAL_USERID, "userId"); * customProperties.put(AttributeNameConstants.WSCREDENTIAL_PASSWORD, "password"); */ Map<String, java.util.Hashtable> mySharedState = (Map<String, java.util.Hashtable>) _sharedState; mySharedState.put(AttributeNameConstants.WSCREDENTIAL_PROPERTIES_KEY, customProperties); } catch (Exception e) { throw new LoginException("LoginException: " + e.getMessage()); } return true; } public boolean commit() throws LoginException { return true; } public boolean abort() { return true; } public boolean logout() { return true; }}
What to do next
Add your custom login module into the WEB_INBOUND, and DEFAULT Java Authentication and Authorization Service (JAAS) system login configurations of server.xml. Put the custom login module class in a JAR file, for example, customLoginModule.jar, then make the JAR file available to the Liberty profile server. See Configure a JAAS custom login module for the Liberty profile.
Parent topic: Develop extensions to the Liberty profile security infrastructure
Related
Configure a JAAS custom login module for the Liberty profile
|