KEYCLOAK-16048 SAML Client import - add md:RequestedAttribute as "User Attribute" ProtocolMapper

This commit is contained in:
cgeorgilakis 2021-03-22 22:55:32 +02:00 committed by GitHub
parent f754b34c0c
commit 18afdea392
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 48 additions and 0 deletions

View file

@ -31,7 +31,10 @@ import org.keycloak.exportimport.ClientDescriptionConverterFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.protocol.saml.mappers.AttributeStatementHelper;
import org.keycloak.protocol.saml.mappers.UserAttributeStatementMapper;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
import org.keycloak.saml.SignatureAlgorithm;
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
import org.keycloak.saml.common.exceptions.ConfigurationException;
@ -48,6 +51,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -178,6 +182,22 @@ public class EntityDescriptorDescriptionConverter implements ClientDescriptionCo
}
}
app.setProtocolMappers(spDescriptorType.getAttributeConsumingService().stream().flatMap(att -> att.getRequestedAttribute().stream())
.map(attr -> {
ProtocolMapperRepresentation mapper = new ProtocolMapperRepresentation();
mapper.setName(attr.getName());
mapper.setProtocol("saml");
mapper.setProtocolMapper(UserAttributeStatementMapper.PROVIDER_ID);
Map<String, String> config = new HashMap<>();
config.put(AttributeStatementHelper.SAML_ATTRIBUTE_NAME, attr.getName());
if (attr.getFriendlyName() != null)
config.put(AttributeStatementHelper.FRIENDLY_NAME, attr.getFriendlyName());
if (attr.getNameFormat() != null)
config.put(AttributeStatementHelper.SAML_ATTRIBUTE_NAMEFORMAT, getSAMLNameFormat(attr.getNameFormat()));
mapper.setConfig(config);
return mapper;
}).collect(Collectors.toList()));
for (KeyDescriptorType keyDescriptor : spDescriptorType.getKeyDescriptor()) {
X509Certificate cert = null;
try {
@ -200,6 +220,20 @@ public class EntityDescriptorDescriptionConverter implements ClientDescriptionCo
return app;
}
private static String getSAMLNameFormat(String xmlValue) {
String value =null;
if (JBossSAMLURIConstants.ATTRIBUTE_FORMAT_URI.getUri().toString().equals(xmlValue)) {
value = AttributeStatementHelper.URI_REFERENCE;
} else if (JBossSAMLURIConstants.ATTRIBUTE_FORMAT_BASIC.getUri().toString().equals(xmlValue)) {
value = AttributeStatementHelper.BASIC;
} else if (JBossSAMLURIConstants.ATTRIBUTE_FORMAT_UNSPECIFIED.getUri().toString().equals(xmlValue)) {
value = AttributeStatementHelper.UNSPECIFIED;
}
return value;
}
private static String getLogoutLocation(SPSSODescriptorType idp, String bindingURI) {
String logoutResponseLocation = null;

View file

@ -25,11 +25,14 @@ import org.keycloak.client.registration.Auth;
import org.keycloak.client.registration.ClientRegistrationException;
import org.keycloak.client.registration.HttpErrorException;
import org.keycloak.events.Errors;
import org.keycloak.protocol.saml.mappers.AttributeStatementHelper;
import org.keycloak.representations.idm.ClientInitialAccessCreatePresentation;
import org.keycloak.representations.idm.ClientInitialAccessPresentation;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.util.KeycloakModelUtils;
@ -81,6 +84,14 @@ public class SAMLClientRegistrationTest extends AbstractClientRegistrationTest {
)); // No redirect URI for ARTIFACT binding which is unsupported
assertThat(response.getAttributes().get("saml_single_logout_service_url_redirect"), is("https://LoadBalancer-9.siroe.com:3443/federation/SPSloRedirect/metaAlias/sp"));
Assert.assertNotNull(response.getProtocolMappers());
Assert.assertEquals(1,response.getProtocolMappers().size());
ProtocolMapperRepresentation mapper = response.getProtocolMappers().get(0);
Assert.assertEquals("saml-user-attribute-mapper",mapper.getProtocolMapper());
Assert.assertEquals("urn:oid:2.5.4.42",mapper.getConfig().get(AttributeStatementHelper.SAML_ATTRIBUTE_NAME));
Assert.assertEquals("givenName",mapper.getConfig().get(AttributeStatementHelper.FRIENDLY_NAME));
Assert.assertEquals(AttributeStatementHelper.URI_REFERENCE,mapper.getConfig().get(AttributeStatementHelper.SAML_ATTRIBUTE_NAMEFORMAT));
}
@Test

View file

@ -107,5 +107,8 @@ x5Ql0ejivIJAYcMGUyA+/YwJg2FGoA==
index="4"
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="https://LoadBalancer-9.siroe.com:3443/federation/Consumer/metaAlias/sp/redirect"/>
<AttributeConsumingService index="0">
<RequestedAttribute Name="urn:oid:2.5.4.42" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" FriendlyName="givenName"/>
</AttributeConsumingService>
</SPSSODescriptor>
</EntityDescriptor>