Author: ajaquith
Date: Mon Mar 31 20:42:00 2008
New Revision: 643254
URL: http://svn.apache.org/viewvc?rev=643254&view=rev
Log:
Re-factored the authentication subsystem to remove the need for JAAS
configuration files. WEB-INF/jspwiki.jaas goes away, as does the need for
PolicyLoader. Also, responsibilities for web authentication move to
WikiServletFilter. Authentication is now configured via jspwiki.properties --
see that file for details. WikiSession API change: getLoginContext() vanishes.
Modified:
incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/WikiContext.java
incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/WikiSession.java
Modified: incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/WikiContext.java
URL:
http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/WikiContext.java?rev=643254&r1=643253&r2=643254&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/WikiContext.java (original)
+++ incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/WikiContext.java Mon Mar 31
20:42:00 2008
@@ -194,15 +194,6 @@
* request, and determine if a WikiSession object is present. If not, a new
* one is created.
* </p>
- * <p>
- * After the WikiSession object is obtained, the current authentication
- * status is checked. If not authenticated, or if the login status reported
- * by the container has changed, the constructor attempts to log in the
user
- * with
- * [EMAIL PROTECTED]
com.ecyrd.jspwiki.auth.AuthenticationManager#login(HttpServletRequest)}.
- * If an login process throws an exception, this method logs the error but
- * does not re-throw it.
- * </p>
* @param engine The WikiEngine that is handling the request
* @param request The HttpServletRequest that should be associated with
this
* context. This parameter may be <code>null</code>.
@@ -250,35 +241,12 @@
m_command = command.targetedCommand( m_page );
}
- // Log in the user if new session or the container status changed
- boolean doLogin = (request != null) && m_session.isNew();
-
// Debugging...
if( log.isDebugEnabled() )
{
HttpSession session = ( request == null ) ? null :
request.getSession( false );
String sid = ( session == null ) ? "(null)" : session.getId();
log.debug( "Creating WikiContext for session ID=" + sid + ";
target=" + getName() );
- log.debug( "Do we need to log the user in? " + doLogin );
- }
-
- if( doLogin || m_session.isContainerStatusChanged( request ) )
- {
- try
- {
- engine.getAuthenticationManager().login( request );
- }
- catch ( WikiSecurityException e )
- {
- // Login failed because config was screwy
- log.error( "Could not log in user: " + e.getMessage() );
- }
- }
-
- // Mark the session as "not new"
- if( m_session.isNew() )
- {
- m_session.setNew( false );
}
// Figure out what template to use
Modified: incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/WikiSession.java
URL:
http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/WikiSession.java?rev=643254&r1=643253&r2=643254&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/WikiSession.java (original)
+++ incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/WikiSession.java Mon Mar 31
20:42:00 2008
@@ -26,9 +26,6 @@
import java.util.*;
import javax.security.auth.Subject;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.login.LoginContext;
-import javax.security.auth.login.LoginException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
@@ -38,8 +35,6 @@
import com.ecyrd.jspwiki.auth.authorize.Group;
import com.ecyrd.jspwiki.auth.authorize.GroupManager;
import com.ecyrd.jspwiki.auth.authorize.Role;
-import com.ecyrd.jspwiki.auth.login.CookieAssertionLoginModule;
-import com.ecyrd.jspwiki.auth.login.PrincipalWrapper;
import com.ecyrd.jspwiki.auth.user.UserDatabase;
import com.ecyrd.jspwiki.auth.user.UserProfile;
import com.ecyrd.jspwiki.event.WikiEvent;
@@ -117,17 +112,9 @@
private final Map m_messages = new HashMap();
- private String m_cachedCookieIdentity= null;
-
- private String m_cachedRemoteUser = null;
-
- private Principal m_cachedUserPrincipal = null;
-
/** The WikiEngine that created this session. */
private WikiEngine m_engine = null;
- private boolean m_isNew = true;
-
private String m_status = ANONYMOUS;
private Principal m_userPrincipal = WikiPrincipal.GUEST;
@@ -157,25 +144,6 @@
}
/**
- * Returns <code>true</code> if the wiki session is newly initialized.
- *
- * @return True, if this is a new session.
- */
- protected final boolean isNew()
- {
- return m_isNew;
- }
-
- /**
- * Sets the status of this wiki session.
- * @param isNew whether this session should be considered "new".
- */
- protected final void setNew( boolean isNew )
- {
- m_isNew = isNew;
- }
-
- /**
* Private constructor to prevent WikiSession from being instantiated
* directly.
*/
@@ -247,20 +215,6 @@
}
/**
- * Creates and returns a new login context for this wiki session.
- * This method is called by
- * [EMAIL PROTECTED] com.ecyrd.jspwiki.auth.AuthenticationManager}.
- * @param application the name of the application
- * @param handler the callback handler
- * @return A new login context
- * @throws LoginException If the login context cannot be created
- */
- public final LoginContext getLoginContext( String application,
CallbackHandler handler ) throws LoginException
- {
- return new LoginContext( application, m_subject, handler );
- }
-
- /**
* <p> Returns the Principal used to log in to an authenticated session.
The
* login principal is determined by examining the Subject's Principal set
* for PrincipalWrappers or WikiPrincipals with type designator
@@ -274,10 +228,6 @@
*/
public final Principal getLoginPrincipal()
{
- if ( m_loginPrincipal instanceof PrincipalWrapper )
- {
- return ((PrincipalWrapper)m_loginPrincipal).getPrincipal();
- }
return m_loginPrincipal;
}
@@ -296,10 +246,6 @@
*/
public final Principal getUserPrincipal()
{
- if ( m_loginPrincipal instanceof PrincipalWrapper )
- {
- return ((PrincipalWrapper)m_userPrincipal).getPrincipal();
- }
return m_userPrincipal;
}
@@ -530,10 +476,35 @@
}
case WikiSecurityEvent.LOGIN_INITIATED:
{
+ // Do nothing
+ }
+ case WikiSecurityEvent.PRINCIPAL_ADD:
+ {
+ WikiSession target = (WikiSession)e.getTarget();
+ if ( this.equals( target ) & m_status == AUTHENTICATED
)
+ {
+ Set principals = m_subject.getPrincipals();
+ principals.add(e.getPrincipal());
+ }
+ break;
+ }
+ case WikiSecurityEvent.LOGIN_ANONYMOUS:
+ {
WikiSession target = (WikiSession)e.getTarget();
if ( this.equals( target ) )
{
- updatePrincipals();
+ m_status = ANONYMOUS;
+
+ // Set the login/user principals and login status
+ Set principals = m_subject.getPrincipals();
+ m_loginPrincipal = (Principal)e.getPrincipal();
+ m_userPrincipal = m_loginPrincipal;
+
+ // Add the login principal to the Subject, and set
the built-in roles
+ principals.clear();
+ principals.add(m_loginPrincipal);
+ principals.add(Role.ALL);
+ principals.add(Role.ANONYMOUS);
}
break;
}
@@ -543,6 +514,17 @@
if ( this.equals( target ) )
{
m_status = ASSERTED;
+
+ // Set the login/user principals and login status
+ Set principals = m_subject.getPrincipals();
+ m_loginPrincipal = (Principal)e.getPrincipal();
+ m_userPrincipal = m_loginPrincipal;
+
+ // Add the login principal to the Subject, and set
the built-in roles
+ principals.clear();
+ principals.add(m_loginPrincipal);
+ principals.add(Role.ALL);
+ principals.add(Role.ASSERTED);
}
break;
}
@@ -552,9 +534,21 @@
if ( this.equals( target ) )
{
m_status = AUTHENTICATED;
+
+ // Set the login/user principals and login status
+ Set principals = m_subject.getPrincipals();
+ m_loginPrincipal = (Principal)e.getPrincipal();
+ m_userPrincipal = m_loginPrincipal;
+
+ // Add the login principal to the Subject, and set
the built-in roles
+ principals.clear();
+ principals.add(m_loginPrincipal);
+ principals.add(Role.ALL);
+ principals.add(Role.AUTHENTICATED);
+
+ // Add the user and group principals
injectUserProfilePrincipals(); // Add principals
for the user profile
- injectRolePrincipals(); // Inject role and group
principals
- updatePrincipals();
+ injectGroupPrincipals(); // Inject group
principals
}
break;
}
@@ -564,7 +558,7 @@
if ( this.equals( source ) )
{
injectUserProfilePrincipals(); // Add principals
for the user profile
- updatePrincipals();
+ injectGroupPrincipals(); // Inject group
principals
}
break;
}
@@ -572,7 +566,7 @@
{
// Refresh user principals based on new user profile
WikiSession source = (WikiSession)e.getSource();
- if ( this.equals( source ) )
+ if ( this.equals( source ) && m_status ==
AUTHENTICATED )
{
// To prepare for refresh, set the new full name
as the primary principal
UserProfile[] profiles =
(UserProfile[])e.getTarget();
@@ -581,11 +575,19 @@
{
throw new IllegalStateException( "User profile
FullName cannot be null." );
}
- m_userPrincipal = new WikiPrincipal(
newProfile.getFullname() );
-
- // Refresh principals for the user profile
- injectUserProfilePrincipals();
- updatePrincipals();
+
+ Set principals = m_subject.getPrincipals();
+ m_loginPrincipal = new WikiPrincipal(
newProfile.getLoginName() );
+
+ // Add the login principal to the Subject, and set
the built-in roles
+ principals.clear();
+ principals.add( m_loginPrincipal );
+ principals.add( Role.ALL );
+ principals.add( Role.AUTHENTICATED );
+
+ // Add the user and group principals
+ injectUserProfilePrincipals(); // Add principals
for the user profile
+ injectGroupPrincipals(); // Inject group
principals
}
break;
}
@@ -610,83 +612,26 @@
m_subject.getPrincipals().add( WikiPrincipal.GUEST );
m_subject.getPrincipals().add( Role.ANONYMOUS );
m_subject.getPrincipals().add( Role.ALL );
- m_cachedCookieIdentity = null;
- m_cachedRemoteUser = null;
- m_cachedUserPrincipal = null;
}
/**
- * Returns whether the HTTP servlet container's authentication status has
- * changed. Used to detect whether the container has logged in a user since
- * the last call to this function. This method is stateful. After calling
- * this function, the cached values are set to those in the current
request.
- * If the servlet request is <code>null</code>, this method always returns
- * <code>false</code>. Note that once a user authenticates, the container
- * status for the session will <em>never</em> change again, unless the
- * session is invalidated by timeout or logout.
- * @param request the servlet request
- * @return <code>true</code> if the status has changed, <code>false</code>
- * otherwise
- */
- protected final boolean isContainerStatusChanged( HttpServletRequest
request )
- {
- if ( request == null || m_status.equals( AUTHENTICATED ) )
- {
- return false;
- }
-
- String remoteUser = request.getRemoteUser();
- Principal userPrincipal = request.getUserPrincipal();
- String cookieIdentity = CookieAssertionLoginModule.getUserCookie(
request );
- boolean changed = false;
-
- // If request contains non-null remote user, update cached value if
changed
- if ( remoteUser != null && !remoteUser.equals( m_cachedRemoteUser) )
- {
- m_cachedRemoteUser = remoteUser;
- log.info( "Remote user changed to " + remoteUser );
- changed = true;
- }
-
- // If request contains non-null user principal, updated cached value
if changed
- if ( userPrincipal != null && !userPrincipal.equals(
m_cachedUserPrincipal ) )
- {
- m_cachedUserPrincipal = userPrincipal;
- log.info( "User principal changed to " + userPrincipal.getName() );
- changed = true;
- }
-
- // If cookie identity changed (to a different value or back to null),
update cache
- if ( ( cookieIdentity != null && !cookieIdentity.equals(
m_cachedCookieIdentity ) )
- || ( cookieIdentity == null && m_cachedCookieIdentity != null )
)
- {
- m_cachedCookieIdentity = cookieIdentity;
- log.info( "Cookie changed to " + cookieIdentity );
- changed = true;
- }
- return changed;
- }
-
- /**
- * Injects GroupPrincipal and Role objects into the user's Principal set
- * based on the groups and roles the user belongs to.
- * For Roles, the algorithm first calls the
- * [EMAIL PROTECTED] Authorizer#getRoles()} to obtain the array of
- * Principals the authorizer knows about. Then, the method
- * [EMAIL PROTECTED] Authorizer#isUserInRole(WikiSession, Principal)} is
- * called for each Principal. If the user possesses the role,
- * an equivalent role Principal is injected into the user's
- * principal set.
- * Reloads user Principals into the suppplied WikiSession's Subject.
- * Existing Role principals are preserved; all other Principal
- * types are flushed and replaced by those returned by
- * [EMAIL PROTECTED]
com.ecyrd.jspwiki.auth.user.UserDatabase#getPrincipals(String)}.
- * This method should generally be called after a user's [EMAIL PROTECTED]
com.ecyrd.jspwiki.auth.user.UserProfile}
- * is saved. If the wiki session is null, or there is no matching user
profile, the
- * method returns silently.
- */
- protected final void injectRolePrincipals()
- {
+ * Injects GroupPrincipal objects into the user's Principal set based on
the
+ * groups the user belongs to. For Groups, the algorithm first calls the
+ * [EMAIL PROTECTED] GroupManager#getRoles()} to obtain the array of
GroupPrincipals
+ * the authorizer knows about. Then, the method
+ * [EMAIL PROTECTED] GroupManager#isUserInRole(WikiSession, Principal)} is
called for
+ * each Principal. If the user is a member of the group, an equivalent
+ * GroupPrincipal is injected into the user's principal set. Existing
+ * GroupPrincipals are flushed and replaced. This method should generally
be
+ * called after a user's [EMAIL PROTECTED]
com.ecyrd.jspwiki.auth.user.UserProfile} is
+ * saved. If the wiki session is null, or there is no matching user
profile,
+ * the method returns silently.
+ */
+ protected final void injectGroupPrincipals()
+ {
+ // Flush the existing GroupPrincipals
+
m_subject.getPrincipals().removeAll(m_subject.getPrincipals(GroupPrincipal.class));
+
// Get the GroupManager and test for each Group
GroupManager manager = m_engine.getGroupManager();
Principal[] groups = manager.getRoles();
@@ -697,29 +642,6 @@
m_subject.getPrincipals().add( groups[i] );
}
}
-
- // Get the authorizer's known roles, then test for each
- try
- {
- Authorizer authorizer =
m_engine.getAuthorizationManager().getAuthorizer();
- Principal[] roles = authorizer.getRoles();
- for ( int i = 0; i < roles.length; i++ )
- {
- Principal role = roles[i];
- if ( authorizer.isUserInRole( this, role ) )
- {
- String roleName = role.getName();
- if ( !Role.isReservedName( roleName ) )
- {
- m_subject.getPrincipals().add( new Role( roleName ) );
- }
- }
- }
- }
- catch ( WikiException e )
- {
- log.error( "Could not refresh role principals: " + e.getMessage()
);
- }
}
/**
@@ -731,18 +653,8 @@
*/
protected final void injectUserProfilePrincipals()
{
- // Copy all Role and GroupPrincipal principals into a temporary cache
- Set oldPrincipals = m_subject.getPrincipals();
- Set newPrincipals = new HashSet();
- for (Iterator it = oldPrincipals.iterator(); it.hasNext();)
- {
- Principal principal = (Principal)it.next();
- if ( AuthenticationManager.isRolePrincipal( principal ) )
- {
- newPrincipals.add( principal );
- }
- }
- String searchId = getUserPrincipal().getName();
+ // Search for the user profile
+ String searchId = m_loginPrincipal.getName();
if ( searchId == null )
{
// Oh dear, this wasn't an authenticated user after all
@@ -762,105 +674,27 @@
Principal[] principals = database.getPrincipals(
profile.getLoginName() );
for (int i = 0; i < principals.length; i++)
{
+ // Add the Principal to the Subject
Principal principal = principals[i];
- newPrincipals.add( principal );
- }
-
- // Replace the Subject's old Principals with the new ones
- oldPrincipals.clear();
- oldPrincipals.addAll( newPrincipals );
- }
- catch ( NoSuchPrincipalException e )
- {
- // We will get here if the user has a principal but not a profile
- // For example, it's a container-managed user who hasn't set up a
profile yet
- log.warn("User profile '" + searchId + "' not found. This is
normal for container-auth users who haven't set up a profile yet.");
- }
- }
-
- /**
- * Updates the internally cached principals returned by [EMAIL PROTECTED]
#getUserPrincipal()} and
- * [EMAIL PROTECTED] #getLoginPrincipal()}. This method is called when the
WikiSession receives
- * the [EMAIL PROTECTED]
com.ecyrd.jspwiki.event.WikiSecurityEvent#LOGIN_INITIATED} message.
- */
- protected final void updatePrincipals()
- {
- Set principals = m_subject.getPrincipals();
- m_loginPrincipal = null;
- m_userPrincipal = null;
- Principal wikinamePrincipal = null;
- Principal fullnamePrincipal = null;
- Principal otherPrincipal = null;
-
- for( Iterator it = principals.iterator(); it.hasNext(); )
- {
- Principal currentPrincipal = (Principal) it.next();
- if ( !( currentPrincipal instanceof Role || currentPrincipal
instanceof GroupPrincipal ) )
- {
- // For login principal, take the first PrincipalWrapper or
WikiPrincipal of type LOGIN_NAME
- // For user principal take the first WikiPrincipal of type
WIKI_NAME
- if ( currentPrincipal instanceof PrincipalWrapper )
+ m_subject.getPrincipals().add( principal );
+
+ // Set the user principal if needed; we prefer FullName, but
the WikiName will also work
+ boolean isFullNamePrincipal = (principal instanceof
WikiPrincipal && ((WikiPrincipal)principal).getType() ==
WikiPrincipal.FULL_NAME);
+ if (isFullNamePrincipal)
{
- m_loginPrincipal = currentPrincipal;
+ m_userPrincipal = principal;
}
- else if ( currentPrincipal instanceof WikiPrincipal )
+ else if (!(m_userPrincipal instanceof WikiPrincipal))
{
- WikiPrincipal wp = (WikiPrincipal) currentPrincipal;
- if ( wp.getType().equals( WikiPrincipal.LOGIN_NAME ) )
- {
- m_loginPrincipal = wp;
- }
- else if ( wp.getType().equals( WikiPrincipal.WIKI_NAME ) )
- {
- wikinamePrincipal = currentPrincipal;
- m_userPrincipal = wp;
- }
- else if ( wp.getType().equals( WikiPrincipal.FULL_NAME ) )
- {
- fullnamePrincipal = currentPrincipal;
- }
- else
- {
- otherPrincipal = currentPrincipal;
- }
- }
- else if ( otherPrincipal == null )
- {
- otherPrincipal = currentPrincipal;
+ m_userPrincipal = principal;
}
}
}
- if ( otherPrincipal == null )
- {
- otherPrincipal = WikiPrincipal.GUEST;
- }
-
- // If no login principal, use wiki name, full name or other principal
(in that order)
- if ( m_loginPrincipal == null )
- {
- m_loginPrincipal = wikinamePrincipal;
- if ( m_loginPrincipal == null )
- {
- m_loginPrincipal = fullnamePrincipal;
- if ( m_loginPrincipal == null )
- {
- m_loginPrincipal = otherPrincipal;
- }
- }
- }
-
- // If no user principal, use wiki name, full name or login principal
(in that order)
- if ( m_userPrincipal == null )
+ catch ( NoSuchPrincipalException e )
{
- m_userPrincipal = wikinamePrincipal;
- if ( m_userPrincipal == null )
- {
- m_userPrincipal = fullnamePrincipal;
- if ( m_userPrincipal == null )
- {
- m_userPrincipal = m_loginPrincipal;
- }
- }
+ // We will get here if the user has a principal but not a profile
+ // For example, it's a container-managed user who hasn't set up a
profile yet
+ log.warn("User profile '" + searchId + "' not found. This is
normal for container-auth users who haven't set up a profile yet.");
}
}