Programmatic login for JAAS


 

+

Search Tips   |   Advanced Search

 

Overview

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. The work of the programmer can be broadly classified in terms of where the actual user authentication is performed:

Users of Web apps can receive prompts for authentication data in many ways. The <login-config> element in the Web app 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 administrative security is enabled. To use form-based login for Web apps, specify FORM in the auth-method tag of the <login-config> element in the deployment descriptor of each Web app.

Applications can present site-specific login forms by using the WAS form-login type. The Java EE spec defines form login as one of the authentication methods for Web apps. WAS provides a form-logout mechanism.

 

Java Authentication and Authorization Service programmatic login

Java Authentication and Authorization Service (JAAS) is a new feature in WAS. It is also mandated by the Java EE 1.4 Specification. JAAS is a collection of strategic authentication APIs that replace the Common Object Request Broker Architecture (CORBA) programmatic login APIs. WAS provides some extensions to JAAS: Before beginning developing with programmatic login APIs, consider the following points:


JAAS login configurations provided

WSLogin JAAS login Used by Java clients, client container applications, servlets, JSP files, and enterprise beans to perform authentication based on...

This configuration does not support the CallbackHandler handler specified in the client container deployment descriptor.

ClientContainer JAAS login Recognizes the CallbackHandler handler specified in the client container deployment descriptor.

Authenticated Subjects contain a principal...

com.ibm.websphere.security.auth.WSPrincipal

...and a credential...

com.ibm.websphere.security.auth.WSCredential

If the authenticated Subject is passed to the method...

com.ibm.websphere.security.auth.WSSubject.doAs

...or the other doAs methods, the WAS security runtime can perform authorization checks on Java EE resources, based on the Subject com.ibm.websphere.security.auth.WSCredential credential.

Customer-defined JAAS login configurations We can define other JAAS login configurations.

The subjects from these customer-defined JAAS login configurations might not be used by the WAS security runtime to perform authorization checks if the subject does not contain the required principal and credentials.

 

Find the root cause login exception from a JAAS login

If we get a LoginException exception after issuing the LoginContext.login API, we 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 with which we can pull out the exception that was wrapped after issuing the previous command.

You are not always guaranteed to get a WSLoginFailedException exception, but most of the exceptions that are generated from the user registry display here.

The following example illustrates a LoginContext.login API with the associated catch block.

To issue the getCause API, cast the class exception...

WSLoginFailedException

...to...

com.ibm.websphere.security.auth.WSLoginFailedException

The following determineCause example 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 javax.naming.NamingException)
                
// check for Ldap embedded exception
                {
                    temp_exception = ((javax.naming.NamingException)e).getRootCause();
                }
            else if (e instanceof my_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 
                
//  Application Server perspective
                return root_exception;
            }
            if (temp_exception != null)
            {
                
// we have an exception; go back and 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

We can also receive the root cause exception from a servlet filter when addressing post-form login processing. This exception is useful because it shows the user what happened.

To obtain the root cause exception:

Throwable t = com.ibm.websphere.security.auth.WSSubject.getRootLoginException();  
if (t != null)  	
         t = determineCause(t);

When we have the exception, we can run it through the previous determineCause example to get the native registry root cause.

 

Enable root cause login exception propagation to pure Java clients

Currently, the root cause does not get propagated to a pure client for security reasons. We might want to propagate the root cause to a pure client in a trusted environment. To enable root cause login exception propagation to a pure client, click...

Security | Global security | Custom Properties

...and set the following property...

com.ibm.websphere.security.registry.propagateExceptionsToClient=true

 

Non-prompt programmatic login

WAS provides a non-prompt implementation of the interface...

javax.security.auth.callback.CallbackHandler

...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 is useful for server-side application code to authenticate an identity and to use that identity to invoke downstream Java EE 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();
    
    
// maybe 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 Java EE 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, JSPs, servlet, or other Java EE resources.

The WSCallbackHandlerImpl callback handler is different depending on whether you use WAS security or WS-Security. It is located in sas.jar for security, and in was-wssecurity.jar for WS-Security.

 

User interface prompt programmatic login

WAS also provides a user interface implementation of the javax.security.auth.callback.CallbackHandler implementation to collect authentication data from a user through user interface login prompts. The callback handler...

com.ibm.websphere.security.auth.callback.WSGUICallbackHandlerImpl

...presents a user interface login panel to prompt users for authentication data.

(UNIX)

This behavior requires an X11 server to be called out by the DISPLAY environment.

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();


// maybe 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 Java EE 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
}

