keycloak-uncached

Merge pull request #3569 from mposolda/master KEYCLOAK-3831

11/30/2016 10:44:18 AM

Details

diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/AddressMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/AddressMapper.java
index 674c9ff..2f40c21 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/AddressMapper.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/AddressMapper.java
@@ -17,14 +17,11 @@
 
 package org.keycloak.protocol.oidc.mappers;
 
-import org.keycloak.models.ClientSessionModel;
-import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
 import org.keycloak.provider.ProviderConfigProperty;
-import org.keycloak.representations.AccessToken;
 import org.keycloak.representations.AddressClaimSet;
 import org.keycloak.representations.IDToken;
 
@@ -34,7 +31,6 @@ import java.util.List;
 import java.util.Map;
 
 /**
- * Set the 'name' claim to be first + last name.
  *
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
@@ -43,26 +39,39 @@ public class AddressMapper extends AbstractOIDCProtocolMapper implements OIDCAcc
 
     private static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
 
+    public static final String STREET = "street";
+
     static {
         OIDCAttributeMapperHelper.addIncludeInTokensConfig(configProperties, AddressMapper.class);
+
+        configProperties.add(createConfigProperty(STREET));
+        configProperties.add(createConfigProperty(AddressClaimSet.LOCALITY));
+        configProperties.add(createConfigProperty(AddressClaimSet.REGION));
+        configProperties.add(createConfigProperty(AddressClaimSet.POSTAL_CODE));
+        configProperties.add(createConfigProperty(AddressClaimSet.COUNTRY));
+        configProperties.add(createConfigProperty(AddressClaimSet.FORMATTED));
+    }
+
+    protected static ProviderConfigProperty createConfigProperty(String claimName) {
+        ProviderConfigProperty property = new ProviderConfigProperty();
+        property.setName(getModelPropertyName(claimName));
+        property.setLabel("addressClaim." + claimName + ".label");
+        property.setHelpText("addressClaim." + claimName + ".tooltip");
+        property.setType(ProviderConfigProperty.STRING_TYPE);
+        property.setDefaultValue(claimName);
+        return property;
+    }
+
+    public static String getModelPropertyName(String claimName) {
+        return "user.attribute." + claimName;
     }
 
     public static final String PROVIDER_ID = "oidc-address-mapper";
 
     public static ProtocolMapperModel createAddressMapper() {
-        Map<String, String> config;
-        ProtocolMapperModel address = new ProtocolMapperModel();
-        address.setName("address");
-        address.setProtocolMapper(PROVIDER_ID);
-        address.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
-        address.setConsentRequired(true);
-        address.setConsentText("${address}");
-        config = new HashMap<String, String>();
-        config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, "true");
-        config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, "true");
-        address.setConfig(config);
-        return address;
+        return createAddressMapper(true, true);
     }
+
     public static ProtocolMapperModel createAddressMapper(boolean idToken, boolean accessToken) {
         Map<String, String> config;
         ProtocolMapperModel address = new ProtocolMapperModel();
@@ -74,6 +83,14 @@ public class AddressMapper extends AbstractOIDCProtocolMapper implements OIDCAcc
         config = new HashMap<String, String>();
         config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, Boolean.toString(idToken));
         config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, Boolean.toString(accessToken));
+
+        config.put(getModelPropertyName(STREET), STREET);
+        config.put(getModelPropertyName(AddressClaimSet.LOCALITY), AddressClaimSet.LOCALITY);
+        config.put(getModelPropertyName(AddressClaimSet.REGION), AddressClaimSet.REGION);
+        config.put(getModelPropertyName(AddressClaimSet.POSTAL_CODE), AddressClaimSet.POSTAL_CODE);
+        config.put(getModelPropertyName(AddressClaimSet.COUNTRY), AddressClaimSet.COUNTRY);
+        config.put(getModelPropertyName(AddressClaimSet.FORMATTED), AddressClaimSet.FORMATTED);
+
         address.setConfig(config);
         return address;
     }
@@ -107,12 +124,24 @@ public class AddressMapper extends AbstractOIDCProtocolMapper implements OIDCAcc
     protected void setClaim(IDToken token, ProtocolMapperModel mappingModel, UserSessionModel userSession) {
         UserModel user = userSession.getUser();
         AddressClaimSet addressSet = new AddressClaimSet();
-        addressSet.setStreetAddress(user.getFirstAttribute("street"));
-        addressSet.setLocality(user.getFirstAttribute("locality"));
-        addressSet.setRegion(user.getFirstAttribute("region"));
-        addressSet.setPostalCode(user.getFirstAttribute("postal_code"));
-        addressSet.setCountry(user.getFirstAttribute("country"));
+        addressSet.setStreetAddress(getUserModelAttributeValue(user, mappingModel, STREET));
+        addressSet.setLocality(getUserModelAttributeValue(user, mappingModel, AddressClaimSet.LOCALITY));
+        addressSet.setRegion(getUserModelAttributeValue(user, mappingModel, AddressClaimSet.REGION));
+        addressSet.setPostalCode(getUserModelAttributeValue(user, mappingModel, AddressClaimSet.POSTAL_CODE));
+        addressSet.setCountry(getUserModelAttributeValue(user, mappingModel, AddressClaimSet.COUNTRY));
+        addressSet.setFormattedAddress(getUserModelAttributeValue(user, mappingModel, AddressClaimSet.FORMATTED));
         token.getOtherClaims().put("address", addressSet);
     }
 
+    private String getUserModelAttributeValue(UserModel user, ProtocolMapperModel mappingModel, String claim) {
+        String modelPropertyName = getModelPropertyName(claim);
+        String userAttrName = mappingModel.getConfig().get(modelPropertyName);
+
+        if (userAttrName == null) {
+            userAttrName = claim;
+        }
+
+        return user.getFirstAttribute(userAttrName);
+    }
+
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OIDCProtocolMappersTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OIDCProtocolMappersTest.java
index ac86d20..7ffcfdc 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OIDCProtocolMappersTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OIDCProtocolMappersTest.java
@@ -29,7 +29,9 @@ import org.keycloak.admin.client.resource.ClientResource;
 import org.keycloak.admin.client.resource.ProtocolMappersResource;
 import org.keycloak.admin.client.resource.UserResource;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
+import org.keycloak.protocol.oidc.mappers.AddressMapper;
 import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.AddressClaimSet;
 import org.keycloak.representations.IDToken;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.ProtocolMapperRepresentation;
@@ -96,11 +98,13 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
 
             user.singleAttribute("street", "5 Yawkey Way");
             user.singleAttribute("locality", "Boston");
-            user.singleAttribute("region", "MA");
+            user.singleAttribute("region_some", "MA"); // Custom name for userAttribute name, which will be mapped to region
             user.singleAttribute("postal_code", "02115");
             user.singleAttribute("country", "USA");
+            user.singleAttribute("formatted", "6 Foo Street");
             user.singleAttribute("phone", "617-777-6666");
 
+
             List<String> departments = Arrays.asList("finance", "development");
             user.getAttributes().put("departments", departments);
             userResource.update(user);
@@ -108,6 +112,9 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
             ClientResource app = findClientResourceByClientId(adminClient.realm("test"), "test-app");
 
             ProtocolMapperRepresentation mapper = createAddressMapper(true, true);
+            mapper.getConfig().put(AddressMapper.getModelPropertyName(AddressClaimSet.REGION), "region_some");
+            mapper.getConfig().put(AddressMapper.getModelPropertyName(AddressClaimSet.COUNTRY), "country_some");
+            mapper.getConfig().remove(AddressMapper.getModelPropertyName(AddressClaimSet.POSTAL_CODE)); // Even if we remove protocolMapper config property, it should still default to postal_code
             app.getProtocolMappers().createMapper(mapper);
 
             ProtocolMapperRepresentation hard = createHardcodedClaim("hard", "hard", "coded", "String", false, null, true, true);
@@ -131,7 +138,8 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
             assertEquals(idToken.getAddress().getLocality(), "Boston");
             assertEquals(idToken.getAddress().getRegion(), "MA");
             assertEquals(idToken.getAddress().getPostalCode(), "02115");
-            assertEquals(idToken.getAddress().getCountry(), "USA");
+            assertNull(idToken.getAddress().getCountry()); // Null because we changed userAttribute name to "country_some", but user contains "country"
+            assertEquals(idToken.getAddress().getFormattedAddress(), "6 Foo Street");
             assertNotNull(idToken.getOtherClaims().get("home_phone"));
             assertEquals("617-777-6666", idToken.getOtherClaims().get("home_phone"));
             assertEquals("coded", idToken.getOtherClaims().get("hard"));
@@ -150,7 +158,8 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
             assertEquals(accessToken.getAddress().getLocality(), "Boston");
             assertEquals(accessToken.getAddress().getRegion(), "MA");
             assertEquals(accessToken.getAddress().getPostalCode(), "02115");
-            assertEquals(accessToken.getAddress().getCountry(), "USA");
+            assertNull(idToken.getAddress().getCountry()); // Null because we changed userAttribute name to "country_some", but user contains "country"
+            assertEquals(idToken.getAddress().getFormattedAddress(), "6 Foo Street");
             assertNotNull(accessToken.getOtherClaims().get("home_phone"));
             assertEquals("617-777-6666", accessToken.getOtherClaims().get("home_phone"));
             assertEquals("coded", accessToken.getOtherClaims().get("hard"));
diff --git a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
index 29f1465..8cf09f3 100644
--- a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
+++ b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
@@ -170,8 +170,18 @@ sectorIdentifierUri.label=Sector Identifier URI
 sectorIdentifierUri.tooltip=Providers that use pairwise sub values and support Dynamic Client Registration SHOULD use the sector_identifier_uri parameter. It provides a way for a group of websites under common administrative control to have consistent pairwise sub values independent of the individual domain names. It also provides a way for Clients to change redirect_uri domains without having to reregister all of their users.
 pairwiseSubAlgorithmSalt.label=Salt
 pairwiseSubAlgorithmSalt.tooltip=Salt used when calculating the pairwise subject identifier. If left blank, a salt will be generated.
-
-
+addressClaim.street.label=User Attribute Name for Street
+addressClaim.street.tooltip=Name of User Attribute, which will be used to map to 'street_address' subclaim inside 'address' token claim. Defaults to 'street' .
+addressClaim.locality.label=User Attribute Name for Locality
+addressClaim.locality.tooltip=Name of User Attribute, which will be used to map to 'locality' subclaim inside 'address' token claim. Defaults to 'locality' .
+addressClaim.region.label=User Attribute Name for Region
+addressClaim.region.tooltip=Name of User Attribute, which will be used to map to 'region' subclaim inside 'address' token claim. Defaults to 'region' .
+addressClaim.postal_code.label=User Attribute Name for Postal Code
+addressClaim.postal_code.tooltip=Name of User Attribute, which will be used to map to 'postal_code' subclaim inside 'address' token claim. Defaults to 'postal_code' .
+addressClaim.country.label=User Attribute Name for Country
+addressClaim.country.tooltip=Name of User Attribute, which will be used to map to 'country' subclaim inside 'address' token claim. Defaults to 'country' .
+addressClaim.formatted.label=User Attribute Name for Formatted Address
+addressClaim.formatted.tooltip=Name of User Attribute, which will be used to map to 'formatted' subclaim inside 'address' token claim. Defaults to 'formatted' .
 
 # client details
 clients.tooltip=Clients are trusted browser apps and web services in a realm. These clients can request a login. You can also define client specific roles.