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/12/19 00:45:41 UTC

svn commit: r892403 - in /incubator/shiro/trunk: core/src/main/java/org/apache/shiro/mgt/ web/src/main/java/org/apache/shiro/web/ web/src/main/java/org/apache/shiro/web/mgt/

Author: lhazlewood
Date: Fri Dec 18 23:45:40 2009
New Revision: 892403

URL: http://svn.apache.org/viewvc?rev=892403&view=rev
Log:
SHIRO-114 - removed circular dependency.  The SecurityManager instance is now passed in as a context attribute

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/DefaultSubjectFactory.java
    incubator/shiro/trunk/core/src/main/java/org/apache/shiro/mgt/SubjectFactory.java
    incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/DefaultWebSecurityManager.java
    incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/mgt/DefaultWebSubjectFactory.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=892403&r1=892402&r2=892403&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 Fri Dec 18 23:45:40 2009
@@ -19,7 +19,6 @@
 package org.apache.shiro.mgt;
 
 import org.apache.shiro.authc.*;
-import org.apache.shiro.authz.AuthorizationException;
 import org.apache.shiro.authz.Authorizer;
 import org.apache.shiro.crypto.Cipher;
 import org.apache.shiro.realm.Realm;
@@ -34,7 +33,6 @@
 
 import java.io.Serializable;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -87,7 +85,7 @@
      */
     public DefaultSecurityManager() {
         super();
-        this.subjectFactory = new DefaultSubjectFactory(this);
+        this.subjectFactory = new DefaultSubjectFactory();
         this.subjectBinder = new SessionSubjectBinder();
     }
 
@@ -117,9 +115,6 @@
 
     public void setSubjectFactory(SubjectFactory subjectFactory) {
         this.subjectFactory = subjectFactory;
-        if (this.subjectFactory instanceof SecurityManagerAware) {
-            ((SecurityManagerAware) this.subjectFactory).setSecurityManager(this);
-        }
     }
 
     public SubjectBinder getSubjectBinder() {
@@ -325,7 +320,7 @@
     }
 
     /**
-     * This implementation attempts to resolve any session ID that may exist in the context argument by first
+     * This implementation attempts to resolve any session ID that may exist in the context argument by
      * passing it to the {@link #resolveSession(Map)} method.  The
      * return value from that call is then used to attempt to resolve the subject identity via the
      * {@link #resolvePrincipals(java.util.Map)} method.  The return value from that call is then used to create
@@ -338,17 +333,46 @@
      * @since 1.0
      */
     public Subject createSubject(Map context) {
+        if (context == null) {
+            context = new HashMap();
+        }
+
+        //ensure that the context map has a SecurityManager instance, and if not, add one:
+        Map resolved = ensureSecurityManager(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:
-        Map resolved = resolveSession(context);
+        resolved = resolveSession(resolved);
+
         //Similarly, the SubjectFactory should not have any concept of RememberMe - translate that here first
         //if possible before handing off to the SubjectFactory:
         resolved = resolvePrincipals(resolved);
+
         return getSubjectFactory().createSubject(resolved);
     }
 
     /**
+     * Determines if there is a {@code SecurityManager} instance in the context map under the
+     * {@link SubjectFactory#SECURITY_MANAGER} key, and if not, adds 'this' to the map under that key.  This ensures
+     * the SubjectFactory instance will have access to a SecurityManager during Subject construction if necessary.
+     *
+     * @param context the subject context data that may contain a SecurityManager instance.
+     * @return The context Map to use to pass to a {@link SubjectFactory} for subject creation.
+     * @since 1.0
+     */
+    @SuppressWarnings({"unchecked"})
+    protected Map ensureSecurityManager(Map context) {
+        if (context.containsKey(SubjectFactory.SECURITY_MANAGER)) {
+            log.debug("Context already contains a SecurityManager instance.  Returning.");
+            return context;
+        }
+        log.trace("No SecurityManager found in context.  Adding self reference.");
+        context.put(SubjectFactory.SECURITY_MANAGER, this);
+        return context;
+    }
+
+    /**
      * Attempts to resolve any session id in the context to its corresponding {@link Session} and returns a
      * context that represents this resolved {@code Session} to ensure it may be referenced if necessary by the
      * invoked {@link SubjectFactory} that performs actual {@link Subject} construction.
@@ -374,19 +398,18 @@
         }
         log.trace("No session found in context.  Looking for a session id to resolve in to a session.");
         //otherwise try to resolve a session if a session id exists:
-        Map copy = new HashMap(context);
         Serializable sessionId = getSessionId(context);
         if (sessionId != null) {
             try {
                 Session session = getSession(sessionId);
-                copy.put(SubjectFactory.SESSION, session);
+                context.put(SubjectFactory.SESSION, session);
             } catch (InvalidSessionException e) {
                 onInvalidSessionId(sessionId, e);
                 log.debug("Context referenced sessionId is invalid.  Ignoring and creating an anonymous " +
                         "(session-less) Subject instance.", e);
             }
         }
-        return copy;
+        return context;
     }
 
     /**
@@ -442,22 +465,19 @@
      */
     @SuppressWarnings({"unchecked"})
     protected Map resolvePrincipals(Map context) {
-        Map ctx = context;
-
         if (!containsIdentity(context)) {
             log.trace("No identity (PrincipalCollection) found in the context.  Looking for a remembered identity.");
             PrincipalCollection principals = getRememberedIdentity();
             if (principals != null) {
                 log.debug("Found remembered PrincipalCollection.  Adding to the context to be used " +
                         "for subject construction by the SubjectFactory.");
-                ctx = new HashMap(context);
-                ctx.put(SubjectFactory.PRINCIPALS, principals);
+                context.put(SubjectFactory.PRINCIPALS, principals);
             } else {
                 log.trace("No remembered identity found.  Returning original context.");
             }
         }
 
-        return ctx;
+        return context;
     }
 
     /**
@@ -573,45 +593,9 @@
     public Subject getSubject() {
         Subject subject = getSubjectBinder().getSubject();
         if (subject == null) {
-            subject = createSubject(Collections.EMPTY_MAP);
+            subject = createSubject(new HashMap());
             bind(subject);
         }
         return subject;
     }
-
-    /**
-     * Acquires the {@link Subject Subject} that owns the {@link Session Session} with the specified {@code sessionId}.
-     * <p/>
-     * <b>Although simple in concept, this method provides incredibly powerful functionality:</b>
-     * <p/>
-     * The ability to reference a {@code Subject} and their server-side session
-     * <em>across clients of different mediums</em> such as web applications, Java applets,
-     * standalone C# clients over XMLRPC and/or SOAP, and many others. This is a <em>huge</em>
-     * benefit in heterogeneous enterprise applications.
-     * <p/>
-     * To maintain session integrity across client mediums, the {@code sessionId} <b>must</b> be transmitted
-     * to all client mediums securely (e.g. over SSL) to prevent man-in-the-middle attacks.  This
-     * is nothing new - all web applications are susceptible to the same problem when transmitting
-     * {@code Cookie}s or when using URL rewriting.  As long as the
-     * {@code sessionId} is transmitted securely, session integrity can be maintained.
-     *
-     * @param sessionId the id of the session that backs the desired Subject being acquired.
-     * @return the {@code Subject} that owns the {@code Session Session} with the specified {@code sessionId}
-     * @throws InvalidSessionException if the session identified by {@code sessionId} has been stopped, expired, or
-     *                                 doesn't exist.
-     * @throws AuthorizationException  if the executor of this method is not allowed to acquire the owning
-     *                                 {@code Subject}.  The reason for the exception is implementation-specific and
-     *                                 could be for any number of reasons.  A common reason in many systems would be
-     *                                 if one host tried to acquire a {@code Subject} based on a {@code Session} that
-     *                                 originated on an entirely different host (although it is not a Shiro requirement
-     *                                 this scenario is disallowed - its just an example that <em>may</em> throw an
-     *                                 Exception in some systems).
-     * @see org.apache.shiro.authz.HostUnauthorizedException
-     * @since 1.0
-     */
-    protected Subject getSubjectBySessionId(Serializable sessionId) throws InvalidSessionException, AuthorizationException {
-        Map<String, Object> context = new HashMap<String, Object>(1);
-        context.put(SubjectFactory.SESSION_ID, sessionId);
-        return createSubject(context);
-    }
 }

Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/mgt/DefaultSubjectFactory.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/mgt/DefaultSubjectFactory.java?rev=892403&r1=892402&r2=892403&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/mgt/DefaultSubjectFactory.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/mgt/DefaultSubjectFactory.java Fri Dec 18 23:45:40 2009
@@ -18,6 +18,7 @@
  */
 package org.apache.shiro.mgt;
 
