From d2a540352771f2dfffecc302909905fb2737eace Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Mon, 13 Apr 2015 09:45:23 -0400 Subject: [PATCH 1/2] refactor for broker mappers --- .../provider/AbstractIdentityProvider.java | 17 ++ .../provider/BrokeredIdentityContext.java | 171 +++++++++++ .../broker/provider/IdentityProvider.java | 21 +- .../oidc/AbstractOAuth2IdentityProvider.java | 19 +- .../broker/oidc/OIDCIdentityProvider.java | 37 ++- .../keycloak/broker/saml/SAMLEndpoint.java | 31 +- .../broker/saml/SAMLIdentityProvider.java | 38 ++- .../keycloak/provider/ConfiguredProvider.java | 15 + .../provider/ProviderConfigProperty.java | 57 ++++ .../mappers/AttributeStatementHelper.java | 12 +- .../mappers/HardcodedAttributeMapper.java | 11 +- .../protocol/saml/mappers/HardcodedRole.java | 11 +- .../protocol/saml/mappers/RoleListMapper.java | 19 +- .../protocol/saml/mappers/RoleNameMapper.java | 15 +- .../mappers/UserAttributeStatementMapper.java | 9 +- .../UserPropertyAttributeStatementMapper.java | 9 +- .../org/keycloak/protocol/ProtocolMapper.java | 59 +--- .../protocol/oidc/mappers/AddressMapper.java | 15 +- .../protocol/oidc/mappers/FullNameMapper.java | 15 +- .../protocol/oidc/mappers/HardcodedClaim.java | 27 +- .../protocol/oidc/mappers/HardcodedRole.java | 11 +- .../mappers/OIDCAttributeMapperHelper.java | 21 +- .../protocol/oidc/mappers/RoleNameMapper.java | 15 +- .../oidc/mappers/UserAttributeMapper.java | 11 +- .../oidc/mappers/UserPropertyMapper.java | 11 +- .../oidc/mappers/UserSessionNoteMapper.java | 269 +++++++++--------- .../resources/IdentityBrokerService.java | 61 ++-- .../admin/ServerInfoAdminResource.java | 3 +- .../facebook/FacebookIdentityProvider.java | 7 +- .../social/github/GitHubIdentityProvider.java | 7 +- .../linkedin/LinkedInIdentityProvider.java | 9 +- .../StackoverflowIdentityProvider.java | 12 +- .../twitter/TwitterIdentityProvider.java | 11 +- .../provider/CustomIdentityProvider.java | 2 +- .../provider/social/CustomSocialProvider.java | 2 +- 35 files changed, 690 insertions(+), 370 deletions(-) create mode 100755 broker/core/src/main/java/org/keycloak/broker/provider/BrokeredIdentityContext.java create mode 100755 model/api/src/main/java/org/keycloak/provider/ConfiguredProvider.java create mode 100755 model/api/src/main/java/org/keycloak/provider/ProviderConfigProperty.java diff --git a/broker/core/src/main/java/org/keycloak/broker/provider/AbstractIdentityProvider.java b/broker/core/src/main/java/org/keycloak/broker/provider/AbstractIdentityProvider.java index a0f8309314..d65081d188 100755 --- a/broker/core/src/main/java/org/keycloak/broker/provider/AbstractIdentityProvider.java +++ b/broker/core/src/main/java/org/keycloak/broker/provider/AbstractIdentityProvider.java @@ -18,8 +18,10 @@ package org.keycloak.broker.provider; import org.keycloak.events.EventBuilder; +import org.keycloak.models.ClientSessionModel; import org.keycloak.models.IdentityProviderModel; import org.keycloak.models.RealmModel; +import org.keycloak.models.UserModel; import org.keycloak.models.UserSessionModel; import javax.ws.rs.core.Response; @@ -59,4 +61,19 @@ public abstract class AbstractIdentityProvider public Response keycloakInitiatedBrowserLogout(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm) { return null; } + + @Override + public void attachUserSession(UserSessionModel userSession, ClientSessionModel clientSession, BrokeredIdentityContext context) { + + } + + @Override + public void importNewUser(UserModel user, BrokeredIdentityContext context) { + + } + + @Override + public void updateBrokeredUser(UserModel user, BrokeredIdentityContext context) { + + } } 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 new file mode 100755 index 0000000000..7bee93623d --- /dev/null +++ b/broker/core/src/main/java/org/keycloak/broker/provider/BrokeredIdentityContext.java @@ -0,0 +1,171 @@ +/* + * JBoss, Home of Professional Open Source + * + * Copyright 2013 Red Hat, Inc. and/or its affiliates. + * + * 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.broker.provider; + +import org.keycloak.models.IdentityProviderModel; + +import java.util.HashMap; +import java.util.Map; + +/** + *

Represents all identity information obtained from an {@link org.keycloak.broker.provider.IdentityProvider} after a + * successful authentication.

+ * + * @author Pedro Igor + */ +public class BrokeredIdentityContext { + + private String id; + private String username; + private String email; + private String firstName; + private String lastName; + private String brokerSessionId; + private String brokerUserId; + private String code; + private String token; + private IdentityProviderModel idpConfig; + private IdentityProvider idp; + private Map contextData = new HashMap<>(); + + public BrokeredIdentityContext(String id) { + if (id == null) { + throw new RuntimeException("No identifier provider for identity."); + } + + this.id = id; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getBrokerSessionId() { + return brokerSessionId; + } + + public void setBrokerSessionId(String brokerSessionId) { + this.brokerSessionId = brokerSessionId; + } + + public String getBrokerUserId() { + return brokerUserId; + } + + public void setBrokerUserId(String brokerUserId) { + this.brokerUserId = brokerUserId; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public IdentityProviderModel getIdpConfig() { + return idpConfig; + } + + public void setIdpConfig(IdentityProviderModel idpConfig) { + this.idpConfig = idpConfig; + } + + public IdentityProvider getIdp() { + return idp; + } + + public void setIdp(IdentityProvider idp) { + this.idp = idp; + } + + public Map getContextData() { + return contextData; + } + + public void setContextData(Map contextData) { + this.contextData = contextData; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public void setName(String name) { + if (name != null) { + int i = name.lastIndexOf(' '); + if (i != -1) { + firstName = name.substring(0, i); + lastName = name.substring(i + 1); + } else { + firstName = name; + } + } + } + + + @Override + public String toString() { + return "{" + + "id='" + id + '\'' + + ", username='" + username + '\'' + + ", email='" + email + '\'' + + '}'; + } +} diff --git a/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProvider.java b/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProvider.java index ebc2ccd1a0..0517b3a27c 100755 --- a/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProvider.java +++ b/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProvider.java @@ -18,9 +18,11 @@ package org.keycloak.broker.provider; import org.keycloak.events.EventBuilder; +import org.keycloak.models.ClientSessionModel; import org.keycloak.models.FederatedIdentityModel; import org.keycloak.models.IdentityProviderModel; import org.keycloak.models.RealmModel; +import org.keycloak.models.UserModel; import org.keycloak.models.UserSessionModel; import org.keycloak.provider.Provider; @@ -38,15 +40,22 @@ public interface IdentityProvider extends Provi * This method should be called by provider after the JAXRS callback endpoint has finished authentication * with the remote IDP * - * @param userNotes notes to add to the UserSessionModel - * @param identityProviderConfig provider config - * @param federatedIdentity federated identity - * @param code relayState or state parameter used to identity the client session + * @param context * @return */ - public Response authenticated(Map userNotes, IdentityProviderModel identityProviderConfig, FederatedIdentity federatedIdentity, String code); + public Response authenticated(BrokeredIdentityContext context); } + /** + * + * @param userSession + * @param clientSession + * @param context + */ + void attachUserSession(UserSessionModel userSession, ClientSessionModel clientSession, BrokeredIdentityContext context); + void importNewUser(UserModel user, BrokeredIdentityContext context); + void updateBrokeredUser(UserModel user, BrokeredIdentityContext context); + /** * JAXRS callback endpoint for when the remote IDP wants to callback to keycloak. * @@ -68,7 +77,7 @@ public interface IdentityProvider extends Provi * identity provider. * @return */ - Response handleRequest(AuthenticationRequest request); + Response performLogin(AuthenticationRequest request); /** *

Returns a {@link javax.ws.rs.core.Response} containing the token previously stored during the authentication process for a diff --git a/broker/oidc/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java b/broker/oidc/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java index 8d57b2c81c..0eab543b20 100755 --- a/broker/oidc/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java +++ b/broker/oidc/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java @@ -25,14 +25,18 @@ import org.keycloak.OAuth2Constants; import org.keycloak.broker.oidc.util.SimpleHttp; import org.keycloak.broker.provider.AbstractIdentityProvider; import org.keycloak.broker.provider.AuthenticationRequest; +import org.keycloak.broker.provider.BrokeredIdentityContext; import org.keycloak.broker.provider.FederatedIdentity; import org.keycloak.broker.provider.IdentityBrokerException; import org.keycloak.events.Errors; import org.keycloak.events.EventBuilder; import org.keycloak.events.EventType; +import org.keycloak.models.ClientSessionModel; import org.keycloak.models.FederatedIdentityModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; +import org.keycloak.models.UserModel; +import org.keycloak.models.UserSessionModel; import org.keycloak.services.messages.Messages; import org.keycloak.services.resources.flows.Flows; @@ -87,7 +91,7 @@ public abstract class AbstractOAuth2IdentityProvider notes, String response) { + protected BrokeredIdentityContext getFederatedIdentity(String response) { String accessToken = extractTokenFromResponse(response, OAUTH2_PARAMETER_ACCESS_TOKEN); if (accessToken == null) { @@ -136,7 +140,7 @@ public abstract class AbstractOAuth2IdentityProvider userNotes = new HashMap(); - FederatedIdentity federatedIdentity = getFederatedIdentity(userNotes, response); + BrokeredIdentityContext federatedIdentity = getFederatedIdentity(response); if (getConfig().isStoreToken()) { federatedIdentity.setToken(response); } - return callback.authenticated(userNotes, getConfig(), federatedIdentity, state); + federatedIdentity.setCode(state); + federatedIdentity.setIdpConfig(getConfig()); + federatedIdentity.setIdp(AbstractOAuth2IdentityProvider.this); + + return callback.authenticated(federatedIdentity); } } catch (Exception e) { logger.error("Failed to make identity provider oauth callback", e); diff --git a/broker/oidc/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java b/broker/oidc/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java index c1b39a977f..19a0f9df53 100755 --- a/broker/oidc/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java +++ b/broker/oidc/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java @@ -22,6 +22,7 @@ import org.jboss.logging.Logger; import org.keycloak.RSATokenVerifier; import org.keycloak.broker.oidc.util.SimpleHttp; import org.keycloak.broker.provider.AuthenticationRequest; +import org.keycloak.broker.provider.BrokeredIdentityContext; import org.keycloak.broker.provider.FederatedIdentity; import org.keycloak.broker.provider.IdentityBrokerException; import org.keycloak.events.Errors; @@ -29,7 +30,9 @@ import org.keycloak.events.EventBuilder; import org.keycloak.events.EventType; import org.keycloak.jose.jws.JWSInput; import org.keycloak.jose.jws.crypto.RSAProvider; +import org.keycloak.models.ClientSessionModel; import org.keycloak.models.RealmModel; +import org.keycloak.models.UserModel; import org.keycloak.models.UserSessionModel; import org.keycloak.representations.AccessTokenResponse; import org.keycloak.representations.IDToken; @@ -61,6 +64,9 @@ public class OIDCIdentityProvider extends AbstractOAuth2IdentityProvider notes, String response) { + protected BrokeredIdentityContext getFederatedIdentity(String response) { AccessTokenResponse tokenResponse = null; try { tokenResponse = JsonSerialization.readValue(response, AccessTokenResponse.class); @@ -170,21 +176,18 @@ public class OIDCIdentityProvider extends AbstractOAuth2IdentityProvider notes = new HashMap<>(); - notes.put(SAML_FEDERATED_SUBJECT, subjectNameID.getValue()); - if (subjectNameID.getFormat() != null) notes.put(SAML_FEDERATED_SUBJECT_NAMEFORMAT, subjectNameID.getFormat().toString()); - FederatedIdentity identity = new FederatedIdentity(subjectNameID.getValue()); + //Map notes = new HashMap<>(); + BrokeredIdentityContext identity = new BrokeredIdentityContext(subjectNameID.getValue()); + identity.setCode(relayState); + identity.getContextData().put(SAML_LOGIN_RESPONSE, responseType); + identity.getContextData().put(SAML_ASSERTION, assertion); identity.setUsername(subjectNameID.getValue()); @@ -284,24 +291,28 @@ public class SAMLEndpoint { for (Object statement : assertion.getStatements()) { if (statement instanceof AuthnStatementType) { authn = (AuthnStatementType)statement; + identity.getContextData().put(SAML_AUTHN_STATEMENT, authn); break; } } String brokerUserId = config.getAlias() + "." + subjectNameID.getValue(); identity.setBrokerUserId(brokerUserId); + identity.setIdpConfig(config); + identity.setIdp(provider); if (authn != null && authn.getSessionIndex() != null) { identity.setBrokerSessionId(identity.getBrokerUserId() + "." + authn.getSessionIndex()); - notes.put(SAML_FEDERATED_SESSION_INDEX, authn.getSessionIndex()); - } - return callback.authenticated(notes, config, identity, relayState); + } + + + return callback.authenticated(identity); } catch (Exception e) { throw new IdentityBrokerException("Could not process response from SAML identity provider.", e); } - - } + + private AssertionType getAssertion(ResponseType responseType) throws ProcessingException { List assertions = responseType.getAssertions(); diff --git a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java index af817c934a..aaec932cb8 100755 --- a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java +++ b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java @@ -19,10 +19,18 @@ package org.keycloak.broker.saml; import org.keycloak.broker.provider.AbstractIdentityProvider; import org.keycloak.broker.provider.AuthenticationRequest; +import org.keycloak.broker.provider.BrokeredIdentityContext; import org.keycloak.broker.provider.IdentityBrokerException; +import org.keycloak.dom.saml.v2.assertion.AssertionType; +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.protocol.ResponseType; import org.keycloak.events.EventBuilder; +import org.keycloak.models.ClientSessionModel; import org.keycloak.models.FederatedIdentityModel; import org.keycloak.models.RealmModel; +import org.keycloak.models.UserModel; import org.keycloak.models.UserSessionModel; import org.keycloak.protocol.saml.SAML2AuthnRequestBuilder; import org.keycloak.protocol.saml.SAML2LogoutRequestBuilder; @@ -47,11 +55,11 @@ public class SAMLIdentityProvider extends AbstractIdentityProviderBill Burke + * @version $Revision: 1 $ + */ +public interface ConfiguredProvider { + String getHelpText(); + + List getConfigProperties(); +} diff --git a/model/api/src/main/java/org/keycloak/provider/ProviderConfigProperty.java b/model/api/src/main/java/org/keycloak/provider/ProviderConfigProperty.java new file mode 100755 index 0000000000..e3a217d1c6 --- /dev/null +++ b/model/api/src/main/java/org/keycloak/provider/ProviderConfigProperty.java @@ -0,0 +1,57 @@ +package org.keycloak.provider; + +/** +* @author Bill Burke +* @version $Revision: 1 $ +*/ +public class ProviderConfigProperty { + public static final String BOOLEAN_TYPE="boolean"; + public static final String STRING_TYPE="String"; + public static final String LIST_TYPE="List"; + + protected String name; + protected String label; + protected String helpText; + protected String type; + protected Object defaultValue; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public Object getDefaultValue() { + return defaultValue; + } + + public void setDefaultValue(Object defaultValue) { + this.defaultValue = defaultValue; + } + + public String getHelpText() { + return helpText; + } + + public void setHelpText(String helpText) { + this.helpText = helpText; + } +} diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/AttributeStatementHelper.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/AttributeStatementHelper.java index 11e27dc20d..c85461911b 100755 --- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/AttributeStatementHelper.java +++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/AttributeStatementHelper.java @@ -1,8 +1,8 @@ package org.keycloak.protocol.saml.mappers; import org.keycloak.models.ProtocolMapperModel; -import org.keycloak.protocol.ProtocolMapper; import org.keycloak.protocol.ProtocolMapperUtils; +import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.protocol.saml.SamlProtocol; import org.keycloak.saml.common.constants.JBossSAMLURIConstants; import org.keycloak.dom.saml.v2.assertion.AttributeStatementType; @@ -48,18 +48,18 @@ public class AttributeStatementHelper { return attribute; } - public static void setConfigProperties(List configProperties) { - ProtocolMapper.ConfigProperty property = new ProtocolMapper.ConfigProperty(); + public static void setConfigProperties(List configProperties) { + ProviderConfigProperty property = new ProviderConfigProperty(); property.setName(AttributeStatementHelper.FRIENDLY_NAME); property.setLabel(AttributeStatementHelper.FRIENDLY_NAME_LABEL); property.setHelpText(AttributeStatementHelper.FRIENDLY_NAME_HELP_TEXT); configProperties.add(property); - property = new ProtocolMapper.ConfigProperty(); + property = new ProviderConfigProperty(); property.setName(AttributeStatementHelper.SAML_ATTRIBUTE_NAME); property.setLabel("SAML Attribute Name"); property.setHelpText("SAML Attribute Name"); configProperties.add(property); - property = new ProtocolMapper.ConfigProperty(); + property = new ProviderConfigProperty(); property.setName(AttributeStatementHelper.SAML_ATTRIBUTE_NAMEFORMAT); property.setLabel("SAML Attribute NameFormat"); property.setHelpText("SAML Attribute NameFormat. Can be basic, URI reference, or unspecified."); @@ -67,7 +67,7 @@ public class AttributeStatementHelper { types.add(AttributeStatementHelper.BASIC); types.add(AttributeStatementHelper.URI_REFERENCE); types.add(AttributeStatementHelper.UNSPECIFIED); - property.setType(ProtocolMapper.ConfigProperty.LIST_TYPE); + property.setType(ProviderConfigProperty.LIST_TYPE); property.setDefaultValue(types); configProperties.add(property); diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/HardcodedAttributeMapper.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/HardcodedAttributeMapper.java index 5ec2589535..5aa2d0a1ca 100755 --- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/HardcodedAttributeMapper.java +++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/HardcodedAttributeMapper.java @@ -5,6 +5,7 @@ import org.keycloak.models.KeycloakSession; import org.keycloak.models.ProtocolMapperModel; import org.keycloak.models.UserSessionModel; import org.keycloak.dom.saml.v2.assertion.AttributeStatementType; +import org.keycloak.provider.ProviderConfigProperty; import java.util.ArrayList; import java.util.List; @@ -18,15 +19,15 @@ import java.util.List; public class HardcodedAttributeMapper extends AbstractSAMLProtocolMapper implements SAMLAttributeStatementMapper { public static final String PROVIDER_ID = "saml-hardcode-attribute-mapper"; public static final String ATTRIBUTE_VALUE = "attribute.value"; - private static final List configProperties = new ArrayList(); + private static final List configProperties = new ArrayList(); static { - ConfigProperty property; + ProviderConfigProperty property; AttributeStatementHelper.setConfigProperties(configProperties); - property = new ConfigProperty(); + property = new ProviderConfigProperty(); property.setName(ATTRIBUTE_VALUE); property.setLabel("Attribute value"); - property.setType(ConfigProperty.STRING_TYPE); + property.setType(ProviderConfigProperty.STRING_TYPE); property.setHelpText("Value of the attribute you want to hard code."); configProperties.add(property); @@ -34,7 +35,7 @@ public class HardcodedAttributeMapper extends AbstractSAMLProtocolMapper impleme - public List getConfigProperties() { + public List getConfigProperties() { return configProperties; } @Override diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/HardcodedRole.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/HardcodedRole.java index 15a6d8b021..321727a4f2 100755 --- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/HardcodedRole.java +++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/HardcodedRole.java @@ -1,6 +1,7 @@ package org.keycloak.protocol.saml.mappers; import org.keycloak.models.ProtocolMapperModel; +import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.protocol.saml.SamlProtocol; import java.util.ArrayList; @@ -17,21 +18,21 @@ import java.util.Map; public class HardcodedRole extends AbstractSAMLProtocolMapper { public static final String PROVIDER_ID = "saml-hardcode-role-mapper"; public static final String ATTRIBUTE_VALUE = "attribute.value"; - private static final List configProperties = new ArrayList(); + private static final List configProperties = new ArrayList(); static { - ConfigProperty property; - property = new ConfigProperty(); + ProviderConfigProperty property; + property = new ProviderConfigProperty(); property.setName("role"); property.setLabel("Role"); property.setHelpText("Role name you want to hardcode."); - property.setType(ConfigProperty.STRING_TYPE); + property.setType(ProviderConfigProperty.STRING_TYPE); configProperties.add(property); } - public List getConfigProperties() { + public List getConfigProperties() { return configProperties; } @Override diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/RoleListMapper.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/RoleListMapper.java index eb0e3549b2..677b2bf64b 100755 --- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/RoleListMapper.java +++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/RoleListMapper.java @@ -7,6 +7,7 @@ import org.keycloak.models.ProtocolMapperModel; import org.keycloak.models.RoleModel; import org.keycloak.models.UserSessionModel; import org.keycloak.protocol.ProtocolMapper; +import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.protocol.saml.SamlProtocol; import org.keycloak.dom.saml.v2.assertion.AttributeStatementType; import org.keycloak.dom.saml.v2.assertion.AttributeType; @@ -25,22 +26,22 @@ public class RoleListMapper extends AbstractSAMLProtocolMapper implements SAMLRo public static final String PROVIDER_ID = "saml-role-list-mapper"; public static final String SINGLE_ROLE_ATTRIBUTE = "single"; - private static final List configProperties = new ArrayList(); + private static final List configProperties = new ArrayList(); static { - ConfigProperty property; - property = new ConfigProperty(); + ProviderConfigProperty property; + property = new ProviderConfigProperty(); property.setName(AttributeStatementHelper.SAML_ATTRIBUTE_NAME); property.setLabel("Role attribute name"); property.setDefaultValue("Role"); property.setHelpText("Name of the SAML attribute you want to put your roles into. i.e. 'Role', 'memberOf'."); configProperties.add(property); - property = new ProtocolMapper.ConfigProperty(); + property = new ProviderConfigProperty(); property.setName(AttributeStatementHelper.FRIENDLY_NAME); property.setLabel(AttributeStatementHelper.FRIENDLY_NAME_LABEL); property.setHelpText(AttributeStatementHelper.FRIENDLY_NAME_HELP_TEXT); configProperties.add(property); - property = new ProtocolMapper.ConfigProperty(); + property = new ProviderConfigProperty(); property.setName(AttributeStatementHelper.SAML_ATTRIBUTE_NAMEFORMAT); property.setLabel("SAML Attribute NameFormat"); property.setHelpText("SAML Attribute NameFormat. Can be basic, URI reference, or unspecified."); @@ -48,13 +49,13 @@ public class RoleListMapper extends AbstractSAMLProtocolMapper implements SAMLRo types.add(AttributeStatementHelper.BASIC); types.add(AttributeStatementHelper.URI_REFERENCE); types.add(AttributeStatementHelper.UNSPECIFIED); - property.setType(ProtocolMapper.ConfigProperty.LIST_TYPE); + property.setType(ProviderConfigProperty.LIST_TYPE); property.setDefaultValue(types); configProperties.add(property); - property = new ConfigProperty(); + property = new ProviderConfigProperty(); property.setName(SINGLE_ROLE_ATTRIBUTE); property.setLabel("Single Role Attribute"); - property.setType(ConfigProperty.BOOLEAN_TYPE); + property.setType(ProviderConfigProperty.BOOLEAN_TYPE); property.setDefaultValue("true"); property.setHelpText("If true, all roles will be stored under one attribute with multiple attribute values."); configProperties.add(property); @@ -78,7 +79,7 @@ public class RoleListMapper extends AbstractSAMLProtocolMapper implements SAMLRo } @Override - public List getConfigProperties() { + public List getConfigProperties() { return configProperties; } diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/RoleNameMapper.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/RoleNameMapper.java index adde0b8580..1cbf93688c 100755 --- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/RoleNameMapper.java +++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/RoleNameMapper.java @@ -4,6 +4,7 @@ import org.keycloak.models.ApplicationModel; import org.keycloak.models.ProtocolMapperModel; import org.keycloak.models.RoleContainerModel; import org.keycloak.models.RoleModel; +import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.protocol.oidc.mappers.AbstractOIDCProtocolMapper; import org.keycloak.protocol.saml.SamlProtocol; @@ -20,31 +21,31 @@ import java.util.Map; */ public class RoleNameMapper extends AbstractOIDCProtocolMapper implements SAMLRoleNameMapper { - private static final List configProperties = new ArrayList(); + private static final List configProperties = new ArrayList(); public static final String ROLE_CONFIG = "role"; public static String NEW_ROLE_NAME = "new.role.name"; static { - ConfigProperty property; - property = new ConfigProperty(); + ProviderConfigProperty property; + property = new ProviderConfigProperty(); property.setName(ROLE_CONFIG); property.setLabel("Role"); property.setHelpText("Role name you want changed. To reference an application role the syntax is appname.approle, i.e. myapp.myrole"); - property.setType(ConfigProperty.STRING_TYPE); + property.setType(ProviderConfigProperty.STRING_TYPE); configProperties.add(property); - property = new ConfigProperty(); + property = new ProviderConfigProperty(); property.setName(NEW_ROLE_NAME); property.setLabel("New Role Name"); property.setHelpText("The new role name."); - property.setType(ConfigProperty.STRING_TYPE); + property.setType(ProviderConfigProperty.STRING_TYPE); configProperties.add(property); } public static final String PROVIDER_ID = "saml-role-name-mapper"; - public List getConfigProperties() { + public List getConfigProperties() { return configProperties; } diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/UserAttributeStatementMapper.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/UserAttributeStatementMapper.java index a31b5a406f..81d52b2ba5 100755 --- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/UserAttributeStatementMapper.java +++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/UserAttributeStatementMapper.java @@ -7,6 +7,7 @@ import org.keycloak.models.UserModel; import org.keycloak.models.UserSessionModel; import org.keycloak.protocol.ProtocolMapperUtils; import org.keycloak.dom.saml.v2.assertion.AttributeStatementType; +import org.keycloak.provider.ProviderConfigProperty; import java.util.ArrayList; import java.util.List; @@ -18,11 +19,11 @@ import java.util.List; * @version $Revision: 1 $ */ public class UserAttributeStatementMapper extends AbstractSAMLProtocolMapper implements SAMLAttributeStatementMapper { - private static final List configProperties = new ArrayList(); + private static final List configProperties = new ArrayList(); static { - ConfigProperty property; - property = new ConfigProperty(); + ProviderConfigProperty property; + property = new ProviderConfigProperty(); property.setName(ProtocolMapperUtils.USER_ATTRIBUTE); property.setLabel(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_LABEL); property.setHelpText(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_HELP_TEXT); @@ -34,7 +35,7 @@ public class UserAttributeStatementMapper extends AbstractSAMLProtocolMapper imp public static final String PROVIDER_ID = "saml-user-attribute-mapper"; - public List getConfigProperties() { + public List getConfigProperties() { return configProperties; } @Override diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/UserPropertyAttributeStatementMapper.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/UserPropertyAttributeStatementMapper.java index c9596d0d73..3034624102 100755 --- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/UserPropertyAttributeStatementMapper.java +++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/UserPropertyAttributeStatementMapper.java @@ -7,6 +7,7 @@ import org.keycloak.models.UserModel; import org.keycloak.models.UserSessionModel; import org.keycloak.protocol.ProtocolMapperUtils; import org.keycloak.dom.saml.v2.assertion.AttributeStatementType; +import org.keycloak.provider.ProviderConfigProperty; import java.util.ArrayList; import java.util.List; @@ -18,11 +19,11 @@ import java.util.List; * @version $Revision: 1 $ */ public class UserPropertyAttributeStatementMapper extends AbstractSAMLProtocolMapper implements SAMLAttributeStatementMapper { - private static final List configProperties = new ArrayList(); + private static final List configProperties = new ArrayList(); static { - ConfigProperty property; - property = new ConfigProperty(); + ProviderConfigProperty property; + property = new ProviderConfigProperty(); property.setName(ProtocolMapperUtils.USER_ATTRIBUTE); property.setLabel(ProtocolMapperUtils.USER_MODEL_PROPERTY_LABEL); property.setHelpText(ProtocolMapperUtils.USER_MODEL_PROPERTY_HELP_TEXT); @@ -34,7 +35,7 @@ public class UserPropertyAttributeStatementMapper extends AbstractSAMLProtocolMa public static final String PROVIDER_ID = "saml-user-property-mapper"; - public List getConfigProperties() { + public List getConfigProperties() { return configProperties; } @Override diff --git a/services/src/main/java/org/keycloak/protocol/ProtocolMapper.java b/services/src/main/java/org/keycloak/protocol/ProtocolMapper.java index d986decd59..2016d5d99b 100755 --- a/services/src/main/java/org/keycloak/protocol/ProtocolMapper.java +++ b/services/src/main/java/org/keycloak/protocol/ProtocolMapper.java @@ -1,71 +1,16 @@ package org.keycloak.protocol; +import org.keycloak.provider.ConfiguredProvider; import org.keycloak.provider.Provider; import org.keycloak.provider.ProviderFactory; -import java.util.List; - /** * @author Bill Burke * @version $Revision: 1 $ */ -public interface ProtocolMapper extends Provider, ProviderFactory { +public interface ProtocolMapper extends Provider, ProviderFactory,ConfiguredProvider { String getProtocol(); String getDisplayCategory(); String getDisplayType(); - String getHelpText(); - public static class ConfigProperty { - public static final String BOOLEAN_TYPE="boolean"; - public static final String STRING_TYPE="String"; - public static final String LIST_TYPE="List"; - - protected String name; - protected String label; - protected String helpText; - protected String type; - protected Object defaultValue; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getLabel() { - return label; - } - - public void setLabel(String label) { - this.label = label; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public Object getDefaultValue() { - return defaultValue; - } - - public void setDefaultValue(Object defaultValue) { - this.defaultValue = defaultValue; - } - - public String getHelpText() { - return helpText; - } - - public void setHelpText(String helpText) { - this.helpText = helpText; - } - } - - List getConfigProperties(); } 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 fa95be176c..5ebff0d8ef 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 @@ -6,6 +6,7 @@ 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; @@ -23,21 +24,21 @@ import java.util.Map; */ public class AddressMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper { - private static final List configProperties = new ArrayList(); + private static final List configProperties = new ArrayList(); static { - ConfigProperty property; - property = new ConfigProperty(); + ProviderConfigProperty property; + property = new ProviderConfigProperty(); property.setName(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN); property.setLabel(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN_LABEL); - property.setType(ConfigProperty.BOOLEAN_TYPE); + property.setType(ProviderConfigProperty.BOOLEAN_TYPE); property.setDefaultValue("true"); property.setHelpText(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN_HELP_TEXT); configProperties.add(property); - property = new ConfigProperty(); + property = new ProviderConfigProperty(); property.setName(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN); property.setLabel(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN_LABEL); - property.setType(ConfigProperty.BOOLEAN_TYPE); + property.setType(ProviderConfigProperty.BOOLEAN_TYPE); property.setDefaultValue("true"); property.setHelpText(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN_HELP_TEXT); configProperties.add(property); @@ -75,7 +76,7 @@ public class AddressMapper extends AbstractOIDCProtocolMapper implements OIDCAcc } - public List getConfigProperties() { + public List getConfigProperties() { return configProperties; } diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/FullNameMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/FullNameMapper.java index 000f520a8f..caeeedf90b 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/FullNameMapper.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/FullNameMapper.java @@ -7,6 +7,7 @@ import org.keycloak.models.UserModel; import org.keycloak.models.UserSessionModel; import org.keycloak.protocol.ProtocolMapperUtils; import org.keycloak.protocol.oidc.OIDCLoginProtocol; +import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.representations.AccessToken; import org.keycloak.representations.IDToken; @@ -23,21 +24,21 @@ import java.util.Map; */ public class FullNameMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper { - private static final List configProperties = new ArrayList(); + private static final List configProperties = new ArrayList(); static { - ConfigProperty property; - property = new ConfigProperty(); + ProviderConfigProperty property; + property = new ProviderConfigProperty(); property.setName(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN); property.setLabel(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN_LABEL); - property.setType(ConfigProperty.BOOLEAN_TYPE); + property.setType(ProviderConfigProperty.BOOLEAN_TYPE); property.setDefaultValue("true"); property.setHelpText(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN_HELP_TEXT); configProperties.add(property); - property = new ConfigProperty(); + property = new ProviderConfigProperty(); property.setName(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN); property.setLabel(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN_LABEL); - property.setType(ConfigProperty.BOOLEAN_TYPE); + property.setType(ProviderConfigProperty.BOOLEAN_TYPE); property.setDefaultValue("true"); property.setHelpText(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN_HELP_TEXT); configProperties.add(property); @@ -47,7 +48,7 @@ public class FullNameMapper extends AbstractOIDCProtocolMapper implements OIDCAc public static final String PROVIDER_ID = "oidc-full-name-mapper"; - public List getConfigProperties() { + public List getConfigProperties() { return configProperties; } diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/HardcodedClaim.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/HardcodedClaim.java index ecea9e8a91..f0bebf62ef 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/HardcodedClaim.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/HardcodedClaim.java @@ -8,6 +8,7 @@ import org.keycloak.models.UserSessionModel; import org.keycloak.protocol.ProtocolMapper; import org.keycloak.protocol.ProtocolMapperUtils; import org.keycloak.protocol.oidc.OIDCLoginProtocol; +import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.representations.AccessToken; import org.keycloak.representations.IDToken; @@ -24,25 +25,25 @@ import java.util.Map; */ public class HardcodedClaim extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper { - private static final List configProperties = new ArrayList(); + private static final List configProperties = new ArrayList(); public static final String CLAIM_VALUE = "claim.value"; static { - ConfigProperty property; - property = new ConfigProperty(); + ProviderConfigProperty property; + property = new ProviderConfigProperty(); property.setName(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME); property.setLabel(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME_LABEL); - property.setType(ConfigProperty.STRING_TYPE); + property.setType(ProviderConfigProperty.STRING_TYPE); property.setHelpText("Claim name you want to hard code into the token. This can be a fully qualified name like 'address.street'. In this case, a nested json object will be created."); configProperties.add(property); - property = new ConfigProperty(); + property = new ProviderConfigProperty(); property.setName(CLAIM_VALUE); property.setLabel("Claim value"); - property.setType(ConfigProperty.STRING_TYPE); + property.setType(ProviderConfigProperty.STRING_TYPE); property.setHelpText("Value of the claim you want to hard code. 'true' and 'false can be used for boolean values."); configProperties.add(property); - property = new ConfigProperty(); + property = new ProviderConfigProperty(); property.setName(OIDCAttributeMapperHelper.JSON_TYPE); property.setLabel(OIDCAttributeMapperHelper.JSON_TYPE); List types = new ArrayList(3); @@ -50,21 +51,21 @@ public class HardcodedClaim extends AbstractOIDCProtocolMapper implements OIDCAc types.add("long"); types.add("int"); types.add("boolean"); - property.setType(ProtocolMapper.ConfigProperty.LIST_TYPE); + property.setType(ProviderConfigProperty.LIST_TYPE); property.setDefaultValue(types); property.setHelpText("JSON type that should be used for the value of the claim. long, int, boolean, and String are valid values."); configProperties.add(property); - property = new ConfigProperty(); + property = new ProviderConfigProperty(); property.setName(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN); property.setLabel(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN_LABEL); - property.setType(ConfigProperty.BOOLEAN_TYPE); + property.setType(ProviderConfigProperty.BOOLEAN_TYPE); property.setDefaultValue("true"); property.setHelpText(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN_HELP_TEXT); configProperties.add(property); - property = new ConfigProperty(); + property = new ProviderConfigProperty(); property.setName(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN); property.setLabel(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN_LABEL); - property.setType(ConfigProperty.BOOLEAN_TYPE); + property.setType(ProviderConfigProperty.BOOLEAN_TYPE); property.setDefaultValue("true"); property.setHelpText(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN_HELP_TEXT); configProperties.add(property); @@ -74,7 +75,7 @@ public class HardcodedClaim extends AbstractOIDCProtocolMapper implements OIDCAc public static final String PROVIDER_ID = "oidc-hardcoded-claim-mapper"; - public List getConfigProperties() { + public List getConfigProperties() { return configProperties; } diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/HardcodedRole.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/HardcodedRole.java index 088389fbec..fd1910fda8 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/HardcodedRole.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/HardcodedRole.java @@ -6,6 +6,7 @@ import org.keycloak.models.ProtocolMapperModel; import org.keycloak.models.UserSessionModel; import org.keycloak.protocol.ProtocolMapperUtils; import org.keycloak.protocol.oidc.OIDCLoginProtocol; +import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.representations.AccessToken; import java.util.ArrayList; @@ -21,24 +22,24 @@ import java.util.Map; */ public class HardcodedRole extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper { - private static final List configProperties = new ArrayList(); + private static final List configProperties = new ArrayList(); public static final String ROLE_CONFIG = "role"; static { - ConfigProperty property; - property = new ConfigProperty(); + ProviderConfigProperty property; + property = new ProviderConfigProperty(); property.setName(ROLE_CONFIG); property.setLabel("Role"); property.setHelpText("Role you want added to the token. To specify an application role the syntax is appname.approle, i.e. myapp.myrole"); - property.setType(ConfigProperty.STRING_TYPE); + property.setType(ProviderConfigProperty.STRING_TYPE); configProperties.add(property); } public static final String PROVIDER_ID = "oidc-hardcoded-role-mapper"; - public List getConfigProperties() { + public List getConfigProperties() { return configProperties; } diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAttributeMapperHelper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAttributeMapperHelper.java index 7635a4bc3e..bae8c08abd 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAttributeMapperHelper.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAttributeMapperHelper.java @@ -5,6 +5,7 @@ import org.keycloak.models.RealmModel; import org.keycloak.protocol.ProtocolMapper; import org.keycloak.protocol.ProtocolMapperUtils; import org.keycloak.protocol.oidc.OIDCLoginProtocol; +import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.representations.AccessToken; import org.keycloak.representations.IDToken; @@ -101,15 +102,15 @@ public class OIDCAttributeMapperHelper { return "true".equals(mappingModel.getConfig().get(INCLUDE_IN_ACCESS_TOKEN)); } - public static void addAttributeConfig(List configProperties) { - ProtocolMapper.ConfigProperty property; - property = new ProtocolMapper.ConfigProperty(); + public static void addAttributeConfig(List configProperties) { + ProviderConfigProperty property; + property = new ProviderConfigProperty(); property.setName(TOKEN_CLAIM_NAME); property.setLabel(TOKEN_CLAIM_NAME_LABEL); - property.setType(ProtocolMapper.ConfigProperty.STRING_TYPE); + property.setType(ProviderConfigProperty.STRING_TYPE); property.setHelpText("Name of the claim to insert into the token. This can be a fully qualified name like 'address.street'. In this case, a nested json object will be created."); configProperties.add(property); - property = new ProtocolMapper.ConfigProperty(); + property = new ProviderConfigProperty(); property.setName(JSON_TYPE); property.setLabel(JSON_TYPE); List types = new ArrayList(3); @@ -117,21 +118,21 @@ public class OIDCAttributeMapperHelper { types.add("long"); types.add("int"); types.add("boolean"); - property.setType(ProtocolMapper.ConfigProperty.LIST_TYPE); + property.setType(ProviderConfigProperty.LIST_TYPE); property.setDefaultValue(types); property.setHelpText("JSON type that should be used to populate the json claim in the token. long, int, boolean, and String are valid values."); configProperties.add(property); - property = new ProtocolMapper.ConfigProperty(); + property = new ProviderConfigProperty(); property.setName(INCLUDE_IN_ID_TOKEN); property.setLabel(INCLUDE_IN_ID_TOKEN_LABEL); - property.setType(ProtocolMapper.ConfigProperty.BOOLEAN_TYPE); + property.setType(ProviderConfigProperty.BOOLEAN_TYPE); property.setDefaultValue("true"); property.setHelpText(INCLUDE_IN_ID_TOKEN_HELP_TEXT); configProperties.add(property); - property = new ProtocolMapper.ConfigProperty(); + property = new ProviderConfigProperty(); property.setName(INCLUDE_IN_ACCESS_TOKEN); property.setLabel(INCLUDE_IN_ACCESS_TOKEN_LABEL); - property.setType(ProtocolMapper.ConfigProperty.BOOLEAN_TYPE); + property.setType(ProviderConfigProperty.BOOLEAN_TYPE); property.setDefaultValue("true"); property.setHelpText(INCLUDE_IN_ACCESS_TOKEN_HELP_TEXT); configProperties.add(property); diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/RoleNameMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/RoleNameMapper.java index 1e5784cce7..35bb712eb5 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/RoleNameMapper.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/RoleNameMapper.java @@ -7,6 +7,7 @@ import org.keycloak.models.UserModel; import org.keycloak.models.UserSessionModel; import org.keycloak.protocol.ProtocolMapperUtils; import org.keycloak.protocol.oidc.OIDCLoginProtocol; +import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.representations.AccessToken; import org.keycloak.representations.IDToken; @@ -23,31 +24,31 @@ import java.util.Map; */ public class RoleNameMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper { - private static final List configProperties = new ArrayList(); + private static final List configProperties = new ArrayList(); public static final String ROLE_CONFIG = "role"; public static String NEW_ROLE_NAME = "new.role.name"; static { - ConfigProperty property; - property = new ConfigProperty(); + ProviderConfigProperty property; + property = new ProviderConfigProperty(); property.setName(ROLE_CONFIG); property.setLabel("Role"); property.setHelpText("Role name you want changed. To reference an application role the syntax is appname.approle, i.e. myapp.myrole"); - property.setType(ConfigProperty.STRING_TYPE); + property.setType(ProviderConfigProperty.STRING_TYPE); configProperties.add(property); - property = new ConfigProperty(); + property = new ProviderConfigProperty(); property.setName(NEW_ROLE_NAME); property.setLabel("New Role Name"); property.setHelpText("The new role name. The new name format corresponds to where in the access token the role will be mapped to. So, a new name of 'myapp.newname' will map the role to that position in the access token. A new name of 'newname' will map the role to the realm roles in the token."); - property.setType(ConfigProperty.STRING_TYPE); + property.setType(ProviderConfigProperty.STRING_TYPE); configProperties.add(property); } public static final String PROVIDER_ID = "oidc-role-name-mapper"; - public List getConfigProperties() { + public List getConfigProperties() { return configProperties; } diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserAttributeMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserAttributeMapper.java index b38283c262..b8543510d6 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserAttributeMapper.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserAttributeMapper.java @@ -7,6 +7,7 @@ import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; import org.keycloak.models.UserSessionModel; import org.keycloak.protocol.ProtocolMapperUtils; +import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.representations.AccessToken; import org.keycloak.representations.IDToken; @@ -23,15 +24,15 @@ import java.util.List; */ public class UserAttributeMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper { - private static final List configProperties = new ArrayList(); + private static final List configProperties = new ArrayList(); static { - ConfigProperty property; - property = new ConfigProperty(); + ProviderConfigProperty property; + property = new ProviderConfigProperty(); property.setName(ProtocolMapperUtils.USER_ATTRIBUTE); property.setLabel(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_LABEL); property.setHelpText(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_HELP_TEXT); - property.setType(ConfigProperty.STRING_TYPE); + property.setType(ProviderConfigProperty.STRING_TYPE); configProperties.add(property); OIDCAttributeMapperHelper.addAttributeConfig(configProperties); @@ -40,7 +41,7 @@ public class UserAttributeMapper extends AbstractOIDCProtocolMapper implements O public static final String PROVIDER_ID = "oidc-usermodel-attribute-mapper"; - public List getConfigProperties() { + public List getConfigProperties() { return configProperties; } 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 15573ac499..8b5eb2f42c 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 @@ -6,6 +6,7 @@ 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 org.keycloak.representations.AccessToken; import org.keycloak.representations.IDToken; @@ -21,14 +22,14 @@ import java.util.List; * @version $Revision: 1 $ */ public class UserPropertyMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper { - private static final List configProperties = new ArrayList(); + private static final List configProperties = new ArrayList(); static { - ConfigProperty property; - property = new ConfigProperty(); + ProviderConfigProperty property; + property = new ProviderConfigProperty(); property.setName(ProtocolMapperUtils.USER_ATTRIBUTE); property.setLabel(ProtocolMapperUtils.USER_MODEL_PROPERTY_LABEL); - property.setType(ConfigProperty.STRING_TYPE); + property.setType(ProviderConfigProperty.STRING_TYPE); property.setHelpText(ProtocolMapperUtils.USER_MODEL_PROPERTY_HELP_TEXT); configProperties.add(property); OIDCAttributeMapperHelper.addAttributeConfig(configProperties); @@ -37,7 +38,7 @@ public class UserPropertyMapper extends AbstractOIDCProtocolMapper implements OI public static final String PROVIDER_ID = "oidc-usermodel-property-mapper"; - public List getConfigProperties() { + public List getConfigProperties() { return configProperties; } diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserSessionNoteMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserSessionNoteMapper.java index 45b22bf3b4..1539e24d84 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserSessionNoteMapper.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserSessionNoteMapper.java @@ -1,134 +1,135 @@ -package org.keycloak.protocol.oidc.mappers; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.keycloak.models.ClientSessionModel; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.ProtocolMapperModel; -import org.keycloak.models.UserSessionModel; -import org.keycloak.protocol.ProtocolMapperUtils; -import org.keycloak.protocol.oidc.OIDCLoginProtocol; -import org.keycloak.representations.AccessToken; -import org.keycloak.representations.IDToken; - -/** - * Mappings UserSessionModel.note to an ID Token claim. - * - * @author Marek Posolda - */ -public class UserSessionNoteMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper { - - private static final List configProperties = new ArrayList(); - - static { - ConfigProperty property; - property = new ConfigProperty(); - property.setName(ProtocolMapperUtils.USER_SESSION_NOTE); - property.setLabel(ProtocolMapperUtils.USER_SESSION_MODEL_NOTE_LABEL); - property.setHelpText(ProtocolMapperUtils.USER_SESSION_MODEL_NOTE_HELP_TEXT); - property.setType(ConfigProperty.STRING_TYPE); - configProperties.add(property); - property = new ConfigProperty(); - property.setName(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME); - property.setLabel(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME_LABEL); - property.setType(ConfigProperty.STRING_TYPE); - property.setHelpText("Name of the claim to insert into the token. This can be a fully qualified name like 'address.street'. In this case, a nested json object will be created."); - configProperties.add(property); - property = new ConfigProperty(); - property.setName(OIDCAttributeMapperHelper.JSON_TYPE); - property.setLabel(OIDCAttributeMapperHelper.JSON_TYPE); - property.setType(ConfigProperty.STRING_TYPE); - property.setDefaultValue(ConfigProperty.STRING_TYPE); - property.setHelpText("JSON type that should be used to populate the json claim in the token. long, int, boolean, and String are valid values."); - configProperties.add(property); - property = new ConfigProperty(); - property.setName(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN); - property.setLabel(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN_LABEL); - property.setType(ConfigProperty.BOOLEAN_TYPE); - property.setDefaultValue("true"); - property.setHelpText(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN_HELP_TEXT); - configProperties.add(property); - property = new ConfigProperty(); - property.setName(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN); - property.setLabel(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN_LABEL); - property.setType(ConfigProperty.BOOLEAN_TYPE); - property.setDefaultValue("true"); - property.setHelpText(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN_HELP_TEXT); - configProperties.add(property); - - } - - public static final String PROVIDER_ID = "oidc-usersessionmodel-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 TOKEN_MAPPER_CATEGORY; - } - - @Override - public String getHelpText() { - return "Map a custom user session note to a token claim."; - } - - @Override - public AccessToken transformAccessToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session, - UserSessionModel userSession, ClientSessionModel clientSession) { - if (!OIDCAttributeMapperHelper.includeInAccessToken(mappingModel)) return token; - - setClaim(token, mappingModel, userSession); - return token; - } - - protected void setClaim(IDToken token, ProtocolMapperModel mappingModel, UserSessionModel userSession) { - String noteName = mappingModel.getConfig().get(ProtocolMapperUtils.USER_SESSION_NOTE); - String noteValue = userSession.getNote(noteName); - if (noteValue == null) return; - OIDCAttributeMapperHelper.mapClaim(token, mappingModel, noteValue); - } - - @Override - public IDToken transformIDToken(IDToken token, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession) { - if (!OIDCAttributeMapperHelper.includeInIDToken(mappingModel)) return token; - setClaim(token, mappingModel, userSession); - return token; - } - - public static ProtocolMapperModel createClaimMapper(String name, - String userSessionNote, - String tokenClaimName, String jsonType, - boolean consentRequired, String consentText, - boolean accessToken, boolean idToken) { - ProtocolMapperModel mapper = new ProtocolMapperModel(); - mapper.setName(name); - mapper.setProtocolMapper(PROVIDER_ID); - mapper.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL); - mapper.setConsentRequired(consentRequired); - mapper.setConsentText(consentText); - Map config = new HashMap(); - config.put(ProtocolMapperUtils.USER_SESSION_NOTE, userSessionNote); - config.put(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME, tokenClaimName); - config.put(OIDCAttributeMapperHelper.JSON_TYPE, jsonType); - if (accessToken) config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, "true"); - if (idToken) config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, "true"); - mapper.setConfig(config); - return mapper; - } -} +package org.keycloak.protocol.oidc.mappers; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.keycloak.models.ClientSessionModel; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.ProtocolMapperModel; +import org.keycloak.models.UserSessionModel; +import org.keycloak.protocol.ProtocolMapperUtils; +import org.keycloak.protocol.oidc.OIDCLoginProtocol; +import org.keycloak.provider.ProviderConfigProperty; +import org.keycloak.representations.AccessToken; +import org.keycloak.representations.IDToken; + +/** + * Mappings UserSessionModel.note to an ID Token claim. + * + * @author Marek Posolda + */ +public class UserSessionNoteMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper { + + private static final List configProperties = new ArrayList(); + + static { + ProviderConfigProperty property; + property = new ProviderConfigProperty(); + property.setName(ProtocolMapperUtils.USER_SESSION_NOTE); + property.setLabel(ProtocolMapperUtils.USER_SESSION_MODEL_NOTE_LABEL); + property.setHelpText(ProtocolMapperUtils.USER_SESSION_MODEL_NOTE_HELP_TEXT); + property.setType(ProviderConfigProperty.STRING_TYPE); + configProperties.add(property); + property = new ProviderConfigProperty(); + property.setName(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME); + property.setLabel(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME_LABEL); + property.setType(ProviderConfigProperty.STRING_TYPE); + property.setHelpText("Name of the claim to insert into the token. This can be a fully qualified name like 'address.street'. In this case, a nested json object will be created."); + configProperties.add(property); + property = new ProviderConfigProperty(); + property.setName(OIDCAttributeMapperHelper.JSON_TYPE); + property.setLabel(OIDCAttributeMapperHelper.JSON_TYPE); + property.setType(ProviderConfigProperty.STRING_TYPE); + property.setDefaultValue(ProviderConfigProperty.STRING_TYPE); + property.setHelpText("JSON type that should be used to populate the json claim in the token. long, int, boolean, and String are valid values."); + configProperties.add(property); + property = new ProviderConfigProperty(); + property.setName(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN); + property.setLabel(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN_LABEL); + property.setType(ProviderConfigProperty.BOOLEAN_TYPE); + property.setDefaultValue("true"); + property.setHelpText(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN_HELP_TEXT); + configProperties.add(property); + property = new ProviderConfigProperty(); + property.setName(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN); + property.setLabel(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN_LABEL); + property.setType(ProviderConfigProperty.BOOLEAN_TYPE); + property.setDefaultValue("true"); + property.setHelpText(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN_HELP_TEXT); + configProperties.add(property); + + } + + public static final String PROVIDER_ID = "oidc-usersessionmodel-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 TOKEN_MAPPER_CATEGORY; + } + + @Override + public String getHelpText() { + return "Map a custom user session note to a token claim."; + } + + @Override + public AccessToken transformAccessToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session, + UserSessionModel userSession, ClientSessionModel clientSession) { + if (!OIDCAttributeMapperHelper.includeInAccessToken(mappingModel)) return token; + + setClaim(token, mappingModel, userSession); + return token; + } + + protected void setClaim(IDToken token, ProtocolMapperModel mappingModel, UserSessionModel userSession) { + String noteName = mappingModel.getConfig().get(ProtocolMapperUtils.USER_SESSION_NOTE); + String noteValue = userSession.getNote(noteName); + if (noteValue == null) return; + OIDCAttributeMapperHelper.mapClaim(token, mappingModel, noteValue); + } + + @Override + public IDToken transformIDToken(IDToken token, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession) { + if (!OIDCAttributeMapperHelper.includeInIDToken(mappingModel)) return token; + setClaim(token, mappingModel, userSession); + return token; + } + + public static ProtocolMapperModel createClaimMapper(String name, + String userSessionNote, + String tokenClaimName, String jsonType, + boolean consentRequired, String consentText, + boolean accessToken, boolean idToken) { + ProtocolMapperModel mapper = new ProtocolMapperModel(); + mapper.setName(name); + mapper.setProtocolMapper(PROVIDER_ID); + mapper.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL); + mapper.setConsentRequired(consentRequired); + mapper.setConsentText(consentText); + Map config = new HashMap(); + config.put(ProtocolMapperUtils.USER_SESSION_NOTE, userSessionNote); + config.put(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME, tokenClaimName); + config.put(OIDCAttributeMapperHelper.JSON_TYPE, jsonType); + if (accessToken) config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, "true"); + if (idToken) config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, "true"); + mapper.setConfig(config); + return mapper; + } +} 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 df9771f056..89ce7cc587 100755 --- a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java +++ b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java @@ -22,6 +22,7 @@ import org.jboss.resteasy.spi.HttpRequest; import org.jboss.resteasy.spi.ResteasyProviderFactory; import org.keycloak.ClientConnection; import org.keycloak.broker.provider.AuthenticationRequest; +import org.keycloak.broker.provider.BrokeredIdentityContext; import org.keycloak.broker.provider.FederatedIdentity; import org.keycloak.broker.provider.IdentityBrokerException; import org.keycloak.broker.provider.IdentityProvider; @@ -39,7 +40,6 @@ import org.keycloak.models.OAuthClientModel; import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; import org.keycloak.models.UserSessionModel; -import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.protocol.oidc.TokenManager; import org.keycloak.provider.ProviderFactory; import org.keycloak.services.managers.AppAuthManager; @@ -131,7 +131,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal try { ClientSessionCode clientSessionCode = parseClientSessionCode(code); IdentityProvider identityProvider = getIdentityProvider(session, realmModel, providerId); - Response response = identityProvider.handleRequest(createAuthenticationRequest(providerId, clientSessionCode)); + Response response = identityProvider.performLogin(createAuthenticationRequest(providerId, clientSessionCode)); if (response != null) { this.event.success(); @@ -238,10 +238,11 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal return getToken(providerId, true); } - public Response authenticated(Map userNotes, IdentityProviderModel identityProviderConfig, FederatedIdentity federatedIdentity, String code) { + public Response authenticated(BrokeredIdentityContext context) { ClientSessionCode clientCode = null; + IdentityProviderModel identityProviderConfig = context.getIdpConfig(); try { - clientCode = parseClientSessionCode(code); + clientCode = parseClientSessionCode(context.getCode()); } catch (Exception e) { return redirectToErrorPage(Messages.IDENTITY_PROVIDER_AUTHENTICATION_FAILED, e, identityProviderConfig.getProviderId()); @@ -251,32 +252,27 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal if (isDebugEnabled()) { LOGGER.debugf("Token will not be stored for identity provider [%s].", providerId); } - federatedIdentity.setToken(null); + context.setToken(null); } - federatedIdentity.setIdentityProviderId(providerId); ClientSessionModel clientSession = clientCode.getClientSession(); - FederatedIdentityModel federatedIdentityModel = new FederatedIdentityModel(providerId, federatedIdentity.getId(), - federatedIdentity.getUsername(), federatedIdentity.getToken()); + FederatedIdentityModel federatedIdentityModel = new FederatedIdentityModel(providerId, context.getId(), + context.getUsername(), context.getToken()); this.event.event(EventType.IDENTITY_PROVIDER_LOGIN) .detail(Details.REDIRECT_URI, clientSession.getRedirectUri()) - .detail(Details.IDENTITY_PROVIDER_USERNAME, federatedIdentity.getUsername()); + .detail(Details.IDENTITY_PROVIDER_USERNAME, context.getUsername()); UserModel federatedUser = this.session.users().getUserByFederatedIdentity(federatedIdentityModel, this.realmModel); // Check if federatedUser is already authenticated (this means linking social into existing federatedUser account) if (clientSession.getUserSession() != null) { - UserSessionModel userSession = clientSession.getUserSession(); - for (Map.Entry entry : userNotes.entrySet()) { - userSession.setNote(entry.getKey(), entry.getValue()); - } - return performAccountLinking(clientSession, providerId, federatedIdentityModel, federatedUser); + return performAccountLinking(clientSession, context, federatedIdentityModel, federatedUser); } if (federatedUser == null) { try { - federatedUser = createUser(federatedIdentity); + federatedUser = createUser(context); if (identityProviderConfig.isUpdateProfileFirstLogin()) { if (isDebugEnabled()) { @@ -289,18 +285,16 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal } } - updateFederatedIdentity(federatedIdentity, federatedUser); + updateFederatedIdentity(context, federatedUser); UserSessionModel userSession = this.session.sessions() - .createUserSession(this.realmModel, federatedUser, federatedUser.getUsername(), this.clientConnection.getRemoteAddr(), "broker", false, federatedIdentity.getBrokerSessionId(), federatedIdentity.getBrokerUserId()); + .createUserSession(this.realmModel, federatedUser, federatedUser.getUsername(), this.clientConnection.getRemoteAddr(), "broker", false, context.getBrokerSessionId(), context.getBrokerUserId()); this.event.user(federatedUser); this.event.session(userSession); TokenManager.attachClientSession(userSession, clientSession); - for (Map.Entry entry : userNotes.entrySet()) { - userSession.setNote(entry.getKey(), entry.getValue()); - } + context.getIdp().attachUserSession(userSession, clientSession, context); userSession.setNote(BROKER_PROVIDER_ID, providerId); if (isDebugEnabled()) { @@ -311,17 +305,17 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal this.uriInfo, event); } - private Response performAccountLinking(ClientSessionModel clientSession, String providerId, FederatedIdentityModel federatedIdentityModel, UserModel federatedUser) { + private Response performAccountLinking(ClientSessionModel clientSession, BrokeredIdentityContext context, FederatedIdentityModel federatedIdentityModel, UserModel federatedUser) { this.event.event(EventType.IDENTITY_PROVIDER_ACCCOUNT_LINKING); if (federatedUser != null) { - return redirectToErrorPage(Messages.IDENTITY_PROVIDER_ALREADY_LINKED, providerId); + return redirectToErrorPage(Messages.IDENTITY_PROVIDER_ALREADY_LINKED, context.getIdpConfig().getAlias()); } UserModel authenticatedUser = clientSession.getUserSession().getUser(); if (isDebugEnabled()) { - LOGGER.debugf("Linking account [%s] from identity provider [%s] to user [%s].", federatedIdentityModel, providerId, authenticatedUser); + LOGGER.debugf("Linking account [%s] from identity provider [%s] to user [%s].", federatedIdentityModel, context.getIdpConfig().getAlias(), authenticatedUser); } if (!authenticatedUser.isEnabled()) { @@ -335,14 +329,14 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal } this.session.users().addFederatedIdentity(this.realmModel, authenticatedUser, federatedIdentityModel); + context.getIdp().attachUserSession(clientSession.getUserSession(), clientSession, context); this.event.success(); - return Response.status(302).location(UriBuilder.fromUri(clientSession.getRedirectUri()).build()).build(); } - private void updateFederatedIdentity(FederatedIdentity updatedIdentity, UserModel federatedUser) { - FederatedIdentityModel federatedIdentityModel = this.session.users().getFederatedIdentity(federatedUser, updatedIdentity.getIdentityProviderId(), this.realmModel); + private void updateFederatedIdentity(BrokeredIdentityContext updatedIdentity, UserModel federatedUser) { + FederatedIdentityModel federatedIdentityModel = this.session.users().getFederatedIdentity(federatedUser, updatedIdentity.getIdpConfig().getAlias(), this.realmModel); // Skip DB write if tokens are null or equal if (!ObjectUtil.isEqualOrNull(updatedIdentity.getToken(), federatedIdentityModel.getToken())) { @@ -351,9 +345,10 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal this.session.users().updateFederatedIdentity(this.realmModel, federatedUser, federatedIdentityModel); if (isDebugEnabled()) { - LOGGER.debugf("Identity [%s] update with response from identity provider [%s].", federatedUser, updatedIdentity.getIdentityProviderId()); + LOGGER.debugf("Identity [%s] update with response from identity provider [%s].", federatedUser, updatedIdentity.getIdpConfig().getAlias()); } } + updatedIdentity.getIdp().updateBrokeredUser(federatedUser, updatedIdentity); } private ClientSessionCode parseClientSessionCode(String code) { @@ -475,8 +470,8 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal throw new IdentityBrokerException("Configuration for identity provider [" + providerId + "] not found."); } - private UserModel createUser(FederatedIdentity updatedIdentity) { - FederatedIdentityModel federatedIdentityModel = new FederatedIdentityModel(updatedIdentity.getIdentityProviderId(), updatedIdentity.getId(), + private UserModel createUser(BrokeredIdentityContext updatedIdentity) { + FederatedIdentityModel federatedIdentityModel = new FederatedIdentityModel(updatedIdentity.getIdpConfig().getAlias(), updatedIdentity.getId(), updatedIdentity.getUsername(), updatedIdentity.getToken()); // Check if no user already exists with this username or email UserModel existingUser = null; @@ -494,9 +489,9 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal if (this.realmModel.isRegistrationEmailAsUsername() && !Validation.isEmpty(updatedIdentity.getEmail())) { username = updatedIdentity.getEmail(); } else if (username == null) { - username = updatedIdentity.getIdentityProviderId() + "." + updatedIdentity.getId(); + username = updatedIdentity.getIdpConfig().getAlias() + "." + updatedIdentity.getId(); } else { - username = updatedIdentity.getIdentityProviderId() + "." + updatedIdentity.getUsername(); + username = updatedIdentity.getIdpConfig().getAlias() + "." + updatedIdentity.getUsername(); } if (username != null) { username = username.trim(); @@ -520,12 +515,14 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal } federatedUser.setEnabled(true); + federatedUser.setEmail(updatedIdentity.getEmail()); federatedUser.setFirstName(updatedIdentity.getFirstName()); federatedUser.setLastName(updatedIdentity.getLastName()); - federatedUser.setEmail(updatedIdentity.getEmail()); this.session.users().addFederatedIdentity(this.realmModel, federatedUser, federatedIdentityModel); + updatedIdentity.getIdp().importNewUser(federatedUser, updatedIdentity); + this.event.clone().user(federatedUser).event(EventType.REGISTER) .detail(Details.IDENTITY_PROVIDER, federatedIdentityModel.getIdentityProvider()) .detail(Details.IDENTITY_PROVIDER_USERNAME, updatedIdentity.getUsername()) diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java index ec72cc146f..acaa0b84d7 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java @@ -15,6 +15,7 @@ import org.keycloak.models.utils.ModelToRepresentation; import org.keycloak.protocol.LoginProtocol; import org.keycloak.protocol.LoginProtocolFactory; import org.keycloak.protocol.ProtocolMapper; +import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.provider.ProviderFactory; import org.keycloak.provider.Spi; import org.keycloak.representations.idm.ProtocolMapperRepresentation; @@ -142,7 +143,7 @@ public class ServerInfoAdminResource { rep.setHelpText(mapper.getHelpText()); rep.setCategory(mapper.getDisplayCategory()); rep.setProperties(new LinkedList()); - for (ProtocolMapper.ConfigProperty prop : mapper.getConfigProperties()) { + for (ProviderConfigProperty prop : mapper.getConfigProperties()) { ProtocolMapperTypeRepresentation.ConfigProperty propRep = new ProtocolMapperTypeRepresentation.ConfigProperty(); propRep.setName(prop.getName()); propRep.setLabel(prop.getLabel()); diff --git a/social/facebook/src/main/java/org/keycloak/social/facebook/FacebookIdentityProvider.java b/social/facebook/src/main/java/org/keycloak/social/facebook/FacebookIdentityProvider.java index de54cc5c72..4fc319a660 100755 --- a/social/facebook/src/main/java/org/keycloak/social/facebook/FacebookIdentityProvider.java +++ b/social/facebook/src/main/java/org/keycloak/social/facebook/FacebookIdentityProvider.java @@ -4,6 +4,7 @@ import org.codehaus.jackson.JsonNode; import org.keycloak.broker.oidc.AbstractOAuth2IdentityProvider; import org.keycloak.broker.oidc.OAuth2IdentityProviderConfig; import org.keycloak.broker.oidc.util.SimpleHttp; +import org.keycloak.broker.provider.BrokeredIdentityContext; import org.keycloak.broker.provider.FederatedIdentity; import org.keycloak.broker.provider.IdentityBrokerException; import org.keycloak.social.SocialIdentityProvider; @@ -25,13 +26,13 @@ public class FacebookIdentityProvider extends AbstractOAuth2IdentityProvider imp config.setUserInfoUrl(PROFILE_URL); } - protected FederatedIdentity doGetFederatedIdentity(String accessToken) { + protected BrokeredIdentityContext doGetFederatedIdentity(String accessToken) { try { JsonNode profile = SimpleHttp.doGet(PROFILE_URL).header("Authorization", "Bearer " + accessToken).asJson(); String id = getJsonProperty(profile, "id"); - FederatedIdentity user = new FederatedIdentity(id); + BrokeredIdentityContext user = new BrokeredIdentityContext(id); String email = getJsonProperty(profile, "email"); @@ -59,6 +60,8 @@ public class FacebookIdentityProvider extends AbstractOAuth2IdentityProvider imp } user.setName(firstName + lastName); + user.setIdpConfig(getConfig()); + user.setIdp(this); return user; } catch (Exception e) { diff --git a/social/github/src/main/java/org/keycloak/social/github/GitHubIdentityProvider.java b/social/github/src/main/java/org/keycloak/social/github/GitHubIdentityProvider.java index d3ff667d04..978b4fe0b2 100755 --- a/social/github/src/main/java/org/keycloak/social/github/GitHubIdentityProvider.java +++ b/social/github/src/main/java/org/keycloak/social/github/GitHubIdentityProvider.java @@ -4,6 +4,7 @@ import org.codehaus.jackson.JsonNode; import org.keycloak.broker.oidc.AbstractOAuth2IdentityProvider; import org.keycloak.broker.oidc.OAuth2IdentityProviderConfig; import org.keycloak.broker.oidc.util.SimpleHttp; +import org.keycloak.broker.provider.BrokeredIdentityContext; import org.keycloak.broker.provider.FederatedIdentity; import org.keycloak.broker.provider.IdentityBrokerException; import org.keycloak.social.SocialIdentityProvider; @@ -26,15 +27,17 @@ public class GitHubIdentityProvider extends AbstractOAuth2IdentityProvider imple } @Override - protected FederatedIdentity doGetFederatedIdentity(String accessToken) { + protected BrokeredIdentityContext doGetFederatedIdentity(String accessToken) { try { JsonNode profile = SimpleHttp.doGet(PROFILE_URL).header("Authorization", "Bearer " + accessToken).asJson(); - FederatedIdentity user = new FederatedIdentity(getJsonProperty(profile, "id")); + BrokeredIdentityContext user = new BrokeredIdentityContext(getJsonProperty(profile, "id")); user.setUsername(getJsonProperty(profile, "login")); user.setName(getJsonProperty(profile, "name")); user.setEmail(getJsonProperty(profile, "email")); + user.setIdpConfig(getConfig()); + user.setIdp(this); return user; } catch (Exception e) { diff --git a/social/linkedin/src/main/java/org/keycloak/social/linkedin/LinkedInIdentityProvider.java b/social/linkedin/src/main/java/org/keycloak/social/linkedin/LinkedInIdentityProvider.java index 298612e6b1..9283ce541e 100755 --- a/social/linkedin/src/main/java/org/keycloak/social/linkedin/LinkedInIdentityProvider.java +++ b/social/linkedin/src/main/java/org/keycloak/social/linkedin/LinkedInIdentityProvider.java @@ -26,6 +26,7 @@ import org.jboss.logging.Logger; import org.keycloak.broker.oidc.AbstractOAuth2IdentityProvider; import org.keycloak.broker.oidc.OAuth2IdentityProviderConfig; import org.keycloak.broker.oidc.util.SimpleHttp; +import org.keycloak.broker.provider.BrokeredIdentityContext; import org.keycloak.broker.provider.FederatedIdentity; import org.keycloak.broker.provider.IdentityBrokerException; import org.keycloak.social.SocialIdentityProvider; @@ -52,18 +53,20 @@ public class LinkedInIdentityProvider extends AbstractOAuth2IdentityProvider imp } @Override - protected FederatedIdentity doGetFederatedIdentity(String accessToken) { + protected BrokeredIdentityContext doGetFederatedIdentity(String accessToken) { log.debug("doGetFederatedIdentity()"); try { JsonNode profile = SimpleHttp.doGet(PROFILE_URL).header("Authorization", "Bearer " + accessToken).asJson(); - FederatedIdentity user = new FederatedIdentity(getJsonProperty(profile, "id")); + BrokeredIdentityContext user = new BrokeredIdentityContext(getJsonProperty(profile, "id")); user.setUsername(extractUsernameFromProfileURL(getJsonProperty(profile, "publicProfileUrl"))); user.setName(getJsonProperty(profile, "formattedName")); user.setEmail(getJsonProperty(profile, "emailAddress")); + user.setIdpConfig(getConfig()); + user.setIdp(this); - return user; + return user; } catch (Exception e) { throw new IdentityBrokerException("Could not obtain user profile from github.", e); } diff --git a/social/stackoverflow/src/main/java/org/keycloak/social/stackoverflow/StackoverflowIdentityProvider.java b/social/stackoverflow/src/main/java/org/keycloak/social/stackoverflow/StackoverflowIdentityProvider.java index 40fb32f2cd..4ee77e85cb 100755 --- a/social/stackoverflow/src/main/java/org/keycloak/social/stackoverflow/StackoverflowIdentityProvider.java +++ b/social/stackoverflow/src/main/java/org/keycloak/social/stackoverflow/StackoverflowIdentityProvider.java @@ -27,6 +27,7 @@ import org.codehaus.jackson.JsonNode; import org.jboss.logging.Logger; import org.keycloak.broker.oidc.AbstractOAuth2IdentityProvider; import org.keycloak.broker.oidc.util.SimpleHttp; +import org.keycloak.broker.provider.BrokeredIdentityContext; import org.keycloak.broker.provider.FederatedIdentity; import org.keycloak.broker.provider.IdentityBrokerException; import org.keycloak.social.SocialIdentityProvider; @@ -53,8 +54,10 @@ public class StackoverflowIdentityProvider extends AbstractOAuth2IdentityProvide config.setUserInfoUrl(PROFILE_URL); } + + @Override - protected FederatedIdentity doGetFederatedIdentity(String accessToken) { + protected BrokeredIdentityContext doGetFederatedIdentity(String accessToken) { log.debug("doGetFederatedIdentity()"); try { @@ -64,14 +67,17 @@ public class StackoverflowIdentityProvider extends AbstractOAuth2IdentityProvide } JsonNode profile = SimpleHttp.doGet(URL).asJson().get("items").get(0); - FederatedIdentity user = new FederatedIdentity(getJsonProperty(profile, "user_id")); + BrokeredIdentityContext user = new BrokeredIdentityContext(getJsonProperty(profile, "user_id")); user.setUsername(extractUsernameFromProfileURL(getJsonProperty(profile, "link"))); user.setName(unescapeHtml3(getJsonProperty(profile, "display_name"))); // email is not provided // user.setEmail(getJsonProperty(profile, "email")); + user.setIdpConfig(getConfig()); + user.setIdp(this); - return user; + + return user; } catch (Exception e) { throw new IdentityBrokerException("Could not obtain user profile from Stackoverflow: " + e.getMessage(), e); } diff --git a/social/twitter/src/main/java/org/keycloak/social/twitter/TwitterIdentityProvider.java b/social/twitter/src/main/java/org/keycloak/social/twitter/TwitterIdentityProvider.java index fea19e9ded..f8aebe22c6 100755 --- a/social/twitter/src/main/java/org/keycloak/social/twitter/TwitterIdentityProvider.java +++ b/social/twitter/src/main/java/org/keycloak/social/twitter/TwitterIdentityProvider.java @@ -26,6 +26,7 @@ import org.keycloak.ClientConnection; import org.keycloak.broker.oidc.OAuth2IdentityProviderConfig; import org.keycloak.broker.provider.AbstractIdentityProvider; import org.keycloak.broker.provider.AuthenticationRequest; +import org.keycloak.broker.provider.BrokeredIdentityContext; import org.keycloak.broker.provider.FederatedIdentity; import org.keycloak.broker.provider.IdentityBrokerException; import org.keycloak.events.EventBuilder; @@ -35,6 +36,8 @@ import org.keycloak.models.ClientSessionModel; import org.keycloak.models.FederatedIdentityModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; +import org.keycloak.models.UserModel; +import org.keycloak.models.UserSessionModel; import org.keycloak.services.managers.ClientSessionCode; import org.keycloak.services.messages.Messages; import org.keycloak.services.resources.flows.Flows; @@ -73,7 +76,7 @@ public class TwitterIdentityProvider extends AbstractIdentityProvider(), getConfig(), identity, state); + return callback.authenticated(identity); } catch (Exception e) { logger.error("Could get user profile from twitter.", e); } diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/provider/CustomIdentityProvider.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/provider/CustomIdentityProvider.java index f7859260ad..c0e8194314 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/provider/CustomIdentityProvider.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/provider/CustomIdentityProvider.java @@ -34,7 +34,7 @@ public class CustomIdentityProvider extends AbstractIdentityProvider Date: Wed, 15 Apr 2015 11:10:53 -0400 Subject: [PATCH 2/2] broker mapper mgmt --- .../provider/AbstractIdentityProvider.java | 5 +- .../broker/provider/FederatedIdentity.java | 135 ------------------ .../broker/provider/IdentityProvider.java | 18 +-- .../provider/IdentityProviderMapper.java | 24 ++++ .../provider/IdentityProviderMapperSpi.java | 27 ++++ .../services/org.keycloak.provider.Spi | 3 +- .../oidc/AbstractOAuth2IdentityProvider.java | 6 - .../oidc/KeycloakOIDCIdentityProvider.java | 2 + .../KeycloakOIDCIdentityProviderFactory.java | 3 - .../broker/oidc/OIDCIdentityProvider.java | 26 +--- .../oidc/OIDCIdentityProviderFactory.java | 2 - .../AbstractOAuth2IdentityProviderTest.java | 9 +- .../keycloak/broker/saml/SAMLEndpoint.java | 27 ++-- .../broker/saml/SAMLIdentityProvider.java | 10 -- .../saml/SAMLIdentityProviderFactory.java | 10 +- .../representations/AddressClaimSet.java | 19 ++- .../org/keycloak/representations/IDToken.java | 82 ++++++----- .../representations/JsonWebToken.java | 20 +++ .../idm/ConfigPropertyRepresentation.java | 53 +++++++ .../IdentityProviderMapperRepresentation.java | 57 ++++++++ ...ntityProviderMapperTypeRepresentation.java | 56 ++++++++ .../idm/ProtocolMapperTypeRepresentation.java | 54 +------ .../models/utils/ModelToRepresentation.java | 14 ++ .../models/utils/RepresentationToModel.java | 12 ++ .../resources/IdentityBrokerService.java | 28 +++- .../admin/IdentityProviderResource.java | 109 ++++++++++++++ .../admin/ServerInfoAdminResource.java | 8 +- .../facebook/FacebookIdentityProvider.java | 1 - .../social/github/GitHubIdentityProvider.java | 1 - .../linkedin/LinkedInIdentityProvider.java | 1 - .../StackoverflowIdentityProvider.java | 1 - .../twitter/TwitterIdentityProvider.java | 4 - 32 files changed, 500 insertions(+), 327 deletions(-) delete mode 100755 broker/core/src/main/java/org/keycloak/broker/provider/FederatedIdentity.java create mode 100755 broker/core/src/main/java/org/keycloak/broker/provider/IdentityProviderMapper.java create mode 100755 broker/core/src/main/java/org/keycloak/broker/provider/IdentityProviderMapperSpi.java create mode 100755 core/src/main/java/org/keycloak/representations/idm/ConfigPropertyRepresentation.java create mode 100755 core/src/main/java/org/keycloak/representations/idm/IdentityProviderMapperRepresentation.java create mode 100755 core/src/main/java/org/keycloak/representations/idm/IdentityProviderMapperTypeRepresentation.java diff --git a/broker/core/src/main/java/org/keycloak/broker/provider/AbstractIdentityProvider.java b/broker/core/src/main/java/org/keycloak/broker/provider/AbstractIdentityProvider.java index d65081d188..a231346522 100755 --- a/broker/core/src/main/java/org/keycloak/broker/provider/AbstractIdentityProvider.java +++ b/broker/core/src/main/java/org/keycloak/broker/provider/AbstractIdentityProvider.java @@ -20,6 +20,7 @@ package org.keycloak.broker.provider; import org.keycloak.events.EventBuilder; import org.keycloak.models.ClientSessionModel; import org.keycloak.models.IdentityProviderModel; +import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; import org.keycloak.models.UserSessionModel; @@ -68,12 +69,12 @@ public abstract class AbstractIdentityProvider } @Override - public void importNewUser(UserModel user, BrokeredIdentityContext context) { + public void importNewUser(KeycloakSession session, RealmModel realm, UserModel user, BrokeredIdentityContext context) { } @Override - public void updateBrokeredUser(UserModel user, BrokeredIdentityContext context) { + public void updateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, BrokeredIdentityContext context) { } } diff --git a/broker/core/src/main/java/org/keycloak/broker/provider/FederatedIdentity.java b/broker/core/src/main/java/org/keycloak/broker/provider/FederatedIdentity.java deleted file mode 100755 index 4d58970d7f..0000000000 --- a/broker/core/src/main/java/org/keycloak/broker/provider/FederatedIdentity.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * JBoss, Home of Professional Open Source - * - * Copyright 2013 Red Hat, Inc. and/or its affiliates. - * - * 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.broker.provider; - -/** - *

Represents all identity information obtained from an {@link IdentityProvider} after a - * successful authentication.

- * - * @author Pedro Igor - */ -public class FederatedIdentity { - - private String id; - private String username; - private String firstName; - private String lastName; - private String email; - private String token; - private String identityProviderId; - private String brokerSessionId; - private String brokerUserId; - - public FederatedIdentity(String id) { - if (id == null) { - throw new RuntimeException("No identifier provider for identity."); - } - - this.id = id; - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getFirstName() { - return firstName; - } - - public void setName(String name) { - if (name != null) { - int i = name.lastIndexOf(' '); - if (i != -1) { - firstName = name.substring(0, i); - lastName = name.substring(i + 1); - } else { - firstName = name; - } - } - } - - public String getLastName() { - return lastName; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - - public void setToken(String token) { - this.token = token; - } - - public String getToken() { - return this.token; - } - - public String getIdentityProviderId() { - return this.identityProviderId; - } - - public void setIdentityProviderId(String identityProviderId) { - this.identityProviderId = identityProviderId; - } - - public String getBrokerSessionId() { - return brokerSessionId; - } - - public void setBrokerSessionId(String brokerSessionId) { - this.brokerSessionId = brokerSessionId; - } - - public String getBrokerUserId() { - return brokerUserId; - } - - public void setBrokerUserId(String brokerUserId) { - this.brokerUserId = brokerUserId; - } - - @Override - public String toString() { - return "{" + - "id='" + id + '\'' + - ", username='" + username + '\'' + - ", firstName='" + firstName + '\'' + - ", lastName='" + lastName + '\'' + - ", email='" + email + '\'' + - ", token='" + token + '\'' + - ", identityProviderId='" + identityProviderId + '\'' + - '}'; - } -} diff --git a/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProvider.java b/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProvider.java index 0517b3a27c..01d5455b02 100755 --- a/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProvider.java +++ b/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProvider.java @@ -21,6 +21,7 @@ import org.keycloak.events.EventBuilder; import org.keycloak.models.ClientSessionModel; import org.keycloak.models.FederatedIdentityModel; import org.keycloak.models.IdentityProviderModel; +import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; import org.keycloak.models.UserSessionModel; @@ -28,7 +29,6 @@ import org.keycloak.provider.Provider; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; -import java.util.Map; /** * @author Pedro Igor @@ -46,15 +46,9 @@ public interface IdentityProvider extends Provi public Response authenticated(BrokeredIdentityContext context); } - /** - * - * @param userSession - * @param clientSession - * @param context - */ void attachUserSession(UserSessionModel userSession, ClientSessionModel clientSession, BrokeredIdentityContext context); - void importNewUser(UserModel user, BrokeredIdentityContext context); - void updateBrokeredUser(UserModel user, BrokeredIdentityContext context); + void importNewUser(KeycloakSession session, RealmModel realm, UserModel user, BrokeredIdentityContext context); + void updateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, BrokeredIdentityContext context); /** * JAXRS callback endpoint for when the remote IDP wants to callback to keycloak. @@ -67,12 +61,6 @@ public interface IdentityProvider extends Provi *

Initiates the authentication process by sending an authentication request to an identity provider. This method is called * only once during the authentication.

* - *

Depending on how the authentication is performed, this method may redirect the user to the identity provider for authentication. - * In this case, the response would contain a {@link javax.ws.rs.core.Response} that will be used to redirect the user.

- * - *

However, if the authentication flow does not require a redirect to the identity provider (eg.: simple challenge/response mechanism), this method may return a response containing - * a {@link FederatedIdentity} representing the identity information for an user. In this case, the authentication flow stops.

- * * @param request The initial authentication request. Contains all the contextual information in order to build an authentication request to the * identity provider. * @return diff --git a/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProviderMapper.java b/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProviderMapper.java new file mode 100755 index 0000000000..990c6de09b --- /dev/null +++ b/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProviderMapper.java @@ -0,0 +1,24 @@ +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.ConfiguredProvider; +import org.keycloak.provider.Provider; +import org.keycloak.provider.ProviderFactory; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public interface IdentityProviderMapper extends Provider, ProviderFactory,ConfiguredProvider { + String[] getCompatibleProviders(); + String getDisplayCategory(); + String getDisplayType(); + + void importNewUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context); + void updateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context); + + +} diff --git a/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProviderMapperSpi.java b/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProviderMapperSpi.java new file mode 100755 index 0000000000..e660700a1a --- /dev/null +++ b/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProviderMapperSpi.java @@ -0,0 +1,27 @@ +package org.keycloak.broker.provider; + +import org.keycloak.provider.Provider; +import org.keycloak.provider.ProviderFactory; +import org.keycloak.provider.Spi; + +/** + * @author Stian Thorgersen + */ +public class IdentityProviderMapperSpi implements Spi { + + @Override + public String getName() { + return "identity-provider-mapper"; + } + + @Override + public Class getProviderClass() { + return IdentityProviderMapper.class; + } + + @Override + public Class getProviderFactoryClass() { + return IdentityProviderMapper.class; + } + +} diff --git a/broker/core/src/main/resources/META-INF/services/org.keycloak.provider.Spi b/broker/core/src/main/resources/META-INF/services/org.keycloak.provider.Spi index d4ef41b616..fa44621234 100755 --- a/broker/core/src/main/resources/META-INF/services/org.keycloak.provider.Spi +++ b/broker/core/src/main/resources/META-INF/services/org.keycloak.provider.Spi @@ -1 +1,2 @@ -org.keycloak.broker.provider.IdentityProviderSpi \ No newline at end of file +org.keycloak.broker.provider.IdentityProviderSpi +org.keycloak.broker.provider.IdentityProviderMapperSpi \ No newline at end of file diff --git a/broker/oidc/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java b/broker/oidc/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java index 0581eb10bf..60b1f4a0b1 100755 --- a/broker/oidc/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java +++ b/broker/oidc/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java @@ -26,17 +26,13 @@ import org.keycloak.broker.oidc.util.SimpleHttp; import org.keycloak.broker.provider.AbstractIdentityProvider; import org.keycloak.broker.provider.AuthenticationRequest; import org.keycloak.broker.provider.BrokeredIdentityContext; -import org.keycloak.broker.provider.FederatedIdentity; import org.keycloak.broker.provider.IdentityBrokerException; import org.keycloak.events.Errors; import org.keycloak.events.EventBuilder; import org.keycloak.events.EventType; -import org.keycloak.models.ClientSessionModel; import org.keycloak.models.FederatedIdentityModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; -import org.keycloak.models.UserModel; -import org.keycloak.models.UserSessionModel; import org.keycloak.services.messages.Messages; import org.keycloak.services.resources.flows.Flows; @@ -49,8 +45,6 @@ import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; import java.io.IOException; import java.net.URI; -import java.util.HashMap; -import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; diff --git a/broker/oidc/src/main/java/org/keycloak/broker/oidc/KeycloakOIDCIdentityProvider.java b/broker/oidc/src/main/java/org/keycloak/broker/oidc/KeycloakOIDCIdentityProvider.java index ff89a89edc..14626c5759 100755 --- a/broker/oidc/src/main/java/org/keycloak/broker/oidc/KeycloakOIDCIdentityProvider.java +++ b/broker/oidc/src/main/java/org/keycloak/broker/oidc/KeycloakOIDCIdentityProvider.java @@ -95,4 +95,6 @@ public class KeycloakOIDCIdentityProvider extends OIDCIdentityProvider { } + + } diff --git a/broker/oidc/src/main/java/org/keycloak/broker/oidc/KeycloakOIDCIdentityProviderFactory.java b/broker/oidc/src/main/java/org/keycloak/broker/oidc/KeycloakOIDCIdentityProviderFactory.java index 6a47135faf..b59a4279c3 100755 --- a/broker/oidc/src/main/java/org/keycloak/broker/oidc/KeycloakOIDCIdentityProviderFactory.java +++ b/broker/oidc/src/main/java/org/keycloak/broker/oidc/KeycloakOIDCIdentityProviderFactory.java @@ -19,10 +19,7 @@ package org.keycloak.broker.oidc; import org.keycloak.broker.provider.AbstractIdentityProviderFactory; import org.keycloak.models.IdentityProviderModel; -import org.keycloak.protocol.oidc.representations.OIDCConfigurationRepresentation; -import org.keycloak.util.JsonSerialization; -import java.io.IOException; import java.io.InputStream; import java.util.Map; diff --git a/broker/oidc/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java b/broker/oidc/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java index 19a0f9df53..eb73c0a5a6 100755 --- a/broker/oidc/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java +++ b/broker/oidc/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java @@ -19,11 +19,9 @@ package org.keycloak.broker.oidc; import org.codehaus.jackson.JsonNode; import org.jboss.logging.Logger; -import org.keycloak.RSATokenVerifier; import org.keycloak.broker.oidc.util.SimpleHttp; import org.keycloak.broker.provider.AuthenticationRequest; import org.keycloak.broker.provider.BrokeredIdentityContext; -import org.keycloak.broker.provider.FederatedIdentity; import org.keycloak.broker.provider.IdentityBrokerException; import org.keycloak.events.Errors; import org.keycloak.events.EventBuilder; @@ -36,6 +34,7 @@ import org.keycloak.models.UserModel; import org.keycloak.models.UserSessionModel; import org.keycloak.representations.AccessTokenResponse; import org.keycloak.representations.IDToken; +import org.keycloak.representations.JsonWebToken; import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.messages.Messages; import org.keycloak.services.resources.IdentityBrokerService; @@ -53,7 +52,6 @@ import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; import java.io.IOException; import java.security.PublicKey; -import java.util.Map; /** * @author Pedro Igor @@ -178,14 +176,14 @@ public class OIDCIdentityProvider extends AbstractOAuth2IdentityProviderBill Burke diff --git a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java index aaec932cb8..f88c45dc94 100755 --- a/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java +++ b/broker/saml/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java @@ -136,16 +136,6 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider otherClaims = new HashMap(); - public String getNonce() { return nonce; } @@ -259,18 +279,4 @@ public class IDToken extends JsonWebToken { this.claimsLocales = claimsLocales; } - /** - * This is a map of any other claims and data that might be in the IDToken. Could be custom claims set up by the auth server - * - * @return - */ - @JsonAnyGetter - public Map getOtherClaims() { - return otherClaims; - } - - @JsonAnySetter - public void setOtherClaims(String name, Object value) { - otherClaims.put(name, value); - } } diff --git a/core/src/main/java/org/keycloak/representations/JsonWebToken.java b/core/src/main/java/org/keycloak/representations/JsonWebToken.java index d0a4e9d91e..8db6ef3fcf 100755 --- a/core/src/main/java/org/keycloak/representations/JsonWebToken.java +++ b/core/src/main/java/org/keycloak/representations/JsonWebToken.java @@ -1,10 +1,14 @@ package org.keycloak.representations; +import org.codehaus.jackson.annotate.JsonAnyGetter; +import org.codehaus.jackson.annotate.JsonAnySetter; import org.codehaus.jackson.annotate.JsonIgnore; import org.codehaus.jackson.annotate.JsonProperty; import org.keycloak.util.Time; import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; /** * @author Bill Burke @@ -29,6 +33,7 @@ public class JsonWebToken implements Serializable { protected String type; @JsonProperty("azp") public String issuedFor; + protected Map otherClaims = new HashMap(); public String getId() { return id; @@ -153,4 +158,19 @@ public class JsonWebToken implements Serializable { this.issuedFor = issuedFor; return this; } + + /** + * This is a map of any other claims and data that might be in the IDToken. Could be custom claims set up by the auth server + * + * @return + */ + @JsonAnyGetter + public Map getOtherClaims() { + return otherClaims; + } + + @JsonAnySetter + public void setOtherClaims(String name, Object value) { + otherClaims.put(name, value); + } } diff --git a/core/src/main/java/org/keycloak/representations/idm/ConfigPropertyRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ConfigPropertyRepresentation.java new file mode 100755 index 0000000000..0a962709cb --- /dev/null +++ b/core/src/main/java/org/keycloak/representations/idm/ConfigPropertyRepresentation.java @@ -0,0 +1,53 @@ +package org.keycloak.representations.idm; + +/** +* @author Bill Burke +* @version $Revision: 1 $ +*/ +public class ConfigPropertyRepresentation { + protected String name; + protected String label; + protected String helpText; + protected String type; + protected Object defaultValue; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public Object getDefaultValue() { + return defaultValue; + } + + public void setDefaultValue(Object defaultValue) { + this.defaultValue = defaultValue; + } + + public String getHelpText() { + return helpText; + } + + public void setHelpText(String helpText) { + this.helpText = helpText; + } +} diff --git a/core/src/main/java/org/keycloak/representations/idm/IdentityProviderMapperRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/IdentityProviderMapperRepresentation.java new file mode 100755 index 0000000000..2d59ab8565 --- /dev/null +++ b/core/src/main/java/org/keycloak/representations/idm/IdentityProviderMapperRepresentation.java @@ -0,0 +1,57 @@ +package org.keycloak.representations.idm; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class IdentityProviderMapperRepresentation { + protected String id; + protected String name; + protected String identityProviderAlias; + protected String identityProviderMapper; + protected Map config = new HashMap(); + + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getIdentityProviderAlias() { + return identityProviderAlias; + } + + public void setIdentityProviderAlias(String identityProviderAlias) { + this.identityProviderAlias = identityProviderAlias; + } + + public String getIdentityProviderMapper() { + return identityProviderMapper; + } + + public void setIdentityProviderMapper(String identityProviderMapper) { + this.identityProviderMapper = identityProviderMapper; + } + + public Map getConfig() { + return config; + } + + public void setConfig(Map config) { + this.config = config; + } +} diff --git a/core/src/main/java/org/keycloak/representations/idm/IdentityProviderMapperTypeRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/IdentityProviderMapperTypeRepresentation.java new file mode 100755 index 0000000000..c76f6eed0d --- /dev/null +++ b/core/src/main/java/org/keycloak/representations/idm/IdentityProviderMapperTypeRepresentation.java @@ -0,0 +1,56 @@ +package org.keycloak.representations.idm; + +import java.util.List; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class IdentityProviderMapperTypeRepresentation { + protected String id; + protected String name; + protected String category; + protected String helpText; + + protected List properties; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public String getHelpText() { + return helpText; + } + + public void setHelpText(String helpText) { + this.helpText = helpText; + } + + public List getProperties() { + return properties; + } + + public void setProperties(List properties) { + this.properties = properties; + } +} diff --git a/core/src/main/java/org/keycloak/representations/idm/ProtocolMapperTypeRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ProtocolMapperTypeRepresentation.java index 779f3be519..212fe58c63 100755 --- a/core/src/main/java/org/keycloak/representations/idm/ProtocolMapperTypeRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/ProtocolMapperTypeRepresentation.java @@ -12,55 +12,7 @@ public class ProtocolMapperTypeRepresentation { protected String category; protected String helpText; - public static class ConfigProperty { - protected String name; - protected String label; - protected String helpText; - protected String type; - protected Object defaultValue; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getLabel() { - return label; - } - - public void setLabel(String label) { - this.label = label; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public Object getDefaultValue() { - return defaultValue; - } - - public void setDefaultValue(Object defaultValue) { - this.defaultValue = defaultValue; - } - - public String getHelpText() { - return helpText; - } - - public void setHelpText(String helpText) { - this.helpText = helpText; - } - } - - protected List properties; + protected List properties; public String getId() { return id; @@ -94,11 +46,11 @@ public class ProtocolMapperTypeRepresentation { this.helpText = helpText; } - public List getProperties() { + public List getProperties() { return properties; } - public void setProperties(List properties) { + public void setProperties(List properties) { this.properties = properties; } } diff --git a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java index dc1124ae54..a2bb17faf2 100755 --- a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java +++ b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java @@ -4,6 +4,7 @@ import org.keycloak.models.ClientModel; import org.keycloak.models.ClientIdentityProviderMappingModel; import org.keycloak.models.ClientSessionModel; import org.keycloak.models.FederatedIdentityModel; +import org.keycloak.models.IdentityProviderMapperModel; import org.keycloak.models.IdentityProviderModel; import org.keycloak.models.ProtocolMapperModel; import org.keycloak.models.RealmModel; @@ -18,6 +19,7 @@ import org.keycloak.representations.idm.ClientIdentityProviderMappingRepresentat import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.CredentialRepresentation; import org.keycloak.representations.idm.FederatedIdentityRepresentation; +import org.keycloak.representations.idm.IdentityProviderMapperRepresentation; import org.keycloak.representations.idm.IdentityProviderRepresentation; import org.keycloak.representations.idm.ProtocolMapperRepresentation; import org.keycloak.representations.idm.RealmEventsConfigRepresentation; @@ -327,4 +329,16 @@ public class ModelToRepresentation { return rep; } + public static IdentityProviderMapperRepresentation toRepresentation(IdentityProviderMapperModel model) { + IdentityProviderMapperRepresentation rep = new IdentityProviderMapperRepresentation(); + rep.setId(model.getId()); + rep.setIdentityProviderMapper(model.getIdentityProviderMapper()); + rep.setIdentityProviderAlias(model.getIdentityProviderAlias()); + Map config = new HashMap(); + config.putAll(model.getConfig()); + rep.setConfig(config); + rep.setName(model.getName()); + return rep; + } + } diff --git a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java index f830ac1f24..69871514f1 100755 --- a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java +++ b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java @@ -9,6 +9,7 @@ import org.keycloak.models.ClaimMask; import org.keycloak.models.ClientIdentityProviderMappingModel; import org.keycloak.models.ClientModel; import org.keycloak.models.FederatedIdentityModel; +import org.keycloak.models.IdentityProviderMapperModel; import org.keycloak.models.IdentityProviderModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.PasswordPolicy; @@ -25,6 +26,7 @@ import org.keycloak.representations.idm.ClientIdentityProviderMappingRepresentat import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.CredentialRepresentation; import org.keycloak.representations.idm.FederatedIdentityRepresentation; +import org.keycloak.representations.idm.IdentityProviderMapperRepresentation; import org.keycloak.representations.idm.IdentityProviderRepresentation; import org.keycloak.representations.idm.OAuthClientRepresentation; import org.keycloak.representations.idm.ProtocolMapperRepresentation; @@ -870,6 +872,16 @@ public class RepresentationToModel { return model; } + public static IdentityProviderMapperModel toModel(IdentityProviderMapperRepresentation rep) { + IdentityProviderMapperModel model = new IdentityProviderMapperModel(); + model.setId(rep.getId()); + model.setName(rep.getName()); + model.setIdentityProviderAlias(rep.getIdentityProviderAlias()); + model.setIdentityProviderMapper(rep.getIdentityProviderMapper()); + model.setConfig(rep.getConfig()); + return model; + } + private static List toModel(List repIdentityProviders, RealmModel realm) { List result = new ArrayList(); 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 4098d33e4f..7550eb8bbe 100755 --- a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java +++ b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java @@ -23,10 +23,10 @@ import org.jboss.resteasy.spi.ResteasyProviderFactory; import org.keycloak.ClientConnection; import org.keycloak.broker.provider.AuthenticationRequest; import org.keycloak.broker.provider.BrokeredIdentityContext; -import org.keycloak.broker.provider.FederatedIdentity; import org.keycloak.broker.provider.IdentityBrokerException; import org.keycloak.broker.provider.IdentityProvider; import org.keycloak.broker.provider.IdentityProviderFactory; +import org.keycloak.broker.provider.IdentityProviderMapper; import org.keycloak.events.Details; import org.keycloak.events.Errors; import org.keycloak.events.EventBuilder; @@ -34,11 +34,14 @@ import org.keycloak.events.EventType; import org.keycloak.models.ClientModel; import org.keycloak.models.ClientSessionModel; import org.keycloak.models.FederatedIdentityModel; +import org.keycloak.models.IdentityProviderMapperModel; import org.keycloak.models.IdentityProviderModel; import org.keycloak.models.KeycloakSession; +import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; import org.keycloak.models.UserSessionModel; +import org.keycloak.protocol.ProtocolMapper; import org.keycloak.protocol.oidc.TokenManager; import org.keycloak.provider.ProviderFactory; import org.keycloak.services.managers.AppAuthManager; @@ -71,6 +74,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import static org.keycloak.models.AccountRoles.MANAGE_ACCOUNT; import static org.keycloak.models.ClientSessionModel.Action.AUTHENTICATE; @@ -347,7 +351,16 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal LOGGER.debugf("Identity [%s] update with response from identity provider [%s].", federatedUser, updatedIdentity.getIdpConfig().getAlias()); } } - updatedIdentity.getIdp().updateBrokeredUser(federatedUser, updatedIdentity); + updatedIdentity.getIdp().updateBrokeredUser(session, realmModel, federatedUser, updatedIdentity); + Set mappers = realmModel.getIdentityProviderMappersByAlias(updatedIdentity.getIdpConfig().getAlias()); + if (mappers != null) { + KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory(); + for (IdentityProviderMapperModel mapper : mappers) { + IdentityProviderMapper target = (IdentityProviderMapper)sessionFactory.getProviderFactory(IdentityProviderMapper.class, mapper.getIdentityProviderMapper()); + target.updateBrokeredUser(session, realmModel, federatedUser, mapper, updatedIdentity); + } + } + } private ClientSessionCode parseClientSessionCode(String code) { @@ -520,7 +533,16 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal this.session.users().addFederatedIdentity(this.realmModel, federatedUser, federatedIdentityModel); - updatedIdentity.getIdp().importNewUser(federatedUser, updatedIdentity); + updatedIdentity.getIdp().importNewUser(session, realmModel, federatedUser, updatedIdentity); + Set mappers = realmModel.getIdentityProviderMappersByAlias(updatedIdentity.getIdpConfig().getAlias()); + if (mappers != null) { + KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory(); + for (IdentityProviderMapperModel mapper : mappers) { + IdentityProviderMapper target = (IdentityProviderMapper)sessionFactory.getProviderFactory(IdentityProviderMapper.class, mapper.getIdentityProviderMapper()); + target.importNewUser(session, realmModel, federatedUser, mapper, updatedIdentity); + } + } + this.event.clone().user(federatedUser).event(EventType.REGISTER) .detail(Details.IDENTITY_PROVIDER, federatedIdentityModel.getIdentityProvider()) diff --git a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java index bbb32b441b..3f1983c50d 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java @@ -2,28 +2,40 @@ package org.keycloak.services.resources.admin; import org.jboss.logging.Logger; import org.jboss.resteasy.annotations.cache.NoCache; +import org.jboss.resteasy.spi.NotFoundException; import org.keycloak.broker.provider.IdentityProvider; import org.keycloak.broker.provider.IdentityProviderFactory; +import org.keycloak.broker.provider.IdentityProviderMapper; import org.keycloak.models.ClientModel; import org.keycloak.models.ClientIdentityProviderMappingModel; import org.keycloak.models.FederatedIdentityModel; +import org.keycloak.models.IdentityProviderMapperModel; import org.keycloak.models.IdentityProviderModel; import org.keycloak.models.KeycloakSession; +import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.ModelDuplicateException; +import org.keycloak.models.ProtocolMapperModel; import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; import org.keycloak.models.utils.ModelToRepresentation; import org.keycloak.models.utils.RepresentationToModel; +import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.provider.ProviderFactory; +import org.keycloak.representations.idm.ConfigPropertyRepresentation; +import org.keycloak.representations.idm.IdentityProviderMapperRepresentation; +import org.keycloak.representations.idm.IdentityProviderMapperTypeRepresentation; import org.keycloak.representations.idm.IdentityProviderRepresentation; +import org.keycloak.representations.idm.ProtocolMapperRepresentation; import org.keycloak.services.resources.flows.Flows; import org.keycloak.social.SocialIdentityProvider; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; +import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; +import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; @@ -31,6 +43,7 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import java.util.ArrayList; +import java.util.LinkedList; import java.util.List; /** @@ -45,6 +58,8 @@ public class IdentityProviderResource { private final KeycloakSession session; private final IdentityProviderModel identityProviderModel; + @Context private UriInfo uriInfo; + public IdentityProviderResource(RealmAuth auth, RealmModel realm, KeycloakSession session, IdentityProviderModel identityProviderModel) { this.realm = realm; this.session = session; @@ -56,6 +71,7 @@ public class IdentityProviderResource { @NoCache @Produces(MediaType.APPLICATION_JSON) public IdentityProviderRepresentation getIdentityProvider() { + this.auth.requireView(); IdentityProviderRepresentation rep = ModelToRepresentation.toRepresentation(this.identityProviderModel); return rep; @@ -75,6 +91,7 @@ public class IdentityProviderResource { @PUT @Consumes(MediaType.APPLICATION_JSON) + @NoCache public Response update(IdentityProviderRepresentation providerRep) { try { this.auth.requireManage(); @@ -163,6 +180,7 @@ public class IdentityProviderResource { @GET @Path("export") + @NoCache public Response export(@Context UriInfo uriInfo, @QueryParam("format") String format) { try { this.auth.requireView(); @@ -173,6 +191,97 @@ public class IdentityProviderResource { } } + @GET + @Path("mapper-types") + @NoCache + public List getMapperTypes() { + this.auth.requireView(); + KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory(); + List types = new LinkedList<>(); + List factories = sessionFactory.getProviderFactories(IdentityProviderMapper.class); + for (ProviderFactory factory : factories) { + IdentityProviderMapper mapper = (IdentityProviderMapper)factory; + for (String type : mapper.getCompatibleProviders()) { + if (type.equals(identityProviderModel.getProviderId())) { + IdentityProviderMapperTypeRepresentation rep = new IdentityProviderMapperTypeRepresentation(); + rep.setId(mapper.getId()); + rep.setCategory(mapper.getDisplayCategory()); + rep.setName(mapper.getDisplayType()); + rep.setHelpText(mapper.getHelpText()); + List configProperties = mapper.getConfigProperties(); + for (ProviderConfigProperty prop : configProperties) { + ConfigPropertyRepresentation propRep = new ConfigPropertyRepresentation(); + propRep.setName(prop.getName()); + propRep.setLabel(prop.getLabel()); + propRep.setType(prop.getType()); + propRep.setDefaultValue(prop.getDefaultValue()); + propRep.setHelpText(prop.getHelpText()); + rep.getProperties().add(propRep); + } + types.add(rep); + + } + } + } + return types; + } + + @GET + @Path("mappers") + @Produces(MediaType.APPLICATION_JSON) + @NoCache + public List getMappers() { + this.auth.requireView(); + List mappers = new LinkedList<>(); + for (IdentityProviderMapperModel model : realm.getIdentityProviderMappersByAlias(identityProviderModel.getAlias())) { + mappers.add(ModelToRepresentation.toRepresentation(model)); + } + return mappers; + } + + @POST + @Path("mappers") + @Consumes(MediaType.APPLICATION_JSON) + public Response addMapper(IdentityProviderMapperRepresentation mapper) { + auth.requireManage(); + IdentityProviderMapperModel model = RepresentationToModel.toModel(mapper); + model = realm.addIdentityProviderMapper(model); + return Response.created(uriInfo.getAbsolutePathBuilder().path(model.getId()).build()).build(); + + } + + @GET + @NoCache + @Path("mappers/{id}") + @Produces(MediaType.APPLICATION_JSON) + public IdentityProviderMapperRepresentation getMapperById(@PathParam("id") String id) { + auth.requireView(); + IdentityProviderMapperModel model = realm.getIdentityProviderMapperById(id); + if (model == null) throw new NotFoundException("Model not found"); + return ModelToRepresentation.toRepresentation(model); + } + + @PUT + @NoCache + @Path("mappers/{id}") + @Consumes(MediaType.APPLICATION_JSON) + public void update(@PathParam("id") String id, IdentityProviderMapperRepresentation rep) { + auth.requireManage(); + IdentityProviderMapperModel model = realm.getIdentityProviderMapperById(id); + if (model == null) throw new NotFoundException("Model not found"); + model = RepresentationToModel.toModel(rep); + realm.updateIdentityProviderMapper(model); + } + + @DELETE + @NoCache + @Path("mappers/{id}") + public void delete(@PathParam("id") String id) { + auth.requireManage(); + IdentityProviderMapperModel model = realm.getIdentityProviderMapperById(id); + if (model == null) throw new NotFoundException("Model not found"); + realm.removeIdentityProviderMapper(model); + } private void removeClientIdentityProviders(List clients, IdentityProviderModel identityProvider) { for (ClientModel clientModel : clients) { diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java index 0bdb525d5f..f535b191ba 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java @@ -18,6 +18,7 @@ import org.keycloak.protocol.ProtocolMapper; import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.provider.ProviderFactory; import org.keycloak.provider.Spi; +import org.keycloak.representations.idm.ConfigPropertyRepresentation; import org.keycloak.representations.idm.ProtocolMapperRepresentation; import org.keycloak.representations.idm.ProtocolMapperTypeRepresentation; import org.keycloak.social.SocialIdentityProvider; @@ -142,9 +143,10 @@ public class ServerInfoAdminResource { rep.setName(mapper.getDisplayType()); rep.setHelpText(mapper.getHelpText()); rep.setCategory(mapper.getDisplayCategory()); - rep.setProperties(new LinkedList()); - for (ProviderConfigProperty prop : mapper.getConfigProperties()) { - ProtocolMapperTypeRepresentation.ConfigProperty propRep = new ProtocolMapperTypeRepresentation.ConfigProperty(); + rep.setProperties(new LinkedList()); + List configProperties = mapper.getConfigProperties(); + for (ProviderConfigProperty prop : configProperties) { + ConfigPropertyRepresentation propRep = new ConfigPropertyRepresentation(); propRep.setName(prop.getName()); propRep.setLabel(prop.getLabel()); propRep.setType(prop.getType()); diff --git a/social/facebook/src/main/java/org/keycloak/social/facebook/FacebookIdentityProvider.java b/social/facebook/src/main/java/org/keycloak/social/facebook/FacebookIdentityProvider.java index 4fc319a660..cc9364f612 100755 --- a/social/facebook/src/main/java/org/keycloak/social/facebook/FacebookIdentityProvider.java +++ b/social/facebook/src/main/java/org/keycloak/social/facebook/FacebookIdentityProvider.java @@ -5,7 +5,6 @@ import org.keycloak.broker.oidc.AbstractOAuth2IdentityProvider; import org.keycloak.broker.oidc.OAuth2IdentityProviderConfig; import org.keycloak.broker.oidc.util.SimpleHttp; import org.keycloak.broker.provider.BrokeredIdentityContext; -import org.keycloak.broker.provider.FederatedIdentity; import org.keycloak.broker.provider.IdentityBrokerException; import org.keycloak.social.SocialIdentityProvider; diff --git a/social/github/src/main/java/org/keycloak/social/github/GitHubIdentityProvider.java b/social/github/src/main/java/org/keycloak/social/github/GitHubIdentityProvider.java index 978b4fe0b2..ec56d151ab 100755 --- a/social/github/src/main/java/org/keycloak/social/github/GitHubIdentityProvider.java +++ b/social/github/src/main/java/org/keycloak/social/github/GitHubIdentityProvider.java @@ -5,7 +5,6 @@ import org.keycloak.broker.oidc.AbstractOAuth2IdentityProvider; import org.keycloak.broker.oidc.OAuth2IdentityProviderConfig; import org.keycloak.broker.oidc.util.SimpleHttp; import org.keycloak.broker.provider.BrokeredIdentityContext; -import org.keycloak.broker.provider.FederatedIdentity; import org.keycloak.broker.provider.IdentityBrokerException; import org.keycloak.social.SocialIdentityProvider; diff --git a/social/linkedin/src/main/java/org/keycloak/social/linkedin/LinkedInIdentityProvider.java b/social/linkedin/src/main/java/org/keycloak/social/linkedin/LinkedInIdentityProvider.java index 9283ce541e..911a55cc47 100755 --- a/social/linkedin/src/main/java/org/keycloak/social/linkedin/LinkedInIdentityProvider.java +++ b/social/linkedin/src/main/java/org/keycloak/social/linkedin/LinkedInIdentityProvider.java @@ -27,7 +27,6 @@ import org.keycloak.broker.oidc.AbstractOAuth2IdentityProvider; import org.keycloak.broker.oidc.OAuth2IdentityProviderConfig; import org.keycloak.broker.oidc.util.SimpleHttp; import org.keycloak.broker.provider.BrokeredIdentityContext; -import org.keycloak.broker.provider.FederatedIdentity; import org.keycloak.broker.provider.IdentityBrokerException; import org.keycloak.social.SocialIdentityProvider; diff --git a/social/stackoverflow/src/main/java/org/keycloak/social/stackoverflow/StackoverflowIdentityProvider.java b/social/stackoverflow/src/main/java/org/keycloak/social/stackoverflow/StackoverflowIdentityProvider.java index 4ee77e85cb..f834464665 100755 --- a/social/stackoverflow/src/main/java/org/keycloak/social/stackoverflow/StackoverflowIdentityProvider.java +++ b/social/stackoverflow/src/main/java/org/keycloak/social/stackoverflow/StackoverflowIdentityProvider.java @@ -28,7 +28,6 @@ import org.jboss.logging.Logger; import org.keycloak.broker.oidc.AbstractOAuth2IdentityProvider; import org.keycloak.broker.oidc.util.SimpleHttp; import org.keycloak.broker.provider.BrokeredIdentityContext; -import org.keycloak.broker.provider.FederatedIdentity; import org.keycloak.broker.provider.IdentityBrokerException; import org.keycloak.social.SocialIdentityProvider; diff --git a/social/twitter/src/main/java/org/keycloak/social/twitter/TwitterIdentityProvider.java b/social/twitter/src/main/java/org/keycloak/social/twitter/TwitterIdentityProvider.java index f8aebe22c6..b209fce9fa 100755 --- a/social/twitter/src/main/java/org/keycloak/social/twitter/TwitterIdentityProvider.java +++ b/social/twitter/src/main/java/org/keycloak/social/twitter/TwitterIdentityProvider.java @@ -27,7 +27,6 @@ import org.keycloak.broker.oidc.OAuth2IdentityProviderConfig; import org.keycloak.broker.provider.AbstractIdentityProvider; import org.keycloak.broker.provider.AuthenticationRequest; import org.keycloak.broker.provider.BrokeredIdentityContext; -import org.keycloak.broker.provider.FederatedIdentity; import org.keycloak.broker.provider.IdentityBrokerException; import org.keycloak.events.EventBuilder; import org.keycloak.events.EventType; @@ -36,8 +35,6 @@ import org.keycloak.models.ClientSessionModel; import org.keycloak.models.FederatedIdentityModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; -import org.keycloak.models.UserModel; -import org.keycloak.models.UserSessionModel; import org.keycloak.services.managers.ClientSessionCode; import org.keycloak.services.messages.Messages; import org.keycloak.services.resources.flows.Flows; @@ -55,7 +52,6 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import java.net.URI; -import java.util.HashMap; import static org.keycloak.models.ClientSessionModel.Action.AUTHENTICATE;