org.springframework.security.web.method.annotation.UserDetailsArgumentResolver Maven / Gradle / Ivy
package org.springframework.security.web.method.annotation;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.expression.BeanResolver;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
/**
* @see org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver
*/
public class UserDetailsArgumentResolver implements HandlerMethodArgumentResolver {
private ExpressionParser parser = new SpelExpressionParser();
private BeanResolver beanResolver;
private final UserDetailsService userDetailsService;
public UserDetailsArgumentResolver(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
@Override
public boolean supportsParameter(MethodParameter parameter) {
return findMethodAnnotation(AuthenticationPrincipal.class, parameter) != null;
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
Authentication authentication = orElseThrow(SecurityContextHolder.getContext().getAuthentication());
if (authentication instanceof AnonymousAuthenticationToken || !authentication.isAuthenticated()) {
throw new AccessDeniedException("Access is denied from... " + authentication.getPrincipal());
}
Object principal = authentication.getPrincipal();
AuthenticationPrincipal authPrincipal = findMethodAnnotation(AuthenticationPrincipal.class, parameter);
String expressionToParse = authPrincipal.expression();
if (StringUtils.hasLength(expressionToParse)) {
StandardEvaluationContext context = new StandardEvaluationContext();
context.setRootObject(principal);
context.setVariable("this", principal);
context.setBeanResolver(beanResolver);
Expression expression = this.parser.parseExpression(expressionToParse);
principal = expression.getValue(context);
}
if (principal != null && !parameter.getParameterType().isAssignableFrom(principal.getClass())) {
if (principal instanceof UserDetails && UserDetails.class.isAssignableFrom(parameter.getParameterType())) {
try {
UserDetails userDetails = this.userDetailsService.loadUserByUsername(authentication.getName());
Field field = ReflectionUtils.findField(authentication.getClass(), "principal");
Assert.notNull(field, "Not Found Field 'pricipal' from... " + authentication.getClass());
ReflectionUtils.makeAccessible(field);
ReflectionUtils.setField(field, authentication, userDetails);
SecurityContextHolder.getContext().setAuthentication(authentication);
return userDetails;
}
catch (UsernameNotFoundException e) {
throw new AccessDeniedException(principal + " is not assignable to " + parameter.getParameterType(), e);
}
}
throw new AccessDeniedException(principal + " is not assignable to " + parameter.getParameterType());
}
return orElseThrow(principal);
}
private T orElseThrow(T t) {
if (t == null) {
throw new AccessDeniedException("Access is denied");
}
return t;
}
public void setBeanResolver(BeanResolver beanResolver) {
this.beanResolver = beanResolver;
}
private T findMethodAnnotation(Class annotationClass, MethodParameter parameter) {
T annotation = parameter.getParameterAnnotation(annotationClass);
if (annotation != null) {
return annotation;
}
Annotation[] annotationsToSearch = parameter.getParameterAnnotations();
for (Annotation toSearch : annotationsToSearch) {
annotation = AnnotationUtils.findAnnotation(toSearch.annotationType(), annotationClass);
if (annotation != null) {
return annotation;
}
}
return null;
}
}