shiro-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From lhazlew...@apache.org
Subject svn commit: r816790 - in /incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject: DelegatingSubject.java PrincipalCollection.java Subject.java
Date Fri, 18 Sep 2009 21:34:27 GMT
Author: lhazlewood
Date: Fri Sep 18 21:34:25 2009
New Revision: 816790

URL: http://svn.apache.org/viewvc?rev=816790&view=rev
Log:
SHIRO-25: Subject 'assumeIdentity' additions.  Work in progress - do not use yet.  Method
names reflect current list discussion, but could change at any time.

Modified:
    incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/DelegatingSubject.java
    incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/PrincipalCollection.java
    incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/Subject.java

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=816790&r1=816789&r2=816790&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
Fri Sep 18 21:34:25 2009
@@ -31,12 +31,14 @@
 import org.apache.shiro.session.mgt.DelegatingSession;
 import org.apache.shiro.subject.support.SubjectCallable;
 import org.apache.shiro.subject.support.SubjectRunnable;
+import org.apache.shiro.util.CollectionUtils;
 import org.apache.shiro.util.ThreadContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.Serializable;
 import java.net.InetAddress;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.concurrent.Callable;
@@ -73,10 +75,13 @@
 
     private static final Logger log = LoggerFactory.getLogger(DelegatingSubject.class);
 
-    protected PrincipalCollection principals = new SimplePrincipalCollection();
-    protected boolean authenticated = false;
-    protected InetAddress inetAddress = null;
-    protected Session session = null;
+    private static final String IDENTITIES_SESSION_KEY = DelegatingSubject.class.getName()
+ ".IDENTITIES_SESSION_KEY";
+
+    protected PrincipalCollection principals;
+    protected boolean authenticated;
+    protected InetAddress inetAddress;
+    protected Session session;
+    private List<PrincipalCollection> assumedIdentities; //supports assumed identities
(aka 'run as')
 
     protected transient SecurityManager securityManager;
 
@@ -92,12 +97,10 @@
         this.securityManager = securityManager;
         this.principals = principals;
         this.authenticated = authenticated;
-
-        if (inetAddress != null) {
-            this.inetAddress = inetAddress;
-        }
+        this.inetAddress = inetAddress;
         if (session != null) {
             this.session = decorate(session);
+            this.assumedIdentities = getAssumedIdentities(this.session);
         }
     }
 
@@ -105,7 +108,7 @@
         if (session == null) {
             throw new IllegalArgumentException("session cannot be null");
         }
-        return decorateSession(session.getId());
+        return new StoppingAwareProxiedSession(session, this);
     }
 
     protected Session decorateSession(Serializable sessionId) {
@@ -113,7 +116,7 @@
             throw new IllegalArgumentException("sessionId cannot be null");
         }
         DelegatingSession target = new DelegatingSession(getSecurityManager(), sessionId);
-        return new StoppingAwareProxiedSession(target, this);
+        return decorate(target);
     }
 
     public SecurityManager getSecurityManager() {
@@ -121,8 +124,7 @@
     }
 
     protected boolean hasPrincipals() {
-        PrincipalCollection principals = getPrincipals();
-        return principals != null && !principals.isEmpty();
+        return !CollectionUtils.isEmpty(getPrincipals());
     }
 
     /**
@@ -134,19 +136,22 @@
         return this.inetAddress;
     }
 
+    protected Object getPrimaryPrincipal(PrincipalCollection principals) {
+        if (!CollectionUtils.isEmpty(principals)) {
+            return principals.iterator().next();
+        }
+        return null;
+    }
+
     /**
      * @see Subject#getPrincipal()
      */
     public Object getPrincipal() {
-        PrincipalCollection principals = getPrincipals();
-        if (principals == null || principals.isEmpty()) {
-            return null;
-        }
-        return principals.asSet().iterator().next();
+        return getPrimaryPrincipal(getPrincipals());
     }
 
     public PrincipalCollection getPrincipals() {
-        return this.principals;
+        return CollectionUtils.isEmpty(this.assumedIdentities) ? this.principals : this.assumedIdentities.get(0);
     }
 
     public boolean isPermitted(String permission) {
@@ -243,28 +248,40 @@
 
     public void login(AuthenticationToken token) throws AuthenticationException {
         Subject subject = securityManager.login(this, token);
-        PrincipalCollection principals = subject.getPrincipals();
+
+        PrincipalCollection principals;
+
+        InetAddress inetAddress = null;
+
+        if (subject instanceof DelegatingSubject) {
+            DelegatingSubject delegating = (DelegatingSubject) subject;
+            //we have to do this in case there are assumed identities - we don't want to
lose the 'real' principals:
+            principals = delegating.principals;
+            inetAddress = delegating.inetAddress;
+        } else {
+            principals = subject.getPrincipals();
+        }
+
         if (principals == null || principals.isEmpty()) {
             String msg = "Principals returned from securityManager.login( token ) returned
a null or " +
-                    "empty value.  This value must be non null and populated with one or
more elements.  " +
-                    "Please check the SecurityManager implementation to ensure this happens
after a " +
-                    "successful login attempt.";
+                    "empty value.  This value must be non null and populated with one or
more elements.";
             throw new IllegalStateException(msg);
         }
         this.principals = principals;
+        this.authenticated = true;
+        if (token instanceof InetAuthenticationToken) {
+            inetAddress = ((InetAuthenticationToken) token).getInetAddress();
+        }
+        if (inetAddress != null) {
+            this.inetAddress = inetAddress;
+        }
         Session session = subject.getSession(false);
         if (session != null) {
             this.session = decorate(session);
+            this.assumedIdentities = getAssumedIdentities(this.session);
         } else {
             this.session = null;
         }
-        this.authenticated = true;
-        if (token instanceof InetAuthenticationToken) {
-            InetAddress inetAddress = ((InetAuthenticationToken) token).getInetAddress();
-            if (inetAddress != null) {
-                this.inetAddress = inetAddress;
-            }
-        }
         ThreadContext.bind(this);
     }
 
@@ -303,6 +320,7 @@
             this.principals = null;
             this.authenticated = false;
             this.inetAddress = null;
+            this.assumedIdentities = null;
             //Don't set securityManager to null here - the Subject can still be
             //used, it is just considered anonymous at this point.  The SecurityManager instance
is
             //necessary if the subject would log in again or acquire a new session.  This
is in response to
@@ -315,21 +333,6 @@
         this.session = null;
     }
 
