SecuredAuthorizationManager should cache annotation's value

Closes gh-12232
This commit is contained in:
Evgeniy Cheban 2022-12-03 01:08:11 +01:00 committed by Josh Cummings
parent 18a3ff2745
commit e0d676c03f
1 changed files with 28 additions and 20 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,14 +17,18 @@
package org.springframework.security.authorization.method;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.support.AopUtils;
import org.springframework.lang.NonNull;
import org.springframework.core.MethodClassKey;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.authorization.AuthorityAuthorizationManager;
import org.springframework.security.authorization.AuthoritiesAuthorizationManager;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
@ -39,7 +43,9 @@ import org.springframework.security.core.Authentication;
*/
public final class SecuredAuthorizationManager implements AuthorizationManager<MethodInvocation> {
private final SecuredAuthorizationManagerRegistry registry = new SecuredAuthorizationManagerRegistry();
private final AuthoritiesAuthorizationManager delegate = new AuthoritiesAuthorizationManager();
private final Map<MethodClassKey, Set<String>> cachedAuthorities = new ConcurrentHashMap<>();
/**
* Determine if an {@link Authentication} has access to a method by evaluating the
@ -51,26 +57,28 @@ public final class SecuredAuthorizationManager implements AuthorizationManager<M
*/
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, MethodInvocation mi) {
AuthorizationManager<MethodInvocation> delegate = this.registry.getManager(mi);
return delegate.check(authentication, mi);
Set<String> authorities = getAuthorities(mi);
return authorities.isEmpty() ? null : this.delegate.check(authentication, authorities);
}
private static final class SecuredAuthorizationManagerRegistry extends AbstractAuthorizationManagerRegistry {
private Set<String> getAuthorities(MethodInvocation methodInvocation) {
Method method = methodInvocation.getMethod();
Object target = methodInvocation.getThis();
Class<?> targetClass = (target != null) ? target.getClass() : null;
MethodClassKey cacheKey = new MethodClassKey(method, targetClass);
return this.cachedAuthorities.computeIfAbsent(cacheKey, (k) -> resolveAuthorities(method, targetClass));
}
@NonNull
@Override
AuthorizationManager<MethodInvocation> resolveManager(Method method, Class<?> targetClass) {
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
Secured secured = findSecuredAnnotation(specificMethod);
return (secured != null) ? AuthorityAuthorizationManager.hasAnyAuthority(secured.value()) : NULL_MANAGER;
}
private Secured findSecuredAnnotation(Method method) {
Secured secured = AuthorizationAnnotationUtils.findUniqueAnnotation(method, Secured.class);
return (secured != null) ? secured
: AuthorizationAnnotationUtils.findUniqueAnnotation(method.getDeclaringClass(), Secured.class);
}
private Set<String> resolveAuthorities(Method method, Class<?> targetClass) {
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
Secured secured = findSecuredAnnotation(specificMethod);
return (secured != null) ? Set.of(secured.value()) : Collections.emptySet();
}
private Secured findSecuredAnnotation(Method method) {
Secured secured = AuthorizationAnnotationUtils.findUniqueAnnotation(method, Secured.class);
return (secured != null) ? secured
: AuthorizationAnnotationUtils.findUniqueAnnotation(method.getDeclaringClass(), Secured.class);
}
}