Skip to content

Commit

Permalink
Use groups attribute mapping to propogate id token roles
Browse files Browse the repository at this point in the history
create attribute mapping for user name

[#115082717] https://www.pivotaltracker.com/story/show/115082717

Signed-off-by: Jonathan Lo <jlo@us.ibm.com>
  • Loading branch information
Priyata25 authored and cf-identity committed Mar 25, 2016
1 parent 408e9a1 commit 39aa3cd
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 35 deletions.
Expand Up @@ -27,6 +27,7 @@ public class ExternalIdentityProviderDefinition extends AbstractIdentityProvider
public static final String FAMILY_NAME_ATTRIBUTE_NAME = "family_name"; //can be a string public static final String FAMILY_NAME_ATTRIBUTE_NAME = "family_name"; //can be a string
public static final String PHONE_NUMBER_ATTRIBUTE_NAME = "phone_number"; //can be a string public static final String PHONE_NUMBER_ATTRIBUTE_NAME = "phone_number"; //can be a string
public static final String USER_ATTRIBUTE_PREFIX = "user.attribute."; public static final String USER_ATTRIBUTE_PREFIX = "user.attribute.";
public static final String USER_NAME_ATTRIBUTE_PREFIX = "user_name";


public static final String EXTERNAL_GROUPS_WHITELIST = "externalGroupsWhitelist"; public static final String EXTERNAL_GROUPS_WHITELIST = "externalGroupsWhitelist";
public static final String ATTRIBUTE_MAPPINGS = "attributeMappings"; public static final String ATTRIBUTE_MAPPINGS = "attributeMappings";
Expand Down
Expand Up @@ -13,19 +13,17 @@


package org.cloudfoundry.identity.uaa.provider.oauth; package org.cloudfoundry.identity.uaa.provider.oauth;


import com.fasterxml.jackson.core.type.TypeReference;
import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Base64;
import org.cloudfoundry.identity.uaa.authentication.manager.ExternalGroupAuthorizationEvent; import org.cloudfoundry.identity.uaa.authentication.manager.ExternalGroupAuthorizationEvent;
import org.cloudfoundry.identity.uaa.authentication.manager.ExternalLoginAuthenticationManager; import org.cloudfoundry.identity.uaa.authentication.manager.ExternalLoginAuthenticationManager;
import org.cloudfoundry.identity.uaa.oauth.jwt.Jwt; import org.cloudfoundry.identity.uaa.oauth.jwt.Jwt;
import org.cloudfoundry.identity.uaa.oauth.jwt.JwtHelper; import org.cloudfoundry.identity.uaa.oauth.jwt.JwtHelper;
import org.cloudfoundry.identity.uaa.oauth.token.Claims;
import org.cloudfoundry.identity.uaa.provider.AbstractXOAuthIdentityProviderDefinition; import org.cloudfoundry.identity.uaa.provider.AbstractXOAuthIdentityProviderDefinition;
import org.cloudfoundry.identity.uaa.provider.IdentityProvider; import org.cloudfoundry.identity.uaa.provider.IdentityProvider;
import org.cloudfoundry.identity.uaa.provider.IdentityProviderProvisioning; import org.cloudfoundry.identity.uaa.provider.IdentityProviderProvisioning;
import org.cloudfoundry.identity.uaa.provider.RawXOAuthIdentityProviderDefinition; import org.cloudfoundry.identity.uaa.provider.RawXOAuthIdentityProviderDefinition;
import org.cloudfoundry.identity.uaa.provider.XOIDCIdentityProviderDefinition; import org.cloudfoundry.identity.uaa.provider.XOIDCIdentityProviderDefinition;
import org.cloudfoundry.identity.uaa.provider.ldap.ExtendedLdapUserDetails;
import org.cloudfoundry.identity.uaa.user.UaaAuthority;
import org.cloudfoundry.identity.uaa.user.UaaUser; import org.cloudfoundry.identity.uaa.user.UaaUser;
import org.cloudfoundry.identity.uaa.user.UaaUserPrototype; import org.cloudfoundry.identity.uaa.user.UaaUserPrototype;
import org.cloudfoundry.identity.uaa.util.JsonUtils; import org.cloudfoundry.identity.uaa.util.JsonUtils;
Expand All @@ -35,23 +33,32 @@
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap; import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException; import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;


import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;


import static org.cloudfoundry.identity.uaa.oauth.token.CompositeAccessToken.ID_TOKEN; import static org.cloudfoundry.identity.uaa.oauth.token.CompositeAccessToken.ID_TOKEN;
import static org.cloudfoundry.identity.uaa.provider.ExternalIdentityProviderDefinition.GROUP_ATTRIBUTE_NAME;
import static org.cloudfoundry.identity.uaa.provider.ExternalIdentityProviderDefinition.USER_NAME_ATTRIBUTE_PREFIX;


public class XOAuthAuthenticationManager extends ExternalLoginAuthenticationManager { public class XOAuthAuthenticationManager extends ExternalLoginAuthenticationManager {


Expand All @@ -76,26 +83,38 @@ protected UaaUser getUser(Authentication request) {
IdentityProvider provider = providerProvisioning.retrieveByOrigin(origin, IdentityZoneHolder.get().getId()); IdentityProvider provider = providerProvisioning.retrieveByOrigin(origin, IdentityZoneHolder.get().getId());


if (provider != null && provider.getConfig() instanceof AbstractXOAuthIdentityProviderDefinition) { if (provider != null && provider.getConfig() instanceof AbstractXOAuthIdentityProviderDefinition) {
Claims claims = getClaimsFromToken(codeToken, (AbstractXOAuthIdentityProviderDefinition) provider.getConfig()); AbstractXOAuthIdentityProviderDefinition config = (AbstractXOAuthIdentityProviderDefinition) provider.getConfig();
Map<String, Object> claims = getClaimsFromToken(codeToken, config);
if (claims == null) { if (claims == null) {
return null; return null;
} }
String email = claims.getEmail();
String username = claims.getUserName(); Map<String, Object> attributeMappings = config.getAttributeMappings();

String email = (String) claims.get("email");

String username;
String userNameAttributePrefix = (String) attributeMappings.get(USER_NAME_ATTRIBUTE_PREFIX);
if (StringUtils.hasText(userNameAttributePrefix)) {
username = (String) claims.get(userNameAttributePrefix);
} else {
username = (String) claims.get("preferred_username");
}

if (email == null) { if (email == null) {
email = generateEmailIfNull(username); email = generateEmailIfNull(username);
} }


return new UaaUser( return new UaaUser(
new UaaUserPrototype() new UaaUserPrototype()
.withEmail(email) .withEmail(email)
.withGivenName(claims.getGivenName()) .withGivenName((String) claims.get("given_name"))
.withFamilyName(claims.getFamilyName()) .withFamilyName((String) claims.get("family_name"))
.withPhoneNumber(claims.getPhoneNumber()) .withPhoneNumber((String) claims.get("phone_number"))
.withModified(new Date()) .withModified(new Date())
.withUsername(claims.getUserName()) .withUsername(username)
.withPassword("") .withPassword("")
.withAuthorities(UaaAuthority.USER_AUTHORITIES) .withAuthorities(extractXOAuthUserAuthorities(attributeMappings, claims))
.withCreated(new Date()) .withCreated(new Date())
.withOrigin(origin) .withOrigin(origin)
.withExternalId(null) .withExternalId(null)
Expand All @@ -107,6 +126,32 @@ protected UaaUser getUser(Authentication request) {
return null; return null;
} }


private List<? extends GrantedAuthority> extractXOAuthUserAuthorities(Map<String, Object> attributeMappings , Map<String, Object> claims) {
List<String> groupNames = new LinkedList<>();
if (attributeMappings.get(GROUP_ATTRIBUTE_NAME) instanceof String) {
groupNames.add((String) attributeMappings.get(GROUP_ATTRIBUTE_NAME));
} else if (attributeMappings.get(GROUP_ATTRIBUTE_NAME) instanceof Collection) {
groupNames.addAll((Collection) attributeMappings.get(GROUP_ATTRIBUTE_NAME));
}

Set<String> scopes = new HashSet<>();
for (String g : groupNames) {
Object roles = claims.get(g);
if (roles instanceof String) {
scopes.addAll(Arrays.asList(((String) roles).split(",")));
} else if (roles instanceof Collection) {
scopes.addAll((Collection<? extends String>) roles);
}
}

List<XOAuthUserAuthority> authorities = new ArrayList<>();
for (String scope : scopes) {
authorities.add(new XOAuthUserAuthority(scope));
}

return authorities;
}

@Override @Override
protected UaaUser userAuthenticated(Authentication request, UaaUser userFromRequest, UaaUser userFromDb) { protected UaaUser userAuthenticated(Authentication request, UaaUser userFromRequest, UaaUser userFromDb) {
boolean userModified = false; boolean userModified = false;
Expand Down Expand Up @@ -146,14 +191,14 @@ private String getResponseType(AbstractXOAuthIdentityProviderDefinition config)
} }
} }


private Claims getClaimsFromToken(XOAuthCodeToken codeToken, AbstractXOAuthIdentityProviderDefinition config) { private Map<String,Object> getClaimsFromToken(XOAuthCodeToken codeToken, AbstractXOAuthIdentityProviderDefinition config) {
String id_token = getTokenFromCode(codeToken, config); String id_token = getTokenFromCode(codeToken, config);
if(id_token == null) { if(id_token == null) {
return null; return null;
} }
Jwt decodeIdToken = JwtHelper.decode(id_token); Jwt decodeIdToken = JwtHelper.decode(id_token);


return JsonUtils.readValue(decodeIdToken.getClaims(), Claims.class); return JsonUtils.readValue(decodeIdToken.getClaims(), new TypeReference<Map<String, Object>>(){});
} }


private String getTokenFromCode(XOAuthCodeToken codeToken, AbstractXOAuthIdentityProviderDefinition config) { private String getTokenFromCode(XOAuthCodeToken codeToken, AbstractXOAuthIdentityProviderDefinition config) {
Expand Down
@@ -0,0 +1,30 @@
/*******************************************************************************
* Cloud Foundry
* Copyright (c) [2009-2016] Pivotal Software, Inc. All Rights Reserved.
*
* This product is licensed to you under the Apache License, Version 2.0 (the "License").
* You may not use this product except in compliance with the License.
*
* This product includes a number of subcomponents with
* separate copyright notices and license terms. Your use of these
* subcomponents is subject to the terms and conditions of the
* subcomponent's license, as noted in the LICENSE file.
*******************************************************************************/
package org.cloudfoundry.identity.uaa.provider.oauth;

import org.springframework.security.core.GrantedAuthority;

public class XOAuthUserAuthority implements GrantedAuthority {

private final String authority;

public XOAuthUserAuthority(String authority) {
this.authority = authority;
}

@Override
public String getAuthority() {
return authority;
}

}

0 comments on commit 39aa3cd

Please sign in to comment.