+import org.apache.shiro.SecurityUtils;
 import org.apache.shiro.authc.AuthenticationInfo;
 import org.apache.shiro.authc.AuthenticationToken;
 import org.apache.shiro.authc.HostAuthenticationToken;
@@ -25,6 +26,9 @@
 import org.apache.shiro.subject.DelegatingSubject;
 import org.apache.shiro.subject.PrincipalCollection;
 import org.apache.shiro.subject.Subject;
+import org.apache.shiro.util.CollectionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.util.Map;
 
@@ -36,25 +40,13 @@
  * @author Les Hazlewood
  * @since 1.0
  */
-public class DefaultSubjectFactory implements SubjectFactory, SecurityManagerAware {
+public class DefaultSubjectFactory implements SubjectFactory {
 
-    private SecurityManager securityManager;
+    private static transient final Logger log = LoggerFactory.getLogger(DefaultSubjectFactory.class);
 
     public DefaultSubjectFactory() {
     }
 
-    public DefaultSubjectFactory(SecurityManager securityManager) {
-        this.securityManager = securityManager;
-    }
-
-    public SecurityManager getSecurityManager() {
-        return securityManager;
-    }
-
-    public void setSecurityManager(SecurityManager securityManager) {
-        this.securityManager = securityManager;
-    }
-
     @SuppressWarnings({"unchecked"})
     protected static <E> E getTypedValue(Map context, String key, Class<E> type) {
         E found = null;
@@ -71,14 +63,29 @@
         return found;
     }
 
-    protected static boolean isEmpty(PrincipalCollection principals) {
-        return principals == null || principals.isEmpty();
+    protected SecurityManager getSecurityManager(Map context) {
+        SecurityManager securityManager = getTypedValue(context, SubjectFactory.SECURITY_MANAGER, SecurityManager.class);
+        if (securityManager == null) {
+            if (log.isDebugEnabled()) {
+                log.debug("No SecurityManager available in subject context map.  " +
+                        "Falling back to SecurityUtils.getSecurityManager() lookup.");
+            }
+            securityManager = SecurityUtils.getSecurityManager();
+        }
+        if (securityManager == null) {
+            String msg = "No " + SecurityManager.class.getName() + " instance was available in the subject context " +
+                    "via the " + SubjectFactory.SECURITY_MANAGER + " key.  " +
+                    "This is required for this " + SubjectFactory.class.getSimpleName() + " implementation to " +
+                    "function.";
+            throw new IllegalStateException(msg);
+        }
+        return securityManager;
     }
 
     protected PrincipalCollection getPrincipals(Map context, Session session) {
         PrincipalCollection principals = getTypedValue(context, SubjectFactory.PRINCIPALS, PrincipalCollection.class);
 
-        if (isEmpty(principals)) {
+        if (CollectionUtils.isEmpty(principals)) {
             //check to see if they were just authenticated:
             AuthenticationInfo info = getTypedValue(context, SubjectFactory.AUTHENTICATION_INFO, AuthenticationInfo.class);
             if (info != null) {
@@ -86,14 +93,14 @@
             }
         }
 
-        if (isEmpty(principals)) {
+        if (CollectionUtils.isEmpty(principals)) {
             Subject subject = getTypedValue(context, SubjectFactory.SUBJECT, Subject.class);
             if (subject != null) {
                 principals = subject.getPrincipals();
             }
         }
 
-        if (isEmpty(principals)) {
+        if (CollectionUtils.isEmpty(principals)) {
             //try the session:
             if (session != null) {
                 principals = (PrincipalCollection) session.getAttribute(SessionSubjectBinder.PRINCIPALS_SESSION_KEY);
@@ -156,11 +163,12 @@
     }
 
     public Subject createSubject(Map context) {
+        SecurityManager securityManager = getSecurityManager(context);
         Session session = getSession(context);
         PrincipalCollection principals = getPrincipals(context, session);
         boolean authenticated = isAuthenticated(context, session);
         String host = getHost(context, session);
-        return newSubjectInstance(principals, authenticated, host, session, getSecurityManager());
+        return newSubjectInstance(principals, authenticated, host, session, securityManager);
     }
 
     protected Subject newSubjectInstance(PrincipalCollection principals, boolean authenticated, String host,

Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/mgt/SubjectFactory.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/mgt/SubjectFactory.java?rev=892403&r1=892402&r2=892403&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/mgt/SubjectFactory.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/mgt/SubjectFactory.java Fri Dec 18 23:45:40 2009
@@ -30,6 +30,8 @@
  */
 public interface SubjectFactory {
 
+    public static final String SECURITY_MANAGER = SubjectFactory.class.getName() + ".SECURITY_MANAGER";
+
     public static final String SESSION_ID = SubjectFactory.class.getName() + ".SESSION_ID";
 
     public static final String AUTHENTICATION_TOKEN = SubjectFactory.class.getName() + ".AUTHENTICATION_TOKEN";

Modified: incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/DefaultWebSecurityManager.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/DefaultWebSecurityManager.java?rev=892403&r1=892402&r2=892403&view=diff
==============================================================================
--- incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/DefaultWebSecurityManager.java (original)
+++ incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/DefaultWebSecurityManager.java Fri Dec 18 23:45:40 2009
@@ -60,7 +60,7 @@
 
     public DefaultWebSecurityManager() {
         super();
-        setSubjectFactory(new DefaultWebSubjectFactory(this));
+        setSubjectFactory(new DefaultWebSubjectFactory());
         setRememberMeManager(new WebRememberMeManager());
         setSessionManager(new ServletContainerSessionManager());
     }

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=892403&r1=892402&r2=892403&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 Fri Dec 18 23:45:40 2009
@@ -48,10 +48,6 @@
         super();
     }
 
-    public DefaultWebSubjectFactory(SecurityManager securityManager) {
-        super(securityManager);
-    }
-
     protected ServletRequest getServletRequest(Map context) {
         ServletRequest request = getTypedValue(context, SubjectFactory.SERVLET_REQUEST, ServletRequest.class);
 
@@ -111,13 +107,14 @@
     }
 
     public Subject createSubject(Map context) {
+        SecurityManager securityManager = getSecurityManager(context);
         Session session = getSession(context);
         PrincipalCollection principals = getPrincipals(context, session);
         boolean authenticated = isAuthenticated(context, session);
         String host = getHost(context, session);
         ServletRequest request = getServletRequest(context);
         ServletResponse response = getServletResponse(context);
-        return newSubjectInstance(principals, authenticated, host, session, request, response, getSecurityManager());
+        return newSubjectInstance(principals, authenticated, host, session, request, response, securityManager);
     }
 
     protected Subject newSubjectInstance(PrincipalCollection principals, boolean authenticated,