Skip to content

Commit

Permalink
Refactor password grant
Browse files Browse the repository at this point in the history
* if origin is available, retrieve IdP and check if password can be used
* use always identityProviderProvisioning and remove externalOAuthProviderConfigurator
  • Loading branch information
strehle committed Nov 28, 2024
1 parent 744700c commit 37b4dd7
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import org.cloudfoundry.identity.uaa.provider.OIDCIdentityProviderDefinition;
import org.cloudfoundry.identity.uaa.provider.oauth.ExternalOAuthAuthenticationManager;
import org.cloudfoundry.identity.uaa.provider.oauth.ExternalOAuthCodeToken;
import org.cloudfoundry.identity.uaa.provider.oauth.ExternalOAuthProviderConfigurator;
import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationEvent;
Expand All @@ -45,6 +44,7 @@
import java.net.URL;
import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Stream;

import static org.cloudfoundry.identity.uaa.oauth.token.TokenConstants.GRANT_TYPE_PASSWORD;
import static org.springframework.http.MediaType.APPLICATION_JSON;
Expand All @@ -56,15 +56,13 @@ public class PasswordGrantAuthenticationManager implements AuthenticationManager
private IdentityProviderProvisioning identityProviderProvisioning;
private RestTemplateConfig restTemplateConfig;
private ExternalOAuthAuthenticationManager externalOAuthAuthenticationManager;
private ExternalOAuthProviderConfigurator externalOAuthProviderProvisioning;
private ApplicationEventPublisher eventPublisher;

public PasswordGrantAuthenticationManager(DynamicZoneAwareAuthenticationManager zoneAwareAuthzAuthenticationManager, final @Qualifier("identityProviderProvisioning") IdentityProviderProvisioning identityProviderProvisioning, RestTemplateConfig restTemplateConfig, ExternalOAuthAuthenticationManager externalOAuthAuthenticationManager, ExternalOAuthProviderConfigurator externalOAuthProviderProvisioning) {
public PasswordGrantAuthenticationManager(DynamicZoneAwareAuthenticationManager zoneAwareAuthzAuthenticationManager, final @Qualifier("identityProviderProvisioning") IdentityProviderProvisioning identityProviderProvisioning, RestTemplateConfig restTemplateConfig, ExternalOAuthAuthenticationManager externalOAuthAuthenticationManager) {
this.zoneAwareAuthzAuthenticationManager = zoneAwareAuthzAuthenticationManager;
this.identityProviderProvisioning = identityProviderProvisioning;
this.restTemplateConfig = restTemplateConfig;
this.externalOAuthAuthenticationManager = externalOAuthAuthenticationManager;
this.externalOAuthProviderProvisioning = externalOAuthProviderProvisioning;
}

@Override
Expand All @@ -73,7 +71,7 @@ public Authentication authenticate(Authentication authentication) throws Authent
List<String> allowedProviders = getAllowedProviders();
String defaultProvider = IdentityZoneHolder.get().getConfig().getDefaultIdentityProvider();
UaaLoginHint loginHintToUse;
IdentityProvider<OIDCIdentityProviderDefinition> identityProvider = retrieveOidcPasswordIdp(uaaLoginHint, defaultProvider, allowedProviders);
IdentityProvider<?> identityProvider = retrievePasswordIdp(uaaLoginHint, defaultProvider, allowedProviders);
List<String> possibleProviders;
if (identityProvider != null) {
possibleProviders = List.of(identityProvider.getOriginKey());
Expand All @@ -87,7 +85,7 @@ public Authentication authenticate(Authentication authentication) throws Authent
} else {
loginHintToUse = getUaaLoginHintForChainedAuth(possibleProviders);
if (identityProvider == null) {
identityProvider = retrieveOidcPasswordIdp(loginHintToUse, null, null);
identityProvider = retrievePasswordIdp(loginHintToUse, null, null);
}
}
} else {
Expand All @@ -109,12 +107,12 @@ public Authentication authenticate(Authentication authentication) throws Authent
}
}

