From 0ad1a9ef9ee5ac9a162e7bd8721601bc927db460 Mon Sep 17 00:00:00 2001
From: Matthias Piepkorn <mpiepk@gmail.com>
Date: Sun, 29 Jan 2017 11:01:01 +0000
Subject: [PATCH] Add more attribute mappers, cleanup existing mappers
---
src/main/java/org/keycloak/protocol/cas/mappers/GroupMembershipMapper.java | 30 +--
src/main/java/org/keycloak/protocol/cas/mappers/CASAttributeMapperHelper.java | 28 +++
src/main/java/org/keycloak/protocol/cas/mappers/HardcodedClaim.java | 8
src/main/java/org/keycloak/protocol/cas/mappers/UserRealmRoleMappingMapper.java | 67 +++++++
src/main/java/org/keycloak/protocol/cas/mappers/UserAttributeMapper.java | 26 --
src/main/java/org/keycloak/protocol/cas/mappers/AbstractUserRoleMappingMapper.java | 98 ++++++++++
src/main/java/org/keycloak/protocol/cas/mappers/UserPropertyMapper.java | 25 --
src/main/java/org/keycloak/protocol/cas/mappers/UserSessionNoteMapper.java | 73 ++++++++
src/main/java/org/keycloak/protocol/cas/mappers/AbstractCASProtocolMapper.java | 16 +
src/main/java/org/keycloak/protocol/cas/utils/AttributesMapAdapter.java | 5
src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper | 3
src/main/java/org/keycloak/protocol/cas/mappers/UserClientRoleMappingMapper.java | 115 ++++++++++++
src/main/java/org/keycloak/protocol/cas/mappers/FullNameMapper.java | 22 --
13 files changed, 427 insertions(+), 89 deletions(-)
diff --git a/src/main/java/org/keycloak/protocol/cas/mappers/AbstractCASProtocolMapper.java b/src/main/java/org/keycloak/protocol/cas/mappers/AbstractCASProtocolMapper.java
index 2c19433..6838f6d 100644
--- a/src/main/java/org/keycloak/protocol/cas/mappers/AbstractCASProtocolMapper.java
+++ b/src/main/java/org/keycloak/protocol/cas/mappers/AbstractCASProtocolMapper.java
@@ -3,8 +3,12 @@
import org.keycloak.Config;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.protocol.ProtocolMapper;
import org.keycloak.protocol.cas.CASLoginProtocol;
+import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
+
+import java.util.Map;
public abstract class AbstractCASProtocolMapper implements ProtocolMapper, CASAttributeMapper {
public static final String TOKEN_MAPPER_CATEGORY = "Token mapper";
@@ -35,4 +39,16 @@
public String getDisplayCategory() {
return TOKEN_MAPPER_CATEGORY;
}
+
+ protected void setMappedAttribute(Map<String, Object> attributes, ProtocolMapperModel mappingModel, Object attributeValue) {
+ setPlainAttribute(attributes, mappingModel, OIDCAttributeMapperHelper.mapAttributeValue(mappingModel, attributeValue));
+ }
+
+ protected void setPlainAttribute(Map<String, Object> attributes, ProtocolMapperModel mappingModel, Object attributeValue) {
+ String protocolClaim = mappingModel.getConfig().get(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME);
+ if (protocolClaim == null || attributeValue == null) {
+ return;
+ }
+ attributes.put(protocolClaim, attributeValue);
+ }
}
diff --git a/src/main/java/org/keycloak/protocol/cas/mappers/AbstractUserRoleMappingMapper.java b/src/main/java/org/keycloak/protocol/cas/mappers/AbstractUserRoleMappingMapper.java
new file mode 100644
index 0000000..93f59f1
--- /dev/null
+++ b/src/main/java/org/keycloak/protocol/cas/mappers/AbstractUserRoleMappingMapper.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2016 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.protocol.cas.mappers;
+
+import org.keycloak.models.*;
+import org.keycloak.models.utils.RoleUtils;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * Base class for mapping of user role mappings to an ID and Access Token claim.
+ *
+ * @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
+ */
+abstract class AbstractUserRoleMappingMapper extends AbstractCASProtocolMapper {
+
+ /**
+ * Returns a stream with roles that come from:
+ * <ul>
+ * <li>Direct assignment of the role to the user</li>
+ * <li>Direct assignment of the role to any group of the user or any of its parent group</li>
+ * <li>Composite roles are expanded recursively, the composite role itself is also contained in the returned stream</li>
+ * </ul>
+ * @param user User to enumerate the roles for
+ */
+ public Stream<RoleModel> getAllUserRolesStream(UserModel user) {
+ return Stream.concat(
+ user.getRoleMappings().stream(),
+ user.getGroups().stream()
+ .flatMap(this::groupAndItsParentsStream)
+ .flatMap(g -> g.getRoleMappings().stream()))
+ .flatMap(RoleUtils::expandCompositeRolesStream);
+ }
+
+ /**
+ * Returns stream of the given group and its parents (recursively).
+ * @param group
+ * @return
+ */
+ private Stream<GroupModel> groupAndItsParentsStream(GroupModel group) {
+ Stream.Builder<GroupModel> sb = Stream.builder();
+ while (group != null) {
+ sb.add(group);
+ group = group.getParent();
+ }
+ return sb.build();
+ }
+
+ /**
+ * Retrieves all roles of the current user based on direct roles set to the user, its groups and their parent groups.
+ * Then it recursively expands all composite roles, and restricts according to the given predicate {@code restriction}.
+ * If the current client sessions is restricted (i.e. no client found in active user session has full scope allowed),
+ * the final list of roles is also restricted by the client scope. Finally, the list is mapped to the token into
+ * a claim.
+ */
+ protected void setAttribute(Map<String, Object> attributes, ProtocolMapperModel mappingModel, UserSessionModel userSession,
+ Predicate<RoleModel> restriction, String prefix) {
+ String rolePrefix = prefix == null ? "" : prefix;
+ UserModel user = userSession.getUser();
+
+ // get a set of all realm roles assigned to the user or its group
+ Stream<RoleModel> clientUserRoles = getAllUserRolesStream(user).filter(restriction);
+
+ boolean dontLimitScope = userSession.getClientSessions().stream().anyMatch(cs -> cs.getClient().isFullScopeAllowed());
+ if (! dontLimitScope) {
+ Set<RoleModel> clientRoles = userSession.getClientSessions().stream()
+ .flatMap(cs -> cs.getClient().getScopeMappings().stream())
+ .collect(Collectors.toSet());
+
+ clientUserRoles = clientUserRoles.filter(clientRoles::contains);
+ }
+
+ Set<String> realmRoleNames = clientUserRoles
+ .map(m -> rolePrefix + m.getName())
+ .collect(Collectors.toSet());
+
+ setPlainAttribute(attributes, mappingModel, realmRoleNames);
+ }
+}
diff --git a/src/main/java/org/keycloak/protocol/cas/mappers/CASAttributeMapperHelper.java b/src/main/java/org/keycloak/protocol/cas/mappers/CASAttributeMapperHelper.java
new file mode 100644
index 0000000..53ba5d2
--- /dev/null
+++ b/src/main/java/org/keycloak/protocol/cas/mappers/CASAttributeMapperHelper.java
@@ -0,0 +1,28 @@
+package org.keycloak.protocol.cas.mappers;
+
+import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.protocol.cas.CASLoginProtocol;
+import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class CASAttributeMapperHelper {
+ public static ProtocolMapperModel createClaimMapper(String name,
+ String tokenClaimName, String claimType,
+ boolean consentRequired, String consentText,
+ String mapperId) {
+ ProtocolMapperModel mapper = new ProtocolMapperModel();
+ mapper.setName(name);
+ mapper.setProtocolMapper(mapperId);
+ mapper.setProtocol(CASLoginProtocol.LOGIN_PROTOCOL);
+ mapper.setConsentRequired(consentRequired);
+ mapper.setConsentText(consentText);
+ Map<String, String> config = new HashMap<String, String>();
+ config.put(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME, tokenClaimName);
+ config.put(OIDCAttributeMapperHelper.JSON_TYPE, claimType);
+ mapper.setConfig(config);
+ return mapper;
+ }
+
+}
diff --git a/src/main/java/org/keycloak/protocol/cas/mappers/FullNameMapper.java b/src/main/java/org/keycloak/protocol/cas/mappers/FullNameMapper.java
index e66da7d..aef4b51 100644
--- a/src/main/java/org/keycloak/protocol/cas/mappers/FullNameMapper.java
+++ b/src/main/java/org/keycloak/protocol/cas/mappers/FullNameMapper.java
@@ -3,16 +3,12 @@
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
-import org.keycloak.protocol.cas.CASLoginProtocol;
import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
import org.keycloak.provider.ProviderConfigProperty;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
-
-import static org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME;
public class FullNameMapper extends AbstractCASProtocolMapper {
private static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
@@ -47,26 +43,14 @@
@Override
public void setAttribute(Map<String, Object> attributes, ProtocolMapperModel mappingModel, UserSessionModel userSession) {
UserModel user = userSession.getUser();
- String protocolClaim = mappingModel.getConfig().get(TOKEN_CLAIM_NAME);
- if (protocolClaim == null) {
- return;
- }
String first = user.getFirstName() == null ? "" : user.getFirstName() + " ";
String last = user.getLastName() == null ? "" : user.getLastName();
- attributes.put(protocolClaim, first + last);
+ setMappedAttribute(attributes, mappingModel, first + last);
}
public static ProtocolMapperModel create(String name, String tokenClaimName,
boolean consentRequired, String consentText) {
- ProtocolMapperModel mapper = new ProtocolMapperModel();
- mapper.setName(name);
- mapper.setProtocolMapper(PROVIDER_ID);
- mapper.setProtocol(CASLoginProtocol.LOGIN_PROTOCOL);
- mapper.setConsentRequired(consentRequired);
- mapper.setConsentText(consentText);
- Map<String, String> config = new HashMap<String, String>();
- config.put(TOKEN_CLAIM_NAME, tokenClaimName);
- mapper.setConfig(config);
- return mapper;
+ return CASAttributeMapperHelper.createClaimMapper(name, tokenClaimName,
+ "String", consentRequired, consentText, PROVIDER_ID);
}
}
diff --git a/src/main/java/org/keycloak/protocol/cas/mappers/GroupMembershipMapper.java b/src/main/java/org/keycloak/protocol/cas/mappers/GroupMembershipMapper.java
index 6d9c8ac..a6db974 100644
--- a/src/main/java/org/keycloak/protocol/cas/mappers/GroupMembershipMapper.java
+++ b/src/main/java/org/keycloak/protocol/cas/mappers/GroupMembershipMapper.java
@@ -4,19 +4,23 @@
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.utils.ModelToRepresentation;
-import org.keycloak.protocol.cas.CASLoginProtocol;
import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
import org.keycloak.provider.ProviderConfigProperty;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
public class GroupMembershipMapper extends AbstractCASProtocolMapper {
private static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
+ private static final String FULL_PATH = "full.path";
+
static {
OIDCAttributeMapperHelper.addTokenClaimNameConfig(configProperties);
ProviderConfigProperty property1 = new ProviderConfigProperty();
- property1.setName("full.path");
+ property1.setName(FULL_PATH);
property1.setLabel("Full group path");
property1.setType(ProviderConfigProperty.BOOLEAN_TYPE);
property1.setDefaultValue("true");
@@ -58,28 +62,18 @@
membership.add(group.getName());
}
}
- String protocolClaim = mappingModel.getConfig().get(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME);
-
- attributes.put(protocolClaim, membership);
+ setPlainAttribute(attributes, mappingModel, membership);
}
public static boolean useFullPath(ProtocolMapperModel mappingModel) {
- return "true".equals(mappingModel.getConfig().get("full.path"));
+ return "true".equals(mappingModel.getConfig().get(FULL_PATH));
}
public static ProtocolMapperModel create(String name, String tokenClaimName,
boolean consentRequired, String consentText, boolean fullPath) {
- ProtocolMapperModel mapper = new ProtocolMapperModel();
- mapper.setName(name);
- mapper.setProtocolMapper(PROVIDER_ID);
- mapper.setProtocol(CASLoginProtocol.LOGIN_PROTOCOL);
- mapper.setConsentRequired(consentRequired);
- mapper.setConsentText(consentText);
- Map<String, String> config = new HashMap<String, String>();
- config.put(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME, tokenClaimName);
- config.put("full.path", Boolean.toString(fullPath));
- mapper.setConfig(config);
-
+ ProtocolMapperModel mapper = CASAttributeMapperHelper.createClaimMapper(name, tokenClaimName,
+ "String", consentRequired, consentText, PROVIDER_ID);
+ mapper.getConfig().put(FULL_PATH, Boolean.toString(fullPath));
return mapper;
}
}
diff --git a/src/main/java/org/keycloak/protocol/cas/mappers/HardcodedClaim.java b/src/main/java/org/keycloak/protocol/cas/mappers/HardcodedClaim.java
index df7000c..42c7535 100644
--- a/src/main/java/org/keycloak/protocol/cas/mappers/HardcodedClaim.java
+++ b/src/main/java/org/keycloak/protocol/cas/mappers/HardcodedClaim.java
@@ -54,13 +54,7 @@
@Override
public void setAttribute(Map<String, Object> attributes, ProtocolMapperModel mappingModel, UserSessionModel userSession) {
- String protocolClaim = mappingModel.getConfig().get(TOKEN_CLAIM_NAME);
- if (protocolClaim == null) {
- return;
- }
- String attributeValue = mappingModel.getConfig().get(CLAIM_VALUE);
- if (attributeValue == null) return;
- attributes.put(protocolClaim, OIDCAttributeMapperHelper.mapAttributeValue(mappingModel, attributeValue));
+ setMappedAttribute(attributes, mappingModel, mappingModel.getConfig().get(CLAIM_VALUE));
}
}
diff --git a/src/main/java/org/keycloak/protocol/cas/mappers/UserAttributeMapper.java b/src/main/java/org/keycloak/protocol/cas/mappers/UserAttributeMapper.java
index 3637069..19173c2 100644
--- a/src/main/java/org/keycloak/protocol/cas/mappers/UserAttributeMapper.java
+++ b/src/main/java/org/keycloak/protocol/cas/mappers/UserAttributeMapper.java
@@ -5,17 +5,12 @@
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.protocol.ProtocolMapperUtils;
-import org.keycloak.protocol.cas.CASLoginProtocol;
import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
import org.keycloak.provider.ProviderConfigProperty;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
-
-import static org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper.JSON_TYPE;
-import static org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME;
public class UserAttributeMapper extends AbstractCASProtocolMapper {
private static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
@@ -66,33 +61,20 @@
@Override
public void setAttribute(Map<String, Object> attributes, ProtocolMapperModel mappingModel, UserSessionModel userSession) {
UserModel user = userSession.getUser();
- String protocolClaim = mappingModel.getConfig().get(TOKEN_CLAIM_NAME);
- if (protocolClaim == null) {
- return;
- }
String attributeName = mappingModel.getConfig().get(ProtocolMapperUtils.USER_ATTRIBUTE);
List<String> attributeValue = KeycloakModelUtils.resolveAttribute(user, attributeName);
- if (attributeValue == null) return;
- attributes.put(protocolClaim, OIDCAttributeMapperHelper.mapAttributeValue(mappingModel, attributeValue));
+ setMappedAttribute(attributes, mappingModel, attributeValue);
}
public static ProtocolMapperModel create(String name, String userAttribute,
String tokenClaimName, String claimType,
boolean consentRequired, String consentText, boolean multivalued) {
- ProtocolMapperModel mapper = new ProtocolMapperModel();
- mapper.setName(name);
- mapper.setProtocolMapper(PROVIDER_ID);
- mapper.setProtocol(CASLoginProtocol.LOGIN_PROTOCOL);
- mapper.setConsentRequired(consentRequired);
- mapper.setConsentText(consentText);
- Map<String, String> config = new HashMap<String, String>();
- config.put(ProtocolMapperUtils.USER_ATTRIBUTE, userAttribute);
- config.put(TOKEN_CLAIM_NAME, tokenClaimName);
- config.put(JSON_TYPE, claimType);
+ ProtocolMapperModel mapper = CASAttributeMapperHelper.createClaimMapper(name, tokenClaimName,
+ claimType, consentRequired, consentText, PROVIDER_ID);
+ mapper.getConfig().put(ProtocolMapperUtils.USER_ATTRIBUTE, userAttribute);
if (multivalued) {
mapper.getConfig().put(ProtocolMapperUtils.MULTIVALUED, "true");
}
- mapper.setConfig(config);
return mapper;
}
}
diff --git a/src/main/java/org/keycloak/protocol/cas/mappers/UserClientRoleMappingMapper.java b/src/main/java/org/keycloak/protocol/cas/mappers/UserClientRoleMappingMapper.java
new file mode 100644
index 0000000..15ff8ac
--- /dev/null
+++ b/src/main/java/org/keycloak/protocol/cas/mappers/UserClientRoleMappingMapper.java
@@ -0,0 +1,115 @@
+package org.keycloak.protocol.cas.mappers;
+
+import org.keycloak.models.*;
+import org.keycloak.protocol.ProtocolMapperUtils;
+import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
+import org.keycloak.provider.ProviderConfigProperty;
+
+import java.util.*;
+import java.util.function.Predicate;
+
+public class UserClientRoleMappingMapper extends AbstractUserRoleMappingMapper {
+
+ public static final String PROVIDER_ID = "cas-usermodel-client-role-mapper";
+
+ private static final List<ProviderConfigProperty> CONFIG_PROPERTIES = new ArrayList<>();
+
+ static {
+
+ ProviderConfigProperty clientId = new ProviderConfigProperty();
+ clientId.setName(ProtocolMapperUtils.USER_MODEL_CLIENT_ROLE_MAPPING_CLIENT_ID);
+ clientId.setLabel(ProtocolMapperUtils.USER_MODEL_CLIENT_ROLE_MAPPING_CLIENT_ID_LABEL);
+ clientId.setHelpText(ProtocolMapperUtils.USER_MODEL_CLIENT_ROLE_MAPPING_CLIENT_ID_HELP_TEXT);
+ clientId.setType(ProviderConfigProperty.CLIENT_LIST_TYPE);
+ CONFIG_PROPERTIES.add(clientId);
+
+ ProviderConfigProperty clientRolePrefix = new ProviderConfigProperty();
+ clientRolePrefix.setName(ProtocolMapperUtils.USER_MODEL_CLIENT_ROLE_MAPPING_ROLE_PREFIX);
+ clientRolePrefix.setLabel(ProtocolMapperUtils.USER_MODEL_CLIENT_ROLE_MAPPING_ROLE_PREFIX_LABEL);
+ clientRolePrefix.setHelpText(ProtocolMapperUtils.USER_MODEL_CLIENT_ROLE_MAPPING_ROLE_PREFIX_HELP_TEXT);
+ clientRolePrefix.setType(ProviderConfigProperty.STRING_TYPE);
+ CONFIG_PROPERTIES.add(clientRolePrefix);
+
+ OIDCAttributeMapperHelper.addTokenClaimNameConfig(CONFIG_PROPERTIES);
+ }
+
+ @Override
+ public List<ProviderConfigProperty> getConfigProperties() {
+ return CONFIG_PROPERTIES;
+ }
+
+ @Override
+ public String getId() {
+ return PROVIDER_ID;
+ }
+
+ @Override
+ public String getDisplayType() {
+ return "User Client Role";
+ }
+
+ @Override
+ public String getDisplayCategory() {
+ return TOKEN_MAPPER_CATEGORY;
+ }
+
+ @Override
+ public String getHelpText() {
+ return "Map a user client role to a token claim.";
+ }
+
+ @Override
+ public void setAttribute(Map<String, Object> attributes, ProtocolMapperModel mappingModel, UserSessionModel userSession) {
+ String clientId = mappingModel.getConfig().get(ProtocolMapperUtils.USER_MODEL_CLIENT_ROLE_MAPPING_CLIENT_ID);
+ String rolePrefix = mappingModel.getConfig().get(ProtocolMapperUtils.USER_MODEL_CLIENT_ROLE_MAPPING_ROLE_PREFIX);
+
+ setAttribute(attributes, mappingModel, userSession, getClientRoleFilter(clientId, userSession), rolePrefix);
+ }
+
+ private static Predicate<RoleModel> getClientRoleFilter(String clientId, UserSessionModel userSession) {
+ if (clientId == null) {
+ return RoleModel::isClientRole;
+ }
+
+ RealmModel clientRealm = userSession.getRealm();
+ ClientModel client = clientRealm.getClientByClientId(clientId.trim());
+
+ if (client == null) {
+ return RoleModel::isClientRole;
+ }
+
+ ClientTemplateModel template = client.getClientTemplate();
+ boolean useTemplateScope = template != null && client.useTemplateScope();
+ boolean fullScopeAllowed = (useTemplateScope && template.isFullScopeAllowed()) || client.isFullScopeAllowed();
+
+ Set<RoleModel> clientRoleMappings = client.getRoles();
+ if (fullScopeAllowed) {
+ return clientRoleMappings::contains;
+ }
+
+ Set<RoleModel> scopeMappings = new HashSet<>();
+
+ if (useTemplateScope) {
+ Set<RoleModel> templateScopeMappings = template.getScopeMappings();
+ if (templateScopeMappings != null) {
+ scopeMappings.addAll(templateScopeMappings);
+ }
+ }
+
+ Set<RoleModel> clientScopeMappings = client.getScopeMappings();
+ if (clientScopeMappings != null) {
+ scopeMappings.addAll(clientScopeMappings);
+ }
+
+ return role -> clientRoleMappings.contains(role) && scopeMappings.contains(role);
+ }
+
+ public static ProtocolMapperModel create(String clientId, String clientRolePrefix,
+ String name, String tokenClaimName) {
+ ProtocolMapperModel mapper = CASAttributeMapperHelper.createClaimMapper(name, tokenClaimName,
+ "String", true, name, PROVIDER_ID);
+ mapper.getConfig().put(ProtocolMapperUtils.USER_MODEL_CLIENT_ROLE_MAPPING_CLIENT_ID, clientId);
+ mapper.getConfig().put(ProtocolMapperUtils.USER_MODEL_CLIENT_ROLE_MAPPING_ROLE_PREFIX, clientRolePrefix);
+ return mapper;
+ }
+}
diff --git a/src/main/java/org/keycloak/protocol/cas/mappers/UserPropertyMapper.java b/src/main/java/org/keycloak/protocol/cas/mappers/UserPropertyMapper.java
index 057636d..b299b27 100644
--- a/src/main/java/org/keycloak/protocol/cas/mappers/UserPropertyMapper.java
+++ b/src/main/java/org/keycloak/protocol/cas/mappers/UserPropertyMapper.java
@@ -4,17 +4,12 @@
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.protocol.ProtocolMapperUtils;
-import org.keycloak.protocol.cas.CASLoginProtocol;
import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
import org.keycloak.provider.ProviderConfigProperty;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
-
-import static org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper.JSON_TYPE;
-import static org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME;
public class UserPropertyMapper extends AbstractCASProtocolMapper {
private static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
@@ -57,29 +52,17 @@
@Override
public void setAttribute(Map<String, Object> attributes, ProtocolMapperModel mappingModel, UserSessionModel userSession) {
UserModel user = userSession.getUser();
- String protocolClaim = mappingModel.getConfig().get(TOKEN_CLAIM_NAME);
- if (protocolClaim == null) {
- return;
- }
String propertyName = mappingModel.getConfig().get(ProtocolMapperUtils.USER_ATTRIBUTE);
String propertyValue = ProtocolMapperUtils.getUserModelValue(user, propertyName);
- attributes.put(protocolClaim, OIDCAttributeMapperHelper.mapAttributeValue(mappingModel, propertyValue));
+ setMappedAttribute(attributes, mappingModel, propertyValue);
}
public static ProtocolMapperModel create(String name, String userAttribute,
String tokenClaimName, String claimType,
boolean consentRequired, String consentText) {
- ProtocolMapperModel mapper = new ProtocolMapperModel();
- mapper.setName(name);
- mapper.setProtocolMapper(PROVIDER_ID);
- mapper.setProtocol(CASLoginProtocol.LOGIN_PROTOCOL);
- mapper.setConsentRequired(consentRequired);
- mapper.setConsentText(consentText);
- Map<String, String> config = new HashMap<String, String>();
- config.put(ProtocolMapperUtils.USER_ATTRIBUTE, userAttribute);
- config.put(TOKEN_CLAIM_NAME, tokenClaimName);
- config.put(JSON_TYPE, claimType);
- mapper.setConfig(config);
+ ProtocolMapperModel mapper = CASAttributeMapperHelper.createClaimMapper(name, tokenClaimName,
+ claimType, consentRequired, consentText, PROVIDER_ID);
+ mapper.getConfig().put(ProtocolMapperUtils.USER_ATTRIBUTE, userAttribute);
return mapper;
}
}
diff --git a/src/main/java/org/keycloak/protocol/cas/mappers/UserRealmRoleMappingMapper.java b/src/main/java/org/keycloak/protocol/cas/mappers/UserRealmRoleMappingMapper.java
new file mode 100644
index 0000000..117264a
--- /dev/null
+++ b/src/main/java/org/keycloak/protocol/cas/mappers/UserRealmRoleMappingMapper.java
@@ -0,0 +1,67 @@
+package org.keycloak.protocol.cas.mappers;
+
+import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.protocol.ProtocolMapperUtils;
+import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
+import org.keycloak.provider.ProviderConfigProperty;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class UserRealmRoleMappingMapper extends AbstractUserRoleMappingMapper {
+ public static final String PROVIDER_ID = "cas-usermodel-realm-role-mapper";
+
+ private static final List<ProviderConfigProperty> CONFIG_PROPERTIES = new ArrayList<>();
+
+ static {
+
+ ProviderConfigProperty realmRolePrefix = new ProviderConfigProperty();
+ realmRolePrefix.setName(ProtocolMapperUtils.USER_MODEL_REALM_ROLE_MAPPING_ROLE_PREFIX);
+ realmRolePrefix.setLabel(ProtocolMapperUtils.USER_MODEL_REALM_ROLE_MAPPING_ROLE_PREFIX_LABEL);
+ realmRolePrefix.setHelpText(ProtocolMapperUtils.USER_MODEL_REALM_ROLE_MAPPING_ROLE_PREFIX_HELP_TEXT);
+ realmRolePrefix.setType(ProviderConfigProperty.STRING_TYPE);
+ CONFIG_PROPERTIES.add(realmRolePrefix);
+
+ OIDCAttributeMapperHelper.addTokenClaimNameConfig(CONFIG_PROPERTIES);
+ }
+
+ @Override
+ public List<ProviderConfigProperty> getConfigProperties() {
+ return CONFIG_PROPERTIES;
+ }
+
+ @Override
+ public String getId() {
+ return PROVIDER_ID;
+ }
+
+ @Override
+ public String getDisplayType() {
+ return "User Realm Role";
+ }
+
+ @Override
+ public String getDisplayCategory() {
+ return TOKEN_MAPPER_CATEGORY;
+ }
+
+ @Override
+ public String getHelpText() {
+ return "Map a user realm role to a token claim.";
+ }
+
+ @Override
+ public void setAttribute(Map<String, Object> attributes, ProtocolMapperModel mappingModel, UserSessionModel userSession) {
+ String rolePrefix = mappingModel.getConfig().get(ProtocolMapperUtils.USER_MODEL_REALM_ROLE_MAPPING_ROLE_PREFIX);
+ setAttribute(attributes, mappingModel, userSession, role -> ! role.isClientRole(), rolePrefix);
+ }
+
+ public static ProtocolMapperModel create(String realmRolePrefix, String name, String tokenClaimName) {
+ ProtocolMapperModel mapper = CASAttributeMapperHelper.createClaimMapper(name, tokenClaimName,
+ "String", true, name, PROVIDER_ID);
+ mapper.getConfig().put(ProtocolMapperUtils.USER_MODEL_REALM_ROLE_MAPPING_ROLE_PREFIX, realmRolePrefix);
+ return mapper;
+ }
+}
diff --git a/src/main/java/org/keycloak/protocol/cas/mappers/UserSessionNoteMapper.java b/src/main/java/org/keycloak/protocol/cas/mappers/UserSessionNoteMapper.java
new file mode 100644
index 0000000..5c2881a
--- /dev/null
+++ b/src/main/java/org/keycloak/protocol/cas/mappers/UserSessionNoteMapper.java
@@ -0,0 +1,73 @@
+package org.keycloak.protocol.cas.mappers;
+
+import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.protocol.ProtocolMapperUtils;
+import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
+import org.keycloak.provider.ProviderConfigProperty;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class UserSessionNoteMapper extends AbstractCASProtocolMapper {
+
+ private static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
+
+ static {
+ ProviderConfigProperty property;
+ property = new ProviderConfigProperty();
+ property.setName(ProtocolMapperUtils.USER_SESSION_NOTE);
+ property.setLabel(ProtocolMapperUtils.USER_SESSION_MODEL_NOTE_LABEL);
+ property.setHelpText(ProtocolMapperUtils.USER_SESSION_MODEL_NOTE_HELP_TEXT);
+ property.setType(ProviderConfigProperty.STRING_TYPE);
+ configProperties.add(property);
+ OIDCAttributeMapperHelper.addTokenClaimNameConfig(configProperties);
+ OIDCAttributeMapperHelper.addJsonTypeConfig(configProperties);
+ }
+
+ public static final String PROVIDER_ID = "cas-usersessionmodel-note-mapper";
+
+
+ public List<ProviderConfigProperty> getConfigProperties() {
+ return configProperties;
+ }
+
+ @Override
+ public String getId() {
+ return PROVIDER_ID;
+ }
+
+ @Override
+ public String getDisplayType() {
+ return "User Session Note";
+ }
+
+ @Override
+ public String getDisplayCategory() {
+ return TOKEN_MAPPER_CATEGORY;
+ }
+
+ @Override
+ public String getHelpText() {
+ return "Map a custom user session note to a token claim.";
+ }
+
+ @Override
+ public void setAttribute(Map<String, Object> attributes, ProtocolMapperModel mappingModel, UserSessionModel userSession) {
+ String noteName = mappingModel.getConfig().get(ProtocolMapperUtils.USER_SESSION_NOTE);
+ String noteValue = userSession.getNote(noteName);
+ if (noteValue == null) return;
+ setMappedAttribute(attributes, mappingModel, noteValue);
+ }
+
+ public static ProtocolMapperModel create(String name,
+ String userSessionNote,
+ String tokenClaimName, String jsonType,
+ boolean consentRequired, String consentText) {
+ ProtocolMapperModel mapper = CASAttributeMapperHelper.createClaimMapper(name, tokenClaimName,
+ jsonType, consentRequired, consentText, PROVIDER_ID);
+ mapper.getConfig().put(ProtocolMapperUtils.USER_SESSION_NOTE, userSessionNote);
+ return mapper;
+ }
+}
diff --git a/src/main/java/org/keycloak/protocol/cas/utils/AttributesMapAdapter.java b/src/main/java/org/keycloak/protocol/cas/utils/AttributesMapAdapter.java
index bf9b148..ca8f7ed 100644
--- a/src/main/java/org/keycloak/protocol/cas/utils/AttributesMapAdapter.java
+++ b/src/main/java/org/keycloak/protocol/cas/utils/AttributesMapAdapter.java
@@ -10,6 +10,7 @@
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.namespace.QName;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -37,8 +38,8 @@
AttributeWrapperType(Map<String, Object> attributes) {
this.elements = new ArrayList<>();
for (Map.Entry<String, Object> entry : attributes.entrySet()) {
- if (entry.getValue() instanceof List) {
- for (Object item : ((List) entry.getValue())) {
+ if (entry.getValue() instanceof Collection) {
+ for (Object item : ((Collection) entry.getValue())) {
addElement(entry.getKey(), item);
}
} else {
diff --git a/src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper b/src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper
index 46409eb..353f1c8 100644
--- a/src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper
+++ b/src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper
@@ -19,4 +19,7 @@
org.keycloak.protocol.cas.mappers.GroupMembershipMapper
org.keycloak.protocol.cas.mappers.HardcodedClaim
org.keycloak.protocol.cas.mappers.UserAttributeMapper
+org.keycloak.protocol.cas.mappers.UserClientRoleMappingMapper
org.keycloak.protocol.cas.mappers.UserPropertyMapper
+org.keycloak.protocol.cas.mappers.UserRealmRoleMappingMapper
+org.keycloak.protocol.cas.mappers.UserSessionNoteMapper
--
Gitblit v1.9.1