JAASRealmpublic class JAASRealm extends RealmBase Implmentation of Realm that authenticates users via the Java
Authentication and Authorization Service (JAAS). JAAS support requires
either JDK 1.4 (which includes it as part of the standard platform) or
JDK 1.3 (with the plug-in jaas.jar file).
The value configured for the appName property is passed to
the javax.security.auth.login.LoginContext constructor, to
specify the application name used to select the set of relevant
LoginModules required.
The JAAS Specification describes the result of a successful login as a
javax.security.auth.Subject instance, which can contain zero
or more java.security.Principal objects in the return value
of the Subject.getPrincipals() method. However, it provides
no guidance on how to distinguish Principals that describe the individual
user (and are thus appropriate to return as the value of
request.getUserPrincipal() in a web application) from the Principal(s)
that describe the authorized roles for this user. To maintain as much
independence as possible from the underlying LoginMethod
implementation executed by JAAS, the following policy is implemented by
this Realm:
- The JAAS
LoginModule is assumed to return a
Subject with at least one Principal instance
representing the user himself or herself, and zero or more separate
Principals representing the security roles authorized
for this user.
- On the
Principal representing the user, the Principal
name is an appropriate value to return via the Servlet API method
HttpServletRequest.getRemoteUser() .
- On the
Principals representing the security roles, the
name is the name of the authorized security role.
- This Realm will be configured with two lists of fully qualified Java
class names of classes that implement
java.security.Principal - one that identifies class(es)
representing a user, and one that identifies class(es) representing
a security role.
- As this Realm iterates over the
Principals returned by
Subject.getPrincipals() , it will identify the first
Principal that matches the "user classes" list as the
Principal for this user.
- As this Realm iterates over the
Princpals returned by
Subject.getPrincipals() , it will accumulate the set of
all Principals matching the "role classes" list as
identifying the security roles for this user.
- It is a configuration error for the JAAS login method to return a
validated
Subject without a Principal that
matches the "user classes" list.
|
Fields Summary |
---|
private static com.sun.org.apache.commons.logging.Log | log | protected String | appNameThe application name passed to the JAAS LoginContext ,
which uses it to select the set of relevant LoginModules . | protected static final String | infoDescriptive information about this Realm implementation. | protected static final String | nameDescriptive information about this Realm implementation. | protected ArrayList | roleClassesThe list of role class names, split out for easy processing. | protected static final org.apache.catalina.util.StringManager | smThe string manager for this package. | protected ArrayList | userClassesThe set of user class names, split out for easy processing. | protected String | roleClassNamesComma-delimited list of javax.security.Principal classes
that represent security roles. | protected String | userClassNamesComma-delimited list of javax.security.Principal classes
that represent individual users. |
Methods Summary |
---|
public java.security.Principal | authenticate(java.lang.String username, java.lang.String credentials)Return the Principal associated with the specified username and
credentials, if there is one; otherwise return null .
If there are any errors with the JDBC connection, executing
the query or anything we return null (don't authenticate). This
event is also logged, and the connection will be closed so that
a subsequent request will automatically re-open it.
// Establish a LoginContext to use for authentication
try {
LoginContext loginContext = null;
if( appName==null ) appName="Tomcat";
if( log.isDebugEnabled())
log.debug("Authenticating " + appName + " " + username);
// What if the LoginModule is in the container class loader ?
//
ClassLoader ocl=Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
try {
loginContext = new LoginContext
(appName, new JAASCallbackHandler(this, username,
credentials));
} catch (Throwable e) {
log.debug("Error initializing JAAS: " + e.toString());
log.debug(sm.getString("jaasRealm.loginException", username), e);
return (null);
} finally {
Thread.currentThread().setContextClassLoader(ocl);
}
if( log.isDebugEnabled())
log.debug("Login context created " + username);
// Negotiate a login via this LoginContext
Subject subject = null;
try {
loginContext.login();
subject = loginContext.getSubject();
if (subject == null) {
if( log.isDebugEnabled())
log.debug(sm.getString("jaasRealm.failedLogin", username));
return (null);
}
} catch (AccountExpiredException e) {
if (log.isDebugEnabled())
log.debug(sm.getString("jaasRealm.accountExpired", username));
return (null);
} catch (CredentialExpiredException e) {
if (log.isDebugEnabled())
log.debug(sm.getString("jaasRealm.credentialExpired", username));
return (null);
} catch (FailedLoginException e) {
if (log.isDebugEnabled())
log.debug(sm.getString("jaasRealm.failedLogin", username));
return (null);
} catch (LoginException e) {
log.debug(sm.getString("jaasRealm.loginException", username), e);
return (null);
} catch (Throwable e) {
log.debug("Unexpected error", e);
return (null);
}
if( log.isDebugEnabled())
log.debug("Getting principal " + subject);
// Return the appropriate Principal for this authenticated Subject
Principal principal = createPrincipal(username, subject);
if (principal == null) {
log.debug(sm.getString("jaasRealm.authenticateFailure", username));
return (null);
}
if (log.isDebugEnabled()) {
log.debug(sm.getString("jaasRealm.authenticateSuccess", username));
}
return (principal);
} catch( Throwable t) {
log.error( "error ", t);
return null;
}
| protected java.security.Principal | createPrincipal(java.lang.String username, javax.security.auth.Subject subject)Construct and return a java.security.Principal instance
representing the authenticated user for the specified Subject. If no
such Principal can be constructed, return null .
// Prepare to scan the Principals for this Subject
String password = null; // Will not be carried forward
ArrayList roles = new ArrayList();
// Scan the Principals for this Subject
Iterator principals = subject.getPrincipals().iterator();
while (principals.hasNext()) {
Principal principal = (Principal) principals.next();
// No need to look further - that's our own stuff
if( principal instanceof GenericPrincipal ) {
if( log.isDebugEnabled() )
log.debug("Found old GenericPrincipal " + principal );
return principal;
}
String principalClass = principal.getClass().getName();
if( log.isDebugEnabled() )
log.info("Principal: " + principalClass + " " + principal);
if (userClasses.contains(principalClass)) {
// Override the default - which is the original user, accepted by
// the friendly LoginManager
username = principal.getName();
}
if (roleClasses.contains(principalClass)) {
roles.add(principal.getName());
}
// Same as Jboss - that's a pretty clean solution
if( (principal instanceof Group) &&
"Roles".equals( principal.getName())) {
Group grp=(Group)principal;
Enumeration en=grp.members();
while( en.hasMoreElements() ) {
Principal roleP=(Principal)en.nextElement();
roles.add( roleP.getName());
}
}
}
// Create the resulting Principal for our authenticated user
if (username != null) {
return (new GenericPrincipal(this, username, password, roles));
} else {
return (null);
}
| public java.lang.String | getAppName()getter for the appName member variable
return appName;
| protected java.lang.String | getName()Return a short name for this Realm implementation.
return (this.name);
| protected java.lang.String | getPassword(java.lang.String username)Return the password associated with the given principal's user name.
return (null);
| protected java.security.Principal | getPrincipal(java.lang.String username)Return the Principal associated with the given user name.
return (null);
| public java.lang.String | getRoleClassNames()
return (this.roleClassNames);
| public java.lang.String | getUserClassNames()
return (this.userClassNames);
| public void | setAppName(java.lang.String name)setter for the appName member variable
// ------------------------------------------------------------- Properties
appName = name;
| public void | setContainer(org.apache.catalina.Container container)
super.setContainer(container);
String name=container.getName();
if( appName==null ) {
appName=name;
log.info("Setting JAAS app name " + appName);
}
| public void | setRoleClassNames(java.lang.String roleClassNames)
this.roleClassNames = roleClassNames;
roleClasses.clear();
String temp = this.roleClassNames;
if (temp == null) {
return;
}
while (true) {
int comma = temp.indexOf(',");
if (comma < 0) {
break;
}
roleClasses.add(temp.substring(0, comma).trim());
temp = temp.substring(comma + 1);
}
temp = temp.trim();
if (temp.length() > 0) {
roleClasses.add(temp);
}
| public void | setUserClassNames(java.lang.String userClassNames)
this.userClassNames = userClassNames;
userClasses.clear();
String temp = this.userClassNames;
if (temp == null) {
return;
}
while (true) {
int comma = temp.indexOf(',");
if (comma < 0) {
break;
}
userClasses.add(temp.substring(0, comma).trim());
temp = temp.substring(comma + 1);
}
temp = temp.trim();
if (temp.length() > 0) {
userClasses.add(temp);
}
| public void | start()Prepare for active use of the public methods of this Component.
// Perform normal superclass initialization
super.start();
| public void | stop()Gracefully shut down active use of the public methods of this Component.
// Perform normal superclass finalization
super.stop();
|
|