Introduce system authenticated bean post processing
authorMathieu Baudier <mbaudier@argeo.org>
Mon, 18 Apr 2011 08:51:15 +0000 (08:51 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Mon, 18 Apr 2011 08:51:15 +0000 (08:51 +0000)
NEW - bug 17: Generalize agent management and registration beyond JMS
https://bugzilla.argeo.org/show_bug.cgi?id=17

git-svn-id: https://svn.argeo.org/commons/trunk@4445 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/AbstractSystemExecution.java [new file with mode: 0644]
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/InternalAuthentication.java
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/KeyBasedSystemExecutionService.java
security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/SystemExecutionBeanPostProcessor.java [new file with mode: 0644]

diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/AbstractSystemExecution.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/AbstractSystemExecution.java
new file mode 100644 (file)
index 0000000..55f0fef
--- /dev/null
@@ -0,0 +1,64 @@
+package org.argeo.security.core;
+
+import java.security.AccessController;
+
+import javax.security.auth.Subject;
+
+import org.argeo.ArgeoException;
+import org.springframework.security.Authentication;
+import org.springframework.security.AuthenticationManager;
+import org.springframework.security.context.SecurityContext;
+import org.springframework.security.context.SecurityContextHolder;
+
+/** Provides base method for executing code with system authorization. */
+public abstract class AbstractSystemExecution {
+       private AuthenticationManager authenticationManager;
+       private String systemAuthenticationKey;
+
+       /**
+        * Authenticate the calling thread to the underlying
+        * {@link AuthenticationManager}
+        */
+       protected void authenticateAsSystem() {
+               SecurityContext securityContext = SecurityContextHolder.getContext();
+               Authentication currentAuth = securityContext.getAuthentication();
+               if (currentAuth != null)
+                       throw new ArgeoException(
+                                       "System execution on an already authenticated thread: "
+                                                       + currentAuth + ", THREAD="
+                                                       + Thread.currentThread().getId());
+
+               Subject subject = Subject.getSubject(AccessController.getContext());
+               if (subject != null
+                               && !subject.getPrincipals(Authentication.class).isEmpty())
+                       throw new ArgeoException(
+                                       "There is already an authenticated subject: " + subject);
+
+               String key = systemAuthenticationKey != null ? systemAuthenticationKey
+                               : System.getProperty(
+                                               InternalAuthentication.SYSTEM_KEY_PROPERTY,
+                                               InternalAuthentication.SYSTEM_KEY_DEFAULT);
+               if (key == null)
+                       throw new ArgeoException("No system key defined");
+               Authentication auth = authenticationManager
+                               .authenticate(new InternalAuthentication(key));
+               securityContext.setAuthentication(auth);
+       }
+
+       /** Removes the authentication from the calling thread. */
+       protected void deauthenticateAsSystem() {
+               // remove the authentication
+               SecurityContext securityContext = SecurityContextHolder.getContext();
+               securityContext.setAuthentication(null);
+       }
+
+       public void setAuthenticationManager(
+                       AuthenticationManager authenticationManager) {
+               this.authenticationManager = authenticationManager;
+       }
+
+       public void setSystemAuthenticationKey(String systemAuthenticationKey) {
+               this.systemAuthenticationKey = systemAuthenticationKey;
+       }
+
+}
index f20f6805bdb5c4a6042ce3a4a631f330365e18bc..51c21eed167738e0765c7294a55547b5b8245b95 100644 (file)
@@ -21,11 +21,14 @@ import org.springframework.security.GrantedAuthority;
 import org.springframework.security.GrantedAuthorityImpl;
 import org.springframework.security.adapters.PrincipalSpringSecurityUserToken;
 
+/** A token base on a system key used to request a system authentication. */
 public class InternalAuthentication extends PrincipalSpringSecurityUserToken
                implements SystemAuthentication {
        private static final long serialVersionUID = -6783376375615949315L;
        public final static String DEFAULT_SYSTEM_USERNAME = "system";
        public final static String DEFAULT_SYSTEM_ROLE = "ROLE_SYSTEM";
+       public final static String SYSTEM_KEY_PROPERTY = "argeo.security.systemKey";
+       public final static String SYSTEM_KEY_DEFAULT = "argeo";
 
        public InternalAuthentication(String key, String systemUsername,
                        String systemRole) {
index b2dfc4a2439922cbd795d3c6c1522444130903c2..07ae046539c93ca5dd8f2deddf9c6ee62db4b7c6 100644 (file)
@@ -1,28 +1,19 @@
 package org.argeo.security.core;
 
-import java.security.AccessController;
 import java.util.concurrent.Callable;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 import java.util.concurrent.FutureTask;
 
-import javax.security.auth.Subject;
-
 import org.argeo.ArgeoException;
 import org.argeo.security.SystemExecutionService;
-import org.springframework.security.Authentication;
-import org.springframework.security.AuthenticationManager;
-import org.springframework.security.context.SecurityContext;
-import org.springframework.security.context.SecurityContextHolder;
 
 /**
  * Implementation of a {@link SystemExecutionService} using a key-based
  * {@link InternalAuthentication}
  */
-public class KeyBasedSystemExecutionService implements SystemExecutionService {
-       private AuthenticationManager authenticationManager;
-       private String systemAuthenticationKey;
-
+public class KeyBasedSystemExecutionService extends AbstractSystemExecution
+               implements SystemExecutionService {
        public void execute(Runnable runnable) {
                try {
                        wrapWithSystemAuthentication(Executors.callable(runnable)).call();
@@ -44,46 +35,13 @@ public class KeyBasedSystemExecutionService implements SystemExecutionService {
                return new Callable<T>() {
 
                        public T call() throws Exception {
-                               SecurityContext securityContext = SecurityContextHolder
-                                               .getContext();
-                               Authentication currentAuth = securityContext
-                                               .getAuthentication();
-                               if (currentAuth != null)
-                                       throw new ArgeoException(
-                                                       "System execution on an already authenticated thread: "
-                                                                       + currentAuth + ", THREAD="
-                                                                       + Thread.currentThread().getId());
-
-                               Subject subject = Subject.getSubject(AccessController
-                                               .getContext());
-                               if (subject != null
-                                               && !subject.getPrincipals(Authentication.class)
-                                                               .isEmpty())
-                                       throw new ArgeoException(
-                                                       "There is already an authenticated subject: "
-                                                                       + subject);
-
-                               Authentication auth = authenticationManager
-                                               .authenticate(new InternalAuthentication(
-                                                               systemAuthenticationKey));
-                               securityContext.setAuthentication(auth);
+                               authenticateAsSystem();
                                try {
                                        return runnable.call();
                                } finally {
-                                       // remove the authentication
-                                       securityContext.setAuthentication(null);
+                                       deauthenticateAsSystem();
                                }
                        }
                };
        }
-
-       public void setAuthenticationManager(
-                       AuthenticationManager authenticationManager) {
-               this.authenticationManager = authenticationManager;
-       }
-
-       public void setSystemAuthenticationKey(String systemAuthenticationKey) {
-               this.systemAuthenticationKey = systemAuthenticationKey;
-       }
-
 }
diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/SystemExecutionBeanPostProcessor.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/SystemExecutionBeanPostProcessor.java
new file mode 100644 (file)
index 0000000..0173173
--- /dev/null
@@ -0,0 +1,29 @@
+package org.argeo.security.core;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+
+/**
+ * Executes with a system authentication the initialization methods of the
+ * application context where it has been defined.
+ */
+public class SystemExecutionBeanPostProcessor extends
+               AbstractSystemExecution implements BeanPostProcessor {
+
+       public Object postProcessBeforeInitialization(Object bean, String beanName)
+                       throws BeansException {
+               authenticateAsSystem();
+               return bean;
+       }
+
+       public Object postProcessAfterInitialization(Object bean, String beanName)
+                       throws BeansException {
+               // NOTE: in case there was an exception in on the initialization method
+               // 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();
+               return bean;
+       }
+
+}