You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jspwiki.apache.org by aj...@apache.org on 2008/12/31 18:32:17 UTC

svn commit: r730419 - in /incubator/jspwiki/trunk: src/com/ecyrd/jspwiki/auth/ src/com/ecyrd/jspwiki/auth/login/ src/com/ecyrd/jspwiki/xmlrpc/ tests/com/ecyrd/jspwiki/ tests/com/ecyrd/jspwiki/workflow/

Author: ajaquith
Date: Wed Dec 31 09:32:14 2008
New Revision: 730419

URL: http://svn.apache.org/viewvc?rev=730419&view=rev
Log:
AuthenticationManager now handles LoginExceptions more gracefully and propagates them to the original caller instead of wrapping them in WikiSecurityExceptions.

Modified:
    incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/auth/AuthenticationManager.java
    incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/auth/UserManager.java
    incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/auth/WikiSecurityException.java
    incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/auth/login/WikiCallbackHandler.java
    incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/xmlrpc/MetaWeblogHandler.java
    incubator/jspwiki/trunk/tests/com/ecyrd/jspwiki/TestEngine.java
    incubator/jspwiki/trunk/tests/com/ecyrd/jspwiki/workflow/ApprovalWorkflowTest.java

Modified: incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/auth/AuthenticationManager.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/auth/AuthenticationManager.java?rev=730419&r1=730418&r2=730419&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/auth/AuthenticationManager.java (original)
+++ incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/auth/AuthenticationManager.java Wed Dec 31 09:32:14 2008
@@ -277,6 +277,7 @@
 
         // If user not authenticated, check if container logged them in, or if
         // there's an authentication cookie
+        Set<Principal> principals = null;
         if ( !session.isAuthenticated() )
         {
             // Create a callback handler
@@ -290,15 +291,31 @@
                 throw new WikiSecurityException( e.getMessage() );
             }
             
-            // Execute the container login module, then (if that fails) the cookie auth module
-            Set<Principal> principals = authenticationMgr.doJAASLogin( WebContainerLoginModule.class, handler, options );
-            if ( principals.size() == 0 && authenticationMgr.allowsCookieAuthentication() )
+            // Execute the container login module
+            try
+            {
+                principals = authenticationMgr.doJAASLogin( WebContainerLoginModule.class, handler, options );
+            }
+            catch ( LoginException e )
             {
-                principals = authenticationMgr.doJAASLogin( CookieAuthenticationLoginModule.class, handler, options );
+                // Container credentials not supplied in request. Ok, try the auth cookie!
+            }
+            
+            // Execute the cookie authentication module (if allowed)
+            if ( ( principals == null || principals.size() == 0 ) && authenticationMgr.allowsCookieAuthentication() )
+            {
+                try
+                {
+                    principals = authenticationMgr.doJAASLogin( CookieAuthenticationLoginModule.class, handler, options );
+                }
+                catch( LoginException e )
+                {
+                    // Authentication cookie not supplied in request. Ok, try the assertion cookie!
+                }
             }
             
             // If the container logged the user in successfully, tell the WikiSession (and add all of the Principals)
