System authentication
authorMathieu Baudier <mbaudier@argeo.org>
Sun, 6 Sep 2015 18:59:11 +0000 (18:59 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Sun, 6 Sep 2015 18:59:11 +0000 (18:59 +0000)
git-svn-id: https://svn.argeo.org/commons/trunk@8376 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

13 files changed:
org.argeo.cms/src/org/argeo/cms/internal/auth/ImpliedByPrincipal.java
org.argeo.cms/src/org/argeo/cms/internal/auth/UserAdminLoginModule.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/Activator.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/jaas.cfg
org.argeo.security.core/src/org/argeo/security/SystemAuth.java [new file with mode: 0644]
org.argeo.security.core/src/org/argeo/security/core/AbstractSystemExecution.java
org.argeo.security.core/src/org/argeo/security/core/AuthenticatedApplicationContextInitialization.java
org.argeo.security.core/src/org/argeo/security/core/SystemLoginModule.java [new file with mode: 0644]
org.argeo.security.jackrabbit/ext/test/org/argeo/security/jackrabbit/JackrabbitAuthTest.java
org.argeo.security.jackrabbit/ext/test/org/argeo/security/jackrabbit/test_jaas.config
org.argeo.security.jackrabbit/src/org/argeo/security/jackrabbit/SystemJackrabbitLoginModule.java

index 417ea69cee817ff4e0fafc834e39d2f0b4641dd1..829c17e35d78be824cc5913445fcbe020cb1b952 100644 (file)
@@ -85,6 +85,6 @@ public final class ImpliedByPrincipal implements Group {
 
        @Override
        public String toString() {
-               return name.toString() + ", implied by " + causes;
+               return name.toString() + " implied by " + causes;
        }
 }
index 63ca969b8947890cb9b3f778110effbe4f77a9aa..f598515217d6dbce821fd4bba5e4181cfdce699b 100644 (file)
@@ -5,6 +5,8 @@ import java.nio.CharBuffer;
 import java.nio.charset.Charset;
 import java.security.Principal;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -22,6 +24,9 @@ import javax.security.auth.x500.X500Principal;
 
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.jackrabbit.core.security.AnonymousPrincipal;
+import org.apache.jackrabbit.core.security.SecurityConstants;
+import org.apache.jackrabbit.core.security.principal.AdminPrincipal;
 import org.argeo.cms.CmsException;
 import org.argeo.cms.KernelHeader;
 import org.argeo.cms.internal.kernel.Activator;
@@ -35,12 +40,20 @@ public class UserAdminLoginModule implements LoginModule {
        private CallbackHandler callbackHandler;
        private boolean isAnonymous = false;
 
-       private final static LdapName ROLE_USER_NAME, ROLE_ANONYMOUS_NAME;
+       private final static LdapName ROLE_ADMIN_NAME, ROLE_USER_NAME,
+                       ROLE_ANONYMOUS_NAME;
+       private final static List<LdapName> RESERVED_ROLES;
        private final static X500Principal ROLE_ANONYMOUS_PRINCIPAL;
        static {
                try {
+                       ROLE_ADMIN_NAME = new LdapName(KernelHeader.ROLE_ADMIN);
                        ROLE_USER_NAME = new LdapName(KernelHeader.ROLE_USER);
                        ROLE_ANONYMOUS_NAME = new LdapName(KernelHeader.ROLE_ANONYMOUS);
+                       RESERVED_ROLES = Collections.unmodifiableList(Arrays
+                                       .asList(new LdapName[] { ROLE_ANONYMOUS_NAME,
+                                                       ROLE_USER_NAME, ROLE_ADMIN_NAME,
+                                                       new LdapName(KernelHeader.ROLE_GROUP_ADMIN),
+                                                       new LdapName(KernelHeader.ROLE_USER_ADMIN) }));
                        ROLE_ANONYMOUS_PRINCIPAL = new X500Principal(
                                        ROLE_ANONYMOUS_NAME.toString());
                } catch (InvalidNameException e) {
@@ -133,15 +146,17 @@ public class UserAdminLoginModule implements LoginModule {
                        try {
                                String authName = authorization.getName();
 
-                               // determine user'S principal
+                               // determine user's principal
                                final LdapName name;
                                final Principal userPrincipal;
                                if (authName == null) {
                                        name = ROLE_ANONYMOUS_NAME;
                                        userPrincipal = ROLE_ANONYMOUS_PRINCIPAL;
                                        principals.add(userPrincipal);
+                                       principals.add(new AnonymousPrincipal());
                                } else {
                                        name = new LdapName(authName);
+                                       checkUserName(name);
                                        userPrincipal = new X500Principal(name.toString());
                                        principals.add(userPrincipal);
                                        principals.add(new ImpliedByPrincipal(ROLE_USER_NAME,
@@ -151,17 +166,15 @@ public class UserAdminLoginModule implements LoginModule {
                                // Add roles provided by authorization
                                for (String role : authorization.getRoles()) {
                                        LdapName roleName = new LdapName(role);
-                                       if (ROLE_USER_NAME.equals(roleName))
-                                               throw new CmsException(ROLE_USER_NAME
-                                                               + " cannot be listed as role");
-                                       if (ROLE_ANONYMOUS_NAME.equals(roleName))
-                                               throw new CmsException(ROLE_ANONYMOUS_NAME
-                                                               + " cannot be listed as role");
                                        if (roleName.equals(name)) {
                                                // skip
                                        } else {
+                                               checkImpliedPrincipalName(roleName);
                                                principals.add(new ImpliedByPrincipal(roleName
                                                                .toString(), userPrincipal));
+                                               if (roleName.equals(ROLE_ADMIN_NAME))
+                                                       principals.add(new AdminPrincipal(
+                                                                       SecurityConstants.ADMIN_ID));
                                        }
                                }
 
@@ -197,4 +210,15 @@ public class UserAdminLoginModule implements LoginModule {
                subject = null;
                authorization = null;
        }
+
+       private void checkUserName(LdapName name) {
+               if (RESERVED_ROLES.contains(name))
+                       throw new CmsException(name + " is a reserved name");
+       }
+
+       private void checkImpliedPrincipalName(LdapName roleName) {
+               if (ROLE_USER_NAME.equals(roleName)
+                               || ROLE_ANONYMOUS_NAME.equals(roleName))
+                       throw new CmsException(roleName + " cannot be listed as role");
+       }
 }
index 6bad825ddda3a629b324c4d15b73936a369c5f8f..1b21f56635f8885242cef1e26443b87a1708c9ab 100644 (file)
@@ -2,6 +2,8 @@ package org.argeo.cms.internal.kernel;
 
 import java.util.UUID;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.argeo.security.SystemAuthentication;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
@@ -11,6 +13,8 @@ import org.osgi.framework.BundleContext;
  * access to kernel information for the rest of the bundle (and only it)
  */
 public class Activator implements BundleActivator {
+       private final Log log = LogFactory.getLog(Activator.class);
+
        private final static String systemKey;
        static {
                systemKey = UUID.randomUUID().toString();
@@ -25,8 +29,12 @@ public class Activator implements BundleActivator {
                assert bundleContext == null;
                assert kernel == null;
                bundleContext = context;
-               kernel = new Kernel();
-               kernel.init();
+               try {
+                       kernel = new Kernel();
+                       kernel.init();
+               } catch (Exception e) {
+                       log.error("Cannot boot kernel", e);
+               }
        }
 
        @Override
index 83f21202e45612855b87d23d29a226479469df3a..67f0c3737caab318e3acd0c8a28d0e207ffe0760 100644 (file)
@@ -2,17 +2,22 @@ package org.argeo.cms.internal.kernel;
 
 import java.lang.management.ManagementFactory;
 import java.net.URL;
+import java.security.PrivilegedAction;
 import java.util.HashMap;
 import java.util.Map;
 
 import javax.jcr.Repository;
 import javax.jcr.RepositoryFactory;
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.jackrabbit.util.TransientFileFactory;
 import org.argeo.ArgeoException;
 import org.argeo.cms.CmsException;
+import org.argeo.cms.KernelHeader;
 import org.argeo.jackrabbit.OsgiJackrabbitRepositoryFactory;
 import org.argeo.jcr.ArgeoJcrConstants;
 import org.argeo.security.core.InternalAuthentication;
@@ -47,12 +52,35 @@ final class Kernel implements ServiceListener {
        NodeHttp nodeHttp;
        private KernelThread kernelThread;
 
-       void init() {
+       private final Subject kernelSubject = new Subject();
+
+       public Kernel() {
                URL url = getClass().getClassLoader().getResource(
                                KernelConstants.JAAS_CONFIG);
                System.setProperty("java.security.auth.login.config",
                                url.toExternalForm());
+               try {
+                       LoginContext kernelLc = new LoginContext(
+                                       KernelHeader.LOGIN_CONTEXT_SYSTEM, kernelSubject);
+                       kernelLc.login();
+               } catch (LoginException e) {
+                       throw new CmsException("Cannot log in kernel", e);
+               }
+       }
+
+       final void init() {
+               Subject.doAs(kernelSubject, new PrivilegedAction<Void>() {
+
+                       @Override
+                       public Void run() {
+                               doInit();
+                               return null;
+                       }
+
+               });
+       }
 
+       private void doInit() {
                ClassLoader currentContextCl = Thread.currentThread()
                                .getContextClassLoader();
                Thread.currentThread().setContextClassLoader(
@@ -121,6 +149,14 @@ final class Kernel implements ServiceListener {
                // Clean hanging threads from Jackrabbit
                TransientFileFactory.shutdown();
 
+               try {
+                       LoginContext kernelLc = new LoginContext(
+                                       KernelHeader.LOGIN_CONTEXT_SYSTEM, kernelSubject);
+                       kernelLc.logout();
+               } catch (LoginException e) {
+                       throw new CmsException("Cannot log in kernel", e);
+               }
+
                long duration = System.currentTimeMillis() - begin;
                log.info("## ARGEO CMS DOWN in " + (duration / 1000) + "."
                                + (duration % 1000) + "s ##");
index 0a512fff93988b778b01300ef65e70ffed67a9dc..13ecac4b09c1c599248420b2df2699114b1b3330 100644 (file)
@@ -131,6 +131,8 @@ class NodeSecurity implements AuthenticationManager {
        @Override
        public Authentication authenticate(Authentication authentication)
                        throws AuthenticationException {
+//             throw new UnsupportedOperationException(
+//                             "Authentication manager is deprectaed and should not be used.");
                Authentication auth = null;
                if (authentication instanceof InternalAuthentication)
                        auth = internalAuth.authenticate(authentication);
index 0e76f376a3793a5a3175bbe591c946d6c9a7a616..783d1f71fe05cd4511ee602c281cfd8a968ddb15 100644 (file)
@@ -17,9 +17,7 @@ OLD_ANONYMOUS {
 };
 
 SYSTEM {
-   org.argeo.cms.internal.auth.SystemLoginModule requisite;
-   org.springframework.security.authentication.jaas.SecurityContextLoginModule requisite;
-   org.argeo.security.jackrabbit.SystemJackrabbitLoginModule requisite;
+    org.argeo.security.core.SystemLoginModule requisite;
 };
 
 OLD_SYSTEM {
diff --git a/org.argeo.security.core/src/org/argeo/security/SystemAuth.java b/org.argeo.security.core/src/org/argeo/security/SystemAuth.java
new file mode 100644 (file)
index 0000000..76a03fb
--- /dev/null
@@ -0,0 +1,28 @@
+package org.argeo.security;
+
+import java.security.Principal;
+
+public final class SystemAuth implements Principal {
+       private final String name = "init";
+
+       @Override
+       public String getName() {
+               return name;
+       }
+
+       @Override
+       public int hashCode() {
+               return name.hashCode();
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               return this == obj;
+       }
+
+       @Override
+       public String toString() {
+               return name.toString();
+       }
+
+}
index 3acf26c8a1d3097f0336aea0d1c0051556d477dc..42cf42eef34bd58afc4eda67286ff0805f4ebc57 100644 (file)
  */
 package org.argeo.security.core;
 
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.argeo.ArgeoException;
-import org.argeo.security.SystemAuthentication;
 import org.springframework.security.authentication.AuthenticationManager;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.context.SecurityContext;
-import org.springframework.security.core.context.SecurityContextHolder;
 
 /** Provides base method for executing code with system authorization. */
 public abstract class AbstractSystemExecution {
-       static {
-               // Forces Spring Security to use inheritable strategy
-               // FIXME find a better place for forcing spring security mode
-               // doesn't work for the time being
-               // if (System.getProperty(SecurityContextHolder.SYSTEM_PROPERTY) ==
-               // null)
-               // SecurityContextHolder
-               // .setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
-       }
-
        private final static Log log = LogFactory
                        .getLog(AbstractSystemExecution.class);
-       private AuthenticationManager authenticationManager;
-       private String systemAuthenticationKey;
+       // private AuthenticationManager authenticationManager;
+       private final Subject subject = new Subject();
+       // private String systemAuthenticationKey;
+
+       private final String loginModule = "SYSTEM";
 
        /** Whether the current thread was authenticated by this component. */
-       private ThreadLocal<Boolean> authenticatedBySelf = new ThreadLocal<Boolean>() {
-               protected Boolean initialValue() {
-                       return false;
-               }
-       };
+       // private ThreadLocal<Boolean> authenticatedBySelf = new
+       // ThreadLocal<Boolean>() {
+       // protected Boolean initialValue() {
+       // return false;
+       // }
+       // };
 
        /**
         * Authenticate the calling thread to the underlying
         * {@link AuthenticationManager}
         */
        protected void authenticateAsSystem() {
-               if (authenticatedBySelf.get())
-                       return;
-               SecurityContext securityContext = SecurityContextHolder.getContext();
-               Authentication currentAuth = securityContext.getAuthentication();
-               if (currentAuth != null) {
-                       if (!(currentAuth instanceof SystemAuthentication))
-                               throw new ArgeoException(
-                                               "System execution on an already authenticated thread: "
-                                                               + currentAuth + ", THREAD="
-                                                               + Thread.currentThread().getId());
-                       return;
+               try {
+                       LoginContext lc = new LoginContext(loginModule, subject);
+                       lc.login();
+               } catch (LoginException e) {
+                       throw new ArgeoException("Cannot login as system", e);
                }
-               // Subject subject = Subject.getSubject(AccessController.getContext());
-               // if (subject != null
-               // && !subject.getPrincipals(Authentication.class).isEmpty())
+               // if (authenticatedBySelf.get())
+               // return;
+               // SecurityContext securityContext = SecurityContextHolder.getContext();
+               // Authentication currentAuth = securityContext.getAuthentication();
+               // if (currentAuth != null) {
+               // if (!(currentAuth instanceof SystemAuthentication))
                // throw new ArgeoException(
-               // "There is already an authenticated subject: " + subject);
-
-               String key = systemAuthenticationKey != null ? systemAuthenticationKey
-                               : System.getProperty(
-                                               SystemAuthentication.SYSTEM_KEY_PROPERTY,
-                                               InternalAuthentication.SYSTEM_KEY_DEFAULT);
-               if (key == null)
-                       throw new ArgeoException("No system key defined");
-               if (authenticationManager == null)
-                       throw new ArgeoException("Authentication manager cannot be null.");
-               Authentication auth = authenticationManager
-                               .authenticate(new InternalAuthentication(key));
-               securityContext.setAuthentication(auth);
-
-               authenticatedBySelf.set(true);
+               // "System execution on an already authenticated thread: "
+               // + currentAuth + ", THREAD="
+               // + Thread.currentThread().getId());
+               // return;
+               // }
+               //
+               // String key = systemAuthenticationKey != null ?
+               // systemAuthenticationKey
+               // : System.getProperty(
+               // SystemAuthentication.SYSTEM_KEY_PROPERTY,
+               // InternalAuthentication.SYSTEM_KEY_DEFAULT);
+               // if (key == null)
+               // throw new ArgeoException("No system key defined");
+               // if (authenticationManager == null)
+               // throw new ArgeoException("Authentication manager cannot be null.");
+               // Authentication auth = authenticationManager
+               // .authenticate(new InternalAuthentication(key));
+               // securityContext.setAuthentication(auth);
+               //
+               // authenticatedBySelf.set(true);
                if (log.isTraceEnabled())
                        log.trace("System authenticated");
        }
 
-       // /** Removes the authentication from the calling thread. */
-       // protected void deauthenticateAsSystem() {
-       // // remove the authentication
-       // // SecurityContext securityContext = SecurityContextHolder.getContext();
-       // // securityContext.setAuthentication(null);
-       // // authenticatedBySelf.set(false);
-       // if (log.isTraceEnabled()) {
-       // log.trace("System deauthenticated");
-       // // Thread.dumpStack();
-       // }
-       // }
+       protected void deauthenticateAsSystem() {
+               try {
+                       LoginContext lc = new LoginContext(loginModule, subject);
+                       lc.logout();
+               } catch (LoginException e) {
+                       throw new ArgeoException("Cannot logout as system", e);
+               }
+       }
 
-       /**
-        * Whether the current thread was authenticated by this component or a
-        * parent thread.
-        */
-       protected Boolean isAuthenticatedBySelf() {
-               return authenticatedBySelf.get();
+       protected Subject getSubject() {
+               return subject;
        }
 
+       // /**
+       // * Whether the current thread was authenticated by this component or a
+       // * parent thread.
+       // */
+       // protected Boolean isAuthenticatedBySelf() {
+       // return authenticatedBySelf.get();
+       // }
+       //
        public void setAuthenticationManager(
                        AuthenticationManager authenticationManager) {
-               this.authenticationManager = authenticationManager;
+               log.warn("Use of authenticationManager is deprecated, remove this property from the configuration.");
        }
 
        public void setSystemAuthenticationKey(String systemAuthenticationKey) {
-               this.systemAuthenticationKey = systemAuthenticationKey;
+               log.warn("Use of systemAuthenticationKey is deprecated, remove this property from the configuration.");
+               // this.systemAuthenticationKey = systemAuthenticationKey;
        }
 }
index 5faa2a75110f265621290e7a04cb84294c0ffbde..6c477ee9f97161426216cc9da4d4dcceefd46e79 100644 (file)
 package org.argeo.security.core;
 
 import java.beans.PropertyDescriptor;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.ArrayList;
 import java.util.List;
 
+import javax.security.auth.Subject;
+
+import org.eclipse.gemini.blueprint.context.DependencyInitializationAwareBeanPostProcessor;
 import org.springframework.beans.BeansException;
 import org.springframework.beans.PropertyValues;
-import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
+import org.springframework.beans.factory.support.AbstractBeanFactory;
+import org.springframework.beans.factory.support.SecurityContextProvider;
+import org.springframework.beans.factory.support.SimpleSecurityContextProvider;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
 import org.springframework.context.ApplicationEvent;
 import org.springframework.context.ApplicationListener;
 import org.springframework.context.event.ContextRefreshedEvent;
@@ -31,41 +40,51 @@ import org.springframework.context.event.ContextRefreshedEvent;
  * methods of the application context where it has been defined.
  */
 public class AuthenticatedApplicationContextInitialization extends
-               AbstractSystemExecution implements InstantiationAwareBeanPostProcessor,
-               ApplicationListener<ApplicationEvent> {
+               AbstractSystemExecution implements DependencyInitializationAwareBeanPostProcessor,
+               ApplicationListener<ApplicationEvent>, ApplicationContextAware {
        // private Log log = LogFactory
        // .getLog(AuthenticatedApplicationContextInitialization.class);
        /** If non empty, restricts to these beans */
        private List<String> beanNames = new ArrayList<String>();
 
-       @SuppressWarnings("rawtypes")
-       public Object postProcessBeforeInstantiation(Class beanClass,
-                       String beanName) throws BeansException {
-               // we authenticate when any bean is instantiated
-               // we will deauthenticate only when the application context has been
-               // refreshed in order to be able to deal with factory beans has well
-               if (!isAuthenticatedBySelf()) {
-                       if (beanNames.size() == 0)
-                               authenticateAsSystem();
-                       else if (beanNames.contains(beanName))
-                               authenticateAsSystem();
-               }
-               return null;
-       }
-
-       public boolean postProcessAfterInstantiation(Object bean, String beanName)
-                       throws BeansException {
-               return true;
-       }
-
-       public PropertyValues postProcessPropertyValues(PropertyValues pvs,
-                       PropertyDescriptor[] pds, Object bean, String beanName)
-                       throws BeansException {
-               return pvs;
-       }
+//     @SuppressWarnings("rawtypes")
+//     public Object postProcessBeforeInstantiation(Class beanClass,
+//                     String beanName) throws BeansException {
+//             // we authenticate when any bean is instantiated
+//             // we will deauthenticate only when the application context has been
+//             // refreshed in order to be able to deal with factory beans has well
+//             // if (!isAuthenticatedBySelf()) {
+//             // if (beanNames.size() == 0)
+//             // authenticateAsSystem();
+//             // else if (beanNames.contains(beanName))
+//             // authenticateAsSystem();
+//             // }
+//             return null;
+//     }
+//
+//     public boolean postProcessAfterInstantiation(Object bean, String beanName)
+//                     throws BeansException {
+//             return true;
+//     }
+//
+//     public PropertyValues postProcessPropertyValues(PropertyValues pvs,
+//                     PropertyDescriptor[] pds, Object bean, String beanName)
+//                     throws BeansException {
+//             return pvs;
+//     }
 
        public Object postProcessBeforeInitialization(Object bean, String beanName)
                        throws BeansException {
+               if (beanNames.size() == 0 || beanNames.contains(beanName))
+                       authenticateAsSystem();
+               // try {
+               // if (beanNames.size() == 0 || beanNames.contains(beanName)) {
+               // LoginContext lc = new LoginContext("INIT", subject);
+               // lc.login();
+               // }
+               // } catch (LoginException e) {
+               // throw new ArgeoException("Cannot login as initialization", e);
+               // }
                return bean;
        }
 
@@ -75,7 +94,17 @@ public class AuthenticatedApplicationContextInitialization extends
                // we expect the underlying thread to die and thus the system
                // authentication to be lost. We have currently no way to catch the
                // exception and perform the deauthentication by ourselves.
-               // deauthenticateAsSystem();
+               if (beanNames.size() == 0 || beanNames.contains(beanName))
+                       deauthenticateAsSystem();
+               // try {
+               // if (beanNames.size() == 0 || beanNames.contains(beanName)) {
+               // LoginContext lc = new LoginContext("INIT", subject);
+               // lc.logout();
+               // }
+               // } catch (LoginException e) {
+               // // TODO Auto-generated catch block
+               // e.printStackTrace();
+               // }
                return bean;
        }
 
@@ -91,4 +120,23 @@ public class AuthenticatedApplicationContextInitialization extends
                this.beanNames = beanNames;
        }
 
+       @Override
+       public void setApplicationContext(ApplicationContext applicationContext)
+                       throws BeansException {
+               if (applicationContext.getAutowireCapableBeanFactory() instanceof AbstractBeanFactory) {
+                       final AbstractBeanFactory beanFactory = ((AbstractBeanFactory) applicationContext
+                                       .getAutowireCapableBeanFactory());
+                       // retrieve subject's access control context
+                       // and set it as the bean factory security context
+                       Subject.doAs(getSubject(), new PrivilegedAction<Void>() {
+                               @Override
+                               public Void run() {
+                                       SecurityContextProvider scp = new SimpleSecurityContextProvider(
+                                                       AccessController.getContext());
+                                       beanFactory.setSecurityContextProvider(scp);
+                                       return null;
+                               }
+                       });
+               }
+       }
 }
diff --git a/org.argeo.security.core/src/org/argeo/security/core/SystemLoginModule.java b/org.argeo.security.core/src/org/argeo/security/core/SystemLoginModule.java
new file mode 100644 (file)
index 0000000..a1d68b3
--- /dev/null
@@ -0,0 +1,45 @@
+package org.argeo.security.core;
+
+import java.util.Map;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+
+import org.argeo.security.SystemAuth;
+
+public class SystemLoginModule implements LoginModule {
+       private Subject subject;
+
+       @Override
+       public void initialize(Subject subject, CallbackHandler callbackHandler,
+                       Map<String, ?> sharedState, Map<String, ?> options) {
+               this.subject = subject;
+       }
+
+       @Override
+       public boolean login() throws LoginException {
+               // TODO check permission?
+               return true;
+       }
+
+       @Override
+       public boolean commit() throws LoginException {
+               subject.getPrincipals().add(new SystemAuth());
+               return true;
+       }
+
+       @Override
+       public boolean abort() throws LoginException {
+               return true;
+       }
+
+       @Override
+       public boolean logout() throws LoginException {
+               // remove ALL credentials (e.g. additional Jackrabbit credentials)
+               subject.getPrincipals().clear();
+               return true;
+       }
+
+}
index 45a6567aa45b603e3bbdef70d8473e7cdd8b23e6..140dfa67fcd833b23925c4fc117fb5e00d74ed3b 100644 (file)
@@ -1,9 +1,12 @@
 package org.argeo.security.jackrabbit;
 
 import java.net.URL;
+import java.security.PrivilegedExceptionAction;
 
 import javax.jcr.Repository;
 import javax.jcr.Session;
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginContext;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -13,13 +16,19 @@ public class JackrabbitAuthTest extends AbstractJackrabbitTestCase {
        private final Log log = LogFactory.getLog(JackrabbitAuthTest.class);
 
        public void testLogin() throws Exception {
-               // Subject subject = new Subject();
-               // LoginContext loginContext = new LoginContext("UNIX",subject);
-               // loginContext.login();
-
-               Repository repository = getRepository();
-               Session session = repository.login();
-               log.debug(session.getUserID());
+               Subject subject = new Subject();
+               LoginContext loginContext = new LoginContext("SYSTEM", subject);
+               loginContext.login();
+               Subject.doAs(subject, new PrivilegedExceptionAction<Void>() {
+
+                       @Override
+                       public Void run() throws Exception {
+                               Repository repository = getRepository();
+                               Session session = repository.login();
+                               log.debug(session.getUserID());
+                               return null;
+                       }
+               });
        }
 
        @Override
index 3b4ee81a30402474626825600193516a9a036762..233af5461d698428074dd47836a15ef1bd9d1eb8 100644 (file)
@@ -1,3 +1,7 @@
+SYSTEM {
+   org.argeo.security.core.SystemLoginModule requisite;
+};
+
 Jackrabbit {
    org.argeo.security.jackrabbit.SystemJackrabbitLoginModule requisite;
 };
index b11d7b4b5b2f98594e622a2be85320f56a3f48fa..9977938eccb4029dc6ec683a4e1796a4e0370452 100644 (file)
@@ -1,6 +1,5 @@
 package org.argeo.security.jackrabbit;
 
-import java.security.Principal;
 import java.util.Map;
 import java.util.Set;
 
@@ -8,9 +7,11 @@ import javax.security.auth.Subject;
 import javax.security.auth.callback.CallbackHandler;
 import javax.security.auth.login.LoginException;
 import javax.security.auth.spi.LoginModule;
+import javax.security.auth.x500.X500Principal;
 
-import org.apache.jackrabbit.core.security.AnonymousPrincipal;
+import org.apache.jackrabbit.core.security.SecurityConstants;
 import org.apache.jackrabbit.core.security.principal.AdminPrincipal;
+import org.argeo.security.SystemAuth;
 
 public class SystemJackrabbitLoginModule implements LoginModule {
 
@@ -29,32 +30,51 @@ public class SystemJackrabbitLoginModule implements LoginModule {
 
        @Override
        public boolean commit() throws LoginException {
-               Set<Principal> principals = subject.getPrincipals();
-               if (principals.isEmpty()) {// system
-                       subject.getPrincipals().add(new AdminPrincipal("admin"));
+               Set<SystemAuth> initPrincipal = subject
+                               .getPrincipals(SystemAuth.class);
+               if (!initPrincipal.isEmpty()) {
+                       subject.getPrincipals().add(
+                                       new AdminPrincipal(SecurityConstants.ADMIN_ID));
                        return true;
                }
-               boolean isAdmin = false;
-               boolean isAnonymous = false;
-               // FIXME make it more generic
-               for (Principal principal : principals) {
-                       if (principal.getName().equalsIgnoreCase(
-                                       "cn=admin,ou=roles,ou=node"))
-                               isAdmin = true;
-                       else if (principal.getName().equalsIgnoreCase(
-                                       "cn=anonymous,ou=roles,ou=node"))
-                               isAnonymous = true;
-               }
 
-               if (isAnonymous && isAdmin)
-                       throw new LoginException("Cannot be admin and anonymous");
+               Set<X500Principal> userPrincipal = subject
+                               .getPrincipals(X500Principal.class);
+               if (userPrincipal.isEmpty())
+                       throw new LoginException("Subject must be pre-authenticated");
+               if (userPrincipal.size() > 1)
+                       throw new LoginException("Multiple user principals "
+                                       + userPrincipal);
 
-               // Add special Jackrabbit roles
-               if (isAdmin)
-                       principals.add(new AdminPrincipal("admin"));
-               if (isAnonymous)// anonymous
-                       principals.add(new AnonymousPrincipal());
                return true;
+
+               // Set<Principal> principals = subject.getPrincipals();
+               // if (principals.isEmpty()) {// system
+               // throw new LoginException("Subject must be pre-authenticated");
+               // // subject.getPrincipals().add(new AdminPrincipal("admin"));
+               // // return true;
+               // }
+               // boolean isAdmin = false;
+               // boolean isAnonymous = false;
+               // // FIXME make it more generic
+               // for (Principal principal : principals) {
+               // if (principal.getName().equalsIgnoreCase(
+               // "cn=admin,ou=roles,ou=node"))
+               // isAdmin = true;
+               // else if (principal.getName().equalsIgnoreCase(
+               // "cn=anonymous,ou=roles,ou=node"))
+               // isAnonymous = true;
+               // }
+               //
+               // if (isAnonymous && isAdmin)
+               // throw new LoginException("Cannot be admin and anonymous");
+               //
+               // // Add special Jackrabbit roles
+               // if (isAdmin)
+               // principals.add(new AdminPrincipal(SecurityConstants.ADMIN_ID));
+               // if (isAnonymous)// anonymous
+               // principals.add(new AnonymousPrincipal());
+               // return true;
        }
 
        @Override
@@ -64,9 +84,14 @@ public class SystemJackrabbitLoginModule implements LoginModule {
 
        @Override
        public boolean logout() throws LoginException {
-               subject.getPrincipals().removeAll(
-                               subject.getPrincipals(AdminPrincipal.class));
+               Set<SystemAuth> initPrincipal = subject
+                               .getPrincipals(SystemAuth.class);
+               if (!initPrincipal.isEmpty()) {
+                       subject.getPrincipals(AdminPrincipal.class);
+                       return true;
+               }
+               // subject.getPrincipals().removeAll(
+               // subject.getPrincipals(AdminPrincipal.class));
                return true;
        }
-
 }