KEYCLOAK-8377 Role Attributes
This commit is contained in:
parent
460cdf4508
commit
9ef4c7fffd
33 changed files with 641 additions and 45 deletions
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
package org.keycloak.representations.idm;
|
package org.keycloak.representations.idm;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -35,6 +37,7 @@ public class RoleRepresentation {
|
||||||
protected Composites composites;
|
protected Composites composites;
|
||||||
private Boolean clientRole;
|
private Boolean clientRole;
|
||||||
private String containerId;
|
private String containerId;
|
||||||
|
protected Map<String, List<String>> attributes;
|
||||||
|
|
||||||
public static class Composites {
|
public static class Composites {
|
||||||
protected Set<String> realm;
|
protected Set<String> realm;
|
||||||
|
@ -138,4 +141,21 @@ public class RoleRepresentation {
|
||||||
public void setContainerId(String containerId) {
|
public void setContainerId(String containerId) {
|
||||||
this.containerId = containerId;
|
this.containerId = containerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, List<String>> getAttributes() {
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAttributes(Map<String, List<String>> attributes) {
|
||||||
|
this.attributes = attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RoleRepresentation singleAttribute(String name, String value) {
|
||||||
|
if (attributes == null) {
|
||||||
|
attributes = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
attributes.put(name, Arrays.asList(value));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,13 @@ import org.keycloak.models.cache.infinispan.entities.CachedRealmRole;
|
||||||
import org.keycloak.models.cache.infinispan.entities.CachedRole;
|
import org.keycloak.models.cache.infinispan.entities.CachedRole;
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
@ -39,22 +44,25 @@ public class RoleAdapter implements RoleModel {
|
||||||
protected RealmCacheSession cacheSession;
|
protected RealmCacheSession cacheSession;
|
||||||
protected RealmModel realm;
|
protected RealmModel realm;
|
||||||
protected Set<RoleModel> composites;
|
protected Set<RoleModel> composites;
|
||||||
|
private final Supplier<RoleModel> modelSupplier;
|
||||||
|
|
||||||
public RoleAdapter(CachedRole cached, RealmCacheSession session, RealmModel realm) {
|
public RoleAdapter(CachedRole cached, RealmCacheSession session, RealmModel realm) {
|
||||||
this.cached = cached;
|
this.cached = cached;
|
||||||
this.cacheSession = session;
|
this.cacheSession = session;
|
||||||
this.realm = realm;
|
this.realm = realm;
|
||||||
|
this.modelSupplier = this::getRoleModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void getDelegateForUpdate() {
|
protected void getDelegateForUpdate() {
|
||||||
if (updated == null) {
|
if (updated == null) {
|
||||||
cacheSession.registerRoleInvalidation(cached.getId(), cached.getName(), getContainerId());
|
cacheSession.registerRoleInvalidation(cached.getId(), cached.getName(), getContainerId());
|
||||||
updated = cacheSession.getRealmDelegate().getRoleById(cached.getId(), realm);
|
updated = modelSupplier.get();
|
||||||
if (updated == null) throw new IllegalStateException("Not found in database");
|
if (updated == null) throw new IllegalStateException("Not found in database");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean invalidated;
|
protected boolean invalidated;
|
||||||
|
|
||||||
public void invalidate() {
|
public void invalidate() {
|
||||||
invalidated = true;
|
invalidated = true;
|
||||||
}
|
}
|
||||||
|
@ -68,8 +76,6 @@ public class RoleAdapter implements RoleModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
if (isUpdated()) return updated.getName();
|
if (isUpdated()) return updated.getName();
|
||||||
|
@ -144,7 +150,7 @@ public class RoleAdapter implements RoleModel {
|
||||||
@Override
|
@Override
|
||||||
public String getContainerId() {
|
public String getContainerId() {
|
||||||
if (isClientRole()) {
|
if (isClientRole()) {
|
||||||
CachedClientRole appRole = (CachedClientRole)cached;
|
CachedClientRole appRole = (CachedClientRole) cached;
|
||||||
return appRole.getClientId();
|
return appRole.getClientId();
|
||||||
} else {
|
} else {
|
||||||
return realm.getId();
|
return realm.getId();
|
||||||
|
@ -157,7 +163,7 @@ public class RoleAdapter implements RoleModel {
|
||||||
if (cached instanceof CachedRealmRole) {
|
if (cached instanceof CachedRealmRole) {
|
||||||
return realm;
|
return realm;
|
||||||
} else {
|
} else {
|
||||||
CachedClientRole appRole = (CachedClientRole)cached;
|
CachedClientRole appRole = (CachedClientRole) cached;
|
||||||
return realm.getClientById(appRole.getClientId());
|
return realm.getClientById(appRole.getClientId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -167,6 +173,59 @@ public class RoleAdapter implements RoleModel {
|
||||||
return this.equals(role) || KeycloakModelUtils.searchFor(role, this, new HashSet<>());
|
return this.equals(role) || KeycloakModelUtils.searchFor(role, this, new HashSet<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSingleAttribute(String name, String value) {
|
||||||
|
getDelegateForUpdate();
|
||||||
|
updated.setSingleAttribute(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAttribute(String name, Collection<String> values) {
|
||||||
|
getDelegateForUpdate();
|
||||||
|
updated.setAttribute(name, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeAttribute(String name) {
|
||||||
|
getDelegateForUpdate();
|
||||||
|
updated.removeAttribute(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFirstAttribute(String name) {
|
||||||
|
if (updated != null) {
|
||||||
|
return updated.getFirstAttribute(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cached.getAttributes(modelSupplier).getFirst(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getAttribute(String name) {
|
||||||
|
if (updated != null) {
|
||||||
|
return updated.getAttribute(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> result = cached.getAttributes(modelSupplier).get(name);
|
||||||
|
if (result == null) {
|
||||||
|
result = Collections.emptyList();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, List<String>> getAttributes() {
|
||||||
|
if (updated != null) {
|
||||||
|
return updated.getAttributes();
|
||||||
|
}
|
||||||
|
|
||||||
|
return cached.getAttributes(modelSupplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RoleModel getRoleModel() {
|
||||||
|
return cacheSession.getRealmDelegate().getRoleById(cached.getId(), realm);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
|
|
|
@ -17,11 +17,15 @@
|
||||||
|
|
||||||
package org.keycloak.models.cache.infinispan.entities;
|
package org.keycloak.models.cache.infinispan.entities;
|
||||||
|
|
||||||
|
import org.keycloak.common.util.MultivaluedHashMap;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
|
import org.keycloak.models.cache.infinispan.DefaultLazyLoader;
|
||||||
|
import org.keycloak.models.cache.infinispan.LazyLoader;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
@ -34,6 +38,7 @@ public class CachedRole extends AbstractRevisioned implements InRealm {
|
||||||
final protected String description;
|
final protected String description;
|
||||||
final protected boolean composite;
|
final protected boolean composite;
|
||||||
final protected Set<String> composites = new HashSet<String>();
|
final protected Set<String> composites = new HashSet<String>();
|
||||||
|
private final LazyLoader<RoleModel, MultivaluedHashMap<String, String>> attributes;
|
||||||
|
|
||||||
public CachedRole(Long revision, RoleModel model, RealmModel realm) {
|
public CachedRole(Long revision, RoleModel model, RealmModel realm) {
|
||||||
super(revision, model.getId());
|
super(revision, model.getId());
|
||||||
|
@ -46,7 +51,7 @@ public class CachedRole extends AbstractRevisioned implements InRealm {
|
||||||
composites.add(child.getId());
|
composites.add(child.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
attributes = new DefaultLazyLoader<>(roleModel -> new MultivaluedHashMap<>(roleModel.getAttributes()), MultivaluedHashMap::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
@ -68,4 +73,8 @@ public class CachedRole extends AbstractRevisioned implements InRealm {
|
||||||
public Set<String> getComposites() {
|
public Set<String> getComposites() {
|
||||||
return composites;
|
return composites;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MultivaluedHashMap<String, String> getAttributes(Supplier<RoleModel> roleModel) {
|
||||||
|
return attributes.get(roleModel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,11 +21,19 @@ import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleContainerModel;
|
import org.keycloak.models.RoleContainerModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
|
import org.keycloak.models.jpa.entities.RoleAttributeEntity;
|
||||||
import org.keycloak.models.jpa.entities.RoleEntity;
|
import org.keycloak.models.jpa.entities.RoleEntity;
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
|
import javax.persistence.Query;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -116,6 +124,77 @@ public class RoleAdapter implements RoleModel, JpaModel<RoleEntity> {
|
||||||
return this.equals(role) || KeycloakModelUtils.searchFor(role, this, new HashSet<>());
|
return this.equals(role) || KeycloakModelUtils.searchFor(role, this, new HashSet<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void persistAttributeValue(String name, String value) {
|
||||||
|
RoleAttributeEntity attr = new RoleAttributeEntity();
|
||||||
|
attr.setId(KeycloakModelUtils.generateId());
|
||||||
|
attr.setName(name);
|
||||||
|
attr.setValue(value);
|
||||||
|
attr.setRole(role);
|
||||||
|
em.persist(attr);
|
||||||
|
role.getAttributes().add(attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSingleAttribute(String name, String value) {
|
||||||
|
setAttribute(name, Collections.singletonList(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAttribute(String name, Collection<String> values) {
|
||||||
|
removeAttribute(name);
|
||||||
|
|
||||||
|
for (String value : values) {
|
||||||
|
persistAttributeValue(name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeAttribute(String name) {
|
||||||
|
Collection<RoleAttributeEntity> attributes = role.getAttributes();
|
||||||
|
if (attributes == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Query query = em.createNamedQuery("deleteRoleAttributesByNameAndUser");
|
||||||
|
query.setParameter("name", name);
|
||||||
|
query.setParameter("roleId", role.getId());
|
||||||
|
query.executeUpdate();
|
||||||
|
|
||||||
|
attributes.removeIf(attribute -> attribute.getName().equals(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFirstAttribute(String name) {
|
||||||
|
for (RoleAttributeEntity attribute : role.getAttributes()) {
|
||||||
|
if (attribute.getName().equals(name)) {
|
||||||
|
return attribute.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getAttribute(String name) {
|
||||||
|
List<String> attributes = new ArrayList<>();
|
||||||
|
for (RoleAttributeEntity attribute : role.getAttributes()) {
|
||||||
|
if (attribute.getName().equals(name)) {
|
||||||
|
attributes.add(attribute.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, List<String>> getAttributes() {
|
||||||
|
Map<String, List<String>> map = new HashMap<>();
|
||||||
|
for (RoleAttributeEntity attribute : role.getAttributes()) {
|
||||||
|
map.computeIfAbsent(attribute.getName(), name -> new ArrayList<>()).add(attribute.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isClientRole() {
|
public boolean isClientRole() {
|
||||||
return role.isClientRole();
|
return role.isClientRole();
|
||||||
|
@ -154,7 +233,7 @@ public class RoleAdapter implements RoleModel, JpaModel<RoleEntity> {
|
||||||
|
|
||||||
public static RoleEntity toRoleEntity(RoleModel model, EntityManager em) {
|
public static RoleEntity toRoleEntity(RoleModel model, EntityManager em) {
|
||||||
if (model instanceof RoleAdapter) {
|
if (model instanceof RoleAdapter) {
|
||||||
return ((RoleAdapter)model).getEntity();
|
return ((RoleAdapter) model).getEntity();
|
||||||
}
|
}
|
||||||
return em.getReference(RoleEntity.class, model.getId());
|
return em.getReference(RoleEntity.class, model.getId());
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2018 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.models.jpa.entities;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.Nationalized;
|
||||||
|
|
||||||
|
import javax.persistence.Access;
|
||||||
|
import javax.persistence.AccessType;
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.FetchType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.NamedQueries;
|
||||||
|
import javax.persistence.NamedQuery;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:leon.graser@bosch-si.com">Leon Graser</a>
|
||||||
|
*/
|
||||||
|
@NamedQueries({
|
||||||
|
@NamedQuery(name = "deleteRoleAttributesByNameAndUser", query = "delete from RoleAttributeEntity attr where attr.role.id = :roleId and attr.name = :name"),
|
||||||
|
})
|
||||||
|
@Table(name = "ROLE_ATTRIBUTE")
|
||||||
|
@Entity
|
||||||
|
public class RoleAttributeEntity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@Column(name = "ID", length = 36)
|
||||||
|
@Access(AccessType.PROPERTY)
|
||||||
|
protected String id;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@JoinColumn(name = "ROLE_ID")
|
||||||
|
protected RoleEntity role;
|
||||||
|
|
||||||
|
@Column(name = "NAME")
|
||||||
|
protected String name;
|
||||||
|
|
||||||
|
@Nationalized
|
||||||
|
@Column(name = "VALUE")
|
||||||
|
protected String value;
|
||||||
|
|
||||||
|
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 getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RoleEntity getRole() {
|
||||||
|
return role;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRole(RoleEntity role) {
|
||||||
|
this.role = role;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
boolean result = false;
|
||||||
|
|
||||||
|
if (o instanceof RoleAttributeEntity) {
|
||||||
|
RoleAttributeEntity otherRole = (RoleAttributeEntity) o;
|
||||||
|
result = id.equals(otherRole.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return id.hashCode();
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,10 +17,14 @@
|
||||||
|
|
||||||
package org.keycloak.models.jpa.entities;
|
package org.keycloak.models.jpa.entities;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.BatchSize;
|
||||||
|
import org.hibernate.annotations.Fetch;
|
||||||
|
import org.hibernate.annotations.FetchMode;
|
||||||
import org.hibernate.annotations.Nationalized;
|
import org.hibernate.annotations.Nationalized;
|
||||||
|
|
||||||
import javax.persistence.Access;
|
import javax.persistence.Access;
|
||||||
import javax.persistence.AccessType;
|
import javax.persistence.AccessType;
|
||||||
|
import javax.persistence.CascadeType;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
import javax.persistence.FetchType;
|
import javax.persistence.FetchType;
|
||||||
|
@ -31,9 +35,13 @@ import javax.persistence.ManyToMany;
|
||||||
import javax.persistence.ManyToOne;
|
import javax.persistence.ManyToOne;
|
||||||
import javax.persistence.NamedQueries;
|
import javax.persistence.NamedQueries;
|
||||||
import javax.persistence.NamedQuery;
|
import javax.persistence.NamedQuery;
|
||||||
|
import javax.persistence.OneToMany;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
import javax.persistence.UniqueConstraint;
|
import javax.persistence.UniqueConstraint;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -93,6 +101,11 @@ public class RoleEntity {
|
||||||
@JoinTable(name = "COMPOSITE_ROLE", joinColumns = @JoinColumn(name = "COMPOSITE"), inverseJoinColumns = @JoinColumn(name = "CHILD_ROLE"))
|
@JoinTable(name = "COMPOSITE_ROLE", joinColumns = @JoinColumn(name = "COMPOSITE"), inverseJoinColumns = @JoinColumn(name = "CHILD_ROLE"))
|
||||||
private Set<RoleEntity> compositeRoles = new HashSet<>();
|
private Set<RoleEntity> compositeRoles = new HashSet<>();
|
||||||
|
|
||||||
|
@OneToMany(cascade = CascadeType.REMOVE, orphanRemoval = true, mappedBy="role")
|
||||||
|
@Fetch(FetchMode.SELECT)
|
||||||
|
@BatchSize(size = 20)
|
||||||
|
protected List<RoleAttributeEntity> attributes = new ArrayList<>();
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
@ -109,7 +122,13 @@ public class RoleEntity {
|
||||||
this.realmId = realmId;
|
this.realmId = realmId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Collection<RoleAttributeEntity> getAttributes() {
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAttributes(List<RoleAttributeEntity> attributes) {
|
||||||
|
this.attributes = attributes;
|
||||||
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
|
|
|
@ -23,11 +23,31 @@
|
||||||
<where>NAME LIKE 'group.resource.%'</where>
|
<where>NAME LIKE 'group.resource.%'</where>
|
||||||
</update>
|
</update>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
|
|
||||||
|
<changeSet author="keycloak" id="4.6.0-KEYCLOAK-8377">
|
||||||
|
<createTable tableName="ROLE_ATTRIBUTE">
|
||||||
|
<column name="ID" type="VARCHAR(36)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="ROLE_ID" type="VARCHAR(36)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="NAME" type="VARCHAR(255)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="VALUE" type="NVARCHAR(255)"/>
|
||||||
|
</createTable>
|
||||||
|
<addPrimaryKey columnNames="ID" constraintName="CONSTRAINT_ROLE_ATTRIBUTE_PK" tableName="ROLE_ATTRIBUTE"/>
|
||||||
|
<addForeignKeyConstraint baseColumnNames="ROLE_ID" baseTableName="ROLE_ATTRIBUTE" constraintName="FK_ROLE_ATTRIBUTE_ID" referencedColumnNames="ID" referencedTableName="KEYCLOAK_ROLE"/>
|
||||||
|
<createIndex indexName="IDX_ROLE_ATTRIBUTE" tableName="ROLE_ATTRIBUTE">
|
||||||
|
<column name="ROLE_ID" type="VARCHAR(36)"/>
|
||||||
|
</createIndex>
|
||||||
|
</changeSet>
|
||||||
|
|
||||||
<changeSet author="gideonray@gmail.com" id="4.6.0-KEYCLOAK-8555">
|
<changeSet author="gideonray@gmail.com" id="4.6.0-KEYCLOAK-8555">
|
||||||
<createIndex tableName="COMPONENT" indexName="IDX_COMPONENT_PROVIDER_TYPE">
|
<createIndex tableName="COMPONENT" indexName="IDX_COMPONENT_PROVIDER_TYPE">
|
||||||
<column name="PROVIDER_TYPE" type="VARCHAR(255)"/>
|
<column name="PROVIDER_TYPE" type="VARCHAR(255)"/>
|
||||||
</createIndex>
|
</createIndex>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
|
|
||||||
</databaseChangeLog>
|
</databaseChangeLog>
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
<class>org.keycloak.models.jpa.entities.UserFederationProviderEntity</class>
|
<class>org.keycloak.models.jpa.entities.UserFederationProviderEntity</class>
|
||||||
<class>org.keycloak.models.jpa.entities.UserFederationMapperEntity</class>
|
<class>org.keycloak.models.jpa.entities.UserFederationMapperEntity</class>
|
||||||
<class>org.keycloak.models.jpa.entities.RoleEntity</class>
|
<class>org.keycloak.models.jpa.entities.RoleEntity</class>
|
||||||
|
<class>org.keycloak.models.jpa.entities.RoleAttributeEntity</class>
|
||||||
<class>org.keycloak.models.jpa.entities.FederatedIdentityEntity</class>
|
<class>org.keycloak.models.jpa.entities.FederatedIdentityEntity</class>
|
||||||
<class>org.keycloak.models.jpa.entities.MigrationModelEntity</class>
|
<class>org.keycloak.models.jpa.entities.MigrationModelEntity</class>
|
||||||
<class>org.keycloak.models.jpa.entities.UserEntity</class>
|
<class>org.keycloak.models.jpa.entities.UserEntity</class>
|
||||||
|
|
|
@ -223,6 +223,18 @@ public class ModelToRepresentation {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RoleRepresentation toRepresentation(RoleModel role) {
|
public static RoleRepresentation toRepresentation(RoleModel role) {
|
||||||
|
RoleRepresentation rep = new RoleRepresentation();
|
||||||
|
rep.setId(role.getId());
|
||||||
|
rep.setName(role.getName());
|
||||||
|
rep.setDescription(role.getDescription());
|
||||||
|
rep.setComposite(role.isComposite());
|
||||||
|
rep.setClientRole(role.isClientRole());
|
||||||
|
rep.setContainerId(role.getContainerId());
|
||||||
|
rep.setAttributes(role.getAttributes());
|
||||||
|
return rep;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RoleRepresentation toBriefRepresentation(RoleModel role) {
|
||||||
RoleRepresentation rep = new RoleRepresentation();
|
RoleRepresentation rep = new RoleRepresentation();
|
||||||
rep.setId(role.getId());
|
rep.setId(role.getId());
|
||||||
rep.setName(role.getName());
|
rep.setName(role.getName());
|
||||||
|
|
|
@ -1033,6 +1033,11 @@ public class RepresentationToModel {
|
||||||
public static void createRole(RealmModel newRealm, RoleRepresentation roleRep) {
|
public static void createRole(RealmModel newRealm, RoleRepresentation roleRep) {
|
||||||
RoleModel role = roleRep.getId() != null ? newRealm.addRole(roleRep.getId(), roleRep.getName()) : newRealm.addRole(roleRep.getName());
|
RoleModel role = roleRep.getId() != null ? newRealm.addRole(roleRep.getId(), roleRep.getName()) : newRealm.addRole(roleRep.getName());
|
||||||
if (roleRep.getDescription() != null) role.setDescription(roleRep.getDescription());
|
if (roleRep.getDescription() != null) role.setDescription(roleRep.getDescription());
|
||||||
|
if (roleRep.getAttributes() != null) {
|
||||||
|
for (Map.Entry<String, List<String>> attribute : roleRep.getAttributes().entrySet()) {
|
||||||
|
role.setAttribute(attribute.getKey(), attribute.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addComposites(RoleModel role, RoleRepresentation roleRep, RealmModel realm) {
|
private static void addComposites(RoleModel role, RoleRepresentation roleRep, RealmModel realm) {
|
||||||
|
|
|
@ -17,6 +17,9 @@
|
||||||
|
|
||||||
package org.keycloak.models;
|
package org.keycloak.models;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -50,4 +53,15 @@ public interface RoleModel {
|
||||||
|
|
||||||
boolean hasRole(RoleModel role);
|
boolean hasRole(RoleModel role);
|
||||||
|
|
||||||
|
void setSingleAttribute(String name, String value);
|
||||||
|
|
||||||
|
void setAttribute(String name, Collection<String> values);
|
||||||
|
|
||||||
|
void removeAttribute(String name);
|
||||||
|
|
||||||
|
String getFirstAttribute(String name);
|
||||||
|
|
||||||
|
List<String> getAttribute(String name);
|
||||||
|
|
||||||
|
Map<String, List<String>> getAttributes();
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,10 +41,8 @@ import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.PathParam;
|
import javax.ws.rs.PathParam;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.QueryParam;
|
import javax.ws.rs.QueryParam;
|
||||||
import javax.ws.rs.core.Context;
|
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.Response.Status;
|
import javax.ws.rs.core.Response.Status;
|
||||||
import javax.ws.rs.core.UriInfo;
|
|
||||||
|
|
||||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||||
import org.keycloak.OAuthErrorException;
|
import org.keycloak.OAuthErrorException;
|
||||||
|
|
|
@ -45,11 +45,9 @@ import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.PathParam;
|
import javax.ws.rs.PathParam;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.QueryParam;
|
import javax.ws.rs.QueryParam;
|
||||||
import javax.ws.rs.core.Context;
|
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.Response.Status;
|
import javax.ws.rs.core.Response.Status;
|
||||||
import javax.ws.rs.core.UriInfo;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
|
@ -31,7 +31,6 @@ import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.utils.ModelToRepresentation;
|
import org.keycloak.models.utils.ModelToRepresentation;
|
||||||
import org.keycloak.representations.idm.RoleRepresentation;
|
import org.keycloak.representations.idm.RoleRepresentation;
|
||||||
import org.keycloak.services.ErrorResponseException;
|
import org.keycloak.services.ErrorResponseException;
|
||||||
import org.keycloak.services.ForbiddenException;
|
|
||||||
|
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
import javax.ws.rs.DELETE;
|
import javax.ws.rs.DELETE;
|
||||||
|
@ -98,7 +97,7 @@ public class ClientRoleMappingsResource {
|
||||||
Set<RoleModel> mappings = user.getClientRoleMappings(client);
|
Set<RoleModel> mappings = user.getClientRoleMappings(client);
|
||||||
List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
|
List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
|
||||||
for (RoleModel roleModel : mappings) {
|
for (RoleModel roleModel : mappings) {
|
||||||
mapRep.add(ModelToRepresentation.toRepresentation(roleModel));
|
mapRep.add(ModelToRepresentation.toBriefRepresentation(roleModel));
|
||||||
}
|
}
|
||||||
return mapRep;
|
return mapRep;
|
||||||
}
|
}
|
||||||
|
@ -121,7 +120,7 @@ public class ClientRoleMappingsResource {
|
||||||
Set<RoleModel> roles = client.getRoles();
|
Set<RoleModel> roles = client.getRoles();
|
||||||
List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
|
List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
|
||||||
for (RoleModel roleModel : roles) {
|
for (RoleModel roleModel : roles) {
|
||||||
if (user.hasRole(roleModel)) mapRep.add(ModelToRepresentation.toRepresentation(roleModel));
|
if (user.hasRole(roleModel)) mapRep.add(ModelToRepresentation.toBriefRepresentation(roleModel));
|
||||||
}
|
}
|
||||||
return mapRep;
|
return mapRep;
|
||||||
}
|
}
|
||||||
|
@ -154,7 +153,7 @@ public class ClientRoleMappingsResource {
|
||||||
|
|
||||||
List<RoleRepresentation> mappings = new ArrayList<RoleRepresentation>();
|
List<RoleRepresentation> mappings = new ArrayList<RoleRepresentation>();
|
||||||
for (RoleModel roleModel : roles) {
|
for (RoleModel roleModel : roles) {
|
||||||
mappings.add(ModelToRepresentation.toRepresentation(roleModel));
|
mappings.add(ModelToRepresentation.toBriefRepresentation(roleModel));
|
||||||
}
|
}
|
||||||
return mappings;
|
return mappings;
|
||||||
}
|
}
|
||||||
|
@ -202,7 +201,7 @@ public class ClientRoleMappingsResource {
|
||||||
}
|
}
|
||||||
auth.roles().requireMapRole(roleModel);
|
auth.roles().requireMapRole(roleModel);
|
||||||
user.deleteRoleMapping(roleModel);
|
user.deleteRoleMapping(roleModel);
|
||||||
roles.add(ModelToRepresentation.toRepresentation(roleModel));
|
roles.add(ModelToRepresentation.toBriefRepresentation(roleModel));
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -76,7 +76,7 @@ public class ClientScopeEvaluateScopeMappingsResource {
|
||||||
public List<RoleRepresentation> getGrantedScopeMappings() {
|
public List<RoleRepresentation> getGrantedScopeMappings() {
|
||||||
return getGrantedRoles().stream().map((RoleModel role) -> {
|
return getGrantedRoles().stream().map((RoleModel role) -> {
|
||||||
|
|
||||||
return ModelToRepresentation.toRepresentation(role);
|
return ModelToRepresentation.toBriefRepresentation(role);
|
||||||
|
|
||||||
}).collect(Collectors.toList());
|
}).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,7 @@ public class ClientScopeEvaluateScopeMappingsResource {
|
||||||
|
|
||||||
}).map((RoleModel role) -> {
|
}).map((RoleModel role) -> {
|
||||||
|
|
||||||
return ModelToRepresentation.toRepresentation(role);
|
return ModelToRepresentation.toBriefRepresentation(role);
|
||||||
|
|
||||||
}).collect(Collectors.toList());
|
}).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,7 +94,7 @@ public class RoleContainerResource extends RoleResource {
|
||||||
Set<RoleModel> roleModels = roleContainer.getRoles();
|
Set<RoleModel> roleModels = roleContainer.getRoles();
|
||||||
List<RoleRepresentation> roles = new ArrayList<RoleRepresentation>();
|
List<RoleRepresentation> roles = new ArrayList<RoleRepresentation>();
|
||||||
for (RoleModel roleModel : roleModels) {
|
for (RoleModel roleModel : roleModels) {
|
||||||
roles.add(ModelToRepresentation.toRepresentation(roleModel));
|
roles.add(ModelToRepresentation.toBriefRepresentation(roleModel));
|
||||||
}
|
}
|
||||||
return roles;
|
return roles;
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,7 +119,7 @@ public class RoleMapperResource {
|
||||||
if (realmMappings.size() > 0) {
|
if (realmMappings.size() > 0) {
|
||||||
List<RoleRepresentation> realmRep = new ArrayList<RoleRepresentation>();
|
List<RoleRepresentation> realmRep = new ArrayList<RoleRepresentation>();
|
||||||
for (RoleModel roleModel : realmMappings) {
|
for (RoleModel roleModel : realmMappings) {
|
||||||
realmRep.add(ModelToRepresentation.toRepresentation(roleModel));
|
realmRep.add(ModelToRepresentation.toBriefRepresentation(roleModel));
|
||||||
}
|
}
|
||||||
all.setRealmMappings(realmRep);
|
all.setRealmMappings(realmRep);
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,7 @@ public class RoleMapperResource {
|
||||||
List<RoleRepresentation> roles = new ArrayList<RoleRepresentation>();
|
List<RoleRepresentation> roles = new ArrayList<RoleRepresentation>();
|
||||||
mappings.setMappings(roles);
|
mappings.setMappings(roles);
|
||||||
for (RoleModel role : roleMappings) {
|
for (RoleModel role : roleMappings) {
|
||||||
roles.add(ModelToRepresentation.toRepresentation(role));
|
roles.add(ModelToRepresentation.toBriefRepresentation(role));
|
||||||
}
|
}
|
||||||
appMappings.put(client.getClientId(), mappings);
|
appMappings.put(client.getClientId(), mappings);
|
||||||
all.setClientMappings(appMappings);
|
all.setClientMappings(appMappings);
|
||||||
|
@ -161,7 +161,7 @@ public class RoleMapperResource {
|
||||||
Set<RoleModel> realmMappings = roleMapper.getRealmRoleMappings();
|
Set<RoleModel> realmMappings = roleMapper.getRealmRoleMappings();
|
||||||
List<RoleRepresentation> realmMappingsRep = new ArrayList<RoleRepresentation>();
|
List<RoleRepresentation> realmMappingsRep = new ArrayList<RoleRepresentation>();
|
||||||
for (RoleModel roleModel : realmMappings) {
|
for (RoleModel roleModel : realmMappings) {
|
||||||
realmMappingsRep.add(ModelToRepresentation.toRepresentation(roleModel));
|
realmMappingsRep.add(ModelToRepresentation.toBriefRepresentation(roleModel));
|
||||||
}
|
}
|
||||||
return realmMappingsRep;
|
return realmMappingsRep;
|
||||||
}
|
}
|
||||||
|
@ -184,7 +184,7 @@ public class RoleMapperResource {
|
||||||
List<RoleRepresentation> realmMappingsRep = new ArrayList<RoleRepresentation>();
|
List<RoleRepresentation> realmMappingsRep = new ArrayList<RoleRepresentation>();
|
||||||
for (RoleModel roleModel : roles) {
|
for (RoleModel roleModel : roles) {
|
||||||
if (roleMapper.hasRole(roleModel)) {
|
if (roleMapper.hasRole(roleModel)) {
|
||||||
realmMappingsRep.add(ModelToRepresentation.toRepresentation(roleModel));
|
realmMappingsRep.add(ModelToRepresentation.toBriefRepresentation(roleModel));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return realmMappingsRep;
|
return realmMappingsRep;
|
||||||
|
@ -253,7 +253,7 @@ public class RoleMapperResource {
|
||||||
for (RoleModel roleModel : roleModels) {
|
for (RoleModel roleModel : roleModels) {
|
||||||
auth.roles().requireMapRole(roleModel);
|
auth.roles().requireMapRole(roleModel);
|
||||||
roleMapper.deleteRoleMapping(roleModel);
|
roleMapper.deleteRoleMapping(roleModel);
|
||||||
roles.add(ModelToRepresentation.toRepresentation(roleModel));
|
roles.add(ModelToRepresentation.toBriefRepresentation(roleModel));
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -31,6 +31,7 @@ import javax.ws.rs.core.UriInfo;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -58,6 +59,19 @@ public abstract class RoleResource {
|
||||||
protected void updateRole(RoleRepresentation rep, RoleModel role) {
|
protected void updateRole(RoleRepresentation rep, RoleModel role) {
|
||||||
role.setName(rep.getName());
|
role.setName(rep.getName());
|
||||||
role.setDescription(rep.getDescription());
|
role.setDescription(rep.getDescription());
|
||||||
|
|
||||||
|
if (rep.getAttributes() != null) {
|
||||||
|
Set<String> attrsToRemove = new HashSet<>(role.getAttributes().keySet());
|
||||||
|
attrsToRemove.removeAll(rep.getAttributes().keySet());
|
||||||
|
|
||||||
|
for (Map.Entry<String, List<String>> attr : rep.getAttributes().entrySet()) {
|
||||||
|
role.setAttribute(attr.getKey(), attr.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String attr : attrsToRemove) {
|
||||||
|
role.removeAttribute(attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void addComposites(AdminPermissionEvaluator auth, AdminEventBuilder adminEvent, UriInfo uriInfo, List<RoleRepresentation> roles, RoleModel role) {
|
protected void addComposites(AdminPermissionEvaluator auth, AdminEventBuilder adminEvent, UriInfo uriInfo, List<RoleRepresentation> roles, RoleModel role) {
|
||||||
|
@ -84,7 +98,7 @@ public abstract class RoleResource {
|
||||||
|
|
||||||
Set<RoleRepresentation> composites = new HashSet<RoleRepresentation>(role.getComposites().size());
|
Set<RoleRepresentation> composites = new HashSet<RoleRepresentation>(role.getComposites().size());
|
||||||
for (RoleModel composite : role.getComposites()) {
|
for (RoleModel composite : role.getComposites()) {
|
||||||
composites.add(ModelToRepresentation.toRepresentation(composite));
|
composites.add(ModelToRepresentation.toBriefRepresentation(composite));
|
||||||
}
|
}
|
||||||
return composites;
|
return composites;
|
||||||
}
|
}
|
||||||
|
@ -95,7 +109,7 @@ public abstract class RoleResource {
|
||||||
Set<RoleRepresentation> composites = new HashSet<RoleRepresentation>(role.getComposites().size());
|
Set<RoleRepresentation> composites = new HashSet<RoleRepresentation>(role.getComposites().size());
|
||||||
for (RoleModel composite : role.getComposites()) {
|
for (RoleModel composite : role.getComposites()) {
|
||||||
if (composite.getContainer() instanceof RealmModel)
|
if (composite.getContainer() instanceof RealmModel)
|
||||||
composites.add(ModelToRepresentation.toRepresentation(composite));
|
composites.add(ModelToRepresentation.toBriefRepresentation(composite));
|
||||||
}
|
}
|
||||||
return composites;
|
return composites;
|
||||||
}
|
}
|
||||||
|
@ -106,7 +120,7 @@ public abstract class RoleResource {
|
||||||
Set<RoleRepresentation> composites = new HashSet<RoleRepresentation>(role.getComposites().size());
|
Set<RoleRepresentation> composites = new HashSet<RoleRepresentation>(role.getComposites().size());
|
||||||
for (RoleModel composite : role.getComposites()) {
|
for (RoleModel composite : role.getComposites()) {
|
||||||
if (composite.getContainer().equals(app))
|
if (composite.getContainer().equals(app))
|
||||||
composites.add(ModelToRepresentation.toRepresentation(composite));
|
composites.add(ModelToRepresentation.toBriefRepresentation(composite));
|
||||||
}
|
}
|
||||||
return composites;
|
return composites;
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,7 +87,7 @@ public class ScopeMappedClientResource {
|
||||||
Set<RoleModel> mappings = KeycloakModelUtils.getClientScopeMappings(scopedClient, scopeContainer); //scopedClient.getClientScopeMappings(client);
|
Set<RoleModel> mappings = KeycloakModelUtils.getClientScopeMappings(scopedClient, scopeContainer); //scopedClient.getClientScopeMappings(client);
|
||||||
List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
|
List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
|
||||||
for (RoleModel roleModel : mappings) {
|
for (RoleModel roleModel : mappings) {
|
||||||
mapRep.add(ModelToRepresentation.toRepresentation(roleModel));
|
mapRep.add(ModelToRepresentation.toBriefRepresentation(roleModel));
|
||||||
}
|
}
|
||||||
return mapRep;
|
return mapRep;
|
||||||
}
|
}
|
||||||
|
@ -165,7 +165,7 @@ public class ScopeMappedClientResource {
|
||||||
|
|
||||||
for (RoleModel roleModel : roleModels) {
|
for (RoleModel roleModel : roleModels) {
|
||||||
scopeContainer.deleteScopeMapping(roleModel);
|
scopeContainer.deleteScopeMapping(roleModel);
|
||||||
roles.add(ModelToRepresentation.toRepresentation(roleModel));
|
roles.add(ModelToRepresentation.toBriefRepresentation(roleModel));
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -98,7 +98,7 @@ public class ScopeMappedResource {
|
||||||
if (realmMappings.size() > 0) {
|
if (realmMappings.size() > 0) {
|
||||||
List<RoleRepresentation> realmRep = new ArrayList<RoleRepresentation>();
|
List<RoleRepresentation> realmRep = new ArrayList<RoleRepresentation>();
|
||||||
for (RoleModel roleModel : realmMappings) {
|
for (RoleModel roleModel : realmMappings) {
|
||||||
realmRep.add(ModelToRepresentation.toRepresentation(roleModel));
|
realmRep.add(ModelToRepresentation.toBriefRepresentation(roleModel));
|
||||||
}
|
}
|
||||||
all.setRealmMappings(realmRep);
|
all.setRealmMappings(realmRep);
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,7 @@ public class ScopeMappedResource {
|
||||||
List<RoleRepresentation> roles = new ArrayList<RoleRepresentation>();
|
List<RoleRepresentation> roles = new ArrayList<RoleRepresentation>();
|
||||||
mappings.setMappings(roles);
|
mappings.setMappings(roles);
|
||||||
for (RoleModel role : roleMappings) {
|
for (RoleModel role : roleMappings) {
|
||||||
roles.add(ModelToRepresentation.toRepresentation(role));
|
roles.add(ModelToRepresentation.toBriefRepresentation(role));
|
||||||
}
|
}
|
||||||
clientMappings.put(client.getClientId(), mappings);
|
clientMappings.put(client.getClientId(), mappings);
|
||||||
all.setClientMappings(clientMappings);
|
all.setClientMappings(clientMappings);
|
||||||
|
@ -144,7 +144,7 @@ public class ScopeMappedResource {
|
||||||
Set<RoleModel> realmMappings = scopeContainer.getRealmScopeMappings();
|
Set<RoleModel> realmMappings = scopeContainer.getRealmScopeMappings();
|
||||||
List<RoleRepresentation> realmMappingsRep = new ArrayList<RoleRepresentation>();
|
List<RoleRepresentation> realmMappingsRep = new ArrayList<RoleRepresentation>();
|
||||||
for (RoleModel roleModel : realmMappings) {
|
for (RoleModel roleModel : realmMappings) {
|
||||||
realmMappingsRep.add(ModelToRepresentation.toRepresentation(roleModel));
|
realmMappingsRep.add(ModelToRepresentation.toBriefRepresentation(roleModel));
|
||||||
}
|
}
|
||||||
return realmMappingsRep;
|
return realmMappingsRep;
|
||||||
}
|
}
|
||||||
|
@ -174,7 +174,7 @@ public class ScopeMappedResource {
|
||||||
for (RoleModel roleModel : roles) {
|
for (RoleModel roleModel : roles) {
|
||||||
if (client.hasScope(roleModel)) continue;
|
if (client.hasScope(roleModel)) continue;
|
||||||
if (!auth.roles().canMapClientScope(roleModel)) continue;
|
if (!auth.roles().canMapClientScope(roleModel)) continue;
|
||||||
available.add(ModelToRepresentation.toRepresentation(roleModel));
|
available.add(ModelToRepresentation.toBriefRepresentation(roleModel));
|
||||||
}
|
}
|
||||||
return available;
|
return available;
|
||||||
}
|
}
|
||||||
|
@ -206,7 +206,7 @@ public class ScopeMappedResource {
|
||||||
public static List<RoleRepresentation> getComposite(ScopeContainerModel client, Set<RoleModel> roles) {
|
public static List<RoleRepresentation> getComposite(ScopeContainerModel client, Set<RoleModel> roles) {
|
||||||
List<RoleRepresentation> composite = new ArrayList<RoleRepresentation>();
|
List<RoleRepresentation> composite = new ArrayList<RoleRepresentation>();
|
||||||
for (RoleModel roleModel : roles) {
|
for (RoleModel roleModel : roles) {
|
||||||
if (client.hasScope(roleModel)) composite.add(ModelToRepresentation.toRepresentation(roleModel));
|
if (client.hasScope(roleModel)) composite.add(ModelToRepresentation.toBriefRepresentation(roleModel));
|
||||||
}
|
}
|
||||||
return composite;
|
return composite;
|
||||||
}
|
}
|
||||||
|
@ -258,7 +258,7 @@ public class ScopeMappedResource {
|
||||||
|
|
||||||
for (RoleModel roleModel : roleModels) {
|
for (RoleModel roleModel : roleModels) {
|
||||||
scopeContainer.deleteScopeMapping(roleModel);
|
scopeContainer.deleteScopeMapping(roleModel);
|
||||||
roles.add(ModelToRepresentation.toRepresentation(roleModel));
|
roles.add(ModelToRepresentation.toBriefRepresentation(roleModel));
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.keycloak.testsuite.util.RoleBuilder;
|
||||||
|
|
||||||
import javax.ws.rs.NotFoundException;
|
import javax.ws.rs.NotFoundException;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -151,4 +152,43 @@ public class RoleByIdResourceTest extends AbstractAdminTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void attributes() {
|
||||||
|
for (String id : ids.values()) {
|
||||||
|
RoleRepresentation role = resource.getRole(id);
|
||||||
|
assertNotNull(role.getAttributes());
|
||||||
|
assertTrue(role.getAttributes().isEmpty());
|
||||||
|
|
||||||
|
// update the role with attributes
|
||||||
|
Map<String, List<String>> attributes = new HashMap<>();
|
||||||
|
List<String> attributeValues = new ArrayList<>();
|
||||||
|
attributeValues.add("value1");
|
||||||
|
attributes.put("key1", attributeValues);
|
||||||
|
attributeValues = new ArrayList<>();
|
||||||
|
attributeValues.add("value2.1");
|
||||||
|
attributeValues.add("value2.2");
|
||||||
|
attributes.put("key2", attributeValues);
|
||||||
|
role.setAttributes(attributes);
|
||||||
|
|
||||||
|
resource.updateRole(id, role);
|
||||||
|
role = resource.getRole(id);
|
||||||
|
assertNotNull(role);
|
||||||
|
Map<String, List<String>> roleAttributes = role.getAttributes();
|
||||||
|
assertNotNull(roleAttributes);
|
||||||
|
|
||||||
|
assertEquals(attributes, roleAttributes);
|
||||||
|
|
||||||
|
|
||||||
|
// delete an attribute
|
||||||
|
attributes.remove("key2");
|
||||||
|
role.setAttributes(attributes);
|
||||||
|
resource.updateRole(id, role);
|
||||||
|
role = resource.getRole(id);
|
||||||
|
assertNotNull(role);
|
||||||
|
roleAttributes = role.getAttributes();
|
||||||
|
assertNotNull(roleAttributes);
|
||||||
|
|
||||||
|
assertEquals(attributes, roleAttributes);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -388,8 +388,8 @@ public class UserStorageRestTest extends AbstractAdminTest {
|
||||||
String id2 = createUserFederationProvider(dummyRep2);
|
String id2 = createUserFederationProvider(dummyRep2);
|
||||||
|
|
||||||
// Assert provider instances available
|
// Assert provider instances available
|
||||||
assertFederationProvider(userFederation().get(id1).toRepresentation(), id1, id1, "dummy", 2, 1000, 500, 123);
|
assertFederationProvider(userFederation().get(id1).toBriefRepresentation(), id1, id1, "dummy", 2, 1000, 500, 123);
|
||||||
assertFederationProvider(userFederation().get(id2).toRepresentation(), id2, "dn1", "dummy", 1, -1, -1, -1, "prop1", "prop1Val", "prop2", "true");
|
assertFederationProvider(userFederation().get(id2).toBriefRepresentation(), id2, "dn1", "dummy", 1, -1, -1, -1, "prop1", "prop1Val", "prop2", "true");
|
||||||
|
|
||||||
// Assert sorted
|
// Assert sorted
|
||||||
List<UserFederationProviderRepresentation> providerInstances = userFederation().getProviderInstances();
|
List<UserFederationProviderRepresentation> providerInstances = userFederation().getProviderInstances();
|
||||||
|
@ -411,7 +411,7 @@ public class UserStorageRestTest extends AbstractAdminTest {
|
||||||
|
|
||||||
@Test (expected = NotFoundException.class)
|
@Test (expected = NotFoundException.class)
|
||||||
public void testLookupNotExistentProvider() {
|
public void testLookupNotExistentProvider() {
|
||||||
userFederation().get("not-existent").toRepresentation();
|
userFederation().get("not-existent").toBriefRepresentation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -433,7 +433,7 @@ public class UserStorageRestTest extends AbstractAdminTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assert sync didn't happen
|
// Assert sync didn't happen
|
||||||
Assert.assertEquals(-1, userFederation().get(id1).toRepresentation().getLastSync());
|
Assert.assertEquals(-1, userFederation().get(id1).toBriefRepresentation().getLastSync());
|
||||||
|
|
||||||
// Sync and assert it happened
|
// Sync and assert it happened
|
||||||
SynchronizationResultRepresentation syncResult = userFederation().get(id1).syncUsers("triggerFullSync");
|
SynchronizationResultRepresentation syncResult = userFederation().get(id1).syncUsers("triggerFullSync");
|
||||||
|
@ -443,7 +443,7 @@ public class UserStorageRestTest extends AbstractAdminTest {
|
||||||
eventRep.put("action", "triggerFullSync");
|
eventRep.put("action", "triggerFullSync");
|
||||||
assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userFederationResourcePath(id1) + "/sync", eventRep, ResourceType.USER_FEDERATION_PROVIDER);
|
assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userFederationResourcePath(id1) + "/sync", eventRep, ResourceType.USER_FEDERATION_PROVIDER);
|
||||||
|
|
||||||
int fullSyncTime = userFederation().get(id1).toRepresentation().getLastSync();
|
int fullSyncTime = userFederation().get(id1).toBriefRepresentation().getLastSync();
|
||||||
Assert.assertTrue(fullSyncTime > 0);
|
Assert.assertTrue(fullSyncTime > 0);
|
||||||
|
|
||||||
// Changed sync
|
// Changed sync
|
||||||
|
@ -454,7 +454,7 @@ public class UserStorageRestTest extends AbstractAdminTest {
|
||||||
assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userFederationResourcePath(id1) + "/sync", eventRep, ResourceType.USER_FEDERATION_PROVIDER);
|
assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userFederationResourcePath(id1) + "/sync", eventRep, ResourceType.USER_FEDERATION_PROVIDER);
|
||||||
|
|
||||||
Assert.assertEquals("0 imported users, 0 updated users", syncResult.getStatus());
|
Assert.assertEquals("0 imported users, 0 updated users", syncResult.getStatus());
|
||||||
int changedSyncTime = userFederation().get(id1).toRepresentation().getLastSync();
|
int changedSyncTime = userFederation().get(id1).toBriefRepresentation().getLastSync();
|
||||||
Assert.assertTrue(fullSyncTime + 50 <= changedSyncTime);
|
Assert.assertTrue(fullSyncTime + 50 <= changedSyncTime);
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
|
|
|
@ -1368,7 +1368,7 @@ public class UserTest extends AbstractAdminTest {
|
||||||
|
|
||||||
// List realm roles
|
// List realm roles
|
||||||
assertNames(roles.realmLevel().listAll(), "realm-role", "realm-composite", "user", "offline_access", Constants.AUTHZ_UMA_AUTHORIZATION);
|
assertNames(roles.realmLevel().listAll(), "realm-role", "realm-composite", "user", "offline_access", Constants.AUTHZ_UMA_AUTHORIZATION);
|
||||||
assertNames(roles.realmLevel().listAvailable(), "admin", "customer-user-premium", "realm-composite-role", "sample-realm-role");
|
assertNames(roles.realmLevel().listAvailable(), "admin", "customer-user-premium", "realm-composite-role", "sample-realm-role", "attribute-role");
|
||||||
assertNames(roles.realmLevel().listEffective(), "realm-role", "realm-composite", "realm-child", "user", "offline_access", Constants.AUTHZ_UMA_AUTHORIZATION);
|
assertNames(roles.realmLevel().listEffective(), "realm-role", "realm-composite", "realm-child", "user", "offline_access", Constants.AUTHZ_UMA_AUTHORIZATION);
|
||||||
|
|
||||||
// List client roles
|
// List client roles
|
||||||
|
|
|
@ -501,7 +501,7 @@ public class GroupTest extends AbstractGroupTest {
|
||||||
|
|
||||||
// List realm roles
|
// List realm roles
|
||||||
assertNames(roles.realmLevel().listAll(), "realm-role", "realm-composite");
|
assertNames(roles.realmLevel().listAll(), "realm-role", "realm-composite");
|
||||||
assertNames(roles.realmLevel().listAvailable(), "admin", "offline_access", Constants.AUTHZ_UMA_AUTHORIZATION, "user", "customer-user-premium", "realm-composite-role", "sample-realm-role");
|
assertNames(roles.realmLevel().listAvailable(), "admin", "offline_access", Constants.AUTHZ_UMA_AUTHORIZATION, "user", "customer-user-premium", "realm-composite-role", "sample-realm-role", "attribute-role");
|
||||||
assertNames(roles.realmLevel().listEffective(), "realm-role", "realm-composite", "realm-child");
|
assertNames(roles.realmLevel().listEffective(), "realm-role", "realm-composite", "realm-child");
|
||||||
|
|
||||||
// List client roles
|
// List client roles
|
||||||
|
|
|
@ -274,6 +274,7 @@ public class ExportImportTest extends AbstractKeycloakTest {
|
||||||
List<ComponentRepresentation> components = adminClient.realm("test").components().query();
|
List<ComponentRepresentation> components = adminClient.realm("test").components().query();
|
||||||
KeysMetadataRepresentation keyMetadata = adminClient.realm("test").keys().getKeyMetadata();
|
KeysMetadataRepresentation keyMetadata = adminClient.realm("test").keys().getKeyMetadata();
|
||||||
String sampleRealmRoleId = adminClient.realm("test").roles().get("sample-realm-role").toRepresentation().getId();
|
String sampleRealmRoleId = adminClient.realm("test").roles().get("sample-realm-role").toRepresentation().getId();
|
||||||
|
Map<String, List<String>> roleAttributes = adminClient.realm("test").roles().get("attribute-role").toRepresentation().getAttributes();
|
||||||
String testAppId = adminClient.realm("test").clients().findByClientId("test-app").get(0).getId();
|
String testAppId = adminClient.realm("test").clients().findByClientId("test-app").get(0).getId();
|
||||||
String sampleClientRoleId = adminClient.realm("test").clients().get(testAppId).roles().get("sample-client-role").toRepresentation().getId();
|
String sampleClientRoleId = adminClient.realm("test").clients().get(testAppId).roles().get("sample-client-role").toRepresentation().getId();
|
||||||
|
|
||||||
|
@ -309,6 +310,9 @@ public class ExportImportTest extends AbstractKeycloakTest {
|
||||||
String importedSampleRealmRoleId = adminClient.realm("test").roles().get("sample-realm-role").toRepresentation().getId();
|
String importedSampleRealmRoleId = adminClient.realm("test").roles().get("sample-realm-role").toRepresentation().getId();
|
||||||
assertEquals(sampleRealmRoleId, importedSampleRealmRoleId);
|
assertEquals(sampleRealmRoleId, importedSampleRealmRoleId);
|
||||||
|
|
||||||
|
Map<String, List<String>> importedRoleAttributes = adminClient.realm("test").roles().get("attribute-role").toRepresentation().getAttributes();
|
||||||
|
assertEquals(roleAttributes, importedRoleAttributes);
|
||||||
|
|
||||||
String importedSampleClientRoleId = adminClient.realm("test").clients().get(testAppId).roles().get("sample-client-role").toRepresentation().getId();
|
String importedSampleClientRoleId = adminClient.realm("test").clients().get(testAppId).roles().get("sample-client-role").toRepresentation().getId();
|
||||||
assertEquals(sampleClientRoleId, importedSampleClientRoleId);
|
assertEquals(sampleClientRoleId, importedSampleClientRoleId);
|
||||||
|
|
||||||
|
|
|
@ -385,6 +385,16 @@
|
||||||
"name": "sample-realm-role",
|
"name": "sample-realm-role",
|
||||||
"description": "Sample realm role"
|
"description": "Sample realm role"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "attribute-role",
|
||||||
|
"description": "has attributes assigned",
|
||||||
|
"attributes": {
|
||||||
|
"hello": [
|
||||||
|
"world",
|
||||||
|
"keycloak"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "realm-composite-role",
|
"name": "realm-composite-role",
|
||||||
"description": "Realm composite role containing client role",
|
"description": "Realm composite role containing client role",
|
||||||
|
|
|
@ -788,6 +788,24 @@ module.config([ '$routeProvider', function($routeProvider) {
|
||||||
},
|
},
|
||||||
controller : 'RoleDetailCtrl'
|
controller : 'RoleDetailCtrl'
|
||||||
})
|
})
|
||||||
|
.when('/realms/:realm/roles/:role/role-attributes', {
|
||||||
|
templateUrl : resourceUrl + '/partials/role-attributes.html',
|
||||||
|
resolve : {
|
||||||
|
realm : function(RealmLoader) {
|
||||||
|
return RealmLoader();
|
||||||
|
},
|
||||||
|
role : function(RoleLoader) {
|
||||||
|
return RoleLoader();
|
||||||
|
},
|
||||||
|
roles : function(RoleListLoader) {
|
||||||
|
return RoleListLoader();
|
||||||
|
},
|
||||||
|
clients : function(ClientListLoader) {
|
||||||
|
return ClientListLoader();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
controller : 'RoleDetailCtrl'
|
||||||
|
})
|
||||||
.when('/realms/:realm/roles/:role/users', {
|
.when('/realms/:realm/roles/:role/users', {
|
||||||
templateUrl : resourceUrl + '/partials/realm-role-users.html',
|
templateUrl : resourceUrl + '/partials/realm-role-users.html',
|
||||||
resolve : {
|
resolve : {
|
||||||
|
@ -943,6 +961,27 @@ module.config([ '$routeProvider', function($routeProvider) {
|
||||||
},
|
},
|
||||||
controller : 'ClientRoleDetailCtrl'
|
controller : 'ClientRoleDetailCtrl'
|
||||||
})
|
})
|
||||||
|
.when('/realms/:realm/clients/:client/roles/:role/role-attributes', {
|
||||||
|
templateUrl : resourceUrl + '/partials/client-role-attributes.html',
|
||||||
|
resolve : {
|
||||||
|
realm : function(RealmLoader) {
|
||||||
|
return RealmLoader();
|
||||||
|
},
|
||||||
|
client : function(ClientLoader) {
|
||||||
|
return ClientLoader();
|
||||||
|
},
|
||||||
|
role : function(ClientRoleLoader) {
|
||||||
|
return ClientRoleLoader();
|
||||||
|
},
|
||||||
|
roles : function(RoleListLoader) {
|
||||||
|
return RoleListLoader();
|
||||||
|
},
|
||||||
|
clients : function(ClientListLoader) {
|
||||||
|
return ClientListLoader();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
controller : 'ClientRoleDetailCtrl'
|
||||||
|
})
|
||||||
.when('/realms/:realm/clients/:client/mappers', {
|
.when('/realms/:realm/clients/:client/mappers', {
|
||||||
templateUrl : resourceUrl + '/partials/client-mappers.html',
|
templateUrl : resourceUrl + '/partials/client-mappers.html',
|
||||||
resolve : {
|
resolve : {
|
||||||
|
|
|
@ -685,12 +685,14 @@ module.controller('ClientRoleDetailCtrl', function($scope, realm, client, role,
|
||||||
$scope.changed = $scope.create;
|
$scope.changed = $scope.create;
|
||||||
|
|
||||||
$scope.save = function() {
|
$scope.save = function() {
|
||||||
|
convertAttributeValuesToLists();
|
||||||
if ($scope.create) {
|
if ($scope.create) {
|
||||||
ClientRole.save({
|
ClientRole.save({
|
||||||
realm: realm.realm,
|
realm: realm.realm,
|
||||||
client : client.id
|
client : client.id
|
||||||
}, $scope.role, function (data, headers) {
|
}, $scope.role, function (data, headers) {
|
||||||
$scope.changed = false;
|
$scope.changed = false;
|
||||||
|
convertAttributeValuesToString($scope.role);
|
||||||
role = angular.copy($scope.role);
|
role = angular.copy($scope.role);
|
||||||
|
|
||||||
ClientRole.get({ realm: realm.realm, client : client.id, role: role.name }, function(role) {
|
ClientRole.get({ realm: realm.realm, client : client.id, role: role.name }, function(role) {
|
||||||
|
@ -721,6 +723,34 @@ module.controller('ClientRoleDetailCtrl', function($scope, realm, client, role,
|
||||||
$location.url("/realms/" + realm.realm + "/clients/" + client.id + "/roles");
|
$location.url("/realms/" + realm.realm + "/clients/" + client.id + "/roles");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.addAttribute = function() {
|
||||||
|
$scope.role.attributes[$scope.newAttribute.key] = $scope.newAttribute.value;
|
||||||
|
delete $scope.newAttribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.removeAttribute = function(key) {
|
||||||
|
delete $scope.role.attributes[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertAttributeValuesToLists() {
|
||||||
|
var attrs = $scope.role.attributes;
|
||||||
|
for (var attribute in attrs) {
|
||||||
|
if (typeof attrs[attribute] === "string") {
|
||||||
|
var attrVals = attrs[attribute].split("##");
|
||||||
|
attrs[attribute] = attrVals;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertAttributeValuesToString(role) {
|
||||||
|
var attrs = role.attributes;
|
||||||
|
for (var attribute in attrs) {
|
||||||
|
if (typeof attrs[attribute] === "object") {
|
||||||
|
var attrVals = attrs[attribute].join("##");
|
||||||
|
attrs[attribute] = attrVals;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
roleControl($scope, realm, role, roles, clients,
|
roleControl($scope, realm, role, roles, clients,
|
||||||
ClientRole, RoleById, RoleRealmComposites, RoleClientComposites,
|
ClientRole, RoleById, RoleRealmComposites, RoleClientComposites,
|
||||||
|
|
|
@ -1461,12 +1461,14 @@ module.controller('RoleDetailCtrl', function($scope, realm, role, roles, clients
|
||||||
$scope.changed = $scope.create;
|
$scope.changed = $scope.create;
|
||||||
|
|
||||||
$scope.save = function() {
|
$scope.save = function() {
|
||||||
|
convertAttributeValuesToLists();
|
||||||
console.log('save');
|
console.log('save');
|
||||||
if ($scope.create) {
|
if ($scope.create) {
|
||||||
Role.save({
|
Role.save({
|
||||||
realm: realm.realm
|
realm: realm.realm
|
||||||
}, $scope.role, function (data, headers) {
|
}, $scope.role, function (data, headers) {
|
||||||
$scope.changed = false;
|
$scope.changed = false;
|
||||||
|
convertAttributeValuesToString($scope.role);
|
||||||
role = angular.copy($scope.role);
|
role = angular.copy($scope.role);
|
||||||
|
|
||||||
Role.get({ realm: realm.realm, role: role.name }, function(role) {
|
Role.get({ realm: realm.realm, role: role.name }, function(role) {
|
||||||
|
@ -1488,7 +1490,35 @@ module.controller('RoleDetailCtrl', function($scope, realm, role, roles, clients
|
||||||
$location.url("/realms/" + realm.realm + "/roles");
|
$location.url("/realms/" + realm.realm + "/roles");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.addAttribute = function() {
|
||||||
|
$scope.role.attributes[$scope.newAttribute.key] = $scope.newAttribute.value;
|
||||||
|
delete $scope.newAttribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.removeAttribute = function(key) {
|
||||||
|
delete $scope.role.attributes[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertAttributeValuesToLists() {
|
||||||
|
var attrs = $scope.role.attributes;
|
||||||
|
for (var attribute in attrs) {
|
||||||
|
if (typeof attrs[attribute] === "string") {
|
||||||
|
var attrVals = attrs[attribute].split("##");
|
||||||
|
attrs[attribute] = attrVals;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertAttributeValuesToString(role) {
|
||||||
|
var attrs = role.attributes;
|
||||||
|
for (var attribute in attrs) {
|
||||||
|
if (typeof attrs[attribute] === "object") {
|
||||||
|
var attrVals = attrs[attribute].join("##");
|
||||||
|
attrs[attribute] = attrVals;
|
||||||
|
console.log("attribute" + attrVals)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
roleControl($scope, realm, role, roles, clients,
|
roleControl($scope, realm, role, roles, clients,
|
||||||
ClientRole, RoleById, RoleRealmComposites, RoleClientComposites,
|
ClientRole, RoleById, RoleRealmComposites, RoleClientComposites,
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
|
||||||
|
<ol class="breadcrumb">
|
||||||
|
<li><a href="#/realms/{{realm.realm}}/clients">{{:: 'clients' | translate}}</a></li>
|
||||||
|
<li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}">{{client.clientId}}</a></li>
|
||||||
|
<li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/roles">{{:: 'roles' | translate}}</a></li>
|
||||||
|
<li>{{role.name}}</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<kc-tabs-client-role></kc-tabs-client-role>
|
||||||
|
|
||||||
|
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!client.access.configure">
|
||||||
|
<table class="table table-striped table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{:: 'key' | translate}}</th>
|
||||||
|
<th>{{:: 'value' | translate}}</th>
|
||||||
|
<th>{{:: 'actions' | translate}}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
<tr ng-repeat="(key, value) in role.attributes | toOrderedMapSortedByKey">
|
||||||
|
<td>{{key}}</td>
|
||||||
|
<td><input ng-model="role.attributes[key]" class="form-control" type="text" name="{{key}}" id="attribute-{{key}}" /></td>
|
||||||
|
<td class="kc-action-cell" data-ng-click="removeAttribute(key)">{{:: 'delete' | translate}}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td><input ng-model="newAttribute.key" class="form-control" type="text" id="newAttributeKey" /></td>
|
||||||
|
<td><input ng-model="newAttribute.value" class="form-control" type="text" id="newAttributeValue" /></td>
|
||||||
|
<td class="kc-action-cell" data-ng-click="addAttribute()" data-ng-disabled="!newAttribute.key.length || !newAttribute.value.length">{{:: 'add' | translate}}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="form-group" data-ng-show="client.access.configure">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<button kc-save data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
|
||||||
|
<button kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<kc-menu></kc-menu>
|
|
@ -0,0 +1,41 @@
|
||||||
|
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
|
||||||
|
<ol class="breadcrumb">
|
||||||
|
<li><a href="#/realms/{{realm.realm}}/roles">{{:: 'roles' | translate}}</a></li>
|
||||||
|
<li>{{role.name}}</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<kc-tabs-role></kc-tabs-role>
|
||||||
|
|
||||||
|
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
||||||
|
<table class="table table-striped table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{:: 'key' | translate}}</th>
|
||||||
|
<th>{{:: 'value' | translate}}</th>
|
||||||
|
<th>{{:: 'actions' | translate}}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr ng-repeat="(key, value) in role.attributes | toOrderedMapSortedByKey">
|
||||||
|
<td>{{key}}</td>
|
||||||
|
<td><input ng-model="role.attributes[key]" class="form-control" type="text" name="{{key}}" id="attribute-{{key}}" /></td>
|
||||||
|
<td class="kc-action-cell" data-ng-click="removeAttribute(key)">{{:: 'delete' | translate}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><input ng-model="newAttribute.key" class="form-control" type="text" id="newAttributeKey" /></td>
|
||||||
|
<td><input ng-model="newAttribute.value" class="form-control" type="text" id="newAttributeValue" /></td>
|
||||||
|
<td class="kc-action-cell" data-ng-click="addAttribute()" data-ng-disabled="!newAttribute.key.length || !newAttribute.value.length">{{:: 'add' | translate}}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="form-group" data-ng-show="access.manageRealm">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<button kc-save data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
|
||||||
|
<button kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<kc-menu></kc-menu>
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
<ul class="nav nav-tabs" data-ng-show="!create">
|
<ul class="nav nav-tabs" data-ng-show="!create">
|
||||||
<li ng-class="{active: !path[6]}"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/roles/{{role.id}}">{{:: 'details' | translate}}</a></li>
|
<li ng-class="{active: !path[6]}"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/roles/{{role.id}}">{{:: 'details' | translate}}</a></li>
|
||||||
|
<li ng-class="{active: path[6] && path[6] == 'role-attributes'}"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/roles/{{role.id}}/role-attributes">{{:: 'attributes' | translate}}</a></li>
|
||||||
<li ng-class="{active: path[6] && path[6] == 'permissions'}" data-ng-show="serverInfo.featureEnabled('ADMIN_FINE_GRAINED_AUTHZ') && access.manageAuthorization && client.access.configure">
|
<li ng-class="{active: path[6] && path[6] == 'permissions'}" data-ng-show="serverInfo.featureEnabled('ADMIN_FINE_GRAINED_AUTHZ') && access.manageAuthorization && client.access.configure">
|
||||||
<a href="#/realms/{{realm.realm}}/clients/{{client.id}}/roles/{{role.id}}/permissions">{{:: 'authz-permissions' | translate}}</a>
|
<a href="#/realms/{{realm.realm}}/clients/{{client.id}}/roles/{{role.id}}/permissions">{{:: 'authz-permissions' | translate}}</a>
|
||||||
<kc-tooltip>{{:: 'manage-permissions-role.tooltip' | translate}}</kc-tooltip>
|
<kc-tooltip>{{:: 'manage-permissions-role.tooltip' | translate}}</kc-tooltip>
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
<ul class="nav nav-tabs" data-ng-show="!create">
|
<ul class="nav nav-tabs" data-ng-show="!create">
|
||||||
<li ng-class="{active: !path[4]}"><a href="#/realms/{{realm.realm}}/roles/{{role.id}}">{{:: 'details' | translate}}</a></li>
|
<li ng-class="{active: !path[4]}"><a href="#/realms/{{realm.realm}}/roles/{{role.id}}">{{:: 'details' | translate}}</a></li>
|
||||||
|
<li ng-class="{active: path[4] == 'role-attributes'}"><a href="#/realms/{{realm.realm}}/roles/{{role.id}}/role-attributes">{{:: 'attributes' | translate}}</a></li>
|
||||||
<li ng-class="{active: path[4] == 'permissions'}" data-ng-show="serverInfo.featureEnabled('ADMIN_FINE_GRAINED_AUTHZ') && access.manageRealm && access.manageAuthorization">
|
<li ng-class="{active: path[4] == 'permissions'}" data-ng-show="serverInfo.featureEnabled('ADMIN_FINE_GRAINED_AUTHZ') && access.manageRealm && access.manageAuthorization">
|
||||||
<a href="#/realms/{{realm.realm}}/roles/{{role.id}}/permissions">{{:: 'authz-permissions' | translate}}</a>
|
<a href="#/realms/{{realm.realm}}/roles/{{role.id}}/permissions">{{:: 'authz-permissions' | translate}}</a>
|
||||||
<kc-tooltip>{{:: 'manage-permissions-role.tooltip' | translate}}</kc-tooltip>
|
<kc-tooltip>{{:: 'manage-permissions-role.tooltip' | translate}}</kc-tooltip>
|
||||||
|
|
Loading…
Reference in a new issue