mirror of
https://github.com/jlengrand/helidon.git
synced 2026-03-10 08:21:17 +00:00
Support for overriding configuration of security providers using simple properties. (#2511)
Signed-off-by: Tomas Langer <tomas.langer@oracle.com>
This commit is contained in:
@@ -138,6 +138,21 @@ security:
|
|||||||
roles: ["user"]
|
roles: ["user"]
|
||||||
----
|
----
|
||||||
|
|
||||||
|
==== Overriding configuration
|
||||||
|
When a configuration needs to be overridden, we may have problems with the list
|
||||||
|
type of the `providers` configuration. To simplify overrides using properties,
|
||||||
|
you can explicitly setup a type of provider using a `type` key.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
[source,properties]
|
||||||
|
----
|
||||||
|
security.providers.1.type=header-atn
|
||||||
|
security.providers.1.header-atn.authenticate=false
|
||||||
|
----
|
||||||
|
|
||||||
|
Would explicitly override the second provider (`http-basic-auth` in example above) with
|
||||||
|
`header-atn` provider. Note that the `type` and the key of the provider must match.
|
||||||
|
|
||||||
=== Hybrid pattern (Builder & Configuration)
|
=== Hybrid pattern (Builder & Configuration)
|
||||||
|
|
||||||
[source,java]
|
[source,java]
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ import java.util.stream.Collectors;
|
|||||||
import io.helidon.common.configurable.ThreadPoolSupplier;
|
import io.helidon.common.configurable.ThreadPoolSupplier;
|
||||||
import io.helidon.common.serviceloader.HelidonServiceLoader;
|
import io.helidon.common.serviceloader.HelidonServiceLoader;
|
||||||
import io.helidon.config.Config;
|
import io.helidon.config.Config;
|
||||||
|
import io.helidon.config.ConfigValue;
|
||||||
import io.helidon.security.internal.SecurityAuditEvent;
|
import io.helidon.security.internal.SecurityAuditEvent;
|
||||||
import io.helidon.security.spi.AuditProvider;
|
import io.helidon.security.spi.AuditProvider;
|
||||||
import io.helidon.security.spi.AuthenticationProvider;
|
import io.helidon.security.spi.AuthenticationProvider;
|
||||||
@@ -80,6 +81,7 @@ public class Security {
|
|||||||
|
|
||||||
private static final Set<String> RESERVED_PROVIDER_KEYS = Set.of(
|
private static final Set<String> RESERVED_PROVIDER_KEYS = Set.of(
|
||||||
"name",
|
"name",
|
||||||
|
"type",
|
||||||
"class",
|
"class",
|
||||||
"is-authentication-provider",
|
"is-authentication-provider",
|
||||||
"is-authorization-provider",
|
"is-authorization-provider",
|
||||||
@@ -951,7 +953,9 @@ public class Security {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void providerFromConfig(Map<String, SecurityProviderService> configKeyToService,
|
private void providerFromConfig(Map<String, SecurityProviderService> configKeyToService,
|
||||||
Map<String, SecurityProviderService> classNameToService, String knownKeys, Config pConf) {
|
Map<String, SecurityProviderService> classNameToService,
|
||||||
|
String knownKeys,
|
||||||
|
Config pConf) {
|
||||||
AtomicReference<SecurityProviderService> service = new AtomicReference<>();
|
AtomicReference<SecurityProviderService> service = new AtomicReference<>();
|
||||||
AtomicReference<Config> providerSpecific = new AtomicReference<>();
|
AtomicReference<Config> providerSpecific = new AtomicReference<>();
|
||||||
|
|
||||||
@@ -1053,24 +1057,38 @@ public class Security {
|
|||||||
Config pConf,
|
Config pConf,
|
||||||
AtomicReference<SecurityProviderService> service,
|
AtomicReference<SecurityProviderService> service,
|
||||||
AtomicReference<Config> providerSpecific) {
|
AtomicReference<Config> providerSpecific) {
|
||||||
// everything else is based on provider specific configuration
|
|
||||||
pConf.asNodeList().get().stream().filter(this::notReservedProviderKey).forEach(providerSpecificConf -> {
|
|
||||||
if (!providerSpecific.compareAndSet(null, providerSpecificConf)) {
|
|
||||||
throw new SecurityException("More than one provider configurations found, each provider can only"
|
|
||||||
+ " have one provider specific config. Conflict: "
|
|
||||||
+ providerSpecific.get().key()
|
|
||||||
+ " and " + providerSpecificConf.key());
|
|
||||||
}
|
|
||||||
|
|
||||||
String keyName = providerSpecificConf.name();
|
ConfigValue<String> type = pConf.get("type").asString();
|
||||||
if (configKeyToService.containsKey(keyName)) {
|
if (type.isPresent()) {
|
||||||
service.set(configKeyToService.get(keyName));
|
// explicit type, ignore search below
|
||||||
} else {
|
findProviderService(service, configKeyToService, type.get(), knownKeys);
|
||||||
throw new SecurityException("Configuration key " + providerSpecificConf.key()
|
providerSpecific.set(pConf.get(type.get()));
|
||||||
+ " is not a valid provider configuration. Supported keys: "
|
} else {
|
||||||
+ knownKeys);
|
// everything else is based on provider specific configuration
|
||||||
}
|
pConf.asNodeList().get().stream().filter(this::notReservedProviderKey).forEach(providerSpecificConf -> {
|
||||||
});
|
if (!providerSpecific.compareAndSet(null, providerSpecificConf)) {
|
||||||
|
throw new SecurityException("More than one provider configurations found, each provider can only"
|
||||||
|
+ " have one provider specific config. Conflict: "
|
||||||
|
+ providerSpecific.get().key()
|
||||||
|
+ " and " + providerSpecificConf.key());
|
||||||
|
}
|
||||||
|
|
||||||
|
findProviderService(service, configKeyToService, providerSpecificConf.name(), knownKeys);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void findProviderService(AtomicReference<SecurityProviderService> service,
|
||||||
|
Map<String, SecurityProviderService> configKeyToService,
|
||||||
|
String name,
|
||||||
|
String knownKeys) {
|
||||||
|
if (configKeyToService.containsKey(name)) {
|
||||||
|
service.set(configKeyToService.get(name));
|
||||||
|
} else {
|
||||||
|
throw new SecurityException("Configuration key " + name
|
||||||
|
+ " is not a valid provider configuration. Supported keys: "
|
||||||
|
+ knownKeys);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String loadProviderServices(Map<String, SecurityProviderService> configKeyToService,
|
private String loadProviderServices(Map<String, SecurityProviderService> configKeyToService,
|
||||||
|
|||||||
67
tests/integration/security/gh2455/pom.xml
Normal file
67
tests/integration/security/gh2455/pom.xml
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright (c) 2020 Oracle and/or its affiliates.
|
||||||
|
~
|
||||||
|
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
~ you may not use this file except in compliance with the License.
|
||||||
|
~ You may obtain a copy of the License at
|
||||||
|
~
|
||||||
|
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
~
|
||||||
|
~ Unless required by applicable law or agreed to in writing, software
|
||||||
|
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
~ See the License for the specific language governing permissions and
|
||||||
|
~ limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>helidon-tests-integration-security</artifactId>
|
||||||
|
<groupId>io.helidon.tests.integration</groupId>
|
||||||
|
<version>2.1.1-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>helidon-tests-integration-security-gh2455</artifactId>
|
||||||
|
<name>Helidon Tests Integration Security GH-2455</name>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
Integration test for issue https://github.com/oracle/helidon/issues/2455
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.helidon.security</groupId>
|
||||||
|
<artifactId>helidon-security</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.helidon.security.providers</groupId>
|
||||||
|
<artifactId>helidon-security-providers-http-auth</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.helidon.security.providers</groupId>
|
||||||
|
<artifactId>helidon-security-providers-header</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.helidon.security.providers</groupId>
|
||||||
|
<artifactId>helidon-security-providers-abac</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.helidon.config</groupId>
|
||||||
|
<artifactId>helidon-config-yaml</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hamcrest</groupId>
|
||||||
|
<artifactId>hamcrest-all</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2020 Oracle and/or its affiliates.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
security:
|
||||||
|
providers:
|
||||||
|
- abac:
|
||||||
|
- http-basic-auth:
|
||||||
|
realm: "helidon"
|
||||||
|
users:
|
||||||
|
- login: "tomas"
|
||||||
|
password: "password"
|
||||||
|
roles: ["admin"]
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020 Oracle and/or its affiliates.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.helidon.tests.integration.security.gh2455;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import io.helidon.config.Config;
|
||||||
|
import io.helidon.config.ConfigSources;
|
||||||
|
import io.helidon.security.Security;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
class TestProviderOverrides {
|
||||||
|
@Test
|
||||||
|
void testOverride() {
|
||||||
|
Map<String, String> map = Map.of(
|
||||||
|
"security.providers.1.type", "header-atn",
|
||||||
|
"security.providers.1.header-atn.authenticate", "false"
|
||||||
|
);
|
||||||
|
Config config = Config.builder()
|
||||||
|
.addSource(ConfigSources.create(map))
|
||||||
|
.addSource(ConfigSources.classpath("application.yaml"))
|
||||||
|
.disableEnvironmentVariablesSource()
|
||||||
|
.disableSystemPropertiesSource()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Security security = Security.create(config.get("security"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -37,5 +37,6 @@
|
|||||||
<modules>
|
<modules>
|
||||||
<module>gh1487</module>
|
<module>gh1487</module>
|
||||||
<module>gh2297</module>
|
<module>gh2297</module>
|
||||||
|
<module>gh2455</module>
|
||||||
</modules>
|
</modules>
|
||||||
</project>
|
</project>
|
||||||
Reference in New Issue
Block a user