package edu.asu.spring.quadriga.aspects;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import edu.asu.spring.quadriga.aspects.annotations.ElementAccessPolicy;
import edu.asu.spring.quadriga.aspects.annotations.NoAuthorizationCheck;
import edu.asu.spring.quadriga.aspects.annotations.RestAccessPolicies;
import edu.asu.spring.quadriga.exceptions.QuadrigaAccessException;
import edu.asu.spring.quadriga.exceptions.RestException;
/**
* Aspect based Access authentication for REST APIs Can be used around a method
* in any REST based controllers to authenticate the client.
*
* @author Lohith Dwaraka
*
*/
@Aspect
@Component
public class RestAccessAspect {
@Autowired
private IAuthorizationManager authorizationManager;
/**
* This method prevents the access permissions check for the web package
* methods annotated with 'noCheck' for rest interfaces
*
* @param pjp
* @param noCheck
* @return ProceedingJoinPoint object
* @throws Throwable
*/
@Around("within(edu.asu.spring.quadriga.rest..*) && @annotation(noCheck)")
public Object chkProjectAuthorization(ProceedingJoinPoint pjp, NoAuthorizationCheck noCheck) throws Throwable {
return pjp.proceed();
}
/**
* This method checks the access permissions for the objects before
* executing the methods.This provides run time access permission check to
* the methods in the web package and annotated with 'checks' during rest
* interface access.
*
* @param pjp
* @param checks
* @return - no access it throws Access Denied exception. if he have access
* returns ProceedingJointPoint object
* @throws Throwable
*/
@Around("within(edu.asu.spring.quadriga.rest..*) && @annotation(checks)")
public Object chkAuthorization(ProceedingJoinPoint pjp, RestAccessPolicies checks) throws Throwable {
boolean haveAccess = true;
// retrieve the logged in User name
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String userName = auth.getName().toLowerCase();
if (userName == null || userName.isEmpty()) {
throw new RestException(401);
}
// Loop through all the access policies specified
ElementAccessPolicy[] policies = checks.value();
for (ElementAccessPolicy policy : policies) {
// retrieve the authorization object based on the type
IAuthorization authorization = authorizationManager.getAuthorizationObject(policy.type());
try {
// calling the object
if (policy.paramIndex() > 0) {
String accessObjectId = pjp.getArgs()[policy.paramIndex() - 1].toString();
haveAccess = authorization.chkAuthorization(userName, accessObjectId, policy.userRole());
} else {
haveAccess = authorization.chkAuthorizationByRole(userName, policy.userRole());
}
} catch (QuadrigaAccessException e) {
throw new RestException(403);
}
if (haveAccess) {
break;
}
}
if (!haveAccess) {
throw new RestException(403);
}
return pjp.proceed();
}
}