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,