Skip to content

Commit

Permalink
Merge pull request #39649 from michalvavrik/feature/migrate-security-…
Browse files Browse the repository at this point in the history
…config-classes-to-configmapping

Migrate the Security extension config classes to `@ConfigMapping`
  • Loading branch information
sberyozkin committed Mar 23, 2024
2 parents df34d7f + e44c6de commit 814958b
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,32 @@
import java.util.Optional;
import java.util.Set;

import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigPhase;
import io.quarkus.runtime.annotations.ConfigRoot;
import io.smallrye.config.ConfigMapping;
import io.smallrye.config.WithDefault;
import io.smallrye.config.WithName;

/**
*
*/
@ConfigRoot(phase = ConfigPhase.BUILD_TIME)
public final class SecurityConfig {
@ConfigMapping(prefix = "quarkus.security")
@ConfigRoot
public interface SecurityConfig {

/**
* Whether authorization is enabled in dev mode or not. In other launch modes authorization is always enabled.
*/
@ConfigItem(name = "auth.enabled-in-dev-mode", defaultValue = "true")
public boolean authorizationEnabledInDevMode;
@WithName("auth.enabled-in-dev-mode")
@WithDefault("true")
boolean authorizationEnabledInDevMode();

/**
* List of security providers to register
*/
@ConfigItem
public Optional<Set<String>> securityProviders;
Optional<Set<String>> securityProviders();

/**
* Security provider configuration
*/
@ConfigItem
public Map<String, String> securityProviderConfig;
Map<String, String> securityProviderConfig();
}
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ public class SecurityProcessor {
void produceJcaSecurityProviders(BuildProducer<JCAProviderBuildItem> jcaProviders,
BuildProducer<BouncyCastleProviderBuildItem> bouncyCastleProvider,
BuildProducer<BouncyCastleJsseProviderBuildItem> bouncyCastleJsseProvider) {
Set<String> providers = security.securityProviders.orElse(Set.of());
Set<String> providers = security.securityProviders().orElse(Set.of());
for (String providerName : providers) {
if (SecurityProviderUtils.BOUNCYCASTLE_PROVIDER_NAME.equals(providerName)) {
bouncyCastleProvider.produce(new BouncyCastleProviderBuildItem());
Expand All @@ -138,7 +138,8 @@ void produceJcaSecurityProviders(BuildProducer<JCAProviderBuildItem> jcaProvider
} else if (SecurityProviderUtils.BOUNCYCASTLE_FIPS_JSSE_PROVIDER_NAME.equals(providerName)) {
bouncyCastleJsseProvider.produce(new BouncyCastleJsseProviderBuildItem(true));
} else {
jcaProviders.produce(new JCAProviderBuildItem(providerName, security.securityProviderConfig.get(providerName)));
jcaProviders
.produce(new JCAProviderBuildItem(providerName, security.securityProviderConfig().get(providerName)));
}
log.debugf("Added providerName: %s", providerName);
}
Expand Down Expand Up @@ -412,7 +413,7 @@ void addBouncyCastleExportsToNativeImage(BuildProducer<JPMSExportBuildItem> jpms
}
}

private <BI extends MultiBuildItem> Optional<BI> getOne(List<BI> items) {
private static <BI extends MultiBuildItem> Optional<BI> getOne(List<BI> items) {
if (items.size() > 1) {
throw new IllegalStateException("Only a single Bouncy Castle registration can be provided.");
}
Expand All @@ -425,7 +426,7 @@ private <BI extends MultiBuildItem> Optional<BI> getOne(List<BI> items) {
* @param providerName - JCA provider name
* @return class names that make up the provider and its services
*/
private List<String> registerProvider(String providerName,
private static List<String> registerProvider(String providerName,
String providerConfig,
BuildProducer<NativeImageSecurityProviderBuildItem> additionalProviders) {
List<String> providerClasses = new ArrayList<>();
Expand Down Expand Up @@ -496,7 +497,7 @@ void transformAdditionalSecuredClassesToMethods(List<AdditionalSecuredClassesBui
void transformSecurityAnnotations(BuildProducer<AnnotationsTransformerBuildItem> transformers,
List<AdditionalSecuredMethodsBuildItem> additionalSecuredMethods,
SecurityBuildTimeConfig config) {
if (config.denyUnannotated) {
if (config.denyUnannotated()) {
transformers.produce(new AnnotationsTransformerBuildItem(new DenyingUnannotatedTransformer()));
}
if (!additionalSecuredMethods.isEmpty()) {
Expand Down Expand Up @@ -543,7 +544,7 @@ void gatherSecurityChecks(BuildProducer<SyntheticBeanBuildItem> syntheticBeans,

IndexView index = beanArchiveBuildItem.getIndex();
Map<MethodInfo, SecurityCheck> securityChecks = gatherSecurityAnnotations(index, configExpSecurityCheckProducer,
additionalSecured.values(), config.denyUnannotated, recorder, configBuilderProducer,
additionalSecured.values(), config.denyUnannotated(), recorder, configBuilderProducer,
reflectiveClassBuildItemBuildProducer, rolesAllowedConfigExpResolverBuildItems);
for (AdditionalSecurityCheckBuildItem additionalSecurityCheck : additionalSecurityChecks) {
securityChecks.put(additionalSecurityCheck.getMethodInfo(),
Expand Down Expand Up @@ -596,7 +597,7 @@ public void resolveConfigExpressionRoles(Optional<ConfigExpRolesAllowedSecurityC
}
}

private Map<MethodInfo, SecurityCheck> gatherSecurityAnnotations(IndexView index,
private static Map<MethodInfo, SecurityCheck> gatherSecurityAnnotations(IndexView index,
BuildProducer<ConfigExpRolesAllowedSecurityCheckBuildItem> configExpSecurityCheckProducer,
Collection<AdditionalSecured> additionalSecuredMethods, boolean denyUnannotated, SecurityCheckRecorder recorder,
BuildProducer<RunTimeConfigBuilderBuildItem> configBuilderProducer,
Expand Down Expand Up @@ -775,7 +776,7 @@ private static Set<String> getSetForKey(String[] allowedRoles) {
return new HashSet<>(Arrays.asList(allowedRoles));
}

private boolean alreadyHasAnnotation(AnnotationInstance alreadyExistingInstance, DotName annotationName) {
private static boolean alreadyHasAnnotation(AnnotationInstance alreadyExistingInstance, DotName annotationName) {
return alreadyExistingInstance.target().kind() == AnnotationTarget.Kind.METHOD
&& alreadyExistingInstance.name().equals(annotationName);
}
Expand All @@ -785,7 +786,7 @@ static boolean isPublicNonStaticNonConstructor(MethodInfo methodInfo) {
&& !"<init>".equals(methodInfo.name());
}

private void gatherSecurityAnnotations(
private static void gatherSecurityAnnotations(
IndexView index, DotName dotName,
Map<MethodInfo, AnnotationInstance> alreadyCheckedMethods,
Map<ClassInfo, AnnotationInstance> classLevelAnnotations,
Expand Down Expand Up @@ -845,7 +846,7 @@ void registerAdditionalBeans(BuildProducer<AdditionalBeanBuildItem> beans) {
@BuildStep
AdditionalBeanBuildItem authorizationController(LaunchModeBuildItem launchMode) {
Class<? extends AuthorizationController> controllerClass = AuthorizationController.class;
if (launchMode.getLaunchMode() == LaunchMode.DEVELOPMENT && !security.authorizationEnabledInDevMode) {
if (launchMode.getLaunchMode() == LaunchMode.DEVELOPMENT && !security.authorizationEnabledInDevMode()) {
controllerClass = DevModeDisabledAuthorizationController.class;
}
return AdditionalBeanBuildItem.builder().addBeanClass(controllerClass).build();
Expand Down Expand Up @@ -915,7 +916,7 @@ static class AdditionalSecured {
}
}

class SecurityCheckStorageAppPredicate implements Predicate<String> {
static class SecurityCheckStorageAppPredicate implements Predicate<String> {

@Override
public boolean test(String s) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package io.quarkus.security.runtime;

import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigPhase;
import io.quarkus.runtime.annotations.ConfigRoot;
import io.smallrye.config.ConfigMapping;
import io.smallrye.config.WithDefault;
import io.smallrye.config.WithName;

/**
* @author Michal Szynkiewicz, michal.l.szynkiewicz@gmail.com
*/
@ConfigRoot(name = "security", phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED)
public class SecurityBuildTimeConfig {
@ConfigMapping(prefix = "quarkus.security")
@ConfigRoot(phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED)
public interface SecurityBuildTimeConfig {
/**
* If set to true, access to all methods of beans that have any security annotations on other members will be denied by
* default.
Expand All @@ -27,7 +30,8 @@ public class SecurityBuildTimeConfig {
* }
* </pre>
*/
@ConfigItem(name = "deny-unannotated-members")
public boolean denyUnannotated;
@WithName("deny-unannotated-members")
@WithDefault("false")
boolean denyUnannotated();

}
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,14 @@ public boolean requiresMethodArguments() {
}

private static void throwException(SecurityIdentity identity) {
throw getException(identity);
}

private static RuntimeException getException(SecurityIdentity identity) {
if (identity.isAnonymous()) {
throw new UnauthorizedException();
return new UnauthorizedException();
} else {
throw new ForbiddenException();
return new ForbiddenException();
}
}

Expand Down Expand Up @@ -103,7 +107,7 @@ protected Uni<?> checkPermissions(SecurityIdentity identity, Permission permissi
public Uni<?> apply(Boolean hasPermission) {
if (FALSE.equals(hasPermission)) {
// check failed
throwException(identity);
return Uni.createFrom().failure(getException(identity));
}

return SUCCESSFUL_CHECK;
Expand Down Expand Up @@ -214,7 +218,7 @@ public Uni<?> apply(Boolean hasPermission) {
final boolean hasAnotherPermission = i + 1 < permissions.length;
if (!hasAnotherPermission) {
// check failed
throwException(identity);
return Uni.createFrom().failure(getException(identity));
}

// check next permission
Expand Down

0 comments on commit 814958b

Please sign in to comment.