Do not use the callback handler...

com.ibm.websphere.security.auth.callback.WSGUICallbackHandlerImpl

...for server-side resources like enterprise bean, servlet, JSPs, and so on. The user interface login prompt blocks the server for user input. This behavior is not good for a server process.

WAS also provides a Kerberos credential cache implementation of the javax.security.auth.callback.CallbackHandler interface. The callback handler...

com.ibm.websphere.security.auth.callback.WSCcacheCallBackHandlerImpl

Using this interface, an application can push authentication data to the WebSphere LoginModule instance to perform authentication.

This capability is only for the client side application code to authenticate to WAS with the Kerberos credential cache. If the following options exist in wsjaas_client.conf, set them to false:

useDefaultKeytab=false
useDefaultCcache=false
tryFirstPass=false
useFirstPass=false
forwardable=false
renewable=false
renewable=false
noaddress=false

javax.security.auth.login.LoginContext lc = null;

String krb5Ccache = /etc/krb5/krb5cc_utle;

try {
lc = new javax.security.auth.login.LoginContext("WSKRB5Login",
new com.ibm.websphere.security.auth.callback.WSCcacheCallBackHandlerImpl(user, krb5Realm, krb5Ccache, false));

// create a LoginContext and specify a CallbackHandler implementation

// CallbackHandler implementation determines how authentication data is collected

// in this case, the authentication date is collected by stdin prompt

// and passed 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();


// maybe 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 Java EE 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
}

Application Server with the default Kerberos credential cache.

javax.security.auth.login.LoginContext lc = null;

try {
lc = new javax.security.auth.login.LoginContext("WSKRB5Login",
new com.ibm.websphere.security.auth.callback.WSCcacheCallBackHandlerImpl(user, krb5Realm, null, true));

// create a LoginContext and specify a CallbackHandler implementation

// CallbackHandler implementation determines how authentication data is collected

// in this case, the authentication date is collected by stdin prompt

// and passed 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();


// maybe 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 Java EE 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
}

Application Server with the Microsoft native Kerberos credential cache. The client must
login to the Microsoft Domain Controller.

javax.security.auth.login.LoginContext lc = null;

try {
lc = new javax.security.auth.login.LoginContext("WSKRB5Login",
new com.ibm.websphere.security.auth.callback.WSCcacheCallBackHandlerImpl(null, null, null, true));

// create a LoginContext and specify a CallbackHandler implementation

// CallbackHandler implementation determines how authentication data is collected

// in this case, the authentication date is collected by stdin prompt

// and passed 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();


// maybe 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 Java EE 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
}

 

WSKRB5Login module

Generic JAAS login configuration based on a Kerberos principal name password or a Kerberos credential cache to the WAS security runtime. This configuration does not support the CallbackHandler handler specified in the client container deployment descriptor.

Place either the krb5.ini or krb5.conf files we have created in a default location. If either file is not located in the default location set the java.security.krb5.conf JVM system property with the correct path and Kerberos configuration file name.

/etc/krb5/krb5.conf

Kerberos settings, the Kerberos key distribution center (KDC) name, and realm settings are provided in the Kerberos configuration file or through property files...

 

Stdin prompt programmatic login

WAS provides a stdin implementation of the interface...

javax.security.auth.callback.CallbackHandler

The callback handler...

com.ibm.websphere.security.auth.callback.WSStdinCallbackHandlerImpl

...prompts and collects authentication data from a user through the stdin prompt.

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 determines how authentication data is collected
    
// in this case, the authentication date is collected by stdin prompt
    
// and passed 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();
    
    
// maybe 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 Java EE 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, JSPs, and so on. The input from the stdin prompt is not sent to 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 good for a server process.



 

Related tasks

Develop programmatic logins with the Java Authentication and Authorization Service
Customizing application login with Java Authentication and Authorization Service

 

Related

Develop custom login modules for a system login configuration for JAAS
Customizing a server-side Java Authentication and Authorization Service authentication and login configuration
Getting the caller subject from the thread
Getting the RunAs subject from the thread
Overriding the RunAs subject on the thread
Revoking users from a cache
Example: Programmatic logins using BasicAuth