TopsecurityLoginModule.java
- LoginModule is the heart of all JAAS systems
- this is where the final yes/no decisions are made during authentication - this is
where you put your own complicated validation routinesTopsecurityCallbackHandler.java
- interfaces user input with the security
mechanismsTopsecurityPrincipal.java
- basicly an object representation of the acknowledged
identity within the JAAS fremeworkjava.security.auth.login.config
TopsecurityClient.java
- to initiate the actual JAAS login as
seen from the basic client perspectivejava.security.auth.login.config
."-Djava.security.auth.login.config=..."
or have performed a System.setProperty("java.security.auth.policy", "...");
before calling the .login method.TopsecurityClient.java
package dk.topsecurity; import javax.security.auth.Subject; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; /** * |
TopsecurityLoginModule.java
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; } } |
initialize
: initializes LoginModule
- hereby saving a reference to the Subject, which is used to
save the Principal
and Credential(s)
after a successfull authentication.
login
: requests LoginModule
to authenticate
Subject
. Principal
is created after successfull
authentication and later added to a set in the subject (in the .commit method)commit
: tihs method is called after LoginContext
authenticates succesfully (returns boolean true).abort
: informs LoginModule
about failed authentication subject. logout
: logs out Subject
by removing Principal
s and Credential(s)
s from the Subject
object.(new BufferedReader(new InputStreamReader(System.in))).readLine()
to interactively retrieve a credential from the user at a command prompt. It
_could_ equally well fetch a password - but that is not done currently. TopsecurityCallbackHandler.java
package dk.topsecurity; import java.io.*; import javax.security.auth.*; import javax.security.auth.callback.*; public class TopsecurityCallbackHandler implements CallbackHandler { public void handle(Callback callbacks[]) throws IOException, UnsupportedCallbackException { for(int i=0;i<callbacks.length;i++) { if(callbacks[i] instanceof NameCallback) { NameCallback nc = (NameCallback) callbacks[0]; System.err.print(nc.getPrompt()); System.err.flush(); String name = (new BufferedReader(new InputStreamReader(System.in))).readLine(); nc.setName(name); } else { throw(new UnsupportedCallbackException(callbacks[i], "Callback handler not support")); } } } } |
TopsecurityPrincipal.java
package dk.topsecurity; import java.security.Principal; /** * <p> TopsecurityPrincipal class implements the * java.security.Principal interface and represents a user, who is * successfully authenticated in the LoginModule.. * * <p> Principals such as this <code>TopsecurityPrincipal</code> * may be associated with a particular <code>Subject</code> * to augment that <code>Subject</code> with an additional * identity. Authorization decisions can then be based upon * the Principals associated with a <code>Subject</code>. * * @see java.security.Principal * @see javax.security.auth.Subject */ public class TopsecurityPrincipal implements Principal { private final String name; /** * Create TopsecurityPrincipal representing user with username provided.<p> * * @param name the username for this user. * @exception NullPointerException if the <code>name</code> is <code>null</code>. */ public TopsecurityPrincipal(String name) { if(name == null) { throw new IllegalArgumentException("Null name"); } this.name = name; } /** * Returns username for this <code>TopsecurityPrincipal</code>.<p> * * @return the username for this <code>TopsecurityPrincipal</code> */ public String getName() { return name; } /** * Return a string representation of this <code>TopsecurityPrincipal</code>.<p> * * @return a string representation of this <code>TopsecurityPrincipal</code>. */ public String toString() { return "TopsecurityPrincipal: "+name; } /** * Compares the specified Object with this <code>TopsecurityPrincipal</code>. * True if the given object is also a <code>TopsecurityPrincipal</code> * with the same username.<p> * * @param o Object to be compared for equality with .this * @return true if the specified Object is equal equal to .this */ public boolean equals(Object obj) { if(obj == null) return false; if(obj == this) return true; if(!(obj instanceof TopsecurityPrincipal)) return false; TopsecurityPrincipal another = (TopsecurityPrincipal) obj; return name.equals(another.getName()); } /** * Return a hash code for this <code>TopsecurityPrincipal</code>.<p> * * @return a hash code for this <code>TopsecurityPrincipal</code>. */ public int hasCode() { return name.hashCode(); } } |
TopsecurityLogin.conf
TopsecurityJAASModule { dk.topsecurity.TopsecurityLoginModule required; }; |
build.xml
<project name="javacert" default="all" basedir=".\"> <target name="clean"> <delete quiet="true" dir=".\build"/> <delete quiet="true" dir=".\javadoc"/> <mkdir dir="./build"/> </target> <target name="compile"> <javac srcdir="./source" destdir=".\build"/> </target> <target name="package"> <jar destfile="./topsecurity.jar" basedir="./build" includes="**"> <manifest> <attribute name="Main-class" value="dk.topsecurity.TopsecurityClient"/> <attribute name="Built-By" value="http://www.topsecurity.dk"/> <section name="suncertify/server/"> <attribute name="Sealed" value="false"/> </section> <attribute name="Specification-Title" value="Topsecurity JAAS Example"/> <attribute name="Specification-Version" value="1.0"/> <attribute name="Specification-Vendor" value="http://www.topsecurity.dk"/> <attribute name="Implementation-Title" value="Topsecurity JAAS Example"/> <attribute name="Implementation-Version" value="1.0"/> <attribute name="Implementation-Vendor" value="http://www.topsecurity.dk"/> </manifest> </jar> </target> <target name="all" depends="clean,compile,package"> </target> </project> |