-            if ( principals.size() > 0 )
+            if ( principals != null && principals.size() > 0 )
             {
                 fireEvent( WikiSecurityEvent.LOGIN_AUTHENTICATED, getLoginPrincipal( principals ), session );
                 for ( Principal principal : principals )
@@ -312,18 +329,34 @@
         if ( !session.isAuthenticated() && authenticationMgr.allowsCookieAssertions() )
         {
             // Execute the cookie assertion login module
-            Set<Principal> principals = authenticationMgr.doJAASLogin( CookieAssertionLoginModule.class, handler, options );
-            if ( principals.size() > 0 )
+            try
+            {
+                principals = authenticationMgr.doJAASLogin( CookieAssertionLoginModule.class, handler, options );
+                if ( principals != null && principals.size() > 0 )
+                {
+                    fireEvent( WikiSecurityEvent.LOGIN_ASSERTED, getLoginPrincipal( principals ), session);
+                }
+            }
+            catch( LoginException e )
             {
-                fireEvent( WikiSecurityEvent.LOGIN_ASSERTED, getLoginPrincipal( principals ), session);
+                // Assertion cookie not supplied in request. Ok, use the IP address!
             }
         }
 
         // If user still anonymous, use the remote address
-        if (session.isAnonymous() )
+        if ( session.isAnonymous() )
         {
-            Set<Principal> principals = authenticationMgr.doJAASLogin( AnonymousLoginModule.class, handler, options );
-            if ( principals.size() > 0 )
+            try
+            {
+                principals = authenticationMgr.doJAASLogin( AnonymousLoginModule.class, handler, options );
+            }
+            catch( LoginException e )
+            {
+                // If the anonymous login didn't succeed, we have a genuine configuration problem!
+                e.printStackTrace();
+                throw new WikiSecurityException( e.getMessage() );
+            }
+            if ( principals != null && principals.size() > 0 )
             {
                 fireEvent( WikiSecurityEvent.LOGIN_ANONYMOUS, getLoginPrincipal( principals ), session );
                 return true;
@@ -344,15 +377,21 @@
      * class will be used. When the LoginModule's <code>initialize</code> method is invoked,
      * an options Map populated by properties keys prefixed by {@link #PREFIX_LOGIN_MODULE_OPTIONS}
      * will be passed as a parameter.
-     * @param session the current wiki session; may not be null.
+     * @param session the current wiki session; may not be <code>null</code>.
      * @param username The user name. This is a login name, not a WikiName. In
      *            most cases they are the same, but in some cases, they might
      *            not be.
      * @param password the password
-     * @return true, if the username/password is valid
-     * @throws com.ecyrd.jspwiki.auth.WikiSecurityException if the Authorizer or UserManager cannot be obtained
+     * @return <code>true</code> if the username/password is valid; <code>false</code>
+     *             if the LoginModule should be ignored, or the WikiSession was <code>null</code>
+     * @throws LoginException
+     *             if the LoginModule's <code>login()</code> or <code>commit()</code> phases
+     *             failed for any reason, including invalid credentials.
+     * @throws WikiSecurityException
+     *             if the login failed for any other reason. The root-cause exception can
+     *             be retrieved via {@link java.lang.Throwable#getCause()}
      */
-    public final boolean login( WikiSession session, String username, String password ) throws WikiSecurityException
+    public final boolean login( WikiSession session, String username, String password ) throws WikiSecurityException, LoginException
     {
         if ( session == null )
         {
@@ -374,7 +413,7 @@
         
         // Execute the user's specified login module
         Set<Principal> principals = doJAASLogin( m_loginModuleClass, handler, m_loginModuleOptions );
-        if (principals.size() > 0)
+        if ( principals.size() > 0 )
         {
             fireEvent(WikiSecurityEvent.LOGIN_AUTHENTICATED, getLoginPrincipal( principals ), session );
             for ( Principal principal : principals )
@@ -511,6 +550,8 @@
      * then its {@link javax.security.auth.spi.LoginModule#initialize(Subject, CallbackHandler, Map, Map)}
      * method is called. The parameters passed to <code>initialize</code> is a 
      * dummy Subject, an empty shared-state Map, and an options Map the caller supplies.
+     * If login succeeds, this method will return the Set of Principals. If it fails for any reason,
+     * including invalid credentials, it will throw a {@link javax.security.auth.login.LoginException}.
      * 
      * @param clazz
      *            the LoginModule class to instantiate
@@ -519,10 +560,14 @@
      * @param options
      *            a Map of key/value strings for initializing the LoginModule
      * @return the set of Principals returned by the JAAS method {@link Subject#getPrincipals()}
+     * @throws LoginException
+     *             if the LoginModule's <code>login()</code> or <code>commit()</code> phases
+     *             failed for any reason, including invalid credentials.
      * @throws WikiSecurityException
-     *             if the LoginModule could not be instantiated for any reason
+     *             if the LoginModule could not be instantiated. The root-cause exception can
+     *             be retrieved via {@link java.lang.Throwable#getCause()}
      */
-    protected Set<Principal> doJAASLogin(Class<? extends LoginModule> clazz, CallbackHandler handler, Map<String,String> options) throws WikiSecurityException
+    protected Set<Principal> doJAASLogin(Class<? extends LoginModule> clazz, CallbackHandler handler, Map<String,String> options) throws WikiSecurityException, LoginException
     {
         // Instantiate the login module
         LoginModule loginModule = null;
@@ -530,13 +575,13 @@
         {
             loginModule = clazz.newInstance();
         }
-        catch (InstantiationException e)
+        catch ( InstantiationException e )
         {
-            throw new WikiSecurityException(e.getMessage());
+            throw new WikiSecurityException( e.getMessage(), e );
         }
-        catch (IllegalAccessException e)
+        catch ( IllegalAccessException e )
         {
-            throw new WikiSecurityException(e.getMessage());
+            throw new WikiSecurityException( e.getMessage(), e );
         }
 
         // Initialize the LoginModule
@@ -544,23 +589,15 @@
         loginModule.initialize( subject, handler, EMPTY_MAP, options );
 
         // Try to log in:
-        boolean loginSucceeded = false;
         boolean commitSucceeded = false;
-        try
-        {
-            loginSucceeded = loginModule.login();
-            if (loginSucceeded)
-            {
-                commitSucceeded = loginModule.commit();
-            }
-        }
-        catch (LoginException e)
+        boolean loginSucceeded = loginModule.login();
+        if ( loginSucceeded )
         {
-            // Login or commit failed! No principal for you!
+            commitSucceeded = loginModule.commit();
         }
 
         // If we successfully logged in & committed, return all the principals
-        if (loginSucceeded && commitSucceeded)
+        if ( loginSucceeded && commitSucceeded )
         {
             return subject.getPrincipals();
         }

Modified: incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/auth/UserManager.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/auth/UserManager.java?rev=730419&r1=730418&r2=730419&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/auth/UserManager.java (original)
+++ incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/auth/UserManager.java Wed Dec 31 09:32:14 2008
@@ -28,6 +28,7 @@
 
 import javax.mail.MessagingException;
 import javax.mail.internet.AddressException;
+import javax.security.auth.login.LoginException;
 import javax.servlet.http.HttpServletRequest;
 
 import org.apache.jspwiki.api.WikiException;
@@ -371,7 +372,7 @@
                     mgr.login( session, profile.getLoginName(), profile.getPassword() );
                 }
             }
-            catch ( WikiException e )
+            catch ( LoginException e )
             {
                 throw new WikiSecurityException( e.getMessage() );
             }

Modified: incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/auth/WikiSecurityException.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/auth/WikiSecurityException.java?rev=730419&r1=730418&r2=730419&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/auth/WikiSecurityException.java (original)
+++ incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/auth/WikiSecurityException.java Wed Dec 31 09:32:14 2008
@@ -23,23 +23,32 @@
 import org.apache.jspwiki.api.WikiException;
 
 /**
- *  Indicates an authentication or authorization
- *  error or exception.
- *
- *  @author Erik Bunn
- *  @since 2.0
+ * Indicates an authentication or authorization error or exception.
+ * 
+ * @author Erik Bunn
+ * @since 2.0
  */
-public class WikiSecurityException
-    extends WikiException
+public class WikiSecurityException extends WikiException
 {
     private static final long serialVersionUID = 3617293441285764405L;
 
     /**
-     *  Constructs an exception.
-     *  @param msg the message to supply to the exception
+     * Constructs an exception.
+     * 
+     * @param msg the message to supply to the exception
      */
     public WikiSecurityException( String msg )
     {
-        super(msg);
+        super( msg );
+    }
+
+    /**
+     * Constructs an exception with a root cause.
+     * @param msg the message to supply to the exception
+     * @param cause the root cause
+     */
+    public WikiSecurityException( String msg, Throwable cause )
+    {
+        super( msg, cause );
     }
 }

Modified: incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/auth/login/WikiCallbackHandler.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/auth/login/WikiCallbackHandler.java?rev=730419&r1=730418&r2=730419&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/auth/login/WikiCallbackHandler.java (original)
+++ incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/auth/login/WikiCallbackHandler.java Wed Dec 31 09:32:14 2008
@@ -22,13 +22,12 @@
 
 import java.io.IOException;
 
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.NameCallback;
-import javax.security.auth.callback.PasswordCallback;
-import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.callback.*;
 
+import com.ecyrd.jspwiki.WikiSession;
 import com.ecyrd.jspwiki.auth.user.UserDatabase;
+import com.ecyrd.jspwiki.log.Logger;
+import com.ecyrd.jspwiki.log.LoggerFactory;
 
 /**
  * Handles logins made from inside the wiki application, rather than via the web
@@ -42,6 +41,8 @@
  */
 public class WikiCallbackHandler implements CallbackHandler
 {
+    private static final Logger log = LoggerFactory.getLogger(WikiCallbackHandler.class);
+
     private final UserDatabase m_database;
 
     private final String       m_password;
@@ -84,6 +85,18 @@
             {
                 ( (PasswordCallback) callback ).setPassword( m_password.toCharArray() );
             }
+            else if( callbacks[i] instanceof TextOutputCallback )
+            {
+                TextOutputCallback textOutputCb = (TextOutputCallback) callbacks[i];
+                String loginResult = textOutputCb.getMessage();
+                if(  textOutputCb.getMessageType() == TextOutputCallback.ERROR )
+                {
+                    log.error( loginResult );
+                    throw new IOException( loginResult );
+                }
+
+                log.info( loginResult );
+            }
             else
             {
                 throw new UnsupportedCallbackException( callback );

Modified: incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/xmlrpc/MetaWeblogHandler.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/xmlrpc/MetaWeblogHandler.java?rev=730419&r1=730418&r2=730419&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/xmlrpc/MetaWeblogHandler.java (original)
+++ incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/xmlrpc/MetaWeblogHandler.java Wed Dec 31 09:32:14 2008
@@ -23,6 +23,8 @@
 import java.io.ByteArrayInputStream;
 import java.util.*;
 
+import javax.security.auth.login.LoginException;
+
 import com.ecyrd.jspwiki.log.Logger;
 import com.ecyrd.jspwiki.log.LoggerFactory;
 
@@ -106,6 +108,10 @@
         {
             throw new XmlRpcException( 1, e.getMessage(), e );
         }
+        catch( LoginException e )
+        {
+            throw new XmlRpcException( 1, e.getMessage(), e );
+        }
         return;
     }
 

Modified: incubator/jspwiki/trunk/tests/com/ecyrd/jspwiki/TestEngine.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/tests/com/ecyrd/jspwiki/TestEngine.java?rev=730419&r1=730418&r2=730419&view=diff
==============================================================================
--- incubator/jspwiki/trunk/tests/com/ecyrd/jspwiki/TestEngine.java (original)
+++ incubator/jspwiki/trunk/tests/com/ecyrd/jspwiki/TestEngine.java Wed Dec 31 09:32:14 2008
@@ -25,6 +25,7 @@
 import java.util.Map;
 import java.util.Properties;
 
+import javax.security.auth.login.LoginException;
 import javax.servlet.ServletContext;
 import javax.servlet.http.HttpServletRequest;
 
@@ -82,7 +83,7 @@
      * @return the wiki session
      * @throws WikiSecurityException 
      */
-    public WikiSession adminSession() throws WikiSecurityException
+    public WikiSession adminSession() throws WikiSecurityException, LoginException
     {
         if ( m_adminWikiSession == null )
         {
@@ -118,7 +119,7 @@
      * @return the wiki session
      * @throws WikiSecurityException 
      */
-    public WikiSession janneSession() throws WikiSecurityException
+    public WikiSession janneSession() throws WikiSecurityException, LoginException
     {
         if ( m_janneWikiSession == null )
         {
@@ -344,9 +345,16 @@
         // Build new request and associate our admin session
         MockHttpServletRequest request = newHttpRequest();
         WikiSession wikiSession = SessionMonitor.getInstance( this ).find( request.getSession() );
-        this.getAuthenticationManager().login( wikiSession,
-                Users.ADMIN,
-                Users.ADMIN_PASS );
+        try
+        {
+            this.getAuthenticationManager().login( wikiSession,
+                    Users.ADMIN,
+                    Users.ADMIN_PASS );
+        }
+        catch( LoginException e )
+        {
+            throw new WikiException( e.getMessage(), e );
+        }
 
         // Create page and wiki context
         WikiPage page = createPage( WikiName.valueOf( pageName ) );
@@ -360,9 +368,16 @@
         // Build new request and associate our Janne session
         MockHttpServletRequest request = newHttpRequest();
         WikiSession wikiSession = SessionMonitor.getInstance( this ).find( request.getSession() );
-        this.getAuthenticationManager().login( wikiSession,
-                Users.JANNE,
-                Users.JANNE_PASS );
+        try
+        {
+            this.getAuthenticationManager().login( wikiSession,
+                    Users.JANNE,
+                    Users.JANNE_PASS );
+        }
+        catch( LoginException e )
+        {
+            throw new WikiException( e.getMessage(), e );
+        }
 
         // Create page and wiki context
         WikiPage page = createPage( WikiName.valueOf( pageName ) );
@@ -443,7 +458,7 @@
      * @return the initialized round trip
      * @throws WikiSecurityException
      */
-    public MockRoundtrip authenticatedTrip( String user, String password, Class<? extends WikiActionBean> beanClass ) throws WikiSecurityException
+    public MockRoundtrip authenticatedTrip( String user, String password, Class<? extends WikiActionBean> beanClass ) throws WikiSecurityException, LoginException
     {
         MockServletContext servletContext = (MockServletContext)getServletContext();
         if ( servletContext.getFilters().size() == 0 )

Modified: incubator/jspwiki/trunk/tests/com/ecyrd/jspwiki/workflow/ApprovalWorkflowTest.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/tests/com/ecyrd/jspwiki/workflow/ApprovalWorkflowTest.java?rev=730419&r1=730418&r2=730419&view=diff
==============================================================================
--- incubator/jspwiki/trunk/tests/com/ecyrd/jspwiki/workflow/ApprovalWorkflowTest.java (original)
+++ incubator/jspwiki/trunk/tests/com/ecyrd/jspwiki/workflow/ApprovalWorkflowTest.java Wed Dec 31 09:32:14 2008
@@ -180,7 +180,7 @@
         assertEquals( notification, w.getHistory().get( 2 ) );
     }
 
-    public void testSaveWikiPageWithApproval() throws WikiException
+    public void testSaveWikiPageWithApproval() throws Exception
     {
         // Create a sample test page and try to save it
         String pageName = "SaveWikiPageWorkflow-Test" + System.currentTimeMillis();
@@ -212,7 +212,7 @@
         m_engine.deletePage( pageName );
     }
 
-    public void testSaveWikiPageWithRejection() throws WikiException
+    public void testSaveWikiPageWithRejection() throws Exception
     {
         // Create a sample test page and try to save it
         String pageName = "SaveWikiPageWorkflow-Test" + System.currentTimeMillis();