mirror of https://github.com/jacekkow/keycloak-protocol-cas

Matthias Piepkorn
2017-02-05 5a0869a771f65f87fa2a4ed402fb1f3597b92198
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 }