Merge pull request #5483 from geoand/spring-security-preparation

Make build registration of security interceptors more flexible
This commit is contained in:
Georgios Andrianakis
2019-11-18 10:05:15 +02:00
committed by GitHub
8 changed files with 308 additions and 144 deletions

View File

@@ -1,6 +1,7 @@
package io.quarkus.resteasy.deployment;
import static io.quarkus.deployment.annotations.ExecutionTime.STATIC_INIT;
import static io.quarkus.resteasy.deployment.SecurityTransformerUtils.hasSecurityAnnotation;
import java.util.HashSet;
import java.util.List;
@@ -10,7 +11,6 @@ import java.util.stream.Collectors;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import io.quarkus.arc.deployment.AnnotationsTransformerBuildItem;
import io.quarkus.deployment.Capabilities;
import io.quarkus.deployment.IsDevelopment;
import io.quarkus.deployment.annotations.BuildProducer;
@@ -41,24 +41,19 @@ public class ResteasyBuiltinsProcessor {
void setUpDenyAllJaxRs(CombinedIndexBuildItem index,
JaxRsSecurityConfig config,
ResteasyDeploymentBuildItem resteasyDeployment,
BuildProducer<AnnotationsTransformerBuildItem> transformers,
BuildProducer<AdditionalSecuredClassesBuildIem> additionalSecuredClasses) {
if (config.denyJaxRs) {
Set<ClassInfo> classes = new HashSet<>();
DenyJaxRsTransformer transformer = new DenyJaxRsTransformer(resteasyDeployment.getDeployment());
List<String> resourceClasses = resteasyDeployment.getDeployment().getScannedResourceClasses();
for (String className : resourceClasses) {
ClassInfo classInfo = index.getIndex().getClassByName(DotName.createSimple(className));
if (transformer.requiresSyntheticDenyAll(classInfo)) {
if (!hasSecurityAnnotation(classInfo)) {
classes.add(classInfo);
}
}
additionalSecuredClasses.produce(new AdditionalSecuredClassesBuildIem(classes));
transformers.produce(new AnnotationsTransformerBuildItem(transformer));
}
}

View File

@@ -0,0 +1,33 @@
package io.quarkus.security.deployment;
import static io.quarkus.security.deployment.SecurityTransformerUtils.DENY_ALL;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.jboss.jandex.AnnotationTarget;
import io.quarkus.arc.processor.AnnotationsTransformer;
public class AdditionalDenyingUnannotatedTransformer implements AnnotationsTransformer {
private final Set<String> classNames;
public AdditionalDenyingUnannotatedTransformer(Collection<String> classNames) {
this.classNames = new HashSet<>(classNames);
}
@Override
public boolean appliesTo(AnnotationTarget.Kind kind) {
return kind == org.jboss.jandex.AnnotationTarget.Kind.CLASS;
}
@Override
public void transform(TransformationContext context) {
String className = context.getTarget().asClass().name().toString();
if (classNames.contains(className)) {
context.transform().add(DENY_ALL).done();
}
}
}

View File

@@ -0,0 +1,31 @@
package io.quarkus.security.deployment;
import java.util.function.Function;
import org.jboss.jandex.MethodInfo;
import io.quarkus.builder.item.MultiBuildItem;
import io.quarkus.gizmo.BytecodeCreator;
import io.quarkus.gizmo.ResultHandle;
/**
* Used as an integration point when extensions need to customize the security behavior of a bean
*/
public final class AdditionalSecurityCheckBuildItem extends MultiBuildItem {
private final MethodInfo methodInfo;
private final Function<BytecodeCreator, ResultHandle> function;
public AdditionalSecurityCheckBuildItem(MethodInfo methodInfo, Function<BytecodeCreator, ResultHandle> function) {
this.methodInfo = methodInfo;
this.function = function;
}
public MethodInfo getMethodInfo() {
return methodInfo;
}
public Function<BytecodeCreator, ResultHandle> getSecurityCheckResultHandleCreator() {
return function;
}
}

View File

@@ -0,0 +1,20 @@
package io.quarkus.security.deployment;
import javax.annotation.security.DenyAll;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import org.jboss.jandex.DotName;
import io.quarkus.security.Authenticated;
public final class DotNames {
public static final DotName ROLES_ALLOWED = DotName.createSimple(RolesAllowed.class.getName());
public static final DotName AUTHENTICATED = DotName.createSimple(Authenticated.class.getName());
public static final DotName DENY_ALL = DotName.createSimple(DenyAll.class.getName());
public static final DotName PERMIT_ALL = DotName.createSimple(PermitAll.class.getName());
private DotNames() {
}
}

View File

@@ -0,0 +1,64 @@
package io.quarkus.security.deployment;
import static io.quarkus.gizmo.MethodDescriptor.ofConstructor;
import java.util.function.Function;
import io.quarkus.gizmo.BytecodeCreator;
import io.quarkus.gizmo.ResultHandle;
import io.quarkus.security.runtime.interceptor.check.AuthenticatedCheck;
import io.quarkus.security.runtime.interceptor.check.DenyAllCheck;
import io.quarkus.security.runtime.interceptor.check.PermitAllCheck;
import io.quarkus.security.runtime.interceptor.check.RolesAllowedCheck;
public class SecurityCheckInstantiationUtil {
private SecurityCheckInstantiationUtil() {
}
public static Function<BytecodeCreator, ResultHandle> rolesAllowedSecurityCheck(final String[] rolesAllowed) {
return new Function<BytecodeCreator, ResultHandle>() {
@Override
public ResultHandle apply(BytecodeCreator creator) {
if ((rolesAllowed == null)) {
throw new IllegalStateException(
"Cannot use a null array to create an instance of " + RolesAllowedCheck.class.getName());
}
ResultHandle ctorArgs = creator.newArray(String.class, creator.load(rolesAllowed.length));
int i = 0;
for (String val : rolesAllowed) {
creator.writeArrayValue(ctorArgs, i++, creator.load(val));
}
return creator.newInstance(ofConstructor(RolesAllowedCheck.class, String[].class), ctorArgs);
}
};
}
public static Function<BytecodeCreator, ResultHandle> denyAllSecurityCheck() {
return new Function<BytecodeCreator, ResultHandle>() {
@Override
public ResultHandle apply(BytecodeCreator creator) {
return creator.newInstance(ofConstructor(DenyAllCheck.class));
}
};
}
public static Function<BytecodeCreator, ResultHandle> permitAllSecurityCheck() {
return new Function<BytecodeCreator, ResultHandle>() {
@Override
public ResultHandle apply(BytecodeCreator creator) {
return creator.newInstance(ofConstructor(PermitAllCheck.class));
}
};
}
public static Function<BytecodeCreator, ResultHandle> authenticatedSecurityCheck() {
return new Function<BytecodeCreator, ResultHandle>() {
@Override
public ResultHandle apply(BytecodeCreator creator) {
return creator.newInstance(ofConstructor(AuthenticatedCheck.class));
}
};
}
}

View File

@@ -1,23 +1,26 @@
package io.quarkus.security.deployment;
import java.lang.reflect.Method;
import static io.quarkus.security.deployment.SecurityCheckInstantiationUtil.authenticatedSecurityCheck;
import static io.quarkus.security.deployment.SecurityCheckInstantiationUtil.denyAllSecurityCheck;
import static io.quarkus.security.deployment.SecurityCheckInstantiationUtil.permitAllSecurityCheck;
import static io.quarkus.security.deployment.SecurityCheckInstantiationUtil.rolesAllowedSecurityCheck;
import java.lang.reflect.Modifier;
import java.security.Provider;
import java.security.Security;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationTarget;
import org.jboss.jandex.AnnotationValue;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.Index;
import org.jboss.jandex.MethodInfo;
import org.jboss.jandex.Type;
import org.jboss.logging.Logger;
@@ -26,10 +29,8 @@ import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
import io.quarkus.arc.deployment.AnnotationsTransformerBuildItem;
import io.quarkus.arc.deployment.BeanRegistrarBuildItem;
import io.quarkus.arc.deployment.InterceptorBindingRegistrarBuildItem;
import io.quarkus.arc.processor.AnnotationStore;
import io.quarkus.arc.processor.BeanConfigurator;
import io.quarkus.arc.processor.BeanRegistrar;
import io.quarkus.arc.processor.BuildExtension;
import io.quarkus.arc.processor.BuiltinScope;
import io.quarkus.deployment.Capabilities;
import io.quarkus.deployment.annotations.BuildProducer;
@@ -39,6 +40,7 @@ import io.quarkus.deployment.builditem.ApplicationIndexBuildItem;
import io.quarkus.deployment.builditem.CapabilityBuildItem;
import io.quarkus.deployment.builditem.FeatureBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import io.quarkus.gizmo.BytecodeCreator;
import io.quarkus.gizmo.MethodCreator;
import io.quarkus.gizmo.MethodDescriptor;
import io.quarkus.gizmo.ResultHandle;
@@ -54,6 +56,7 @@ import io.quarkus.security.runtime.interceptor.SecurityCheckStorage;
import io.quarkus.security.runtime.interceptor.SecurityCheckStorageBuilder;
import io.quarkus.security.runtime.interceptor.SecurityConstrainer;
import io.quarkus.security.runtime.interceptor.SecurityHandler;
import io.quarkus.security.runtime.interceptor.check.SecurityCheck;
import io.quarkus.security.spi.AdditionalSecuredClassesBuildIem;
public class SecurityProcessor {
@@ -94,14 +97,6 @@ public class SecurityProcessor {
}
}
@BuildStep
void transformSecurityAnnotations(BuildProducer<AnnotationsTransformerBuildItem> transformers,
SecurityBuildTimeConfig config) {
if (config.denyUnannotated) {
transformers.produce(new AnnotationsTransformerBuildItem(new DenyingUnannotatedTransformer()));
}
}
@BuildStep
void registerSecurityInterceptors(BuildProducer<InterceptorBindingRegistrarBuildItem> registrars,
BuildProducer<AdditionalBeanBuildItem> beans) {
@@ -112,44 +107,71 @@ public class SecurityProcessor {
beans.produce(new AdditionalBeanBuildItem(SecurityHandler.class, SecurityConstrainer.class));
}
/*
* The annotation store is not meant to be generally supported for security annotation.
* It is only used here in order to be able to register the DenyAllInterceptor for
* methods that don't have a security annotation
*/
@BuildStep
void transformSecurityAnnotations(BuildProducer<AnnotationsTransformerBuildItem> transformers,
List<AdditionalSecuredClassesBuildIem> additionalSecuredClasses,
SecurityBuildTimeConfig config) {
if (config.denyUnannotated) {
transformers.produce(new AnnotationsTransformerBuildItem(new DenyingUnannotatedTransformer()));
}
if (!additionalSecuredClasses.isEmpty()) {
Set<String> additionalSecured = new HashSet<>();
for (AdditionalSecuredClassesBuildIem securedClasses : additionalSecuredClasses) {
for (ClassInfo additionalSecuredClass : securedClasses.additionalSecuredClasses) {
additionalSecured.add(additionalSecuredClass.name().toString());
}
}
transformers.produce(
new AnnotationsTransformerBuildItem(new AdditionalDenyingUnannotatedTransformer(additionalSecured)));
}
}
@BuildStep
void gatherSecurityChecks(BuildProducer<BeanRegistrarBuildItem> beanRegistrars,
ApplicationIndexBuildItem indexBuildItem,
BuildProducer<ApplicationClassPredicateBuildItem> classPredicate,
List<AdditionalSecuredClassesBuildIem> additionalSecuredClasses) {
List<AdditionalSecuredClassesBuildIem> additionalSecuredClasses,
List<AdditionalSecurityCheckBuildItem> additionalSecurityChecks, SecurityBuildTimeConfig config) {
classPredicate.produce(new ApplicationClassPredicateBuildItem(new SecurityCheckStorage.AppPredicate()));
Set<ClassInfo> additionalSecured = new HashSet<>();
if (additionalSecuredClasses != null) {
for (AdditionalSecuredClassesBuildIem securedClasses : additionalSecuredClasses) {
additionalSecured.addAll(securedClasses.additionalSecuredClasses);
}
for (AdditionalSecuredClassesBuildIem securedClasses : additionalSecuredClasses) {
additionalSecured.addAll(securedClasses.additionalSecuredClasses);
}
beanRegistrars.produce(new BeanRegistrarBuildItem(new BeanRegistrar() {
@Override
public void register(RegistrationContext registrationContext) {
Map<MethodInfo, AnnotationInstance> methodAnnotations = gatherSecurityAnnotationsByLooping(indexBuildItem,
registrationContext, additionalSecured);
Map<MethodInfo, Function<BytecodeCreator, ResultHandle>> securityChecks = gatherSecurityAnnotations(
indexBuildItem, additionalSecured, config.denyUnannotated);
for (AdditionalSecurityCheckBuildItem additionalSecurityCheck : additionalSecurityChecks) {
securityChecks.put(additionalSecurityCheck.getMethodInfo(),
additionalSecurityCheck.getSecurityCheckResultHandleCreator());
}
DotName name = DotName.createSimple(SecurityCheckStorage.class.getName());
BeanConfigurator<Object> configurator = registrationContext.configure(name);
configurator.addType(name);
configurator.scope(BuiltinScope.APPLICATION.getInfo());
configurator.creator(m -> {
ResultHandle storageBuilder = m
configurator.creator(creator -> {
ResultHandle storageBuilder = creator
.newInstance(MethodDescriptor.ofConstructor(SecurityCheckStorageBuilder.class));
for (Map.Entry<MethodInfo, AnnotationInstance> methodEntry : methodAnnotations.entrySet()) {
registerSecuredMethod(storageBuilder, m, methodEntry);
for (Map.Entry<MethodInfo, Function<BytecodeCreator, ResultHandle>> methodEntry : securityChecks
.entrySet()) {
registerSecuredMethod(storageBuilder, creator, methodEntry);
}
ResultHandle ret = m.invokeVirtualMethod(
ResultHandle ret = creator.invokeVirtualMethod(
MethodDescriptor.ofMethod(SecurityCheckStorageBuilder.class, "create",
SecurityCheckStorage.class),
storageBuilder);
m.returnValue(ret);
creator.returnValue(ret);
});
configurator.done();
}
@@ -158,39 +180,17 @@ public class SecurityProcessor {
private void registerSecuredMethod(ResultHandle checkStorage,
MethodCreator methodCreator,
Map.Entry<MethodInfo, AnnotationInstance> methodEntry) {
try {
MethodInfo method = methodEntry.getKey();
ResultHandle aClass = methodCreator.load(method.declaringClass().name().toString());
ResultHandle methodName = methodCreator.load(method.name());
ResultHandle params = paramTypes(methodCreator, method.parameters());
Map.Entry<MethodInfo, Function<BytecodeCreator, ResultHandle>> methodEntry) {
MethodInfo methodInfo = methodEntry.getKey();
ResultHandle declaringClass = methodCreator.load(methodInfo.declaringClass().name().toString());
ResultHandle methodName = methodCreator.load(methodInfo.name());
ResultHandle methodParamTypes = paramTypes(methodCreator, methodInfo.parameters());
AnnotationInstance instance = methodEntry.getValue();
ResultHandle securityAnnotation = methodCreator.load(instance.name().toString());
ResultHandle annotationParameters = annotationValues(methodCreator, instance);
Method registerAnnotation = SecurityCheckStorageBuilder.class.getDeclaredMethod("registerAnnotation",
String.class, String.class, String[].class, String.class, String[].class);
methodCreator.invokeVirtualMethod(MethodDescriptor.ofMethod(registerAnnotation), checkStorage,
aClass, methodName, params, securityAnnotation, annotationParameters);
} catch (NoSuchMethodException e) {
throw new IllegalStateException("registerAnnotation method not found on on SecurityCheckStorage", e);
}
}
private ResultHandle annotationValues(MethodCreator methodCreator, AnnotationInstance instance) {
AnnotationValue value = instance.value();
if (value != null && value.asStringArray() != null) {
String[] values = value.asStringArray();
ResultHandle result = methodCreator.newArray(String.class, methodCreator.load(values.length));
int i = 0;
for (String val : values) {
methodCreator.writeArrayValue(result, i++, methodCreator.load(val));
}
return result;
}
return methodCreator.loadNull();
methodCreator.invokeVirtualMethod(
MethodDescriptor.ofMethod(SecurityCheckStorageBuilder.class, "registerCheck", void.class, String.class,
String.class, String[].class, SecurityCheck.class),
checkStorage,
declaringClass, methodName, methodParamTypes, methodEntry.getValue().apply(methodCreator));
}
private ResultHandle paramTypes(MethodCreator ctor, List<Type> parameters) {
@@ -203,61 +203,106 @@ public class SecurityProcessor {
return result;
}
private Map<MethodInfo, AnnotationInstance> gatherSecurityAnnotationsByLooping(ApplicationIndexBuildItem indexBuildItem,
BeanRegistrar.RegistrationContext registrationContext,
Set<ClassInfo> additionalSecuredClasses) {
Set<DotName> securityAnnotations = SecurityAnnotationsRegistrar.SECURITY_BINDINGS.keySet();
AnnotationStore annotationStore = registrationContext.get(BuildExtension.Key.ANNOTATION_STORE);
Set<ClassInfo> classesWithSecurity = new HashSet<>(additionalSecuredClasses);
private Map<MethodInfo, Function<BytecodeCreator, ResultHandle>> gatherSecurityAnnotations(
ApplicationIndexBuildItem indexBuildItem,
Set<ClassInfo> additionalSecuredClasses, boolean denyUnannotated) {
Index index = indexBuildItem.getIndex();
for (DotName securityAnno : SecurityAnnotationsRegistrar.SECURITY_BINDINGS.keySet()) {
for (AnnotationInstance annotation : index.getAnnotations(securityAnno)) {
AnnotationTarget target = annotation.target();
switch (target.kind()) {
case CLASS:
classesWithSecurity.add(target.asClass());
break;
case METHOD:
classesWithSecurity.add(target.asMethod().declaringClass());
break;
default:
throw new IllegalStateException("Security annotation discovered on unsupported target: " + target);
Map<MethodInfo, AnnotationInstance> methodToInstanceCollector = new HashMap<>();
Map<MethodInfo, Function<BytecodeCreator, ResultHandle>> result = new HashMap<>(gatherSecurityAnnotations(
indexBuildItem, DotNames.ROLES_ALLOWED, methodToInstanceCollector,
(instance -> rolesAllowedSecurityCheck(instance.value().asStringArray()))));
result.putAll(gatherSecurityAnnotations(indexBuildItem, DotNames.PERMIT_ALL, methodToInstanceCollector,
(instance -> permitAllSecurityCheck())));
result.putAll(gatherSecurityAnnotations(indexBuildItem, DotNames.AUTHENTICATED, methodToInstanceCollector,
(instance -> authenticatedSecurityCheck())));
result.putAll(gatherSecurityAnnotations(indexBuildItem, DotNames.DENY_ALL, methodToInstanceCollector,
(instance -> denyAllSecurityCheck())));
/*
* Handle additional secured classes by adding the denyAll check to all public non-static methods
* that don't have security annotations
*/
for (ClassInfo additionalSecureClassInfo : additionalSecuredClasses) {
for (MethodInfo methodInfo : additionalSecureClassInfo.methods()) {
if (!isPublicNonStaticNonConstructor(methodInfo)) {
continue;
}
AnnotationInstance alreadyExistingInstance = methodToInstanceCollector.get(methodInfo);
if ((alreadyExistingInstance == null)) {
result.put(methodInfo, denyAllSecurityCheck());
} else if (alreadyExistingInstance.target().kind() == AnnotationTarget.Kind.CLASS) {
throw new IllegalStateException("Class " + methodInfo.declaringClass()
+ " should not have been added as an additional secured class");
}
}
}
return gatherSecurityAnnotations(securityAnnotations,
classesWithSecurity, annotationStore);
}
private Map<MethodInfo, AnnotationInstance> gatherSecurityAnnotations(Set<DotName> securityAnnotations,
Set<ClassInfo> classesWithSecurity,
AnnotationStore annotationStore) {
Map<MethodInfo, AnnotationInstance> methodAnnotations = new HashMap<>();
for (ClassInfo classInfo : classesWithSecurity) {
Collection<AnnotationInstance> classAnnotations = annotationStore.getAnnotations(classInfo);
AnnotationInstance classLevelAnnotation = getSingle(classAnnotations, securityAnnotations);
for (MethodInfo method : classInfo.methods()) {
AnnotationInstance methodAnnotation = getSingle(annotationStore.getAnnotations(method), securityAnnotations);
methodAnnotation = methodAnnotation == null ? classLevelAnnotation : methodAnnotation;
if (methodAnnotation != null) {
methodAnnotations.put(method, methodAnnotation);
/*
* If we need to add the denyAll security check to all unannotated methods, we simply go through all secured methods,
* collect the declaring classes, then go through all methods of the classes and add the necessary check
*/
if (denyUnannotated) {
Set<ClassInfo> allClassesWithSecurityChecks = new HashSet<>(methodToInstanceCollector.keySet().size());
for (MethodInfo methodInfo : methodToInstanceCollector.keySet()) {
allClassesWithSecurityChecks.add(methodInfo.declaringClass());
}
for (ClassInfo classWithSecurityCheck : allClassesWithSecurityChecks) {
for (MethodInfo methodInfo : classWithSecurityCheck.methods()) {
if (!isPublicNonStaticNonConstructor(methodInfo)) {
continue;
}
if (methodToInstanceCollector.containsKey(methodInfo)) { // the method already has a security check
continue;
}
result.put(methodInfo, denyAllSecurityCheck());
}
}
}
return methodAnnotations;
return result;
}
private AnnotationInstance getSingle(Collection<AnnotationInstance> classAnnotations, Set<DotName> securityAnnotations) {
AnnotationInstance result = null;
for (AnnotationInstance annotation : classAnnotations) {
if (securityAnnotations.contains(annotation.name())) {
if (result != null) {
throw new IllegalStateException("Multiple security annotations on target: " + annotation.target());
private boolean isPublicNonStaticNonConstructor(MethodInfo methodInfo) {
return Modifier.isPublic(methodInfo.flags()) && !Modifier.isStatic(methodInfo.flags())
&& !"<init>".equals(methodInfo.name());
}
private Map<MethodInfo, Function<BytecodeCreator, ResultHandle>> gatherSecurityAnnotations(
ApplicationIndexBuildItem indexBuildItem, DotName dotName,
Map<MethodInfo, AnnotationInstance> alreadyCheckedMethods,
Function<AnnotationInstance, Function<BytecodeCreator, ResultHandle>> securityCheckInstanceCreator) {
Map<MethodInfo, Function<BytecodeCreator, ResultHandle>> result = new HashMap<>();
List<AnnotationInstance> instances = indexBuildItem.getIndex().getAnnotations(dotName);
// make sure we process annotations on methods first
for (AnnotationInstance instance : instances) {
AnnotationTarget target = instance.target();
if (target.kind() == AnnotationTarget.Kind.METHOD) {
MethodInfo methodInfo = target.asMethod();
if (alreadyCheckedMethods.containsKey(methodInfo)) {
throw new IllegalStateException("Method " + methodInfo.name() + " of class " + methodInfo.declaringClass()
+ " is annotated with multiple security annotations");
}
alreadyCheckedMethods.put(methodInfo, instance);
result.put(methodInfo, securityCheckInstanceCreator.apply(instance));
}
}
// now add the class annotations to methods if they haven't already been annotated
for (AnnotationInstance instance : instances) {
AnnotationTarget target = instance.target();
if (target.kind() == AnnotationTarget.Kind.CLASS) {
List<MethodInfo> methods = target.asClass().methods();
for (MethodInfo methodInfo : methods) {
AnnotationInstance alreadyExistingInstance = alreadyCheckedMethods.get(methodInfo);
if ((alreadyExistingInstance == null)) {
result.put(methodInfo, securityCheckInstanceCreator.apply(instance));
} else if (alreadyExistingInstance.target().kind() == AnnotationTarget.Kind.CLASS) {
throw new IllegalStateException(
"Class " + methodInfo.declaringClass() + " is annotated with multiple security annotations");
}
}
result = annotation;
}
}

View File

@@ -6,27 +6,16 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import javax.annotation.security.DenyAll;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import io.quarkus.security.Authenticated;
import io.quarkus.security.runtime.interceptor.check.AuthenticatedCheck;
import io.quarkus.security.runtime.interceptor.check.DenyAllCheck;
import io.quarkus.security.runtime.interceptor.check.PermitAllCheck;
import io.quarkus.security.runtime.interceptor.check.RolesAllowedCheck;
import io.quarkus.security.runtime.interceptor.check.SecurityCheck;
public class SecurityCheckStorageBuilder {
private final Map<MethodDescription, SecurityCheck> securityChecks = new HashMap<>();
public void registerAnnotation(String aClass,
public void registerCheck(String className,
String methodName,
String[] parameterTypes,
String securityAnnotation,
String[] value) {
securityChecks.put(new MethodDescription(aClass, methodName, parameterTypes),
determineCheck(securityAnnotation, value));
SecurityCheck securityCheck) {
securityChecks.put(new MethodDescription(className, methodName, parameterTypes), securityCheck);
}
public SecurityCheckStorage create() {
@@ -40,23 +29,7 @@ public class SecurityCheckStorageBuilder {
};
}
private SecurityCheck determineCheck(String securityAnnotation, String[] value) {
if (DenyAll.class.getName().equals(securityAnnotation)) {
return new DenyAllCheck();
}
if (RolesAllowed.class.getName().equals(securityAnnotation)) {
return new RolesAllowedCheck(value);
}
if (PermitAll.class.getName().equals(securityAnnotation)) {
return new PermitAllCheck();
}
if (Authenticated.class.getName().equals(securityAnnotation)) {
return new AuthenticatedCheck();
}
throw new IllegalArgumentException("Unsupported security check " + securityAnnotation);
}
private String[] typesAsStrings(Class[] parameterTypes) {
private String[] typesAsStrings(Class<?>[] parameterTypes) {
String[] result = new String[parameterTypes.length];
for (int i = 0; i < parameterTypes.length; i++) {
result[i] = parameterTypes[i].getName();
@@ -69,8 +42,8 @@ public class SecurityCheckStorageBuilder {
private final String methodName;
private final String[] parameterTypes;
public MethodDescription(String aClass, String methodName, String[] parameterTypes) {
this.className = aClass;
public MethodDescription(String className, String methodName, String[] parameterTypes) {
this.className = className;
this.methodName = methodName;
this.parameterTypes = parameterTypes;
}

View File

@@ -7,6 +7,9 @@ import org.jboss.jandex.ClassInfo;
import io.quarkus.builder.item.MultiBuildItem;
/**
* Contains classes that need to have @DenyAll on all methods that don't have security annotations
*/
public final class AdditionalSecuredClassesBuildIem extends MultiBuildItem {
public final Collection<ClassInfo> additionalSecuredClasses;