-    private class StoppingAwareProxiedSession extends ProxiedSession {
-
-        private final DelegatingSubject owner;
-
-        private StoppingAwareProxiedSession(Session target, DelegatingSubject owningSubject)
{
-            super(target);
-            owner = owningSubject;
-        }
-
-        public void stop() throws InvalidSessionException {
-            super.stop();
-            owner.sessionStopped();
-        }
-    }
-
     public <V> V execute(Callable<V> callable) throws ExecutionException {
         Callable<V> associated = associateWith(callable);
         try {
@@ -358,4 +361,96 @@
         }
         return new SubjectRunnable(this, runnable);
     }
+
+    private class StoppingAwareProxiedSession extends ProxiedSession {
+
+        private final DelegatingSubject owner;
+
+        private StoppingAwareProxiedSession(Session target, DelegatingSubject owningSubject)
{
+            super(target);
+            owner = owningSubject;
+        }
+
+        public void stop() throws InvalidSessionException {
+            super.stop();
+            owner.sessionStopped();
+        }
+    }
+
+    // ======================================
+    // 'Run As' support implementations
+    // ======================================
+    //TODO - WORK IN PROGRESS - DO NOT USE
+    public void assumeIdentity(Subject subject) {
+        if (subject == null) {
+            throw new NullPointerException("Subject argument cannot be null.");
+        }
+        PrincipalCollection principals = subject.getPrincipals();
+        if (principals == null || principals.isEmpty()) {
+            throw new IllegalArgumentException("Subject argument does not have any principals.");
+        }
+        pushIdentity(principals);
+    }
+
+    //TODO - WORK IN PROGRESS - DO NOT USE
+    public boolean isAssumedIdentity() {
+        return !CollectionUtils.isEmpty(this.assumedIdentities);
+    }
+
+    //TODO - WORK IN PROGRESS - DO NOT USE
+    public Object getOriginalPrincipal() {
+        return getPrimaryPrincipal(this.principals);
+    }
+
+    //TODO - WORK IN PROGRESS - DO NOT USE
+    public PrincipalCollection getOriginalPrincipals() {
+        return this.principals;
+    }
+
+    //TODO - WORK IN PROGRESS - DO NOT USE
+    public void releaseAssumedIdentity() {
+        popIdentity();
+    }
+
+    //TODO - WORK IN PROGRESS - DO NOT USE
+    protected List<PrincipalCollection> getAssumedIdentities(Session session) {
+        if (session != null) {
+            //noinspection unchecked
+            return (List<PrincipalCollection>) session.getAttribute(IDENTITIES_SESSION_KEY);
+        }
+        return null;
+    }
+
+    //TODO - WORK IN PROGRESS - DO NOT USE
+    protected void pushIdentity(PrincipalCollection principals) {
+        if (this.assumedIdentities == null) {
+            this.assumedIdentities = new ArrayList<PrincipalCollection>();
+        }
+        this.assumedIdentities.add(0, principals);
+        Session session = getSession();
+        session.setAttribute(IDENTITIES_SESSION_KEY, this.assumedIdentities);
+    }
+
+    //TODO - WORK IN PROGRESS - DO NOT USE
+    protected PrincipalCollection popIdentity() {
+        PrincipalCollection popped = null;
+        if (!CollectionUtils.isEmpty(this.assumedIdentities)) {
+            popped = this.assumedIdentities.remove(0);
+            Session session;
+            if (!CollectionUtils.isEmpty(this.assumedIdentities)) {
+                //persist the changed deque to the session
+                session = getSession();
+                session.setAttribute(IDENTITIES_SESSION_KEY, this.assumedIdentities);
+            } else {
+                //deque is empty, remove it from the session:
+                session = getSession(false);
+                if (session != null) {
+                    session.removeAttribute(IDENTITIES_SESSION_KEY);
+                }
+            }
+        }
+
+        return popped;
+    }
+
 }

Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/PrincipalCollection.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/PrincipalCollection.java?rev=816790&r1=816789&r2=816790&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/PrincipalCollection.java
(original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/PrincipalCollection.java
Fri Sep 18 21:34:25 2009
@@ -33,36 +33,33 @@
  * {@code Realm} implementation.  The 'first' principal is that which is returned by
  * {@link #asList() asList()}{@code .iterator().next()}.
  * <p/>
- * A PrincipalCollection orgainizes its internal principals based on the {@code Realm} where
they came from when the
+ * A PrincipalCollection organizes its internal principals based on the {@code Realm} where
they came from when the
  * Subject was first created.  To obtain the principal(s) for a specific Realm, see the {@link
#fromRealm} method.  You
  * can also see which realms contributed to this collection via the {@link #getRealmNames()
getRealmNames()} method.
  *
+ * @author Les Hazlewood
  * @see #fromRealm(String realmName)
  * @see #getRealmNames()
- *
- * @author Les Hazlewood
  * @since 0.9
  */
 public interface PrincipalCollection extends Iterable, Serializable {
 
     /**
-     * Returns a single principal assignable from the specified type, or <tt>null</tt>
if there are none of the
+     * Returns a single principal assignable from the specified type, or {@code null} if
there are none of the
      * specified type.
-     *
-     * <p>Note that this would return <code>null</code> List always if
the corresponding subject has not yet
-     * logged in.</p>
+     * <p/>
+     * Note that this will return {@code null} if the 'owning' subject has not yet logged
in.
      *
      * @param type the type of the principal that should be returned.
-     * @return a principal of the specified type or <tt>null</tt> if there isn't
one of the specified type.
+     * @return a principal of the specified type or {@code null} if there isn't one of the
specified type.
      */
     <T> T oneByType(Class<T> type);
 
     /**
      * Returns all principals assignable from the specified type, or an empty Collection
if no principals of that
      * type are contained.
-     *
-     * <p>Note that this would return an empty Collection always if the corresponding
subject has not yet
-     * logged in.</p>
+     * <p/>
+     * Note that this will return an empty Collection if the 'owning' subject has not yet
logged in.
      *
      * @param type the type of the principals that should be returned.
      * @return a Collection of principals that are assignable from the specified type, or
@@ -73,8 +70,8 @@
     /**
      * Returns a single Subject's principals retrieved from all configured Realms as a List,
or an empty List if
      * there are not any principals.
-     *
-     * <p>Note that this would return an empty List always if the corresponding subject
has not yet logged in.</p>
+     * <p/>
+     * Note that this will return an empty List if the 'owning' subject has not yet logged
in.
      *
      * @return a single Subject's principals retrieved from all configured Realms as a List.
      */
@@ -83,8 +80,8 @@
     /**
      * Returns a single Subject's principals retrieved from all configured Realms as a Set,
or an empty Set if there
      * are not any principals.
-     *
-     * <p>Note that this would return an empty Set always if the corresponding subject
has not yet logged in.</p>
+     * <p/>
+     * Note that this will return an empty Set if the 'owning' subject has not yet logged
in.
      *
      * @return a single Subject's principals retrieved from all configured Realms as a Set.
      */
@@ -93,8 +90,8 @@
     /**
      * Returns a single Subject's principals retrieved from the specified Realm <em>only</em>
as a Collection, or an empty
      * Collection if there are not any principals from that realm.
-     *
-     * <p>Note that this would return an empty Collection always if the corresponding
subject has not yet logged in.</p>
+     * <p/>
+     * Note that this will return an empty Collection if the 'owning' subject has not yet
logged in.
      *
      * @param realmName the name of the Realm from which the principals were retrieved.
      * @return the Subject's principals from the specified Realm only as a Collection or
an empty Collection if there
@@ -110,9 +107,9 @@
     Set<String> getRealmNames();
 
     /**
-     * Returns <code>true</code> if this collection is empty, <code>false</code>
otherwise.
+     * Returns {@code true} if this collection is empty, {@code false} otherwise.
      *
-     * @return <code>true</code> if this collection is empty, <code>false</code>
otherwise.
+     * @return {@code true} if this collection is empty, {@code false} otherwise.
      */
     boolean isEmpty();
 }

Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/Subject.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/Subject.java?rev=816790&r1=816789&r2=816790&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/Subject.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/subject/Subject.java Fri Sep
18 21:34:25 2009
@@ -478,11 +478,15 @@
      */
     Runnable associateWith(Runnable runnable);
 
-    /*void runAs(PrincipalCollection identity);
+    /*void assumeIdentity(PrincipalCollection identity);
 
     <V> V runAs(PrincipalCollection identity, Callable<V> work);
 
-    PrincipalCollection getRunAsIdentity();*/
+    PrincipalCollection getOriginalIdentity();
+
+    PrincipalCollection releaseAssumedIdentity();
+
+    */
 
     /**
      * Builder design pattern implementation for creating {@link Subject} instances in a
simplified way without



Mime
View raw message