Merge pull request #941 from pedroigor/KEYCLOAK-996

[KEYCLOAK-996] - Allow application to select provider.
This commit is contained in:
Pedro Igor 2015-01-30 14:28:50 -02:00
commit e452165c4a
6 changed files with 156 additions and 20 deletions

View file

@ -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";
}

View file

@ -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();
}

View file

@ -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()) {

View file

@ -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);

View file

@ -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"};
}
}

View file

@ -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());
}
}