Skip to content

Commit 99eeccd

Browse files
authored
OIDC config Refactoring (helidon-io#3277)
* OIDC support for client secret post authentication method (+ refactoring to WebClient) * Fix web client services - not impacted by new changes to builder * The correct authentication type is Basic, not basic. * IDCS role mapper based on reactive code * Fix bearer test, first letter should be capitalized Signed-off-by: Tomas Langer <tomas.langer@oracle.com>
1 parent d698877 commit 99eeccd

28 files changed

Lines changed: 2189 additions & 221 deletions

File tree

config/yaml/pom.xml

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,6 @@
5050
<groupId>jakarta.annotation</groupId>
5151
<artifactId>jakarta.annotation-api</artifactId>
5252
</dependency>
53-
<dependency>
54-
<groupId>org.eclipse.microprofile.config</groupId>
55-
<artifactId>microprofile-config-api</artifactId>
56-
<!-- this does not work correctly with JPMS and usage of service loader -->
57-
<!-- <scope>provided</scope>-->
58-
<!-- <optional>true</optional>-->
59-
</dependency>
6053
<dependency>
6154
<groupId>io.helidon.config</groupId>
6255
<artifactId>helidon-config-testing</artifactId>

docs/mp/guides/05_security-oidc.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ security:
246246
- abac:
247247
# Adds ABAC Provider - it does not require any configuration
248248
- oidc:
249-
redirect-uri: "/oidc/redirect/*"
249+
redirect-uri: "/oidc/redirect"
250250
audience: "account"
251251
client-id: "myClientID" // <1>
252252
client-secret: "Client secret generated into Keycloak client credential" // <2>

examples/security/idcs-login/pom.xml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,13 @@
8282
<artifactId>helidon-security-integration-webserver</artifactId>
8383
</dependency>
8484
<dependency>
85-
<!-- Config API + yaml support -->
86-
<groupId>io.helidon.bundles</groupId>
87-
<artifactId>helidon-bundles-config</artifactId>
85+
<!-- Encryption of secrets -->
86+
<groupId>io.helidon.config</groupId>
87+
<artifactId>helidon-config-encryption</artifactId>
8888
</dependency>
8989
<dependency>
90-
<!-- Encryption of secrets + reference support in Config -->
9190
<groupId>io.helidon.config</groupId>
92-
<artifactId>helidon-config-encryption</artifactId>
91+
<artifactId>helidon-config-yaml</artifactId>
9392
</dependency>
9493
<dependency>
9594
<groupId>org.jboss</groupId>

examples/security/idcs-login/src/main/resources/logging.properties

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
#
1616

1717
handlers=io.helidon.common.HelidonConsoleHandler
18+
19+
# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread
20+
java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n
21+
1822
.level=INFO
1923
AUDIT.level=FINEST
2024
io.helidon.security.providers.oidc.level=FINEST

security/integration/webserver/src/main/java/io/helidon/security/integration/webserver/SecurityHandler.java

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2020 Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2021 Oracle and/or its affiliates.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -34,6 +34,7 @@
3434
import java.util.logging.Logger;
3535

3636
import io.helidon.common.http.Http;
37+
import io.helidon.common.http.HttpRequest;
3738
import io.helidon.config.Config;
3839
import io.helidon.security.AuditEvent;
3940
import io.helidon.security.AuthenticationResponse;
@@ -46,6 +47,7 @@
4647
import io.helidon.security.SecurityRequest;
4748
import io.helidon.security.SecurityRequestBuilder;
4849
import io.helidon.security.SecurityResponse;
50+
import io.helidon.security.Subject;
4951
import io.helidon.security.integration.common.AtnTracing;
5052
import io.helidon.security.integration.common.AtzTracing;
5153
import io.helidon.security.integration.common.SecurityTracing;
@@ -577,16 +579,21 @@ private CompletionStage<AtxResult> processAuthorization(ServerRequest req,
577579
Set<String> rolesSet = rolesAllowed.orElse(Set.of());
578580

579581
if (!rolesSet.isEmpty()) {
582+
/*
583+
As this part bypasses authorization providers, audit logging is not done, we need to explicitly audit this!
584+
*/
580585
// first validate roles - RBAC is supported out of the box by security, no need to invoke provider
581586
if (explicitAuthorizer.isPresent()) {
582587
if (rolesSet.stream().noneMatch(role -> context.isUserInRole(role, explicitAuthorizer.get()))) {
588+
auditRoleMissing(context, req.path(), context.user(), rolesSet);
583589
abortRequest(res, null, Http.Status.FORBIDDEN_403.code(), Map.of());
584590
future.complete(AtxResult.STOP);
585591
atzTracing.finish();
586592
return future;
587593
}
588594
} else {
589595
if (rolesSet.stream().noneMatch(context::isUserInRole)) {
596+
auditRoleMissing(context, req.path(), context.user(), rolesSet);
590597
abortRequest(res, null, Http.Status.FORBIDDEN_403.code(), Map.of());
591598
future.complete(AtxResult.STOP);
592599
atzTracing.finish();
@@ -643,6 +650,18 @@ private CompletionStage<AtxResult> processAuthorization(ServerRequest req,
643650
return future;
644651
}
645652

653+
private void auditRoleMissing(SecurityContext context,
654+
HttpRequest.Path path,
655+
Optional<Subject> user,
656+
Set<String> rolesSet) {
657+
658+
context.audit(SecurityAuditEvent.failure(AuditEvent.AUTHZ_TYPE_PREFIX + ".authorize",
659+
"User is not in any of the required roles: %s. Path %s. Subject %s")
660+
.addParam(AuditEvent.AuditParam.plain("roles", rolesSet))
661+
.addParam(AuditEvent.AuditParam.plain("path", path))
662+
.addParam(AuditEvent.AuditParam.plain("subject", user)));
663+
}
664+
646665
/**
647666
* List of query parameter handlers.
648667
*
@@ -839,6 +858,7 @@ private AtxResult(SecurityRequest ignored) {
839858
// WARNING: builder methods must not have side-effects, as they are used to build instance from configuration
840859
// if you want side effects, use methods on SecurityHandler
841860
private static final class Builder implements io.helidon.common.Builder<SecurityHandler> {
861+
private final List<QueryParamHandler> queryParamHandlers = new LinkedList<>();
842862
private Optional<Set<String>> rolesAllowed = Optional.empty();
843863
private Optional<ClassToInstanceStore<Object>> customObjects = Optional.empty();
844864
private Optional<Config> config = Optional.empty();
@@ -850,7 +870,6 @@ private static final class Builder implements io.helidon.common.Builder<Security
850870
private Optional<Boolean> audited = Optional.empty();
851871
private Optional<String> auditEventType = Optional.empty();
852872
private Optional<String> auditMessageFormat = Optional.empty();
853-
private final List<QueryParamHandler> queryParamHandlers = new LinkedList<>();
854873
private boolean combined;
855874

856875
private Builder() {
@@ -1030,10 +1049,10 @@ Builder audit(boolean audited) {
10301049

10311050
Builder rolesAllowed(Collection<String> roles) {
10321051
rolesAllowed.ifPresentOrElse(strings -> strings.addAll(roles),
1033-
() -> {
1034-
Set<String> newRoles = new HashSet<>(roles);
1035-
rolesAllowed = Optional.of(newRoles);
1036-
});
1052+
() -> {
1053+
Set<String> newRoles = new HashSet<>(roles);
1054+
rolesAllowed = Optional.of(newRoles);
1055+
});
10371056
return this;
10381057
}
10391058
}

security/providers/http-auth/src/main/java/io/helidon/security/providers/httpauth/HttpBasicOutboundConfig.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020 Oracle and/or its affiliates.
2+
* Copyright (c) 2020, 2021 Oracle and/or its affiliates.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -36,7 +36,7 @@ public class HttpBasicOutboundConfig {
3636
*/
3737
public static final TokenHandler DEFAULT_TOKEN_HANDLER = TokenHandler.builder()
3838
.tokenHeader("Authorization")
39-
.tokenPrefix("basic ")
39+
.tokenPrefix("Basic ")
4040
.build();
4141

4242
private final TokenHandler tokenHandler;

security/providers/idcs-mapper/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
</dependency>
7777
<dependency>
7878
<groupId>org.hamcrest</groupId>
79-
<artifactId>hamcrest-core</artifactId>
79+
<artifactId>hamcrest-all</artifactId>
8080
<scope>test</scope>
8181
</dependency>
8282
</dependencies>

security/providers/idcs-mapper/src/main/java/io/helidon/security/providers/idcs/mapper/IdcsMtRoleMapperProvider.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2020 Oracle and/or its affiliates.
2+
* Copyright (c) 2019, 2021 Oracle and/or its affiliates.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -49,7 +49,10 @@
4949
/**
5050
* {@link io.helidon.security.spi.SubjectMappingProvider} to obtain roles from IDCS server for a user.
5151
* Supports multi tenancy in IDCS.
52+
*
53+
* @deprecated use {@link io.helidon.security.providers.idcs.mapper.IdcsMtRoleMapperRxProvider} instead
5254
*/
55+
@Deprecated(forRemoval = true, since = "2.4.0")
5356
public class IdcsMtRoleMapperProvider extends IdcsRoleMapperProviderBase {
5457
/**
5558
* Name of the header containing the IDCS tenant. This is the default used, can be overriden

0 commit comments

Comments
 (0)