Skip to content

Commit

Permalink
Merge pull request #26967 from radcortez/fix-25591
Browse files Browse the repository at this point in the history
Use ConfigMapping to map duplicated properties and avoid unknown config warning
  • Loading branch information
gsmet authored Aug 3, 2022

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
2 parents 640bf13 + fcc37aa commit c9a996d
Showing 8 changed files with 81 additions and 52 deletions.
Original file line number Diff line number Diff line change
@@ -60,6 +60,9 @@ final public class Constants {
public static final String ANNOTATION_CONFIG_DOC_MAP_KEY = "io.quarkus.runtime.annotations.ConfigDocMapKey";
public static final String ANNOTATION_CONFIG_DOC_SECTION = "io.quarkus.runtime.annotations.ConfigDocSection";

public static final String ANNOTATION_CONFIG_WITH_NAME = "io.smallrye.config.WithName";
public static final String ANNOTATION_CONFIG_WITH_DEFAULT = "io.smallrye.config.WithDefault";

public static final Set<String> SUPPORTED_ANNOTATIONS_TYPES = Set.of(ANNOTATION_BUILD_STEP, ANNOTATION_CONFIG_GROUP,
ANNOTATION_CONFIG_ROOT, ANNOTATION_TEMPLATE, ANNOTATION_RECORDER);

Original file line number Diff line number Diff line change
@@ -3,6 +3,8 @@
import static io.quarkus.annotation.processor.Constants.ANNOTATION_CONFIG_DOC_MAP_KEY;
import static io.quarkus.annotation.processor.Constants.ANNOTATION_CONFIG_DOC_SECTION;
import static io.quarkus.annotation.processor.Constants.ANNOTATION_CONFIG_ITEM;
import static io.quarkus.annotation.processor.Constants.ANNOTATION_CONFIG_WITH_DEFAULT;
import static io.quarkus.annotation.processor.Constants.ANNOTATION_CONFIG_WITH_NAME;
import static io.quarkus.annotation.processor.Constants.ANNOTATION_CONVERT_WITH;
import static io.quarkus.annotation.processor.Constants.ANNOTATION_DEFAULT_CONVERTER;
import static io.quarkus.annotation.processor.Constants.DOT;
@@ -137,7 +139,7 @@ private List<ConfigDocItem> recursivelyFindConfigItems(Element element, String r
}

for (Element enclosedElement : element.getEnclosedElements()) {
if (!enclosedElement.getKind().isField() && (!enclosedElement.getKind().equals(ElementKind.METHOD) || !isMapping)) {
if (!enclosedElement.getKind().isField() && (!isMapping || !enclosedElement.getKind().equals(ElementKind.METHOD))) {
continue;
}

@@ -153,7 +155,7 @@ private List<ConfigDocItem> recursivelyFindConfigItems(Element element, String r
String name = null;
String defaultValue = NO_DEFAULT;
String defaultValueDoc = EMPTY;
final TypeMirror typeMirror = enclosedElement.asType();
final TypeMirror typeMirror = unwrapTypeMirror(enclosedElement.asType());
String type = typeMirror.toString();
List<String> acceptedValues = null;
final TypeElement clazz = (TypeElement) element;
@@ -217,6 +219,19 @@ private List<ConfigDocItem> recursivelyFindConfigItems(Element element, String r
|| annotationName.equals(ANNOTATION_CONVERT_WITH)) {
useHyphenateEnumValue = false;
}

// Mappings
if (isMapping) {
for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : annotationMirror
.getElementValues().entrySet()) {
Object value = entry.getValue().getValue();
if (annotationName.equals(ANNOTATION_CONFIG_WITH_NAME)) {
name = parentName + DOT + value;
} else if (annotationName.equals(ANNOTATION_CONFIG_WITH_DEFAULT)) {
defaultValue = value.toString();
}
}
}
}

if (isDeprecated) {
@@ -247,24 +262,8 @@ private List<ConfigDocItem> recursivelyFindConfigItems(Element element, String r
boolean list = false;
boolean optional = false;
if (!typeMirror.getKind().isPrimitive()) {
TypeElement typeElement;
DeclaredType declaredType;
if (typeMirror instanceof DeclaredType) {
declaredType = (DeclaredType) typeMirror;
typeElement = (TypeElement) declaredType.asElement();
} else if (typeMirror instanceof ExecutableType) {
ExecutableType executableType = (ExecutableType) typeMirror;
TypeMirror returnType = executableType.getReturnType();
if (returnType instanceof DeclaredType) {
declaredType = ((DeclaredType) returnType);
typeElement = (TypeElement) declaredType.asElement();
} else {
continue;
}
} else {
continue;
}

DeclaredType declaredType = (DeclaredType) typeMirror;
TypeElement typeElement = (TypeElement) declaredType.asElement();
Name qualifiedName = typeElement.getQualifiedName();
optional = qualifiedName.toString().startsWith(Optional.class.getName())
|| qualifiedName.contentEquals(Map.class.getName());
@@ -313,14 +312,7 @@ private List<ConfigDocItem> recursivelyFindConfigItems(Element element, String r
|| typeInString.startsWith(Set.class.getName())
|| realTypeMirror.getKind() == TypeKind.ARRAY)) {
list = true;
DeclaredType declaredRealType;
if (typeMirror instanceof DeclaredType) {
declaredRealType = (DeclaredType) typeMirror;
} else {
ExecutableType executableType = (ExecutableType) typeMirror;
TypeMirror returnType = executableType.getReturnType();
declaredRealType = ((DeclaredType) returnType);
}
DeclaredType declaredRealType = (DeclaredType) typeMirror;
typeArguments = declaredRealType.getTypeArguments();
if (!typeArguments.isEmpty()) {
realTypeMirror = typeArguments.get(0);
@@ -378,6 +370,19 @@ private List<ConfigDocItem> recursivelyFindConfigItems(Element element, String r
return configDocItems;
}

private TypeMirror unwrapTypeMirror(TypeMirror typeMirror) {
if (typeMirror instanceof DeclaredType) {
return typeMirror;
}

if (typeMirror instanceof ExecutableType) {
ExecutableType executableType = (ExecutableType) typeMirror;
return executableType.getReturnType();
}

return typeMirror;
}

private boolean isConfigGroup(String type) {
if (type.startsWith("java.") || PRIMITIVE_TYPES.contains(type)) {
return false;
Original file line number Diff line number Diff line change
@@ -88,6 +88,8 @@ public void addConfigRoot(final PackageElement pkg, TypeElement clazz) {

for (AnnotationMirror mirror : clazz.getAnnotationMirrors()) {
if (mirror.getAnnotationType().toString().equals(Constants.ANNOTATION_CONFIG_MAPPING)) {
isMapping = true;
name = Constants.EMPTY;
for (Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : mirror.getElementValues()
.entrySet()) {
if ("prefix()".equals(entry.getKey().toString())) {
@@ -145,17 +147,16 @@ public Set<ConfigDocGeneratedOutput> scanExtensionsConfigurationItems(Properties
* Loads the list of configuration items per configuration root
*
*/
private Properties loadAllExtensionConfigItemsParConfigRoot() throws IOException {
private Properties loadAllExtensionConfigItemsParConfigRoot() {
return allExtensionGeneratedDocs.asProperties();
}

/**
* Update extensions config roots. We need to gather the complete list of configuration roots of an extension
* when generating the documentation.
*
* @throws IOException
*/
private void updateConfigurationRootsList(Map.Entry<ConfigRootInfo, List<ConfigDocItem>> entry) throws IOException {
private void updateConfigurationRootsList(Map.Entry<ConfigRootInfo, List<ConfigDocItem>> entry) {
String extensionFileName = entry.getKey().getFileName();
String clazz = entry.getKey().getClazz().getQualifiedName().toString();
configurationRootsParExtensionFileName.put(extensionFileName, clazz);
Original file line number Diff line number Diff line change
@@ -110,6 +110,8 @@ public static SmallRyeConfigBuilder configBuilder(final boolean runTime, final b
}
if (runTime || bootstrap) {
builder.addDefaultSources();
// Validator only for runtime. We cannot use the current validator for build time (chicken / egg problem)
builder.addDiscoveredValidator();
builder.withDefaultValue(UUID_KEY, UUID.randomUUID().toString());
builder.withSources(new DotEnvConfigSourceProvider());
builder.withSources(
@@ -179,7 +181,6 @@ public OptionalInt getPriority() {
builder.addDefaultInterceptors();
builder.addDiscoveredInterceptors();
builder.addDiscoveredConverters();
builder.addDiscoveredValidator();
return builder;
}

Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
#io.smallrye.config.validator.BeanValidationConfigValidatorImpl
io.quarkus.hibernate.validator.runtime.HibernateBeanValidationConfigValidator
Original file line number Diff line number Diff line change
@@ -24,7 +24,6 @@ public class JaxRsSecurityConfig {
*
* The role of '**' means any authenticated user, which is equivalent to the {@link io.quarkus.security.Authenticated}
* annotation.
*
*/
@ConfigItem
public Optional<List<String>> defaultRolesAllowed;
Original file line number Diff line number Diff line change
@@ -15,8 +15,6 @@
import javax.ws.rs.Priorities;
import javax.ws.rs.ext.RuntimeDelegate;

import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigProvider;
import org.jboss.jandex.AnnotationTarget;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.CompositeIndex;
@@ -45,6 +43,7 @@
import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem;
import io.quarkus.resteasy.reactive.common.runtime.JaxRsSecurityConfig;
import io.quarkus.resteasy.reactive.common.runtime.ResteasyReactiveConfig;
import io.quarkus.resteasy.reactive.spi.AbstractInterceptorBuildItem;
import io.quarkus.resteasy.reactive.spi.AdditionalResourceClassBuildItem;
@@ -66,22 +65,15 @@ public class ResteasyReactiveCommonProcessor {
private static final int LEGACY_WRITER_PRIORITY = Priorities.USER / 2; // writers are compared by increased priority

@BuildStep
void setUpDenyAllJaxRs(CombinedIndexBuildItem index,
void setUpDenyAllJaxRs(
CombinedIndexBuildItem index,
ResteasyReactiveConfig rrConfig,
JaxRsSecurityConfig securityConfig,
Optional<ResourceScanningResultBuildItem> resteasyDeployment,
BuildProducer<AdditionalSecuredClassesBuildItem> additionalSecuredClasses) {

Config config = ConfigProvider.getConfig();

// we do this in order to avoid having 'io.quarkus.resteasy.reactive.common.runtime.JaxRsSecurityConfig' conflict with 'io.quarkus.resteasy.runtime.JaxRsSecurityConfig'
Optional<Boolean> denyUnannotatedEndpointsConfig = config
.getOptionalValue("quarkus.security.jaxrs.deny-unannotated-endpoints", Boolean.class);
Optional<List<String>> defaultRolesAllowedConfig = config
.getOptionalValues("quarkus.security.jaxrs.default-roles-allowed", String.class);

if (denyUnannotatedEndpointsConfig.orElse(false) && resteasyDeployment.isPresent()) {
final List<ClassInfo> classes = new ArrayList<>();

if (securityConfig.denyJaxRs() && resteasyDeployment.isPresent()) {
List<ClassInfo> classes = new ArrayList<>();
Set<DotName> resourceClasses = resteasyDeployment.get().getResult().getScannedResourcePaths().keySet();
for (DotName className : resourceClasses) {
ClassInfo classInfo = index.getIndex().getClassByName(className);
@@ -91,9 +83,8 @@ void setUpDenyAllJaxRs(CombinedIndexBuildItem index,
}

additionalSecuredClasses.produce(new AdditionalSecuredClassesBuildItem(classes));
} else if (defaultRolesAllowedConfig.isPresent() && resteasyDeployment.isPresent()) {

final List<ClassInfo> classes = new ArrayList<>();
} else if (securityConfig.defaultRolesAllowed().isPresent() && resteasyDeployment.isPresent()) {
List<ClassInfo> classes = new ArrayList<>();
Set<DotName> resourceClasses = resteasyDeployment.get().getResult().getScannedResourcePaths().keySet();
for (DotName className : resourceClasses) {
ClassInfo classInfo = index.getIndex().getClassByName(className);
@@ -102,7 +93,7 @@ void setUpDenyAllJaxRs(CombinedIndexBuildItem index,
}
}
additionalSecuredClasses
.produce(new AdditionalSecuredClassesBuildItem(classes, defaultRolesAllowedConfig));
.produce(new AdditionalSecuredClassesBuildItem(classes, securityConfig.defaultRolesAllowed()));
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package io.quarkus.resteasy.reactive.common.runtime;

import java.util.List;
import java.util.Optional;

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_AND_RUN_TIME_FIXED)
@ConfigMapping(prefix = "quarkus.security.jaxrs")
public interface JaxRsSecurityConfig {
/**
* if set to true, access to all JAX-RS resources will be denied by default
*/
@WithName("deny-unannotated-endpoints")
@WithDefault("false")
boolean denyJaxRs();

/**
* If no security annotations are affecting a method then they will default to requiring these roles,
* (equivalent to adding an @RolesAllowed annotation with the roles to every endpoint class).
*
* The role of '**' means any authenticated user, which is equivalent to the {@link io.quarkus.security.Authenticated}
* annotation.
*/
Optional<List<String>> defaultRolesAllowed();
}

0 comments on commit c9a996d

Please sign in to comment.