keycloak-memoizeit
Changes
services/src/main/java/org/keycloak/forms/login/freemarker/model/IdentityProviderBean.java 12(+8 -4)
testsuite/integration/src/test/java/org/keycloak/testsuite/broker/IdentityProviderHintTest.java 7(+7 -0)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/AccountFederatedIdentityPage.java 18(+14 -4)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountTest.java 18(+17 -1)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/HiddenProviderTest.java 65(+65 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/IdentityProviderBuilder.java 9(+9 -0)
themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html 7(+7 -0)
Details
diff --git a/services/src/main/java/org/keycloak/forms/login/freemarker/model/IdentityProviderBean.java b/services/src/main/java/org/keycloak/forms/login/freemarker/model/IdentityProviderBean.java
index 87b935a..f682a3f 100755
--- a/services/src/main/java/org/keycloak/forms/login/freemarker/model/IdentityProviderBean.java
+++ b/services/src/main/java/org/keycloak/forms/login/freemarker/model/IdentityProviderBean.java
@@ -27,6 +27,7 @@ import java.net.URI;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
@@ -63,10 +64,13 @@ public class IdentityProviderBean {
private void addIdentityProvider(Set<IdentityProvider> orderedSet, RealmModel realm, URI baseURI, IdentityProviderModel identityProvider) {
String loginUrl = Urls.identityProviderAuthnRequest(baseURI, identityProvider.getAlias(), realm.getName()).toString();
String displayName = KeycloakModelUtils.getIdentityProviderDisplayName(session, identityProvider);
-
- orderedSet.add(new IdentityProvider(identityProvider.getAlias(),
- displayName, identityProvider.getProviderId(), loginUrl,
- identityProvider.getConfig() != null ? identityProvider.getConfig().get("guiOrder") : null));
+ Map<String, String> config = identityProvider.getConfig();
+ boolean hideOnLoginPage = config != null && Boolean.parseBoolean(config.get("hideOnLoginPage"));
+ if (!hideOnLoginPage) {
+ orderedSet.add(new IdentityProvider(identityProvider.getAlias(),
+ displayName, identityProvider.getProviderId(), loginUrl,
+ config != null ? config.get("guiOrder") : null));
+ }
}
public List<IdentityProvider> getProviders() {
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/IdentityProviderHintTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/IdentityProviderHintTest.java
index 36c291f..05d1afa 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/IdentityProviderHintTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/IdentityProviderHintTest.java
@@ -87,6 +87,13 @@ public class IdentityProviderHintTest {
assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/test-app"));
assertTrue(this.driver.getPageSource().contains("idToken"));
}
+
+ @Test
+ public void testSuccessfulRedirectToProviderHiddenOnLoginPage() {
+ this.driver.navigate().to("http://localhost:8081/test-app?kc_idp_hint=kc-oidc-idp-hidden");
+
+ assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8082/auth/"));
+ }
@Test
public void testInvalidIdentityProviderHint() {
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/LoginPage.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/LoginPage.java
index 4b3ecb4..2fe160e 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/LoginPage.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/LoginPage.java
@@ -143,13 +143,13 @@ public class LoginPage extends AbstractPage {
registerLink.click();
}
- public void clickSocial(String providerId) {
- WebElement socialButton = findSocialButton(providerId);
+ public void clickSocial(String alias) {
+ WebElement socialButton = findSocialButton(alias);
socialButton.click();
}
- public WebElement findSocialButton(String providerId) {
- String id = "zocial-" + providerId;
+ public WebElement findSocialButton(String alias) {
+ String id = "zocial-" + alias;
return this.driver.findElement(By.id(id));
}
diff --git a/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json b/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json
index ab70714..1bfc295 100755
--- a/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json
+++ b/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json
@@ -205,6 +205,24 @@
"defaultScope": "email profile",
"backchannelSupported": "true"
}
+ },
+ {
+ "alias" : "kc-oidc-idp-hidden",
+ "providerId" : "keycloak-oidc",
+ "enabled": true,
+ "storeToken" : true,
+ "addReadTokenRoleOnCreate": true,
+ "config": {
+ "clientId": "broker-app",
+ "clientSecret": "secret",
+ "authorizationUrl": "http://localhost:8082/auth/realms/realm-with-oidc-idp-hidden/protocol/openid-connect/auth",
+ "tokenUrl": "http://localhost:8082/auth/realms/realm-with-oidc-idp-hidden/protocol/openid-connect/token",
+ "userInfoUrl": "http://localhost:8082/auth/realms/realm-with-oidc-idp-hidden/protocol/openid-connect/userinfo",
+ "logoutUrl": "http://localhost:8082/auth/realms/realm-with-oidc-idp-hidden/protocol/openid-connect/logout",
+ "defaultScope": "email profile",
+ "backchannelSupported": "true",
+ "hideOnLoginPage": true
+ }
}
],
"identityProviderMappers": [
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/AccountFederatedIdentityPage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/AccountFederatedIdentityPage.java
index ebd6773..9ca2372 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/AccountFederatedIdentityPage.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/AccountFederatedIdentityPage.java
@@ -50,13 +50,23 @@ public class AccountFederatedIdentityPage extends AbstractAccountPage {
public boolean isCurrent() {
return driver.getTitle().contains("Account Management") && driver.getPageSource().contains("Federated Identities");
}
+
+ public WebElement findAddProviderButton(String alias) {
+ return driver.findElement(By.id("add-" + alias));
+ }
+
+ public WebElement findRemoveProviderButton(String alias) {
+ return driver.findElement(By.id("remove-" + alias));
+ }
- public void clickAddProvider(String providerId) {
- driver.findElement(By.id("add-" + providerId)).click();
+ public void clickAddProvider(String alias) {
+ WebElement addButton = findAddProviderButton(alias);
+ addButton.click();
}
- public void clickRemoveProvider(String providerId) {
- driver.findElement(By.id("remove-" + providerId)).click();
+ public void clickRemoveProvider(String alias) {
+ WebElement addButton = findRemoveProviderButton(alias);
+ addButton.click();
}
public String getError() {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountTest.java
index 97e3c84..cc398ae 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountTest.java
@@ -40,6 +40,7 @@ import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
import org.keycloak.testsuite.admin.ApiUtil;
import org.keycloak.testsuite.drone.Different;
import org.keycloak.testsuite.pages.AccountApplicationsPage;
+import org.keycloak.testsuite.pages.AccountFederatedIdentityPage;
import org.keycloak.testsuite.pages.AccountLogPage;
import org.keycloak.testsuite.pages.AccountPasswordPage;
import org.keycloak.testsuite.pages.AccountSessionsPage;
@@ -95,6 +96,12 @@ public class AccountTest extends AbstractTestRealmKeycloakTest {
.alias("myoidc")
.displayName("MyOIDC")
.build());
+ testRealm.addIdentityProvider(IdentityProviderBuilder.create()
+ .providerId("oidc")
+ .alias("myhiddenoidc")
+ .displayName("MyHiddenOIDC")
+ .hideOnLoginPage()
+ .build());
RealmBuilder.edit(testRealm)
.user(user2);
@@ -138,6 +145,9 @@ public class AccountTest extends AbstractTestRealmKeycloakTest {
@Page
protected AccountApplicationsPage applicationsPage;
+
+ @Page
+ protected AccountFederatedIdentityPage federatedIdentityPage;
@Page
protected ErrorPage errorPage;
@@ -918,7 +928,13 @@ public class AccountTest extends AbstractTestRealmKeycloakTest {
Assert.assertEquals("GitHub", loginPage.findSocialButton("github").getText());
Assert.assertEquals("mysaml", loginPage.findSocialButton("mysaml").getText());
Assert.assertEquals("MyOIDC", loginPage.findSocialButton("myoidc").getText());
-
+ }
+
+ @Test
+ public void testIdentityProviderHiddenOnLoginPageIsVisbleInAccount(){
+ federatedIdentityPage.open();
+ loginPage.login("test-user@localhost", "password");
+ Assert.assertNotNull(federatedIdentityPage.findAddProviderButton("myhiddenoidc"));
}
@Test
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/HiddenProviderTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/HiddenProviderTest.java
new file mode 100644
index 0000000..eae92a7
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/HiddenProviderTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * 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.forms;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Assert;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+import org.keycloak.admin.client.resource.RealmResource;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
+import org.keycloak.testsuite.pages.LoginPage;
+import org.keycloak.testsuite.util.IdentityProviderBuilder;
+
+public class HiddenProviderTest extends AbstractTestRealmKeycloakTest {
+
+ @Page
+ protected LoginPage loginPage;
+
+ @Override
+ protected RealmResource testRealm() {
+ return adminClient.realm("realm-with-broker");
+ }
+
+ @Override
+ public void configureTestRealm(RealmRepresentation testRealm) {
+ testRealm.addIdentityProvider(IdentityProviderBuilder.create()
+ .providerId("oidc")
+ .alias("visible-oidc")
+ .displayName("VisibleOIDC")
+ .build());
+ testRealm.addIdentityProvider(IdentityProviderBuilder.create()
+ .providerId("oidc")
+ .alias("hidden-oidc")
+ .displayName("HiddenOIDC")
+ .hideOnLoginPage()
+ .build());
+ }
+
+ @Test
+ public void testVisibleProviderButton() {
+ loginPage.open();
+ Assert.assertNotNull(loginPage.findSocialButton("visible-oidc"));
+ }
+
+ @Test(expected=org.openqa.selenium.NoSuchElementException.class)
+ public void testHiddenProviderButton() {
+ loginPage.open();
+ Assert.assertNull(loginPage.findSocialButton("hidden-oidc"));
+ }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/IdentityProviderBuilder.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/IdentityProviderBuilder.java
index 7cb1446..7fccde7 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/IdentityProviderBuilder.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/IdentityProviderBuilder.java
@@ -17,6 +17,7 @@
package org.keycloak.testsuite.util;
+import java.util.HashMap;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
/**
@@ -48,6 +49,14 @@ public class IdentityProviderBuilder {
rep.setDisplayName(displayName);
return this;
}
+
+ public IdentityProviderBuilder hideOnLoginPage() {
+ if (rep.getConfig() == null) {
+ rep.setConfig(new HashMap<>());
+ }
+ rep.getConfig().put("hideOnLoginPage", "true");
+ return this;
+ }
public IdentityProviderRepresentation build() {
return rep;
diff --git a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
index 04b6d21..3133863 100644
--- a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
+++ b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
@@ -2,6 +2,7 @@ consoleTitle=Keycloak Admin Console
# Common messages
enabled=Enabled
+hidden=Hidden
name=Name
displayName=Display name
displayNameHtml=HTML Display name
@@ -466,6 +467,8 @@ off=Off
update-profile-on-first-login.tooltip=Define conditions under which a user has to update their profile during first-time login.
trust-email=Trust Email
trust-email.tooltip=If enabled then email provided by this provider is not verified even if verification is enabled for the realm.
+hide-on-login-page=Hide on Login Page
+hide-on-login-page.tooltip=If hidden, then login with this provider is possible only if requested explicitly, e.g. using the 'kc_idp_hint' parameter.
gui-order.tooltip=Number defining order of the provider in GUI (eg. on Login page).
first-broker-login-flow.tooltip=Alias of authentication flow, which is triggered after first login with this identity provider. Term 'First Login' means that there is not yet existing Keycloak account linked with the authenticated identity provider account.
post-broker-login-flow.tooltip=Alias of authentication flow, which is triggered after each login with this identity provider. Useful if you want additional verification of each user authenticated with this identity provider (for example OTP). Leave this empty if you don't want any additional authenticators to be triggered after login with this identity provider. Also note, that authenticator implementations must assume that user is already set in ClientSession as identity provider already set it.
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider.html b/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider.html
index ade7b83..22ac869 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider.html
@@ -33,7 +33,7 @@
<caption class="hidden">{{:: 'table-of-identity-providers' | translate}}</caption>
<thead>
<tr>
- <th colspan="6" class="kc-table-actions">
+ <th colspan="7" class="kc-table-actions">
<div class="dropdown pull-right" data-ng-show="access.manageIdentityProviders">
<select class="form-control" ng-model="provider"
ng-options="p.name group by p.groupName for p in allProviders track by p.id"
@@ -47,6 +47,7 @@
<th>{{:: 'name' | translate}}</th>
<th>{{:: 'provider' | translate}}</th>
<th>{{:: 'enabled' | translate}}</th>
+ <th>{{:: 'hidden' | translate}}</th>
<th width="15%">{{:: 'gui-order' | translate}}</th>
<th colspan="2">{{:: 'actions' | translate}}</th>
</tr>
@@ -62,6 +63,7 @@
</td>
<td>{{identityProvider.providerId}}</td>
<td translate="{{identityProvider.enabled}}"></td>
+ <td translate="{{identityProvider.config.hideOnLoginPage == 'true'}}"></td>
<td>{{identityProvider.config.guiOrder}}</td>
<td class="kc-action-cell" kc-open="/realms/{{realm.realm}}/identity-provider-settings/provider/{{identityProvider.providerId}}/{{identityProvider.alias}}">{{:: 'edit' | translate}}</td>
<td class="kc-action-cell" data-ng-show="access.manageIdentityProviders" data-ng-click="removeIdentityProvider(identityProvider)">{{:: 'delete' | translate}}</td>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html b/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html
index b4069ea..6a04d37 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html
@@ -65,6 +65,13 @@
<kc-tooltip>{{:: 'trust-email.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group">
+ <label class="col-md-2 control-label" for="hideOnLoginPage">{{:: 'hide-on-login-page' | translate}}</label>
+ <div class="col-md-6">
+ <input ng-model="identityProvider.config.hideOnLoginPage" name="identityProvider.config.hideOnLoginPage" id="hideOnLoginPage" onoffswitchvalue on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
+ </div>
+ <kc-tooltip>{{:: 'hide-on-login-page.tooltip' | translate}}</kc-tooltip>
+ </div>
+ <div class="form-group">
<label class="col-md-2 control-label" for="guiOrder">{{:: 'gui-order' | translate}}</label>
<div class="col-md-6">
<input class="form-control" id="guiOrder" type="text" ng-model="identityProvider.config.guiOrder">
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html b/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html
index 3aad92b..83010b6 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html
@@ -62,6 +62,13 @@
<kc-tooltip>{{:: 'trust-email.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group">
+ <label class="col-md-2 control-label" for="hideOnLoginPage">{{:: 'hide-on-login-page' | translate}}</label>
+ <div class="col-md-6">
+ <input ng-model="identityProvider.config.hideOnLoginPage" name="identityProvider.config.hideOnLoginPage" id="hideOnLoginPage" onoffswitchvalue on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
+ </div>
+ <kc-tooltip>{{:: 'hide-on-login-page.tooltip' | translate}}</kc-tooltip>
+ </div>
+ <div class="form-group">
<label class="col-md-2 control-label" for="guiOrder">{{:: 'gui-order' | translate}}</label>
<div class="col-md-6">
<input class="form-control" id="guiOrder" type="text" ng-model="identityProvider.config.guiOrder">
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-social.html b/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-social.html
index d5c0d85..8e200e7 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-social.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-social.html
@@ -79,6 +79,13 @@
<kc-tooltip>{{:: 'trust-email.tooltip' | translate}}</kc-tooltip>
</div>
<div class="form-group">
+ <label class="col-md-2 control-label" for="hideOnLoginPage">{{:: 'hide-on-login-page' | translate}}</label>
+ <div class="col-md-6">
+ <input ng-model="identityProvider.config.hideOnLoginPage" name="identityProvider.config.hideOnLoginPage" id="hideOnLoginPage" onoffswitchvalue on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
+ </div>
+ <kc-tooltip>{{:: 'hide-on-login-page.tooltip' | translate}}</kc-tooltip>
+ </div>
+ <div class="form-group">
<label class="col-md-2 control-label" for="guiOrder">{{:: 'gui-order' | translate}}</label>
<div class="col-md-6">
<input class="form-control" id="guiOrder" type="text" ng-model="identityProvider.config.guiOrder">