Programmatic login
Programmatic login is a type of form login that supports application presentation site-specific login forms for the purpose of authentication.
When enterprise bean client applications require the user to provide identifying information, the writer of the application must collect that information and authenticate the user. You can broadly classify the work of the programmer in terms of where the actual user authentication is performed...
- In a client program
- In a server program
Users of Webapplications can receive prompts for authentication data in many ways. The <login-config> element in the web application (.war) deployment descriptor file defines the mechanism used to collect this information. Programmers who want to customize login procedures, rather than relying on general purpose devices like a 401 dialog window in a browser, can use a form-based login to provide an application-specific HTML form for collecting login information.
No authentication occurs unless WebSphere global security is enabled. If you want to use form-based login for Webapplications, specify FORM in the auth-method tag of the <login-config> element in the deployment descriptor of each web application (.war).
Applications can present site-specific login forms by using the WebSphere form-login type. The Java 2 Platform, Enterprise Edition (J2EE) specification defines form login as one of the authentication methods for Webapplications. However, the Servlet Version 2.2 specification does not define a mechanism for logging out. WAS extends J2EE by also providing a form-logout mechanism.
Java Authentication and Authorization Service programmatic login
JAAS is a new feature in WAS. It is also mandated by the J2EE 1.3 Specification. JAAS is a collection of WebSphere strategic authentication APIs and replace of the CORBA programmatic login APIs. WebSphere Application Server provides some extensions to JAAS...
Before you begin developing with programmatic login APIs, consider the following points ...
- For the pure Java client application or client container application, initialize the client Object Request Broker (ORB) security prior to performing a JAAS login. Do this by executing the following code prior to the JAAS login...
For more information, see Example... JAAS programmatic login.... import java.util.Hashtable; import javax.naming.Context; import javax.naming.InitialContext; ... // Perform an InitialContext and default lookup prior to logging // in to initialize ORB security and for the bootstrap host/port // to be determined for SecurityServer lookup. If you do not want // to validate the userid/password during the JAAS login, disable // the com.ibm.CORBA.validateBasicAuth property in the // sas.client.props file. Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.ibm.websphere.naming.WsnInitialContextFactory"); env.put(Context.PROVIDER_URL, "corbaloc:iiop:myhost.companyname.com:2809"); Context initialContext = new InitialContext(env); Object obj = initialContext.lookup("");- For the pure Java client application or client container application, make sure that the host name and the port number of the target JNDI bootstrap properties are specified properly. See the Developing applications that use CosNaming (CORBA Naming interface) section for details.
- If the application uses custom JAAS login configuration, make sure that the custom JAAS login configuration is properly defined. See the JAAS Login Configuration section for details.
- Some of the JAAS APIs are protected by Java 2 security permissions. If these APIs are used by application code, make sure that these permissions are added to the application was.policy file. See Adding the was.policy file to the application, Using policytool to edit policy file. For more details of which APIs are protected by Java 2 Security permissions, check the IBM Developer Kit, Java edition; JAAS and the WebSphere public APIs Javadoc for more details. The following list indicates the APIs used in the samples code provided in this documentation.
- javax.security.auth.login.LoginContext constructors are protected by javax.security.auth.AuthPermission "createLoginContext".
- javax.security.auth.Subject.doAs() and com.ibm.websphere.security.auth.WSSubject.doAs() are protected by javax.security.auth.AuthPermission "doAs".
- javax.security.auth.Subject.doAsPrivileged() and com.ibm.websphere.security.auth.WSSubject.doAsPrivileged() are protected by javax.security.auth.AuthPermission "doAsPrivileged".
- com.ibm.websphere.security.auth.WSSubject: Due to a design oversight in the JAAS 1.0, javax.security.auth.Subject.getSubject() does not return the Subject associated with the thread of execution inside a java.security.AccessController.doPrivileged() code block. This can present an inconsistent behavior that is problematic and causes undesirable effort. The com.ibm.websphere.security.auth.WSSubject API provides a work around to associate Subject to thread of execution. The com.ibm.websphere.security.auth.WSSubject API extends the JAAS model to J2EE resources for authorization checks. The Subject associated with the thread of execution within com.ibm.websphere.security.auth.WSSubject.doAs() or com.ibm.websphere.security.auth.WSSubject.doAsPrivileged() code block is used for J2EE resources authorization checks.
- UI support for defining new JAAS login configuration: You can configure JAAS login configuration in the administrative console and store it in WCCM (WebSphere Common Configuration Model). Applications can define new JAAS login configuration in the administratiave console and the the data is persisted in the configuration respository (stored in the WCCM). However, WebSphere Application Server still supports the default JAAS login configuration format (plain text file) provided by the JAAS default implementation. But if there are duplication login configurations defined in both the WCCM and the plain text file format, the one in the WCCM takes precedence. There are advantages to defining the login configuration in the WCCM...
- UI support in defining JAAS login configuration.
- You can manage the JAAS configuration login configuration centrally.
- The JAAS configuration login configuration is distributed in a Network Deployment installation.
- WebSphere JAAS login configurations: WebSphere provides JAAS login configurations for application to perform programmatic authentication to the WebSphere security run time. These WebSphere JAAS login configurations perform authentication to the WebSphere configured authentication mechanism SWAM(or LTPA) and user registry (Local OS, LDAP or Custom) based on the authentication data supplied. The authenticated Subject from these JAAS login configurations contain the required Principal and Credentials that can be used by WebSphere security run time to perform authorization checks on J2EE role-based protected resources. Here is the JAAS login configurations provided by WebSphere...
- WSLogin JAAS login configuration: A generic JAAS login configuration that a Java Client, client container application, servlet, JSP file, enterprise bean, and so on, can use to perform authentication based on a user ID and password, or a token to the WebSphere security run time. However, this does not honor the CallbackHandler specified in the Client Container deployment descriptor.
- ClientContainer JAAS login configuration: This JAAS login configuration honors the CallbackHandler specified in the client container deployment descriptor. The login module of this login configuration uses the CallbackHandler in the client container deployment descriptor if one is specified, even if the application code specified one CallbackHandler in the LoginContext. This is for client container application.
- Subject authenticated with the previously mentioned JAAS login configurations contain a com.ibm.websphere.security.auth.WSPrincipal and a com.ibm.websphere.security.auth.WSCredential. If the authenticated Subject is passed the in com.ibm.websphere.security.auth.WSSubject.doAs() (or the other doAs() methods), the WebSphere security run time can perform authorization checks on J2EE resources, based on the Subject com.ibm.websphere.security.auth.WSCredential.
- Customer-defined JAAS login configurations: You can define other JAAS login configurations. See Configuring JAAS login configuration section for details. Use these login configurations to perform programmatic authentication to the customer authentication mechanism. However, the subjects from these customer-defined JAAS login configurations might not be used by WebSphere security run time to perform authorization checks if the subject does not contain the required principal and credentials.
Finding the root cause login exception from a JAAS login
If you get a LoginException after issuing the LoginContext.login() API, you can find the root cause exception from the configured user registry. In the login modules, the registry exceptions are wrapped by a com.ibm.websphere.security.auth.WSLoginFailedException. This exception has a getCause() method that allows you to pull out the exception that was wrapped after issuing the above command.
You are not always guaranteed to get an exception of type WSLoginFailedException, but note that most of the exceptions generated from the user registry show up here.The following is a LoginContext.login() API example with associated catch block. WSLoginFailedException has to be casted to com.ibm.websphere.security.auth.WSLoginFailedException if you want to issue the getCause() API.
Note that The determineCause() example below can be used for processing CustomUserRegistry exception types.
try { lc.login(); } catch (LoginException le) { // drill down through the exceptions as they might cascade through the runtime Throwable root_exception = determineCause(le); // now you can use "root_exception" to compare to a particular exception type // for example, if you have implemented a CustomUserRegistry type, you would // know what to look for here. } /* Method used to drill down into the WSLoginFailedException to find the "root cause" exception */ public Throwable determineCause Throwable(e) { Throwable root_exception = e, temp_exception = null; // keep looping until there are no more embedded WSLoginFailedException or // WSSecurityException exceptions while (true) { if (e instanceof com.ibm.websphere.security.auth.WSLoginFailedException) { temp_exception = ((com.ibm.websphere.security.auth.WSLoginFailedException) e).getCause(); } else if (e instanceof com.ibm.websphere.security.WSSecurityException) { temp_exception = ((com.ibm.websphere.security.WSSecurityException) e).getCause(); } else if (e instanceof com.ibm.ws.security.registry.nt.NTException) // get NT specific error code, if configured { System.out.println ("Error code from NT exception: " + ((com.ibm.ws.security.registry.nt.NTException)e).getErrorCode()); return e; } else if (e instanceof com.ibm.ws.security.registry.unix.UnixRegistryException) // get Unix specific error code, if configured { System.out.println ("Error code from Unix exception: " + ((com.ibm.ws.security.registry.unix.UnixRegistryException)e).getErrorCode()); return e; } else if (e instanceof javax.naming.NamingException) // check for Ldap embedded exception { temp_exception = ((javax.naming.NamingException)e).getRootCause(); } else if (e instanceof your_custom_exception_here) { // your custom processing here, if necessary } else { // this exception is not one of the types we are looking for, // lets return now, this is the root from the WebSphere perspective return root_exception; } if (temp_exception != null) { // we have an exception, let's go back an see if this has another // one embedded within it. root_exception = temp_exception; e = temp_exception; continue; } else { // we finally have the root exception from this call path, this // has to occur at some point return root_exception; } } }
Finding the root cause login exception from a Servlet filter
You can also receive the root cause exception from a servlet filter when addressing post-Form Login processing. This is suitable because it shows the user what happened. The following API can be issued to obtain the root cause exception:
Throwable t = com.ibm.websphere.security.auth.WSSubject.getRootLoginException(); if (t != null) t = determineCause(t);Note that Once you have the exception you can run it through the determineCause() example above to get the native registry root cause.
Enabling root cause login exception propagation to pure Java clients
Currently, the root cause does not get propagated to a pure client for security reasons. However, you might want to propagate the root cause to a pure client in a trusted environment. If you want to enable root cause login exception propagation to a pure client, click Security > Global Security > Custom Properties on the WebSphere Application Server administrative console and set the following property...
com.ibm.websphere.security.registry.propagateExceptionsToClient=true
Non-prompt programmatic login
WebSphere Application Server provides a non-prompt implementation of the javax.security.auth.callback.CallbackHandler interface, which is called com.ibm.websphere.security.auth.callback.WSCallbackHandlerImpl. Using this interface, an application can push authentication data to the WebSphere LoginModule instance to perform authentication. This capability proves useful for server-side application code to authenticate an identity and to use that identity to invoke downstream J2EE resources.
javax.security.auth.login.LoginContext lc = null; try { lc = new javax.security.auth.login.LoginContext("WSLogin", new com.ibm.websphere.security.auth.callback.WSCallbackHandlerImpl("user", "securityrealm", "securedpassword")); // create a LoginContext and specify a CallbackHandler implementation // CallbackHandler implementation determine how authentication data is collected // in this case, the authentication data is "push" to the authentication mechanism // implemented by the LoginModule. } catch javax.security.auth.login.LoginException(e) { System.err.println("ERROR: failed to instantiate a LoginContext and the exception: " + e.getMessage()); e.printStackTrace(); // may be javax.security.auth.AuthPermission "createLoginContext" is not granted // to the application, or the JAAS login configuration is not defined. } if (lc != null) try { lc.login(); // perform login javax.security.auth.Subject s = lc.getSubject(); // get the authenticated subject // Invoke a J2EE resource using the authenticated subject com.ibm.websphere.security.auth.WSSubject.doAs(s, new java.security.PrivilegedAction() { public Object run() { try { bankAccount.deposit(100.00); // where bankAccount is a protected EJB } catch Exception(e) { System.out.println("ERROR: error while accessing EJB resource, exception: " + e.getMessage()); e.printStackTrace(); } return null; } } ); } catch javax.security.auth.login.LoginException(e) { System.err.println("ERROR: login failed with exception: " + e.getMessage()); e.printStackTrace(); // login failed, might want to provide relogin logic }Use the com.ibm.websphere.security.auth.callback.WSCallbackHandlerImpl callback handler with a pure Java client, a client application container, enterprise bean, JSP files, servlet, or other Java 2 Platform, Enterprise Edition (J2EE) resources. See Example... JAAS programmatic login for more information about object request broker (ORB) security initialization requirements in a Java pure client.
User interface prompt programmatic login
WebSphere Application Server also provides a user interface implementation of the javax.security.auth.callback.CallbackHandler implementation to collect authentication data from user through user interface login prompts. This callack handler, com.ibm.websphere.security.auth.callback.WSGUICallbackHandlerImpl, presents a user interface login panel to prompt users for authentication data.
javax.security.auth.login.LoginContext lc = null; try { lc = new javax.security.auth.login.LoginContext("WSLogin", new com.ibm.websphere.security.auth.callback.WSGUICallbackHandlerImpl()); // create a LoginContext and specify a CallbackHandler implementation // CallbackHandler implementation determine how authentication data is collected // in this case, the authentication date is collected by GUI login prompt // and pass to the authentication mechanism implemented by the LoginModule. } catch javax.security.auth.login.LoginException(e) { System.err.println("ERROR: failed to instantiate a LoginContext and the exception: " + e.getMessage()); e.printStackTrace(); // may be javax.security.auth.AuthPermission "createLoginContext" is not granted // to the application, or the JAAS login configuration is not defined. } if (lc != null) try { lc.login(); // perform login javax.security.auth.Subject s = lc.getSubject(); // get the authenticated subject // Invoke a J2EE resources using the authenticated subject com.ibm.websphere.security.auth.WSSubject.doAs(s, new java.security.PrivilegedAction() { public Object run() { try { bankAccount.deposit(100.00); // where bankAccount is a protected enterprise bean } catch Exception(e) { System.out.println("ERROR: error while accessing EJB resource, exception: " + e.getMessage()); e.printStackTrace(); } return null; } } ); } catch javax.security.auth.login.LoginException(e) { System.err.println("ERROR: login failed with exception: " + e.getMessage()); e.printStackTrace(); // login failed, might want to provide relogin logic }Note that Do not use the com.ibm.websphere.security.auth.callback.WSGUICallbackHandlerImpl callback handler for server-side resources (like enterprise bean, servlet, JSP file, or any other server side resources). The user interface login prompt blocks the server for user input. This behavior is not desirable for a server process.
Stdin prompt programmatic login
WebSphere Application Server also provides a stdin implementation of the javax.security.auth.callback.CallbackHandler interface to collect authentication data from a user through stdin, which is called com.ibm.websphere.security.auth.callback.WSStdinCallbackHandlerImpl. This callback handler prompts a user for authentication data.
javax.security.auth.login.LoginContext lc = null; try { lc = new javax.security.auth.login.LoginContext("WSLogin", new com.ibm.websphere.security.auth.callback.WSStdinCallbackHandlerImpl()); // create a LoginContext and specify a CallbackHandler implementation // CallbackHandler implementation determine how authentication data is collected // in this case, the authentication date is collected by stdin prompt // and pass to the authentication mechanism implemented by the LoginModule. } catch javax.security.auth.login.LoginException(e) { System.err.println("ERROR: failed to instantiate a LoginContext and the exception: " + e.getMessage()); e.printStackTrace(); // may be javax.security.auth.AuthPermission "createLoginContext" is not granted // to the application, or the JAAS login configuration is not defined. } if (lc != null) try { lc.login(); // perform login javax.security.auth.Subject s = lc.getSubject(); // get the authenticated subject // Invoke a J2EE resource using the authenticated subject com.ibm.websphere.security.auth.WSSubject.doAs(s, new java.security.PrivilegedAction() { public Object run() { try { bankAccount.deposit(100.00); // where bankAccount is a protected enterprise bean } catch Exception(e) { System.out.println("ERROR: error while accessing EJB resource, exception: " + e.getMessage()); e.printStackTrace(); } return null; } } ); } catch javax.security.auth.login.LoginException(e) { System.err.println("ERROR: login failed with exception: " + e.getMessage()); e.printStackTrace(); // login failed, might want to provide relogin logic }Do not use the com.ibm.websphere.security.auth.callback.WSStdinCallbackHandlerImpl callback handler for server side resources (like enterprise beans, servlets, JSP files, and so on). The stdin prompt does not make send in the server environment, most servers run in the background and do not have a console. However, if the server does have a console, the stdin prompt blocks the server for user input. This behavior is not desirable for a server process.
See Also
Getting the RunAs Subject from the Thread
Overriding the RunAs Subject on the Thread
Customizing a server-side Java Authentication and Authorization Service authentication and login configuration
Getting the Caller Subject from the Thread
Example: JAAS programmatic login
User revocation from a cache