...
A Principal is an entity that is authenticated.
...
Coding
AuthenticationHandler
The core interface to implement for your authentication-handling plugin is AuthenticationHandler.
...
You can code directly to this interface, or you .
Our trivial example
Suppose that the credentials we're examining consist of usernames and passwords and that we want to authenticate where the password is the integer representation of the length of the username.
Code Block | ||
---|---|---|
| ||
/**
* Authenticates where the presented password is the integer length of the
* username.
*/
public class UsernameLengthAuthnHandler
implements AuthenticationHandler {
public boolean authenticate(Credentials credentials) throws AuthenticationException {
UsernamePasswordCredentials upCredentials =
(UsernamePasswordCredentials) credentials;
String username = upCredentials.getUsername();
String password = upCredentials.getPassword();
String correctPassword =
Integer.toString(username.length());
return correctPassword.equals(password);
}
public boolean supports(Credentials credentials) {
// we support credentials that bear usernames and passwords
return credentials instanceof UsernamePasswordCredentials;
}
}
|
See the Using the REMOTE_USER example for a more advanced example of coding directly to AuthenticationHandler to accomplish something other than username and password authentication.
AuthenticationHandlers that take usernames and passwords
You can extend AbstractUsernamePasswordAuthenticationHandler if you're dealing with usernames and passwords.
Code Block | ||
---|---|---|
| ||
/** * Abstract class to override supports so that we don't need to duplicate the * check for UsernamePasswordCredentials. * * @version $Revision: 1.12 $ $Date: 2005/06/20 18:15:36 $ */ public abstract class AbstractUsernamePasswordAuthenticationHandler implements AuthenticationHandler, InitializingBean { /** * PasswordEncoder to be used by subclasses to encode passwords for * comparing against a resource. */ private PasswordEncoder passwordEncoder; /** Instance of logging for subclasses. */ private Log log = LogFactory.getLog(this.getClass()); /** * Method automatically handles conversion to UsernamePasswordCredentials * and delegates to abstract authenticateUsernamePasswordInternal so * subclasses do not need to cast. */ public final boolean authenticate(final Credentials credentials) throws AuthenticationException { return authenticateUsernamePasswordInternal((UsernamePasswordCredentials) credentials); } /** * Abstract convenience method that assumes the credentials passed in are a * subclass of UsernamePasswordCredentials. * * @param credentials the credentials representing the Username and Password * presented to CAS * @return true if the credentials are authentic, false otherwise. * @throws AuthenticationException if authenticity cannot be determined. */ protected abstract boolean authenticateUsernamePasswordInternal( final UsernamePasswordCredentials credentials) throws AuthenticationException; public final void afterPropertiesSet() throws Exception { if (this.passwordEncoder == null) { this.passwordEncoder = new PlainTextPasswordEncoder(); getLog().info( "No PasswordEncoder set. Using default: " + this.passwordEncoder.getClass().getName()); } afterPropertiesSetInternal(); } /** * Method designed to be overwritten subclasses that need to do additional * properties checking. * * @throws Exception if there is an error checking the properties. */ protected void afterPropertiesSetInternal() throws Exception { // this is designed to be overwritten } /** * Method to return the PasswordEncoder to be used to encode passwords. * * @return the PasswordEncoder associated with this class. */ public final PasswordEncoder getPasswordEncoder() { return this.passwordEncoder; } /** * Method to return the log instance in order for subclasses to have access * to the log object. * * @return the logging instance for this class. */ public final Log getLog() { return this.log; } /** * Sets the PasswordEncoder to be used with this class. * * @param passwordEncoder the PasswordEncoder to use when encoding * passwords. */ public final void setPasswordEncoder(final PasswordEncoder passwordEncoder) { this.passwordEncoder = passwordEncoder; } /** * @return true if the credentials are not null and the credentials class is * assignable from UsernamePasswordCredentials. */ public final boolean supports(final Credentials credentials) { return credentials != null && UsernamePasswordCredentials.class.isAssignableFrom(credentials .getClass()); } } |
Our trivial example revisited
Suppose again that the password for any given username is the number of letters in that username.
By extending the abstract class, we can implement this handler more simply. The abstract class handles casting the Credentials to a UsernamePasswordCredentials and handles implementing the supports() method.
Code Block | ||
---|---|---|
| ||
package org.jasig.cas.authentication.handler.support; import org.jasig.cas.authentication.handler.AuthenticationException; import org.jasig.cas.authentication.principal.UsernamePasswordCredentials; /** * Authenticates where the presented password is the integer length of the * username. */ public class UsernameLengthAuthnHandler extends AbstractUsernamePasswordAuthenticationHandler { protected boolean authenticateUsernamePasswordInternal( UsernamePasswordCredentials credentials) throws AuthenticationException { String username = credentials.getUsername(); String password = credentials.getPassword(); String correctPassword = Integer.toString(username.length()); return correctPassword.equals(password); } } |