Search in sources :

Example 16 with Subject

use of io.helidon.security.Subject in project helidon by oracle.

the class IdcsMtRoleMapperRxProvider method getGrantsFromServer.

/**
 * Get grants from IDCS server. The result is cached.
 *
 * @param idcsTenantId ID of the IDCS tenant
 * @param idcsAppName  Name of IDCS application
 * @param subject      subject to get grants for
 * @return optional list of grants from server
 */
protected Single<List<? extends Grant>> getGrantsFromServer(String idcsTenantId, String idcsAppName, Subject subject) {
    String subjectName = subject.principal().getName();
    String subjectType = (String) subject.principal().abacAttribute("sub_type").orElse(defaultIdcsSubjectType());
    RoleMapTracing tracing = SecurityTracing.get().roleMapTracing("idcs");
    return Single.create(getAppToken(idcsTenantId, tracing)).flatMapSingle(maybeAppToken -> {
        if (maybeAppToken.isEmpty()) {
            return Single.error(new SecurityException("Application token not available"));
        }
        return Single.just(maybeAppToken.get());
    }).flatMapSingle(appToken -> {
        JsonObjectBuilder requestBuilder = JSON.createObjectBuilder().add("mappingAttributeValue", subjectName).add("subjectType", subjectType).add("appName", idcsAppName).add("includeMemberships", true);
        JsonArrayBuilder arrayBuilder = JSON.createArrayBuilder();
        arrayBuilder.add("urn:ietf:params:scim:schemas:oracle:idcs:Asserter");
        requestBuilder.add("schemas", arrayBuilder);
        Context parentContext = Contexts.context().orElseGet(Contexts::globalContext);
        Context childContext = Context.builder().parent(parentContext).build();
        tracing.findParent().ifPresent(childContext::register);
        WebClientRequestBuilder post = oidcConfig().generalWebClient().post().context(childContext).uri(multitenantEndpoints.assertEndpoint(idcsTenantId)).headers(it -> {
            it.add(Http.Header.AUTHORIZATION, "Bearer " + appToken);
            return it;
        });
        return processRoleRequest(post, requestBuilder.build(), subjectName);
    });
}
Also used : ProviderRequest(io.helidon.security.ProviderRequest) WebClient(io.helidon.webclient.WebClient) Context(io.helidon.common.context.Context) JsonBuilderFactory(jakarta.json.JsonBuilderFactory) SecurityException(io.helidon.security.SecurityException) OidcConfig(io.helidon.security.providers.oidc.common.OidcConfig) EvictableCache(io.helidon.security.providers.common.EvictableCache) Single(io.helidon.common.reactive.Single) Grant(io.helidon.security.Grant) Subject(io.helidon.security.Subject) URI(java.net.URI) LinkedList(java.util.LinkedList) Http(io.helidon.common.http.Http) SecurityTracing(io.helidon.security.integration.common.SecurityTracing) Config(io.helidon.config.Config) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) SecurityProvider(io.helidon.security.spi.SecurityProvider) JsonArrayBuilder(jakarta.json.JsonArrayBuilder) TokenHandler(io.helidon.security.util.TokenHandler) Logger(java.util.logging.Logger) AuthenticationResponse(io.helidon.security.AuthenticationResponse) Contexts(io.helidon.common.context.Contexts) Json(jakarta.json.Json) Objects(java.util.Objects) JsonObjectBuilder(jakarta.json.JsonObjectBuilder) List(java.util.List) Optional(java.util.Optional) RoleMapTracing(io.helidon.security.integration.common.RoleMapTracing) Collections(java.util.Collections) WebClientRequestBuilder(io.helidon.webclient.WebClientRequestBuilder) Context(io.helidon.common.context.Context) RoleMapTracing(io.helidon.security.integration.common.RoleMapTracing) SecurityException(io.helidon.security.SecurityException) JsonArrayBuilder(jakarta.json.JsonArrayBuilder) JsonObjectBuilder(jakarta.json.JsonObjectBuilder) Contexts(io.helidon.common.context.Contexts) WebClientRequestBuilder(io.helidon.webclient.WebClientRequestBuilder)

Example 17 with Subject

use of io.helidon.security.Subject in project helidon by oracle.

the class JwtProviderTest method testEcBothWays.

