From 37b4dd7632d22436e811c0188a8562ec8a63ea4d Mon Sep 17 00:00:00 2001 From: strehle Date: Thu, 28 Nov 2024 08:38:18 +0100 Subject: [PATCH] Refactor password grant * if origin is available, retrieve IdP and check if password can be used * use always identityProviderProvisioning and remove externalOAuthProviderConfigurator --- .../PasswordGrantAuthenticationManager.java | 25 ++++++------- ...asswordGrantAuthenticationManagerTest.java | 35 +++++++++---------- 2 files changed, 29 insertions(+), 31 deletions(-) diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/authentication/manager/PasswordGrantAuthenticationManager.java b/server/src/main/java/org/cloudfoundry/identity/uaa/authentication/manager/PasswordGrantAuthenticationManager.java index fa2c4c3b17c..67a1ff97390 100644 --- a/server/src/main/java/org/cloudfoundry/identity/uaa/authentication/manager/PasswordGrantAuthenticationManager.java +++ b/server/src/main/java/org/cloudfoundry/identity/uaa/authentication/manager/PasswordGrantAuthenticationManager.java @@ -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; @@ -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; @@ -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 @@ -73,7 +71,7 @@ public Authentication authenticate(Authentication authentication) throws Authent List allowedProviders = getAllowedProviders(); String defaultProvider = IdentityZoneHolder.get().getConfig().getDefaultIdentityProvider(); UaaLoginHint loginHintToUse; - IdentityProvider identityProvider = retrieveOidcPasswordIdp(uaaLoginHint, defaultProvider, allowedProviders); + IdentityProvider identityProvider = retrievePasswordIdp(uaaLoginHint, defaultProvider, allowedProviders); List possibleProviders; if (identityProvider != null) { possibleProviders = List.of(identityProvider.getOriginKey()); @@ -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 { @@ -109,12 +107,12 @@ public Authentication authenticate(Authentication authentication) throws Authent } } - private IdentityProvider retrieveOidcPasswordIdp(UaaLoginHint loginHint, String defaultOrigin, List allowedProviders) { - IdentityProvider idp = null; + private IdentityProvider retrievePasswordIdp(UaaLoginHint loginHint, String defaultOrigin, List 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 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))) { @@ -145,8 +143,11 @@ private UaaLoginHint getUaaLoginHintForChainedAuth(List allowedProviders return loginHintToUse; } - Authentication oidcPasswordGrant(Authentication authentication, final IdentityProvider 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(); diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/authentication/manager/PasswordGrantAuthenticationManagerTest.java b/server/src/test/java/org/cloudfoundry/identity/uaa/authentication/manager/PasswordGrantAuthenticationManagerTest.java index 689d44cb41f..0dce1cc9a97 100644 --- a/server/src/test/java/org/cloudfoundry/identity/uaa/authentication/manager/PasswordGrantAuthenticationManagerTest.java +++ b/server/src/test/java/org/cloudfoundry/identity/uaa/authentication/manager/PasswordGrantAuthenticationManagerTest.java @@ -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; @@ -80,7 +79,6 @@ class PasswordGrantAuthenticationManagerTest { private IdentityProviderProvisioning identityProviderProvisioning; private RestTemplateConfig restTemplateConfig; private ExternalOAuthAuthenticationManager externalOAuthAuthenticationManager; - private ExternalOAuthProviderConfigurator externalOAuthProviderConfigurator; private ApplicationEventPublisher eventPublisher; private IdentityProvider idp; @@ -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); @@ -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"); @@ -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); @@ -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()); } @@ -184,7 +181,7 @@ void testOIDCPasswordGrant() { ArgumentCaptor 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(); @@ -238,7 +235,7 @@ void testOIDCPasswordGrantWithForwardHeader() { ArgumentCaptor 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(); @@ -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); @@ -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); @@ -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); @@ -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); @@ -540,7 +537,7 @@ void testOIDCPasswordGrantWithPrompts() { ArgumentCaptor 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(); @@ -671,7 +668,7 @@ void testOIDCPasswordGrant_NoLoginHintWithDefaultOIDC() { ArgumentCaptor 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(); @@ -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>(){})); 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()); } @@ -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>(){})); 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()); } @@ -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); @@ -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()); } @@ -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()); }