diff --git a/core/src/main/java/com/inteligr8/alfresco/annotations/IfAuthorized.java b/core/src/main/java/com/inteligr8/alfresco/annotations/IfAuthorized.java new file mode 100644 index 0000000..4fccf8a --- /dev/null +++ b/core/src/main/java/com/inteligr8/alfresco/annotations/IfAuthorized.java @@ -0,0 +1,30 @@ +package com.inteligr8.alfresco.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * This annotation tells the framework to only execute the annotated method if + * the ACS authenticated user is authorized. + * + * @see com.inteligr8.alfresco.annotations.Authorizable + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@Repeatable(IfAuthorizeds.class) +public @interface IfAuthorized { + + /** + * The authorities (users and/or user groups) to constrain for the + * authorization context. Only one authority needs to match. To + * require multiple authorities, use multiple @IfAuthorized + * annotations. + * + * @return An array of ACS authorities; empty means any authenticated user. + */ + String[] value() default ""; + +} diff --git a/core/src/main/java/com/inteligr8/alfresco/annotations/IfAuthorizeds.java b/core/src/main/java/com/inteligr8/alfresco/annotations/IfAuthorizeds.java new file mode 100644 index 0000000..a35852e --- /dev/null +++ b/core/src/main/java/com/inteligr8/alfresco/annotations/IfAuthorizeds.java @@ -0,0 +1,14 @@ +package com.inteligr8.alfresco.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface IfAuthorizeds { + + IfAuthorized[] value(); + +} diff --git a/core/src/main/java/com/inteligr8/alfresco/annotations/aspect/IfAuthorizedAspect.java b/core/src/main/java/com/inteligr8/alfresco/annotations/aspect/IfAuthorizedAspect.java new file mode 100644 index 0000000..543c4c6 --- /dev/null +++ b/core/src/main/java/com/inteligr8/alfresco/annotations/aspect/IfAuthorizedAspect.java @@ -0,0 +1,92 @@ +package com.inteligr8.alfresco.annotations.aspect; + +import java.lang.reflect.Method; +import java.util.Set; + +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.util.collections.CollectionUtils; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.extensions.webscripts.Description.RequiredAuthentication; +import org.springframework.extensions.webscripts.WebScriptException; +import org.springframework.http.HttpStatus; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.server.ResponseStatusException; + +import com.inteligr8.alfresco.annotations.IfAuthorized; +import com.inteligr8.alfresco.annotations.context.WebScriptContext; + +import net.sf.acegisecurity.GrantedAuthority; + +/** + * This aspect implements the IfAuthorized annotation. + * + * @see com.inteligr8.alfresco.annotations.IfAuthorized + */ +@Aspect +public class IfAuthorizedAspect { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired(required = false) + private WebScriptContext wscontext; + + @Autowired(required = false) + private WebApplicationContext wacontext; + + @Pointcut("@annotation(com.inteligr8.alfresco.annotations.IfAuthorized) && execution(* *(..))") + public void isIfAuthorizedAnnotated() { + } + + @Around("isIfAuthorizedAnnotated()") + public Object ifAuthorized(ProceedingJoinPoint joinPoint) throws Throwable { + this.logger.trace("ifAuthorized({})", joinPoint); + + if (this.wscontext != null && !RequiredAuthentication.user.equals(this.wscontext.getWebscript().getDescription().getRequiredAuthentication())) + return joinPoint.proceed(); + + if (!(joinPoint.getSignature() instanceof MethodSignature)) + throw new IllegalStateException("The @IfAuthorized annotation must be on methods and methods have signatures"); + + MethodSignature methodSig = (MethodSignature) joinPoint.getSignature(); + Method method = methodSig.getMethod(); + IfAuthorized[] ifauths = method.getAnnotationsByType(IfAuthorized.class); + for (IfAuthorized ifauth : ifauths) { + if (ifauth.value() != null && ifauth.value().length > 0) { + if (!this.isAuthorized(ifauth.value())) + return this.unauthorized(); + } + } + + return joinPoint.proceed(); + } + + protected boolean isAuthorized(String[] permittedAuthorities) { + Set permittedAuthoritiesSet = CollectionUtils.asSet(permittedAuthorities); + + GrantedAuthority[] authenticatedAuthorities = AuthenticationUtil.getFullAuthentication().getAuthorities(); + for (GrantedAuthority auth : authenticatedAuthorities) { + if (permittedAuthoritiesSet.contains(auth.getAuthority())) + return true; + } + + return false; + } + + protected Object unauthorized() { + if (this.wscontext != null) { + throw new WebScriptException(HttpStatus.FORBIDDEN.value(), "The authenticated user is not authorized to use this resource"); + } else if (this.wacontext != null) { + throw new ResponseStatusException(HttpStatus.FORBIDDEN, "The authenticated user is not authorized to use this resource"); + } else { + return null; + } + } + +} diff --git a/core/src/main/resources/META-INF/aop.xml b/core/src/main/resources/META-INF/aop.xml index b704794..0e07e13 100644 --- a/core/src/main/resources/META-INF/aop.xml +++ b/core/src/main/resources/META-INF/aop.xml @@ -6,6 +6,7 @@ +