From 9c0b5fead46f7cc1c9f1deb0b73fc0f66528d870 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Mon, 18 Apr 2011 08:51:15 +0000 Subject: [PATCH] Introduce system authenticated bean post processing 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 --- .../core/AbstractSystemExecution.java | 64 +++++++++++++++++++ .../security/core/InternalAuthentication.java | 3 + .../core/KeyBasedSystemExecutionService.java | 50 ++------------- .../SystemExecutionBeanPostProcessor.java | 29 +++++++++ 4 files changed, 100 insertions(+), 46 deletions(-) create mode 100644 security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/AbstractSystemExecution.java create mode 100644 security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/SystemExecutionBeanPostProcessor.java 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 index 000000000..55f0fefcc --- /dev/null +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/AbstractSystemExecution.java @@ -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; + } + +} diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/InternalAuthentication.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/InternalAuthentication.java index f20f6805b..51c21eed1 100644 --- a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/InternalAuthentication.java +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/InternalAuthentication.java @@ -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) { diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/KeyBasedSystemExecutionService.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/KeyBasedSystemExecutionService.java index b2dfc4a24..07ae04653 100644 --- a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/KeyBasedSystemExecutionService.java +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/KeyBasedSystemExecutionService.java @@ -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() { 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 index 000000000..017317361 --- /dev/null +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/SystemExecutionBeanPostProcessor.java @@ -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; + } + +} -- 2.30.2