diff --git a/broker/core/src/main/java/org/keycloak/broker/provider/BrokeredIdentityContext.java b/broker/core/src/main/java/org/keycloak/broker/provider/BrokeredIdentityContext.java index f90f803efe..6052f5738b 100755 --- a/broker/core/src/main/java/org/keycloak/broker/provider/BrokeredIdentityContext.java +++ b/broker/core/src/main/java/org/keycloak/broker/provider/BrokeredIdentityContext.java @@ -17,6 +17,7 @@ */ package org.keycloak.broker.provider; +import org.keycloak.models.ClientSessionModel; import org.keycloak.models.IdentityProviderModel; import java.util.HashMap; @@ -43,6 +44,7 @@ public class BrokeredIdentityContext { private IdentityProviderModel idpConfig; private IdentityProvider idp; private Map contextData = new HashMap<>(); + private ClientSessionModel clientSession; public BrokeredIdentityContext(String id) { if (id == null) { @@ -166,6 +168,14 @@ public class BrokeredIdentityContext { this.lastName = lastName; } + public ClientSessionModel getClientSession() { + return clientSession; + } + + public void setClientSession(ClientSessionModel clientSession) { + this.clientSession = clientSession; + } + public void setName(String name) { if (name != null) { int i = name.lastIndexOf(' '); diff --git a/broker/core/src/main/java/org/keycloak/broker/provider/HardcodedAttributeMapper.java b/broker/core/src/main/java/org/keycloak/broker/provider/HardcodedAttributeMapper.java new file mode 100755 index 0000000000..d182d6f1a6 --- /dev/null +++ b/broker/core/src/main/java/org/keycloak/broker/provider/HardcodedAttributeMapper.java @@ -0,0 +1,89 @@ +package org.keycloak.broker.provider; + +import org.keycloak.models.ClientModel; +import org.keycloak.models.IdentityProviderMapperModel; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.RealmModel; +import org.keycloak.models.RoleModel; +import org.keycloak.models.UserModel; +import org.keycloak.provider.ProviderConfigProperty; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class HardcodedAttributeMapper extends AbstractIdentityProviderMapper { + public static final String ATTRIBUTE = "attribute"; + public static final String ATTRIBUTE_VALUE = "attribute.value"; + protected static final List configProperties = new ArrayList(); + + static { + ProviderConfigProperty property; + property = new ProviderConfigProperty(); + property.setName(ATTRIBUTE); + property.setLabel("User Attribute"); + property.setHelpText("Name of user attribute you want to hardcode"); + property.setType(ProviderConfigProperty.STRING_TYPE); + configProperties.add(property); + property = new ProviderConfigProperty(); + property.setName(ATTRIBUTE_VALUE); + property.setLabel("User Attribute Value"); + property.setHelpText("Value you want to hardcode"); + property.setType(ProviderConfigProperty.STRING_TYPE); + configProperties.add(property); + } + + + + @Override + public List getConfigProperties() { + return configProperties; + } + + @Override + public String getDisplayCategory() { + return "Attribute Importer"; + } + + @Override + public String getDisplayType() { + return "Hardcoded Attribute"; + } + + public static final String[] COMPATIBLE_PROVIDERS = {ANY_PROVIDER}; + + + public static final String PROVIDER_ID = "hardcoded-attribute-idp-mapper"; + + @Override + public String getId() { + return PROVIDER_ID; + } + + @Override + public String[] getCompatibleProviders() { + return COMPATIBLE_PROVIDERS; + } + + @Override + public void importNewUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) { + String attribute = mapperModel.getConfig().get(ATTRIBUTE); + String attributeValue = mapperModel.getConfig().get(ATTRIBUTE_VALUE); + user.setSingleAttribute(attribute, attributeValue); + } + + @Override + public void updateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) { + String attribute = mapperModel.getConfig().get(ATTRIBUTE); + String attributeValue = mapperModel.getConfig().get(ATTRIBUTE_VALUE); + user.setSingleAttribute(attribute, attributeValue); + } + + @Override + public String getHelpText() { + return "When user is imported from provider, hardcode a value to a specific user attribute."; + } +} diff --git a/broker/core/src/main/java/org/keycloak/broker/provider/HardcodedUserSessionAttributeMapper.java b/broker/core/src/main/java/org/keycloak/broker/provider/HardcodedUserSessionAttributeMapper.java new file mode 100755 index 0000000000..676e6b1edf --- /dev/null +++ b/broker/core/src/main/java/org/keycloak/broker/provider/HardcodedUserSessionAttributeMapper.java @@ -0,0 +1,87 @@ +package org.keycloak.broker.provider; + +import org.keycloak.models.IdentityProviderMapperModel; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.RealmModel; +import org.keycloak.models.UserModel; +import org.keycloak.provider.ProviderConfigProperty; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class HardcodedUserSessionAttributeMapper extends AbstractIdentityProviderMapper { + public static final String ATTRIBUTE = "attribute"; + public static final String ATTRIBUTE_VALUE = "attribute.value"; + protected static final List configProperties = new ArrayList(); + + static { + ProviderConfigProperty property; + property = new ProviderConfigProperty(); + property.setName(ATTRIBUTE); + property.setLabel("User Session Attribute"); + property.setHelpText("Name of user session attribute you want to hardcode"); + property.setType(ProviderConfigProperty.STRING_TYPE); + configProperties.add(property); + property = new ProviderConfigProperty(); + property.setName(ATTRIBUTE_VALUE); + property.setLabel("User Session Attribute Value"); + property.setHelpText("Value you want to hardcode"); + property.setType(ProviderConfigProperty.STRING_TYPE); + configProperties.add(property); + } + + + + @Override + public List getConfigProperties() { + return configProperties; + } + + @Override + public String getDisplayCategory() { + return "Attribute Importer"; + } + + @Override + public String getDisplayType() { + return "Hardcoded User Session Attribute"; + } + + public static final String[] COMPATIBLE_PROVIDERS = {ANY_PROVIDER}; + + + public static final String PROVIDER_ID = "hardcoded-user-session-attribute-idp-mapper"; + + @Override + public String getId() { + return PROVIDER_ID; + } + + @Override + public String[] getCompatibleProviders() { + return COMPATIBLE_PROVIDERS; + } + + @Override + public void importNewUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) { + String attribute = mapperModel.getConfig().get(ATTRIBUTE); + String attributeValue = mapperModel.getConfig().get(ATTRIBUTE_VALUE); + context.getClientSession().setUserSessionNote(attribute, attributeValue); + } + + @Override + public void updateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) { + String attribute = mapperModel.getConfig().get(ATTRIBUTE); + String attributeValue = mapperModel.getConfig().get(ATTRIBUTE_VALUE); + context.getClientSession().setUserSessionNote(attribute, attributeValue); + } + + @Override + public String getHelpText() { + return "When user is imported from provider, hardcode a value to a specific user session attribute."; + } +} diff --git a/broker/core/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderMapper b/broker/core/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderMapper index a3bf053820..ef57994bde 100755 --- a/broker/core/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderMapper +++ b/broker/core/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderMapper @@ -1 +1,3 @@ -org.keycloak.broker.provider.HardcodedRoleMapper \ No newline at end of file +org.keycloak.broker.provider.HardcodedRoleMapper +org.keycloak.broker.provider.HardcodedAttributeMapper +org.keycloak.broker.provider.HardcodedUserSessionAttributeMapper \ No newline at end of file diff --git a/docbook/reference/en/en-US/modules/identity-broker.xml b/docbook/reference/en/en-US/modules/identity-broker.xml index 2288ed75de..a262b850fe 100755 --- a/docbook/reference/en/en-US/modules/identity-broker.xml +++ b/docbook/reference/en/en-US/modules/identity-broker.xml @@ -1264,6 +1264,24 @@ keycloak.createLoginUrl({ JSON structure in Keycloak log file. +
+ User Session Data + + After a user logs in from the external IDP, there's some additional user session note data that Keycloak stores that you + can access. This data can be propagated to the client requesting a login + via the token or SAML assertion being passed back to it by using an appropriate client mapper. + + + BROKER_PROVIDER_ID + + + This is the IDP alias of the broker used to perform the login. + + + + + +
Examples diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/UserSessionNoteStatementMapper.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/UserSessionNoteStatementMapper.java new file mode 100755 index 0000000000..ccf4c1f555 --- /dev/null +++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/UserSessionNoteStatementMapper.java @@ -0,0 +1,69 @@ +package org.keycloak.protocol.saml.mappers; + +import org.keycloak.dom.saml.v2.assertion.AttributeStatementType; +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.ProtocolMapperUtils; +import org.keycloak.provider.ProviderConfigProperty; + +import java.util.ArrayList; +import java.util.List; + +/** + * Maps a user session note to a SAML attribute + * + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class UserSessionNoteStatementMapper extends AbstractSAMLProtocolMapper implements SAMLAttributeStatementMapper { + private static final List configProperties = new ArrayList(); + + static { + ProviderConfigProperty property; + property = new ProviderConfigProperty(); + property.setName("note"); + property.setLabel("User Session Note Attribute"); + property.setHelpText("The user session note you want to grab the value from."); + configProperties.add(property); + AttributeStatementHelper.setConfigProperties(configProperties); + + } + + public static final String PROVIDER_ID = "saml-user-session-note-mapper"; + + + public List getConfigProperties() { + return configProperties; + } + @Override + public String getId() { + return PROVIDER_ID; + } + + @Override + public String getDisplayType() { + return "User Session Note"; + } + + @Override + public String getDisplayCategory() { + return AttributeStatementHelper.ATTRIBUTE_STATEMENT_CATEGORY; + } + + @Override + public String getHelpText() { + return "Map a user session note to a SAML attribute."; + } + + @Override + public void transformAttributeStatement(AttributeStatementType attributeStatement, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession) { + String note = mappingModel.getConfig().get("note"); + String value = userSession.getNote(note); + if (value == null) return; + AttributeStatementHelper.addAttribute(attributeStatement, mappingModel, value); + + } +} diff --git a/saml/saml-protocol/src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper b/saml/saml-protocol/src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper index 58e10db065..163fed5081 100755 --- a/saml/saml-protocol/src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper +++ b/saml/saml-protocol/src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper @@ -4,5 +4,6 @@ org.keycloak.protocol.saml.mappers.HardcodedRole org.keycloak.protocol.saml.mappers.HardcodedAttributeMapper org.keycloak.protocol.saml.mappers.UserAttributeStatementMapper org.keycloak.protocol.saml.mappers.UserPropertyAttributeStatementMapper +org.keycloak.protocol.saml.mappers.UserSessionNoteStatementMapper diff --git a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java index beec6642d7..f95d7d80da 100755 --- a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java +++ b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java @@ -256,6 +256,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal } ClientSessionModel clientSession = clientCode.getClientSession(); + context.setClientSession(clientSession); session.getContext().setClient(clientSession.getClient());