@Test
public void testEcBothWays() {
    String username = "user1";
    String userId = "user1-id";
    String email = "user1@example.org";
    String familyName = "Novak";
    String givenName = "Standa";
    String fullName = "Standa Novak";
    Locale locale = Locale.CANADA_FRENCH;
    Principal principal = Principal.builder().name(username).id(userId).addAttribute("email", email).addAttribute("email_verified", true).addAttribute("family_name", familyName).addAttribute("given_name", givenName).addAttribute("full_name", fullName).addAttribute("locale", locale).build();
    Subject subject = Subject.create(principal);
    JwtProvider provider = JwtProvider.create(providersConfig.get("jwt"));
    SecurityContext context = Mockito.mock(SecurityContext.class);
    when(context.user()).thenReturn(Optional.of(subject));
    ProviderRequest request = mock(ProviderRequest.class);
    when(request.securityContext()).thenReturn(context);
    SecurityEnvironment outboundEnv = SecurityEnvironment.builder().path("/ec").transport("http").targetUri(URI.create("http://localhost:8080/ec")).build();
    EndpointConfig outboundEp = EndpointConfig.create();
    assertThat(provider.isOutboundSupported(request, outboundEnv, outboundEp), is(true));
    OutboundSecurityResponse response = provider.syncOutbound(request, outboundEnv, outboundEp);
    String signedToken = response.requestHeaders().get("Authorization").get(0);
    signedToken = signedToken.substring("bearer ".length());
    // now I want to validate it to prove it was correctly signed
    SignedJwt signedJwt = SignedJwt.parseToken(signedToken);
    signedJwt.verifySignature(verifyKeys).checkValid();
    Jwt jwt = signedJwt.getJwt();
    assertThat(jwt.subject(), is(Optional.of(userId)));
    assertThat(jwt.preferredUsername(), is(Optional.of(username)));
    assertThat(jwt.email(), is(Optional.of(email)));
    assertThat(jwt.emailVerified(), is(Optional.of(true)));
    assertThat(jwt.familyName(), is(Optional.of(familyName)));
    assertThat(jwt.givenName(), is(Optional.of(givenName)));
    assertThat(jwt.fullName(), is(Optional.of(fullName)));
    assertThat(jwt.locale(), is(Optional.of(locale)));
    assertThat(jwt.audience(), is(Optional.of(List.of("audience.application.id"))));
    assertThat(jwt.issuer(), is(Optional.of("jwt.example.com")));
    assertThat(jwt.algorithm(), is(Optional.of(JwkEC.ALG_ES256)));
    Instant instant = jwt.issueTime().get();
    boolean compareResult = Instant.now().minusSeconds(10).compareTo(instant) < 0;
    assertThat("Issue time must not be older than 10 seconds", compareResult, is(true));
    Instant expectedNotBefore = instant.minus(5, ChronoUnit.SECONDS);
    assertThat(jwt.notBefore(), is(Optional.of(expectedNotBefore)));
    Instant expectedExpiry = instant.plus(60 * 60 * 24, ChronoUnit.SECONDS);
    assertThat(jwt.expirationTime(), is(Optional.of(expectedExpiry)));
    // now we need to use the same token to invoke authentication
    ProviderRequest atnRequest = mock(ProviderRequest.class);
    SecurityEnvironment se = SecurityEnvironment.builder().header("Authorization", "bearer " + signedToken).build();
    when(atnRequest.env()).thenReturn(se);
    AuthenticationResponse authenticationResponse = provider.syncAuthenticate(atnRequest);
    authenticationResponse.user().map(Subject::principal).ifPresentOrElse(atnPrincipal -> {
        assertThat(atnPrincipal.id(), is(userId));
        assertThat(atnPrincipal.getName(), is(username));
        assertThat(atnPrincipal.abacAttribute("email"), is(Optional.of(email)));
        assertThat(atnPrincipal.abacAttribute("email_verified"), is(Optional.of(true)));
        assertThat(atnPrincipal.abacAttribute("family_name"), is(Optional.of(familyName)));
        assertThat(atnPrincipal.abacAttribute("given_name"), is(Optional.of(givenName)));
        assertThat(atnPrincipal.abacAttribute("full_name"), is(Optional.of(fullName)));
        assertThat(atnPrincipal.abacAttribute("locale"), is(Optional.of(locale)));
    }, () -> fail("User must be present in response"));
}
Also used : Locale(java.util.Locale) SecurityEnvironment(io.helidon.security.SecurityEnvironment) SignedJwt(io.helidon.security.jwt.SignedJwt) Jwt(io.helidon.security.jwt.Jwt) Instant(java.time.Instant) SignedJwt(io.helidon.security.jwt.SignedJwt) AuthenticationResponse(io.helidon.security.AuthenticationResponse) Subject(io.helidon.security.Subject) ProviderRequest(io.helidon.security.ProviderRequest) OutboundSecurityResponse(io.helidon.security.OutboundSecurityResponse) SecurityContext(io.helidon.security.SecurityContext) Principal(io.helidon.security.Principal) EndpointConfig(io.helidon.security.EndpointConfig) Test(org.junit.jupiter.api.Test)

Example 18 with Subject

use of io.helidon.security.Subject in project helidon by oracle.

the class OidcProvider method processValidationResult.

private AuthenticationResponse processValidationResult(ProviderRequest providerRequest, SignedJwt signedJwt, Errors.Collector collector) {
    Jwt jwt = signedJwt.getJwt();
    Errors errors = collector.collect();
    Errors validationErrors = jwt.validate(oidcConfig.issuer(), oidcConfig.audience());
    if (errors.isValid() && validationErrors.isValid()) {
        errors.log(LOGGER);
        Subject subject = buildSubject(jwt, signedJwt);
        Set<String> scopes = subject.grantsByType("scope").stream().map(Grant::getName).collect(Collectors.toSet());
        // make sure we have the correct scopes
        Set<String> expectedScopes = expectedScopes(providerRequest);
        List<String> missingScopes = new LinkedList<>();
        for (String expectedScope : expectedScopes) {
            if (!scopes.contains(expectedScope)) {
                missingScopes.add(expectedScope);
            }
        }
        if (missingScopes.isEmpty()) {
            return AuthenticationResponse.success(subject);
        } else {
            return errorResponse(providerRequest, Http.Status.FORBIDDEN_403, "insufficient_scope", "Scopes " + missingScopes + " are missing");
        }
    } else {
        if (LOGGER.isLoggable(Level.FINEST)) {
            // only log errors when details requested
            errors.log(LOGGER);
            validationErrors.log(LOGGER);
        }
        return errorResponse(providerRequest, Http.Status.UNAUTHORIZED_401, "invalid_token", "Token not valid");
    }
}
Also used : Errors(io.helidon.common.Errors) SignedJwt(io.helidon.security.jwt.SignedJwt) Jwt(io.helidon.security.jwt.Jwt) Subject(io.helidon.security.Subject) LinkedList(java.util.LinkedList)

Example 19 with Subject

use of io.helidon.security.Subject in project helidon by oracle.

the class OidcSupportTest method testOutboundFull.

@Test
void testOutboundFull() {
    String tokenContent = "huhahihohyhe";
    TokenCredential tokenCredential = TokenCredential.builder().token(tokenContent).build();
    Subject subject = Subject.builder().addPublicCredential(TokenCredential.class, tokenCredential).build();
    ProviderRequest providerRequest = Mockito.mock(ProviderRequest.class);
    SecurityContext ctx = Mockito.mock(SecurityContext.class);
    when(ctx.user()).thenReturn(Optional.of(subject));
    when(providerRequest.securityContext()).thenReturn(ctx);
    SecurityEnvironment outboundEnv = SecurityEnvironment.builder().targetUri(URI.create("http://www.example.com:7777")).path("/test").build();
    EndpointConfig endpointConfig = EndpointConfig.builder().build();
    boolean outboundSupported = provider.isOutboundSupported(providerRequest, outboundEnv, endpointConfig);
    assertThat("Outbound should not be supported by default", outboundSupported, is(false));
    OutboundSecurityResponse response = provider.outboundSecurity(providerRequest, outboundEnv, endpointConfig).toCompletableFuture().join();
    assertThat("Disabled target should have empty headers", response.requestHeaders().size(), is(0));
}
Also used : SecurityEnvironment(io.helidon.security.SecurityEnvironment) SecurityContext(io.helidon.security.SecurityContext) TokenCredential(io.helidon.security.providers.common.TokenCredential) Subject(io.helidon.security.Subject) EndpointConfig(io.helidon.security.EndpointConfig) ProviderRequest(io.helidon.security.ProviderRequest) OutboundSecurityResponse(io.helidon.security.OutboundSecurityResponse) Test(org.junit.jupiter.api.Test)

Example 20 with Subject

use of io.helidon.security.Subject in project helidon by oracle.

the class GoogleTokenProviderTest method buildOutboundRequest.

private ProviderRequest buildOutboundRequest() {
    TokenCredential tc = TokenCredential.create(TOKEN_VALUE, "accounts.google.com", Instant.now(), Instant.now());
    Subject subject = Subject.builder().principal(Principal.create("test")).addPublicCredential(tc).build();
    SecurityContext context = mock(SecurityContext.class);
    when(context.user()).thenReturn(Optional.of(subject));
    ProviderRequest request = mock(ProviderRequest.class);
    when(request.securityContext()).thenReturn(context);
    when(context.executorService()).thenReturn(ForkJoinPool.commonPool());
    return request;
}
Also used : SecurityContext(io.helidon.security.SecurityContext) TokenCredential(io.helidon.security.providers.common.TokenCredential) Subject(io.helidon.security.Subject) ProviderRequest(io.helidon.security.ProviderRequest)

Aggregations

Subject (io.helidon.security.Subject)36 ProviderRequest (io.helidon.security.ProviderRequest)22 SecurityContext (io.helidon.security.SecurityContext)18 SecurityEnvironment (io.helidon.security.SecurityEnvironment)18 AuthenticationResponse (io.helidon.security.AuthenticationResponse)17 Test (org.junit.jupiter.api.Test)17 Principal (io.helidon.security.Principal)16 EndpointConfig (io.helidon.security.EndpointConfig)15 OutboundSecurityResponse (io.helidon.security.OutboundSecurityResponse)15 SignedJwt (io.helidon.security.jwt.SignedJwt)11 Config (io.helidon.config.Config)10 Jwt (io.helidon.security.jwt.Jwt)9 Optional (java.util.Optional)8 Instant (java.time.Instant)7 Locale (java.util.Locale)7 TokenCredential (io.helidon.security.providers.common.TokenCredential)6 LinkedList (java.util.LinkedList)6 List (java.util.List)6 Errors (io.helidon.common.Errors)4 MediaType (io.helidon.common.http.MediaType)4