Skip to content

Commit

Permalink
Align to Keycloak 16.1.1
Browse files Browse the repository at this point in the history
  • Loading branch information
lscorcia committed Feb 17, 2022
1 parent 5845fa9 commit cc4b3c3
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 38 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<failOnMissingWebXml>false</failOnMissingWebXml>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

<version.keycloak>15.0.0</version.keycloak>
<version.keycloak>16.1.1</version.keycloak>
<slf4j-api.version>1.7.30</slf4j-api.version>
<junit.version>4.13.2</junit.version>
</properties>
Expand Down
66 changes: 35 additions & 31 deletions src/main/java/org/keycloak/broker/spid/SpidIdentityProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;

/**
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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<Element> signingKeys = new LinkedList<>();
List<Element> encryptionKeys = new LinkedList<>();
Expand Down Expand Up @@ -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<Entry<IdentityProviderMapperModel, SamlMetadataDescriptorUpdater>> 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<EntityDescriptorType.EDTDescriptorChoiceType> 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<EntityDescriptorType.EDTDescriptorChoiceType> 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);
Expand Down
10 changes: 7 additions & 3 deletions src/main/java/org/keycloak/broker/spid/SpidSAMLEndpoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -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)
{
Expand All @@ -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)
{
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@
<div class="form-group">
<label class="col-md-2 control-label" for="attributeConsumingServiceIndex">{{:: 'identity-provider.saml.attribute-consuming-service-index' | translate}}</label>
<div class="col-md-6">
<input class="form-control" string-to-number type="number" min="0" max="2147483" step="1" ng-model="identityProvider.config.attributeConsumingServiceIndex" id="attributeConsumingServiceIndex"/>
<input class="form-control" string-to-number type="number" min="0" max="65535" step="1" ng-model="identityProvider.config.attributeConsumingServiceIndex" id="attributeConsumingServiceIndex"/>
</div>
<kc-tooltip>{{:: 'identity-provider.saml.attribute-consuming-service-index.tooltip' | translate}}</kc-tooltip>
</div>
Expand Down

0 comments on commit cc4b3c3

Please sign in to comment.