From 2a69b360e7995938d720f9404a4a5cd0d6ffcb10 Mon Sep 17 00:00:00 2001 From: Jonas Hein Date: Tue, 20 Feb 2024 16:59:18 +0100 Subject: [PATCH] made Organisation optional so it uses version 2 if it does not have one --- .../api/service/AdministrationService.java | 6 +++ .../HazelcastAdministrationService.java | 9 ++++ .../fafnir/sso/provider/GoogleProvider.java | 39 ++++++++++------ .../dk/acto/fafnir/sso/util/TokenFactory.java | 45 +++++++++++++++++-- 4 files changed, 82 insertions(+), 17 deletions(-) diff --git a/client/src/main/java/dk/acto/fafnir/api/service/AdministrationService.java b/client/src/main/java/dk/acto/fafnir/api/service/AdministrationService.java index 338f038..984c577 100644 --- a/client/src/main/java/dk/acto/fafnir/api/service/AdministrationService.java +++ b/client/src/main/java/dk/acto/fafnir/api/service/AdministrationService.java @@ -3,6 +3,8 @@ import dk.acto.fafnir.api.model.*; import reactor.core.publisher.ConnectableFlux; +import java.util.Optional; + public interface AdministrationService { /** @@ -99,6 +101,10 @@ public interface AdministrationService { */ OrganisationData readOrganisation(TenantIdentifier identifier); + + + Optional readOrganisationDoesNotThrow(TenantIdentifier identifier); + /** * Updates an organisation. Fails if organisation does not exist. * diff --git a/client/src/main/java/dk/acto/fafnir/api/service/hazelcast/HazelcastAdministrationService.java b/client/src/main/java/dk/acto/fafnir/api/service/hazelcast/HazelcastAdministrationService.java index a8a963f..fbaf23a 100644 --- a/client/src/main/java/dk/acto/fafnir/api/service/hazelcast/HazelcastAdministrationService.java +++ b/client/src/main/java/dk/acto/fafnir/api/service/hazelcast/HazelcastAdministrationService.java @@ -133,6 +133,15 @@ public OrganisationData readOrganisation(TenantIdentifier identifier) { .findAny() .orElseThrow(NoSuchOrganisation::new); } + @Override + public Optional readOrganisationDoesNotThrow(TenantIdentifier identifier) { + IMap orgMap = hazelcastInstance.getMap(hazelcastConf.getPrefix() + ORG_POSTFIX); + return orgMap.values() + .stream() + .filter(entry -> identifier.matches(entry.getProviderConfiguration())) + .findAny(); + } + @Override public OrganisationData updateOrganisation(OrganisationData source) { diff --git a/sso/src/main/java/dk/acto/fafnir/sso/provider/GoogleProvider.java b/sso/src/main/java/dk/acto/fafnir/sso/provider/GoogleProvider.java index 7d5e099..e554e38 100644 --- a/sso/src/main/java/dk/acto/fafnir/sso/provider/GoogleProvider.java +++ b/sso/src/main/java/dk/acto/fafnir/sso/provider/GoogleProvider.java @@ -32,8 +32,8 @@ public String authenticate() { @Override public AuthenticationResult callback(TokenCredentials data) { var token = Try.of(() -> googleOauth.getAccessToken(data.getCode())) - .onFailure(x -> log.error("Authentication failed", x)) - .getOrNull(); + .onFailure(x -> log.error("Authentication failed", x)) + .getOrNull(); if (token == null) { return AuthenticationResult.failure(FailureReason.AUTHENTICATION_FAILED); } @@ -42,22 +42,35 @@ public AuthenticationResult callback(TokenCredentials data) { var subject = jwtToken.getClaims().get("email").asString(); var displayName = jwtToken.getClaims().get("name").asString(); var providerValue = Optional.ofNullable(jwtToken.getClaim("hd")) - .map(Claim::asString) - .orElse(""); + .map(Claim::asString) + .orElse(""); var subjectActual = UserData.builder() - .subject(providerConf.applySubjectRules(subject)) - .name(displayName) - .build(); - var orgActual = administrationService.readOrganisation( - test -> getMetaData().getProviderId().equals(test.getProviderId()) && - (providerValue.equals(test.getValues().get("Organisation Domain")) || "true".equals(test.getValues().get("Catchall Organisation"))) + .subject(providerConf.applySubjectRules(subject)) + .name(displayName) + .build(); + + var orgOptional = administrationService.readOrganisationDoesNotThrow( + test -> getMetaData().getProviderId().equals(test.getProviderId()) && + (providerValue.equals(test.getValues().get("Organisation Domain")) || "true".equals(test.getValues().get("Catchall Organisation"))) ); - var claimsActual = ClaimData.empty(); - var jwt = tokenFactory.generateToken(subjectActual, orgActual, claimsActual, getMetaData(), providerValue); + if (orgOptional.isPresent()) { + var orgActual = orgOptional.get(); + var claimsActual = ClaimData.empty(); + var jwt = tokenFactory.generateToken(subjectActual, orgActual, claimsActual, getMetaData(), providerValue); + return AuthenticationResult.success(jwt); + } else { + var fafnirUser = FafnirUser.builder() + .data(subjectActual) + .organisationId(providerValue) + .organisationName(displayName) + .provider("google") + .build(); - return AuthenticationResult.success(jwt); + var jwt = tokenFactory.generateToken(fafnirUser); + return AuthenticationResult.success(jwt); + } } @Override diff --git a/sso/src/main/java/dk/acto/fafnir/sso/util/TokenFactory.java b/sso/src/main/java/dk/acto/fafnir/sso/util/TokenFactory.java index 2e013f3..d7d772a 100644 --- a/sso/src/main/java/dk/acto/fafnir/sso/util/TokenFactory.java +++ b/sso/src/main/java/dk/acto/fafnir/sso/util/TokenFactory.java @@ -4,10 +4,7 @@ import com.auth0.jwt.algorithms.Algorithm; import dk.acto.fafnir.api.crypto.RsaKeyManager; import dk.acto.fafnir.api.exception.*; -import dk.acto.fafnir.api.model.ClaimData; -import dk.acto.fafnir.api.model.OrganisationData; -import dk.acto.fafnir.api.model.ProviderMetaData; -import dk.acto.fafnir.api.model.UserData; +import dk.acto.fafnir.api.model.*; import io.vavr.control.Try; import lombok.AllArgsConstructor; import org.springframework.stereotype.Component; @@ -70,6 +67,46 @@ public String generateToken(final UserData ud, OrganisationData od, ClaimData cd .get(); } + public String generateToken (final FafnirUser fafnirUser) { + var jwt = JWT.create(); + + var temp = Optional.ofNullable(fafnirUser) + .orElseThrow(NoUser::new); + + jwt.withIssuer(Optional.ofNullable(temp.getProvider()) + .map(idp -> "fafnir-" + idp) + .orElseThrow(NoIssuer::new)); + + jwt.withSubject(Optional.ofNullable(temp.getSubject()) + .orElseThrow(NoSubject::new)); + + jwt.withIssuedAt(Date.from(Instant.now())); + + Optional.ofNullable(temp.getName()) + .ifPresent(name -> jwt.withClaim("name", name)); + + Optional.ofNullable(temp.getMetaId()) + .ifPresent(name -> jwt.withClaim("mId", name)); + + Optional.ofNullable(temp.getLocale()) + .ifPresent(locale -> jwt.withClaim("locale", locale.toLanguageTag())); + + Optional.ofNullable(temp.getOrganisationId()) + .ifPresent(orgId -> jwt.withClaim("org_id", orgId)); + + Optional.ofNullable(temp.getOrganisationName()) + .ifPresent(orgName -> jwt.withClaim("org_name", orgName)); + + Optional.ofNullable(temp.getRoles()) + .filter(x -> x.length > 0) + .ifPresent(roles -> jwt.withArrayClaim("role", roles)); + + + return Try.of(() -> Algorithm.RSA512(keyManager.getPublicKey(), keyManager.getPrivateKey())) + .map(jwt::sign) + .get(); + } + public String generateToken(final UserData ud, OrganisationData od, ClaimData cd, ProviderMetaData pmd) { return generateToken(ud, od, cd, pmd, null); }