Skip to content

Commit

Permalink
Update to Keycloak 15.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
lscorcia committed Jul 30, 2021
1 parent b6f0847 commit 52e3424
Show file tree
Hide file tree
Showing 8 changed files with 320 additions and 446 deletions.
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,20 @@ limitations before planning your Production environment.
## Status
This project is still at an alpha stage. It is currently under development
and things may change quickly. It builds and successfully allows login/logout
to the SPID-TestEnv2 test IdP (https://github.com/italia/spid-testenv2)
and to the online SPID tester (https://idptest.spid.gov.it).
to the SPID Validator test IdP (https://github.com/italia/spid-saml-check)
and to the online SPID tester (https://www.spid-validator.it).
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 14.0.0. **Do not use this provider with previous
Currently the main branch is targeting Keycloak 15.0.0. **Do not use this provider with previous
versions of Keycloak, it won't work!**

If you are evaluating this solution, my suggestion is to test the provider by compiling Keycloak
yourself using the latest available sources. Detailed instructions are
Since this plugin uses some Keycloak internal modules, versions of this plugin
are coupled to Keycloak versions. After (major) Keycloak upgrades, you will almost
certainly have also to update this provider.

Detailed instructions on how to install and configure this component are
available in the project wiki (https://github.com/italia/spid-keycloak-provider/wiki/Installing-the-SPID-provider).

## Build requirements
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>14.0.0</version.keycloak>
<version.keycloak>15.0.0</version.keycloak>
<slf4j-api.version>1.7.30</slf4j-api.version>
<junit.version>4.13.2</junit.version>
</properties>
Expand Down
67 changes: 63 additions & 4 deletions src/main/java/org/keycloak/broker/spid/SpidIdentityProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.keycloak.broker.provider.BrokeredIdentityContext;
import org.keycloak.broker.provider.IdentityBrokerException;
import org.keycloak.broker.provider.IdentityProviderDataMarshaller;
import org.keycloak.broker.provider.IdentityProviderMapper;
import org.keycloak.broker.provider.util.SimpleHttp;
import org.keycloak.broker.saml.SAMLDataMarshaller;
import org.keycloak.common.util.PemUtils;
Expand All @@ -32,6 +33,9 @@
import org.keycloak.dom.saml.v2.assertion.AuthnStatementType;
import org.keycloak.dom.saml.v2.assertion.NameIDType;
import org.keycloak.dom.saml.v2.assertion.SubjectType;
import org.keycloak.dom.saml.v2.metadata.AttributeConsumingServiceType;
import org.keycloak.dom.saml.v2.metadata.EntityDescriptorType;
import org.keycloak.dom.saml.v2.metadata.LocalizedNameType;
import org.keycloak.dom.saml.v2.protocol.AuthnRequestType;
import org.keycloak.dom.saml.v2.protocol.LogoutRequestType;
import org.keycloak.dom.saml.v2.protocol.ResponseType;
Expand All @@ -46,7 +50,9 @@
import org.keycloak.protocol.saml.SamlProtocol;
import org.keycloak.protocol.saml.SamlService;
import org.keycloak.protocol.saml.SamlSessionUtils;
import org.keycloak.protocol.saml.mappers.SamlMetadataDescriptorUpdater;
import org.keycloak.protocol.saml.preprocessor.SamlAuthenticationPreprocessor;
import org.keycloak.saml.SAML2AuthnRequestBuilder;
import org.keycloak.saml.SAML2LogoutRequestBuilder;
import org.keycloak.saml.SAML2NameIDBuilder;
import org.keycloak.saml.SAML2NameIDPolicyBuilder;
Expand All @@ -58,8 +64,10 @@
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
import org.keycloak.saml.common.exceptions.ConfigurationException;
import org.keycloak.saml.common.util.DocumentUtil;
import org.keycloak.saml.common.util.StaxUtil;
import org.keycloak.saml.processing.api.saml.v2.request.SAML2Request;
import org.keycloak.saml.processing.api.saml.v2.sig.SAML2Signature;
import org.keycloak.saml.processing.core.saml.v2.writers.SAMLMetadataWriter;
import org.keycloak.saml.processing.core.util.KeycloakKeySamlExtensionGenerator;
import org.keycloak.saml.validators.DestinationValidator;
import org.keycloak.sessions.AuthenticationSessionModel;
Expand All @@ -75,6 +83,9 @@
import javax.ws.rs.core.UriInfo;
import javax.xml.crypto.dsig.CanonicalizationMethod;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLStreamWriter;

import java.io.StringWriter;
import java.net.URI;
import java.security.KeyPair;
import java.util.Arrays;
Expand Down Expand Up @@ -138,7 +149,7 @@ public Response performLogin(AuthenticationRequest request) {
Boolean allowCreate = null;
if (getConfig().getConfig().get(SpidIdentityProviderConfig.ALLOW_CREATE) == null || getConfig().isAllowCreate())
allowCreate = Boolean.TRUE;
SpidSAML2AuthnRequestBuilder authnRequestBuilder = new SpidSAML2AuthnRequestBuilder()
SAML2AuthnRequestBuilder authnRequestBuilder = new SAML2AuthnRequestBuilder()
.assertionConsumerUrl(assertionConsumerServiceUrl)
.destination(destinationUrl)
.issuer(SAML2NameIDBuilder.value(issuerURL)
Expand Down Expand Up @@ -362,6 +373,8 @@ 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 All @@ -386,9 +399,55 @@ public Response export(UriInfo uriInfo, RealmModel realm, String format) {
});

// Prepare the metadata descriptor model
String descriptor = SPMetadataDescriptor.getSPDescriptor(authnBinding, endpoint, endpoint,
wantAuthnRequestsSigned, wantAssertionsSigned, wantAssertionsEncrypted,
entityId, nameIDPolicyFormat, signingKeys, encryptionKeys);
StringWriter sw = new StringWriter();
XMLStreamWriter writer = StaxUtil.getXMLStreamWriter(sw);
SAMLMetadataWriter metadataWriter = new SAMLMetadataWriter(writer);

EntityDescriptorType entityDescriptor = SPMetadataDescriptor.buildSPdescriptor(
authnBinding, authnBinding, endpoint, endpoint,
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();
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);
}
}
}
}

// 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);
}
});

// Write the metadata and export it to a string
metadataWriter.writeEntityDescriptor(entityDescriptor);

String descriptor = sw.toString();

// Metadata signing
if (getConfig().isSignSpMetadata())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ public Integer getAttributeConsumingServiceIndex() {
}

public void setAttributeConsumingServiceIndex(Integer attributeConsumingServiceIndex) {
if (attributeConsumingServiceIndex < 0) {
if (attributeConsumingServiceIndex == null || attributeConsumingServiceIndex < 0) {
getConfig().remove(ATTRIBUTE_CONSUMING_SERVICE_INDEX);
} else {
getConfig().put(ATTRIBUTE_CONSUMING_SERVICE_INDEX, String.valueOf(attributeConsumingServiceIndex));
Expand Down

This file was deleted.

Loading

0 comments on commit 52e3424

Please sign in to comment.