From cc4b3c3e8f2ff9c51fd4b03b6f93544360d856e3 Mon Sep 17 00:00:00 2001 From: Luca Leonardo Scorcia Date: Thu, 17 Feb 2022 05:02:02 -0500 Subject: [PATCH] Align to Keycloak 16.1.1 --- README.md | 2 +- pom.xml | 2 +- .../broker/spid/SpidIdentityProvider.java | 66 ++++++++++--------- .../broker/spid/SpidSAMLEndpoint.java | 10 ++- .../SpidSpMetadataResourceProvider.java | 2 +- .../realm-identity-provider-spid.html | 2 +- 6 files changed, 46 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 31d98bc..c5d1dc2 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ As far as I know it has not been used in Production in any environment yet. Until the project gets to a stable release, it will be targeting the most recent release of Keycloak as published on the website (see property `version.keycloak` in file `pom.xml`). -Currently the main branch is targeting Keycloak 15.0.0. **Do not use this provider with previous +Currently the main branch is targeting Keycloak 16.1.1. **Do not use the latest release with previous versions of Keycloak, it won't work!** Since this plugin uses some Keycloak internal modules, versions of this plugin diff --git a/pom.xml b/pom.xml index bb58ca4..6bfffcb 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ false UTF-8 - 15.0.0 + 16.1.1 1.7.30 4.13.2 diff --git a/src/main/java/org/keycloak/broker/spid/SpidIdentityProvider.java b/src/main/java/org/keycloak/broker/spid/SpidIdentityProvider.java index 95eea48..e3b0212 100644 --- a/src/main/java/org/keycloak/broker/spid/SpidIdentityProvider.java +++ b/src/main/java/org/keycloak/broker/spid/SpidIdentityProvider.java @@ -41,6 +41,7 @@ import org.keycloak.dom.saml.v2.protocol.ResponseType; import org.keycloak.events.EventBuilder; import org.keycloak.models.FederatedIdentityModel; +import org.keycloak.models.IdentityProviderMapperModel; import org.keycloak.models.KeyManager; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; @@ -88,10 +89,12 @@ import java.io.StringWriter; import java.net.URI; import java.security.KeyPair; +import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; import java.util.Iterator; import java.util.List; +import java.util.Map.Entry; import java.util.Objects; /** @@ -195,7 +198,7 @@ public Response performLogin(AuthenticationRequest request) { } // Save the current RequestID in the Auth Session as we need to verify it against the ID returned from the IdP - request.getAuthenticationSession().setClientNote(SamlProtocol.SAML_REQUEST_ID, authnRequest.getID()); + request.getAuthenticationSession().setClientNote(SamlProtocol.SAML_REQUEST_ID_BROKER, authnRequest.getID()); if (postBinding) { return binding.postBinding(authnRequestBuilder.toDocument()).request(destinationUrl); @@ -373,8 +376,7 @@ public Response export(UriInfo uriInfo, RealmModel realm, String format) { boolean wantAssertionsEncrypted = getConfig().isWantAssertionsEncrypted(); String entityId = getEntityId(uriInfo, realm); String nameIDPolicyFormat = getConfig().getNameIDPolicyFormat(); - int attributeConsumingServiceIndex = getConfig().getAttributeConsumingServiceIndex() != null ? getConfig().getAttributeConsumingServiceIndex(): 1; - String attributeConsumingServiceName = getConfig().getAttributeConsumingServiceName(); + List signingKeys = new LinkedList<>(); List encryptionKeys = new LinkedList<>(); @@ -408,41 +410,43 @@ public Response export(UriInfo uriInfo, RealmModel realm, String format) { wantAuthnRequestsSigned, wantAssertionsSigned, wantAssertionsEncrypted, entityId, nameIDPolicyFormat, signingKeys, encryptionKeys); - // Create the AttributeConsumingService - AttributeConsumingServiceType attributeConsumingService = new AttributeConsumingServiceType(attributeConsumingServiceIndex); - attributeConsumingService.setIsDefault(true); - - if (attributeConsumingServiceName != null && attributeConsumingServiceName.length() > 0) - { - String currentLocale = realm.getDefaultLocale() == null ? "en": realm.getDefaultLocale(); + // Create the AttributeConsumingService if at least one attribute importer mapper exists + List> metadataAttrProviders = new ArrayList<>(); + realm.getIdentityProviderMappersByAliasStream(getConfig().getAlias()) + .forEach(mapper -> { + IdentityProviderMapper target = (IdentityProviderMapper) session.getKeycloakSessionFactory().getProviderFactory(IdentityProviderMapper.class, mapper.getIdentityProviderMapper()); + if (target instanceof SamlMetadataDescriptorUpdater) + metadataAttrProviders.add(new java.util.AbstractMap.SimpleEntry<>(mapper, (SamlMetadataDescriptorUpdater)target)); + }); + + if (!metadataAttrProviders.isEmpty()) { + int attributeConsumingServiceIndex = getConfig().getAttributeConsumingServiceIndex() != null ? getConfig().getAttributeConsumingServiceIndex() : 1; + String attributeConsumingServiceName = getConfig().getAttributeConsumingServiceName(); + //default value for attributeConsumingServiceName + if (attributeConsumingServiceName == null) + attributeConsumingServiceName = realm.getDisplayName() != null ? realm.getDisplayName() : realm.getName() ; + AttributeConsumingServiceType attributeConsumingService = new AttributeConsumingServiceType(attributeConsumingServiceIndex); + attributeConsumingService.setIsDefault(true); + + String currentLocale = realm.getDefaultLocale() == null ? "en" : realm.getDefaultLocale(); LocalizedNameType attributeConsumingServiceNameElement = new LocalizedNameType(currentLocale); attributeConsumingServiceNameElement.setValue(attributeConsumingServiceName); attributeConsumingService.addServiceName(attributeConsumingServiceNameElement); - } - - // Look for the SP descriptor and add the attribute consuming service - for (EntityDescriptorType.EDTChoiceType choiceType: entityDescriptor.getChoiceType()) { - List descriptors = choiceType.getDescriptors(); - if (descriptors != null) { - for (EntityDescriptorType.EDTDescriptorChoiceType descriptor: descriptors) { - if (descriptor.getSpDescriptor() != null) { - descriptor.getSpDescriptor().addAttributeConsumerService(attributeConsumingService); - } + // Look for the SP descriptor and add the attribute consuming service + for (EntityDescriptorType.EDTChoiceType choiceType : entityDescriptor.getChoiceType()) { + List descriptors = choiceType.getDescriptors(); + for (EntityDescriptorType.EDTDescriptorChoiceType descriptor : descriptors) { + descriptor.getSpDescriptor().addAttributeConsumerService(attributeConsumingService); } } - } - - // Add the attribute mappers - realm.getIdentityProviderMappersByAliasStream(getConfig().getAlias()) - .forEach(mapper -> { - IdentityProviderMapper target = (IdentityProviderMapper) session.getKeycloakSessionFactory().getProviderFactory(IdentityProviderMapper.class, mapper.getIdentityProviderMapper()); - if (target instanceof SamlMetadataDescriptorUpdater) - { - SamlMetadataDescriptorUpdater metadataAttrProvider = (SamlMetadataDescriptorUpdater)target; - metadataAttrProvider.updateMetadata(mapper, entityDescriptor); - } + + // Add the attribute mappers + metadataAttrProviders.forEach(mapper -> { + SamlMetadataDescriptorUpdater metadataAttrProvider = mapper.getValue(); + metadataAttrProvider.updateMetadata(mapper.getKey(), entityDescriptor); }); + } // Write the metadata and export it to a string metadataWriter.writeEntityDescriptor(entityDescriptor); diff --git a/src/main/java/org/keycloak/broker/spid/SpidSAMLEndpoint.java b/src/main/java/org/keycloak/broker/spid/SpidSAMLEndpoint.java index 75cb447..b31e7af 100755 --- a/src/main/java/org/keycloak/broker/spid/SpidSAMLEndpoint.java +++ b/src/main/java/org/keycloak/broker/spid/SpidSAMLEndpoint.java @@ -426,7 +426,7 @@ protected Response handleLoginResponse(String samlResponse, SAMLDocumentHolder h return callback.error("SpidFault_" + responseType.getStatus().getStatusMessage().replace(' ', '_')); else { - String statusMessage = responseType.getStatus() == null ? Messages.IDENTITY_PROVIDER_UNEXPECTED_ERROR : responseType.getStatus().getStatusMessage(); + String statusMessage = responseType.getStatus() == null || responseType.getStatus().getStatusMessage() == null ? Messages.IDENTITY_PROVIDER_UNEXPECTED_ERROR : responseType.getStatus().getStatusMessage(); return callback.error(statusMessage); } } @@ -455,7 +455,7 @@ protected Response handleLoginResponse(String samlResponse, SAMLDocumentHolder h } // Apply SPID-specific response validation rules - String spidExpectedRequestId = authSession.getClientNote(SamlProtocol.SAML_REQUEST_ID); + String spidExpectedRequestId = authSession.getClientNote(SamlProtocol.SAML_REQUEST_ID_BROKER); String spidResponseValidationError = verifySpidResponse(holder.getSamlDocument().getDocumentElement(), assertionElement, spidExpectedRequestId); if (spidResponseValidationError != null) { @@ -466,7 +466,7 @@ protected Response handleLoginResponse(String samlResponse, SAMLDocumentHolder h } // Validate InResponseTo attribute: must match the generated request ID - String expectedRequestId = authSession.getClientNote(SamlProtocol.SAML_REQUEST_ID); + String expectedRequestId = authSession.getClientNote(SamlProtocol.SAML_REQUEST_ID_BROKER); final boolean inResponseToValidationSuccess = validateInResponseToAttribute(responseType, expectedRequestId); if (!inResponseToValidationSuccess) { @@ -487,6 +487,10 @@ protected Response handleLoginResponse(String samlResponse, SAMLDocumentHolder h return ErrorPage.error(session, authSession, Response.Status.BAD_REQUEST, Messages.INVALID_REQUESTER); } + if(AssertionUtil.isIdEncrypted(responseType)) { + // This methods writes the parsed and decrypted id back on the responseType parameter: + AssertionUtil.decryptId(responseType, keys.getPrivateKey()); + } AssertionType assertion = responseType.getAssertions().get(0).getAssertion(); NameIDType subjectNameID = getSubjectNameID(assertion); String principal = getPrincipal(assertion); diff --git a/src/main/java/org/keycloak/broker/spid/metadata/SpidSpMetadataResourceProvider.java b/src/main/java/org/keycloak/broker/spid/metadata/SpidSpMetadataResourceProvider.java index 284b208..09df98c 100644 --- a/src/main/java/org/keycloak/broker/spid/metadata/SpidSpMetadataResourceProvider.java +++ b/src/main/java/org/keycloak/broker/spid/metadata/SpidSpMetadataResourceProvider.java @@ -184,7 +184,7 @@ public Response get() { String serviceNameLocale = parsedName.length >= 2 ? parsedName[0]: currentLocale; LocalizedNameType attributeConsumingServiceNameElement = new LocalizedNameType(serviceNameLocale); - attributeConsumingServiceNameElement.setValue(parsedName[1]); + attributeConsumingServiceNameElement.setValue(parsedName.length >= 2 ? parsedName[1]: attributeConsumingServiceNameStr); attributeConsumingService.addServiceName(attributeConsumingServiceNameElement); } } diff --git a/src/main/resources/theme-resources/resources/partials/realm-identity-provider-spid.html b/src/main/resources/theme-resources/resources/partials/realm-identity-provider-spid.html index 9aa4e31..e8c2207 100644 --- a/src/main/resources/theme-resources/resources/partials/realm-identity-provider-spid.html +++ b/src/main/resources/theme-resources/resources/partials/realm-identity-provider-spid.html @@ -311,7 +311,7 @@
- +
{{:: 'identity-provider.saml.attribute-consuming-service-index.tooltip' | translate}}