diff --git a/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/UrlBean.java b/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/UrlBean.java index 5408a1d6de..de7e432d6a 100755 --- a/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/UrlBean.java +++ b/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/UrlBean.java @@ -40,7 +40,7 @@ public class UrlBean { } public String getSocialUrl() { - return Urls.accountSocialPage(baseQueryURI, realm).toString(); + return Urls.accountFederatedIdentityPage(baseQueryURI, realm).toString(); } public String getTotpUrl() { diff --git a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/IdentityProviderBean.java b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/IdentityProviderBean.java index 399fb1548a..80f29bb82b 100755 --- a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/IdentityProviderBean.java +++ b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/IdentityProviderBean.java @@ -23,9 +23,8 @@ package org.keycloak.login.freemarker.model; import org.keycloak.models.IdentityProviderModel; import org.keycloak.models.RealmModel; -import org.keycloak.services.resources.AuthenticationBrokerResource; +import org.keycloak.services.resources.flows.Urls; -import javax.ws.rs.core.UriBuilder; import java.net.URI; import java.util.LinkedList; import java.util.List; @@ -49,11 +48,7 @@ public class IdentityProviderBean { for (IdentityProviderModel identityProvider : identityProviders) { if (identityProvider.isEnabled()) { - String loginUrl = UriBuilder.fromUri(baseURI) - .path(AuthenticationBrokerResource.class) - .path(AuthenticationBrokerResource.class, "performLogin") - .replaceQueryParam("provider_id", identityProvider.getId()) - .build(realm.getName()).toString(); + String loginUrl = Urls.identityProviderAuthnRequest(baseURI, identityProvider, realm).toString(); providers.add(new IdentityProvider(identityProvider.getId(), identityProvider.getName(), loginUrl)); } } diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnectService.java b/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnectService.java index 9b9f8b98cf..99e1859136 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnectService.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnectService.java @@ -25,9 +25,11 @@ import org.keycloak.models.ApplicationModel; import org.keycloak.models.ClientModel; import org.keycloak.models.ClientSessionModel; import org.keycloak.models.Constants; +import org.keycloak.models.IdentityProviderModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.OAuthClientModel; import org.keycloak.models.RealmModel; +import org.keycloak.models.RequiredCredentialModel; import org.keycloak.models.UserModel; import org.keycloak.models.UserSessionModel; import org.keycloak.models.UserSessionProvider; @@ -70,6 +72,7 @@ import java.io.InputStream; import java.net.URI; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -871,8 +874,27 @@ public class OpenIDConnectService { return oauth.cancelLogin(clientSession); } + String accessCode = new ClientSessionCode(realm, clientSession).getCode(); + List requiredCredentials = realm.getRequiredCredentials(); + + if (requiredCredentials.isEmpty()) { + List identityProviders = realm.getIdentityProviders(); + + if (!identityProviders.isEmpty()) { + if (identityProviders.size() == 1) { + return Response.temporaryRedirect( + Urls.identityProviderAuthnRequest(this.uriInfo.getBaseUri(), identityProviders.get(0), this.realm, accessCode)) + .build(); + } + + return Flows.forms(session, realm, null, uriInfo).setError("Realm [" + this.realm.getName() + "] supports multiple identity providers. Could not determine which identity provider should be used to authenticate with.").createErrorPage(); + } + + return Flows.forms(session, realm, null, uriInfo).setError("Realm [" + this.realm.getName() + "] does not support any credential type.").createErrorPage(); + } + LoginFormsProvider forms = Flows.forms(session, realm, clientSession.getClient(), uriInfo) - .setClientSessionCode(new ClientSessionCode(realm, clientSession).getCode()); + .setClientSessionCode(accessCode); String rememberMeUsername = AuthenticationManager.getRememberMeUsername(realm, headers); diff --git a/services/src/main/java/org/keycloak/services/resources/AccountService.java b/services/src/main/java/org/keycloak/services/resources/AccountService.java index f3f6e9ab5d..00b45ba9b8 100755 --- a/services/src/main/java/org/keycloak/services/resources/AccountService.java +++ b/services/src/main/java/org/keycloak/services/resources/AccountService.java @@ -675,7 +675,7 @@ public class AccountService { switch (accountSocialAction) { case ADD: - String redirectUri = UriBuilder.fromUri(Urls.accountSocialPage(uriInfo.getBaseUri(), realm.getName())).build().toString(); + String redirectUri = UriBuilder.fromUri(Urls.accountFederatedIdentityPage(uriInfo.getBaseUri(), realm.getName())).build().toString(); try { ClientSessionModel clientSession = auth.getClientSession(); diff --git a/services/src/main/java/org/keycloak/services/resources/flows/Urls.java b/services/src/main/java/org/keycloak/services/resources/flows/Urls.java index 09c4df32eb..60feca86b1 100755 --- a/services/src/main/java/org/keycloak/services/resources/flows/Urls.java +++ b/services/src/main/java/org/keycloak/services/resources/flows/Urls.java @@ -21,9 +21,13 @@ */ package org.keycloak.services.resources.flows; +import org.keycloak.OAuth2Constants; +import org.keycloak.models.IdentityProviderModel; +import org.keycloak.models.RealmModel; import org.keycloak.protocol.oidc.OpenIDConnect; import org.keycloak.protocol.oidc.OpenIDConnectService; import org.keycloak.services.resources.AccountService; +import org.keycloak.services.resources.AuthenticationBrokerResource; import org.keycloak.services.resources.LoginActionsService; import org.keycloak.services.resources.RealmsResource; import org.keycloak.services.resources.ThemeResource; @@ -56,7 +60,7 @@ public class Urls { return accountBase(baseUri).path(AccountService.class, "passwordPage").build(realmId); } - public static URI accountSocialPage(URI baseUri, String realmId) { + public static URI accountFederatedIdentityPage(URI baseUri, String realmId) { return accountBase(baseUri).path(AccountService.class, "federatedIdentityPage").build(realmId); } @@ -64,6 +68,23 @@ public class Urls { return accountBase(baseUri).path(AccountService.class, "processFederatedIdentityUpdate").build(realmName); } + public static URI identityProviderAuthnRequest(URI baseURI, IdentityProviderModel identityProvider, RealmModel realm, String accessCode) { + UriBuilder uriBuilder = UriBuilder.fromUri(baseURI) + .path(AuthenticationBrokerResource.class) + .path(AuthenticationBrokerResource.class, "performLogin") + .replaceQueryParam("provider_id", identityProvider.getProviderId()); + + if (accessCode != null) { + uriBuilder.replaceQueryParam(OAuth2Constants.CODE, accessCode); + } + + return uriBuilder.build(realm.getName()); + } + + public static URI identityProviderAuthnRequest(URI baseURI, IdentityProviderModel identityProvider, RealmModel realm) { + return identityProviderAuthnRequest(baseURI, identityProvider, realm, null); + } + public static URI accountTotpPage(URI baseUri, String realmId) { return accountBase(baseUri).path(AccountService.class, "totpPage").build(realmId); }