You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shiro.apache.org by lh...@apache.org on 2009/08/26 00:04:45 UTC

svn commit: r807826 - in /incubator/shiro/trunk: core/src/main/java/org/apache/shiro/mgt/ core/src/main/java/org/apache/shiro/subject/ core/src/test/java/org/apache/shiro/mgt/ core/src/test/java/org/apache/shiro/realm/ samples/spring/src/main/java/org/...

Author: lhazlewood
Date: Tue Aug 25 22:04:44 2009
New Revision: 807826

URL: http://svn.apache.org/viewvc?rev=807826&view=rev
Log:
Initial fix for missing ServletRequest/Response problems

Modified:
    incubator/shiro/trunk/core/src/main/java/org/apache/shiro/mgt/DefaultSecurityManager.java
    incubator/shiro/trunk/core/src/main/java/org/apache/shiro/mgt/SecurityManager.java
    incubator/shiro/trunk/core/src/main/java/org/apache/shiro/mgt/ThreadContextSubjectBinder.java
    incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/DelegatingSubject.java
    incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/SubjectBuilder.java
    incubator/shiro/trunk/core/src/test/java/org/apache/shiro/mgt/DefaultSecurityManagerTest.java
    incubator/shiro/trunk/core/src/test/java/org/apache/shiro/realm/AuthorizingRealmTest.java
    incubator/shiro/trunk/samples/spring/src/main/java/org/apache/shiro/samples/spring/web/LoginController.java
    incubator/shiro/trunk/samples/spring/src/main/webapp/WEB-INF/sample-servlet.xml
    incubator/shiro/trunk/support/spring/src/main/java/org/apache/shiro/spring/remoting/SecureRemoteInvocationExecutor.java
    incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/mgt/DefaultWebSubjectFactory.java
    incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/ShiroFilter.java
    incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/subject/support/WebSubjectThreadState.java
    incubator/shiro/trunk/web/src/test/java/org/apache/shiro/web/AbstractWebSecurityManagerTest.java
    incubator/shiro/trunk/web/src/test/java/org/apache/shiro/web/DefaultWebSecurityManagerTest.java

Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/mgt/DefaultSecurityManager.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/mgt/DefaultSecurityManager.java?rev=807826&r1=807825&r2=807826&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/mgt/DefaultSecurityManager.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/mgt/DefaultSecurityManager.java Tue Aug 25 22:04:44 2009
@@ -236,7 +236,7 @@
      * {@link Session} instance.  Either argument can be null.
      * <p/>
      * This method is a convenience that assembles either argument into a context {@link Map Map} (if they are
-     * not null) and returns {@link #getSubject(java.util.Map)} using the Map as the parameter.
+     * not null) and returns {@link #createSubject(java.util.Map)} using the Map as the parameter.
      *
      * @param principals the identity that the constructed {@code Subject} instance should have.
      * @param session    the session to be associated with the constructed {@code Subject} instance.
@@ -251,27 +251,27 @@
         if (session != null) {
             context.put(SubjectFactory.SESSION, session);
         }
-        return getSubject(context);
+        return createSubject(context);
     }
 
     /**
      * Creates a {@code Subject} instance for the user represented by the given method arguments.
      *
-     * @param token the {@code AuthenticationToken} submitted for the successful authentication.
-     * @param info  the {@code AuthenticationInfo} of a newly authenticated user.
-     * @return the {@code Subject} instance that represents the user and session data for the newly
-     *         authenticated user.
+     * @param token    the {@code AuthenticationToken} submitted for the successful authentication.
+     * @param info     the {@code AuthenticationInfo} of a newly authenticated user.
+     * @param existing the existing {@code Subject} instance that initiated the authentication attempt
+     * @return the {@code Subject} instance that represents the context and session data for the newly
+     *         authenticated subject.
      */
-    protected Subject createSubject(AuthenticationToken token, AuthenticationInfo info) {
+    protected Subject createSubject(AuthenticationToken token, AuthenticationInfo info, Subject existing) {
         Map<String, Object> context = new HashMap<String, Object>();
         context.put(SubjectFactory.AUTHENTICATED, Boolean.TRUE);
         context.put(SubjectFactory.AUTHENTICATION_TOKEN, token);
         context.put(SubjectFactory.AUTHENTICATION_INFO, info);
-        Subject subject = getSubject(false);
-        if (subject != null) {
-            context.put(SubjectFactory.SUBJECT, subject);
+        if (existing != null) {
+            context.put(SubjectFactory.SUBJECT, existing);
         }
-        return getSubject(context);
+        return createSubject(context);
     }
 
     /**
@@ -351,7 +351,7 @@
      * @return a Subject representing the authenticated user.
      * @throws AuthenticationException if there is a problem authenticating the specified {@code token}.
      */
-    public Subject login(AuthenticationToken token) throws AuthenticationException {
+    public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException {
         AuthenticationInfo info;
         try {
             info = authenticate(token);
@@ -367,9 +367,9 @@
             }
             throw ae; //propagate
         }
-        Subject subject = createSubject(token, info);
-        bind(subject);
-        return subject;
+        Subject replaced = createSubject(token, info, subject);
+        bind(replaced);
+        return replaced;
     }
 
     protected void onSuccessfulLogin(AuthenticationToken token, AuthenticationInfo info) {
@@ -395,7 +395,7 @@
      * @see SubjectFactory#createSubject(java.util.Map)
      * @since 1.0
      */
-    public Subject getSubject(Map context) {
+    public Subject createSubject(Map context) {
         //Translate a session id if it exists into a Session object before sending to the SubjectFactory
         //The SubjectFactory should not need to know how to acquire sessions as it is often environment
         //specific - better to shield the SF from these details:
@@ -462,7 +462,7 @@
      * @param subjectContext the context map with data that will be used to construct a {@link Subject} instance via
      *                       a {@link SubjectFactory}
      * @return a session id to resolve to a {@link Session} instance or {@code null} if a session id could not be found.
-     * @see #getSubject(java.util.Map)
+     * @see #createSubject(java.util.Map)
      * @see SubjectFactory#createSubject(java.util.Map)
      */
     protected Serializable getSessionId(Map subjectContext) {
@@ -605,6 +605,6 @@
     protected Subject getSubjectBySessionId(Serializable sessionId) throws InvalidSessionException, AuthorizationException {
         Map<String, Object> context = new HashMap<String, Object>(1);
         context.put(SubjectFactory.SESSION_ID, sessionId);
-        return getSubject(context);
+        return createSubject(context);
     }
 }

Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/mgt/SecurityManager.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/mgt/SecurityManager.java?rev=807826&r1=807825&r2=807826&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/mgt/SecurityManager.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/mgt/SecurityManager.java Tue Aug 25 22:04:44 2009
@@ -29,21 +29,21 @@
 
 
 /**
- * A <tt>SecurityManager</tt> executes all security operations for <em>all</em> Subjects (aka users) across a
+ * A {@code SecurityManager} executes all security operations for <em>all</em> Subjects (aka users) across a
  * single application.
  * <p/>
  * The interface itself primarily exists as a convenience - it extends the {@link org.apache.shiro.authc.Authenticator},
  * {@link Authorizer}, and {@link SessionManager} interfaces, thereby consolidating
  * these behaviors into a single point of reference.  For most Shiro usages, this simplifies configuration and
- * tends to be a more convenient approach than referencing <code>Authenticator</code>, <code>Authorizer</code>, and
- * <code>SessionManager</code> instances seperately;  instead one only needs to interact with a
- * single <tt>SecurityManager</tt> instance.
+ * tends to be a more convenient approach than referencing {@code Authenticator}, {@code Authorizer}, and
+ * {@code SessionManager} instances separately;  instead one only needs to interact with a single
+ * {@code SecurityManager} instance.
  * <p/>
- * In addition to the above three interfaces, three unique methods are provided by this interface by itself,
- * {@link #login}, {@link #logout} and {@link #getSubject}.  A {@link org.apache.shiro.subject.Subject Subject} executes
+ * In addition to the above three interfaces, this interface provides a number of methods supporting
+ * {@link Subject} behavior. A {@link org.apache.shiro.subject.Subject Subject} executes
  * authentication, authorization, and session operations for a <em>single</em> user, and as such can only be
- * managed by <tt>A SecurityManager</tt> which is aware of all three functions.  The three parent interfaces on the
- * other hand do not 'know' about <tt>Subject</tt>s to ensure a clean separation of concerns.
+ * managed by {@code A SecurityManager} which is aware of all three functions.  The three parent interfaces on the
+ * other hand do not 'know' about {@code Subject}s to ensure a clean separation of concerns.
  * <p/>
  * <b>Usage Note</b>: In actuality the large majority of application programmers won't interact with a SecurityManager
  * very often, if at all.  <em>Most</em> application programmers only care about security operations for the currently
@@ -52,7 +52,7 @@
  * In that case, the application programmer can call the
  * {@link #getSubject() getSubject()} method and then use that returned instance for continued interaction with
  * Shiro.  If your application code does not have a direct handle to the application's
- * <code>SecurityManager</code>, you can use {@link org.apache.shiro.SecurityUtils SecurityUtils} anywhere in your code
+ * {@code SecurityManager}, you can use {@link org.apache.shiro.SecurityUtils SecurityUtils} anywhere in your code
  * to achieve the same result.
  * <p/>
  * Framework developers on the other hand might find working with an actual SecurityManager useful.
@@ -64,8 +64,9 @@
 public interface SecurityManager extends Authenticator, Authorizer, SessionManager {
 
     /**
-     * Logs in a user, returning a Subject instance if the authentication is successful or throwing an
-     * <code>AuthenticationException</code> if it is not.
+     * Logs in the specified Subject using the given {@code authenticationToken}, returning an updated Subject
+     * instance reflecting the authenticated state if successful or throwing {@code AuthenticationException} if it is
+     * not.
      * <p/>
      * Note that most application developers should probably not call this method directly unless they have a good
      * reason for doing so.  The preferred way to log in a Subject is to call
@@ -74,13 +75,13 @@
      * <p/>
      * Framework developers on the other hand might find calling this method directly useful in certain cases.
      *
+     * @param subject             the subject against which the authentication attempt will occur
      * @param authenticationToken the token representing the Subject's principal(s) and credential(s)
-     * @return an authenticated Subject upon a successful attempt
-     * @throws org.apache.shiro.authc.AuthenticationException
-     *          if the login attempt failed.
-     * @since 0.9
+     * @return the subject instance reflecting the authenticated state after a successful attempt
+     * @throws AuthenticationException if the login attempt failed.
+     * @since 1.0
      */
-    Subject login(AuthenticationToken authenticationToken) throws AuthenticationException;
+    Subject login(Subject subject, AuthenticationToken authenticationToken) throws AuthenticationException;
 
     /**
      * Logs out the specified Subject from the system.
@@ -88,7 +89,7 @@
      * Note that most application developers should not call this method unless they have a good reason for doing
      * so.  The preferred way to logout a Subject is to call
      * <code>{@link org.apache.shiro.subject.Subject#logout Subject.logout()}</code>, not the
-     * <code>SecurityManager</code> directly.
+     * {@code SecurityManager} directly.
      * <p/>
      * Framework developers on the other hand might find calling this method directly useful in certain cases.
      *
@@ -99,20 +100,20 @@
     void logout(Subject subject);
 
     /**
-     * Returns the <tt>Subject</tt> instance representing the currently executing user.
+     * Returns the {@code Subject} instance representing the currently executing user.
      *
-     * @return the <tt>Subject</tt> instance representing the currently executing user.
+     * @return the {@code Subject} instance representing the currently executing user.
      * @since 0.9
      */
     Subject getSubject();
 
     /**
-     * Returns the {@code Subject} instance reflecting the specified contextual data.
+     * Creates a {@code Subject} instance reflecting the specified contextual data.
      * <p/>
      * The context can be anything needed by this {@code SecurityManager} to construct a {@code Subject} instance.
      * Most Shiro end-users will never call this method - it exists primarily for
-     * framework development and to support any underlying {@link SubjectFactory SubjectFactory} implementations used
-     * by the {@code SecurityManager}.
+     * framework development and to support any underlying {@link SubjectFactory SubjectFactory} implementations that
+     * may be configured to be used by the {@code SecurityManager}.
      * <h4>Usage</h4>
      * The difference between calling this method and {@link #getSubject() getSubject()} is that the {@code Subject}
      * instance returned from this method is not automatically 'bound' to the application
@@ -125,7 +126,7 @@
      * @see SubjectFactory#createSubject(java.util.Map)
      * @since 1.0
      */
-    Subject getSubject(Map context);
+    Subject createSubject(Map context);
 
     //Subject getSubjectBySessionId(Serializable sessionId);
 

Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/mgt/ThreadContextSubjectBinder.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/mgt/ThreadContextSubjectBinder.java?rev=807826&r1=807825&r2=807826&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/mgt/ThreadContextSubjectBinder.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/mgt/ThreadContextSubjectBinder.java Tue Aug 25 22:04:44 2009
@@ -18,11 +18,10 @@
  */
 package org.apache.shiro.mgt;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import org.apache.shiro.subject.Subject;
 import org.apache.shiro.util.ThreadContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Associates a {@link Subject Subject} instance to the currently executing thread via the {
@@ -49,7 +48,7 @@
     /**
      * Associates the specified subject to the currently executing thread via the {@link ThreadContext ThreadContext}.
      *
-     * @param subject the subject to accosiate to the currently executing thread.
+     * @param subject the subject to associate to the currently executing thread.
      */
     public void bind(Subject subject) {
         if (log.isTraceEnabled()) {

Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/DelegatingSubject.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/DelegatingSubject.java?rev=807826&r1=807825&r2=807826&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/DelegatingSubject.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/DelegatingSubject.java Tue Aug 25 22:04:44 2009
@@ -242,7 +242,7 @@
     }
 
     public void login(AuthenticationToken token) throws AuthenticationException {
-        Subject subject = securityManager.login(token);
+        Subject subject = securityManager.login(this, token);
         PrincipalCollection principals = subject.getPrincipals();
         if (principals == null || principals.isEmpty()) {
             String msg = "Principals returned from securityManager.login( token ) returned a null or " +

Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/SubjectBuilder.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/SubjectBuilder.java?rev=807826&r1=807825&r2=807826&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/SubjectBuilder.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/SubjectBuilder.java Tue Aug 25 22:04:44 2009
@@ -95,7 +95,7 @@
     }
 
     public Subject buildSubject() {
-        return this.securityManager.getSubject(this.subjectContext);
+        return this.securityManager.createSubject(this.subjectContext);
     }
 
 

Modified: incubator/shiro/trunk/core/src/test/java/org/apache/shiro/mgt/DefaultSecurityManagerTest.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/test/java/org/apache/shiro/mgt/DefaultSecurityManagerTest.java?rev=807826&r1=807825&r2=807826&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/test/java/org/apache/shiro/mgt/DefaultSecurityManagerTest.java (original)
+++ incubator/shiro/trunk/core/src/test/java/org/apache/shiro/mgt/DefaultSecurityManagerTest.java Tue Aug 25 22:04:44 2009
@@ -26,7 +26,6 @@
 import org.apache.shiro.session.Session;
 import org.apache.shiro.session.mgt.AbstractValidatingSessionManager;
 import org.apache.shiro.subject.Subject;
-import org.apache.shiro.util.ThreadContext;
 import org.junit.After;
 import static org.junit.Assert.*;
 import org.junit.Before;
@@ -45,7 +44,6 @@
 
     @Before
     public void setup() {
-        ThreadContext.clear();
         sm = new DefaultSecurityManager();
         sm.setRealm(new PropertiesRealm());
         SecurityUtils.setSecurityManager(sm);

Modified: incubator/shiro/trunk/core/src/test/java/org/apache/shiro/realm/AuthorizingRealmTest.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/test/java/org/apache/shiro/realm/AuthorizingRealmTest.java?rev=807826&r1=807825&r2=807826&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/test/java/org/apache/shiro/realm/AuthorizingRealmTest.java (original)
+++ incubator/shiro/trunk/core/src/test/java/org/apache/shiro/realm/AuthorizingRealmTest.java Tue Aug 25 22:04:44 2009
@@ -18,49 +18,33 @@
  */
 package org.apache.shiro.realm;
 
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.security.Principal;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import org.junit.After;
-import static org.junit.Assert.*;
-import org.junit.Before;
-import org.junit.Test;
-
-import org.apache.shiro.authc.AuthenticationException;
-import org.apache.shiro.authc.AuthenticationInfo;
-import org.apache.shiro.authc.AuthenticationToken;
-import org.apache.shiro.authc.SimpleAccount;
-import org.apache.shiro.authc.SimpleAuthenticationInfo;
-import org.apache.shiro.authc.UsernamePasswordToken;
+import org.apache.shiro.authc.*;
 import org.apache.shiro.authc.credential.AllowAllCredentialsMatcher;
-import org.apache.shiro.authc.credential.CredentialsMatcher;
 import org.apache.shiro.authz.AuthorizationInfo;
 import org.apache.shiro.authz.Permission;
 import org.apache.shiro.authz.SimpleAuthorizationInfo;
 import org.apache.shiro.authz.UnauthorizedException;
 import org.apache.shiro.authz.permission.WildcardPermission;
-import org.apache.shiro.mgt.DefaultSecurityManager;
 import org.apache.shiro.subject.PrincipalCollection;
 import org.apache.shiro.subject.SimplePrincipalCollection;
-import org.apache.shiro.subject.Subject;
+import org.junit.After;
+import static org.junit.Assert.*;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.security.Principal;
+import java.util.*;
 
 
 /**
  * Simple test case for AuthorizingRealm.
- *
+ * <p/>
  * TODO - this could/should be expaned to be more robust end to end test for the AuthorizingRealm
- *
- * @author Tim Veil
  */
 public class AuthorizingRealmTest {
 
-    DefaultSecurityManager securityManager = null;
     AuthorizingRealm realm;
 
     private static final String USERNAME = "testuser";
@@ -80,17 +64,11 @@
     @Before
     public void setup() {
         realm = new AllowAllRealm();
-        securityManager = new DefaultSecurityManager();
-        // Not using constructor to prevent init() from running automatically (so tests can alter SM before init())
-        // Tests must call init() on SM before using.
-        securityManager.setRealm(realm);
 
     }
 
     @After
     public void tearDown() {
-        securityManager.destroy();
-        securityManager = null;
         realm = null;
     }
 
@@ -102,23 +80,23 @@
         } catch (UnknownHostException e) {
             e.printStackTrace();
         }
-        Subject subject = securityManager.login(new UsernamePasswordToken(USERNAME, PASSWORD, localhost));
-        assertTrue(subject.isAuthenticated());
-        assertTrue(subject.hasRole(ROLE));
-        Object principals = subject.getPrincipal();
-        assertTrue(principals instanceof UserIdPrincipal);
 
-        UsernamePrincipal usernamePrincipal = subject.getPrincipals().oneByType(UsernamePrincipal.class);
+        AuthenticationInfo info = realm.getAuthenticationInfo(new UsernamePasswordToken(USERNAME, PASSWORD, localhost));
+
+        assertNotNull(info);
+        assertTrue(realm.hasRole(info.getPrincipals(), ROLE));
+
+        Object principal = info.getPrincipals().iterator().next();
+        assertTrue(principal instanceof UserIdPrincipal);
+
+        UsernamePrincipal usernamePrincipal = info.getPrincipals().oneByType(UsernamePrincipal.class);
         assertTrue(usernamePrincipal.getUsername().equals(USERNAME));
 
-        UserIdPrincipal userIdPrincipal = subject.getPrincipals().oneByType(UserIdPrincipal.class);
+        UserIdPrincipal userIdPrincipal = info.getPrincipals().oneByType(UserIdPrincipal.class);
         assertTrue(userIdPrincipal.getUserId() == USER_ID);
 
-        String stringPrincipal = subject.getPrincipals().oneByType(String.class);
+        String stringPrincipal = info.getPrincipals().oneByType(String.class);
         assertTrue(stringPrincipal.equals(USER_ID + USERNAME));
-
-
-        subject.logout();
     }
 
     @Test
@@ -133,14 +111,12 @@
             }
         };
 
-        securityManager.setRealm(realm);
-
-        // Do login
-        Subject subject = securityManager.login(new UsernamePasswordToken(USERNAME, PASSWORD, localhost));
-        assertTrue(subject.isAuthenticated());
-        assertTrue(subject.hasRole(ROLE));
-        assertTrue((subject.getPrincipal() instanceof UsernamePrincipal));
-        assertEquals(USERNAME, ((UsernamePrincipal) subject.getPrincipal()).getUsername());
+        AuthenticationInfo info = realm.getAuthenticationInfo(new UsernamePasswordToken(USERNAME, PASSWORD, localhost));
+        assertNotNull(info);
+        assertTrue(realm.hasRole(info.getPrincipals(), ROLE));
+        Object principal = info.getPrincipals().iterator().next();
+        assertTrue(principal instanceof UsernamePrincipal);
+        assertEquals(USERNAME, ((UsernamePrincipal) principal).getUsername());
 
 
     }
@@ -238,8 +214,6 @@
 
     public class AllowAllRealm extends AuthorizingRealm {
 
-        CredentialsMatcher credentialsMatcher;
-
         public AllowAllRealm() {
             super();
             setCredentialsMatcher(new AllowAllCredentialsMatcher());

Modified: incubator/shiro/trunk/samples/spring/src/main/java/org/apache/shiro/samples/spring/web/LoginController.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/samples/spring/src/main/java/org/apache/shiro/samples/spring/web/LoginController.java?rev=807826&r1=807825&r2=807826&view=diff
==============================================================================
--- incubator/shiro/trunk/samples/spring/src/main/java/org/apache/shiro/samples/spring/web/LoginController.java (original)
+++ incubator/shiro/trunk/samples/spring/src/main/java/org/apache/shiro/samples/spring/web/LoginController.java Tue Aug 25 22:04:44 2009
@@ -18,9 +18,10 @@
  */
 package org.apache.shiro.samples.spring.web;
 
+import org.apache.shiro.SecurityUtils;
 import org.apache.shiro.authc.AuthenticationException;
 import org.apache.shiro.authc.UsernamePasswordToken;
-import org.apache.shiro.mgt.SecurityManager;
+import org.apache.shiro.subject.Subject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.validation.BindException;
@@ -33,53 +34,22 @@
 /**
  * Spring MVC controller responsible for authenticating the user.
  *
- * @author Jeremy Haile
  * @since 0.1
  */
 public class LoginController extends SimpleFormController {
 
     private static transient final Logger log = LoggerFactory.getLogger(LoginController.class);
 
-    /*--------------------------------------------
-    |             C O N S T A N T S             |
-    ============================================*/
-
-    /*--------------------------------------------
-    |    I N S T A N C E   V A R I A B L E S    |
-    ============================================*/
-    private SecurityManager securityManager;
-
-    /*--------------------------------------------
-    |         C O N S T R U C T O R S           |
-    ============================================*/
-
-    /*--------------------------------------------
-    |  A C C E S S O R S / M O D I F I E R S    |
-    ============================================*/
-
-    /**
-     * Sets the security manager that should be used to login the user.
-     *
-     * @param securityManager the security manager used to perform the login.
-     */
-
-    public void setSecurityManager(SecurityManager securityManager) {
-        this.securityManager = securityManager;
-    }
-
-    /*--------------------------------------------
-    |               M E T H O D S               |
-    ============================================*/
-
-
     protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object cmd, BindException errors) throws Exception {
 
         LoginCommand command = (LoginCommand) cmd;
 
+        Subject subject = SecurityUtils.getSubject();
+
         UsernamePasswordToken token = new UsernamePasswordToken(command.getUsername(), command.getPassword());
 
         try {
-            securityManager.login(token);
+            subject.login(token);
         } catch (AuthenticationException e) {
             log.debug("Error authenticating.", e);
             errors.reject("error.invalidLogin", "The username or password was not correct.");

Modified: incubator/shiro/trunk/samples/spring/src/main/webapp/WEB-INF/sample-servlet.xml
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/samples/spring/src/main/webapp/WEB-INF/sample-servlet.xml?rev=807826&r1=807825&r2=807826&view=diff
==============================================================================
--- incubator/shiro/trunk/samples/spring/src/main/webapp/WEB-INF/sample-servlet.xml (original)
+++ incubator/shiro/trunk/samples/spring/src/main/webapp/WEB-INF/sample-servlet.xml Tue Aug 25 22:04:44 2009
@@ -50,7 +50,6 @@
         <property name="commandClass" value="org.apache.shiro.samples.spring.web.LoginCommand"/>
         <property name="formView" value="login"/>
         <property name="successView" value="redirect:/s/index"/>
-        <property name="securityManager" ref="securityManager"/>
     </bean>
 
     <bean name="logoutController" class="org.apache.shiro.samples.spring.web.LogoutController"/>

Modified: incubator/shiro/trunk/support/spring/src/main/java/org/apache/shiro/spring/remoting/SecureRemoteInvocationExecutor.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/support/spring/src/main/java/org/apache/shiro/spring/remoting/SecureRemoteInvocationExecutor.java?rev=807826&r1=807825&r2=807826&view=diff
==============================================================================
--- incubator/shiro/trunk/support/spring/src/main/java/org/apache/shiro/spring/remoting/SecureRemoteInvocationExecutor.java (original)
+++ incubator/shiro/trunk/support/spring/src/main/java/org/apache/shiro/spring/remoting/SecureRemoteInvocationExecutor.java Tue Aug 25 22:04:44 2009
@@ -101,7 +101,7 @@
                 }
             }
 
-            Subject subject = securityManager.getSubject(context);
+            Subject subject = securityManager.createSubject(context);
             subjectThreadState = new SubjectThreadState(subject);
             subjectThreadState.bind();
 

Modified: incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/mgt/DefaultWebSubjectFactory.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/mgt/DefaultWebSubjectFactory.java?rev=807826&r1=807825&r2=807826&view=diff
==============================================================================
--- incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/mgt/DefaultWebSubjectFactory.java (original)
+++ incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/mgt/DefaultWebSubjectFactory.java Tue Aug 25 22:04:44 2009
@@ -8,6 +8,7 @@
 import org.apache.shiro.subject.Subject;
 import org.apache.shiro.web.WebUtils;
 import org.apache.shiro.web.subject.WebDelegatingSubject;
+import org.apache.shiro.web.subject.WebSubject;
 
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
@@ -36,19 +37,49 @@
 
     protected ServletRequest getServletRequest(Map context) {
         ServletRequest request = getTypedValue(context, SubjectFactory.SERVLET_REQUEST, ServletRequest.class);
+
+        //fall back on existing subject instance if it exists:
+        if (request == null) {
+            Subject existing = getTypedValue(context, SubjectFactory.SUBJECT, Subject.class);
+            if (existing instanceof WebSubject) {
+                request = ((WebSubject) existing).getServletRequest();
+            }
+        }
+        //last resort - try the thread-local (TODO - remove this if possible):
         if (request == null) {
-            throw new IllegalStateException("Subject context map must contain a " +
-                    ServletRequest.class.getName() + " instance to support Web Subject construction.");
+            request = WebUtils.getServletRequest();
+        }
+
+        if (request == null) {
+            throw new IllegalStateException("ServletRequest is not available!  A ServletRequest must be present " +
+                    "in either the Subject context map, on an existing WebSubject or via the thread context.  This " +
+                    "exception is probably indicative of an erroneous application configuration.");
         }
         return request;
     }
 
     protected ServletResponse getServletResponse(Map context) {
         ServletResponse response = getTypedValue(context, SubjectFactory.SERVLET_RESPONSE, ServletResponse.class);
+
+        //fall back on existing subject instance if it exists:
         if (response == null) {
-            throw new IllegalStateException("Subject context map must contain a " +
-                    ServletResponse.class.getName() + " instance to support Web Subject construction.");
+            Subject existing = getTypedValue(context, SubjectFactory.SUBJECT, Subject.class);
+            if (existing instanceof WebSubject) {
+                response = ((WebSubject) existing).getServletResponse();
+            }
         }
+
+        //last resort - try the thread-local (TODO - remove this if possible):
+        if (response == null) {
+            response = WebUtils.getServletResponse();
+        }
+
+        if (response == null) {
+            throw new IllegalStateException("ServletResponse is not available!  A ServletResponse must be present " +
+                    "in either the Subject context map, on an existing WebSubject or via the thread context.  This " +
+                    "exception is probably indicative of an erroneous application configuration.");
+        }
+
         return response;
     }
 

Modified: incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/ShiroFilter.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/ShiroFilter.java?rev=807826&r1=807825&r2=807826&view=diff
==============================================================================
--- incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/ShiroFilter.java (original)
+++ incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/ShiroFilter.java Tue Aug 25 22:04:44 2009
@@ -29,7 +29,6 @@
 import static org.apache.shiro.util.StringUtils.clean;
 import org.apache.shiro.util.ThreadState;
 import org.apache.shiro.web.DefaultWebSecurityManager;
-import org.apache.shiro.web.WebUtils;
 import org.apache.shiro.web.config.IniWebConfiguration;
 import org.apache.shiro.web.config.WebConfiguration;
 import org.apache.shiro.web.subject.WebSubject;
@@ -486,10 +485,6 @@
      * @since 1.0
      */
     protected ThreadState bind(ServletRequest request, ServletResponse response) {
-        //TODO - remove when Builder/SubjectThreadState API is complete:
-        WebUtils.bind(request);
-        WebUtils.bind(response);
-
         WebSubject subject = new WebSubjectBuilder(getSecurityManager(), request, response).buildWebSubject();
         ThreadState threadState = new WebSubjectThreadState(subject);
         threadState.bind();

Modified: incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/subject/support/WebSubjectThreadState.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/subject/support/WebSubjectThreadState.java?rev=807826&r1=807825&r2=807826&view=diff
==============================================================================
--- incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/subject/support/WebSubjectThreadState.java (original)
+++ incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/subject/support/WebSubjectThreadState.java Tue Aug 25 22:04:44 2009
@@ -22,12 +22,66 @@
 import org.apache.shiro.web.WebUtils;
 import org.apache.shiro.web.subject.WebSubject;
 
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
 /**
  * @since 1.0
  */
 public class WebSubjectThreadState extends SubjectThreadState {
 
+    private ServletRequest originalRequest;
+    private ServletResponse originalResponse;
+
+    private final ServletRequest request;
+    private final ServletResponse response;
+
     public WebSubjectThreadState(WebSubject subject) {
         super(subject, WebUtils.getInetAddress(subject.getServletRequest()));
+
+        ServletRequest request = subject.getServletRequest();
+        if (request == null) {
+            request = WebUtils.getServletRequest();
+        }
+        this.request = request;
+
+        ServletResponse response = subject.getServletResponse();
+        if (response == null) {
+            response = WebUtils.getServletResponse();
+        }
+        this.response = response;
+    }
+
+    @Override
+    public void bind() {
+        super.bind();
+        this.originalRequest = WebUtils.getServletRequest();
+        this.originalResponse = WebUtils.getServletResponse();
+
+        if (request == null) {
+            WebUtils.unbindServletRequest();
+        } else {
+            WebUtils.bind(request);
+        }
+        if (response == null) {
+            WebUtils.unbindServletResponse();
+        } else {
+            WebUtils.bind(response);
+        }
+    }
+
+    @Override
+    public void restore() {
+        if (originalRequest == null) {
+            WebUtils.unbindServletRequest();
+        } else {
+            WebUtils.bind(originalRequest);
+        }
+        if (originalResponse == null) {
+            WebUtils.unbindServletResponse();
+        } else {
+            WebUtils.bind(originalResponse);
+        }
+        super.restore();
     }
 }

Modified: incubator/shiro/trunk/web/src/test/java/org/apache/shiro/web/AbstractWebSecurityManagerTest.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/test/java/org/apache/shiro/web/AbstractWebSecurityManagerTest.java?rev=807826&r1=807825&r2=807826&view=diff
==============================================================================
--- incubator/shiro/trunk/web/src/test/java/org/apache/shiro/web/AbstractWebSecurityManagerTest.java (original)
+++ incubator/shiro/trunk/web/src/test/java/org/apache/shiro/web/AbstractWebSecurityManagerTest.java Tue Aug 25 22:04:44 2009
@@ -34,20 +34,15 @@
  */
 public abstract class AbstractWebSecurityManagerTest {
 
-    private WebSubjectThreadState threadState;
-
     @After
     public void tearDown() {
         ThreadContext.clear();
     }
 
     protected Subject newSubject(SecurityManager sm, ServletRequest request, ServletResponse response) {
-        //TODO - remove dependency on WebUtils
-        WebUtils.bind(request);
-        WebUtils.bind(response);
         WebSubject subject = new WebSubjectBuilder(sm, request, response).buildWebSubject();
-        this.threadState = new WebSubjectThreadState(subject);
-        this.threadState.bind();
+        WebSubjectThreadState threadState = new WebSubjectThreadState(subject);
+        threadState.bind();
         return subject;
     }
 

Modified: incubator/shiro/trunk/web/src/test/java/org/apache/shiro/web/DefaultWebSecurityManagerTest.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/test/java/org/apache/shiro/web/DefaultWebSecurityManagerTest.java?rev=807826&r1=807825&r2=807826&view=diff
==============================================================================
--- incubator/shiro/trunk/web/src/test/java/org/apache/shiro/web/DefaultWebSecurityManagerTest.java (original)
+++ incubator/shiro/trunk/web/src/test/java/org/apache/shiro/web/DefaultWebSecurityManagerTest.java Tue Aug 25 22:04:44 2009
@@ -18,6 +18,8 @@
  */
 package org.apache.shiro.web;
 
+import org.apache.shiro.authc.UsernamePasswordToken;
+import org.apache.shiro.realm.text.PropertiesRealm;
 import org.apache.shiro.session.ExpiredSessionException;
 import org.apache.shiro.session.Session;
 import org.apache.shiro.subject.Subject;
@@ -46,6 +48,8 @@
     @Before
     public void setup() {
         sm = new DefaultWebSecurityManager();
+        sm.setSessionMode(DefaultWebSecurityManager.NATIVE_SESSION_MODE);
+        sm.setRealm(new PropertiesRealm());
     }
 
     @After
@@ -72,6 +76,27 @@
     }
 
     @Test
+    public void testLogin() {
+        HttpServletRequest mockRequest = createNiceMock(HttpServletRequest.class);
+        HttpServletResponse mockResponse = createNiceMock(HttpServletResponse.class);
+
+        expect(mockRequest.getCookies()).andReturn(null);
+        expect(mockRequest.getContextPath()).andReturn("/");
+
+        replay(mockRequest);
+
+        Subject subject = newSubject(mockRequest, mockResponse);
+
+        assertFalse(subject.isAuthenticated());
+
+        subject.login(new UsernamePasswordToken("lonestarr", "vespa"));
+
+        assertTrue(subject.isAuthenticated());
+        assertNotNull(subject.getPrincipal());
+        assertTrue(subject.getPrincipal().equals("lonestarr"));
+    }
+
+    @Test
     public void testSessionTimeout() {
         shiroSessionModeInit();
         long globalTimeout = 100;
@@ -145,9 +170,7 @@
         verify(mockResponse);
 
         mockRequest = createNiceMock(HttpServletRequest.class);
-        WebUtils.bind(mockRequest);
         mockResponse = createNiceMock(HttpServletResponse.class);
-        WebUtils.bind(mockResponse);
         //now simulate the cookie going with the request and the Subject should be acquired based on that:
         Cookie[] cookies = new Cookie[]{new Cookie(ShiroHttpSession.DEFAULT_SESSION_ID_NAME, sessionId.toString())};
         expect(mockRequest.getCookies()).andReturn(cookies).anyTimes();