commit | author | age
|
0ad1a9
|
1 |
/* |
MP |
2 |
* Copyright 2016 Red Hat, Inc. and/or its affiliates |
|
3 |
* and other contributors as indicated by the @author tags. |
|
4 |
* |
|
5 |
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
6 |
* you may not use this file except in compliance with the License. |
|
7 |
* You may obtain a copy of the License at |
|
8 |
* |
|
9 |
* http://www.apache.org/licenses/LICENSE-2.0 |
|
10 |
* |
|
11 |
* Unless required by applicable law or agreed to in writing, software |
|
12 |
* distributed under the License is distributed on an "AS IS" BASIS, |
|
13 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
14 |
* See the License for the specific language governing permissions and |
|
15 |
* limitations under the License. |
|
16 |
*/ |
|
17 |
|
|
18 |
package org.keycloak.protocol.cas.mappers; |
|
19 |
|
|
20 |
import org.keycloak.models.*; |
|
21 |
import org.keycloak.models.utils.RoleUtils; |
|
22 |
|
|
23 |
import java.util.Map; |
|
24 |
import java.util.Set; |
|
25 |
import java.util.function.Predicate; |
|
26 |
import java.util.stream.Collectors; |
|
27 |
import java.util.stream.Stream; |
|
28 |
|
|
29 |
/** |
|
30 |
* Base class for mapping of user role mappings to an ID and Access Token claim. |
|
31 |
* |
|
32 |
* @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a> |
|
33 |
*/ |
|
34 |
abstract class AbstractUserRoleMappingMapper extends AbstractCASProtocolMapper { |
|
35 |
|
|
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 |
|
|
68 |
/** |
|
69 |
* Retrieves all roles of the current user based on direct roles set to the user, its groups and their parent groups. |
|
70 |
* Then it recursively expands all composite roles, and restricts according to the given predicate {@code restriction}. |
|
71 |
* If the current client sessions is restricted (i.e. no client found in active user session has full scope allowed), |
|
72 |
* the final list of roles is also restricted by the client scope. Finally, the list is mapped to the token into |
|
73 |
* a claim. |
|
74 |
*/ |
|
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.getClientSessions().stream().anyMatch(cs -> cs.getClient().isFullScopeAllowed()); |
|
84 |
if (! dontLimitScope) { |
|
85 |
Set<RoleModel> clientRoles = userSession.getClientSessions().stream() |
|
86 |
.flatMap(cs -> cs.getClient().getScopeMappings().stream()) |
|
87 |
.collect(Collectors.toSet()); |
|
88 |
|
|
89 |
clientUserRoles = clientUserRoles.filter(clientRoles::contains); |
|
90 |
} |
|
91 |
|
|
92 |
Set<String> realmRoleNames = clientUserRoles |
|
93 |
.map(m -> rolePrefix + m.getName()) |
|
94 |
.collect(Collectors.toSet()); |
|
95 |
|
|
96 |
setPlainAttribute(attributes, mappingModel, realmRoleNames); |
|
97 |
} |
|
98 |
} |