package dk.topsecurity;
import java.io.*;
import java.util.*;
import java.security.Principal;
import javax.security.auth.Subject;
import javax.security.auth.callback.*;
import javax.security.auth.spi.LoginModule;
import javax.security.auth.login.LoginException;
/**
* <p> LoginModule authenticates users from a single credential only
* <p> On successfull authentication, a <code>TopsecurityPrincipal</code> object
* with the user name is added to the Subject.
*/
public class TopsecurityLoginModule implements LoginModule {
// validation objects
private Subject subject;
private TopsecurityPrincipal entity;
private CallbackHandler callbackhandler;
// tracking authentication status
private static final int NOT = 0, OK = 1, COMMIT = 2;
private int status;
/**
* Initializes the LoginModule.<p>
*
* @param subject the Subject to be authenticated as provided through the JAAS interface. <p>
* @param callbackHandler a CallbackHandler for retrieving username and password from the user <p>
* @param sharedState shared LoginModule state. <p>
* @param options options specified in the login Configuration for this particular LoginModule
* (in the java.security.auth.login.config file).
*/
public void initialize(Subject subject, CallbackHandler callbackhandler, Map state, Map options) {
status = NOT;
entity = null;
this.subject = subject;
this.callbackhandler = callbackhandler;
}
/**
* Authenticate the user based on a credential.
* If the credential matches as expected,
* authentication succeeds - otherwise not.<p>
*
* @return true in all cases since this LoginModule should not be ignored.
* @exception FailedLoginException if authentication fails. <p>
* @exception LoginException if this LoginModule is unable to perform the authentication.
*/
public boolean login() throws LoginException {
if(callbackhandler == null) {
throw new LoginException("Error: no CallbackHandler available to retrieve user credentials");
}
Callback callbacks[] = new Callback[1];
callbacks[0] = new NameCallback("Tell me your credential?");
String username = null;
try {
callbackhandler.handle(callbacks); //get the user credential
username = ((NameCallback)callbacks[0]).getName();
} catch(java.io.IOException ioe) {
throw new LoginException(ioe.toString());
} catch(UnsupportedCallbackException ce) {
throw new LoginException("Error: "+ce.getCallback().toString());
}
if(username.equals("Topsecurity")) {
entity = new TopsecurityPrincipal(username);
status = OK;
return true;
} else // not good enough
return false;
}
/**
* <p> Method called if the LoginContext's
* overall authentication succeeded (the relevant REQUIRED,
* REQUISITE, SUFFICIENT and OPTIONAL LoginModules
* mentioned in file java.security.auth.login.config.. did succeed).
*
* <p> If this LoginModule's authentication succeeded
* (status stored in the variable 'status' by the
* .login() method), then the .commit() method associates a
* TopsecurityPrincipal with the Subject located in the
* LoginModule. If this LoginModule's authentication failed,
* any state originally saved is removed. <p>
*
* @exception LoginException if the commit fails.
* @return true if this LoginModule's own .login() and .commit()
* attempts succeeded, false otherwise.
*/
public boolean commit() throws LoginException {
if(status == NOT || subject == null) {
return false;
} else {
Set entities = subject.getPrincipals();
if(!entities.contains(entity)) {
entities.add(entity);
}
status = COMMIT;
return true;
}
}
/**
* <p> This method is called if the LoginContext's
* overall authentication failed.
* (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules
* mentioned in file java.security.auth.login.config.. did not succeed).
*
* <p> If this LoginModule's authentication succeeded
* (status stored in the variable 'status' by the
* .login() method and .commit() methods),
* then the .abort() method cleans up any state that was originally saved. <p>
*
* @exception LoginException if the abort fails.
* @return false if this LoginModule's own login and/or commit attempts
* failed, true otherwise.
*/
public boolean abort() throws LoginException {
if((subject != null) && (entity != null)) {
Set entities = subject.getPrincipals();
if(entities.contains(entity)) {
entities.remove(entity);
}
}
subject = null;
entity = null;
status = NOT;
return true;
}
/**
* Logout the user.
*
* <p> Removes the TopsecurityPrincipal added by the .commit() method. <p>
*
* @exception LoginException if the logout fails.
* @return true in all cases since this LoginModule should not be ignored.
*/
public boolean logout() throws LoginException {
subject.getPrincipals().remove(entity);
status = NOT;
subject = null;
return true;
}
}