Merge pull request #941 from pedroigor/KEYCLOAK-996
[KEYCLOAK-996] - Allow application to select provider.
This commit is contained in:
commit
e452165c4a
6 changed files with 156 additions and 20 deletions
|
@ -29,4 +29,7 @@ public interface AdapterConstants {
|
|||
|
||||
// Cookie used on adapter side to store token info. Used only when tokenStore is 'COOKIE'
|
||||
public static final String KEYCLOAK_ADAPTER_STATE_COOKIE = "KEYCLOAK_ADAPTER_STATE";
|
||||
|
||||
// Request parameter used to specify the identifier of the identity provider that should be used to authenticate an user
|
||||
String K_IDP_HINT = "k_idp_hint";
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package org.keycloak.adapters;
|
||||
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.RSATokenVerifier;
|
||||
|
@ -17,6 +16,8 @@ import java.io.IOException;
|
|||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import static org.keycloak.constants.AdapterConstants.K_IDP_HINT;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
|
@ -131,6 +132,9 @@ public class OAuthRequestAuthenticator {
|
|||
String loginHint = getQueryParamValue("login_hint");
|
||||
url = UriUtils.stripQueryParam(url,"login_hint");
|
||||
|
||||
String idpHint = getQueryParamValue(K_IDP_HINT);
|
||||
url = UriUtils.stripQueryParam(url, K_IDP_HINT);
|
||||
|
||||
KeycloakUriBuilder redirectUriBuilder = deployment.getAuthUrl().clone()
|
||||
.queryParam(OAuth2Constants.CLIENT_ID, deployment.getResourceName())
|
||||
.queryParam(OAuth2Constants.REDIRECT_URI, url)
|
||||
|
@ -139,6 +143,9 @@ public class OAuthRequestAuthenticator {
|
|||
if(loginHint != null && loginHint.length() > 0){
|
||||
redirectUriBuilder.queryParam("login_hint",loginHint);
|
||||
}
|
||||
if (idpHint != null && idpHint.length() > 0) {
|
||||
redirectUriBuilder.queryParam(K_IDP_HINT,idpHint);
|
||||
}
|
||||
|
||||
return redirectUriBuilder.build().toString();
|
||||
}
|
||||
|
|
|
@ -76,6 +76,8 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.keycloak.constants.AdapterConstants.K_IDP_HINT;
|
||||
|
||||
/**
|
||||
* Resource class for the oauth/openid connect token service
|
||||
*
|
||||
|
@ -851,7 +853,8 @@ public class OpenIDConnectService {
|
|||
@QueryParam(OpenIDConnect.SCOPE_PARAM) String scopeParam,
|
||||
@QueryParam(OpenIDConnect.STATE_PARAM) String state,
|
||||
@QueryParam(OpenIDConnect.PROMPT_PARAM) String prompt,
|
||||
@QueryParam(OpenIDConnect.LOGIN_HINT_PARAM) String loginHint) {
|
||||
@QueryParam(OpenIDConnect.LOGIN_HINT_PARAM) String loginHint,
|
||||
@QueryParam(K_IDP_HINT) String idpHint) {
|
||||
event.event(EventType.LOGIN);
|
||||
FrontPageInitializer pageInitializer = new FrontPageInitializer();
|
||||
pageInitializer.responseType = responseType;
|
||||
|
@ -875,6 +878,20 @@ public class OpenIDConnectService {
|
|||
}
|
||||
|
||||
String accessCode = new ClientSessionCode(realm, clientSession).getCode();
|
||||
|
||||
if (idpHint != null && !"".equals(idpHint)) {
|
||||
IdentityProviderModel identityProviderModel = realm.getIdentityProviderById(idpHint);
|
||||
|
||||
if (identityProviderModel == null) {
|
||||
return Flows.forms(session, realm, null, uriInfo)
|
||||
.setError("Could not find an identity provider with the identifier [" + idpHint + "].")
|
||||
.createErrorPage();
|
||||
}
|
||||
|
||||
return Response.temporaryRedirect(
|
||||
Urls.identityProviderAuthnRequest(this.uriInfo.getBaseUri(), identityProviderModel, realm, accessCode)).build();
|
||||
}
|
||||
|
||||
List<RequiredCredentialModel> requiredCredentials = realm.getRequiredCredentials();
|
||||
|
||||
if (requiredCredentials.isEmpty()) {
|
||||
|
|
|
@ -29,12 +29,9 @@ import org.keycloak.models.KeycloakSession;
|
|||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.representations.IDToken;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.testsuite.broker.util.UserSessionStatusServlet;
|
||||
import org.keycloak.testsuite.broker.util.UserSessionStatusServlet.UserSessionStatus;
|
||||
import org.keycloak.testsuite.pages.LoginPage;
|
||||
import org.keycloak.testsuite.pages.LoginUpdateProfilePage;
|
||||
import org.keycloak.testsuite.rule.AbstractKeycloakRule;
|
||||
import org.keycloak.testsuite.rule.WebResource;
|
||||
import org.keycloak.testsuite.rule.WebRule;
|
||||
import org.openqa.selenium.By;
|
||||
|
@ -43,7 +40,6 @@ import org.openqa.selenium.WebDriver;
|
|||
import org.openqa.selenium.WebElement;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -58,20 +54,7 @@ import static org.junit.Assert.assertTrue;
|
|||
public abstract class AbstractIdentityProviderTest {
|
||||
|
||||
@ClassRule
|
||||
public static AbstractKeycloakRule brokerServerRule = new AbstractKeycloakRule() {
|
||||
|
||||
@Override
|
||||
protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) {
|
||||
server.importRealm(getClass().getResourceAsStream("/broker-test/test-realm-with-broker.json"));
|
||||
URL url = getClass().getResource("/broker-test/test-app-keycloak.json");
|
||||
deployApplication("test-app", "/test-app", UserSessionStatusServlet.class, url.getPath(), "manager");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] getTestRealms() {
|
||||
return new String[] {"realm-with-broker"};
|
||||
}
|
||||
};
|
||||
public static BrokerKeyCloakRule brokerServerRule = new BrokerKeyCloakRule();
|
||||
|
||||
@Rule
|
||||
public WebRule webRule = new WebRule(this);
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* JBoss, Home of Professional Open Source
|
||||
*
|
||||
* Copyright 2013 Red Hat, Inc. and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.testsuite.broker;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.testsuite.broker.util.UserSessionStatusServlet;
|
||||
import org.keycloak.testsuite.rule.AbstractKeycloakRule;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* @author pedroigor
|
||||
*/
|
||||
public class BrokerKeyCloakRule extends AbstractKeycloakRule {
|
||||
|
||||
@Override
|
||||
protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) {
|
||||
server.importRealm(getClass().getResourceAsStream("/broker-test/test-realm-with-broker.json"));
|
||||
URL url = getClass().getResource("/broker-test/test-app-keycloak.json");
|
||||
deployApplication("test-app", "/test-app", UserSessionStatusServlet.class, url.getPath(), "manager");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] getTestRealms() {
|
||||
return new String[] {"realm-with-broker"};
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package org.keycloak.testsuite.broker;
|
||||
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.testsuite.pages.LoginPage;
|
||||
import org.keycloak.testsuite.pages.OAuthGrantPage;
|
||||
import org.keycloak.testsuite.rule.AbstractKeycloakRule;
|
||||
import org.keycloak.testsuite.rule.WebResource;
|
||||
import org.keycloak.testsuite.rule.WebRule;
|
||||
import org.keycloak.testutils.KeycloakServer;
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author pedroigor
|
||||
*/
|
||||
public class IdentityProviderHintTest {
|
||||
|
||||
@ClassRule
|
||||
public static BrokerKeyCloakRule keycloakRule = new BrokerKeyCloakRule();
|
||||
|
||||
@ClassRule
|
||||
public static AbstractKeycloakRule samlServerRule = new AbstractKeycloakRule() {
|
||||
|
||||
@Override
|
||||
protected void configureServer(KeycloakServer server) {
|
||||
server.getConfig().setPort(8082);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) {
|
||||
server.importRealm(getClass().getResourceAsStream("/broker-test/test-broker-realm-with-kc-oidc.json"));
|
||||
}
|
||||
};
|
||||
|
||||
@Rule
|
||||
public WebRule webRule = new WebRule(this);
|
||||
|
||||
@WebResource
|
||||
private WebDriver driver;
|
||||
|
||||
@WebResource
|
||||
private LoginPage loginPage;
|
||||
|
||||
@WebResource
|
||||
private OAuthGrantPage grantPage;
|
||||
|
||||
@Test
|
||||
public void testSuccessfulRedirect() {
|
||||
this.driver.navigate().to("http://localhost:8081/test-app?k_idp_hint=kc-oidc-idp");
|
||||
|
||||
assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8082/auth/"));
|
||||
|
||||
// log in to identity provider
|
||||
this.loginPage.login("test-user", "password");
|
||||
|
||||
// grant access to broker-app
|
||||
this.grantPage.assertCurrent();
|
||||
this.grantPage.accept();
|
||||
|
||||
// authenticated and redirected to app
|
||||
assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/test-app"));
|
||||
assertTrue(this.driver.getPageSource().contains("idToken"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidIdentityProviderHint() {
|
||||
this.driver.navigate().to("http://localhost:8081/test-app?k_idp_hint=invalid-idp-id");
|
||||
|
||||
assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/login"));
|
||||
|
||||
assertEquals("Could not find an identity provider with the identifier [invalid-idp-id].", this.driver.findElement(By.className("instruction")).getText());
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue