Author: peter_firmstone
Date: Sun Jul 22 10:19:46 2012
New Revision: 1364250

URL: http://svn.apache.org/viewvc?rev=1364250&view=rev
Log:
Subject.doAs and doAsPrivileged alternatives.

Added:
    river/jtsk/trunk/src/org/apache/river/api/security/SubjectDomain.java   
(with props)
Modified:
    river/jtsk/trunk/src/net/jini/security/Security.java
    river/jtsk/trunk/src/org/apache/river/api/security/CertificateGrant.java
    river/jtsk/trunk/src/org/apache/river/api/security/ClassLoaderGrant.java
    river/jtsk/trunk/src/org/apache/river/api/security/PermissionGrant.java
    river/jtsk/trunk/src/org/apache/river/api/security/PrincipalGrant.java
    
river/jtsk/trunk/src/org/apache/river/api/security/ProtectionDomainGrant.java

Modified: river/jtsk/trunk/src/net/jini/security/Security.java
URL: 
http://svn.apache.org/viewvc/river/jtsk/trunk/src/net/jini/security/Security.java?rev=1364250&r1=1364249&r2=1364250&view=diff
==============================================================================
--- river/jtsk/trunk/src/net/jini/security/Security.java (original)
+++ river/jtsk/trunk/src/net/jini/security/Security.java Sun Jul 22 10:19:46 
2012
@@ -27,18 +27,24 @@ import java.net.URL;
 import java.rmi.RemoteException;
 import java.security.AccessControlContext;
 import java.security.AccessController;
+import java.security.CodeSource;
 import java.security.DomainCombiner;
+import java.security.Guard;
 import java.security.Permission;
+import java.security.Permissions;
 import java.security.Policy;
 import java.security.Principal;
 import java.security.PrivilegedAction;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
 import java.security.ProtectionDomain;
+import java.security.cert.Certificate;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.Iterator;
+import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.StringTokenizer;
@@ -47,10 +53,12 @@ import java.util.concurrent.ConcurrentMa
 import java.util.logging.Level;
 import java.util.logging.LogRecord;
 import java.util.logging.Logger;
+import javax.security.auth.AuthPermission;
 import javax.security.auth.Subject;
 import javax.security.auth.SubjectDomainCombiner;
 import net.jini.security.policy.DynamicPolicy;
 import net.jini.security.policy.SecurityContextSource;
+import org.apache.river.api.security.SubjectDomain;
 
 /**
  * Provides methods for executing actions with privileges enabled, for
@@ -535,6 +543,89 @@ public final class Security {
        });
     }
     
+    private static final Guard authPerm = new AuthPermission("doAsPrivileged");
+    
+    /**
+     * Performs work as a particular Subject in the presence of untrusted code,
+     * for distributed systems.
+     * <p>
+     * This method retrieves the current Threads AccessControlContext and
+     * using a SubjectDomainCombiner subclass, prepends a new ProtectionDomain
+     * implementing SubjectDomain, containing the Principals of the Subject, a 
+     * CodeSource with a null URL and null Certificate array, with no
+     * Permission and a null ClassLoader.
+     * <p>
+     * Unlike Subject.doAs, existing ProtectionDomains are not replaced unless
+     * they implement SubjectDomain.
+     * <p>
+     * If a policy provider is installed that recognises SubjectDomain, then
+     * Subjects who's principals are mutated are effective immediately.
+     * <p>
+     * No AuthPermission is required to call this method.
+     * <p>
+     * @param subject  The Subject the work will be performed as, may be null.
+     * @param action  The code to be run as the Subject.
+     * @return   The value returned by the PrivilegedAction's run() method.
+     * @throws  NullPointerException if action is null;
+     * 
+     */
+    public static <T> T doAs(final Subject subject,
+                       final PrivilegedAction<T> action) {
+        if (action == null) throw new NullPointerException("action was null");
+        AccessControlContext acc = AccessController.getContext();
+        return AccessController.doPrivileged(action, combine(acc, subject));
+    }
+    
+    /**
+     * 
+     * @param <T>
+     * @param subject
+     * @param action
+     * @return
+     * @throws PrivilegedActionException 
+     */
+    public static <T> T doAs(final Subject subject,
+                       final PrivilegedExceptionAction<T> action)
+                       throws PrivilegedActionException {
+        if (action == null) throw new NullPointerException("action was null");
+        AccessControlContext acc = AccessController.getContext();
+        return AccessController.doPrivileged(action, combine(acc, subject));
+    }
+    
+    public static <T> T doAsPrivileged(final Subject subject,
+                       final java.security.PrivilegedAction<T> action,
+                       final SecurityContext context) {
+        if (action == null) throw new NullPointerException("action was null");
+        authPerm.checkGuard(null);
+        AccessControlContext acc = context != null ? 
context.getAccessControlContext() : null;
+        PrivilegedAction<T> act = context != null ? context.wrap(action) : 
action;
+        return AccessController.doPrivileged(act, combine(acc, subject));
+    }
+    
+    public static <T> T doAsPrivileged(final Subject subject,
+                       final java.security.PrivilegedExceptionAction<T> action,
+                       final SecurityContext context) throws 
PrivilegedActionException {
+        if (action == null) throw new NullPointerException("action was null");
+        authPerm.checkGuard(null);
+        AccessControlContext acc = context != null ? 
context.getAccessControlContext() : null;
+        PrivilegedExceptionAction<T> act = context != null ? 
context.wrap(action) : action;
+        return AccessController.doPrivileged(act, combine(acc, subject));
+    }
+    
+    
+    private static AccessControlContext combine(final AccessControlContext 
acc, final Subject subject){
+        return AccessController.doPrivileged(new 
PrivilegedAction<AccessControlContext>(){
+
+            @Override
+            public AccessControlContext run() {
+                AccessControlContext context = acc != null ? acc : new 
AccessControlContext(new ProtectionDomain[0]);
+                if (subject == null) return context;
+                return new AccessControlContext(context, new 
DistributedSubjectCombiner(subject));
+            }
+            
+        });
+    }
+    
     /**
      * Creates privileged context that contains the protection domain of the
      * given caller class (if non-null) and uses the domain combiner of the
@@ -1007,4 +1098,99 @@ public final class Security {
             return 
getAccessControlContext().equals(that.getAccessControlContext());
         }
     }
+    
+    /**
+     * Extends and overrides SubjectDomainCombiner, to allow untrusted code
+     * to run as a Subject, without injecting Principals into the 
ProtectionDomain
+     * of untrusted code.
+     */
+    private static class DistributedSubjectCombiner extends 
SubjectDomainCombiner {
+        
+        private final Subject subject;
+    
+        private DistributedSubjectCombiner(Subject subject){
+            super(subject);
+            if (subject == null) throw new NullPointerException("subject 
cannot be null");
+            this.subject = subject;
+        }
+        
+        /**
+         * Prepends one new SubjectDomain containing the Subject and Subject's 
+         * Principals with a CodeSource that has a null URL and no signer
+         * Certificates.  Combines the current and assigned domains, 
+         * removing any duplicates and any existing SubjectDomain.
+         * A new array is returned.
+         * 
+         * @param currentDomains  the ProtectionDomains associated with the 
+         * current execution Thread, up to the most recent privileged 
+         * ProtectionDomain. The ProtectionDomains are are listed in 
+         * order of execution, with the most recently executing 
+         * ProtectionDomain residing at the beginning of the array. 
+         * This parameter may be null if the current execution Thread has no 
+         * associated ProtectionDomains.
+         * @param assignedDomains  an array of inherited ProtectionDomains. 
+         * ProtectionDomains may be inherited from a parent Thread, 
+         * or from a privileged AccessControlContext.
+         * This parameter may be null if there are no inherited 
ProtectionDomains.
+         * @return  a new array containing current and assigned domains with
+         * a new SubjectDomain prepended.
+         */
+        public ProtectionDomain[] combine(ProtectionDomain[] currentDomains,
+                               ProtectionDomain[] assignedDomains) {
+            Set<ProtectionDomain> result = 
+                    new LinkedHashSet<ProtectionDomain>(currentDomains.length 
+ assignedDomains.length + 1);
+            result.add(new SubjectProtectionDomain(subject));
+            int l = currentDomains.length;
+            for ( int i = 0; i < l; i++ ){
+                if (currentDomains[i] == null || currentDomains[i] instanceof 
SubjectDomain) continue;
+                result.add(currentDomains[i]);
+            }
+            l = assignedDomains.length;
+            for ( int i = 0; i < l; i++ ){
+                if (assignedDomains[i] == null || assignedDomains[i] 
instanceof SubjectDomain) continue;
+                result.add(assignedDomains[i]);
+            }
+            return result.toArray(new ProtectionDomain[result.size()]);
+        }
+    }
+    
+    /**
+     * A ProtectionDomain containing a Subject and CodeSource with a null URL,
+     * with a supportive policy provider installed, a Subject's Principals 
will 
+     * always be up to date.
+     */
+    private static class SubjectProtectionDomain extends ProtectionDomain
+            implements SubjectDomain {
+        private final static CodeSource nullCS = new CodeSource(null, 
(Certificate[]) null);
+        private final Subject subject;
+        
+        private SubjectProtectionDomain(Subject subject){
+            super(nullCS, new Permissions(), null, (Principal[]) 
subject.getPrincipals().toArray());
+            this.subject = subject;
+        }
+
+        public int hashCode() {
+            int hash = 5;
+            hash = 67 * hash + (this.subject != null ? this.subject.hashCode() 
: 0);
+            return hash;
+        }
+        
+        /**
+         * Implement equals to allow efficient caching of AccessControlContext.
+         * 
+         */
+        public boolean equals(Object o){
+            if (!(o instanceof SubjectProtectionDomain)) return false;
+            if (this == o) return true;
+            SubjectProtectionDomain other = (SubjectProtectionDomain) o;
+            if (nullCS != getCodeSource()) return false;
+            return (subject == other.subject);
+        }
+        
+        public Subject getSubject(){
+            return subject;
+        }
+        
+    }
+    
 }

Modified: 
river/jtsk/trunk/src/org/apache/river/api/security/CertificateGrant.java
URL: 
http://svn.apache.org/viewvc/river/jtsk/trunk/src/org/apache/river/api/security/CertificateGrant.java?rev=1364250&r1=1364249&r2=1364250&view=diff
==============================================================================
--- river/jtsk/trunk/src/org/apache/river/api/security/CertificateGrant.java 
(original)
+++ river/jtsk/trunk/src/org/apache/river/api/security/CertificateGrant.java 
Sun Jul 22 10:19:46 2012
@@ -95,7 +95,7 @@ class CertificateGrant extends Principal
        Principal[] pals = null;
        if (pd != null){
            c = pd.getCodeSource();
-           pals = pd.getPrincipals();
+           pals = getPrincipals(pd);
        }
        return implies(c, pals);
     }

Modified: 
river/jtsk/trunk/src/org/apache/river/api/security/ClassLoaderGrant.java
URL: 
http://svn.apache.org/viewvc/river/jtsk/trunk/src/org/apache/river/api/security/ClassLoaderGrant.java?rev=1364250&r1=1364249&r2=1364250&view=diff
==============================================================================
--- river/jtsk/trunk/src/org/apache/river/api/security/ClassLoaderGrant.java 
(original)
+++ river/jtsk/trunk/src/org/apache/river/api/security/ClassLoaderGrant.java 
Sun Jul 22 10:19:46 2012
@@ -70,7 +70,7 @@ class ClassLoaderGrant extends Protectio
         Principal[] pals = null;
         if (pd != null){
             cl = pd.getClassLoader();
-            pals = pd.getPrincipals();
+            pals = getPrincipals(pd);
         }
         return implies(cl, pals);
     }

Modified: 
river/jtsk/trunk/src/org/apache/river/api/security/PermissionGrant.java
URL: 
http://svn.apache.org/viewvc/river/jtsk/trunk/src/org/apache/river/api/security/PermissionGrant.java?rev=1364250&r1=1364249&r2=1364250&view=diff
==============================================================================
--- river/jtsk/trunk/src/org/apache/river/api/security/PermissionGrant.java 
(original)
+++ river/jtsk/trunk/src/org/apache/river/api/security/PermissionGrant.java Sun 
Jul 22 10:19:46 2012
@@ -119,6 +119,7 @@ public abstract class PermissionGrant {
     }
     
     protected final PermissionGrant decorated(){
+        // REMIND: Consider null object pattern.
         return decorated;
     }
     

Modified: river/jtsk/trunk/src/org/apache/river/api/security/PrincipalGrant.java
URL: 
http://svn.apache.org/viewvc/river/jtsk/trunk/src/org/apache/river/api/security/PrincipalGrant.java?rev=1364250&r1=1364249&r2=1364250&view=diff
==============================================================================
--- river/jtsk/trunk/src/org/apache/river/api/security/PrincipalGrant.java 
(original)
+++ river/jtsk/trunk/src/org/apache/river/api/security/PrincipalGrant.java Sun 
Jul 22 10:19:46 2012
@@ -213,10 +213,18 @@ class PrincipalGrant extends PermissionG
     public boolean implies(ProtectionDomain pd) {
         if (pals.isEmpty()) return true;
        if (pd == null) return false;
-       Principal[] hasPrincipals = pd.getPrincipals();
+       Principal[] hasPrincipals = getPrincipals(pd);
        return implies(hasPrincipals);
     }
     
+    protected Principal[] getPrincipals(ProtectionDomain pd){
+        if (pd instanceof SubjectDomain){
+            Set<Principal> pals = ((SubjectDomain) 
pd).getSubject().getPrincipals();
+            return pals.toArray(new Principal[pals.size()]);
+        }
+        return pd.getPrincipals();
+    }
+    
     public boolean implies(ClassLoader cl, Principal[] pal) {
        // A null ClassLoader indicates the system domain.
         return implies(pal);

Modified: 
river/jtsk/trunk/src/org/apache/river/api/security/ProtectionDomainGrant.java
URL: 
http://svn.apache.org/viewvc/river/jtsk/trunk/src/org/apache/river/api/security/ProtectionDomainGrant.java?rev=1364250&r1=1364249&r2=1364250&view=diff
==============================================================================
--- 
river/jtsk/trunk/src/org/apache/river/api/security/ProtectionDomainGrant.java 
(original)
+++ 
river/jtsk/trunk/src/org/apache/river/api/security/ProtectionDomainGrant.java 
Sun Jul 22 10:19:46 2012
@@ -95,7 +95,7 @@ class ProtectionDomainGrant extends Prin
     public boolean implies(ProtectionDomain pd){
 //        if ((domain == null) && (pals.isEmpty())) return true;
 //        if (pd == null) return false;
-        return impliesProtectionDomain(pd) && implies(pd.getPrincipals());
+        return impliesProtectionDomain(pd) && implies(getPrincipals(pd));
        
     }
     

Added: river/jtsk/trunk/src/org/apache/river/api/security/SubjectDomain.java
URL: 
http://svn.apache.org/viewvc/river/jtsk/trunk/src/org/apache/river/api/security/SubjectDomain.java?rev=1364250&view=auto
==============================================================================
--- river/jtsk/trunk/src/org/apache/river/api/security/SubjectDomain.java 
(added)
+++ river/jtsk/trunk/src/org/apache/river/api/security/SubjectDomain.java Sun 
Jul 22 10:19:46 2012
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.river.api.security;
+
+import java.security.ProtectionDomain;
+import javax.security.auth.Subject;
+
+/**
+ *
+ * @author Peter Firmstone
+ */
+public interface SubjectDomain {
+    
+    public Subject getSubject();
+}

Propchange: 
river/jtsk/trunk/src/org/apache/river/api/security/SubjectDomain.java
------------------------------------------------------------------------------
    svn:eol-style = native


Reply via email to