Skip to content
This repository was archived by the owner on Oct 12, 2020. It is now read-only.

Commit 89e3d75

Browse files
committed
update for KEYCLOAK-6884 KEYCLOAK-3454 KEYCLOAK-8298
1 parent f63e407 commit 89e3d75

11 files changed

+66
-109
lines changed

src/main/java/org/keycloak/protocol/cas/endpoints/ServiceValidateEndpoint.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ protected Response successResponse() {
3636
for (ProtocolMapperModel mapping : mappings) {
3737
ProtocolMapper mapper = (ProtocolMapper) sessionFactory.getProviderFactory(ProtocolMapper.class, mapping.getProtocolMapper());
3838
if (mapper instanceof CASAttributeMapper) {
39-
((CASAttributeMapper) mapper).setAttribute(attributes, mapping, userSession);
39+
((CASAttributeMapper) mapper).setAttribute(attributes, mapping, userSession, session, clientSessionCtx);
4040
}
4141
}
4242

src/main/java/org/keycloak/protocol/cas/mappers/AbstractUserRoleMappingMapper.java

+10-55
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,11 @@
1717

1818
package org.keycloak.protocol.cas.mappers;
1919

20-
import org.keycloak.models.*;
21-
import org.keycloak.models.utils.RoleUtils;
20+
import org.keycloak.models.ProtocolMapperModel;
2221

2322
import java.util.Map;
2423
import java.util.Set;
25-
import java.util.function.Predicate;
2624
import java.util.stream.Collectors;
27-
import java.util.stream.Stream;
2825

2926
/**
3027
* Base class for mapping of user role mappings to an ID and Access Token claim.
@@ -33,66 +30,24 @@
3330
*/
3431
abstract class AbstractUserRoleMappingMapper extends AbstractCASProtocolMapper {
3532

36-
/**
37-
* Returns a stream with roles that come from:
38-
* <ul>
39-
* <li>Direct assignment of the role to the user</li>
40-
* <li>Direct assignment of the role to any group of the user or any of its parent group</li>
41-
* <li>Composite roles are expanded recursively, the composite role itself is also contained in the returned stream</li>
42-
* </ul>
43-
* @param user User to enumerate the roles for
44-
*/
45-
public Stream<RoleModel> getAllUserRolesStream(UserModel user) {
46-
return Stream.concat(
47-
user.getRoleMappings().stream(),
48-
user.getGroups().stream()
49-
.flatMap(this::groupAndItsParentsStream)
50-
.flatMap(g -> g.getRoleMappings().stream()))
51-
.flatMap(RoleUtils::expandCompositeRolesStream);
52-
}
53-
54-
/**
55-
* Returns stream of the given group and its parents (recursively).
56-
* @param group
57-
* @return
58-
*/
59-
private Stream<GroupModel> groupAndItsParentsStream(GroupModel group) {
60-
Stream.Builder<GroupModel> sb = Stream.builder();
61-
while (group != null) {
62-
sb.add(group);
63-
group = group.getParent();
64-
}
65-
return sb.build();
66-
}
67-
6833
/**
6934
* Retrieves all roles of the current user based on direct roles set to the user, its groups and their parent groups.
7035
* Then it recursively expands all composite roles, and restricts according to the given predicate {@code restriction}.
7136
* If the current client sessions is restricted (i.e. no client found in active user session has full scope allowed),
7237
* the final list of roles is also restricted by the client scope. Finally, the list is mapped to the token into
7338
* a claim.
7439
*/
75-
protected void setAttribute(Map<String, Object> attributes, ProtocolMapperModel mappingModel, UserSessionModel userSession,
76-
Predicate<RoleModel> restriction, String prefix) {
77-
String rolePrefix = prefix == null ? "" : prefix;
78-
UserModel user = userSession.getUser();
79-
80-
// get a set of all realm roles assigned to the user or its group
81-
Stream<RoleModel> clientUserRoles = getAllUserRolesStream(user).filter(restriction);
82-
83-
boolean dontLimitScope = userSession.getAuthenticatedClientSessions().values().stream().anyMatch(cs -> cs.getClient().isFullScopeAllowed());
84-
if (! dontLimitScope) {
85-
Set<RoleModel> clientRoles = userSession.getAuthenticatedClientSessions().values().stream()
86-
.flatMap(cs -> cs.getClient().getScopeMappings().stream())
87-
.collect(Collectors.toSet());
88-
89-
clientUserRoles = clientUserRoles.filter(clientRoles::contains);
40+
protected void setAttribute(Map<String, Object> attributes, ProtocolMapperModel mappingModel, Set<String> rolesToAdd,
41+
String prefix) {
42+
Set<String> realmRoleNames;
43+
if (prefix != null && !prefix.isEmpty()) {
44+
realmRoleNames = rolesToAdd.stream()
45+
.map(roleName -> prefix + roleName)
46+
.collect(Collectors.toSet());
47+
} else {
48+
realmRoleNames = rolesToAdd;
9049
}
9150

92-
Set<String> realmRoleNames = clientUserRoles
93-
.map(m -> rolePrefix + m.getName())
94-
.collect(Collectors.toSet());
95-
9651
setPlainAttribute(attributes, mappingModel, realmRoleNames);
9752
}
9853
}
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package org.keycloak.protocol.cas.mappers;
22

3+
import org.keycloak.models.ClientSessionContext;
4+
import org.keycloak.models.KeycloakSession;
35
import org.keycloak.models.ProtocolMapperModel;
46
import org.keycloak.models.UserSessionModel;
57

68
import java.util.Map;
79

810
public interface CASAttributeMapper {
9-
void setAttribute(Map<String, Object> attributes, ProtocolMapperModel mappingModel, UserSessionModel userSession);
11+
void setAttribute(Map<String, Object> attributes, ProtocolMapperModel mappingModel, UserSessionModel userSession,
12+
KeycloakSession session, ClientSessionContext clientSessionCtx);
1013
}

src/main/java/org/keycloak/protocol/cas/mappers/FullNameMapper.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package org.keycloak.protocol.cas.mappers;
22

3-
import org.keycloak.models.ProtocolMapperModel;
4-
import org.keycloak.models.UserModel;
5-
import org.keycloak.models.UserSessionModel;
3+
import org.keycloak.models.*;
64
import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
75
import org.keycloak.provider.ProviderConfigProperty;
86

@@ -41,7 +39,8 @@ public String getHelpText() {
4139
}
4240

4341
@Override
44-
public void setAttribute(Map<String, Object> attributes, ProtocolMapperModel mappingModel, UserSessionModel userSession) {
42+
public void setAttribute(Map<String, Object> attributes, ProtocolMapperModel mappingModel, UserSessionModel userSession,
43+
KeycloakSession session, ClientSessionContext clientSessionCt) {
4544
UserModel user = userSession.getUser();
4645
String first = user.getFirstName() == null ? "" : user.getFirstName() + " ";
4746
String last = user.getLastName() == null ? "" : user.getLastName();

src/main/java/org/keycloak/protocol/cas/mappers/GroupMembershipMapper.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package org.keycloak.protocol.cas.mappers;
22

3-
import org.keycloak.models.GroupModel;
4-
import org.keycloak.models.ProtocolMapperModel;
5-
import org.keycloak.models.UserSessionModel;
3+
import org.keycloak.models.*;
64
import org.keycloak.models.utils.ModelToRepresentation;
75
import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
86
import org.keycloak.provider.ProviderConfigProperty;
@@ -52,7 +50,8 @@ public String getHelpText() {
5250
}
5351

5452
@Override
55-
public void setAttribute(Map<String, Object> attributes, ProtocolMapperModel mappingModel, UserSessionModel userSession) {
53+
public void setAttribute(Map<String, Object> attributes, ProtocolMapperModel mappingModel, UserSessionModel userSession,
54+
KeycloakSession session, ClientSessionContext clientSessionCt) {
5655
List<String> membership = new LinkedList<>();
5756
boolean fullPath = useFullPath(mappingModel);
5857
for (GroupModel group : userSession.getUser().getGroups()) {

src/main/java/org/keycloak/protocol/cas/mappers/HardcodedClaim.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.keycloak.protocol.cas.mappers;
22

3+
import org.keycloak.models.ClientSessionContext;
4+
import org.keycloak.models.KeycloakSession;
35
import org.keycloak.models.ProtocolMapperModel;
46
import org.keycloak.models.UserSessionModel;
57
import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
@@ -53,7 +55,8 @@ public String getHelpText() {
5355
}
5456

5557
@Override
56-
public void setAttribute(Map<String, Object> attributes, ProtocolMapperModel mappingModel, UserSessionModel userSession) {
58+
public void setAttribute(Map<String, Object> attributes, ProtocolMapperModel mappingModel, UserSessionModel userSession,
59+
KeycloakSession session, ClientSessionContext clientSessionCt) {
5760
setMappedAttribute(attributes, mappingModel, mappingModel.getConfig().get(CLAIM_VALUE));
5861
}
5962

src/main/java/org/keycloak/protocol/cas/mappers/UserAttributeMapper.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package org.keycloak.protocol.cas.mappers;
22

3-
import org.keycloak.models.ProtocolMapperModel;
4-
import org.keycloak.models.UserModel;
5-
import org.keycloak.models.UserSessionModel;
3+
import org.keycloak.models.*;
64
import org.keycloak.models.utils.KeycloakModelUtils;
75
import org.keycloak.protocol.ProtocolMapperUtils;
86
import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
@@ -66,7 +64,8 @@ public String getHelpText() {
6664
}
6765

6866
@Override
69-
public void setAttribute(Map<String, Object> attributes, ProtocolMapperModel mappingModel, UserSessionModel userSession) {
67+
public void setAttribute(Map<String, Object> attributes, ProtocolMapperModel mappingModel, UserSessionModel userSession,
68+
KeycloakSession session, ClientSessionContext clientSessionCt) {
7069
UserModel user = userSession.getUser();
7170
String attributeName = mappingModel.getConfig().get(ProtocolMapperUtils.USER_ATTRIBUTE);
7271
boolean aggregateAttrs = Boolean.valueOf(mappingModel.getConfig().get(ProtocolMapperUtils.AGGREGATE_ATTRS));

src/main/java/org/keycloak/protocol/cas/mappers/UserClientRoleMappingMapper.java

+18-32
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22

33
import org.keycloak.models.*;
44
import org.keycloak.protocol.ProtocolMapperUtils;
5-
import org.keycloak.protocol.oidc.TokenManager;
65
import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
76
import org.keycloak.provider.ProviderConfigProperty;
7+
import org.keycloak.representations.AccessToken;
8+
import org.keycloak.utils.RoleResolveUtil;
89

910
import java.util.*;
10-
import java.util.function.Predicate;
11+
import java.util.stream.Collectors;
1112

1213
public class UserClientRoleMappingMapper extends AbstractUserRoleMappingMapper {
1314

@@ -60,40 +61,25 @@ public String getHelpText() {
6061
}
6162

6263
@Override
63-
public void setAttribute(Map<String, Object> attributes, ProtocolMapperModel mappingModel, UserSessionModel userSession) {
64+
public void setAttribute(Map<String, Object> attributes, ProtocolMapperModel mappingModel, UserSessionModel userSession,
65+
KeycloakSession session, ClientSessionContext clientSessionCtx) {
6466
String clientId = mappingModel.getConfig().get(ProtocolMapperUtils.USER_MODEL_CLIENT_ROLE_MAPPING_CLIENT_ID);
6567
String rolePrefix = mappingModel.getConfig().get(ProtocolMapperUtils.USER_MODEL_CLIENT_ROLE_MAPPING_ROLE_PREFIX);
6668

67-
setAttribute(attributes, mappingModel, userSession, getClientRoleFilter(clientId, userSession), rolePrefix);
68-
}
69-
70-
private static Predicate<RoleModel> getClientRoleFilter(String clientId, UserSessionModel userSession) {
71-
if (clientId == null) {
72-
return RoleModel::isClientRole;
73-
}
74-
75-
RealmModel clientRealm = userSession.getRealm();
76-
ClientModel client = clientRealm.getClientByClientId(clientId.trim());
77-
78-
if (client == null) {
79-
return RoleModel::isClientRole;
69+
if (clientId != null && !clientId.isEmpty()) {
70+
AccessToken.Access access = RoleResolveUtil.getResolvedClientRoles(session, clientSessionCtx, clientId, false);
71+
if (access == null) {
72+
return;
73+
}
74+
setAttribute(attributes, mappingModel, access.getRoles(), rolePrefix);
75+
} else {
76+
// If clientId is not specified, we consider all clients
77+
Map<String, AccessToken.Access> allAccess = RoleResolveUtil.getAllResolvedClientRoles(session, clientSessionCtx);
78+
Set<String> allRoles = allAccess.values().stream().filter(Objects::nonNull)
79+
.flatMap(access -> access.getRoles().stream())
80+
.collect(Collectors.toSet());
81+
setAttribute(attributes, mappingModel, allRoles, rolePrefix);
8082
}
81-
82-
boolean fullScopeAllowed = client.isFullScopeAllowed();
83-
Set<RoleModel> clientRoleMappings = client.getRoles();
84-
if (fullScopeAllowed) {
85-
return clientRoleMappings::contains;
86-
}
87-
88-
Set<RoleModel> scopeMappings = new HashSet<>();
89-
90-
// CAS protocol does not support scopes, so pass null scopeParam
91-
Set<ClientScopeModel> clientScopes = TokenManager.getRequestedClientScopes(null, client);
92-
for (ClientScopeModel clientScope : clientScopes) {
93-
scopeMappings.addAll(clientScope.getScopeMappings());
94-
}
95-
96-
return role -> clientRoleMappings.contains(role) && scopeMappings.contains(role);
9783
}
9884

9985
public static ProtocolMapperModel create(String clientId, String clientRolePrefix,

src/main/java/org/keycloak/protocol/cas/mappers/UserPropertyMapper.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package org.keycloak.protocol.cas.mappers;
22

3-
import org.keycloak.models.ProtocolMapperModel;
4-
import org.keycloak.models.UserModel;
5-
import org.keycloak.models.UserSessionModel;
3+
import org.keycloak.models.*;
64
import org.keycloak.protocol.ProtocolMapperUtils;
75
import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
86
import org.keycloak.provider.ProviderConfigProperty;
@@ -50,7 +48,8 @@ public String getHelpText() {
5048
}
5149

5250
@Override
53-
public void setAttribute(Map<String, Object> attributes, ProtocolMapperModel mappingModel, UserSessionModel userSession) {
51+
public void setAttribute(Map<String, Object> attributes, ProtocolMapperModel mappingModel, UserSessionModel userSession,
52+
KeycloakSession session, ClientSessionContext clientSessionCt) {
5453
UserModel user = userSession.getUser();
5554
String propertyName = mappingModel.getConfig().get(ProtocolMapperUtils.USER_ATTRIBUTE);
5655
String propertyValue = ProtocolMapperUtils.getUserModelValue(user, propertyName);

src/main/java/org/keycloak/protocol/cas/mappers/UserRealmRoleMappingMapper.java

+13-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
package org.keycloak.protocol.cas.mappers;
22

3+
import org.keycloak.models.ClientSessionContext;
4+
import org.keycloak.models.KeycloakSession;
35
import org.keycloak.models.ProtocolMapperModel;
46
import org.keycloak.models.UserSessionModel;
57
import org.keycloak.protocol.ProtocolMapperUtils;
68
import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
79
import org.keycloak.provider.ProviderConfigProperty;
10+
import org.keycloak.representations.AccessToken;
11+
import org.keycloak.utils.RoleResolveUtil;
812

913
import java.util.ArrayList;
1014
import java.util.List;
@@ -53,9 +57,16 @@ public String getHelpText() {
5357
}
5458

5559
@Override
56-
public void setAttribute(Map<String, Object> attributes, ProtocolMapperModel mappingModel, UserSessionModel userSession) {
60+
public void setAttribute(Map<String, Object> attributes, ProtocolMapperModel mappingModel, UserSessionModel userSession,
61+
KeycloakSession session, ClientSessionContext clientSessionCtx) {
5762
String rolePrefix = mappingModel.getConfig().get(ProtocolMapperUtils.USER_MODEL_REALM_ROLE_MAPPING_ROLE_PREFIX);
58-
setAttribute(attributes, mappingModel, userSession, role -> ! role.isClientRole(), rolePrefix);
63+
64+
AccessToken.Access access = RoleResolveUtil.getResolvedRealmRoles(session, clientSessionCtx, false);
65+
if (access == null) {
66+
return;
67+
}
68+
69+
setAttribute(attributes, mappingModel, access.getRoles(), rolePrefix);
5970
}
6071

6172
public static ProtocolMapperModel create(String realmRolePrefix, String name, String tokenClaimName) {

src/main/java/org/keycloak/protocol/cas/mappers/UserSessionNoteMapper.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.keycloak.protocol.cas.mappers;
22

3+
import org.keycloak.models.ClientSessionContext;
4+
import org.keycloak.models.KeycloakSession;
35
import org.keycloak.models.ProtocolMapperModel;
46
import org.keycloak.models.UserSessionModel;
57
import org.keycloak.protocol.ProtocolMapperUtils;
@@ -54,7 +56,8 @@ public String getHelpText() {
5456
}
5557

5658
@Override
57-
public void setAttribute(Map<String, Object> attributes, ProtocolMapperModel mappingModel, UserSessionModel userSession) {
59+
public void setAttribute(Map<String, Object> attributes, ProtocolMapperModel mappingModel, UserSessionModel userSession,
60+
KeycloakSession session, ClientSessionContext clientSessionCt) {
5861
String noteName = mappingModel.getConfig().get(ProtocolMapperUtils.USER_SESSION_NOTE);
5962
String noteValue = userSession.getNote(noteName);
6063
if (noteValue == null) return;

0 commit comments

Comments
 (0)