|
How to create my own JAAS login module |
|
Subject: How to create my own JAAS login module
Author: authen
In response to: Injection of Customized JAAS Login Module
Posted on: 10/20/2012 12:53:55 AM
package com.myCompany;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.security.Principal;
import com.sun.security.auth.UserPrincipal;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
public class MyLoginModule implements LoginModule {
private Subject subject;
private CallbackHandler callbackHandler;
private Map sharedState;
private Map options;
private boolean succeeded = false;
private String username;
public MyLoginModule() {
System.out.println("My Login Module - Constructor called");
}
@Override
// Required
public boolean abort() throws LoginException {
System.out.println("My Login Module - abort() called");
return false;
}
@Override
// Required
public boolean commit() throws LoginException {
System.out.println("My Login Module - commit() called");
if(succeeded){
Set princSet = subject.getPrincipals();
Principal principal = new UserPrincipal(username);
princSet.add(principal);
}
return succeeded;
}
@Override
// Required
public void initialize(Subject subject,
CallbackHandler callbackHandler,
Map<String, ?> sharedState,
Map<String, ?> options)
{
System.out.println("My Login Module - initialize() called");
this.subject = subject;
this.callbackHandler = callbackHandler;
this.sharedState = sharedState;
this.options = options;
succeeded = false;
}
@Override
// Required
public boolean login() throws LoginException
{
System.out.println("My Login Module - login() called");
if (callbackHandler == null) {
throw new LoginException("Oops, callbackHandler is null");
}
Callback[] callbacks = new Callback[2];
callbacks[0] = new NameCallback("name:");
callbacks[1] = new PasswordCallback("password:", false);
try {
callbackHandler.handle(callbacks);
} catch (IOException e) {
throw new LoginException(
"Oops, IOException calling handle on callbackHandler");
} catch (UnsupportedCallbackException e) {
throw new LoginException("Oops, UnsupportedCallbackException " +
"calling handle on callbackHandler");
}
NameCallback nameCallback = (NameCallback) callbacks[0];
PasswordCallback passwordCallback = (PasswordCallback) callbacks[1];
// name & password from callback handler
String name = nameCallback.getName();
String password = new String(passwordCallback.getPassword());
// options from configuration settings
String option = (String)options.get("anonymousAllowed");
if(password==null || "".equals(password)){
if( option!=null && option.equalsIgnoreCase("true") ){
System.out.println("Succeeded!");
username = name;
succeeded = true;
return succeeded;
}
}else if(authenticate(name, password)){
System.out.println("Succeeded!");
username = name;
succeeded = true;
return succeeded;
}
System.out.println("Failed!");
succeeded = false;
throw new FailedLoginException("Name and password not matched.");
}
@Override
// Required
public boolean logout() throws LoginException {
System.out.println("My Login Module - logout() called");
return false;
}
private boolean authenticate(String name, String password)
{
/* just an exmaple, you can put whatever your authenticating logic here */
return name.equals(password);
}
}
>
> On 10/20/2012 12:48:48 AM authen wrote:
In order for your customized login module to be injected, you have to tell JAAS the following: Where to find your configuration file; Which login module to load and how it is loaded.
Where to find your configuration file? If you name your JAAS login configuration file as jaas_login.conf and put it under directory c:\temp, then you can instruct your JVM to find it by property setting:
System.setProperty("java.security.auth.login.config", "c:\\temp\\jaas_login.conf");
Which login module to load and how it is loaded? The configuration file has the following structure:
myLoginEntity {
ModuleClass Flag Options;
ModuleClass Flag Options;
...
};
myLoginEntity {
ModuleClass Flag Options;
...
};
...
As an example:
myLoginEntity {
com.sun.security.auth.module.Krb5LoginModule required
principal="myName@MY_REALM"
useTicketCache=true
ticketCache="C:\\temp\\krb5cc_myName"
renewTGT=true
useKeyTab=true
keyTab="C:\\temp\\myName.keytab"
storeKey=true;
};
Which instructs that Krb5LoginModule is to be injected with required flag and the corresponding options: using principal myName@MY_REALM as login name and retrieving TGT ticket from cache C:\temp\krb5cc_myName; if a valid ticket found, no need to proceed. if ticket expired (renewTGT=true) or ticket not found, retrieving the private key from keytab C:\temp\myName.keytab; if key is not found, prompting user for password input; requesting Kerberos authentication to KDC by using the above principal and private key (or password); Confirmed by WireShark traffic KRB5 with AS-REQ/AS-REP storing (storeKey=true) the private key into Subject's private space after successful authentication.
Note: By spec, when multiple mechanisms to retrieve a ticket or key is provided, the preference order looks like this: ---- 1. ticket cache ---- 2. keytab ---- 3. shared state ---- 4. user prompt For example, if "principal" is provided both from config and user specified, the value from config would take precedence. The keyTab's path must be double-quote protected, otherwise exception would be thrown. The back-slash (\) in path must be escaped(\\), otherwise, keyTab would be ignored and the user's password would be used instead.
References:
|
|
|
|