client templates backend
This commit is contained in:
parent
06e44b185e
commit
96e1813b34
55 changed files with 2043 additions and 48 deletions
40
connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.8.0.xml
Normal file → Executable file
40
connections/jpa-liquibase/src/main/resources/META-INF/jpa-changelog-1.8.0.xml
Normal file → Executable file
|
@ -7,6 +7,46 @@
|
|||
<constraints nullable="true"/>
|
||||
</column>
|
||||
</addColumn>
|
||||
<createTable tableName="CLIENT_TEMPLATE">
|
||||
<column name="ID" type="VARCHAR(36)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="NAME" type="VARCHAR(255)"/>
|
||||
<column name="REALM_ID" type="VARCHAR(36)"/>
|
||||
<column name="DESCRIPTION" type="VARCHAR(255)"/>
|
||||
<column name="PROTOCOL" type="VARCHAR(255)"/>
|
||||
</createTable>
|
||||
|
||||
|
||||
|
||||
<dropNotNullConstraint tableName="PROTOCOL_MAPPER" columnName="CLIENT_ID" columnDataType="VARCHAR(36)"/>
|
||||
<addColumn tableName="CLIENT">
|
||||
<column name="CLIENT_TEMPLATE_ID" type="VARCHAR(36)">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
</addColumn>
|
||||
<addColumn tableName="PROTOCOL_MAPPER">
|
||||
<column name="CLIENT_TEMPLATE_ID" type="VARCHAR(36)">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
</addColumn>
|
||||
<createTable tableName="REALM_CLIENT_TEMPLATE">
|
||||
<column name="CLIENT_TEMPLATE_ID" type="VARCHAR(36)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="REALM_ID" type="VARCHAR(36)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
|
||||
<addPrimaryKey columnNames="ID" constraintName="PK_CLI_TEMPLATE" tableName="CLIENT_TEMPLATE"/>
|
||||
<addUniqueConstraint columnNames="REALM_ID,NAME" constraintName="UK_CLI_TEMPLATE" tableName="CLIENT_TEMPLATE"/>
|
||||
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="CLIENT_TEMPLATE" constraintName="FK_REALM_CLI_TMPLT" referencedColumnNames="ID" referencedTableName="REALM"/>
|
||||
<addForeignKeyConstraint baseColumnNames="CLIENT_TEMPLATE_ID" baseTableName="PROTOCOL_MAPPER" constraintName="FK_CLI_TMPLT_MAPPER" referencedColumnNames="ID" referencedTableName="CLIENT_TEMPLATE"/>
|
||||
<addForeignKeyConstraint baseColumnNames="CLIENT_TEMPLATE_ID" baseTableName="CLIENT" constraintName="FK_CLI_TMPLT_CLIENT" referencedColumnNames="ID" referencedTableName="CLIENT_TEMPLATE"/>
|
||||
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="REALM_CLIENT_TEMPLATE" constraintName="FK_RLM_CLI_TMPLT_RLM" referencedColumnNames="ID" referencedTableName="REALM"/>
|
||||
<addForeignKeyConstraint baseColumnNames="CLIENT_TEMPLATE_ID" baseTableName="REALM_CLIENT_TEMPLATE" constraintName="FK_RLM_CLI_TMPLT_CLI" referencedColumnNames="ID" referencedTableName="CLIENT_TEMPLATE"/>
|
||||
|
||||
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
|
@ -35,6 +35,7 @@
|
|||
<class>org.keycloak.models.jpa.entities.GroupAttributeEntity</class>
|
||||
<class>org.keycloak.models.jpa.entities.GroupRoleMappingEntity</class>
|
||||
<class>org.keycloak.models.jpa.entities.UserGroupMembershipEntity</class>
|
||||
<class>org.keycloak.models.jpa.entities.ClientTemplateEntity</class>
|
||||
|
||||
<!-- JpaAuditProviders -->
|
||||
<class>org.keycloak.events.jpa.EventEntity</class>
|
||||
|
|
|
@ -40,6 +40,7 @@ public class ClientRepresentation {
|
|||
protected Integer nodeReRegistrationTimeout;
|
||||
protected Map<String, Integer> registeredNodes;
|
||||
protected List<ProtocolMapperRepresentation> protocolMappers;
|
||||
protected String clientTemplate;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
|
@ -290,4 +291,11 @@ public class ClientRepresentation {
|
|||
this.protocolMappers = protocolMappers;
|
||||
}
|
||||
|
||||
public String getClientTemplate() {
|
||||
return clientTemplate;
|
||||
}
|
||||
|
||||
public void setClientTemplate(String clientTemplate) {
|
||||
this.clientTemplate = clientTemplate;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
package org.keycloak.representations.idm;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class ClientTemplateRepresentation {
|
||||
/**
|
||||
* Use this value in ClientRepresentation.setClientTemplate when you want to clear this value
|
||||
*/
|
||||
public static final String NONE = "NONE";
|
||||
protected String id;
|
||||
protected String name;
|
||||
protected String description;
|
||||
protected String protocol;
|
||||
protected List<ProtocolMapperRepresentation> protocolMappers;
|
||||
|
||||
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 getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
|
||||
public List<ProtocolMapperRepresentation> getProtocolMappers() {
|
||||
return protocolMappers;
|
||||
}
|
||||
|
||||
public void setProtocolMappers(List<ProtocolMapperRepresentation> protocolMappers) {
|
||||
this.protocolMappers = protocolMappers;
|
||||
}
|
||||
|
||||
public String getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public void setProtocol(String protocol) {
|
||||
this.protocol = protocol;
|
||||
}
|
||||
}
|
|
@ -65,6 +65,7 @@ public class RealmRepresentation {
|
|||
protected List<ScopeMappingRepresentation> scopeMappings;
|
||||
protected Map<String, List<ScopeMappingRepresentation>> clientScopeMappings;
|
||||
protected List<ClientRepresentation> clients;
|
||||
protected List<ClientTemplateRepresentation> clientTemplates;
|
||||
protected Map<String, String> browserSecurityHeaders;
|
||||
protected Map<String, String> smtpServer;
|
||||
protected List<UserFederationProviderRepresentation> userFederationProviders;
|
||||
|
@ -804,4 +805,12 @@ public class RealmRepresentation {
|
|||
public void setGroups(List<GroupRepresentation> groups) {
|
||||
this.groups = groups;
|
||||
}
|
||||
|
||||
public List<ClientTemplateRepresentation> getClientTemplates() {
|
||||
return clientTemplates;
|
||||
}
|
||||
|
||||
public void setClientTemplates(List<ClientTemplateRepresentation> clientTemplates) {
|
||||
this.clientTemplates = clientTemplates;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import org.codehaus.jackson.JsonGenerator;
|
|||
import org.codehaus.jackson.map.ObjectMapper;
|
||||
import org.codehaus.jackson.map.SerializationConfig;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientTemplateModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
|
@ -19,6 +20,7 @@ import org.keycloak.models.UserModel;
|
|||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.ClientTemplateRepresentation;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
|
@ -47,6 +49,15 @@ public class ExportUtils {
|
|||
public static RealmRepresentation exportRealm(KeycloakSession session, RealmModel realm, boolean includeUsers) {
|
||||
RealmRepresentation rep = ModelToRepresentation.toRepresentation(realm, true);
|
||||
|
||||
// Client Templates
|
||||
List<ClientTemplateModel> templates = realm.getClientTemplates();
|
||||
List<ClientTemplateRepresentation> templateReps = new ArrayList<>();
|
||||
for (ClientTemplateModel app : templates) {
|
||||
ClientTemplateRepresentation clientRep = ModelToRepresentation.toRepresentation(app);
|
||||
templateReps.add(clientRep);
|
||||
}
|
||||
rep.setClientTemplates(templateReps);
|
||||
|
||||
// Clients
|
||||
List<ClientModel> clients = realm.getClients();
|
||||
List<ClientRepresentation> clientReps = new ArrayList<>();
|
||||
|
|
|
@ -9,6 +9,8 @@ import org.keycloak.admin.client.resource.RealmsResource;
|
|||
import org.keycloak.admin.client.resource.ServerInfoResource;
|
||||
import org.keycloak.admin.client.token.TokenManager;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
/**
|
||||
* Provides a Keycloak client. By default, this implementation uses a {@link ResteasyClient RESTEasy client} with the
|
||||
* default {@link ResteasyClientBuilder} settings. To customize the underling client, use a {@link KeycloakBuilder} to
|
||||
|
@ -60,6 +62,19 @@ public class Keycloak {
|
|||
return tokenManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a secure proxy based on an absolute URI.
|
||||
* All set up with appropriate token
|
||||
*
|
||||
* @param proxyClass
|
||||
* @param absoluteURI
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
public <T> T proxy(Class<T> proxyClass, URI absoluteURI) {
|
||||
return client.target(absoluteURI).register(new BearerAuthFilter(tokenManager)).proxy(proxyClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the underlying client. After calling this method, this <code>Keycloak</code> instance cannot be reused.
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
package org.keycloak.admin.client.resource;
|
||||
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.ClientTemplateRepresentation;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.representations.idm.UserSessionRepresentation;
|
||||
|
||||
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.MediaType;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author rodrigo.sasaki@icarros.com.br
|
||||
*/
|
||||
public interface ClientTemplateResource {
|
||||
|
||||
@Path("protocol-mappers")
|
||||
public ProtocolMappersResource getProtocolMappers();
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public ClientTemplateRepresentation toRepresentation();
|
||||
|
||||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void update(ClientTemplateRepresentation rep);
|
||||
|
||||
@DELETE
|
||||
public void remove();
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package org.keycloak.admin.client.resource;
|
||||
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.ClientTemplateRepresentation;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author rodrigo.sasaki@icarros.com.br
|
||||
*/
|
||||
public interface ClientTemplatesResource {
|
||||
|
||||
@Path("{id}")
|
||||
public ClientTemplatesResource get(@PathParam("id") String id);
|
||||
|
||||
@POST
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response create(ClientTemplateRepresentation clientRepresentation);
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<ClientTemplateRepresentation> findAll();
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -26,6 +26,9 @@ public interface RealmResource {
|
|||
@Path("clients")
|
||||
ClientsResource clients();
|
||||
|
||||
@Path("client-templates")
|
||||
ClientTemplatesResource clientTemplates();
|
||||
|
||||
@Path("client-description-converter")
|
||||
@POST
|
||||
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_PLAIN })
|
||||
|
|
|
@ -8,7 +8,7 @@ import java.util.Set;
|
|||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public interface ClientModel extends RoleContainerModel {
|
||||
public interface ClientModel extends RoleContainerModel, ProtocolMapperContainerModel {
|
||||
|
||||
// COMMON ATTRIBUTES
|
||||
|
||||
|
@ -134,6 +134,9 @@ public interface ClientModel extends RoleContainerModel {
|
|||
|
||||
RealmModel getRealm();
|
||||
|
||||
ClientTemplateModel getClientTemplate();
|
||||
void setClientTemplate(ClientTemplateModel template);
|
||||
|
||||
/**
|
||||
* Time in seconds since epoc
|
||||
*
|
||||
|
@ -143,14 +146,7 @@ public interface ClientModel extends RoleContainerModel {
|
|||
|
||||
void setNotBefore(int notBefore);
|
||||
|
||||
Set<ProtocolMapperModel> getProtocolMappers();
|
||||
ProtocolMapperModel addProtocolMapper(ProtocolMapperModel model);
|
||||
void removeProtocolMapper(ProtocolMapperModel mapping);
|
||||
void updateProtocolMapper(ProtocolMapperModel mapping);
|
||||
ProtocolMapperModel getProtocolMapperById(String id);
|
||||
ProtocolMapperModel getProtocolMapperByName(String protocol, String name);
|
||||
|
||||
Map<String, Integer> getRegisteredNodes();
|
||||
Map<String, Integer> getRegisteredNodes();
|
||||
|
||||
/**
|
||||
* Register node or just update the 'lastReRegistration' time if this node is already registered
|
||||
|
|
27
model/api/src/main/java/org/keycloak/models/ClientTemplateModel.java
Executable file
27
model/api/src/main/java/org/keycloak/models/ClientTemplateModel.java
Executable file
|
@ -0,0 +1,27 @@
|
|||
package org.keycloak.models;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public interface ClientTemplateModel extends ProtocolMapperContainerModel {
|
||||
String getId();
|
||||
|
||||
String getName();
|
||||
|
||||
RealmModel getRealm();
|
||||
void setName(String name);
|
||||
|
||||
String getDescription();
|
||||
|
||||
void setDescription(String description);
|
||||
|
||||
String getProtocol();
|
||||
void setProtocol(String protocol);
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package org.keycloak.models;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public interface ProtocolMapperContainerModel {
|
||||
Set<ProtocolMapperModel> getProtocolMappers();
|
||||
|
||||
ProtocolMapperModel addProtocolMapper(ProtocolMapperModel model);
|
||||
|
||||
void removeProtocolMapper(ProtocolMapperModel mapping);
|
||||
|
||||
void updateProtocolMapper(ProtocolMapperModel mapping);
|
||||
|
||||
ProtocolMapperModel getProtocolMapperById(String id);
|
||||
|
||||
ProtocolMapperModel getProtocolMapperByName(String protocol, String name);
|
||||
}
|
|
@ -353,4 +353,15 @@ public interface RealmModel extends RoleContainerModel {
|
|||
List<GroupModel> getTopLevelGroups();
|
||||
boolean removeGroup(GroupModel group);
|
||||
void moveGroup(GroupModel group, GroupModel toParent);
|
||||
|
||||
List<ClientTemplateModel> getClientTemplates();
|
||||
|
||||
ClientTemplateModel addClientTemplate(String name);
|
||||
|
||||
ClientTemplateModel addClientTemplate(String id, String name);
|
||||
|
||||
boolean removeClientTemplate(String id);
|
||||
|
||||
ClientTemplateModel getClientTemplateById(String id);
|
||||
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ public interface RealmProvider extends Provider {
|
|||
|
||||
RoleModel getRoleById(String id, RealmModel realm);
|
||||
ClientModel getClientById(String id, RealmModel realm);
|
||||
ClientTemplateModel getClientTemplateById(String id, RealmModel realm);
|
||||
GroupModel getGroupById(String id, RealmModel realm);
|
||||
|
||||
|
||||
|
|
|
@ -388,8 +388,8 @@ public class UserFederationManager implements UserProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void preRemove(ClientModel client, ProtocolMapperModel protocolMapper) {
|
||||
session.userStorage().preRemove(client, protocolMapper);
|
||||
public void preRemove(ProtocolMapperModel protocolMapper) {
|
||||
session.userStorage().preRemove(protocolMapper);
|
||||
}
|
||||
|
||||
public void updateCredential(RealmModel realm, UserModel user, UserCredentialModel credential) {
|
||||
|
|
|
@ -57,7 +57,7 @@ public interface UserProvider extends Provider {
|
|||
void preRemove(RealmModel realm, GroupModel group);
|
||||
|
||||
void preRemove(RealmModel realm, ClientModel client);
|
||||
void preRemove(ClientModel realm, ProtocolMapperModel protocolMapper);
|
||||
void preRemove(ProtocolMapperModel protocolMapper);
|
||||
|
||||
boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, List<UserCredentialModel> input);
|
||||
boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, UserCredentialModel... input);
|
||||
|
|
|
@ -48,6 +48,7 @@ public class ClientEntity extends AbstractIdentifiableEntity {
|
|||
private List<String> scopeIds = new ArrayList<String>();
|
||||
private List<ClientIdentityProviderMappingEntity> identityProviders = new ArrayList<ClientIdentityProviderMappingEntity>();
|
||||
private List<ProtocolMapperEntity> protocolMappers = new ArrayList<ProtocolMapperEntity>();
|
||||
private String clientTemplate;
|
||||
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
|
@ -300,5 +301,13 @@ public class ClientEntity extends AbstractIdentifiableEntity {
|
|||
public void setRegisteredNodes(Map<String, Integer> registeredNodes) {
|
||||
this.registeredNodes = registeredNodes;
|
||||
}
|
||||
|
||||
public String getClientTemplate() {
|
||||
return clientTemplate;
|
||||
}
|
||||
|
||||
public void setClientTemplate(String clientTemplate) {
|
||||
this.clientTemplate = clientTemplate;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
package org.keycloak.models.entities;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class ClientTemplateEntity extends AbstractIdentifiableEntity {
|
||||
|
||||
private String name;
|
||||
private String description;
|
||||
private String realmId;
|
||||
private String protocol;
|
||||
private List<ProtocolMapperEntity> protocolMappers = new ArrayList<ProtocolMapperEntity>();
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getRealmId() {
|
||||
return realmId;
|
||||
}
|
||||
|
||||
public void setRealmId(String realmId) {
|
||||
this.realmId = realmId;
|
||||
}
|
||||
|
||||
public List<ProtocolMapperEntity> getProtocolMappers() {
|
||||
return protocolMappers;
|
||||
}
|
||||
|
||||
public void setProtocolMappers(List<ProtocolMapperEntity> protocolMappers) {
|
||||
this.protocolMappers = protocolMappers;
|
||||
}
|
||||
|
||||
public String getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public void setProtocol(String protocol) {
|
||||
this.protocol = protocol;
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import org.keycloak.models.AuthenticationFlowModel;
|
|||
import org.keycloak.models.AuthenticatorConfigModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientSessionModel;
|
||||
import org.keycloak.models.ClientTemplateModel;
|
||||
import org.keycloak.models.FederatedIdentityModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.IdentityProviderMapperModel;
|
||||
|
@ -27,6 +28,7 @@ import org.keycloak.representations.idm.AuthenticationExecutionRepresentation;
|
|||
import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
|
||||
import org.keycloak.representations.idm.AuthenticatorConfigRepresentation;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.ClientTemplateRepresentation;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.representations.idm.FederatedIdentityRepresentation;
|
||||
import org.keycloak.representations.idm.GroupRepresentation;
|
||||
|
@ -404,6 +406,24 @@ public class ModelToRepresentation {
|
|||
return rep;
|
||||
}
|
||||
|
||||
public static ClientTemplateRepresentation toRepresentation(ClientTemplateModel clientModel) {
|
||||
ClientTemplateRepresentation rep = new ClientTemplateRepresentation();
|
||||
rep.setId(clientModel.getId());
|
||||
rep.setName(clientModel.getName());
|
||||
rep.setDescription(clientModel.getDescription());
|
||||
rep.setProtocol(clientModel.getProtocol());
|
||||
if (!clientModel.getProtocolMappers().isEmpty()) {
|
||||
List<ProtocolMapperRepresentation> mappings = new LinkedList<>();
|
||||
for (ProtocolMapperModel model : clientModel.getProtocolMappers()) {
|
||||
mappings.add(toRepresentation(model));
|
||||
}
|
||||
rep.setProtocolMappers(mappings);
|
||||
}
|
||||
|
||||
return rep;
|
||||
}
|
||||
|
||||
|
||||
public static ClientRepresentation toRepresentation(ClientModel clientModel) {
|
||||
ClientRepresentation rep = new ClientRepresentation();
|
||||
rep.setId(clientModel.getId());
|
||||
|
@ -429,6 +449,7 @@ public class ModelToRepresentation {
|
|||
rep.setNotBefore(clientModel.getNotBefore());
|
||||
rep.setNodeReRegistrationTimeout(clientModel.getNodeReRegistrationTimeout());
|
||||
rep.setClientAuthenticatorType(clientModel.getClientAuthenticatorType());
|
||||
if (clientModel.getClientTemplate() != null) rep.setClientTemplate(clientModel.getClientTemplate().getName());
|
||||
|
||||
Set<String> redirectUris = clientModel.getRedirectUris();
|
||||
if (redirectUris != null) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.keycloak.models.utils;
|
||||
|
||||
import org.keycloak.models.ClientTemplateModel;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.common.util.Base64;
|
||||
import org.jboss.logging.Logger;
|
||||
|
@ -35,6 +36,7 @@ import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
|
|||
import org.keycloak.representations.idm.AuthenticatorConfigRepresentation;
|
||||
import org.keycloak.representations.idm.ClaimRepresentation;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.ClientTemplateRepresentation;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.representations.idm.FederatedIdentityRepresentation;
|
||||
import org.keycloak.representations.idm.GroupRepresentation;
|
||||
|
@ -182,6 +184,10 @@ public class RepresentationToModel {
|
|||
importIdentityProviders(rep, newRealm);
|
||||
importIdentityProviderMappers(rep, newRealm);
|
||||
|
||||
if (rep.getClientTemplates() != null) {
|
||||
createClientTemplates(session, rep, newRealm);
|
||||
}
|
||||
|
||||
if (rep.getClients() != null) {
|
||||
createClients(session, rep, newRealm);
|
||||
}
|
||||
|
@ -878,6 +884,15 @@ public class RepresentationToModel {
|
|||
}
|
||||
}
|
||||
|
||||
if (resourceRep.getClientTemplate() != null) {
|
||||
for (ClientTemplateModel template : realm.getClientTemplates()) {
|
||||
if (template.getName().equals(resourceRep.getClientTemplate())) {
|
||||
client.setClientTemplate(template);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
|
@ -934,6 +949,61 @@ public class RepresentationToModel {
|
|||
}
|
||||
}
|
||||
|
||||
if (rep.getClientTemplate() != null) {
|
||||
if (rep.getClientTemplate().equals(ClientTemplateRepresentation.NONE)) {
|
||||
resource.setClientTemplate(null);
|
||||
} else {
|
||||
RealmModel realm = resource.getRealm();
|
||||
for (ClientTemplateModel template : realm.getClientTemplates()) {
|
||||
if (template.getName().equals(rep.getClientTemplate())) {
|
||||
resource.setClientTemplate(template);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// CLIENT TEMPLATES
|
||||
|
||||
private static Map<String, ClientTemplateModel> createClientTemplates(KeycloakSession session, RealmRepresentation rep, RealmModel realm) {
|
||||
Map<String, ClientTemplateModel> appMap = new HashMap<>();
|
||||
for (ClientTemplateRepresentation resourceRep : rep.getClientTemplates()) {
|
||||
ClientTemplateModel app = createClientTemplate(session, realm, resourceRep);
|
||||
appMap.put(app.getName(), app);
|
||||
}
|
||||
return appMap;
|
||||
}
|
||||
|
||||
public static ClientTemplateModel createClientTemplate(KeycloakSession session, RealmModel realm, ClientTemplateRepresentation resourceRep) {
|
||||
logger.debug("Create client template: {0}" + resourceRep.getName());
|
||||
|
||||
ClientTemplateModel client = resourceRep.getId()!=null ? realm.addClientTemplate(resourceRep.getId(), resourceRep.getName()) : realm.addClientTemplate(resourceRep.getName());
|
||||
if (resourceRep.getName() != null) client.setName(resourceRep.getName());
|
||||
if(resourceRep.getDescription() != null) client.setDescription(resourceRep.getDescription());
|
||||
if (resourceRep.getProtocol() != null) client.setProtocol(resourceRep.getProtocol());
|
||||
|
||||
if (resourceRep.getProtocolMappers() != null) {
|
||||
// first, remove all default/built in mappers
|
||||
Set<ProtocolMapperModel> mappers = client.getProtocolMappers();
|
||||
for (ProtocolMapperModel mapper : mappers) client.removeProtocolMapper(mapper);
|
||||
|
||||
for (ProtocolMapperRepresentation mapper : resourceRep.getProtocolMappers()) {
|
||||
client.addProtocolMapper(toModel(mapper));
|
||||
}
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
public static void updateClientTemplate(ClientTemplateRepresentation rep, ClientTemplateModel resource) {
|
||||
if (rep.getName() != null) resource.setName(rep.getName());
|
||||
if (rep.getDescription() != null) resource.setDescription(rep.getDescription());
|
||||
|
||||
|
||||
if (rep.getProtocol() != null) resource.setProtocol(rep.getProtocol());
|
||||
}
|
||||
|
||||
public static long getClaimsMask(ClaimRepresentation rep) {
|
||||
|
|
|
@ -55,6 +55,20 @@ public class ClientAdapter implements ClientModel {
|
|||
updated.setWebOrigins(webOrigins);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTemplateModel getClientTemplate() {
|
||||
if (updated != null) return updated.getClientTemplate();
|
||||
if (cached.getClientTemplate() == null) return null;
|
||||
return cacheSession.getClientTemplateById(cached.getClientTemplate(), cachedRealm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClientTemplate(ClientTemplateModel template) {
|
||||
getDelegateForUpdate();
|
||||
updated.setClientTemplate(template);
|
||||
|
||||
}
|
||||
|
||||
public void addWebOrigin(String webOrigin) {
|
||||
getDelegateForUpdate();
|
||||
updated.addWebOrigin(webOrigin);
|
||||
|
|
149
model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientTemplateAdapter.java
vendored
Executable file
149
model/invalidation-cache/infinispan/src/main/java/org/keycloak/models/cache/infinispan/ClientTemplateAdapter.java
vendored
Executable file
|
@ -0,0 +1,149 @@
|
|||
package org.keycloak.models.cache.infinispan;
|
||||
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientTemplateModel;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleContainerModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.cache.CacheRealmProvider;
|
||||
import org.keycloak.models.cache.RealmCache;
|
||||
import org.keycloak.models.cache.entities.CachedClient;
|
||||
import org.keycloak.models.cache.entities.CachedClientTemplate;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class ClientTemplateAdapter implements ClientTemplateModel {
|
||||
protected CacheRealmProvider cacheSession;
|
||||
protected RealmModel cachedRealm;
|
||||
protected RealmCache cache;
|
||||
|
||||
protected ClientTemplateModel updated;
|
||||
protected CachedClientTemplate cached;
|
||||
|
||||
public ClientTemplateAdapter(RealmModel cachedRealm, CachedClientTemplate cached, CacheRealmProvider cacheSession, RealmCache cache) {
|
||||
this.cachedRealm = cachedRealm;
|
||||
this.cache = cache;
|
||||
this.cacheSession = cacheSession;
|
||||
this.cached = cached;
|
||||
}
|
||||
|
||||
private void getDelegateForUpdate() {
|
||||
if (updated == null) {
|
||||
cacheSession.registerApplicationInvalidation(getId());
|
||||
updated = cacheSession.getDelegate().getClientTemplateById(getId(), cachedRealm);
|
||||
if (updated == null) throw new IllegalStateException("Not found in database");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
if (updated != null) return updated.getId();
|
||||
return cached.getId();
|
||||
}
|
||||
|
||||
public RealmModel getRealm() {
|
||||
return cachedRealm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ProtocolMapperModel> getProtocolMappers() {
|
||||
if (updated != null) return updated.getProtocolMappers();
|
||||
return cached.getProtocolMappers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolMapperModel addProtocolMapper(ProtocolMapperModel model) {
|
||||
getDelegateForUpdate();
|
||||
return updated.addProtocolMapper(model);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeProtocolMapper(ProtocolMapperModel mapping) {
|
||||
getDelegateForUpdate();
|
||||
updated.removeProtocolMapper(mapping);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProtocolMapper(ProtocolMapperModel mapping) {
|
||||
getDelegateForUpdate();
|
||||
updated.updateProtocolMapper(mapping);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolMapperModel getProtocolMapperById(String id) {
|
||||
for (ProtocolMapperModel mapping : cached.getProtocolMappers()) {
|
||||
if (mapping.getId().equals(id)) return mapping;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolMapperModel getProtocolMapperByName(String protocol, String name) {
|
||||
for (ProtocolMapperModel mapping : cached.getProtocolMappers()) {
|
||||
if (mapping.getProtocol().equals(protocol) && mapping.getName().equals(name)) return mapping;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
if (updated != null) return updated.getName();
|
||||
return cached.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
getDelegateForUpdate();
|
||||
updated.setName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
if (updated != null) return updated.getDescription();
|
||||
return cached.getDescription();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDescription(String description) {
|
||||
getDelegateForUpdate();
|
||||
updated.setDescription(description);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocol() {
|
||||
if (updated != null) return updated.getProtocol();
|
||||
return cached.getProtocol();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProtocol(String protocol) {
|
||||
getDelegateForUpdate();
|
||||
updated.setProtocol(protocol);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || !(o instanceof ClientModel)) return false;
|
||||
|
||||
ClientTemplateModel that = (ClientTemplateModel) o;
|
||||
return that.getId().equals(getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getId().hashCode();
|
||||
}
|
||||
|
||||
}
|
|
@ -18,14 +18,16 @@ public class DefaultCacheRealmProvider implements CacheRealmProvider {
|
|||
protected boolean transactionActive;
|
||||
protected boolean setRollbackOnly;
|
||||
|
||||
protected Set<String> realmInvalidations = new HashSet<String>();
|
||||
protected Set<String> appInvalidations = new HashSet<String>();
|
||||
protected Set<String> roleInvalidations = new HashSet<String>();
|
||||
protected Set<String> groupInvalidations = new HashSet<String>();
|
||||
protected Map<String, RealmModel> managedRealms = new HashMap<String, RealmModel>();
|
||||
protected Map<String, ClientModel> managedApplications = new HashMap<String, ClientModel>();
|
||||
protected Map<String, RoleModel> managedRoles = new HashMap<String, RoleModel>();
|
||||
protected Map<String, GroupModel> managedGroups = new HashMap<String, GroupModel>();
|
||||
protected Set<String> realmInvalidations = new HashSet<>();
|
||||
protected Set<String> appInvalidations = new HashSet<>();
|
||||
protected Set<String> clientTemplateInvalidations = new HashSet<>();
|
||||
protected Set<String> roleInvalidations = new HashSet<>();
|
||||
protected Set<String> groupInvalidations = new HashSet<>();
|
||||
protected Map<String, RealmModel> managedRealms = new HashMap<>();
|
||||
protected Map<String, ClientModel> managedApplications = new HashMap<>();
|
||||
protected Map<String, ClientTemplateModel> managedClientTemplates = new HashMap<>();
|
||||
protected Map<String, RoleModel> managedRoles = new HashMap<>();
|
||||
protected Map<String, GroupModel> managedGroups = new HashMap<>();
|
||||
|
||||
protected boolean clearAll;
|
||||
|
||||
|
@ -69,6 +71,10 @@ public class DefaultCacheRealmProvider implements CacheRealmProvider {
|
|||
public void registerApplicationInvalidation(String id) {
|
||||
appInvalidations.add(id);
|
||||
}
|
||||
@Override
|
||||
public void registerClientTemplateInvalidation(String id) {
|
||||
clientTemplateInvalidations.add(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerRoleInvalidation(String id) {
|
||||
|
@ -94,6 +100,9 @@ public class DefaultCacheRealmProvider implements CacheRealmProvider {
|
|||
for (String id : appInvalidations) {
|
||||
cache.invalidateCachedApplicationById(id);
|
||||
}
|
||||
for (String id : clientTemplateInvalidations) {
|
||||
cache.invalidateCachedClientTemplateById(id);
|
||||
}
|
||||
}
|
||||
|
||||
private KeycloakTransaction getTransaction() {
|
||||
|
@ -313,5 +322,28 @@ public class DefaultCacheRealmProvider implements CacheRealmProvider {
|
|||
managedApplications.put(id, adapter);
|
||||
return adapter;
|
||||
}
|
||||
@Override
|
||||
public ClientTemplateModel getClientTemplateById(String id, RealmModel realm) {
|
||||
if (!cache.isEnabled()) return getDelegate().getClientTemplateById(id, realm);
|
||||
CachedClientTemplate cached = cache.getClientTemplate(id);
|
||||
if (cached != null && !cached.getRealm().equals(realm.getId())) {
|
||||
cached = null;
|
||||
}
|
||||
|
||||
if (cached == null) {
|
||||
ClientTemplateModel model = getDelegate().getClientTemplateById(id, realm);
|
||||
if (model == null) return null;
|
||||
if (clientTemplateInvalidations.contains(id)) return model;
|
||||
cached = new CachedClientTemplate(cache, getDelegate(), realm, model);
|
||||
cache.addCachedClientTemplate(cached);
|
||||
} else if (clientTemplateInvalidations.contains(id)) {
|
||||
return getDelegate().getClientTemplateById(id, realm);
|
||||
} else if (managedClientTemplates.containsKey(id)) {
|
||||
return managedClientTemplates.get(id);
|
||||
}
|
||||
ClientTemplateModel adapter = new ClientTemplateAdapter(realm, cached, this, cache);
|
||||
managedClientTemplates.put(id, adapter);
|
||||
return adapter;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -348,7 +348,7 @@ public class DefaultCacheUserProvider implements CacheUserProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void preRemove(ClientModel client, ProtocolMapperModel protocolMapper) {
|
||||
getDelegate().preRemove(client, protocolMapper);
|
||||
public void preRemove(ProtocolMapperModel protocolMapper) {
|
||||
getDelegate().preRemove(protocolMapper);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import org.infinispan.Cache;
|
|||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.cache.RealmCache;
|
||||
import org.keycloak.models.cache.entities.CachedClient;
|
||||
import org.keycloak.models.cache.entities.CachedClientTemplate;
|
||||
import org.keycloak.models.cache.entities.CachedGroup;
|
||||
import org.keycloak.models.cache.entities.CachedRealm;
|
||||
import org.keycloak.models.cache.entities.CachedRole;
|
||||
|
@ -177,4 +178,36 @@ public class InfinispanRealmCache implements RealmCache {
|
|||
return o != null && type.isInstance(o) ? type.cast(o) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CachedClientTemplate getClientTemplate(String id) {
|
||||
if (!enabled) return null;
|
||||
return get(id, CachedClientTemplate.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateClientTemplate(CachedClientTemplate app) {
|
||||
logger.tracev("Removing client template {0}", app.getId());
|
||||
cache.remove(app.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCachedClientTemplate(CachedClientTemplate app) {
|
||||
if (!enabled) return;
|
||||
logger.tracev("Adding client template {0}", app.getId());
|
||||
cache.putForExternalRead(app.getId(), app);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCachedClientTemplateById(String id) {
|
||||
logger.tracev("Removing client template {0}", id);
|
||||
cache.remove(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evictCachedClientTemplateById(String id) {
|
||||
logger.tracev("Evicting client template {0}", id);
|
||||
cache.evict(id);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1361,4 +1361,51 @@ public class RealmAdapter implements RealmModel {
|
|||
getDelegateForUpdate();
|
||||
updated.moveGroup(group, toParent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ClientTemplateModel> getClientTemplates() {
|
||||
if (updated != null) return updated.getClientTemplates();
|
||||
List<ClientTemplateModel> apps = new LinkedList<ClientTemplateModel>();
|
||||
for (String id : cached.getClientTemplates()) {
|
||||
ClientTemplateModel model = cacheSession.getClientTemplateById(id, this);
|
||||
if (model == null) {
|
||||
throw new IllegalStateException("Cached clientemplate not found: " + id);
|
||||
}
|
||||
apps.add(model);
|
||||
}
|
||||
return apps;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTemplateModel addClientTemplate(String name) {
|
||||
getDelegateForUpdate();
|
||||
ClientTemplateModel app = updated.addClientTemplate(name);
|
||||
cacheSession.registerClientTemplateInvalidation(app.getId());
|
||||
return app;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTemplateModel addClientTemplate(String id, String name) {
|
||||
getDelegateForUpdate();
|
||||
ClientTemplateModel app = updated.addClientTemplate(id, name);
|
||||
cacheSession.registerClientTemplateInvalidation(app.getId());
|
||||
return app;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeClientTemplate(String id) {
|
||||
cacheSession.registerClientTemplateInvalidation(id);
|
||||
getDelegateForUpdate();
|
||||
return updated.removeClientTemplate(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTemplateModel getClientTemplateById(String id) {
|
||||
if (updated != null) return updated.getClientTemplateById(id);
|
||||
return cacheSession.getClientTemplateById(id, this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ public interface CacheRealmProvider extends RealmProvider {
|
|||
void registerRealmInvalidation(String id);
|
||||
|
||||
void registerApplicationInvalidation(String id);
|
||||
void registerClientTemplateInvalidation(String id);
|
||||
|
||||
void registerRoleInvalidation(String id);
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.keycloak.models.cache;
|
||||
|
||||
import org.keycloak.models.cache.entities.CachedClient;
|
||||
import org.keycloak.models.cache.entities.CachedClientTemplate;
|
||||
import org.keycloak.models.cache.entities.CachedGroup;
|
||||
import org.keycloak.models.cache.entities.CachedRealm;
|
||||
import org.keycloak.models.cache.entities.CachedRole;
|
||||
|
@ -55,4 +56,15 @@ public interface RealmCache {
|
|||
boolean isEnabled();
|
||||
|
||||
void setEnabled(boolean enabled);
|
||||
|
||||
CachedClientTemplate getClientTemplate(String id);
|
||||
|
||||
void invalidateClientTemplate(CachedClientTemplate app);
|
||||
|
||||
void evictCachedClientTemplateById(String id);
|
||||
|
||||
void addCachedClientTemplate(CachedClientTemplate app);
|
||||
|
||||
void invalidateCachedClientTemplateById(String id);
|
||||
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ public class CachedClient implements Serializable {
|
|||
private Map<String, String> roles = new HashMap<String, String>();
|
||||
private int nodeReRegistrationTimeout;
|
||||
private Map<String, Integer> registeredNodes;
|
||||
private String clientTemplate;
|
||||
|
||||
public CachedClient(RealmCache cache, RealmProvider delegate, RealmModel realm, ClientModel model) {
|
||||
id = model.getId();
|
||||
|
@ -98,6 +99,9 @@ public class CachedClient implements Serializable {
|
|||
|
||||
nodeReRegistrationTimeout = model.getNodeReRegistrationTimeout();
|
||||
registeredNodes = new TreeMap<String, Integer>(model.getRegisteredNodes());
|
||||
if (model.getClientTemplate() != null) {
|
||||
clientTemplate = model.getClientTemplate().getId();
|
||||
}
|
||||
}
|
||||
public String getId() {
|
||||
return id;
|
||||
|
@ -230,4 +234,8 @@ public class CachedClient implements Serializable {
|
|||
public Map<String, Integer> getRegisteredNodes() {
|
||||
return registeredNodes;
|
||||
}
|
||||
|
||||
public String getClientTemplate() {
|
||||
return clientTemplate;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
package org.keycloak.models.cache.entities;
|
||||
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientTemplateModel;
|
||||
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.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class CachedClientTemplate implements Serializable {
|
||||
|
||||
private String id;
|
||||
private String name;
|
||||
private String description;
|
||||
private String realm;
|
||||
private String protocol;
|
||||
private Set<ProtocolMapperModel> protocolMappers = new HashSet<ProtocolMapperModel>();
|
||||
|
||||
public CachedClientTemplate(RealmCache cache, RealmProvider delegate, RealmModel realm, ClientTemplateModel model) {
|
||||
id = model.getId();
|
||||
name = model.getName();
|
||||
description = model.getDescription();
|
||||
this.realm = realm.getId();
|
||||
protocol = model.getProtocol();
|
||||
for (ProtocolMapperModel mapper : model.getProtocolMappers()) {
|
||||
this.protocolMappers.add(mapper);
|
||||
}
|
||||
}
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getDescription() { return description; }
|
||||
|
||||
public void setDescription(String description) { this.description = description; }
|
||||
|
||||
public String getRealm() {
|
||||
return realm;
|
||||
}
|
||||
public Set<ProtocolMapperModel> getProtocolMappers() {
|
||||
return protocolMappers;
|
||||
}
|
||||
|
||||
public String getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ import org.keycloak.models.AuthenticationExecutionModel;
|
|||
import org.keycloak.models.AuthenticationFlowModel;
|
||||
import org.keycloak.models.AuthenticatorConfigModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientTemplateModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.IdentityProviderMapperModel;
|
||||
import org.keycloak.models.IdentityProviderModel;
|
||||
|
@ -112,6 +113,7 @@ public class CachedRealm implements Serializable {
|
|||
private Set<String> groups = new HashSet<String>();
|
||||
private Map<String, String> realmRoles = new HashMap<String, String>();
|
||||
private Map<String, String> clients = new HashMap<String, String>();
|
||||
private List<String> clientTemplates= new LinkedList<>();
|
||||
private boolean internationalizationEnabled;
|
||||
private Set<String> supportedLocales = new HashSet<String>();
|
||||
private String defaultLocale;
|
||||
|
@ -210,6 +212,12 @@ public class CachedRealm implements Serializable {
|
|||
cache.addCachedClient(cachedClient);
|
||||
}
|
||||
|
||||
for (ClientTemplateModel template : model.getClientTemplates()) {
|
||||
clientTemplates.add(template.getId());
|
||||
CachedClientTemplate cachedClient = new CachedClientTemplate(cache, delegate, model, template);
|
||||
cache.addCachedClientTemplate(cachedClient);
|
||||
}
|
||||
|
||||
internationalizationEnabled = model.isInternationalizationEnabled();
|
||||
supportedLocales.addAll(model.getSupportedLocales());
|
||||
defaultLocale = model.getDefaultLocale();
|
||||
|
@ -531,4 +539,8 @@ public class CachedRealm implements Serializable {
|
|||
public List<String> getDefaultGroups() {
|
||||
return defaultGroups;
|
||||
}
|
||||
|
||||
public List<String> getClientTemplates() {
|
||||
return clientTemplates;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.keycloak.models.jpa;
|
|||
|
||||
import org.keycloak.connections.jpa.util.JpaUtils;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientTemplateModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
|
@ -9,6 +10,7 @@ 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.ClientTemplateEntity;
|
||||
import org.keycloak.models.jpa.entities.ProtocolMapperEntity;
|
||||
import org.keycloak.models.jpa.entities.RoleEntity;
|
||||
import org.keycloak.models.jpa.entities.ScopeMappingEntity;
|
||||
|
@ -298,6 +300,25 @@ public class ClientAdapter implements ClientModel {
|
|||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTemplateModel getClientTemplate() {
|
||||
ClientTemplateEntity templateEntity = entity.getClientTemplate();
|
||||
if (templateEntity == null) return null;
|
||||
return session.realms().getClientTemplateById(templateEntity.getId(), realm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClientTemplate(ClientTemplateModel template) {
|
||||
if (template == null) {
|
||||
entity.setClientTemplate(null);
|
||||
|
||||
} else {
|
||||
ClientTemplateEntity templateEntity = em.getReference(ClientTemplateEntity.class, template.getId());
|
||||
entity.setClientTemplate(templateEntity);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static boolean contains(String str, String[] array) {
|
||||
for (String s : array) {
|
||||
if (str.equals(s)) return true;
|
||||
|
@ -371,7 +392,7 @@ public class ClientAdapter implements ClientModel {
|
|||
public void removeProtocolMapper(ProtocolMapperModel mapping) {
|
||||
ProtocolMapperEntity toDelete = getProtocolMapperEntity(mapping.getId());
|
||||
if (toDelete != null) {
|
||||
session.users().preRemove(this, mapping);
|
||||
session.users().preRemove(mapping);
|
||||
|
||||
this.entity.getProtocolMappers().remove(toDelete);
|
||||
em.remove(toDelete);
|
||||
|
|
222
model/jpa/src/main/java/org/keycloak/models/jpa/ClientTemplateAdapter.java
Executable file
222
model/jpa/src/main/java/org/keycloak/models/jpa/ClientTemplateAdapter.java
Executable file
|
@ -0,0 +1,222 @@
|
|||
package org.keycloak.models.jpa;
|
||||
|
||||
import org.keycloak.connections.jpa.util.JpaUtils;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientTemplateModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
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.ClientTemplateEntity;
|
||||
import org.keycloak.models.jpa.entities.ProtocolMapperEntity;
|
||||
import org.keycloak.models.jpa.entities.RoleEntity;
|
||||
import org.keycloak.models.jpa.entities.ScopeMappingEntity;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.TypedQuery;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class ClientTemplateAdapter implements ClientTemplateModel {
|
||||
|
||||
protected KeycloakSession session;
|
||||
protected RealmModel realm;
|
||||
protected EntityManager em;
|
||||
protected ClientTemplateEntity entity;
|
||||
|
||||
public ClientTemplateAdapter(RealmModel realm, EntityManager em, KeycloakSession session, ClientTemplateEntity entity) {
|
||||
this.session = session;
|
||||
this.realm = realm;
|
||||
this.em = em;
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
public ClientTemplateEntity getEntity() {
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return entity.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RealmModel getRealm() {
|
||||
return realm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return entity.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
entity.setName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() { return entity.getDescription(); }
|
||||
|
||||
@Override
|
||||
public void setDescription(String description) { entity.setDescription(description); }
|
||||
|
||||
@Override
|
||||
public String getProtocol() {
|
||||
return entity.getProtocol();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProtocol(String protocol) {
|
||||
entity.setProtocol(protocol);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ProtocolMapperModel> getProtocolMappers() {
|
||||
Set<ProtocolMapperModel> mappings = new HashSet<ProtocolMapperModel>();
|
||||
for (ProtocolMapperEntity entity : this.entity.getProtocolMappers()) {
|
||||
ProtocolMapperModel mapping = new ProtocolMapperModel();
|
||||
mapping.setId(entity.getId());
|
||||
mapping.setName(entity.getName());
|
||||
mapping.setProtocol(entity.getProtocol());
|
||||
mapping.setProtocolMapper(entity.getProtocolMapper());
|
||||
mapping.setConsentRequired(entity.isConsentRequired());
|
||||
mapping.setConsentText(entity.getConsentText());
|
||||
Map<String, String> config = new HashMap<String, String>();
|
||||
if (entity.getConfig() != null) {
|
||||
config.putAll(entity.getConfig());
|
||||
}
|
||||
mapping.setConfig(config);
|
||||
mappings.add(mapping);
|
||||
}
|
||||
return mappings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolMapperModel addProtocolMapper(ProtocolMapperModel model) {
|
||||
if (getProtocolMapperByName(model.getProtocol(), model.getName()) != null) {
|
||||
throw new ModelDuplicateException("Protocol mapper name must be unique per protocol");
|
||||
}
|
||||
String id = model.getId() != null ? model.getId() : KeycloakModelUtils.generateId();
|
||||
ProtocolMapperEntity entity = new ProtocolMapperEntity();
|
||||
entity.setId(id);
|
||||
entity.setName(model.getName());
|
||||
entity.setProtocol(model.getProtocol());
|
||||
entity.setProtocolMapper(model.getProtocolMapper());
|
||||
entity.setClientTemplate(this.entity);
|
||||
entity.setConfig(model.getConfig());
|
||||
entity.setConsentRequired(model.isConsentRequired());
|
||||
entity.setConsentText(model.getConsentText());
|
||||
|
||||
em.persist(entity);
|
||||
this.entity.getProtocolMappers().add(entity);
|
||||
return entityToModel(entity);
|
||||
}
|
||||
|
||||
protected ProtocolMapperEntity getProtocolMapperEntity(String id) {
|
||||
for (ProtocolMapperEntity entity : this.entity.getProtocolMappers()) {
|
||||
if (entity.getId().equals(id)) {
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
protected ProtocolMapperEntity getProtocolMapperEntityByName(String protocol, String name) {
|
||||
for (ProtocolMapperEntity entity : this.entity.getProtocolMappers()) {
|
||||
if (entity.getProtocol().equals(protocol) && entity.getName().equals(name)) {
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeProtocolMapper(ProtocolMapperModel mapping) {
|
||||
ProtocolMapperEntity toDelete = getProtocolMapperEntity(mapping.getId());
|
||||
if (toDelete != null) {
|
||||
session.users().preRemove(mapping);
|
||||
|
||||
this.entity.getProtocolMappers().remove(toDelete);
|
||||
em.remove(toDelete);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProtocolMapper(ProtocolMapperModel mapping) {
|
||||
ProtocolMapperEntity entity = getProtocolMapperEntity(mapping.getId());
|
||||
entity.setProtocolMapper(mapping.getProtocolMapper());
|
||||
entity.setConsentRequired(mapping.isConsentRequired());
|
||||
entity.setConsentText(mapping.getConsentText());
|
||||
if (entity.getConfig() == null) {
|
||||
entity.setConfig(mapping.getConfig());
|
||||
} else {
|
||||
entity.getConfig().clear();
|
||||
entity.getConfig().putAll(mapping.getConfig());
|
||||
}
|
||||
em.flush();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolMapperModel getProtocolMapperById(String id) {
|
||||
ProtocolMapperEntity entity = getProtocolMapperEntity(id);
|
||||
if (entity == null) return null;
|
||||
return entityToModel(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolMapperModel getProtocolMapperByName(String protocol, String name) {
|
||||
ProtocolMapperEntity entity = getProtocolMapperEntityByName(protocol, name);
|
||||
if (entity == null) return null;
|
||||
return entityToModel(entity);
|
||||
}
|
||||
|
||||
protected ProtocolMapperModel entityToModel(ProtocolMapperEntity entity) {
|
||||
ProtocolMapperModel mapping = new ProtocolMapperModel();
|
||||
mapping.setId(entity.getId());
|
||||
mapping.setName(entity.getName());
|
||||
mapping.setProtocol(entity.getProtocol());
|
||||
mapping.setProtocolMapper(entity.getProtocolMapper());
|
||||
mapping.setConsentRequired(entity.isConsentRequired());
|
||||
mapping.setConsentText(entity.getConsentText());
|
||||
Map<String, String> config = new HashMap<String, String>();
|
||||
if (entity.getConfig() != null) config.putAll(entity.getConfig());
|
||||
mapping.setConfig(config);
|
||||
return mapping;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || !(o instanceof ClientTemplateModel)) return false;
|
||||
|
||||
ClientTemplateModel that = (ClientTemplateModel) o;
|
||||
return that.getId().equals(getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getId().hashCode();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -2,12 +2,14 @@ package org.keycloak.models.jpa;
|
|||
|
||||
import org.keycloak.migration.MigrationModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientTemplateModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RealmProvider;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.jpa.entities.ClientEntity;
|
||||
import org.keycloak.models.jpa.entities.ClientTemplateEntity;
|
||||
import org.keycloak.models.jpa.entities.GroupEntity;
|
||||
import org.keycloak.models.jpa.entities.RealmEntity;
|
||||
import org.keycloak.models.jpa.entities.RoleEntity;
|
||||
|
@ -145,4 +147,12 @@ public class JpaRealmProvider implements RealmProvider {
|
|||
return new ClientAdapter(realm, em, session, app);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTemplateModel getClientTemplateById(String id, RealmModel realm) {
|
||||
ClientTemplateEntity app = em.find(ClientTemplateEntity.class, id);
|
||||
|
||||
// Check if application belongs to this realm
|
||||
if (app == null || !realm.getId().equals(app.getRealm().getId())) return null;
|
||||
return new ClientTemplateAdapter(realm, em, session, app);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -227,7 +227,7 @@ public class JpaUserProvider implements UserProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void preRemove(ClientModel client, ProtocolMapperModel protocolMapper) {
|
||||
public void preRemove(ProtocolMapperModel protocolMapper) {
|
||||
em.createNamedQuery("deleteUserConsentProtMappersByProtocolMapper")
|
||||
.setParameter("protocolMapperId", protocolMapper.getId())
|
||||
.executeUpdate();
|
||||
|
|
|
@ -7,6 +7,7 @@ import org.keycloak.models.AuthenticationExecutionModel;
|
|||
import org.keycloak.models.AuthenticationFlowModel;
|
||||
import org.keycloak.models.AuthenticatorConfigModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientTemplateModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.IdentityProviderMapperModel;
|
||||
import org.keycloak.models.IdentityProviderModel;
|
||||
|
@ -26,6 +27,7 @@ import org.keycloak.models.jpa.entities.AuthenticationExecutionEntity;
|
|||
import org.keycloak.models.jpa.entities.AuthenticationFlowEntity;
|
||||
import org.keycloak.models.jpa.entities.AuthenticatorConfigEntity;
|
||||
import org.keycloak.models.jpa.entities.ClientEntity;
|
||||
import org.keycloak.models.jpa.entities.ClientTemplateEntity;
|
||||
import org.keycloak.models.jpa.entities.GroupEntity;
|
||||
import org.keycloak.models.jpa.entities.IdentityProviderEntity;
|
||||
import org.keycloak.models.jpa.entities.IdentityProviderMapperEntity;
|
||||
|
@ -2095,4 +2097,64 @@ public class RealmAdapter implements RealmModel {
|
|||
public void addTopLevelGroup(GroupModel subGroup) {
|
||||
subGroup.setParent(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ClientTemplateModel> getClientTemplates() {
|
||||
List<ClientTemplateModel> list = new LinkedList<>();
|
||||
if (realm.getClientTemplates() == null) return list;
|
||||
for (ClientTemplateEntity entity : realm.getClientTemplates()) {
|
||||
list.add(new ClientTemplateAdapter(this, em, session, entity));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTemplateModel addClientTemplate(String name) {
|
||||
return this.addClientTemplate(KeycloakModelUtils.generateId(), name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTemplateModel addClientTemplate(String id, String name) {
|
||||
ClientTemplateEntity entity = new ClientTemplateEntity();
|
||||
entity.setId(id);
|
||||
entity.setName(name);
|
||||
entity.setRealm(realm);
|
||||
realm.getClientTemplates().add(entity);
|
||||
em.persist(entity);
|
||||
em.flush();
|
||||
final ClientTemplateModel resource = new ClientTemplateAdapter(this, em, session, entity);
|
||||
em.flush();
|
||||
return resource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeClientTemplate(String id) {
|
||||
if (id == null) return false;
|
||||
ClientTemplateModel client = getClientTemplateById(id);
|
||||
if (client == null) return false;
|
||||
|
||||
ClientTemplateEntity clientEntity = null;
|
||||
Iterator<ClientTemplateEntity> it = realm.getClientTemplates().iterator();
|
||||
while (it.hasNext()) {
|
||||
ClientTemplateEntity ae = it.next();
|
||||
if (ae.getId().equals(id)) {
|
||||
clientEntity = ae;
|
||||
it.remove();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (client == null) {
|
||||
return false;
|
||||
}
|
||||
em.remove(clientEntity);
|
||||
em.flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTemplateModel getClientTemplateById(String id) {
|
||||
return session.realms().getClientTemplateById(id, this);
|
||||
}
|
||||
|
||||
}
|
|
@ -57,6 +57,10 @@ public class ClientEntity {
|
|||
@Column(name="FULL_SCOPE_ALLOWED")
|
||||
private boolean fullScopeAllowed;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "CLIENT_TEMPLATE_ID")
|
||||
protected ClientTemplateEntity clientTemplate;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "REALM_ID")
|
||||
protected RealmEntity realm;
|
||||
|
@ -392,4 +396,12 @@ public class ClientEntity {
|
|||
public void setRegisteredNodes(Map<String, Integer> registeredNodes) {
|
||||
this.registeredNodes = registeredNodes;
|
||||
}
|
||||
|
||||
public ClientTemplateEntity getClientTemplate() {
|
||||
return clientTemplate;
|
||||
}
|
||||
|
||||
public void setClientTemplate(ClientTemplateEntity clientTemplate) {
|
||||
this.clientTemplate = clientTemplate;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
package org.keycloak.models.jpa.entities;
|
||||
|
||||
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.MapKeyColumn;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
@Entity
|
||||
@Table(name="CLIENT_TEMPLATE", uniqueConstraints = {@UniqueConstraint(columnNames = {"REALM_ID", "NAME"})})
|
||||
public class ClientTemplateEntity {
|
||||
|
||||
@Id
|
||||
@Column(name="ID", length = 36)
|
||||
private String id;
|
||||
@Column(name = "NAME")
|
||||
private String name;
|
||||
@Column(name = "DESCRIPTION")
|
||||
private String description;
|
||||
@OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "clientTemplate")
|
||||
Collection<ProtocolMapperEntity> protocolMappers = new ArrayList<ProtocolMapperEntity>();
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "REALM_ID")
|
||||
protected RealmEntity realm;
|
||||
|
||||
@Column(name="PROTOCOL")
|
||||
private String protocol;
|
||||
|
||||
|
||||
public RealmEntity getRealm() {
|
||||
return realm;
|
||||
}
|
||||
|
||||
public void setRealm(RealmEntity realm) {
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
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 getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public Collection<ProtocolMapperEntity> getProtocolMappers() {
|
||||
return protocolMappers;
|
||||
}
|
||||
|
||||
public void setProtocolMappers(Collection<ProtocolMapperEntity> protocolMappers) {
|
||||
this.protocolMappers = protocolMappers;
|
||||
}
|
||||
|
||||
public String getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public void setProtocol(String protocol) {
|
||||
this.protocol = protocol;
|
||||
}
|
||||
}
|
|
@ -46,6 +46,10 @@ public class ProtocolMapperEntity {
|
|||
@JoinColumn(name = "CLIENT_ID")
|
||||
private ClientEntity client;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "CLIENT_TEMPLATE_ID")
|
||||
private ClientTemplateEntity clientTemplate;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
@ -94,6 +98,14 @@ public class ProtocolMapperEntity {
|
|||
this.client = client;
|
||||
}
|
||||
|
||||
public ClientTemplateEntity getClientTemplate() {
|
||||
return clientTemplate;
|
||||
}
|
||||
|
||||
public void setClientTemplate(ClientTemplateEntity clientTemplate) {
|
||||
this.clientTemplate = clientTemplate;
|
||||
}
|
||||
|
||||
public boolean isConsentRequired() {
|
||||
return consentRequired;
|
||||
}
|
||||
|
|
|
@ -132,6 +132,10 @@ public class RealmEntity {
|
|||
@JoinTable(name="REALM_CLIENT", joinColumns={ @JoinColumn(name="REALM_ID") }, inverseJoinColumns={ @JoinColumn(name="CLIENT_ID") })
|
||||
Collection<ClientEntity> clients = new ArrayList<>();
|
||||
|
||||
@OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true)
|
||||
@JoinTable(name="REALM_CLIENT_TEMPLATE", joinColumns={ @JoinColumn(name="REALM_ID") }, inverseJoinColumns={ @JoinColumn(name="CLIENT_TEMPLATE_ID") })
|
||||
Collection<ClientTemplateEntity> clientTemplates = new ArrayList<>();
|
||||
|
||||
@OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
|
||||
Collection<RoleEntity> roles = new ArrayList<RoleEntity>();
|
||||
|
||||
|
@ -741,5 +745,12 @@ public class RealmEntity {
|
|||
this.clientAuthenticationFlow = clientAuthenticationFlow;
|
||||
}
|
||||
|
||||
public Collection<ClientTemplateEntity> getClientTemplates() {
|
||||
return clientTemplates;
|
||||
}
|
||||
|
||||
public void setClientTemplates(Collection<ClientTemplateEntity> clientTemplates) {
|
||||
this.clientTemplates = clientTemplates;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ 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.ClientTemplateModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
|
@ -363,7 +364,7 @@ public class ClientAdapter extends AbstractMongoAdapter<MongoClientEntity> imple
|
|||
public void removeProtocolMapper(ProtocolMapperModel mapping) {
|
||||
for (ProtocolMapperEntity entity : getMongoEntity().getProtocolMappers()) {
|
||||
if (entity.getId().equals(mapping.getId())) {
|
||||
session.users().preRemove(this, mapping);
|
||||
session.users().preRemove(mapping);
|
||||
|
||||
getMongoEntity().getProtocolMappers().remove(entity);
|
||||
updateMongoEntity();
|
||||
|
@ -713,5 +714,16 @@ public class ClientAdapter extends AbstractMongoAdapter<MongoClientEntity> imple
|
|||
return getId().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTemplateModel getClientTemplate() {
|
||||
if (getMongoEntity().getClientTemplate() == null) return null;
|
||||
return session.realms().getClientTemplateById(getMongoEntity().getClientTemplate(), realm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClientTemplate(ClientTemplateModel template) {
|
||||
getMongoEntity().setClientTemplate(template.getId());
|
||||
updateMongoEntity();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,229 @@
|
|||
package org.keycloak.models.mongo.keycloak.adapters;
|
||||
|
||||
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.ClientTemplateModel;
|
||||
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.entities.ClientTemplateEntity;
|
||||
import org.keycloak.models.entities.ProtocolMapperEntity;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoClientEntity;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoClientTemplateEntity;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
|
||||
import org.keycloak.models.mongo.utils.MongoModelUtils;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
*/
|
||||
public class ClientTemplateAdapter extends AbstractMongoAdapter<MongoClientTemplateEntity> implements ClientTemplateModel {
|
||||
|
||||
protected final MongoClientTemplateEntity clientTemplateEntity;
|
||||
private final RealmModel realm;
|
||||
protected KeycloakSession session;
|
||||
|
||||
public ClientTemplateAdapter(KeycloakSession session, RealmModel realm, MongoClientTemplateEntity clientEntity, MongoStoreInvocationContext invContext) {
|
||||
super(invContext);
|
||||
this.session = session;
|
||||
this.realm = realm;
|
||||
this.clientTemplateEntity = clientEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MongoClientTemplateEntity getMongoEntity() {
|
||||
return clientTemplateEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RealmModel getRealm() {
|
||||
return realm;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return getMongoEntity().getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return getMongoEntity().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
getMongoEntity().setName(name);
|
||||
updateMongoEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() { return getMongoEntity().getDescription(); }
|
||||
|
||||
@Override
|
||||
public String getProtocol() {
|
||||
return getMongoEntity().getProtocol();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProtocol(String protocol) {
|
||||
getMongoEntity().setProtocol(protocol);
|
||||
updateMongoEntity();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setDescription(String description) {
|
||||
getMongoEntity().setDescription(description);
|
||||
updateMongoEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ProtocolMapperModel> getProtocolMappers() {
|
||||
Set<ProtocolMapperModel> result = new HashSet<ProtocolMapperModel>();
|
||||
for (ProtocolMapperEntity entity : getMongoEntity().getProtocolMappers()) {
|
||||
ProtocolMapperModel mapping = new ProtocolMapperModel();
|
||||
mapping.setId(entity.getId());
|
||||
mapping.setName(entity.getName());
|
||||
mapping.setProtocol(entity.getProtocol());
|
||||
mapping.setProtocolMapper(entity.getProtocolMapper());
|
||||
mapping.setConsentRequired(entity.isConsentRequired());
|
||||
mapping.setConsentText(entity.getConsentText());
|
||||
Map<String, String> config = new HashMap<String, String>();
|
||||
if (entity.getConfig() != null) {
|
||||
config.putAll(entity.getConfig());
|
||||
}
|
||||
mapping.setConfig(config);
|
||||
result.add(mapping);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolMapperModel addProtocolMapper(ProtocolMapperModel model) {
|
||||
if (getProtocolMapperByName(model.getProtocol(), model.getName()) != null) {
|
||||
throw new ModelDuplicateException("Protocol mapper name must be unique per protocol");
|
||||
}
|
||||
ProtocolMapperEntity entity = new ProtocolMapperEntity();
|
||||
String id = model.getId() != null ? model.getId() : KeycloakModelUtils.generateId();
|
||||
entity.setId(id);
|
||||
entity.setProtocol(model.getProtocol());
|
||||
entity.setName(model.getName());
|
||||
entity.setProtocolMapper(model.getProtocolMapper());
|
||||
entity.setConfig(model.getConfig());
|
||||
entity.setConsentRequired(model.isConsentRequired());
|
||||
entity.setConsentText(model.getConsentText());
|
||||
getMongoEntity().getProtocolMappers().add(entity);
|
||||
updateMongoEntity();
|
||||
return entityToModel(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeProtocolMapper(ProtocolMapperModel mapping) {
|
||||
for (ProtocolMapperEntity entity : getMongoEntity().getProtocolMappers()) {
|
||||
if (entity.getId().equals(mapping.getId())) {
|
||||
session.users().preRemove(mapping);
|
||||
|
||||
getMongoEntity().getProtocolMappers().remove(entity);
|
||||
updateMongoEntity();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected ProtocolMapperEntity getProtocolMapperyEntityById(String id) {
|
||||
for (ProtocolMapperEntity entity : getMongoEntity().getProtocolMappers()) {
|
||||
if (entity.getId().equals(id)) {
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
protected ProtocolMapperEntity getProtocolMapperEntityByName(String protocol, String name) {
|
||||
for (ProtocolMapperEntity entity : getMongoEntity().getProtocolMappers()) {
|
||||
if (entity.getProtocol().equals(protocol) && entity.getName().equals(name)) {
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void updateProtocolMapper(ProtocolMapperModel mapping) {
|
||||
ProtocolMapperEntity entity = getProtocolMapperyEntityById(mapping.getId());
|
||||
entity.setProtocolMapper(mapping.getProtocolMapper());
|
||||
entity.setConsentRequired(mapping.isConsentRequired());
|
||||
entity.setConsentText(mapping.getConsentText());
|
||||
if (entity.getConfig() != null) {
|
||||
entity.getConfig().clear();
|
||||
entity.getConfig().putAll(mapping.getConfig());
|
||||
} else {
|
||||
entity.setConfig(mapping.getConfig());
|
||||
}
|
||||
updateMongoEntity();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolMapperModel getProtocolMapperById(String id) {
|
||||
ProtocolMapperEntity entity = getProtocolMapperyEntityById(id);
|
||||
if (entity == null) return null;
|
||||
return entityToModel(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolMapperModel getProtocolMapperByName(String protocol, String name) {
|
||||
ProtocolMapperEntity entity = getProtocolMapperEntityByName(protocol, name);
|
||||
if (entity == null) return null;
|
||||
return entityToModel(entity);
|
||||
}
|
||||
|
||||
protected ProtocolMapperModel entityToModel(ProtocolMapperEntity entity) {
|
||||
ProtocolMapperModel mapping = new ProtocolMapperModel();
|
||||
mapping.setId(entity.getId());
|
||||
mapping.setName(entity.getName());
|
||||
mapping.setProtocol(entity.getProtocol());
|
||||
mapping.setProtocolMapper(entity.getProtocolMapper());
|
||||
mapping.setConsentRequired(entity.isConsentRequired());
|
||||
mapping.setConsentText(entity.getConsentText());
|
||||
Map<String, String> config = new HashMap<String, String>();
|
||||
if (entity.getConfig() != null) config.putAll(entity.getConfig());
|
||||
mapping.setConfig(config);
|
||||
return mapping;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || !(o instanceof ClientTemplateModel)) return false;
|
||||
|
||||
ClientTemplateModel that = (ClientTemplateModel) o;
|
||||
return that.getId().equals(getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getId().hashCode();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -28,7 +28,7 @@ import java.util.Set;
|
|||
|
||||
/**
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
*/
|
||||
public class GroupAdapter extends AbstractMongoAdapter<MongoGroupEntity> implements GroupModel {
|
||||
|
||||
|
|
|
@ -7,12 +7,14 @@ import org.keycloak.connections.mongo.api.MongoStore;
|
|||
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
|
||||
import org.keycloak.migration.MigrationModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientTemplateModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RealmProvider;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoClientEntity;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoClientTemplateEntity;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoGroupEntity;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoMigrationModelEntity;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoRealmEntity;
|
||||
|
@ -143,4 +145,15 @@ public class MongoRealmProvider implements RealmProvider {
|
|||
return new ClientAdapter(session, realm, appData, invocationContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTemplateModel getClientTemplateById(String id, RealmModel realm) {
|
||||
MongoClientTemplateEntity appData = getMongoStore().loadEntity(MongoClientTemplateEntity.class, id, invocationContext);
|
||||
|
||||
// Check if application belongs to this realm
|
||||
if (appData == null || !realm.getId().equals(appData.getRealmId())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ClientTemplateAdapter(session, realm, appData, invocationContext);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -435,7 +435,7 @@ public class MongoUserProvider implements UserProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void preRemove(ClientModel client, ProtocolMapperModel protocolMapper) {
|
||||
public void preRemove(ProtocolMapperModel protocolMapper) {
|
||||
// Remove this protocol mapper from all consents, which has it
|
||||
DBObject query = new QueryBuilder()
|
||||
.and("grantedProtocolMappers").is(protocolMapper.getId())
|
||||
|
|
|
@ -9,6 +9,7 @@ import org.keycloak.models.AuthenticationExecutionModel;
|
|||
import org.keycloak.models.AuthenticationFlowModel;
|
||||
import org.keycloak.models.AuthenticatorConfigModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientTemplateModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.IdentityProviderMapperModel;
|
||||
import org.keycloak.models.IdentityProviderModel;
|
||||
|
@ -35,6 +36,7 @@ import org.keycloak.models.entities.RequiredCredentialEntity;
|
|||
import org.keycloak.models.entities.UserFederationMapperEntity;
|
||||
import org.keycloak.models.entities.UserFederationProviderEntity;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoClientEntity;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoClientTemplateEntity;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoGroupEntity;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoRealmEntity;
|
||||
import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
|
||||
|
@ -2013,4 +2015,52 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
|
|||
mapper.setConfig(config);
|
||||
return mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ClientTemplateModel> getClientTemplates() {
|
||||
DBObject query = new QueryBuilder()
|
||||
.and("realmId").is(getId())
|
||||
.get();
|
||||
List<MongoClientTemplateEntity> clientEntities = getMongoStore().loadEntities(MongoClientTemplateEntity.class, query, invocationContext);
|
||||
|
||||
List<ClientTemplateModel> result = new LinkedList<>();
|
||||
for (MongoClientTemplateEntity clientEntity : clientEntities) {
|
||||
result.add(new ClientTemplateAdapter(session, this, clientEntity, invocationContext));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTemplateModel addClientTemplate(String name) {
|
||||
return this.addClientTemplate(null, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTemplateModel addClientTemplate(String id, String name) {
|
||||
MongoClientTemplateEntity clientEntity = new MongoClientTemplateEntity();
|
||||
clientEntity.setId(id);
|
||||
clientEntity.setName(name);
|
||||
clientEntity.setRealmId(getId());
|
||||
getMongoStore().insertEntity(clientEntity, invocationContext);
|
||||
|
||||
final ClientTemplateModel model = new ClientTemplateAdapter(session, this, clientEntity, invocationContext);
|
||||
return model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeClientTemplate(String id) {
|
||||
if (id == null) return false;
|
||||
ClientTemplateModel client = getClientTemplateById(id);
|
||||
if (client == null) return false;
|
||||
|
||||
|
||||
return getMongoStore().removeEntity(MongoClientTemplateEntity.class, id, invocationContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTemplateModel getClientTemplateById(String id) {
|
||||
return model.getClientTemplateById(id, this);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package org.keycloak.models.mongo.keycloak.entities;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.QueryBuilder;
|
||||
import org.keycloak.connections.mongo.api.MongoCollection;
|
||||
import org.keycloak.connections.mongo.api.MongoIdentifiableEntity;
|
||||
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
|
||||
import org.keycloak.models.entities.ClientEntity;
|
||||
import org.keycloak.models.entities.ClientTemplateEntity;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bburke@redhat.com">Bill Burke</a>
|
||||
*/
|
||||
@MongoCollection(collectionName = "clientTemplates")
|
||||
public class MongoClientTemplateEntity extends ClientTemplateEntity implements MongoIdentifiableEntity {
|
||||
|
||||
@Override
|
||||
public void afterRemove(MongoStoreInvocationContext context) {
|
||||
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ import org.keycloak.jose.jws.JWSInputException;
|
|||
import org.keycloak.jose.jws.crypto.RSAProvider;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientSessionModel;
|
||||
import org.keycloak.models.ClientTemplateModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
|
@ -258,13 +259,23 @@ public class TokenManager {
|
|||
Set<String> requestedRoles = new HashSet<String>();
|
||||
// todo scope param protocol independent
|
||||
String scopeParam = clientSession.getNote(OAuth2Constants.SCOPE);
|
||||
for (RoleModel r : TokenManager.getAccess(scopeParam, true, clientSession.getClient(), user)) {
|
||||
ClientModel client = clientSession.getClient();
|
||||
for (RoleModel r : TokenManager.getAccess(scopeParam, true, client, user)) {
|
||||
requestedRoles.add(r.getId());
|
||||
}
|
||||
clientSession.setRoles(requestedRoles);
|
||||
|
||||
Set<String> requestedProtocolMappers = new HashSet<String>();
|
||||
for (ProtocolMapperModel protocolMapper : clientSession.getClient().getProtocolMappers()) {
|
||||
ClientTemplateModel clientTemplate = client.getClientTemplate();
|
||||
if (clientTemplate != null) {
|
||||
for (ProtocolMapperModel protocolMapper : clientTemplate.getProtocolMappers()) {
|
||||
if (protocolMapper.getProtocol().equals(clientSession.getAuthMethod())) {
|
||||
requestedProtocolMappers.add(protocolMapper.getId());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
for (ProtocolMapperModel protocolMapper : client.getProtocolMappers()) {
|
||||
if (protocolMapper.getProtocol().equals(clientSession.getAuthMethod())) {
|
||||
requestedProtocolMappers.add(protocolMapper.getId());
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package org.keycloak.services.managers;
|
||||
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientSessionModel;
|
||||
import org.keycloak.models.ClientTemplateModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
|
@ -185,9 +187,15 @@ public class ClientSessionCode {
|
|||
|
||||
public Set<ProtocolMapperModel> getRequestedProtocolMappers() {
|
||||
Set<ProtocolMapperModel> requestedProtocolMappers = new HashSet<ProtocolMapperModel>();
|
||||
if (clientSession.getProtocolMappers() != null) {
|
||||
for (String protocolMapperId : clientSession.getProtocolMappers()) {
|
||||
ProtocolMapperModel protocolMapper = clientSession.getClient().getProtocolMapperById(protocolMapperId);
|
||||
Set<String> protocolMappers = clientSession.getProtocolMappers();
|
||||
ClientModel client = clientSession.getClient();
|
||||
ClientTemplateModel template = client.getClientTemplate();
|
||||
if (protocolMappers != null) {
|
||||
for (String protocolMapperId : protocolMappers) {
|
||||
ProtocolMapperModel protocolMapper = client.getProtocolMapperById(protocolMapperId);
|
||||
if (protocolMapper == null && template != null) {
|
||||
protocolMapper = template.getProtocolMapperById(protocolMapperId);
|
||||
}
|
||||
if (protocolMapper != null) {
|
||||
requestedProtocolMappers.add(protocolMapper);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
package org.keycloak.services.resources.admin;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||
import org.jboss.resteasy.spi.BadRequestException;
|
||||
import org.jboss.resteasy.spi.NotFoundException;
|
||||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||
import org.keycloak.common.util.Time;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientSessionModel;
|
||||
import org.keycloak.models.ClientTemplateModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.models.utils.RepresentationToModel;
|
||||
import org.keycloak.representations.adapters.action.GlobalRequestResult;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.ClientTemplateRepresentation;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.representations.idm.UserSessionRepresentation;
|
||||
import org.keycloak.services.ErrorResponse;
|
||||
import org.keycloak.services.clientregistration.ClientRegistrationTokenUtils;
|
||||
import org.keycloak.services.managers.ClientManager;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.managers.ResourceAdminManager;
|
||||
import org.keycloak.services.resources.KeycloakApplication;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
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;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.lang.Boolean.TRUE;
|
||||
|
||||
|
||||
/**
|
||||
* Base resource class for managing one particular client of a realm.
|
||||
*
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class ClientTemplateResource {
|
||||
protected static final Logger logger = Logger.getLogger(ClientTemplateResource.class);
|
||||
protected RealmModel realm;
|
||||
private RealmAuth auth;
|
||||
private AdminEventBuilder adminEvent;
|
||||
protected ClientTemplateModel client;
|
||||
protected KeycloakSession session;
|
||||
|
||||
@Context
|
||||
protected UriInfo uriInfo;
|
||||
|
||||
@Context
|
||||
protected KeycloakApplication keycloak;
|
||||
|
||||
protected KeycloakApplication getKeycloakApplication() {
|
||||
return keycloak;
|
||||
}
|
||||
|
||||
public ClientTemplateResource(RealmModel realm, RealmAuth auth, ClientTemplateModel clientModel, KeycloakSession session, AdminEventBuilder adminEvent) {
|
||||
this.realm = realm;
|
||||
this.auth = auth;
|
||||
this.client = clientModel;
|
||||
this.session = session;
|
||||
this.adminEvent = adminEvent;
|
||||
|
||||
auth.init(RealmAuth.Resource.CLIENT);
|
||||
}
|
||||
|
||||
@Path("protocol-mappers")
|
||||
public ProtocolMappersResource getProtocolMappers() {
|
||||
ProtocolMappersResource mappers = new ProtocolMappersResource(client, auth, adminEvent);
|
||||
ResteasyProviderFactory.getInstance().injectProperties(mappers);
|
||||
return mappers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the client template
|
||||
* @param rep
|
||||
* @return
|
||||
*/
|
||||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response update(final ClientTemplateRepresentation rep) {
|
||||
auth.requireManage();
|
||||
|
||||
try {
|
||||
RepresentationToModel.updateClientTemplate(rep, client);
|
||||
adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success();
|
||||
return Response.noContent().build();
|
||||
} catch (ModelDuplicateException e) {
|
||||
return ErrorResponse.exists("Client Template " + rep.getName() + " already exists");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get representation of the client template
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@GET
|
||||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public ClientTemplateRepresentation getClient() {
|
||||
auth.requireView();
|
||||
return ModelToRepresentation.toRepresentation(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the client template
|
||||
*
|
||||
*/
|
||||
@DELETE
|
||||
@NoCache
|
||||
public void deleteClientTemplate() {
|
||||
auth.requireManage();
|
||||
realm.removeClientTemplate(client.getId());
|
||||
adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
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.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientTemplateModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.models.utils.RepresentationToModel;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.ClientTemplateRepresentation;
|
||||
import org.keycloak.services.ErrorResponse;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.Context;
|
||||
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.List;
|
||||
|
||||
/**
|
||||
* Base resource class for managing a realm's client templates.
|
||||
*
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class ClientTemplatesResource {
|
||||
protected static final Logger logger = Logger.getLogger(RealmAdminResource.class);
|
||||
protected RealmModel realm;
|
||||
private RealmAuth auth;
|
||||
private AdminEventBuilder adminEvent;
|
||||
|
||||
@Context
|
||||
protected KeycloakSession session;
|
||||
|
||||
public ClientTemplatesResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
|
||||
this.realm = realm;
|
||||
this.auth = auth;
|
||||
this.adminEvent = adminEvent;
|
||||
|
||||
auth.init(RealmAuth.Resource.CLIENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get client templates belonging to the realm
|
||||
*
|
||||
* Returns a list of client templates belonging to the realm
|
||||
*/
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@NoCache
|
||||
public List<ClientTemplateRepresentation> getClientTemplates() {
|
||||
auth.requireAny();
|
||||
|
||||
List<ClientTemplateRepresentation> rep = new ArrayList<>();
|
||||
List<ClientTemplateModel> clientModels = realm.getClientTemplates();
|
||||
|
||||
boolean view = auth.hasView();
|
||||
for (ClientTemplateModel clientModel : clientModels) {
|
||||
if (view) {
|
||||
rep.add(ModelToRepresentation.toRepresentation(clientModel));
|
||||
} else {
|
||||
ClientTemplateRepresentation client = new ClientTemplateRepresentation();
|
||||
client.setId(clientModel.getId());
|
||||
client.setName(clientModel.getName());
|
||||
client.setDescription(clientModel.getDescription());
|
||||
rep.add(client);
|
||||
}
|
||||
}
|
||||
return rep;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new client template
|
||||
*
|
||||
* Client Template's name must be unique!
|
||||
*
|
||||
* @param uriInfo
|
||||
* @param rep
|
||||
* @return
|
||||
*/
|
||||
@POST
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response createClientTemplate(final @Context UriInfo uriInfo, final ClientTemplateRepresentation rep) {
|
||||
auth.requireManage();
|
||||
|
||||
try {
|
||||
ClientTemplateModel clientModel = RepresentationToModel.createClientTemplate(session, realm, rep);
|
||||
|
||||
adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, clientModel.getId()).representation(rep).success();
|
||||
|
||||
return Response.created(uriInfo.getAbsolutePathBuilder().path(clientModel.getId()).build()).build();
|
||||
} catch (ModelDuplicateException e) {
|
||||
return ErrorResponse.exists("Client Template " + rep.getName() + " already exists");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Base path for managing a specific client template.
|
||||
*
|
||||
* @param id id of client template (not name)
|
||||
* @return
|
||||
*/
|
||||
@Path("{id}")
|
||||
public ClientTemplateResource getClient(final @PathParam("id") String id) {
|
||||
ClientTemplateModel clientModel = realm.getClientTemplateById(id);
|
||||
if (clientModel == null) {
|
||||
throw new NotFoundException("Could not find client template");
|
||||
}
|
||||
|
||||
ClientTemplateResource clientResource = new ClientTemplateResource(realm, auth, clientModel, session, adminEvent);
|
||||
ResteasyProviderFactory.getInstance().injectProperties(clientResource);
|
||||
return clientResource;
|
||||
}
|
||||
|
||||
}
|
|
@ -7,6 +7,7 @@ import org.keycloak.events.admin.OperationType;
|
|||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.ProtocolMapperContainerModel;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.models.utils.RepresentationToModel;
|
||||
|
@ -38,7 +39,7 @@ import java.util.List;
|
|||
public class ProtocolMappersResource {
|
||||
protected static final Logger logger = Logger.getLogger(ProtocolMappersResource.class);
|
||||
|
||||
protected ClientModel client;
|
||||
protected ProtocolMapperContainerModel client;
|
||||
|
||||
protected RealmAuth auth;
|
||||
|
||||
|
@ -50,7 +51,7 @@ public class ProtocolMappersResource {
|
|||
@Context
|
||||
protected KeycloakSession session;
|
||||
|
||||
public ProtocolMappersResource(ClientModel client, RealmAuth auth, AdminEventBuilder adminEvent) {
|
||||
public ProtocolMappersResource(ProtocolMapperContainerModel client, RealmAuth auth, AdminEventBuilder adminEvent) {
|
||||
this.auth = auth;
|
||||
this.client = client;
|
||||
this.adminEvent = adminEvent;
|
||||
|
|
|
@ -144,6 +144,18 @@ public class RealmAdminResource {
|
|||
return clientsResource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base path for managing client templates under this realm.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Path("client-templates")
|
||||
public ClientTemplatesResource getClientTemplates() {
|
||||
ClientTemplatesResource clientsResource = new ClientTemplatesResource(realm, auth, adminEvent);
|
||||
ResteasyProviderFactory.getInstance().injectProperties(clientsResource);
|
||||
return clientsResource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base path for managing client initial access tokens
|
||||
*
|
||||
|
|
|
@ -32,19 +32,24 @@ import org.junit.ClassRule;
|
|||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.common.VerificationException;
|
||||
import org.keycloak.admin.client.Keycloak;
|
||||
import org.keycloak.admin.client.resource.ClientTemplateResource;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.common.enums.SslRequired;
|
||||
import org.keycloak.common.util.Time;
|
||||
import org.keycloak.events.Details;
|
||||
import org.keycloak.events.Errors;
|
||||
import org.keycloak.events.Event;
|
||||
import org.keycloak.jose.jws.JWSInput;
|
||||
import org.keycloak.jose.jws.JWSInputException;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
|
||||
import org.keycloak.protocol.oidc.mappers.AddressMapper;
|
||||
import org.keycloak.protocol.oidc.mappers.HardcodedClaim;
|
||||
|
@ -53,6 +58,9 @@ import org.keycloak.protocol.oidc.mappers.RoleNameMapper;
|
|||
import org.keycloak.protocol.oidc.mappers.UserAttributeMapper;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.IDToken;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.ClientTemplateRepresentation;
|
||||
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
|
||||
import org.keycloak.services.managers.ClientManager;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.testsuite.AssertEvents;
|
||||
|
@ -63,7 +71,6 @@ import org.keycloak.testsuite.rule.KeycloakRule;
|
|||
import org.keycloak.testsuite.rule.WebResource;
|
||||
import org.keycloak.testsuite.rule.WebRule;
|
||||
import org.keycloak.util.BasicAuthHelper;
|
||||
import org.keycloak.common.util.Time;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
|
||||
import javax.ws.rs.client.Client;
|
||||
|
@ -75,7 +82,6 @@ import javax.ws.rs.core.GenericType;
|
|||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
|
@ -91,12 +97,15 @@ import static org.junit.Assert.*;
|
|||
*/
|
||||
public class AccessTokenTest {
|
||||
|
||||
protected static Keycloak keycloak;
|
||||
|
||||
@ClassRule
|
||||
public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
|
||||
|
||||
@Override
|
||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||
appRealm.getClientByClientId("test-app").setDirectAccessGrantsEnabled(true);
|
||||
keycloak = Keycloak.getInstance("http://localhost:8081/auth", "master", "admin", "admin", Constants.ADMIN_CLI_CLIENT_ID);
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -393,7 +402,8 @@ public class AccessTokenTest {
|
|||
{
|
||||
Response response = validateTarget.queryParam("access_token", "bad token").request().get();
|
||||
Assert.assertEquals(400, response.getStatus());
|
||||
HashMap<String, String> error = response.readEntity(new GenericType <HashMap<String, String>>() {});
|
||||
HashMap<String, String> error = response.readEntity(new GenericType<HashMap<String, String>>() {
|
||||
});
|
||||
Assert.assertNotNull(error.get("error"));
|
||||
}
|
||||
|
||||
|
@ -428,7 +438,8 @@ public class AccessTokenTest {
|
|||
{
|
||||
Response response = validateTarget.queryParam("access_token", tokenResponse.getToken()).request().get();
|
||||
Assert.assertEquals(400, response.getStatus());
|
||||
HashMap<String, String> error = response.readEntity(new GenericType <HashMap<String, String>>() {});
|
||||
HashMap<String, String> error = response.readEntity(new GenericType<HashMap<String, String>>() {
|
||||
});
|
||||
Assert.assertNotNull(error.get("error"));
|
||||
}
|
||||
|
||||
|
@ -657,6 +668,7 @@ public class AccessTokenTest {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testTokenMapping() throws Exception {
|
||||
Client client = ClientBuilder.newClient();
|
||||
|
@ -678,7 +690,8 @@ public class AccessTokenTest {
|
|||
ClientModel app = realm.getClientByClientId("test-app");
|
||||
ProtocolMapperModel mapper = AddressMapper.createAddressMapper(true, true);
|
||||
app.addProtocolMapper(mapper);
|
||||
app.addProtocolMapper(HardcodedClaim.create("hard", "hard", "coded", "String", false, null, true, true));
|
||||
ProtocolMapperModel hard = HardcodedClaim.create("hard", "hard", "coded", "String", false, null, true, true);
|
||||
app.addProtocolMapper(hard);
|
||||
app.addProtocolMapper(HardcodedClaim.create("hard-nested", "nested.hard", "coded-nested", "String", false, null, true, true));
|
||||
app.addProtocolMapper(UserAttributeMapper.createClaimMapper("custom phone", "phone", "home_phone", "String", true, "", true, true, false));
|
||||
app.addProtocolMapper(UserAttributeMapper.createClaimMapper("nested phone", "phone", "home.phone", "String", true, "", true, true, false));
|
||||
|
@ -705,11 +718,11 @@ public class AccessTokenTest {
|
|||
Assert.assertNotNull(idToken.getOtherClaims().get("home_phone"));
|
||||
Assert.assertEquals("617-777-6666", idToken.getOtherClaims().get("home_phone"));
|
||||
Assert.assertEquals("coded", idToken.getOtherClaims().get("hard"));
|
||||
Map nested = (Map)idToken.getOtherClaims().get("nested");
|
||||
Map nested = (Map) idToken.getOtherClaims().get("nested");
|
||||
Assert.assertEquals("coded-nested", nested.get("hard"));
|
||||
nested = (Map)idToken.getOtherClaims().get("home");
|
||||
nested = (Map) idToken.getOtherClaims().get("home");
|
||||
Assert.assertEquals("617-777-6666", nested.get("phone"));
|
||||
List<String> departments = (List<String>)idToken.getOtherClaims().get("department");
|
||||
List<String> departments = (List<String>) idToken.getOtherClaims().get("department");
|
||||
Assert.assertEquals(2, departments.size());
|
||||
Assert.assertTrue(departments.contains("finance") && departments.contains("development"));
|
||||
|
||||
|
@ -724,11 +737,11 @@ public class AccessTokenTest {
|
|||
Assert.assertNotNull(accessToken.getOtherClaims().get("home_phone"));
|
||||
Assert.assertEquals("617-777-6666", accessToken.getOtherClaims().get("home_phone"));
|
||||
Assert.assertEquals("coded", accessToken.getOtherClaims().get("hard"));
|
||||
nested = (Map)accessToken.getOtherClaims().get("nested");
|
||||
nested = (Map) accessToken.getOtherClaims().get("nested");
|
||||
Assert.assertEquals("coded-nested", nested.get("hard"));
|
||||
nested = (Map)accessToken.getOtherClaims().get("home");
|
||||
nested = (Map) accessToken.getOtherClaims().get("home");
|
||||
Assert.assertEquals("617-777-6666", nested.get("phone"));
|
||||
departments = (List<String>)idToken.getOtherClaims().get("department");
|
||||
departments = (List<String>) idToken.getOtherClaims().get("department");
|
||||
Assert.assertEquals(2, departments.size());
|
||||
Assert.assertTrue(departments.contains("finance") && departments.contains("development"));
|
||||
Assert.assertTrue(accessToken.getRealmAccess().getRoles().contains("hardcoded"));
|
||||
|
@ -739,7 +752,6 @@ public class AccessTokenTest {
|
|||
|
||||
response.close();
|
||||
}
|
||||
client.close();
|
||||
|
||||
// undo mappers
|
||||
{
|
||||
|
@ -751,11 +763,12 @@ public class AccessTokenTest {
|
|||
|| model.getName().equals("hard")
|
||||
|| model.getName().equals("hard-nested")
|
||||
|| model.getName().equals("custom phone")
|
||||
|| model.getName().equals("departments")
|
||||
|| model.getName().equals("nested phone")
|
||||
|| model.getName().equals("rename-app-role")
|
||||
|| model.getName().equals("hard-realm")
|
||||
|| model.getName().equals("hard-app")
|
||||
) {
|
||||
) {
|
||||
app.removeProtocolMapper(model);
|
||||
}
|
||||
}
|
||||
|
@ -763,7 +776,101 @@ public class AccessTokenTest {
|
|||
session.close();
|
||||
}
|
||||
|
||||
events.clear();
|
||||
|
||||
|
||||
{
|
||||
Response response = executeGrantAccessTokenRequest(grantTarget);
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
org.keycloak.representations.AccessTokenResponse tokenResponse = response.readEntity(org.keycloak.representations.AccessTokenResponse.class);
|
||||
IDToken idToken = getIdToken(tokenResponse);
|
||||
Assert.assertNull(idToken.getAddress());
|
||||
Assert.assertNull(idToken.getOtherClaims().get("home_phone"));
|
||||
Assert.assertNull(idToken.getOtherClaims().get("hard"));
|
||||
Assert.assertNull(idToken.getOtherClaims().get("nested"));
|
||||
Assert.assertNull(idToken.getOtherClaims().get("department"));
|
||||
|
||||
response.close();
|
||||
}
|
||||
|
||||
|
||||
events.clear();
|
||||
client.close();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClientTemplate() throws Exception {
|
||||
RealmResource realm = keycloak.realms().realm("test");
|
||||
ClientTemplateRepresentation rep = new ClientTemplateRepresentation();
|
||||
rep.setName("template");
|
||||
rep.setProtocol("oidc");
|
||||
Response response = realm.clientTemplates().create(rep);
|
||||
Assert.assertEquals(201, response.getStatus());
|
||||
URI templateUri = response.getLocation();
|
||||
response.close();
|
||||
ClientTemplateResource templateResource = keycloak.proxy(ClientTemplateResource.class, templateUri);
|
||||
ProtocolMapperModel hard = HardcodedClaim.create("hard", "hard", "coded", "String", false, null, true, true);
|
||||
ProtocolMapperRepresentation mapper = ModelToRepresentation.toRepresentation(hard);
|
||||
response = templateResource.getProtocolMappers().createMapper(mapper);
|
||||
Assert.assertEquals(201, response.getStatus());
|
||||
response.close();
|
||||
List<ClientRepresentation> clients = realm.clients().findAll();
|
||||
ClientRepresentation clientRep = null;
|
||||
for (ClientRepresentation c : clients) {
|
||||
if (c.getClientId().equals("test-app")) {
|
||||
clientRep = c;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
Assert.assertNotNull(clientRep);
|
||||
clientRep.setClientTemplate("template");
|
||||
realm.clients().get(clientRep.getId()).update(clientRep);
|
||||
|
||||
{
|
||||
Client client = ClientBuilder.newClient();
|
||||
UriBuilder builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
|
||||
URI grantUri = OIDCLoginProtocolService.tokenUrl(builder).build("test");
|
||||
WebTarget grantTarget = client.target(grantUri);
|
||||
|
||||
response = executeGrantAccessTokenRequest(grantTarget);
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
org.keycloak.representations.AccessTokenResponse tokenResponse = response.readEntity(org.keycloak.representations.AccessTokenResponse.class);
|
||||
IDToken idToken = getIdToken(tokenResponse);
|
||||
Assert.assertEquals("coded", idToken.getOtherClaims().get("hard"));
|
||||
|
||||
AccessToken accessToken = getAccessToken(tokenResponse);
|
||||
Assert.assertEquals("coded", accessToken.getOtherClaims().get("hard"));
|
||||
|
||||
|
||||
response.close();
|
||||
client.close();
|
||||
}
|
||||
// undo mappers
|
||||
clientRep.setClientTemplate(ClientTemplateRepresentation.NONE);
|
||||
realm.clients().get(clientRep.getId()).update(clientRep);
|
||||
|
||||
{
|
||||
Client client = ClientBuilder.newClient();
|
||||
UriBuilder builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
|
||||
URI grantUri = OIDCLoginProtocolService.tokenUrl(builder).build("test");
|
||||
WebTarget grantTarget = client.target(grantUri);
|
||||
|
||||
response = executeGrantAccessTokenRequest(grantTarget);
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
org.keycloak.representations.AccessTokenResponse tokenResponse = response.readEntity(org.keycloak.representations.AccessTokenResponse.class);
|
||||
IDToken idToken = getIdToken(tokenResponse);
|
||||
Assert.assertNull(idToken.getOtherClaims().get("hard"));
|
||||
|
||||
AccessToken accessToken = getAccessToken(tokenResponse);
|
||||
Assert.assertNull(accessToken.getOtherClaims().get("hard"));
|
||||
|
||||
|
||||
response.close();
|
||||
client.close();
|
||||
}
|
||||
events.clear();
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue