Skip to content

Commit

Permalink
Read groups claim from token (#1207)
Browse files Browse the repository at this point in the history
  • Loading branch information
damirabdul authored Jan 6, 2023
1 parent 4117433 commit e61acbf
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public static class OAuth2Provider {
private String logoutUri;
private String userNameAttribute;
private String adminAttribute;
private String groupsClaim;
private String adminUserInfoFlag;
private Set<String> adminGroups;
private Set<String> adminPrincipals;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package org.opendatadiscovery.oddplatform.auth.handler.impl;

import com.nimbusds.jose.shaded.json.JSONArray;
import java.util.Objects;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.opendatadiscovery.oddplatform.auth.ODDOAuth2Properties;
import org.opendatadiscovery.oddplatform.auth.handler.OAuthUserHandler;
import org.opendatadiscovery.oddplatform.auth.mapper.GrantedAuthorityExtractor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
import org.springframework.security.oauth2.core.oidc.OidcIdToken;
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import reactor.core.publisher.Mono;

import static org.opendatadiscovery.oddplatform.utils.OperationUtils.containsIgnoreCase;

@RequiredArgsConstructor
public abstract class AbstractOIDCUserHandler implements OAuthUserHandler<OidcUser, OidcUserRequest> {
private final ODDOAuth2Properties oAuth2Properties;
private final GrantedAuthorityExtractor authorityExtractor;

@Override
public Mono<OidcUser> enrichUserWithProviderInformation(final OidcUser oidcUser, final OidcUserRequest request) {
final String registrationId = request.getClientRegistration().getRegistrationId();
final ODDOAuth2Properties.OAuth2Provider provider = oAuth2Properties.getClient().get(registrationId);
final String userNameAttributeName = provider.getUserNameAttribute();
final String userNameAttribute =
Objects.requireNonNullElse(userNameAttributeName, getDefaultUsernameAttribute());
boolean isAdmin = false;
final OidcIdToken token = oidcUser.getIdToken();
if (CollectionUtils.isNotEmpty(provider.getAdminPrincipals())) {
final String adminPrincipalAttribute = StringUtils.isNotEmpty(provider.getAdminAttribute())
? provider.getAdminAttribute() : userNameAttributeName;
final String adminAttribute = token.getClaim(adminPrincipalAttribute);
final boolean containsUsername = containsIgnoreCase(provider.getAdminPrincipals(), adminAttribute);
if (containsUsername) {
isAdmin = true;
}
}
final String groupsClaim = StringUtils.isNotEmpty(provider.getGroupsClaim())
? provider.getGroupsClaim() : getDefaultGroupsClaim();
if (StringUtils.isNotEmpty(groupsClaim) && CollectionUtils.isNotEmpty(provider.getAdminGroups())) {
final JSONArray groups = token.getClaim(groupsClaim);
if (groups != null) {
final boolean containsGroup = groups.stream()
.filter(String.class::isInstance)
.map(String.class::cast)
.anyMatch(g -> containsIgnoreCase(provider.getAdminGroups(), g));
if (containsGroup) {
isAdmin = true;
}
}
}
final Set<GrantedAuthority> authorities = authorityExtractor.getAuthorities(isAdmin);
final DefaultOidcUser enrichedUser =
new DefaultOidcUser(authorities, oidcUser.getIdToken(), oidcUser.getUserInfo(), userNameAttribute);
return Mono.just(enrichedUser);
}

protected abstract String getDefaultUsernameAttribute();

protected abstract String getDefaultGroupsClaim();
}
Original file line number Diff line number Diff line change
@@ -1,74 +1,38 @@
package org.opendatadiscovery.oddplatform.auth.handler.impl;

import com.nimbusds.jose.shaded.json.JSONArray;
import java.util.Objects;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.opendatadiscovery.oddplatform.auth.ODDOAuth2Properties;
import org.opendatadiscovery.oddplatform.auth.Provider;
import org.opendatadiscovery.oddplatform.auth.condition.CognitoCondition;
import org.opendatadiscovery.oddplatform.auth.handler.OAuthUserHandler;
import org.opendatadiscovery.oddplatform.auth.mapper.GrantedAuthorityExtractor;
import org.springframework.context.annotation.Conditional;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
import org.springframework.security.oauth2.core.oidc.OidcIdToken;
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import static org.opendatadiscovery.oddplatform.utils.OperationUtils.containsIgnoreCase;

@Component
@Conditional(CognitoCondition.class)
@RequiredArgsConstructor
public class CognitoUserHandler implements OAuthUserHandler<OidcUser, OidcUserRequest> {
private static final String COGNITO_USERNAME = "cognito:username";
private static final String COGNITO_GROUPS = "cognito:groups";
private final GrantedAuthorityExtractor authorityExtractor;
private final ODDOAuth2Properties oAuth2Properties;
public class CognitoUserHandler extends AbstractOIDCUserHandler
implements OAuthUserHandler<OidcUser, OidcUserRequest> {

public CognitoUserHandler(final ODDOAuth2Properties properties,
final GrantedAuthorityExtractor authorityExtractor) {
super(properties, authorityExtractor);
}

@Override
public boolean shouldHandle(final String provider) {
return StringUtils.isNotEmpty(provider) && provider.equalsIgnoreCase(Provider.COGNITO.name());
}

@Override
public Mono<OidcUser> enrichUserWithProviderInformation(final OidcUser oidcUser,
final OidcUserRequest request) {
final String registrationId = request.getClientRegistration().getRegistrationId();
final ODDOAuth2Properties.OAuth2Provider provider = oAuth2Properties.getClient().get(registrationId);
boolean isAdmin = false;
final OidcIdToken token = oidcUser.getIdToken();
if (CollectionUtils.isNotEmpty(provider.getAdminPrincipals())) {
final String adminPrincipalAttribute = StringUtils.isNotEmpty(provider.getAdminAttribute())
? provider.getAdminAttribute() : COGNITO_USERNAME;
final String username = token.getClaim(adminPrincipalAttribute);
final boolean containsUsername = containsIgnoreCase(provider.getAdminPrincipals(), username);
if (containsUsername) {
isAdmin = true;
}
}
if (CollectionUtils.isNotEmpty(provider.getAdminGroups())) {
final JSONArray groups = token.getClaim(COGNITO_GROUPS);
if (groups != null) {
final boolean containsGroup = groups.stream()
.filter(String.class::isInstance)
.map(String.class::cast)
.anyMatch(g -> containsIgnoreCase(provider.getAdminGroups(), g));
if (containsGroup) {
isAdmin = true;
}
}
}
final Set<GrantedAuthority> authorities = authorityExtractor.getAuthorities(isAdmin);
final String userNameAttributeName = provider.getUserNameAttribute();
final String userNameAttribute = Objects.requireNonNullElse(userNameAttributeName, COGNITO_USERNAME);
final DefaultOidcUser enrichedUser =
new DefaultOidcUser(authorities, oidcUser.getIdToken(), oidcUser.getUserInfo(), userNameAttribute);
return Mono.just(enrichedUser);
protected String getDefaultUsernameAttribute() {
return "cognito:username";
}

@Override
protected String getDefaultGroupsClaim() {
return "cognito:groups";
}
}
Original file line number Diff line number Diff line change
@@ -1,36 +1,28 @@
package org.opendatadiscovery.oddplatform.auth.handler.impl;

import java.util.Arrays;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.opendatadiscovery.oddplatform.auth.ODDOAuth2Properties;
import org.opendatadiscovery.oddplatform.auth.Provider;
import org.opendatadiscovery.oddplatform.auth.condition.CustomProviderCondition;
import org.opendatadiscovery.oddplatform.auth.handler.OAuthUserHandler;
import org.opendatadiscovery.oddplatform.auth.mapper.GrantedAuthorityExtractor;
import org.springframework.context.annotation.Conditional;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
import org.springframework.security.oauth2.core.oidc.IdTokenClaimNames;
import org.springframework.security.oauth2.core.oidc.OidcIdToken;
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import static org.opendatadiscovery.oddplatform.utils.OperationUtils.containsIgnoreCase;

@Component
@Conditional(CustomProviderCondition.class)
@RequiredArgsConstructor
public class CustomOIDCUserHandler implements OAuthUserHandler<OidcUser, OidcUserRequest> {
private final ODDOAuth2Properties oAuth2Properties;
private final GrantedAuthorityExtractor authorityExtractor;
public class CustomOIDCUserHandler extends AbstractOIDCUserHandler
implements OAuthUserHandler<OidcUser, OidcUserRequest> {

public CustomOIDCUserHandler(final ODDOAuth2Properties properties,
final GrantedAuthorityExtractor authorityExtractor) {
super(properties, authorityExtractor);
}

@Override
public boolean shouldHandle(final String provider) {
Expand All @@ -42,24 +34,12 @@ public boolean shouldHandle(final String provider) {
}

@Override
public Mono<OidcUser> enrichUserWithProviderInformation(final OidcUser oidcUser, final OidcUserRequest request) {
final String registrationId = request.getClientRegistration().getRegistrationId();
final ODDOAuth2Properties.OAuth2Provider provider = oAuth2Properties.getClient().get(registrationId);
final String userNameAttributeName = provider.getUserNameAttribute();
final String userNameAttribute = Objects.requireNonNullElse(userNameAttributeName, IdTokenClaimNames.SUB);
boolean isAdmin = false;
final OidcIdToken token = oidcUser.getIdToken();
if (StringUtils.isNotEmpty(provider.getAdminAttribute())
&& CollectionUtils.isNotEmpty(provider.getAdminPrincipals())) {
final String adminAttribute = token.getClaim(provider.getAdminAttribute());
final boolean containsUsername = containsIgnoreCase(provider.getAdminPrincipals(), adminAttribute);
if (containsUsername) {
isAdmin = true;
}
}
final Set<GrantedAuthority> authorities = authorityExtractor.getAuthorities(isAdmin);
final DefaultOidcUser enrichedUser =
new DefaultOidcUser(authorities, oidcUser.getIdToken(), oidcUser.getUserInfo(), userNameAttribute);
return Mono.just(enrichedUser);
protected String getDefaultUsernameAttribute() {
return IdTokenClaimNames.SUB;
}

@Override
protected String getDefaultGroupsClaim() {
return null;
}
}

0 comments on commit e61acbf

Please sign in to comment.