private IdentityProvider<OIDCIdentityProviderDefinition> retrieveOidcPasswordIdp(UaaLoginHint loginHint, String defaultOrigin, List<String> allowedProviders) {
IdentityProvider<OIDCIdentityProviderDefinition> idp = null;
private IdentityProvider<?> retrievePasswordIdp(UaaLoginHint loginHint, String defaultOrigin, List<String> allowedProviders) {
IdentityProvider<?> idp = null;
String useOrigin = loginHint != null && loginHint.getOrigin() != null ? loginHint.getOrigin() : defaultOrigin;
if (useOrigin != null && !useOrigin.equalsIgnoreCase(OriginKeys.UAA) && !useOrigin.equalsIgnoreCase(OriginKeys.LDAP)) {
if (useOrigin != null) {
try {
IdentityProvider<OIDCIdentityProviderDefinition> retrievedByOrigin = externalOAuthProviderProvisioning.retrieveByOrigin(useOrigin,
IdentityProvider<?> retrievedByOrigin = identityProviderProvisioning.retrieveByOrigin(useOrigin,
IdentityZoneHolder.get().getId());
if (retrievedByOrigin != null && retrievedByOrigin.isActive() && retrievedByOrigin.getOriginKey().equals(useOrigin)
&& providerSupportsPasswordGrant(retrievedByOrigin) && (allowedProviders == null || allowedProviders.contains(useOrigin))) {
Expand Down Expand Up @@ -145,8 +143,11 @@ private UaaLoginHint getUaaLoginHintForChainedAuth(List<String> allowedProviders
return loginHintToUse;
}

Authentication oidcPasswordGrant(Authentication authentication, final IdentityProvider<OIDCIdentityProviderDefinition> identityProvider) {
final OIDCIdentityProviderDefinition config = identityProvider.getConfig();
Authentication oidcPasswordGrant(Authentication authentication, final IdentityProvider<?> identityProvider) {
final OIDCIdentityProviderDefinition config = Stream.of(identityProvider).
map(i -> i.getConfig()).
filter(OIDCIdentityProviderDefinition.class::isInstance).
map(OIDCIdentityProviderDefinition.class::cast).findFirst().orElseThrow(() -> new ProviderConfigurationException("Invalid identity provider type"));

//Token per RestCall
URL tokenUrl = config.getTokenUrl();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import org.cloudfoundry.identity.uaa.provider.OIDCIdentityProviderDefinition;
import org.cloudfoundry.identity.uaa.provider.oauth.ExternalOAuthAuthenticationManager;
import org.cloudfoundry.identity.uaa.provider.oauth.ExternalOAuthCodeToken;
import org.cloudfoundry.identity.uaa.provider.oauth.ExternalOAuthProviderConfigurator;
import org.cloudfoundry.identity.uaa.util.AlphanumericRandomValueStringGenerator;
import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
import org.junit.jupiter.api.AfterEach;
Expand Down Expand Up @@ -80,7 +79,6 @@ class PasswordGrantAuthenticationManagerTest {
private IdentityProviderProvisioning identityProviderProvisioning;
private RestTemplateConfig restTemplateConfig;
private ExternalOAuthAuthenticationManager externalOAuthAuthenticationManager;
private ExternalOAuthProviderConfigurator externalOAuthProviderConfigurator;
private ApplicationEventPublisher eventPublisher;

private IdentityProvider idp;
Expand All @@ -95,7 +93,6 @@ void setUp() throws Exception {
identityProviderProvisioning = mock(IdentityProviderProvisioning.class);
restTemplateConfig = mock(RestTemplateConfig.class);
externalOAuthAuthenticationManager = mock(ExternalOAuthAuthenticationManager.class);
externalOAuthProviderConfigurator = mock(ExternalOAuthProviderConfigurator.class);

idp = mock(IdentityProvider.class);
idpConfig = mock(OIDCIdentityProviderDefinition.class);
Expand All @@ -116,7 +113,7 @@ void setUp() throws Exception {
when(ldapProvider.getOriginKey()).thenReturn(OriginKeys.LDAP);

when(identityProviderProvisioning.retrieveActive("uaa")).thenReturn(Arrays.asList(idp, uaaProvider, ldapProvider));
when(externalOAuthProviderConfigurator.retrieveByOrigin("oidcprovider", "uaa")).thenReturn(idp);
when(identityProviderProvisioning.retrieveByOrigin("oidcprovider", "uaa")).thenReturn(idp);

Authentication clientAuth = mock(Authentication.class);
when(clientAuth.getName()).thenReturn("clientid");
Expand All @@ -125,7 +122,7 @@ void setUp() throws Exception {
when(clientAuth.getPrincipal()).thenReturn(uaaClient);
when(uaaClient.getAdditionalInformation()).thenReturn(mock(Map.class));

instance = new PasswordGrantAuthenticationManager(zoneAwareAuthzAuthenticationManager, identityProviderProvisioning, restTemplateConfig, externalOAuthAuthenticationManager, externalOAuthProviderConfigurator);
instance = new PasswordGrantAuthenticationManager(zoneAwareAuthzAuthenticationManager, identityProviderProvisioning, restTemplateConfig, externalOAuthAuthenticationManager);
IdentityZoneHolder.clear();
eventPublisher = mock(ApplicationEventPublisher.class);
instance.setApplicationEventPublisher(eventPublisher);
Expand All @@ -144,7 +141,7 @@ void testPasswordGrantNoLoginHint() {
instance.authenticate(auth);

verify(zoneAwareAuthzAuthenticationManager, times(1)).authenticate(auth);
verify(externalOAuthProviderConfigurator, times(0)).retrieveByOrigin(any(), any());
verify(identityProviderProvisioning, times(0)).retrieveByOrigin(any(), any());
verify(identityProviderProvisioning, times(1)).retrieveActive(any());
}

Expand Down Expand Up @@ -184,7 +181,7 @@ void testOIDCPasswordGrant() {
ArgumentCaptor<ExternalOAuthCodeToken> tokenArgumentCaptor = ArgumentCaptor.forClass(ExternalOAuthCodeToken.class);
verify(externalOAuthAuthenticationManager, times(1)).authenticate(tokenArgumentCaptor.capture());
verify(zoneAwareAuthzAuthenticationManager, times(0)).authenticate(any());
verify(externalOAuthProviderConfigurator, times(1)).retrieveByOrigin(any(), any());
verify(identityProviderProvisioning, times(1)).retrieveByOrigin(any(), any());
verify(identityProviderProvisioning, times(0)).retrieveActive(any());

HttpEntity httpEntity = httpEntityArgumentCaptor.getValue();
Expand Down Expand Up @@ -238,7 +235,7 @@ void testOIDCPasswordGrantWithForwardHeader() {
ArgumentCaptor<ExternalOAuthCodeToken> tokenArgumentCaptor = ArgumentCaptor.forClass(ExternalOAuthCodeToken.class);
verify(externalOAuthAuthenticationManager, times(1)).authenticate(tokenArgumentCaptor.capture());
verify(zoneAwareAuthzAuthenticationManager, times(0)).authenticate(any());
verify(externalOAuthProviderConfigurator, times(1)).retrieveByOrigin(any(), any());
verify(identityProviderProvisioning, times(1)).retrieveByOrigin(any(), any());
verify(identityProviderProvisioning, times(0)).retrieveActive(any());

HttpEntity httpEntity = httpEntityArgumentCaptor.getValue();
Expand Down Expand Up @@ -317,7 +314,7 @@ void testOIDCPasswordGrantProviderNotFoundInDB() {
when(loginHint.getOrigin()).thenReturn("oidcprovider2");
Authentication auth = mock(Authentication.class);
when(zoneAwareAuthzAuthenticationManager.extractLoginHint(auth)).thenReturn(loginHint);
when(externalOAuthProviderConfigurator.retrieveByOrigin(any(), any())).thenThrow(new EmptyResultDataAccessException(1));
when(identityProviderProvisioning.retrieveByOrigin(any(), any())).thenThrow(new EmptyResultDataAccessException(1));

try {
instance.authenticate(auth);
Expand All @@ -337,7 +334,7 @@ void testOIDCPasswordGrantProviderTypeNotOidc() {
when(localIdp.getType()).thenReturn(OriginKeys.SAML);

when(identityProviderProvisioning.retrieveActive("uaa")).thenReturn(Arrays.asList(uaaProvider, ldapProvider, localIdp));
when(externalOAuthProviderConfigurator.retrieveByOrigin("oidcprovider", "uaa")).thenReturn(localIdp);
when(identityProviderProvisioning.retrieveByOrigin("oidcprovider", "uaa")).thenReturn(localIdp);
UaaLoginHint loginHint = mock(UaaLoginHint.class);
when(loginHint.getOrigin()).thenReturn("oidcprovider");
Authentication auth = mock(Authentication.class);
Expand All @@ -362,7 +359,7 @@ void testOIDCPasswordGrantProviderDoesNotSupportPassword() {
when(idpConfig.isPasswordGrantEnabled()).thenReturn(false);

when(identityProviderProvisioning.retrieveActive("uaa")).thenReturn(Arrays.asList(uaaProvider, ldapProvider, localIdp));
when(externalOAuthProviderConfigurator.retrieveByOrigin("oidcprovider", "uaa")).thenReturn(localIdp);
when(identityProviderProvisioning.retrieveByOrigin("oidcprovider", "uaa")).thenReturn(localIdp);
UaaLoginHint loginHint = mock(UaaLoginHint.class);
when(loginHint.getOrigin()).thenReturn("oidcprovider");
Authentication auth = mock(Authentication.class);
Expand All @@ -387,7 +384,7 @@ void testOIDCPasswordGrantProviderNoRelyingPartyCredentials() {
when(idpConfig.isPasswordGrantEnabled()).thenReturn(true);

when(identityProviderProvisioning.retrieveActive("uaa")).thenReturn(Arrays.asList(uaaProvider, ldapProvider, localIdp));
when(externalOAuthProviderConfigurator.retrieveByOrigin("oidcprovider", "uaa")).thenReturn(localIdp);
when(identityProviderProvisioning.retrieveByOrigin("oidcprovider", "uaa")).thenReturn(localIdp);
UaaLoginHint loginHint = mock(UaaLoginHint.class);
when(loginHint.getOrigin()).thenReturn("oidcprovider");
Authentication auth = mock(Authentication.class);
Expand Down Expand Up @@ -540,7 +537,7 @@ void testOIDCPasswordGrantWithPrompts() {
ArgumentCaptor<ExternalOAuthCodeToken> tokenArgumentCaptor = ArgumentCaptor.forClass(ExternalOAuthCodeToken.class);
verify(externalOAuthAuthenticationManager, times(1)).authenticate(tokenArgumentCaptor.capture());
verify(zoneAwareAuthzAuthenticationManager, times(0)).authenticate(any());
verify(externalOAuthProviderConfigurator, times(1)).retrieveByOrigin(any(), any());
verify(identityProviderProvisioning, times(1)).retrieveByOrigin(any(), any());
verify(identityProviderProvisioning, times(0)).retrieveActive(any());

HttpEntity httpEntity = httpEntityArgumentCaptor.getValue();
Expand Down Expand Up @@ -671,7 +668,7 @@ void testOIDCPasswordGrant_NoLoginHintWithDefaultOIDC() {
ArgumentCaptor<ExternalOAuthCodeToken> tokenArgumentCaptor = ArgumentCaptor.forClass(ExternalOAuthCodeToken.class);
verify(externalOAuthAuthenticationManager, times(1)).authenticate(tokenArgumentCaptor.capture());
verify(zoneAwareAuthzAuthenticationManager, times(0)).authenticate(any());
verify(externalOAuthProviderConfigurator, times(1)).retrieveByOrigin(any(), any());
verify(identityProviderProvisioning, times(1)).retrieveByOrigin(any(), any());
verify(identityProviderProvisioning, times(0)).retrieveActive(any());

HttpEntity httpEntity = httpEntityArgumentCaptor.getValue();
Expand Down Expand Up @@ -718,7 +715,7 @@ void testOIDCPasswordGrant_LoginHintOidcOverridesDefaultUaa() {
verify(rt, times(1)).exchange(eq("http://localhost:8080/uaa/oauth/token"), eq(HttpMethod.POST), any(HttpEntity.class),eq(new ParameterizedTypeReference<Map<String,String>>(){}));
verify(externalOAuthAuthenticationManager, times(1)).authenticate(any(ExternalOAuthCodeToken.class));
verify(zoneAwareAuthzAuthenticationManager, times(0)).authenticate(any());
verify(externalOAuthProviderConfigurator, times(1)).retrieveByOrigin(any(), any());
verify(identityProviderProvisioning, times(1)).retrieveByOrigin(any(), any());
verify(identityProviderProvisioning, times(0)).retrieveActive(any());
}

Expand Down Expand Up @@ -764,7 +761,7 @@ void testOIDCPasswordGrant_NoLoginHintDefaultNotAllowedSingleIdpOIDC() {
verify(rt, times(1)).exchange(eq("http://localhost:8080/uaa/oauth/token"), eq(HttpMethod.POST), any(HttpEntity.class),eq(new ParameterizedTypeReference<Map<String,String>>(){}));
verify(externalOAuthAuthenticationManager, times(1)).authenticate(any(ExternalOAuthCodeToken.class));
verify(zoneAwareAuthzAuthenticationManager, times(0)).authenticate(any());
verify(externalOAuthProviderConfigurator, times(1)).retrieveByOrigin(any(), any());
verify(identityProviderProvisioning, atLeast(1)).retrieveByOrigin(any(), any());
verify(identityProviderProvisioning, times(1)).retrieveActive(any());
}

Expand All @@ -783,7 +780,7 @@ void testOIDCPasswordGrant_NoLoginHintDefaultNotAllowedSingleIdpDoesNotSupportPa
when(localIdp.getType()).thenReturn(OriginKeys.OIDC10);
when(idpConfig.isPasswordGrantEnabled()).thenReturn(false);
when(identityProviderProvisioning.retrieveActive("uaa")).thenReturn(Arrays.asList(uaaProvider, ldapProvider, localIdp));
when(externalOAuthProviderConfigurator.retrieveByOrigin("oidcprovider","uaa")).thenReturn(localIdp);
when(identityProviderProvisioning.retrieveByOrigin("oidcprovider","uaa")).thenReturn(localIdp);

try {
instance.authenticate(auth);
Expand Down Expand Up @@ -822,7 +819,7 @@ void testOIDCPasswordGrant_NoLoginHintDefaultNotAllowedChainedAuth() {

verify(zoneAwareAuthzAuthenticationManager, times(1)).authenticate(auth);
verify(zoneAwareAuthzAuthenticationManager, times(0)).setLoginHint(any(), any());
verify(externalOAuthProviderConfigurator, times(1)).retrieveByOrigin(any(), any());
verify(identityProviderProvisioning, times(1)).retrieveByOrigin(any(), any());
verify(identityProviderProvisioning, times(1)).retrieveActive(any());
}

Expand Down Expand Up @@ -877,7 +874,7 @@ void testPasswordGrant_NoLoginHintNoDefaultTriesChainedAuth() {

verify(zoneAwareAuthzAuthenticationManager, times(1)).authenticate(auth);
verify(zoneAwareAuthzAuthenticationManager, times(0)).setLoginHint(any(), any());
verify(externalOAuthProviderConfigurator, times(0)).retrieveByOrigin(any(), any());
verify(identityProviderProvisioning, times(0)).retrieveByOrigin(any(), any());
verify(identityProviderProvisioning, times(1)).retrieveActive(any());
}

Expand Down

0 comments on commit 37b4dd7

Please sign in to comment.