Skip to content

Commit

Permalink
KEYCLOAK-8708: Provide aggregation of group attributes for mappers
Browse files Browse the repository at this point in the history
  • Loading branch information
rmartinc authored and mposolda committed Nov 6, 2018
1 parent 36b0d8b commit cbe59f0
Show file tree
Hide file tree
Showing 10 changed files with 676 additions and 9 deletions.
Expand Up @@ -54,6 +54,7 @@
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
Expand Down Expand Up @@ -409,14 +410,25 @@ public static List<String> resolveAttribute(GroupModel group, String name) {
}


public static List<String> resolveAttribute(UserModel user, String name) {
public static Collection<String> resolveAttribute(UserModel user, String name, boolean aggregateAttrs) {
List<String> values = user.getAttribute(name);
if (!values.isEmpty()) return values;
Set<String> aggrValues = new HashSet<String>();
if (!values.isEmpty()) {
if (!aggregateAttrs) {
return values;
}
aggrValues.addAll(values);
}
for (GroupModel group : user.getGroups()) {
values = resolveAttribute(group, name);
if (values != null) return values;
if (values != null && !values.isEmpty()) {
if (!aggregateAttrs) {
return values;
}
aggrValues.addAll(values);
}
}
return Collections.emptyList();
return aggrValues;
}


Expand Down
Expand Up @@ -44,6 +44,7 @@ public class ProtocolMapperUtils {
public static final String USER_ATTRIBUTE = "user.attribute";
public static final String USER_SESSION_NOTE = "user.session.note";
public static final String MULTIVALUED = "multivalued";
public static final String AGGREGATE_ATTRS = "aggregate.attrs";
public static final String USER_MODEL_PROPERTY_LABEL = "usermodel.prop.label";
public static final String USER_MODEL_PROPERTY_HELP_TEXT = "usermodel.prop.tooltip";
public static final String USER_MODEL_ATTRIBUTE_LABEL = "usermodel.attr.label";
Expand All @@ -64,7 +65,9 @@ public class ProtocolMapperUtils {
public static final String USER_SESSION_MODEL_NOTE_LABEL = "userSession.modelNote.label";
public static final String USER_SESSION_MODEL_NOTE_HELP_TEXT = "userSession.modelNote.tooltip";
public static final String MULTIVALUED_LABEL = "multivalued.label";
public static final String AGGREGATE_ATTRS_LABEL = "aggregate.attrs.label";
public static final String MULTIVALUED_HELP_TEXT = "multivalued.tooltip";
public static final String AGGREGATE_ATTRS_HELP_TEXT = "aggregate.attrs.tooltip";

// Role name mapper can move some roles to different positions
public static final int PRIORITY_ROLE_NAMES_MAPPER = 10;
Expand Down
Expand Up @@ -26,6 +26,7 @@
import org.keycloak.representations.IDToken;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
Expand Down Expand Up @@ -57,6 +58,12 @@ public class UserAttributeMapper extends AbstractOIDCProtocolMapper implements O
property.setType(ProviderConfigProperty.BOOLEAN_TYPE);
configProperties.add(property);

property = new ProviderConfigProperty();
property.setName(ProtocolMapperUtils.AGGREGATE_ATTRS);
property.setLabel(ProtocolMapperUtils.AGGREGATE_ATTRS_LABEL);
property.setHelpText(ProtocolMapperUtils.AGGREGATE_ATTRS_HELP_TEXT);
property.setType(ProviderConfigProperty.BOOLEAN_TYPE);
configProperties.add(property);
}

public static final String PROVIDER_ID = "oidc-usermodel-attribute-mapper";
Expand Down Expand Up @@ -90,7 +97,8 @@ protected void setClaim(IDToken token, ProtocolMapperModel mappingModel, UserSes

UserModel user = userSession.getUser();
String attributeName = mappingModel.getConfig().get(ProtocolMapperUtils.USER_ATTRIBUTE);
List<String> attributeValue = KeycloakModelUtils.resolveAttribute(user, attributeName);
boolean aggregateAttrs = Boolean.valueOf(mappingModel.getConfig().get(ProtocolMapperUtils.AGGREGATE_ATTRS));
Collection<String> attributeValue = KeycloakModelUtils.resolveAttribute(user, attributeName, aggregateAttrs);
if (attributeValue == null) return;
OIDCAttributeMapperHelper.mapClaim(token, mappingModel, attributeValue);
}
Expand All @@ -99,6 +107,15 @@ public static ProtocolMapperModel createClaimMapper(String name,
String userAttribute,
String tokenClaimName, String claimType,
boolean accessToken, boolean idToken, boolean multivalued) {
return createClaimMapper(name, userAttribute, tokenClaimName, claimType,
accessToken, idToken, multivalued, false);
}

public static ProtocolMapperModel createClaimMapper(String name,
String userAttribute,
String tokenClaimName, String claimType,
boolean accessToken, boolean idToken,
boolean multivalued, boolean aggregateAttrs) {
ProtocolMapperModel mapper = OIDCAttributeMapperHelper.createClaimMapper(name, userAttribute,
tokenClaimName, claimType,
accessToken, idToken,
Expand All @@ -107,6 +124,9 @@ public static ProtocolMapperModel createClaimMapper(String name,
if (multivalued) {
mapper.getConfig().put(ProtocolMapperUtils.MULTIVALUED, "true");
}
if (aggregateAttrs) {
mapper.getConfig().put(ProtocolMapperUtils.AGGREGATE_ATTRS, "true");
}

return mapper;
}
Expand Down
Expand Up @@ -26,6 +26,7 @@
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -53,7 +54,7 @@ public static void addAttribute(AttributeStatementType attributeStatement, Proto
}

public static void addAttributes(AttributeStatementType attributeStatement, ProtocolMapperModel mappingModel,
List<String> attributeValues) {
Collection<String> attributeValues) {

AttributeType attribute = createAttributeType(mappingModel);
attributeValues.forEach(attribute::addAttributeValue);
Expand Down
Expand Up @@ -27,6 +27,7 @@
import org.keycloak.protocol.ProtocolMapperUtils;
import org.keycloak.provider.ProviderConfigProperty;

import java.util.Collection;
import java.util.ArrayList;
import java.util.List;

Expand All @@ -48,6 +49,12 @@ public class UserAttributeStatementMapper extends AbstractSAMLProtocolMapper imp
configProperties.add(property);
AttributeStatementHelper.setConfigProperties(configProperties);

property = new ProviderConfigProperty();
property.setName(ProtocolMapperUtils.AGGREGATE_ATTRS);
property.setLabel(ProtocolMapperUtils.AGGREGATE_ATTRS_LABEL);
property.setHelpText(ProtocolMapperUtils.AGGREGATE_ATTRS_HELP_TEXT);
property.setType(ProviderConfigProperty.BOOLEAN_TYPE);
configProperties.add(property);
}

public static final String PROVIDER_ID = "saml-user-attribute-mapper";
Expand Down Expand Up @@ -80,7 +87,8 @@ public String getHelpText() {
public void transformAttributeStatement(AttributeStatementType attributeStatement, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, AuthenticatedClientSessionModel clientSession) {
UserModel user = userSession.getUser();
String attributeName = mappingModel.getConfig().get(ProtocolMapperUtils.USER_ATTRIBUTE);
List<String> attributeValues = KeycloakModelUtils.resolveAttribute(user, attributeName);
boolean aggregateAttrs = Boolean.valueOf(mappingModel.getConfig().get(ProtocolMapperUtils.AGGREGATE_ATTRS));
Collection<String> attributeValues = KeycloakModelUtils.resolveAttribute(user, attributeName, aggregateAttrs);
if (attributeValues.isEmpty()) return;
AttributeStatementHelper.addAttributes(attributeStatement, mappingModel, attributeValues);
}
Expand Down
Expand Up @@ -202,6 +202,10 @@ private String getAttributes() {
for (String attr : principal.getAttributes("hardcoded-attribute")) {
output += attr + ",";
}
output += "<br /> group-attribute: ";
for (String attr : principal.getAttributes("group-attribute")) {
output += attr + ",";
}

return output;
}
Expand Down

0 comments on commit cbe59f0

Please sign in to comment.