From 6030a65d1ba6007fd58f62479aac66dcad7a3729 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Thu, 24 Mar 2016 08:49:08 -0400 Subject: [PATCH] KEYCLOAK-2543 --- .../saml/mappers/UserAttributeMapper.java | 38 +++- .../oidc/mappers/UserPropertyMapper.java | 10 +- .../UserPropertyAttributeStatementMapper.java | 4 +- .../broker/SAMLBrokerUserPropertyTest.java | 212 ++++++++++++++++++ .../realm-with-saml-property-mappers.json | 124 ++++++++++ .../broker-test/test-realm-with-broker.json | 98 ++++++-- 6 files changed, 447 insertions(+), 39 deletions(-) create mode 100755 testsuite/integration/src/test/java/org/keycloak/testsuite/broker/SAMLBrokerUserPropertyTest.java create mode 100755 testsuite/integration/src/test/resources/broker-test/realm-with-saml-property-mappers.json diff --git a/services/src/main/java/org/keycloak/broker/saml/mappers/UserAttributeMapper.java b/services/src/main/java/org/keycloak/broker/saml/mappers/UserAttributeMapper.java index 0a24e294d1..70cae078e5 100755 --- a/services/src/main/java/org/keycloak/broker/saml/mappers/UserAttributeMapper.java +++ b/services/src/main/java/org/keycloak/broker/saml/mappers/UserAttributeMapper.java @@ -64,7 +64,7 @@ public class UserAttributeMapper extends AbstractIdentityProviderMapper { property = new ProviderConfigProperty(); property.setName(USER_ATTRIBUTE); property.setLabel("User Attribute Name"); - property.setHelpText("User attribute name to store saml attribute."); + property.setHelpText("User attribute name to store saml attribute. Use email, lastName, and firstName to map to those predefined user properties."); property.setType(ProviderConfigProperty.STRING_TYPE); configProperties.add(property); } @@ -99,9 +99,17 @@ public class UserAttributeMapper extends AbstractIdentityProviderMapper { @Override public void preprocessFederatedIdentity(KeycloakSession session, RealmModel realm, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) { String attribute = mapperModel.getConfig().get(USER_ATTRIBUTE); - Object value = getAttribute(mapperModel, context); + String value = getAttribute(mapperModel, context); if (value != null) { - context.setUserAttribute(attribute, value.toString()); + if (attribute.equalsIgnoreCase("email")) { + context.setEmail(value); + } else if (attribute.equalsIgnoreCase("firstName")) { + context.setFirstName(value); + } else if (attribute.equalsIgnoreCase("lastName")) { + context.setLastName(value); + } else { + context.setUserAttribute(attribute, value); + } } } @@ -128,19 +136,29 @@ public class UserAttributeMapper extends AbstractIdentityProviderMapper { @Override public void updateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) { String attribute = mapperModel.getConfig().get(USER_ATTRIBUTE); - Object value = getAttribute(mapperModel, context); - String current = user.getFirstAttribute(attribute); - if (value != null && !value.equals(current)) { - user.setSingleAttribute(attribute, value.toString()); - } else if (value == null) { - user.removeAttribute(attribute); + String value = getAttribute(mapperModel, context); + if (attribute.equalsIgnoreCase("email")) { + user.setEmail(value); + } else if (attribute.equalsIgnoreCase("firstName")) { + user.setFirstName(value); + } else if (attribute.equalsIgnoreCase("lastName")) { + user.setLastName(value); + } else { + String current = user.getFirstAttribute(attribute); + if (value != null && !value.equals(current)) { + user.setSingleAttribute(attribute, value.toString()); + } else if (value == null) { + user.removeAttribute(attribute); + } } + + } @Override public String getHelpText() { - return "Import declared saml attribute if it exists in assertion into the specified user attribute."; + return "Import declared saml attribute if it exists in assertion into the specified user property or attribute."; } } diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserPropertyMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserPropertyMapper.java index e56a2beef7..e0ea4c311e 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserPropertyMapper.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserPropertyMapper.java @@ -76,7 +76,7 @@ public class UserPropertyMapper extends AbstractOIDCProtocolMapper implements OI @Override public String getHelpText() { - return "Map a built in user property to a token claim."; + return "Map a built in user property (email, firstName, lastName) to a token claim."; } @Override @@ -104,10 +104,10 @@ public class UserPropertyMapper extends AbstractOIDCProtocolMapper implements OI } public static ProtocolMapperModel createClaimMapper(String name, - String userAttribute, - String tokenClaimName, String claimType, - boolean consentRequired, String consentText, - boolean accessToken, boolean idToken) { + String userAttribute, + String tokenClaimName, String claimType, + boolean consentRequired, String consentText, + boolean accessToken, boolean idToken) { return OIDCAttributeMapperHelper.createClaimMapper(name, userAttribute, tokenClaimName, claimType, consentRequired, consentText, diff --git a/services/src/main/java/org/keycloak/protocol/saml/mappers/UserPropertyAttributeStatementMapper.java b/services/src/main/java/org/keycloak/protocol/saml/mappers/UserPropertyAttributeStatementMapper.java index 0550bab293..fb57a0652e 100755 --- a/services/src/main/java/org/keycloak/protocol/saml/mappers/UserPropertyAttributeStatementMapper.java +++ b/services/src/main/java/org/keycloak/protocol/saml/mappers/UserPropertyAttributeStatementMapper.java @@ -72,7 +72,7 @@ public class UserPropertyAttributeStatementMapper extends AbstractSAMLProtocolMa @Override public String getHelpText() { - return "Map a built in user property to a SAML attribute type."; + return "Map a built in user property (email, firstName, lastName) to a SAML attribute type."; } @Override @@ -87,7 +87,7 @@ public class UserPropertyAttributeStatementMapper extends AbstractSAMLProtocolMa public static ProtocolMapperModel createAttributeMapper(String name, String userAttribute, String samlAttributeName, String nameFormat, String friendlyName, - boolean consentRequired, String consentText) { + boolean consentRequired, String consentText) { String mapperId = PROVIDER_ID; return AttributeStatementHelper.createAttributeMapper(name, userAttribute, samlAttributeName, nameFormat, friendlyName, consentRequired, consentText, mapperId); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/SAMLBrokerUserPropertyTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/SAMLBrokerUserPropertyTest.java new file mode 100755 index 0000000000..037b808cbc --- /dev/null +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/SAMLBrokerUserPropertyTest.java @@ -0,0 +1,212 @@ +/* + * Copyright 2016 Red Hat, Inc. and/or its affiliates + * and other contributors as indicated by the @author tags. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.keycloak.testsuite.broker; + +import org.junit.ClassRule; +import org.junit.Ignore; +import org.junit.Test; +import org.keycloak.dom.saml.v2.protocol.ResponseType; +import org.keycloak.models.IdentityProviderModel; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.RealmModel; +import org.keycloak.models.UserModel; +import org.keycloak.saml.processing.api.saml.v2.request.SAML2Request; +import org.keycloak.saml.processing.web.util.PostBindingUtil; +import org.keycloak.services.managers.RealmManager; +import org.keycloak.testsuite.KeycloakServer; +import org.keycloak.testsuite.rule.AbstractKeycloakRule; + +import javax.mail.MessagingException; +import java.io.IOException; + +import static org.junit.Assert.*; + +/** + * @author pedroigor + */ +public class SAMLBrokerUserPropertyTest extends AbstractKeycloakIdentityProviderTest { + + @ClassRule + public static AbstractKeycloakRule samlServerRule = new AbstractKeycloakRule() { + + @Override + protected void configureServer(KeycloakServer server) { + server.getConfig().setPort(8082); + } + + @Override + protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) { + server.importRealm(getClass().getResourceAsStream("/broker-test/realm-with-saml-property-mappers.json")); + } + + @Override + protected String[] getTestRealms() { + return new String[] { "realm-with-saml-idp-property-mappers" }; + } + }; + + @Override + protected String getProviderId() { + return "kc-saml-idp-property-mappers"; + } + + @Override + protected void doAssertFederatedUser(UserModel federatedUser, IdentityProviderModel identityProviderModel, String expectedEmail, boolean isProfileUpdateExpected) { + if (isProfileUpdateExpected) { + super.doAssertFederatedUser(federatedUser, identityProviderModel, expectedEmail, isProfileUpdateExpected); + } else { + assertEquals(expectedEmail, federatedUser.getEmail()); + assertNotNull(federatedUser.getFirstName()); + assertNotNull(federatedUser.getLastName()); + } + } + + @Override + protected void doAssertFederatedUserNoEmail(UserModel federatedUser) { + assertEquals("kc-saml-idp-basic.test-user-noemail", federatedUser.getUsername()); + //assertEquals("", federatedUser.getEmail()); + assertEquals(null, federatedUser.getFirstName()); + assertEquals(null, federatedUser.getLastName()); + } + + @Override + protected void doAssertTokenRetrieval(String pageSource) { + try { + SAML2Request saml2Request = new SAML2Request(); + ResponseType responseType = (ResponseType) saml2Request + .getSAML2ObjectFromStream(PostBindingUtil.base64DecodeAsStream(pageSource)); + //.getSAML2ObjectFromStream(PostBindingUtil.base64DecodeAsStream(URLDecoder.decode(pageSource, "UTF-8"))); + + assertNotNull(responseType); + assertFalse(responseType.getAssertions().isEmpty()); + } catch (Exception e) { + fail("Could not parse token."); + } + } + + @Override + @Test + public void testSuccessfulAuthenticationWithoutUpdateProfile() { + super.testSuccessfulAuthenticationWithoutUpdateProfile(); + } + + @Test + @Ignore + @Override + public void testSuccessfulAuthentication() { + // ignore + } + + @Override + @Ignore + @Test + public void testSuccessfulAuthenticationUpdateProfileOnMissing_nothingMissing() { + // ignore + } + + @Override + @Ignore + @Test + public void testSuccessfulAuthenticationUpdateProfileOnMissing_missingEmail() { + // ignore + } + + @Override + @Ignore + @Test + public void testSuccessfulAuthenticationWithoutUpdateProfile_emailProvided_emailVerifyEnabled() throws IOException, MessagingException { + // ignore + } + + @Override + @Ignore + @Test + public void testSuccessfulAuthenticationWithoutUpdateProfile_emailNotProvided_emailVerifyEnabled() { + // ignore + } + + @Override + @Ignore + @Test + public void testSuccessfulAuthenticationWithoutUpdateProfile_emailProvided_emailVerifyEnabled_emailTrustEnabled() { + // ignore + } + + @Override + @Ignore + @Test + public void testSuccessfulAuthentication_emailTrustEnabled_emailVerifyEnabled_emailUpdatedOnFirstLogin() throws IOException, MessagingException { + // ignore + } + + @Override + @Ignore + @Test + public void testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername() { + // ignore + } + + @Override + @Ignore + @Test + public void testDisabled() { + // ignore + } + + @Override + @Test + @Ignore + public void testProviderOnLoginPage() { + // ignore + } + + @Override + @Test + @Ignore + public void testAccountManagementLinkIdentity() { + // ignore + } + + @Override + @Test + @Ignore + public void testAccountManagementLinkedIdentityAlreadyExists() { + // ignore + } + + @Override + @Test + @Ignore + public void testIdentityProviderNotAllowed() { + // ignore + } + + @Override + @Test + @Ignore + public void testTokenStorageAndRetrievalByApplication() { + // ignore + } + + @Override + @Test + @Ignore + public void testWithLinkedFederationProvider() throws Exception { + // ignore + } +} diff --git a/testsuite/integration/src/test/resources/broker-test/realm-with-saml-property-mappers.json b/testsuite/integration/src/test/resources/broker-test/realm-with-saml-property-mappers.json new file mode 100755 index 0000000000..3703c7b2f1 --- /dev/null +++ b/testsuite/integration/src/test/resources/broker-test/realm-with-saml-property-mappers.json @@ -0,0 +1,124 @@ +{ + "id": "realm-with-saml-idp-property-mappers", + "realm": "realm-with-saml-idp-property-mappers", + "enabled": true, + "requiredCredentials": [ "password" ], + "defaultRoles": [ "foo", "bar" ], + "privateKey": "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCCPyvTTb14vSMkpe/pds2P5Cqxk7bkeFnQiNMS1vyZ+HS2O79fxzp1eAguHnBTs4XTRT7SZJhIT/6utgqZjmDigKV5N7X5ptq8BM/W1qa1cYBRip261pc+tWf3IywJYQ9yFI9mUQarmIEl0D7GH16NSZklheaWfbodRVarvX+ML0amNtGYVDft/RftYmgbKKrK218qQp9R4GZFtf/Q/RmboNXN7weMINU8GWVkTRrccKBIXSunT6zXGfuj3Wp1YpVq20BWwY2OMM/P+yDAc7LKEO1LJqPBdT4r9BRn2lXiaga3AL24gTKZPKU/tu7uqfFciF+i4Rr58SMDNOzQcnklAgMBAAECggEAc0eibJYEO5d8QXW1kPgcHV2gBChv2mxDYnWYDLbIQSdNdfYP/qABt/MTmm5KkWr16fcCEYoD1w0mqFBrtVn1msSusUmEAYGTXJMNumOmjjX1kzaTQMmqeFBrwqwYz/xehWR5P+A7fSmwNV3KEeW19GvN5w5K96w0TLAQdFV3TQVPSytusDunwuR1yltMe1voaEDZ9z0Pi08YiEk2f6xhj5CMkoiw3mNImzfruphHullxU4FD05fH6tDeJ381527ILpAzDsgYZh4aFLKjUHem96bX4EL7FIzBJ6okgN78AZnUC/EaVfgFTw0qfhoWvZV4ruVXXiMhCg4CMMRDq/k9iQKBgQDBNWsJMT84OnnWmQoJmZogkFV+tsGrSK6Re+aJxLWpishh7dwAnT2OcagZvVdUb0FwNWu1D0B9/SKDDMRnnHBhOGDpH57m/eQdRU0oX1BD27xvffk0lLcfD4BTxnR5e9jss8K4twc9jf0P1rxC/loGJ2NtCH0BrPHgz54Ea+96ewKBgQCsk3JDaaPnFwzVYm2BXlhxOxLPsF4wvD2rIRAswZV4C5xebjand8nwiMmVpNd0PRLkEnkI+waURGv2EY/P3JsssoiY8Xqe8f/1G+SQKre7lbqOas8rFoALepC0BYDiZDFy0Z9ZnRAFzRI5sgIt7jpoMRD4xDNlmiV8X+yBxc3Y3wKBgQChDQsU1YUyNKQ8+sLAL9anEEkD4Ald4q8JPHN2IY+gLLxNzT0XEfsu0pTiJ8805axxgUYv3e/PVYNAJBNPnrqaf6lgiegl+jr9Hzhqz9CTUAYqFaL2boSakoxQyNtsLI0s+cb1vDN/3uy0GDZDzcty18BsMagqDmRtFgNNAj/UIwKBgQCahbeFBv0cOPZjxisY8Bou4N8aGehsqNBq/0LVYExuXa8YmoTTdJ3bgw9Er4G/ccQNdUDsuqAMeCtW/CiRzQ0ge4d1sprB4Rv3I4+HSsiS7SFKzfZLtWzXWlpg5qCdlWr1TR7qhYjIOPO9t1beO3YOvwhcRoliyyAPenBxTmTfbwKBgDtm2WJ5VlQgNpIdOs1CCiqd0DFmWOmvBPspPC1kySiy+Ndr9jNohRZkR7pEjgqA5E8rdzc88LirUN7bY5HFHRWN9KXrs5/o3O1K3GFCp64N6nvnPEYZ2zSJalcMC2fjSsJg26z8Dg1H+gfTIDUMoGiEAAnJXuqk+WayPU+fZMLn", + "publicKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgj8r0029eL0jJKXv6XbNj+QqsZO25HhZ0IjTEtb8mfh0tju/X8c6dXgILh5wU7OF00U+0mSYSE/+rrYKmY5g4oCleTe1+abavATP1tamtXGAUYqdutaXPrVn9yMsCWEPchSPZlEGq5iBJdA+xh9ejUmZJYXmln26HUVWq71/jC9GpjbRmFQ37f0X7WJoGyiqyttfKkKfUeBmRbX/0P0Zm6DVze8HjCDVPBllZE0a3HCgSF0rp0+s1xn7o91qdWKVattAVsGNjjDPz/sgwHOyyhDtSyajwXU+K/QUZ9pV4moGtwC9uIEymTylP7bu7qnxXIhfouEa+fEjAzTs0HJ5JQIDAQAB", + "clients": [ + { + "clientId": "http://localhost:8081/auth/realms/realm-with-broker", + "enabled": true, + "protocol": "saml", + "redirectUris": [ + "http://localhost:8081/auth/realms/realm-with-broker/broker/kc-saml-idp-property-mappers/endpoint" + ], + "attributes": { + "saml.authnstatement": "true", + "saml_single_logout_service_url_post": "http://localhost:8081/auth/realms/realm-with-broker/broker/kc-saml-idp-property-mappers/endpoint", + "saml_assertion_consumer_url_post": "http://localhost:8081/auth/realms/realm-with-broker/broker/kc-saml-idp-property-mappers/endpoint", + "saml_force_name_id_format": "true", + "saml_name_id_format": "username" + + }, + "protocolMappers": [ + { + "name": "role list", + "protocol": "saml", + "protocolMapper": "saml-role-list-mapper", + "consentRequired": false, + "config": { + "attribute.name": "Role", + "attribute.nameformat": "Basic", + "single": "false" + + } + }, + { + "name": "email", + "protocol": "saml", + "protocolMapper": "saml-user-property-mapper", + "consentRequired": false, + "config": { + "user.attribute": "email", + "attribute.name": "email", + "attribute.nameformat": "urn:oasis:names:tc:SAML:2.0:attrname-format:uri" + } + }, + { + "name": "firstName", + "protocol": "saml", + "protocolMapper": "saml-user-property-mapper", + "consentRequired": false, + "config": { + "user.attribute": "firstName", + "attribute.name": "firstName", + "attribute.nameformat": "urn:oasis:names:tc:SAML:2.0:attrname-format:uri", + "friendly.name": "firstName" + } + }, + { + "name": "lastName", + "protocol": "saml", + "protocolMapper": "saml-user-property-mapper", + "consentRequired": false, + "config": { + "user.attribute": "lastName", + "attribute.name": "lastName", + "attribute.nameformat": "urn:oasis:names:tc:SAML:2.0:attrname-format:uri", + "friendly.name": "lastName" + } + } + + ] + + } + ], + "users": [ + { + "username" : "test-user", + "enabled": true, + "email" : "test-user@localhost", + "firstName" : "Test", + "lastName" : "User", + "credentials" : [ + { "type" : "password", + "value" : "password" } + ], + "realmRoles": ["manager"], + "attributes": { + "mobile": "617-666-7777" + } + }, + { + "username" : "test-user-noemail", + "enabled": true, + "firstName" : "Test", + "lastName" : "User", + "credentials" : [ + { "type" : "password", + "value" : "password" } + ], + "realmRoles": ["manager"] + }, + { + "username" : "pedroigor", + "enabled": true, + "email" : "psilva@redhat.com", + "credentials" : [ + { "type" : "password", + "value" : "password" } + ], + "realmRoles": ["manager"] + } + ], + "roles" : { + "realm" : [ + { + "name": "manager", + "description": "Have Manager privileges" + } + ] + } +} \ No newline at end of file diff --git a/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json b/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json index 28cc044e44..8717619721 100755 --- a/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json +++ b/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json @@ -92,19 +92,19 @@ } }, { - "alias" : "model-saml-signed-idp", - "providerId" : "saml", - "enabled": true, - "config": { - "singleSignOnServiceUrl": "http://localhost:8082/auth/realms/realm-with-saml-identity-provider/protocol/saml", - "nameIDPolicyFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", - "signingCertificate": "MIIDdzCCAl+gAwIBAgIEbySuqTANBgkqhkiG9w0BAQsFADBsMRAwDgYDVQQGEwdVbmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYDVQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3duMB4XDTE1MDEyODIyMTYyMFoXDTE3MTAyNDIyMTYyMFowbDEQMA4GA1UEBhMHVW5rbm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UEChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAII/K9NNvXi9IySl7+l2zY/kKrGTtuR4WdCI0xLW/Jn4dLY7v1/HOnV4CC4ecFOzhdNFPtJkmEhP/q62CpmOYOKApXk3tfmm2rwEz9bWprVxgFGKnbrWlz61Z/cjLAlhD3IUj2ZRBquYgSXQPsYfXo1JmSWF5pZ9uh1FVqu9f4wvRqY20ZhUN+39F+1iaBsoqsrbXypCn1HgZkW1/9D9GZug1c3vB4wg1TwZZWRNGtxwoEhdK6dPrNcZ+6PdanVilWrbQFbBjY4wz8/7IMBzssoQ7Usmo8F1Piv0FGfaVeJqBrcAvbiBMpk8pT+27u6p8VyIX6LhGvnxIwM07NByeSUCAwEAAaMhMB8wHQYDVR0OBBYEFFlcNuTYwI9W0tQ224K1gFJlMam0MA0GCSqGSIb3DQEBCwUAA4IBAQB5snl1KWOJALtAjLqD0mLPg1iElmZP82Lq1htLBt3XagwzU9CaeVeCQ7lTp+DXWzPa9nCLhsC3QyrV3/+oqNli8C6NpeqI8FqN2yQW/QMWN1m5jWDbmrWwtQzRUn/rh5KEb5m3zPB+tOC6e/2bV3QeQebxeW7lVMD0tSCviUg1MQf1l2gzuXQo60411YwqrXwk6GMkDOhFDQKDlMchO3oRbQkGbcP8UeiKAXjMeHfzbiBr+cWz8NYZEtxUEDYDjTpKrYCSMJBXpmgVJCZ00BswbksxJwaGqGMPpUKmCV671pf3m8nq3xyiHMDGuGwtbU+GE8kVx85menmp8+964nin", - "wantAuthnRequestsSigned": true, - "forceAuthn": true, - "validateSignature": true, - "postBindingResponse": true, - "postBindingAuthnRequest": true - } + "alias" : "model-saml-signed-idp", + "providerId" : "saml", + "enabled": true, + "config": { + "singleSignOnServiceUrl": "http://localhost:8082/auth/realms/realm-with-saml-identity-provider/protocol/saml", + "nameIDPolicyFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", + "signingCertificate": "MIIDdzCCAl+gAwIBAgIEbySuqTANBgkqhkiG9w0BAQsFADBsMRAwDgYDVQQGEwdVbmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYDVQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3duMB4XDTE1MDEyODIyMTYyMFoXDTE3MTAyNDIyMTYyMFowbDEQMA4GA1UEBhMHVW5rbm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UEChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAII/K9NNvXi9IySl7+l2zY/kKrGTtuR4WdCI0xLW/Jn4dLY7v1/HOnV4CC4ecFOzhdNFPtJkmEhP/q62CpmOYOKApXk3tfmm2rwEz9bWprVxgFGKnbrWlz61Z/cjLAlhD3IUj2ZRBquYgSXQPsYfXo1JmSWF5pZ9uh1FVqu9f4wvRqY20ZhUN+39F+1iaBsoqsrbXypCn1HgZkW1/9D9GZug1c3vB4wg1TwZZWRNGtxwoEhdK6dPrNcZ+6PdanVilWrbQFbBjY4wz8/7IMBzssoQ7Usmo8F1Piv0FGfaVeJqBrcAvbiBMpk8pT+27u6p8VyIX6LhGvnxIwM07NByeSUCAwEAAaMhMB8wHQYDVR0OBBYEFFlcNuTYwI9W0tQ224K1gFJlMam0MA0GCSqGSIb3DQEBCwUAA4IBAQB5snl1KWOJALtAjLqD0mLPg1iElmZP82Lq1htLBt3XagwzU9CaeVeCQ7lTp+DXWzPa9nCLhsC3QyrV3/+oqNli8C6NpeqI8FqN2yQW/QMWN1m5jWDbmrWwtQzRUn/rh5KEb5m3zPB+tOC6e/2bV3QeQebxeW7lVMD0tSCviUg1MQf1l2gzuXQo60411YwqrXwk6GMkDOhFDQKDlMchO3oRbQkGbcP8UeiKAXjMeHfzbiBr+cWz8NYZEtxUEDYDjTpKrYCSMJBXpmgVJCZ00BswbksxJwaGqGMPpUKmCV671pf3m8nq3xyiHMDGuGwtbU+GE8kVx85menmp8+964nin", + "wantAuthnRequestsSigned": true, + "forceAuthn": true, + "validateSignature": true, + "postBindingResponse": true, + "postBindingAuthnRequest": true + } }, { "alias" : "kc-saml-signed-idp", @@ -139,6 +139,21 @@ "postBindingAuthnRequest": true } }, + { + "alias" : "kc-saml-idp-property-mappers", + "providerId" : "saml", + "enabled": true, + "trustEmail" : false, + "addReadTokenRoleOnCreate": true, + "config": { + "singleSignOnServiceUrl": "http://localhost:8082/auth/realms/realm-with-saml-idp-property-mappers/protocol/saml", + "singleLogoutServiceUrl": "http://localhost:8082/auth/realms/realm-with-saml-idp-property-mappers/protocol/saml", + "nameIDPolicyFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", + "forceAuthn": true, + "postBindingResponse": true, + "postBindingAuthnRequest": true + } + }, { "alias" : "model-oidc-idp", "providerId" : "oidc", @@ -233,7 +248,46 @@ "user.attribute": "mobile", "attribute.name": "mobile" } + }, + { + "name": "email-mapper", + "identityProviderAlias": "kc-saml-idp-property-mappers", + "identityProviderMapper": "saml-user-attribute-idp-mapper", + "config": { + "user.attribute": "email", + "attribute.name": "email" + } + }, + { + "name": "firstName-mapper", + "identityProviderAlias": "kc-saml-idp-property-mappers", + "identityProviderMapper": "saml-user-attribute-idp-mapper", + "config": { + "user.attribute": "firstName", + "attribute.name": "firstName" + } + }, + { + "name": "lastName-mapper", + "identityProviderAlias": "kc-saml-idp-property-mappers", + "identityProviderMapper": "saml-user-attribute-idp-mapper", + "config": { + "user.attribute": "lastName", + "attribute.name": "lastName" + } + }, + { + "name": "manager-mapper", + "identityProviderAlias": "kc-saml-idp-property-mappers", + "identityProviderMapper": "saml-role-idp-mapper", + "config": { + "role": "manager", + "attribute.name": "Role", + "attribute.value": "manager" + } + } + ], "users": [ { @@ -263,15 +317,15 @@ "webOrigins": [] }, { - "name": "test-app-with-allowed-providers", - "enabled": true, - "publicClient": true, - "adminUrl": "http://localhost:8081/auth", - "baseUrl": "http://localhost:8081/auth", - "redirectUris": [ - "/test-app/*" - ], - "webOrigins": [] + "name": "test-app-with-allowed-providers", + "enabled": true, + "publicClient": true, + "adminUrl": "http://localhost:8081/auth", + "baseUrl": "http://localhost:8081/auth", + "redirectUris": [ + "/test-app/*" + ], + "webOrigins": [] } ], "oauthClients" : [