Skip to content

Commit dd2ffac

Browse files
authored
Merge pull request #3660 from fhanik/pr/backwards-compatible-origins
Revert to legacy behavior of showing `passcode` as a prompt in /info JSON response.
2 parents 2c486b1 + ae6557c commit dd2ffac

File tree

2 files changed

+86
-62
lines changed

2 files changed

+86
-62
lines changed

server/src/main/java/org/cloudfoundry/identity/uaa/login/LoginInfoEndpoint.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -332,9 +332,11 @@ private String login(Model model, Principal principal, List<String> excludedProm
332332
} else {
333333
samlIdentityProviders = getSamlIdentityProviderDefinitions(allowedIdentityProviderKeys);
334334

335-
if (jsonResponse) {
335+
if (jsonResponse && !(IdentityZoneHolder.get().getConfig().getUserConfig().isAllowOriginLoop())) {
336336
/* the OAuth IdPs and all IdPs are used for determining the redirect; if jsonResponse is true, the
337-
* redirect is ignored anyway */
337+
* redirect is ignored anyway
338+
* When login.allowOriginLoop is explicitly set to false, do not iterate over providers
339+
*/
338340
oauthIdentityProviders = addDefaultOauthMap(oauthIdentityProviders, allowedIdentityProviderKeys, defaultIdentityProviderName);
339341
} else {
340342
oauthIdentityProviders = getOauthIdentityProviderDefinitions(allowedIdentityProviderKeys);

server/src/test/java/org/cloudfoundry/identity/uaa/login/LoginInfoEndpointTests.java

Lines changed: 82 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.cloudfoundry.identity.uaa.zone.beans.IdentityZoneManagerImpl;
3232
import org.junit.jupiter.api.AfterEach;
3333
import org.junit.jupiter.api.BeforeEach;
34+
import org.junit.jupiter.api.Nested;
3435
import org.junit.jupiter.api.Test;
3536
import org.junit.jupiter.api.extension.ExtendWith;
3637
import org.springframework.dao.DataAccessException;
@@ -816,84 +817,88 @@ void allowedIdpsforClientOIDCProvider() throws Exception {
816817
@Test
817818
void oauth_provider_links_shown() throws Exception {
818819
LoginInfoEndpoint endpoint = getEndpoint(IdentityZoneHolder.get());
819-
820-
RawExternalOAuthIdentityProviderDefinition definition = new RawExternalOAuthIdentityProviderDefinition();
821-
822-
definition.setAuthUrl(URI.create("http://auth.url").toURL());
823-
definition.setTokenUrl(URI.create("http://token.url").toURL());
824-
definition.setRelyingPartySecret("client-secret");
825-
826-
IdentityProvider<AbstractExternalOAuthIdentityProviderDefinition> identityProvider = MultitenancyFixture.identityProvider("oauth-idp-alias", "uaa");
827-
identityProvider.setConfig(definition);
828-
829-
when(mockIdentityProviderProvisioning.retrieveActiveByTypes(anyString(), any(), any())).thenReturn(singletonList(identityProvider));
820+
mockOauthProvider(true);
830821
endpoint.loginForHtml(extendedModelMap, null, new MockHttpServletRequest(), singletonList(MediaType.TEXT_HTML));
831-
832822
assertThat((Boolean) extendedModelMap.get("showLoginLinks")).isTrue();
833823
}
834824

835-
@Test
836-
void no_passcode_prompt_present_whenThereIsAtleastOneActiveOauthProvider() throws Exception {
837-
LoginInfoEndpoint endpoint = getEndpoint(IdentityZoneHolder.get());
838-
839-
RawExternalOAuthIdentityProviderDefinition definition = new RawExternalOAuthIdentityProviderDefinition()
840-
.setAuthUrl(URI.create("http://auth.url").toURL())
841-
.setTokenUrl(URI.create("http://token.url").toURL());
825+
@Nested
826+
class WhenAllowOriginLoopHasDefaultValueOfTrue {
827+
LoginInfoEndpoint endpoint = null;
828+
@BeforeEach
829+
void setup() {
830+
endpoint = getEndpoint(IdentityZoneHolder.get());
831+
}
842832

843-
IdentityProvider<AbstractExternalOAuthIdentityProviderDefinition> identityProvider = MultitenancyFixture.identityProvider("oauth-idp-alias", "uaa");
844-
identityProvider.setConfig(definition);
833+
@Test
834+
void passcode_prompt_present_whenThereIsAtleastOneActiveOauthProvider_AllowOriginLoop() throws Exception {
835+
mockOauthProvider(false);
836+
endpoint.infoForLoginJson(extendedModelMap, null, new MockHttpServletRequest("GET", "http://someurl"));
837+
Map<String, Object> mapPrompts = (Map<String, Object>) extendedModelMap.get("prompts");
838+
assertThat(mapPrompts).containsKey("passcode");
839+
}
845840

846-
when(mockIdentityProviderProvisioning.retrieveActiveByTypes(anyString(), eq(OriginKeys.OIDC10), eq(OriginKeys.OAUTH20)))
847-
.thenReturn(singletonList(identityProvider));
848-
endpoint.infoForLoginJson(extendedModelMap, null, new MockHttpServletRequest("GET", "http://someurl"));
841+
@Test
842+
void passcode_prompt_present_whenThereIsAtleastOneActiveOauthProvider_stillWorksWithAccountChooser_AllowOriginLoop() throws Exception {
843+
IdentityZoneHolder.get().getConfig().setAccountChooserEnabled(true);
844+
mockOauthProvider(false);
845+
endpoint.infoForLoginJson(extendedModelMap, null, new MockHttpServletRequest("GET", "http://someurl"));
846+
Map<String, Object> mapPrompts = (Map<String, Object>) extendedModelMap.get("prompts");
847+
assertThat(mapPrompts).containsKey("passcode");
848+
}
849849

850-
Map<String, Object> mapPrompts = (Map<String, Object>) extendedModelMap.get("prompts");
851-
assertThat(mapPrompts).doesNotContainKey("passcode");
850+
@Test
851+
void passcode_prompt_present_whenThereIsAtleastOneActiveOauthProvider_stillWorksWithDiscovery_AllowOriginLoop() throws Exception {
852+
IdentityZoneHolder.get().getConfig().setIdpDiscoveryEnabled(true);
853+
mockOauthProvider(true);
854+
endpoint.infoForLoginJson(extendedModelMap, null, new MockHttpServletRequest("GET", "http://someurl"));
855+
Map<String, Object> mapPrompts = (Map<String, Object>) extendedModelMap.get("prompts");
856+
assertThat(mapPrompts).containsKey("passcode");
857+
}
852858
}
853859

854-
@Test
855-
void no_passcode_prompt_present_whenThereIsAtleastOneActiveOauthProvider_stillWorksWithAccountChooser() throws Exception {
856-
IdentityZoneHolder.get().getConfig().setAccountChooserEnabled(true);
857-
LoginInfoEndpoint endpoint = getEndpoint(IdentityZoneHolder.get());
858-
859-
RawExternalOAuthIdentityProviderDefinition definition = new RawExternalOAuthIdentityProviderDefinition()
860-
.setAuthUrl(URI.create("http://auth.url").toURL())
861-
.setTokenUrl(URI.create("http://token.url").toURL());
860+
@Nested
861+
class WhenAllowOriginLoopIsSetToFalse {
862862

863-
IdentityProvider<AbstractExternalOAuthIdentityProviderDefinition> identityProvider = MultitenancyFixture.identityProvider("oauth-idp-alias", "uaa");
864-
identityProvider.setConfig(definition);
865-
866-
when(mockIdentityProviderProvisioning.retrieveActiveByTypes(anyString(), eq(OriginKeys.OIDC10), eq(OriginKeys.OAUTH20)))
867-
.thenReturn(singletonList(identityProvider));
868-
endpoint.infoForLoginJson(extendedModelMap, null, new MockHttpServletRequest("GET", "http://someurl"));
869-
870-
Map<String, Object> mapPrompts = (Map<String, Object>) extendedModelMap.get("prompts");
871-
assertThat(mapPrompts).doesNotContainKey("passcode");
872-
}
863+
LoginInfoEndpoint endpoint = null;
864+
@BeforeEach
865+
void setup() {
866+
IdentityZoneHolder.get().getConfig().getUserConfig().setAllowOriginLoop(false);
867+
endpoint = getEndpoint(IdentityZoneHolder.get());
868+
}
873869

874-
@Test
875-
void no_passcode_prompt_present_whenThereIsAtleastOneActiveOauthProvider_stillWorksWithDiscovery() throws Exception {
876-
IdentityZoneHolder.get().getConfig().setIdpDiscoveryEnabled(true);
877-
LoginInfoEndpoint endpoint = getEndpoint(IdentityZoneHolder.get());
870+
@Test
871+
void no_passcode_prompt_present_whenThereIsAtleastOneActiveOauthProvider() throws Exception {
872+
mockOauthProvider(false);
873+
endpoint.infoForLoginJson(extendedModelMap, null, new MockHttpServletRequest("GET", "http://someurl"));
874+
Map<String, Object> mapPrompts = (Map<String, Object>) extendedModelMap.get("prompts");
875+
assertThat(mapPrompts).doesNotContainKey("passcode");
876+
}
878877

879-
RawExternalOAuthIdentityProviderDefinition definition = new RawExternalOAuthIdentityProviderDefinition()
880-
.setAuthUrl(URI.create("http://auth.url").toURL())
881-
.setTokenUrl(URI.create("http://token.url").toURL());
882878

883-
IdentityProvider<AbstractExternalOAuthIdentityProviderDefinition> identityProvider = MultitenancyFixture.identityProvider("oauth-idp-alias", "uaa");
884-
identityProvider.setConfig(definition);
879+
@Test
880+
void no_passcode_prompt_present_whenThereIsAtleastOneActiveOauthProvider_stillWorksWithAccountChooser() throws Exception {
881+
IdentityZoneHolder.get().getConfig().setAccountChooserEnabled(true);
882+
mockOauthProvider(false);
883+
endpoint.infoForLoginJson(extendedModelMap, null, new MockHttpServletRequest("GET", "http://someurl"));
884+
Map<String, Object> mapPrompts = (Map<String, Object>) extendedModelMap.get("prompts");
885+
assertThat(mapPrompts).doesNotContainKey("passcode");
886+
}
885887

886-
when(mockIdentityProviderProvisioning.retrieveActiveByTypes(anyString(), any())).thenReturn(singletonList(identityProvider));
887-
endpoint.infoForLoginJson(extendedModelMap, null, new MockHttpServletRequest("GET", "http://someurl"));
888888

889-
Map<String, Object> mapPrompts = (Map<String, Object>) extendedModelMap.get("prompts");
890-
assertThat(mapPrompts).doesNotContainKey("passcode");
889+
@Test
890+
void no_passcode_prompt_present_whenThereIsAtleastOneActiveOauthProvider_stillWorksWithDiscovery() throws Exception {
891+
IdentityZoneHolder.get().getConfig().setIdpDiscoveryEnabled(true);
892+
mockOauthProvider(true);
893+
endpoint.infoForLoginJson(extendedModelMap, null, new MockHttpServletRequest("GET", "http://someurl"));
894+
Map<String, Object> mapPrompts = (Map<String, Object>) extendedModelMap.get("prompts");
895+
assertThat(mapPrompts).doesNotContainKey("passcode");
896+
}
891897
}
892898

893899
@Test
894900
void we_return_both_oauth_and_oidc_providers() throws Exception {
895901
LoginInfoEndpoint endpoint = getEndpoint(IdentityZoneHolder.get());
896-
897902
RawExternalOAuthIdentityProviderDefinition oauthDefinition = new RawExternalOAuthIdentityProviderDefinition()
898903
.setAuthUrl(URI.create("http://auth.url").toURL())
899904
.setTokenUrl(URI.create("http://token.url").toURL());
@@ -1754,8 +1759,7 @@ private static void mockOidcProvider(IdentityProviderProvisioning mockIdentityPr
17541759
when(mockOidcConfig.getResponseType()).thenReturn("token");
17551760
when(mockProvider.getConfig()).thenReturn(mockOidcConfig);
17561761
when(mockOidcConfig.isShowLinkText()).thenReturn(true);
1757-
when(mockIdentityProviderProvisioning.retrieveActiveByTypes(anyString(), any())).thenReturn(singletonList(mockProvider));
1758-
when(mockIdentityProviderProvisioning.retrieveActiveByTypes(anyString(), any(), any())).thenReturn(singletonList(mockProvider));
1762+
when(mockIdentityProviderProvisioning.retrieveActiveByTypes(anyString(), any(String[].class))).thenReturn(singletonList(mockProvider));
17591763
when(mockIdentityProviderProvisioning.retrieveByOrigin(eq("my-OIDC-idp1"), any())).thenReturn(mockProvider);
17601764
}
17611765

@@ -1785,4 +1789,22 @@ private static void assertUsernamePasswordButNoPasscodePromptsAreReturned(
17851789
assertThat(returnedPrompts.get("password")[1]).isEqualTo("Password");
17861790
assertThat(returnedPrompts.get("passcode")).isNull();
17871791
}
1792+
1793+
private IdentityProvider<AbstractExternalOAuthIdentityProviderDefinition> mockOauthProvider(
1794+
boolean anyOrigins
1795+
) throws MalformedURLException {
1796+
RawExternalOAuthIdentityProviderDefinition definition = new RawExternalOAuthIdentityProviderDefinition();
1797+
definition.setAuthUrl(URI.create("http://auth.url").toURL());
1798+
definition.setTokenUrl(URI.create("http://token.url").toURL());
1799+
definition.setRelyingPartySecret("client-secret");
1800+
IdentityProvider<AbstractExternalOAuthIdentityProviderDefinition> identityProvider = MultitenancyFixture.identityProvider("oauth-idp-alias", "uaa");
1801+
identityProvider.setConfig(definition);
1802+
if (anyOrigins) {
1803+
when(mockIdentityProviderProvisioning.retrieveActiveByTypes(anyString(), any(String[].class))).thenReturn(singletonList(identityProvider));
1804+
} else {
1805+
when(mockIdentityProviderProvisioning.retrieveActiveByTypes(anyString(), eq(OriginKeys.OIDC10), eq(OriginKeys.OAUTH20)))
1806+
.thenReturn(singletonList(identityProvider));
1807+
}
1808+
return identityProvider;
1809+
}
17881810
}

0 commit comments

Comments
 (0)