broker token exchange refactor
This commit is contained in:
parent
f9b099d49d
commit
1f4df58e6c
43 changed files with 305 additions and 586 deletions
|
@ -129,8 +129,9 @@ public class OIDCIdentityProvider extends AbstractOAuth2IdentityProvider<OIDCIde
|
|||
@Override
|
||||
public Response keycloakInitiatedBrowserLogout(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm) {
|
||||
if (getConfig().getLogoutUrl() == null || getConfig().getLogoutUrl().trim().equals("")) return null;
|
||||
String sessionId = userSession.getId();
|
||||
UriBuilder logoutUri = UriBuilder.fromUri(getConfig().getLogoutUrl())
|
||||
.queryParam("state", userSession.getId());
|
||||
.queryParam("state", sessionId);
|
||||
String idToken = userSession.getNote(FEDERATED_ID_TOKEN);
|
||||
if (idToken != null) logoutUri.queryParam("id_token_hint", idToken);
|
||||
String redirect = RealmsResource.brokerUrl(uriInfo)
|
||||
|
|
|
@ -7,6 +7,8 @@ import org.keycloak.broker.provider.BrokeredIdentityContext;
|
|||
import org.keycloak.broker.provider.IdentityBrokerException;
|
||||
import org.keycloak.broker.provider.IdentityProvider;
|
||||
import org.keycloak.dom.saml.v2.assertion.AssertionType;
|
||||
import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
|
||||
import org.keycloak.dom.saml.v2.assertion.AttributeType;
|
||||
import org.keycloak.dom.saml.v2.assertion.AuthnStatementType;
|
||||
import org.keycloak.dom.saml.v2.assertion.EncryptedAssertionType;
|
||||
import org.keycloak.dom.saml.v2.assertion.NameIDType;
|
||||
|
@ -36,6 +38,7 @@ import org.keycloak.saml.common.util.StaxParserUtil;
|
|||
import org.keycloak.saml.processing.api.saml.v2.response.SAML2Response;
|
||||
import org.keycloak.saml.processing.core.parsers.saml.SAMLParser;
|
||||
import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder;
|
||||
import org.keycloak.saml.processing.core.saml.v2.constants.X500SAMLProfileConstants;
|
||||
import org.keycloak.saml.processing.core.util.JAXPValidationUtil;
|
||||
import org.keycloak.saml.processing.core.util.XMLEncryptionUtil;
|
||||
import org.keycloak.saml.processing.core.util.XMLSignatureUtil;
|
||||
|
@ -295,6 +298,19 @@ public class SAMLEndpoint {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (assertion.getAttributeStatements() != null ) {
|
||||
for (AttributeStatementType attrStatement : assertion.getAttributeStatements()) {
|
||||
for (AttributeStatementType.ASTChoiceType choice : attrStatement.getAttributes()) {
|
||||
AttributeType attribute = choice.getAttribute();
|
||||
if (X500SAMLProfileConstants.EMAIL.getFriendlyName().equals(attribute.getFriendlyName())
|
||||
|| X500SAMLProfileConstants.EMAIL.get().equals(attribute.getName())) {
|
||||
if (!attribute.getAttributeValue().isEmpty()) identity.setEmail(attribute.getAttributeValue().get(0).toString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
String brokerUserId = config.getAlias() + "." + subjectNameID.getValue();
|
||||
identity.setBrokerUserId(brokerUserId);
|
||||
identity.setIdpConfig(config);
|
||||
|
|
3
model/api/src/main/java/org/keycloak/migration/MigrationProvider.java
Normal file → Executable file
3
model/api/src/main/java/org/keycloak/migration/MigrationProvider.java
Normal file → Executable file
|
@ -1,9 +1,10 @@
|
|||
package org.keycloak.migration;
|
||||
|
||||
import java.util.List;
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Various common utils needed for migration from older version to newer
|
||||
*
|
||||
|
|
|
@ -116,10 +116,6 @@ public interface ClientModel extends RoleContainerModel {
|
|||
|
||||
void setNotBefore(int notBefore);
|
||||
|
||||
void updateIdentityProviders(List<ClientIdentityProviderMappingModel> identityProviders);
|
||||
List<ClientIdentityProviderMappingModel> getIdentityProviders();
|
||||
boolean isAllowedRetrieveTokenFromIdentityProvider(String providerId);
|
||||
|
||||
Set<ProtocolMapperModel> getProtocolMappers();
|
||||
ProtocolMapperModel addProtocolMapper(ProtocolMapperModel model);
|
||||
void removeProtocolMapper(ProtocolMapperModel mapping);
|
||||
|
|
|
@ -8,6 +8,7 @@ public interface Constants {
|
|||
String ADMIN_CONSOLE_CLIENT_ID = "security-admin-console";
|
||||
|
||||
String ACCOUNT_MANAGEMENT_CLIENT_ID = "account";
|
||||
String BROKER_SERVICE_CLIENT_ID = "broker";
|
||||
|
||||
String INSTALLED_APP_URN = "urn:ietf:wg:oauth:2.0:oob";
|
||||
String INSTALLED_APP_URL = "http://localhost";
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package org.keycloak.models;
|
||||
|
||||
import org.keycloak.models.utils.Pbkdf2PasswordEncoder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
@ -8,8 +10,6 @@ import java.util.List;
|
|||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.keycloak.models.utils.Pbkdf2PasswordEncoder;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package org.keycloak.models.entities;
|
||||
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package org.keycloak.models.utils;
|
||||
|
||||
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;
|
||||
|
@ -14,8 +13,6 @@ import org.keycloak.models.UserCredentialModel;
|
|||
import org.keycloak.models.UserFederationProviderModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.representations.idm.ApplicationRepresentation;
|
||||
import org.keycloak.representations.idm.ClientIdentityProviderMappingRepresentation;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.representations.idm.FederatedIdentityRepresentation;
|
||||
|
@ -261,10 +258,6 @@ public class ModelToRepresentation {
|
|||
rep.setRegisteredNodes(new HashMap<>(clientModel.getRegisteredNodes()));
|
||||
}
|
||||
|
||||
if (!clientModel.getIdentityProviders().isEmpty()) {
|
||||
rep.setIdentityProviders(toRepresentation(clientModel.getIdentityProviders()));
|
||||
}
|
||||
|
||||
if (!clientModel.getProtocolMappers().isEmpty()) {
|
||||
List<ProtocolMapperRepresentation> mappings = new LinkedList<>();
|
||||
for (ProtocolMapperModel model : clientModel.getProtocolMappers()) {
|
||||
|
@ -276,21 +269,6 @@ public class ModelToRepresentation {
|
|||
return rep;
|
||||
}
|
||||
|
||||
private static List<ClientIdentityProviderMappingRepresentation> toRepresentation(List<ClientIdentityProviderMappingModel> identityProviders) {
|
||||
ArrayList<ClientIdentityProviderMappingRepresentation> representations = new ArrayList<ClientIdentityProviderMappingRepresentation>();
|
||||
|
||||
for (ClientIdentityProviderMappingModel model : identityProviders) {
|
||||
ClientIdentityProviderMappingRepresentation representation = new ClientIdentityProviderMappingRepresentation();
|
||||
|
||||
representation.setId(model.getIdentityProvider());
|
||||
representation.setRetrieveToken(model.isRetrieveToken());
|
||||
|
||||
representations.add(representation);
|
||||
}
|
||||
|
||||
return representations;
|
||||
}
|
||||
|
||||
public static UserFederationProviderRepresentation toRepresentation(UserFederationProviderModel model) {
|
||||
UserFederationProviderRepresentation rep = new UserFederationProviderRepresentation();
|
||||
rep.setId(model.getId());
|
||||
|
|
|
@ -6,7 +6,6 @@ import org.keycloak.enums.SslRequired;
|
|||
import org.keycloak.migration.MigrationProvider;
|
||||
import org.keycloak.models.BrowserSecurityHeaders;
|
||||
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;
|
||||
|
@ -22,7 +21,6 @@ import org.keycloak.models.UserFederationProviderModel;
|
|||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.representations.idm.ApplicationRepresentation;
|
||||
import org.keycloak.representations.idm.ClaimRepresentation;
|
||||
import org.keycloak.representations.idm.ClientIdentityProviderMappingRepresentation;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.representations.idm.FederatedIdentityRepresentation;
|
||||
|
@ -39,7 +37,6 @@ import org.keycloak.representations.idm.UserRepresentation;
|
|||
import org.keycloak.util.UriUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
@ -610,8 +607,6 @@ public class RepresentationToModel {
|
|||
}
|
||||
}
|
||||
|
||||
client.updateIdentityProviders(toModel(resourceRep.getIdentityProviders(), realm));
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
|
@ -660,7 +655,6 @@ public class RepresentationToModel {
|
|||
}
|
||||
}
|
||||
|
||||
updateClientIdentityProviders(rep.getIdentityProviders(), resource);
|
||||
}
|
||||
|
||||
public static long getClaimsMask(ClaimRepresentation rep) {
|
||||
|
@ -887,37 +881,4 @@ public class RepresentationToModel {
|
|||
return model;
|
||||
}
|
||||
|
||||
private static List<ClientIdentityProviderMappingModel> toModel(List<ClientIdentityProviderMappingRepresentation> repIdentityProviders, RealmModel realm) {
|
||||
List<ClientIdentityProviderMappingModel> result = new ArrayList<ClientIdentityProviderMappingModel>();
|
||||
|
||||
if (repIdentityProviders != null) {
|
||||
for (ClientIdentityProviderMappingRepresentation rep : repIdentityProviders) {
|
||||
ClientIdentityProviderMappingModel identityProviderMapping = new ClientIdentityProviderMappingModel();
|
||||
|
||||
identityProviderMapping.setIdentityProvider(rep.getId());
|
||||
identityProviderMapping.setRetrieveToken(rep.isRetrieveToken());
|
||||
|
||||
result.add(identityProviderMapping);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void updateClientIdentityProviders(List<ClientIdentityProviderMappingRepresentation> identityProviders, ClientModel resource) {
|
||||
if (identityProviders != null) {
|
||||
List<ClientIdentityProviderMappingModel> result = new ArrayList<ClientIdentityProviderMappingModel>();
|
||||
|
||||
for (ClientIdentityProviderMappingRepresentation mappingRepresentation : identityProviders) {
|
||||
ClientIdentityProviderMappingModel identityProviderMapping = new ClientIdentityProviderMappingModel();
|
||||
|
||||
identityProviderMapping.setIdentityProvider(mappingRepresentation.getId());
|
||||
identityProviderMapping.setRetrieveToken(mappingRepresentation.isRetrieveToken());
|
||||
|
||||
result.add(identityProviderMapping);
|
||||
}
|
||||
|
||||
resource.updateIdentityProviders(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
4
model/api/src/main/java/org/keycloak/models/utils/reflection/MethodPropertyImpl.java
Normal file → Executable file
4
model/api/src/main/java/org/keycloak/models/utils/reflection/MethodPropertyImpl.java
Normal file → Executable file
|
@ -1,13 +1,13 @@
|
|||
package org.keycloak.models.utils.reflection;
|
||||
|
||||
import org.keycloak.util.reflections.Reflections;
|
||||
|
||||
import java.beans.Introspector;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import org.keycloak.util.reflections.Reflections;
|
||||
|
||||
/**
|
||||
* A bean property based on the value represented by a getter/setter method pair
|
||||
*/
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package org.keycloak.provider;
|
||||
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
package org.keycloak.provider;
|
||||
|
||||
import org.keycloak.provider.ProviderEvent;
|
||||
import org.keycloak.provider.ProviderEventListener;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
|
|
8
model/api/src/test/java/org/keycloak/models/PasswordPolicyTest.java
Normal file → Executable file
8
model/api/src/test/java/org/keycloak/models/PasswordPolicyTest.java
Normal file → Executable file
|
@ -1,12 +1,12 @@
|
|||
package org.keycloak.models;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
|
|
27
model/file/src/main/java/org/keycloak/models/file/FileUserProvider.java
Normal file → Executable file
27
model/file/src/main/java/org/keycloak/models/file/FileUserProvider.java
Normal file → Executable file
|
@ -16,34 +16,33 @@
|
|||
*/
|
||||
package org.keycloak.models.file;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.file.adapter.UserAdapter;
|
||||
import org.keycloak.connections.file.FileConnectionProvider;
|
||||
import org.keycloak.connections.file.InMemoryModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.CredentialValidationOutput;
|
||||
import org.keycloak.models.FederatedIdentityModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserFederationProviderModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserProvider;
|
||||
import org.keycloak.models.entities.FederatedIdentityEntity;
|
||||
import org.keycloak.models.entities.UserEntity;
|
||||
import org.keycloak.models.file.adapter.UserAdapter;
|
||||
import org.keycloak.models.utils.CredentialValidation;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
import org.keycloak.connections.file.FileConnectionProvider;
|
||||
import org.keycloak.connections.file.InMemoryModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.CredentialValidationOutput;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.entities.FederatedIdentityEntity;
|
||||
import org.keycloak.models.entities.UserEntity;
|
||||
import org.keycloak.models.utils.CredentialValidation;
|
||||
|
||||
/**
|
||||
* UserProvider for JSON persistence.
|
||||
|
|
|
@ -16,12 +16,18 @@
|
|||
*/
|
||||
package org.keycloak.models.file.adapter;
|
||||
|
||||
import org.keycloak.connections.file.InMemoryModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientIdentityProviderMappingModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.entities.ClientEntity;
|
||||
import org.keycloak.models.entities.ProtocolMapperEntity;
|
||||
import org.keycloak.models.entities.RoleEntity;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
@ -30,14 +36,6 @@ import java.util.HashSet;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.keycloak.connections.file.InMemoryModel;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.entities.ClientEntity;
|
||||
import org.keycloak.models.entities.ClientIdentityProviderMappingEntity;
|
||||
import org.keycloak.models.entities.ProtocolMapperEntity;
|
||||
import org.keycloak.models.entities.RoleEntity;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
|
||||
/**
|
||||
* ApplicationModel used for JSON persistence.
|
||||
|
@ -362,48 +360,6 @@ public class ClientAdapter implements ClientModel {
|
|||
return mapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateIdentityProviders(List<ClientIdentityProviderMappingModel> identityProviders) {
|
||||
List<ClientIdentityProviderMappingEntity> stored = new ArrayList<ClientIdentityProviderMappingEntity>();
|
||||
|
||||
for (ClientIdentityProviderMappingModel model : identityProviders) {
|
||||
ClientIdentityProviderMappingEntity entity = new ClientIdentityProviderMappingEntity();
|
||||
|
||||
entity.setId(model.getIdentityProvider());
|
||||
entity.setRetrieveToken(model.isRetrieveToken());
|
||||
stored.add(entity);
|
||||
}
|
||||
|
||||
entity.setIdentityProviders(stored);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ClientIdentityProviderMappingModel> getIdentityProviders() {
|
||||
List<ClientIdentityProviderMappingModel> models = new ArrayList<>();
|
||||
|
||||
for (ClientIdentityProviderMappingEntity e : entity.getIdentityProviders()) {
|
||||
ClientIdentityProviderMappingModel model = new ClientIdentityProviderMappingModel();
|
||||
|
||||
model.setIdentityProvider(e.getId());
|
||||
model.setRetrieveToken(e.isRetrieveToken());
|
||||
|
||||
models.add(model);
|
||||
}
|
||||
|
||||
return models;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowedRetrieveTokenFromIdentityProvider(String providerId) {
|
||||
for (ClientIdentityProviderMappingEntity identityProviderMappingModel : entity.getIdentityProviders()) {
|
||||
if (identityProviderMappingModel.getId().equals(providerId)) {
|
||||
return identityProviderMappingModel.isRetrieveToken();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClientId() {
|
||||
return entity.getClientId();
|
||||
|
|
|
@ -16,18 +16,18 @@
|
|||
*/
|
||||
package org.keycloak.models.file.adapter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleContainerModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.entities.RoleEntity;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.entities.RoleEntity;
|
||||
|
||||
/**
|
||||
* RoleModel for JSON persistence.
|
||||
|
|
|
@ -16,11 +16,10 @@
|
|||
*/
|
||||
package org.keycloak.models.file.adapter;
|
||||
|
||||
import org.keycloak.connections.file.InMemoryModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
|
||||
import static org.keycloak.models.utils.Pbkdf2PasswordEncoder.getSalt;
|
||||
|
||||
import org.keycloak.models.GrantedConsentModel;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.PasswordPolicy;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
|
@ -28,7 +27,11 @@ import org.keycloak.models.UserCredentialModel;
|
|||
import org.keycloak.models.UserCredentialValueModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.entities.CredentialEntity;
|
||||
import org.keycloak.models.entities.FederatedIdentityEntity;
|
||||
import org.keycloak.models.entities.RoleEntity;
|
||||
import org.keycloak.models.entities.UserEntity;
|
||||
import org.keycloak.models.utils.Pbkdf2PasswordEncoder;
|
||||
import org.keycloak.util.Time;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
@ -39,12 +42,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.keycloak.connections.file.InMemoryModel;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.entities.FederatedIdentityEntity;
|
||||
import org.keycloak.models.entities.RoleEntity;
|
||||
import org.keycloak.models.entities.UserEntity;
|
||||
import org.keycloak.util.Time;
|
||||
import static org.keycloak.models.utils.Pbkdf2PasswordEncoder.getSalt;
|
||||
|
||||
/**
|
||||
* UserModel for JSON persistence.
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package org.keycloak.models.cache;
|
||||
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientIdentityProviderMappingModel;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleContainerModel;
|
||||
|
@ -249,24 +248,6 @@ public class ClientAdapter implements ClientModel {
|
|||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateIdentityProviders(List<ClientIdentityProviderMappingModel> identityProviders) {
|
||||
getDelegateForUpdate();
|
||||
updated.updateIdentityProviders(identityProviders);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ClientIdentityProviderMappingModel> getIdentityProviders() {
|
||||
if (updated != null) return updated.getIdentityProviders();
|
||||
return cached.getIdentityProviders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowedRetrieveTokenFromIdentityProvider(String providerId) {
|
||||
if (updated != null) return updated.isAllowedRetrieveTokenFromIdentityProvider(providerId);
|
||||
return cached.isAllowedRetrieveTokenFromIdentityProvider(providerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ProtocolMapperModel> getProtocolMappers() {
|
||||
if (updated != null) return updated.getProtocolMappers();
|
||||
|
|
|
@ -2,12 +2,12 @@ package org.keycloak.models.cache;
|
|||
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.CredentialValidationOutput;
|
||||
import org.keycloak.models.FederatedIdentityModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakTransaction;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.FederatedIdentityModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserFederationProviderModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
|
|
|
@ -2,11 +2,11 @@ package org.keycloak.models.cache;
|
|||
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.CredentialValidationOutput;
|
||||
import org.keycloak.models.FederatedIdentityModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.FederatedIdentityModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserFederationProviderModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
package org.keycloak.models.cache.entities;
|
||||
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientIdentityProviderMappingModel;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RealmProvider;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.cache.RealmCache;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
|
@ -37,7 +35,6 @@ public class CachedClient {
|
|||
private int notBefore;
|
||||
private Set<String> scope = new HashSet<String>();
|
||||
private Set<String> webOrigins = new HashSet<String>();
|
||||
private List<ClientIdentityProviderMappingModel> identityProviders = new ArrayList<ClientIdentityProviderMappingModel>();
|
||||
private Set<ProtocolMapperModel> protocolMappers = new HashSet<ProtocolMapperModel>();
|
||||
private boolean surrogateAuthRequired;
|
||||
private String managementUrl;
|
||||
|
@ -67,7 +64,6 @@ public class CachedClient {
|
|||
for (RoleModel role : model.getScopeMappings()) {
|
||||
scope.add(role.getId());
|
||||
}
|
||||
this.identityProviders = model.getIdentityProviders();
|
||||
for (ProtocolMapperModel mapper : model.getProtocolMappers()) {
|
||||
this.protocolMappers.add(mapper);
|
||||
}
|
||||
|
@ -145,34 +141,10 @@ public class CachedClient {
|
|||
return frontchannelLogout;
|
||||
}
|
||||
|
||||
public List<ClientIdentityProviderMappingModel> getIdentityProviders() {
|
||||
return this.identityProviders;
|
||||
}
|
||||
|
||||
public boolean hasIdentityProvider(String providerId) {
|
||||
for (ClientIdentityProviderMappingModel model : getIdentityProviders()) {
|
||||
if (model.getIdentityProvider().equals(providerId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public Set<ProtocolMapperModel> getProtocolMappers() {
|
||||
return protocolMappers;
|
||||
}
|
||||
|
||||
public boolean isAllowedRetrieveTokenFromIdentityProvider(String providerId) {
|
||||
for (ClientIdentityProviderMappingModel model : getIdentityProviders()) {
|
||||
if (model.getIdentityProvider().equals(providerId)) {
|
||||
return model.isRetrieveToken();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isSurrogateAuthRequired() {
|
||||
return surrogateAuthRequired;
|
||||
}
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
package org.keycloak.models.jpa;
|
||||
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientIdentityProviderMappingModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleContainerModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.jpa.entities.ClientEntity;
|
||||
import org.keycloak.models.jpa.entities.ClientIdentityProviderMappingEntity;
|
||||
import org.keycloak.models.jpa.entities.IdentityProviderEntity;
|
||||
import org.keycloak.models.jpa.entities.ProtocolMapperEntity;
|
||||
import org.keycloak.models.jpa.entities.RoleEntity;
|
||||
import org.keycloak.models.jpa.entities.ScopeMappingEntity;
|
||||
|
@ -263,88 +260,6 @@ public class ClientAdapter implements ClientModel {
|
|||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateIdentityProviders(List<ClientIdentityProviderMappingModel> identityProviders) {
|
||||
Collection<ClientIdentityProviderMappingEntity> entities = entity.getIdentityProviders();
|
||||
Set<String> already = new HashSet<>();
|
||||
List<ClientIdentityProviderMappingEntity> remove = new ArrayList<>();
|
||||
|
||||
for (ClientIdentityProviderMappingEntity entity : entities) {
|
||||
IdentityProviderEntity identityProvider = entity.getIdentityProvider();
|
||||
boolean toRemove = true;
|
||||
|
||||
for (ClientIdentityProviderMappingModel model : identityProviders) {
|
||||
if (model.getIdentityProvider().equals(identityProvider.getAlias())) {
|
||||
toRemove = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (toRemove) {
|
||||
remove.add(entity);
|
||||
} else {
|
||||
already.add(entity.getIdentityProvider().getAlias());
|
||||
}
|
||||
}
|
||||
for (ClientIdentityProviderMappingEntity entity : remove) {
|
||||
entities.remove(entity);
|
||||
em.remove(entity);
|
||||
}
|
||||
em.flush();
|
||||
for (ClientIdentityProviderMappingModel model : identityProviders) {
|
||||
ClientIdentityProviderMappingEntity mappingEntity = null;
|
||||
|
||||
if (!already.contains(model.getIdentityProvider())) {
|
||||
mappingEntity = new ClientIdentityProviderMappingEntity();
|
||||
entities.add(mappingEntity);
|
||||
} else {
|
||||
for (ClientIdentityProviderMappingEntity entity : entities) {
|
||||
if (entity.getIdentityProvider().getAlias().equals(model.getIdentityProvider())) {
|
||||
mappingEntity = entity;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TypedQuery<IdentityProviderEntity> query = em.createNamedQuery("findIdentityProviderByAlias", IdentityProviderEntity.class).setParameter("alias", model.getIdentityProvider());
|
||||
IdentityProviderEntity identityProviderEntity = query.getSingleResult();
|
||||
|
||||
mappingEntity.setIdentityProvider(identityProviderEntity);
|
||||
mappingEntity.setClient(this.entity);
|
||||
mappingEntity.setRetrieveToken(model.isRetrieveToken());
|
||||
|
||||
em.persist(mappingEntity);
|
||||
}
|
||||
em.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ClientIdentityProviderMappingModel> getIdentityProviders() {
|
||||
List<ClientIdentityProviderMappingModel> models = new ArrayList<ClientIdentityProviderMappingModel>();
|
||||
|
||||
for (ClientIdentityProviderMappingEntity entity : this.entity.getIdentityProviders()) {
|
||||
ClientIdentityProviderMappingModel model = new ClientIdentityProviderMappingModel();
|
||||
|
||||
model.setIdentityProvider(entity.getIdentityProvider().getAlias());
|
||||
model.setRetrieveToken(entity.isRetrieveToken());
|
||||
|
||||
models.add(model);
|
||||
}
|
||||
|
||||
return models;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowedRetrieveTokenFromIdentityProvider(String providerId) {
|
||||
for (ClientIdentityProviderMappingModel model : getIdentityProviders()) {
|
||||
if (model.getIdentityProvider().equals(providerId)) {
|
||||
return model.isRetrieveToken();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean contains(String str, String[] array) {
|
||||
for (String s : array) {
|
||||
if (str.equals(s)) return true;
|
||||
|
|
|
@ -25,12 +25,10 @@ import org.keycloak.util.Time;
|
|||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.TypedQuery;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
|
10
model/jpa/src/main/java/org/keycloak/models/jpa/entities/GrantedConsentEntity.java
Normal file → Executable file
10
model/jpa/src/main/java/org/keycloak/models/jpa/entities/GrantedConsentEntity.java
Normal file → Executable file
|
@ -1,25 +1,19 @@
|
|||
package org.keycloak.models.jpa.entities;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.CollectionTable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
|
|
3
model/jpa/src/main/java/org/keycloak/models/jpa/entities/GrantedConsentProtocolMapperEntity.java
Normal file → Executable file
3
model/jpa/src/main/java/org/keycloak/models/jpa/entities/GrantedConsentProtocolMapperEntity.java
Normal file → Executable file
|
@ -1,7 +1,5 @@
|
|||
package org.keycloak.models.jpa.entities;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
|
@ -12,6 +10,7 @@ import javax.persistence.ManyToOne;
|
|||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.Table;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
|
|
3
model/jpa/src/main/java/org/keycloak/models/jpa/entities/GrantedConsentRoleEntity.java
Normal file → Executable file
3
model/jpa/src/main/java/org/keycloak/models/jpa/entities/GrantedConsentRoleEntity.java
Normal file → Executable file
|
@ -1,7 +1,5 @@
|
|||
package org.keycloak.models.jpa.entities;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
|
@ -12,6 +10,7 @@ import javax.persistence.ManyToOne;
|
|||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.Table;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
|
|
|
@ -4,12 +4,10 @@ import com.mongodb.DBObject;
|
|||
import com.mongodb.QueryBuilder;
|
||||
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientIdentityProviderMappingModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.entities.ClientIdentityProviderMappingEntity;
|
||||
import org.keycloak.models.entities.ProtocolMapperEntity;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoClientEntity;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
|
||||
|
@ -396,49 +394,6 @@ public class ClientAdapter extends AbstractMongoAdapter<MongoClientEntity> imple
|
|||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void updateIdentityProviders(List<ClientIdentityProviderMappingModel> identityProviders) {
|
||||
List<ClientIdentityProviderMappingEntity> stored = new ArrayList<ClientIdentityProviderMappingEntity>();
|
||||
|
||||
for (ClientIdentityProviderMappingModel model : identityProviders) {
|
||||
ClientIdentityProviderMappingEntity entity = new ClientIdentityProviderMappingEntity();
|
||||
|
||||
entity.setId(model.getIdentityProvider());
|
||||
entity.setRetrieveToken(model.isRetrieveToken());
|
||||
stored.add(entity);
|
||||
}
|
||||
|
||||
getMongoEntity().setIdentityProviders(stored);
|
||||
updateMongoEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ClientIdentityProviderMappingModel> getIdentityProviders() {
|
||||
List<ClientIdentityProviderMappingModel> models = new ArrayList<ClientIdentityProviderMappingModel>();
|
||||
|
||||
for (ClientIdentityProviderMappingEntity entity : getMongoEntity().getIdentityProviders()) {
|
||||
ClientIdentityProviderMappingModel model = new ClientIdentityProviderMappingModel();
|
||||
|
||||
model.setIdentityProvider(entity.getId());
|
||||
model.setRetrieveToken(entity.isRetrieveToken());
|
||||
|
||||
models.add(model);
|
||||
}
|
||||
|
||||
return models;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowedRetrieveTokenFromIdentityProvider(String providerId) {
|
||||
for (ClientIdentityProviderMappingEntity identityProviderMappingModel : getMongoEntity().getIdentityProviders()) {
|
||||
if (identityProviderMappingModel.getId().equals(providerId)) {
|
||||
return identityProviderMappingModel.isRetrieveToken();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSurrogateAuthRequired() {
|
||||
return getMongoEntity().isSurrogateAuthRequired();
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package org.keycloak.models.mongo.keycloak.adapters;
|
||||
|
||||
import static org.keycloak.models.utils.Pbkdf2PasswordEncoder.getSalt;
|
||||
|
||||
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.GrantedConsentModel;
|
||||
|
@ -22,13 +20,14 @@ import org.keycloak.util.Time;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.keycloak.models.utils.Pbkdf2PasswordEncoder.getSalt;
|
||||
|
||||
/**
|
||||
* Wrapper around UserData object, which will persist wrapped object after each set operation (compatibility with picketlink based idm)
|
||||
*
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.keycloak.models.utils.RepresentationToModel;
|
|||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.services.resources.IdentityBrokerService;
|
||||
import org.keycloak.timer.TimerProvider;
|
||||
|
||||
import java.util.Collections;
|
||||
|
@ -84,6 +85,7 @@ public class RealmManager {
|
|||
setupMasterAdminManagement(realm);
|
||||
setupRealmAdminManagement(realm);
|
||||
setupAccountManagement(realm);
|
||||
setupBrokerService(realm);
|
||||
setupAdminConsole(realm);
|
||||
|
||||
return realm;
|
||||
|
@ -214,6 +216,19 @@ public class RealmManager {
|
|||
}
|
||||
}
|
||||
|
||||
public void setupBrokerService(RealmModel realm) {
|
||||
ClientModel client = realm.getClientNameMap().get(Constants.BROKER_SERVICE_CLIENT_ID);
|
||||
if (client == null) {
|
||||
client = new ClientManager(this).createClient(realm, Constants.BROKER_SERVICE_CLIENT_ID);
|
||||
client.setEnabled(true);
|
||||
client.setFullScopeAllowed(false);
|
||||
|
||||
for (String role : IdentityBrokerService.ROLES) {
|
||||
client.addRole(role).setDescription("${role_"+role+"}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public RealmModel importRealm(RealmRepresentation rep) {
|
||||
String id = rep.getId();
|
||||
if (id == null) {
|
||||
|
@ -228,6 +243,7 @@ public class RealmManager {
|
|||
setupMasterAdminManagement(realm);
|
||||
if (!hasRealmAdminManagementClient(rep)) setupRealmAdminManagement(realm);
|
||||
if (!hasAccountManagementClient(rep)) setupAccountManagement(realm);
|
||||
if (!hasBrokerClient(rep)) setupBrokerService(realm);
|
||||
if (!hasAdminConsoleClient(rep)) setupAdminConsole(realm);
|
||||
|
||||
RepresentationToModel.importRealm(session, rep, realm);
|
||||
|
@ -260,6 +276,15 @@ public class RealmManager {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
private boolean hasBrokerClient(RealmRepresentation rep) {
|
||||
if (rep.getClients() == null) return false;
|
||||
for (ClientRepresentation clientRep : rep.getClients()) {
|
||||
if (clientRep.getClientId().equals(Constants.BROKER_SERVICE_CLIENT_ID)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean hasAdminConsoleClient(RealmRepresentation rep) {
|
||||
if (rep.getClients() == null) return false;
|
||||
|
|
|
@ -34,17 +34,20 @@ import org.keycloak.events.EventType;
|
|||
import org.keycloak.login.LoginFormsProvider;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientSessionModel;
|
||||
import org.keycloak.models.Constants;
|
||||
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.RoleModel;
|
||||
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.representations.AccessToken;
|
||||
import org.keycloak.services.managers.AppAuthManager;
|
||||
import org.keycloak.services.managers.AuthenticationManager;
|
||||
import org.keycloak.services.managers.AuthenticationManager.AuthResult;
|
||||
|
@ -92,6 +95,8 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
|
|||
|
||||
private static final Logger LOGGER = Logger.getLogger(IdentityBrokerService.class);
|
||||
public static final String BROKER_PROVIDER_ID = "BROKER_PROVIDER_ID";
|
||||
public static final String READ_TOKEN_ROLE = "READ_TOKEN";
|
||||
public static final String[] ROLES = {READ_TOKEN_ROLE};
|
||||
|
||||
private final RealmModel realmModel;
|
||||
|
||||
|
@ -185,7 +190,8 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
|
|||
AuthResult authResult = authManager.authenticateBearerToken(this.session, this.realmModel, this.uriInfo, this.clientConnection, this.request.getHttpHeaders());
|
||||
|
||||
if (authResult != null) {
|
||||
String audience = authResult.getToken().getAudience();
|
||||
AccessToken token = authResult.getToken();
|
||||
String audience = token.getAudience();
|
||||
ClientModel clientModel = this.realmModel.getClientByClientId(audience);
|
||||
|
||||
if (clientModel == null) {
|
||||
|
@ -194,16 +200,16 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
|
|||
|
||||
session.getContext().setClient(clientModel);
|
||||
|
||||
if (!clientModel.isAllowedRetrieveTokenFromIdentityProvider(providerId)) {
|
||||
return corsResponse(badRequest("Client [" + audience + "] not authorized to retrieve tokens from identity provider [" + providerId + "]."), clientModel);
|
||||
}
|
||||
ClientModel brokerClient = realmModel.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID);
|
||||
if (brokerClient == null) {
|
||||
return corsResponse(forbidden("Realm has not migrated to support the broker token exchange service"), clientModel);
|
||||
|
||||
}
|
||||
Map<String, AccessToken.Access> resourceAccess = token.getResourceAccess();
|
||||
AccessToken.Access brokerRoles = resourceAccess == null ? null : resourceAccess.get(Constants.BROKER_SERVICE_CLIENT_ID);
|
||||
if (brokerRoles == null || !brokerRoles.isUserInRole(READ_TOKEN_ROLE)) {
|
||||
return corsResponse(forbidden("Client [" + audience + "] not authorized to retrieve tokens from identity provider [" + providerId + "]."), clientModel);
|
||||
|
||||
if (clientModel.isConsentRequired()) {
|
||||
return corsResponse(session.getProvider(LoginFormsProvider.class)
|
||||
.setClientSessionCode(authManager.extractAuthorizationHeaderToken(this.request.getHttpHeaders()))
|
||||
.setAccessRequest("Your information from " + providerId + " identity provider.")
|
||||
.setActionUri(this.uriInfo.getRequestUri())
|
||||
.createOAuthGrant(null), clientModel);
|
||||
}
|
||||
|
||||
IdentityProvider identityProvider = getIdentityProvider(session, realmModel, providerId);
|
||||
|
@ -232,18 +238,6 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
|
|||
}
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("{provider_id}/token")
|
||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
public Response consentTokenRetrieval(@PathParam("provider_id") String providerId,
|
||||
MultivaluedMap<String, String> formData) {
|
||||
if (formData.containsKey("cancel")) {
|
||||
return redirectToErrorPage(Messages.PERMISSION_NOT_APPROVED);
|
||||
}
|
||||
|
||||
return getToken(providerId, true);
|
||||
}
|
||||
|
||||
public Response authenticated(BrokeredIdentityContext context) {
|
||||
ClientSessionCode clientCode = null;
|
||||
IdentityProviderModel identityProviderConfig = context.getIdpConfig();
|
||||
|
@ -445,6 +439,11 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
|
|||
return ErrorResponse.error(message, Status.BAD_REQUEST);
|
||||
}
|
||||
|
||||
private Response forbidden(String message) {
|
||||
fireErrorEvent(message);
|
||||
return ErrorResponse.error(message, Status.FORBIDDEN);
|
||||
}
|
||||
|
||||
public static IdentityProvider getIdentityProvider(KeycloakSession session, RealmModel realm, String alias) {
|
||||
IdentityProviderModel identityProviderModel = realm.getIdentityProviderByAlias(alias);
|
||||
|
||||
|
@ -534,6 +533,13 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
|
|||
federatedUser.setFirstName(updatedIdentity.getFirstName());
|
||||
federatedUser.setLastName(updatedIdentity.getLastName());
|
||||
|
||||
|
||||
if (updatedIdentity.getIdpConfig().isStoreToken()) {
|
||||
RoleModel readTokenRole = realmModel.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(READ_TOKEN_ROLE);
|
||||
federatedUser.grantRole(readTokenRole);
|
||||
}
|
||||
|
||||
|
||||
this.session.users().addFederatedIdentity(this.realmModel, federatedUser, federatedIdentityModel);
|
||||
|
||||
updatedIdentity.getIdp().importNewUser(session, realmModel, federatedUser, updatedIdentity);
|
||||
|
|
|
@ -84,8 +84,6 @@ public class IdentityProviderResource {
|
|||
public Response delete() {
|
||||
this.auth.requireManage();
|
||||
|
||||
removeClientIdentityProviders(this.realm.getClients(), this.identityProviderModel);
|
||||
|
||||
this.realm.removeIdentityProviderByAlias(this.identityProviderModel.getAlias());
|
||||
|
||||
return Response.noContent().build();
|
||||
|
@ -109,7 +107,6 @@ public class IdentityProviderResource {
|
|||
// Admin changed the ID (alias) of identity provider. We must update all clients and users
|
||||
logger.debug("Changing providerId in all clients and linked users. oldProviderId=" + oldProviderId + ", newProviderId=" + newProviderId);
|
||||
|
||||
updateClientsAfterProviderAliasChange(this.realm.getClients(), oldProviderId, newProviderId);
|
||||
updateUsersAfterProviderAliasChange(this.session.users().getUsers(this.realm), oldProviderId, newProviderId);
|
||||
}
|
||||
|
||||
|
@ -131,25 +128,6 @@ public class IdentityProviderResource {
|
|||
return null;
|
||||
}
|
||||
|
||||
private void updateClientsAfterProviderAliasChange(List<ClientModel> clients, String oldProviderId, String newProviderId) {
|
||||
for (ClientModel client : clients) {
|
||||
List<ClientIdentityProviderMappingModel> clientIdentityProviders = client.getIdentityProviders();
|
||||
boolean found = true;
|
||||
|
||||
for (ClientIdentityProviderMappingModel mappingModel : clientIdentityProviders) {
|
||||
if (mappingModel.getIdentityProvider().equals(oldProviderId)) {
|
||||
mappingModel.setIdentityProvider(newProviderId);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
client.updateIdentityProviders(clientIdentityProviders);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateUsersAfterProviderAliasChange(List<UserModel> users, String oldProviderId, String newProviderId) {
|
||||
for (UserModel user : users) {
|
||||
FederatedIdentityModel federatedIdentity = this.session.users().getFederatedIdentity(user, oldProviderId, this.realm);
|
||||
|
@ -285,18 +263,5 @@ public class IdentityProviderResource {
|
|||
realm.removeIdentityProviderMapper(model);
|
||||
}
|
||||
|
||||
private void removeClientIdentityProviders(List<ClientModel> clients, IdentityProviderModel identityProvider) {
|
||||
for (ClientModel clientModel : clients) {
|
||||
List<ClientIdentityProviderMappingModel> identityProviders = clientModel.getIdentityProviders();
|
||||
|
||||
for (ClientIdentityProviderMappingModel providerMappingModel : new ArrayList<>(identityProviders)) {
|
||||
if (providerMappingModel.getIdentityProvider().equals(identityProvider.getAlias())) {
|
||||
identityProviders.remove(providerMappingModel);
|
||||
clientModel.updateIdentityProviders(identityProviders);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
4
testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
Normal file → Executable file
4
testsuite/integration/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
Normal file → Executable file
|
@ -42,7 +42,7 @@ public class ClientTest extends AbstractClientTest {
|
|||
|
||||
@Test
|
||||
public void getClients() {
|
||||
assertNames(realm.clients().findAll(), "account", "realm-management", "security-admin-console");
|
||||
assertNames(realm.clients().findAll(), "account", "realm-management", "security-admin-console", "broker");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -52,7 +52,7 @@ public class ClientTest extends AbstractClientTest {
|
|||
rep.setEnabled(true);
|
||||
realm.clients().create(rep);
|
||||
|
||||
assertNames(realm.clients().findAll(), "account", "realm-management", "security-admin-console", "my-app");
|
||||
assertNames(realm.clients().findAll(), "account", "realm-management", "security-admin-console", "broker", "my-app");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -32,14 +32,17 @@ import org.junit.Test;
|
|||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.models.ClientIdentityProviderMappingModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.FederatedIdentityModel;
|
||||
import org.keycloak.models.IdentityProviderModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserModel.RequiredAction;
|
||||
import org.keycloak.representations.IDToken;
|
||||
import org.keycloak.services.Urls;
|
||||
import org.keycloak.services.resources.IdentityBrokerService;
|
||||
import org.keycloak.testsuite.OAuthClient;
|
||||
import org.keycloak.testsuite.OAuthClient.AccessTokenResponse;
|
||||
import org.keycloak.testsuite.broker.util.UserSessionStatusServlet.UserSessionStatus;
|
||||
|
@ -243,6 +246,7 @@ public abstract class AbstractIdentityProviderTest {
|
|||
FederatedIdentityModel federatedIdentityModel = federatedIdentities.iterator().next();
|
||||
|
||||
assertEquals(getProviderId(), federatedIdentityModel.getIdentityProvider());
|
||||
revokeGrant();
|
||||
|
||||
driver.navigate().to("http://localhost:8081/test-app/logout");
|
||||
driver.navigate().to("http://localhost:8081/test-app");
|
||||
|
@ -285,27 +289,12 @@ public abstract class AbstractIdentityProviderTest {
|
|||
RealmModel realm = getRealm();
|
||||
ClientModel clientModel = realm.getClientByClientId("test-app");
|
||||
|
||||
// This client doesn't have any specific identity providers settings
|
||||
ClientModel client2 = realm.getClientByClientId("test-app");
|
||||
assertEquals(0, client2.getIdentityProviders().size());
|
||||
|
||||
// Provider button is available on login page
|
||||
this.driver.navigate().to("http://localhost:8081/test-app/");
|
||||
assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
|
||||
loginPage.findSocialButton(getProviderId());
|
||||
|
||||
// Add identityProvider to client model
|
||||
List<ClientIdentityProviderMappingModel> appIdentityProviders = new ArrayList<ClientIdentityProviderMappingModel>();
|
||||
ClientIdentityProviderMappingModel mapping = new ClientIdentityProviderMappingModel();
|
||||
mapping.setIdentityProvider(getProviderId());
|
||||
mapping.setRetrieveToken(true);
|
||||
appIdentityProviders.add(mapping);
|
||||
clientModel.updateIdentityProviders(appIdentityProviders);
|
||||
|
||||
// Provider button still available on login page
|
||||
this.driver.navigate().to("http://localhost:8081/test-app/");
|
||||
loginPage.findSocialButton(getProviderId());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserAlreadyExistsWhenUpdatingProfile() {
|
||||
|
@ -411,12 +400,16 @@ public abstract class AbstractIdentityProviderTest {
|
|||
revokeGrant();
|
||||
|
||||
// Logout from account management
|
||||
String pageSource = driver.getPageSource();
|
||||
accountFederatedIdentityPage.logout();
|
||||
assertTrue(driver.getTitle().equals("Log in to realm-with-broker"));
|
||||
assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
|
||||
|
||||
// Try to login. Previous link is not valid anymore, so now it should try to register new user
|
||||
this.loginPage.clickSocial(identityProviderModel.getAlias());
|
||||
this.loginPage.login("test-user", "password");
|
||||
doAfterProviderAuthentication();
|
||||
String current = driver.getCurrentUrl();
|
||||
this.updateProfilePage.assertCurrent();
|
||||
}
|
||||
|
||||
|
@ -429,6 +422,52 @@ public abstract class AbstractIdentityProviderTest {
|
|||
driver.findElement(By.className("model-oidc-idp"));
|
||||
}
|
||||
|
||||
protected void configureClientRetrieveToken(String clientId) {
|
||||
RealmModel realm = getRealm();
|
||||
RoleModel readTokenRole = realm.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(IdentityBrokerService.READ_TOKEN_ROLE);
|
||||
ClientModel client = realm.getClientByClientId(clientId);
|
||||
if (!client.hasScope(readTokenRole)) client.addScopeMapping(readTokenRole);
|
||||
|
||||
brokerServerRule.stopSession(session, true);
|
||||
session = brokerServerRule.startSession();
|
||||
|
||||
}
|
||||
|
||||
protected void configureUserRetrieveToken(String username) {
|
||||
RealmModel realm = getRealm();
|
||||
UserModel user = session.users().getUserByUsername(username, realm);
|
||||
RoleModel readTokenRole = realm.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(IdentityBrokerService.READ_TOKEN_ROLE);
|
||||
if (user != null && !user.hasRole(readTokenRole)) {
|
||||
user.grantRole(readTokenRole);
|
||||
}
|
||||
brokerServerRule.stopSession(session, true);
|
||||
session = brokerServerRule.startSession();
|
||||
|
||||
}
|
||||
|
||||
protected void unconfigureClientRetrieveToken(String clientId) {
|
||||
RealmModel realm = getRealm();
|
||||
RoleModel readTokenRole = realm.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(IdentityBrokerService.READ_TOKEN_ROLE);
|
||||
ClientModel client = realm.getClientByClientId(clientId);
|
||||
if (client.hasScope(readTokenRole)) client.deleteScopeMapping(readTokenRole);
|
||||
|
||||
brokerServerRule.stopSession(session, true);
|
||||
session = brokerServerRule.startSession();
|
||||
|
||||
}
|
||||
|
||||
protected void unconfigureUserRetrieveToken(String username) {
|
||||
RealmModel realm = getRealm();
|
||||
UserModel user = session.users().getUserByUsername(username, realm);
|
||||
RoleModel readTokenRole = realm.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(IdentityBrokerService.READ_TOKEN_ROLE);
|
||||
if (user != null && user.hasRole(readTokenRole)) {
|
||||
user.deleteRoleMapping(readTokenRole);
|
||||
}
|
||||
brokerServerRule.stopSession(session, true);
|
||||
session = brokerServerRule.startSession();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTokenStorageAndRetrievalByApplication() {
|
||||
IdentityProviderModel identityProviderModel = getIdentityProviderModel();
|
||||
|
@ -448,8 +487,6 @@ public abstract class AbstractIdentityProviderTest {
|
|||
|
||||
assertNotNull(identityModel.getToken());
|
||||
|
||||
configureRetrieveToken(realm.getClientByClientId("test-app"), getProviderId(), false);
|
||||
|
||||
UserSessionStatus userSessionStatus = retrieveSessionStatus();
|
||||
String accessToken = userSessionStatus.getAccessTokenString();
|
||||
URI tokenEndpointUrl = Urls.identityProviderRetrieveToken(BASE_URI, getProviderId(), realm.getName());
|
||||
|
@ -463,112 +500,43 @@ public abstract class AbstractIdentityProviderTest {
|
|||
Client client = ClientBuilder.newBuilder().register(authFilter).build();
|
||||
WebTarget tokenEndpoint = client.target(tokenEndpointUrl);
|
||||
Response response = tokenEndpoint.request().get();
|
||||
assertEquals(Status.OK.getStatusCode(), response.getStatus());
|
||||
assertNotNull(response.readEntity(String.class));
|
||||
revokeGrant();
|
||||
|
||||
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
|
||||
|
||||
configureRetrieveToken(getRealm().getClientByClientId("test-app"), getProviderId(), true);
|
||||
driver.navigate().to("http://localhost:8081/test-app/logout");
|
||||
String currentUrl = this.driver.getCurrentUrl();
|
||||
System.out.println("after logout currentUrl: " + currentUrl);
|
||||
assertTrue(currentUrl.startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
|
||||
|
||||
client = ClientBuilder.newBuilder().register(authFilter).build();
|
||||
unconfigureUserRetrieveToken(getProviderId() + ".test-user");
|
||||
loginIDP("test-user");
|
||||
//authenticateWithIdentityProvider(identityProviderModel, "test-user");
|
||||
assertEquals("http://localhost:8081/test-app", driver.getCurrentUrl());
|
||||
|
||||
userSessionStatus = retrieveSessionStatus();
|
||||
accessToken = userSessionStatus.getAccessTokenString();
|
||||
final String authHeader2 = "Bearer " + accessToken;
|
||||
ClientRequestFilter authFilter2 = new ClientRequestFilter() {
|
||||
@Override
|
||||
public void filter(ClientRequestContext requestContext) throws IOException {
|
||||
requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader2);
|
||||
}
|
||||
};
|
||||
client = ClientBuilder.newBuilder().register(authFilter2).build();
|
||||
tokenEndpoint = client.target(tokenEndpointUrl);
|
||||
response = tokenEndpoint.request().get();
|
||||
|
||||
assertEquals(Status.OK.getStatusCode(), response.getStatus());
|
||||
assertNotNull(response.readEntity(String.class));
|
||||
assertEquals(Status.FORBIDDEN.getStatusCode(), response.getStatus());
|
||||
|
||||
revokeGrant();
|
||||
driver.navigate().to("http://localhost:8081/test-app/logout");
|
||||
driver.navigate().to("http://localhost:8081/test-app");
|
||||
|
||||
assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTokenStorageAndRetrievalByOAuthClient() {
|
||||
IdentityProviderModel identityProviderModel = getIdentityProviderModel();
|
||||
|
||||
identityProviderModel.setStoreToken(true);
|
||||
identityProviderModel.setUpdateProfileFirstLogin(false);
|
||||
|
||||
driver.navigate().to("http://localhost:8081/test-app");
|
||||
|
||||
// choose the identity provider
|
||||
this.loginPage.clickSocial(getProviderId());
|
||||
|
||||
assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8082/auth/"));
|
||||
|
||||
// log in to identity provider
|
||||
this.loginPage.login("test-user", "password");
|
||||
|
||||
doAfterProviderAuthentication();
|
||||
|
||||
changePasswordPage.realm("realm-with-broker");
|
||||
changePasswordPage.open();
|
||||
changePasswordPage.changePassword("password", "password");
|
||||
|
||||
driver.navigate().to("http://localhost:8081/test-app/logout");
|
||||
|
||||
oauth.realm("realm-with-broker");
|
||||
oauth.redirectUri("http://localhost:8081/third-party");
|
||||
oauth.clientId("third-party");
|
||||
oauth.doLoginGrant("test-user@localhost", "password");
|
||||
|
||||
grantPage.assertCurrent();
|
||||
grantPage.accept();
|
||||
|
||||
assertTrue(oauth.getCurrentQuery().containsKey(OAuth2Constants.CODE));
|
||||
|
||||
ClientModel clientModel = getRealm().getClientByClientId("third-party");
|
||||
assertEquals(0, clientModel.getIdentityProviders().size());
|
||||
|
||||
configureRetrieveToken(clientModel, getProviderId(), true);
|
||||
|
||||
AccessTokenResponse accessToken = oauth.doAccessTokenRequest(oauth.getCurrentQuery().get(OAuth2Constants.CODE), "password");
|
||||
|
||||
doTokenRequest(accessToken.getAccessToken());
|
||||
}
|
||||
|
||||
public void doTokenRequest(String token) {
|
||||
try {
|
||||
HttpClient client = new DefaultHttpClient();
|
||||
HttpGet get = new HttpGet(Urls.identityProviderRetrieveToken(BASE_URI, getProviderId(), getRealm().getName()));
|
||||
|
||||
get.setHeader("Authorization", "Bearer " + token);
|
||||
|
||||
HttpResponse response = client.execute(get);
|
||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||
|
||||
assertNotNull(IOUtils.toString(response.getEntity().getContent()));
|
||||
} catch (Exception e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void configureRetrieveToken(ClientModel clientModel, String providerId, boolean retrieveToken) {
|
||||
List<ClientIdentityProviderMappingModel> providerMappingModels = clientModel.getIdentityProviders();
|
||||
ClientIdentityProviderMappingModel providerMappingModel = null;
|
||||
|
||||
// Check if provider is already linked with this client
|
||||
for (ClientIdentityProviderMappingModel current : providerMappingModels) {
|
||||
if (current.getIdentityProvider().equals(providerId)) {
|
||||
providerMappingModel = current;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Link provider with client if not linked yet
|
||||
if (providerMappingModel == null) {
|
||||
providerMappingModel = new ClientIdentityProviderMappingModel();
|
||||
providerMappingModel.setIdentityProvider(providerId);
|
||||
providerMappingModels.add(providerMappingModel);
|
||||
}
|
||||
|
||||
providerMappingModel.setRetrieveToken(retrieveToken);
|
||||
|
||||
clientModel.updateIdentityProviders(providerMappingModels);
|
||||
|
||||
brokerServerRule.stopSession(session, true);
|
||||
session = brokerServerRule.startSession();
|
||||
}
|
||||
|
||||
protected abstract void doAssertTokenRetrieval(String pageSource);
|
||||
|
||||
private UserModel assertSuccessfulAuthentication(IdentityProviderModel identityProviderModel, String username, String expectedEmail) {
|
||||
|
@ -605,19 +573,8 @@ public abstract class AbstractIdentityProviderTest {
|
|||
}
|
||||
|
||||
private void authenticateWithIdentityProvider(IdentityProviderModel identityProviderModel, String username) {
|
||||
driver.navigate().to("http://localhost:8081/test-app");
|
||||
loginIDP(username);
|
||||
|
||||
assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
|
||||
|
||||
// choose the identity provider
|
||||
this.loginPage.clickSocial(getProviderId());
|
||||
|
||||
assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8082/auth/"));
|
||||
System.out.println(this.driver.getCurrentUrl());
|
||||
// log in to identity provider
|
||||
this.loginPage.login(username, "password");
|
||||
|
||||
doAfterProviderAuthentication();
|
||||
|
||||
if (identityProviderModel.isUpdateProfileFirstLogin()) {
|
||||
String userEmail = "new@email.com";
|
||||
|
@ -630,6 +587,22 @@ public abstract class AbstractIdentityProviderTest {
|
|||
}
|
||||
}
|
||||
|
||||
private void loginIDP(String username) {
|
||||
driver.navigate().to("http://localhost:8081/test-app");
|
||||
|
||||
assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/auth"));
|
||||
|
||||
// choose the identity provider
|
||||
this.loginPage.clickSocial(getProviderId());
|
||||
|
||||
String currentUrl = this.driver.getCurrentUrl();
|
||||
assertTrue(currentUrl.startsWith("http://localhost:8082/auth/"));
|
||||
System.out.println(this.driver.getCurrentUrl());
|
||||
// log in to identity provider
|
||||
this.loginPage.login(username, "password");
|
||||
doAfterProviderAuthentication();
|
||||
}
|
||||
|
||||
protected UserModel getFederatedUser() {
|
||||
UserSessionStatus userSessionStatus = retrieveSessionStatus();
|
||||
IDToken idToken = userSessionStatus.getIdToken();
|
||||
|
|
|
@ -118,32 +118,6 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
|
|||
this.realmManager.removeRealm(realm);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplicationIdentityProviders() throws Exception {
|
||||
RealmModel realm = installTestRealm();
|
||||
|
||||
ClientModel client = realm.getClientByClientId("test-app-with-allowed-providers");
|
||||
List<ClientIdentityProviderMappingModel> identityProviders = client.getIdentityProviders();
|
||||
|
||||
assertEquals(1, identityProviders.size());
|
||||
|
||||
ClientIdentityProviderMappingModel identityProviderMappingModel = identityProviders.get(0);
|
||||
|
||||
assertEquals("kc-oidc-idp", identityProviderMappingModel.getIdentityProvider());
|
||||
assertEquals(false, identityProviderMappingModel.isRetrieveToken());
|
||||
|
||||
identityProviders.remove(identityProviderMappingModel);
|
||||
|
||||
client.updateIdentityProviders(identityProviders);
|
||||
|
||||
client = realm.getClientById(client.getId());
|
||||
identityProviders = client.getIdentityProviders();
|
||||
|
||||
assertEquals(0, identityProviders.size());
|
||||
this.realmManager.removeRealm(realm);
|
||||
}
|
||||
|
||||
|
||||
private void assertIdentityProviderConfig(List<IdentityProviderModel> identityProviders) {
|
||||
assertFalse(identityProviders.isEmpty());
|
||||
|
||||
|
|
|
@ -75,8 +75,8 @@ public class OIDCKeyCloakServerBrokerBasicTest extends AbstractIdentityProviderT
|
|||
@Override
|
||||
protected void doAfterProviderAuthentication() {
|
||||
// grant access to broker-app
|
||||
grantPage.assertCurrent();
|
||||
grantPage.accept();
|
||||
//grantPage.assertCurrent();
|
||||
//grantPage.accept();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -120,4 +120,14 @@ public class OIDCKeyCloakServerBrokerBasicTest extends AbstractIdentityProviderT
|
|||
public void testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername_emailNotProvided() {
|
||||
super.testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername_emailNotProvided();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTokenStorageAndRetrievalByApplication() {
|
||||
super.testTokenStorageAndRetrievalByApplication();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAccountManagementLinkIdentity() {
|
||||
super.testAccountManagementLinkIdentity();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,8 +67,8 @@ public class SAMLKeyCloakServerBrokerBasicTest extends AbstractIdentityProviderT
|
|||
|
||||
@Override
|
||||
protected void doAssertFederatedUserNoEmail(UserModel federatedUser) {
|
||||
assertEquals("kc-saml-idp-basic.", federatedUser.getUsername());
|
||||
assertEquals("", federatedUser.getEmail());
|
||||
assertEquals("kc-saml-idp-basic.test-user-noemail", federatedUser.getUsername());
|
||||
//assertEquals("", federatedUser.getEmail());
|
||||
assertEquals(null, federatedUser.getFirstName());
|
||||
assertEquals(null, federatedUser.getLastName());
|
||||
}
|
||||
|
@ -94,15 +94,24 @@ public class SAMLKeyCloakServerBrokerBasicTest extends AbstractIdentityProviderT
|
|||
super.testSuccessfulAuthenticationWithoutUpdateProfile();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test
|
||||
public void testTokenStorageAndRetrievalByOAuthClient() {
|
||||
super.testTokenStorageAndRetrievalByOAuthClient();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test
|
||||
public void testSuccessfulAuthentication() {
|
||||
super.testSuccessfulAuthentication();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAccountManagementLinkIdentity() {
|
||||
super.testAccountManagementLinkIdentity();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTokenStorageAndRetrievalByApplication() {
|
||||
super.testTokenStorageAndRetrievalByApplication();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername() {
|
||||
super.testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,8 +67,8 @@ public class SAMLKeyCloakServerBrokerWithSignatureTest extends AbstractIdentityP
|
|||
|
||||
@Override
|
||||
protected void doAssertFederatedUserNoEmail(UserModel federatedUser) {
|
||||
assertEquals("kc-saml-signed-idp.", federatedUser.getUsername());
|
||||
assertEquals("", federatedUser.getEmail());
|
||||
assertEquals("kc-saml-signed-idp.test-user-noemail", federatedUser.getUsername());
|
||||
//assertEquals("", federatedUser.getEmail());
|
||||
assertEquals(null, federatedUser.getFirstName());
|
||||
assertEquals(null, federatedUser.getLastName());
|
||||
}
|
||||
|
@ -93,4 +93,8 @@ public class SAMLKeyCloakServerBrokerWithSignatureTest extends AbstractIdentityP
|
|||
super.testSuccessfulAuthentication();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTokenStorageAndRetrievalByApplication() {
|
||||
super.testTokenStorageAndRetrievalByApplication();
|
||||
}
|
||||
}
|
||||
|
|
8
testsuite/integration/src/test/java/org/keycloak/testsuite/broker/util/UserSessionStatusServlet.java
Normal file → Executable file
8
testsuite/integration/src/test/java/org/keycloak/testsuite/broker/util/UserSessionStatusServlet.java
Normal file → Executable file
|
@ -27,6 +27,7 @@ import javax.servlet.ServletException;
|
|||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Serializable;
|
||||
|
@ -39,8 +40,11 @@ public class UserSessionStatusServlet extends HttpServlet {
|
|||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
if (req.getRequestURI().toString().endsWith("logout")) {
|
||||
resp.setStatus(200);
|
||||
req.logout();
|
||||
String redirect = UriBuilder.fromUri("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/logout")
|
||||
.queryParam("redirect_uri", "http://localhost:8081/test-app").build().toString();
|
||||
resp.sendRedirect(redirect);
|
||||
//resp.setStatus(200);
|
||||
//req.logout();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ public class ImportTest extends AbstractModelTest {
|
|||
Assert.assertEquals(0, session.users().getFederatedIdentities(user, realm).size());
|
||||
|
||||
List<ClientModel> resources = realm.getClients();
|
||||
Assert.assertEquals(6, resources.size());
|
||||
Assert.assertEquals(7, resources.size());
|
||||
|
||||
// Test applications imported
|
||||
ClientModel application = realm.getClientByClientId("Application");
|
||||
|
@ -92,7 +92,7 @@ public class ImportTest extends AbstractModelTest {
|
|||
Assert.assertNotNull(otherApp);
|
||||
Assert.assertNull(nonExisting);
|
||||
Map<String, ClientModel> clients = realm.getClientNameMap();
|
||||
Assert.assertEquals(6, clients.size());
|
||||
Assert.assertEquals(7, clients.size());
|
||||
Assert.assertTrue(clients.values().contains(application));
|
||||
Assert.assertTrue(clients.values().contains(otherApp));
|
||||
Assert.assertTrue(clients.values().contains(accountApp));
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
"clients" : [
|
||||
{
|
||||
"clientId": "broker-app",
|
||||
"consentRequired": "true",
|
||||
"consentRequired": "false",
|
||||
"enabled": true,
|
||||
"secret": "secret",
|
||||
"redirectUris": [
|
||||
"http://localhost:8081/auth/realms/realm-with-broker/broker/kc-oidc-idp/endpoint"
|
||||
"http://localhost:8081/auth/realms/realm-with-broker/broker/kc-oidc-idp/endpoint/*"
|
||||
],
|
||||
"protocolMappers": [
|
||||
{
|
||||
|
|
|
@ -15,6 +15,10 @@
|
|||
"http://localhost:8081/auth/realms/realm-with-broker/broker/kc-saml-signed-idp/endpoint"
|
||||
],
|
||||
"attributes": {
|
||||
"saml_single_logout_service_url_post": "http://localhost:8081/auth/realms/realm-with-broker/broker/kc-saml-signed-idp/endpoint",
|
||||
"saml_assertion_consumer_url_post": "http://localhost:8081/auth/realms/realm-with-broker/broker/kc-saml-signed-idp/endpoint",
|
||||
"saml_force_name_id_format": "true",
|
||||
"saml_name_id_format": "username",
|
||||
"saml.assertion.signature": "true",
|
||||
"saml.server.signature": "true",
|
||||
"saml.signature.algorithm": "RSA_SHA256",
|
||||
|
@ -46,6 +50,18 @@
|
|||
"attribute.name": "mobile",
|
||||
"attribute.nameformat": "Basic"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "email",
|
||||
"protocol": "saml",
|
||||
"protocolMapper": "saml-user-property-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {
|
||||
"user.attribute": "email",
|
||||
"attribute.name": "urn:oid:1.2.840.113549.1.9.1",
|
||||
"attribute.nameformat": "urn:oasis:names:tc:SAML:2.0:attrname-format:uri",
|
||||
"friendly.name": "email"
|
||||
}
|
||||
}
|
||||
|
||||
]
|
||||
|
|
|
@ -15,7 +15,12 @@
|
|||
"http://localhost:8081/auth/realms/realm-with-broker/broker/kc-saml-idp-basic/endpoint"
|
||||
],
|
||||
"attributes": {
|
||||
"saml.authnstatement": "true"
|
||||
"saml.authnstatement": "true",
|
||||
"saml_single_logout_service_url_post": "http://localhost:8081/auth/realms/realm-with-broker/broker/kc-saml-idp-basic/endpoint",
|
||||
"saml_assertion_consumer_url_post": "http://localhost:8081/auth/realms/realm-with-broker/broker/kc-saml-idp-basic/endpoint",
|
||||
"saml_force_name_id_format": "true",
|
||||
"saml_name_id_format": "username"
|
||||
|
||||
},
|
||||
"protocolMappers": [
|
||||
{
|
||||
|
@ -40,6 +45,18 @@
|
|||
"attribute.name": "mobile",
|
||||
"attribute.nameformat": "Basic"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "email",
|
||||
"protocol": "saml",
|
||||
"protocolMapper": "saml-user-property-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {
|
||||
"user.attribute": "email",
|
||||
"attribute.name": "urn:oid:1.2.840.113549.1.9.1",
|
||||
"attribute.nameformat": "urn:oasis:names:tc:SAML:2.0:attrname-format:uri",
|
||||
"friendly.name": "email"
|
||||
}
|
||||
}
|
||||
|
||||
]
|
||||
|
|
|
@ -112,6 +112,7 @@
|
|||
"updateProfileFirstLogin" : "true",
|
||||
"config": {
|
||||
"singleSignOnServiceUrl": "http://localhost:8082/auth/realms/realm-with-saml-signed-idp/protocol/saml",
|
||||
"singleLogoutServiceUrl": "http://localhost:8082/auth/realms/realm-with-saml-signed-idp/protocol/saml",
|
||||
"nameIDPolicyFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
|
||||
"signingCertificate": "MIIDdzCCAl+gAwIBAgIEbySuqTANBgkqhkiG9w0BAQsFADBsMRAwDgYDVQQGEwdVbmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYDVQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3duMB4XDTE1MDEyODIyMTYyMFoXDTE3MTAyNDIyMTYyMFowbDEQMA4GA1UEBhMHVW5rbm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UEChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAII/K9NNvXi9IySl7+l2zY/kKrGTtuR4WdCI0xLW/Jn4dLY7v1/HOnV4CC4ecFOzhdNFPtJkmEhP/q62CpmOYOKApXk3tfmm2rwEz9bWprVxgFGKnbrWlz61Z/cjLAlhD3IUj2ZRBquYgSXQPsYfXo1JmSWF5pZ9uh1FVqu9f4wvRqY20ZhUN+39F+1iaBsoqsrbXypCn1HgZkW1/9D9GZug1c3vB4wg1TwZZWRNGtxwoEhdK6dPrNcZ+6PdanVilWrbQFbBjY4wz8/7IMBzssoQ7Usmo8F1Piv0FGfaVeJqBrcAvbiBMpk8pT+27u6p8VyIX6LhGvnxIwM07NByeSUCAwEAAaMhMB8wHQYDVR0OBBYEFFlcNuTYwI9W0tQ224K1gFJlMam0MA0GCSqGSIb3DQEBCwUAA4IBAQB5snl1KWOJALtAjLqD0mLPg1iElmZP82Lq1htLBt3XagwzU9CaeVeCQ7lTp+DXWzPa9nCLhsC3QyrV3/+oqNli8C6NpeqI8FqN2yQW/QMWN1m5jWDbmrWwtQzRUn/rh5KEb5m3zPB+tOC6e/2bV3QeQebxeW7lVMD0tSCviUg1MQf1l2gzuXQo60411YwqrXwk6GMkDOhFDQKDlMchO3oRbQkGbcP8UeiKAXjMeHfzbiBr+cWz8NYZEtxUEDYDjTpKrYCSMJBXpmgVJCZ00BswbksxJwaGqGMPpUKmCV671pf3m8nq3xyiHMDGuGwtbU+GE8kVx85menmp8+964nin",
|
||||
"wantAuthnRequestsSigned": true,
|
||||
|
@ -128,6 +129,7 @@
|
|||
"updateProfileFirstLogin" : "true",
|
||||
"config": {
|
||||
"singleSignOnServiceUrl": "http://localhost:8082/auth/realms/realm-with-saml-idp-basic/protocol/saml",
|
||||
"singleLogoutServiceUrl": "http://localhost:8082/auth/realms/realm-with-saml-idp-basic/protocol/saml",
|
||||
"nameIDPolicyFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
|
||||
"forceAuthn": true,
|
||||
"postBindingResponse": true,
|
||||
|
@ -155,6 +157,7 @@
|
|||
"providerId" : "keycloak-oidc",
|
||||
"enabled": true,
|
||||
"updateProfileFirstLogin" : "false",
|
||||
"storeToken" : "true",
|
||||
"config": {
|
||||
"clientId": "broker-app",
|
||||
"clientSecret": "secret",
|
||||
|
@ -162,6 +165,7 @@
|
|||
"authorizationUrl": "http://localhost:8082/auth/realms/realm-with-oidc-identity-provider/tokens/login",
|
||||
"tokenUrl": "http://localhost:8082/auth/realms/realm-with-oidc-identity-provider/protocol/openid-connect/token",
|
||||
"userInfoUrl": "http://localhost:8082/auth/realms/realm-with-oidc-identity-provider/protocol/openid-connect/userinfo",
|
||||
"logoutUrl": "http://localhost:8082/auth/realms/realm-with-oidc-identity-provider/tokens/logout",
|
||||
"defaultScope": "email profile"
|
||||
}
|
||||
}
|
||||
|
@ -248,8 +252,8 @@
|
|||
"name": "test-app",
|
||||
"enabled": true,
|
||||
"publicClient": true,
|
||||
"adminUrl": "http://localhost:8081/auth",
|
||||
"baseUrl": "http://localhost:8081/auth",
|
||||
"adminUrl": "http://localhost:8081/test-app",
|
||||
"baseUrl": "http://localhost:8081/test-app",
|
||||
"redirectUris": [
|
||||
"/test-app/*"
|
||||
],
|
||||
|
|
Loading…
Reference in a new issue