mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-10 15:32:05 -03:30
Move doLogin to AbstractOAuthClient (#37638)
Closes #37637 Signed-off-by: stianst <stianst@gmail.com>
This commit is contained in:
parent
acb7abc255
commit
c22f76867f
@ -123,7 +123,7 @@
|
||||
</#list>
|
||||
</#if>
|
||||
</head>
|
||||
<body>
|
||||
<body data-page-id="account">
|
||||
<div id="app">
|
||||
<main class="container">
|
||||
<div class="keycloak__loading-container">
|
||||
|
||||
@ -123,7 +123,7 @@
|
||||
</#list>
|
||||
</#if>
|
||||
</head>
|
||||
<body>
|
||||
<body data-page-id="admin">
|
||||
<div id="app">
|
||||
<main class="container">
|
||||
<div class="keycloak__loading-container">
|
||||
|
||||
@ -600,6 +600,9 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
|
||||
if (!attributes.containsKey("templateName")) {
|
||||
attributes.put("templateName", templateName);
|
||||
}
|
||||
|
||||
attributes.put("pageId", templateName.substring(0, templateName.length() - 4));
|
||||
|
||||
String result = freeMarker.processTemplate(attributes, templateName, theme);
|
||||
Response.ResponseBuilder builder = Response.status(status == null ? Response.Status.OK : status).type(MediaType.TEXT_HTML_UTF_8_TYPE).language(locale).entity(result);
|
||||
for (Map.Entry<String, String> entry : httpResponseHeaders.entrySet()) {
|
||||
|
||||
@ -188,6 +188,7 @@ public class KeycloakErrorHandler implements ExceptionMapper<Throwable> {
|
||||
final var localeBean = new LocaleBean(realm, locale, session.getContext().getUri().getRequestUriBuilder(), messagesBundle);
|
||||
final var lang = realm.isInternationalizationEnabled() ? localeBean.getCurrentLanguageTag() : Locale.ENGLISH.toLanguageTag();
|
||||
|
||||
attributes.put("pageId", "error");
|
||||
attributes.put("statusCode", responseStatus.getStatusCode());
|
||||
|
||||
attributes.put("realm", realm);
|
||||
|
||||
@ -47,7 +47,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak.testframework</groupId>
|
||||
<artifactId>keycloak-test-framework-oauth-nimbus-poc</artifactId>
|
||||
<artifactId>keycloak-test-framework-oauth</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@ -72,10 +72,6 @@
|
||||
<groupId>org.keycloak.testframework</groupId>
|
||||
<artifactId>keycloak-test-framework-oauth</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak.testframework</groupId>
|
||||
<artifactId>keycloak-test-framework-oauth-nimbus-poc</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak.testframework</groupId>
|
||||
<artifactId>keycloak-test-framework-email-server</artifactId>
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package org.keycloak.test.examples;
|
||||
|
||||
import com.nimbusds.oauth2.sdk.GeneralException;
|
||||
import jakarta.mail.MessagingException;
|
||||
import jakarta.mail.internet.MimeMessage;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
@ -11,8 +10,8 @@ import org.keycloak.testframework.annotations.InjectUser;
|
||||
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
import org.keycloak.testframework.mail.MailServer;
|
||||
import org.keycloak.testframework.mail.annotations.InjectMailServer;
|
||||
import org.keycloak.testframework.oauth.nimbus.OAuthClient;
|
||||
import org.keycloak.testframework.oauth.nimbus.annotations.InjectOAuthClient;
|
||||
import org.keycloak.testframework.oauth.OAuthClient;
|
||||
import org.keycloak.testframework.oauth.annotations.InjectOAuthClient;
|
||||
import org.keycloak.testframework.realm.ManagedRealm;
|
||||
import org.keycloak.testframework.realm.ManagedUser;
|
||||
import org.keycloak.testframework.realm.RealmConfig;
|
||||
@ -20,7 +19,6 @@ import org.keycloak.testframework.realm.RealmConfigBuilder;
|
||||
import org.keycloak.testframework.realm.UserConfig;
|
||||
import org.keycloak.testframework.realm.UserConfigBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
@KeycloakIntegrationTest
|
||||
@ -39,8 +37,8 @@ public class EmailTest {
|
||||
OAuthClient oAuthClient;
|
||||
|
||||
@Test
|
||||
public void testEmail() throws GeneralException, IOException, MessagingException {
|
||||
oAuthClient.resourceOwnerCredentialGrant(user.getUsername(), "invalid");
|
||||
public void testEmail() throws MessagingException {
|
||||
oAuthClient.doPasswordGrantRequest(user.getUsername(), "invalid");
|
||||
|
||||
Map<String, String> smtpServer = realm.admin().toRepresentation().getSmtpServer();
|
||||
Assertions.assertEquals("auto@keycloak.org", smtpServer.get("from"));
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package org.keycloak.test.examples;
|
||||
|
||||
import com.nimbusds.oauth2.sdk.GeneralException;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.keycloak.events.EventType;
|
||||
@ -9,14 +8,12 @@ import org.keycloak.testframework.annotations.InjectEvents;
|
||||
import org.keycloak.testframework.annotations.InjectRealm;
|
||||
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
import org.keycloak.testframework.events.Events;
|
||||
import org.keycloak.testframework.oauth.nimbus.OAuthClient;
|
||||
import org.keycloak.testframework.oauth.nimbus.annotations.InjectOAuthClient;
|
||||
import org.keycloak.testframework.oauth.OAuthClient;
|
||||
import org.keycloak.testframework.oauth.annotations.InjectOAuthClient;
|
||||
import org.keycloak.testframework.realm.ManagedRealm;
|
||||
import org.keycloak.testframework.remote.timeoffset.InjectTimeOffSet;
|
||||
import org.keycloak.testframework.remote.timeoffset.TimeOffSet;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@KeycloakIntegrationTest
|
||||
public class EventsTest {
|
||||
|
||||
@ -34,13 +31,13 @@ public class EventsTest {
|
||||
|
||||
@Test
|
||||
public void testFailedLogin() {
|
||||
oAuthClient.resourceOwnerCredentialGrant("invalid", "invalid");
|
||||
oAuthClient.doPasswordGrantRequest("invalid", "invalid");
|
||||
|
||||
EventRepresentation event = events.poll();
|
||||
Assertions.assertEquals(EventType.LOGIN_ERROR.name(), event.getType());
|
||||
Assertions.assertEquals("invalid", event.getDetails().get("username"));
|
||||
|
||||
oAuthClient.resourceOwnerCredentialGrant("invalid2", "invalid");
|
||||
oAuthClient.doPasswordGrantRequest("invalid2", "invalid");
|
||||
|
||||
event = events.poll();
|
||||
Assertions.assertEquals(EventType.LOGIN_ERROR.name(), event.getType());
|
||||
@ -48,17 +45,17 @@ public class EventsTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimeOffset() throws GeneralException, IOException {
|
||||
public void testTimeOffset() {
|
||||
timeOffSet.set(60);
|
||||
|
||||
oAuthClient.clientCredentialGrant();
|
||||
oAuthClient.doClientCredentialsGrantAccessTokenRequest();
|
||||
|
||||
Assertions.assertEquals(EventType.CLIENT_LOGIN.name(), events.poll().getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClientLogin() throws GeneralException, IOException {
|
||||
oAuthClient.clientCredentialGrant();
|
||||
public void testClientLogin() {
|
||||
oAuthClient.doClientCredentialsGrantAccessTokenRequest();
|
||||
|
||||
Assertions.assertEquals(EventType.CLIENT_LOGIN.name(), events.poll().getType());
|
||||
}
|
||||
|
||||
@ -1,103 +0,0 @@
|
||||
package org.keycloak.test.examples;
|
||||
|
||||
import com.nimbusds.oauth2.sdk.AuthorizationResponse;
|
||||
import com.nimbusds.oauth2.sdk.TokenIntrospectionResponse;
|
||||
import com.nimbusds.oauth2.sdk.TokenResponse;
|
||||
import com.nimbusds.oauth2.sdk.token.AccessToken;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.keycloak.testframework.oauth.nimbus.annotations.InjectOAuthClient;
|
||||
import org.keycloak.testframework.annotations.InjectUser;
|
||||
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
import org.keycloak.testframework.oauth.nimbus.OAuthClient;
|
||||
import org.keycloak.testframework.realm.ManagedUser;
|
||||
import org.keycloak.testframework.realm.UserConfig;
|
||||
import org.keycloak.testframework.realm.UserConfigBuilder;
|
||||
import org.keycloak.testframework.ui.annotations.InjectPage;
|
||||
import org.keycloak.testframework.ui.annotations.InjectWebDriver;
|
||||
import org.keycloak.testframework.ui.page.LoginPage;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
|
||||
@KeycloakIntegrationTest
|
||||
public class NimbusOAuthClientTest {
|
||||
|
||||
@InjectUser(config = OAuthUserConfig.class)
|
||||
ManagedUser user;
|
||||
|
||||
@InjectOAuthClient
|
||||
OAuthClient oAuthClient;
|
||||
|
||||
@InjectWebDriver
|
||||
WebDriver webDriver;
|
||||
|
||||
@InjectPage
|
||||
LoginPage loginPage;
|
||||
|
||||
@Test
|
||||
public void testClientCredentials() throws Exception {
|
||||
TokenResponse tokenResponse = oAuthClient.clientCredentialGrant();
|
||||
Assertions.assertTrue(tokenResponse.indicatesSuccess());
|
||||
Assertions.assertNotNull(tokenResponse.toSuccessResponse().getTokens().getAccessToken());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntrospection() throws Exception {
|
||||
AccessToken accessToken = oAuthClient.clientCredentialGrant().toSuccessResponse().getTokens().getAccessToken();
|
||||
TokenIntrospectionResponse introspectionResponse = oAuthClient.introspection(accessToken);
|
||||
Assertions.assertTrue(introspectionResponse.indicatesSuccess());
|
||||
Assertions.assertNotNull(introspectionResponse.toSuccessResponse().getIssuer());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthorizationCode() throws Exception {
|
||||
URL authorizationRequestURL = oAuthClient.authorizationRequest();
|
||||
webDriver.navigate().to(authorizationRequestURL);
|
||||
loginPage.fillLogin(user.getUsername(), user.getPassword());
|
||||
loginPage.submit();
|
||||
|
||||
Assertions.assertEquals(1, oAuthClient.getCallbacks().size());
|
||||
|
||||
URI callbackUri = oAuthClient.getCallbacks().remove(0);
|
||||
|
||||
AuthorizationResponse authorizationResponse = AuthorizationResponse.parse(callbackUri);
|
||||
Assertions.assertTrue(authorizationResponse.indicatesSuccess());
|
||||
Assertions.assertNotNull(authorizationResponse.toSuccessResponse().getAuthorizationCode());
|
||||
|
||||
TokenResponse tokenResponse = oAuthClient.tokenRequest(authorizationResponse.toSuccessResponse().getAuthorizationCode());
|
||||
Assertions.assertTrue(tokenResponse.indicatesSuccess());
|
||||
Assertions.assertNotNull(tokenResponse.toSuccessResponse().getTokens().getAccessToken());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAccessTokenRevocation() throws Exception {
|
||||
TokenResponse tokenResponse = oAuthClient.clientCredentialGrant();
|
||||
Assertions.assertTrue(tokenResponse.indicatesSuccess());
|
||||
Assertions.assertNotNull(tokenResponse.toSuccessResponse().getTokens().getAccessToken());
|
||||
|
||||
AccessToken accessToken = tokenResponse.toSuccessResponse().getTokens().getAccessToken();
|
||||
TokenIntrospectionResponse introspectionResponse = oAuthClient.introspection(accessToken);
|
||||
Assertions.assertTrue(introspectionResponse.indicatesSuccess());
|
||||
Assertions.assertNotNull(introspectionResponse.toSuccessResponse().getScope());
|
||||
|
||||
Assertions.assertEquals(Response.Status.OK.getStatusCode(), oAuthClient.revokeAccessToken(accessToken).getStatusCode());
|
||||
|
||||
introspectionResponse = oAuthClient.introspection(accessToken);
|
||||
Assertions.assertTrue(introspectionResponse.indicatesSuccess());
|
||||
Assertions.assertNull(introspectionResponse.toSuccessResponse().getScope());
|
||||
}
|
||||
|
||||
public static class OAuthUserConfig implements UserConfig {
|
||||
|
||||
@Override
|
||||
public UserConfigBuilder configure(UserConfigBuilder user) {
|
||||
return user.name("First", "Last")
|
||||
.email("test@local")
|
||||
.password("password");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -2,20 +2,17 @@ package org.keycloak.test.examples;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.keycloak.testframework.annotations.InjectClient;
|
||||
import org.keycloak.testframework.annotations.InjectRealm;
|
||||
import org.keycloak.testframework.annotations.InjectUser;
|
||||
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
import org.keycloak.testframework.oauth.OAuthClient;
|
||||
import org.keycloak.testframework.oauth.annotations.InjectOAuthClient;
|
||||
import org.keycloak.testframework.realm.ClientConfig;
|
||||
import org.keycloak.testframework.realm.ClientConfigBuilder;
|
||||
import org.keycloak.testframework.realm.ManagedClient;
|
||||
import org.keycloak.testframework.realm.ManagedRealm;
|
||||
import org.keycloak.testframework.realm.ManagedUser;
|
||||
import org.keycloak.testframework.realm.UserConfig;
|
||||
import org.keycloak.testframework.realm.UserConfigBuilder;
|
||||
import org.keycloak.testsuite.util.oauth.AccessTokenResponse;
|
||||
import org.keycloak.testsuite.util.oauth.AuthorizationEndpointResponse;
|
||||
import org.keycloak.testsuite.util.oauth.TokenRevocationResponse;
|
||||
import org.keycloak.testsuite.util.oauth.UserInfoResponse;
|
||||
|
||||
@ -23,76 +20,71 @@ import org.keycloak.testsuite.util.oauth.UserInfoResponse;
|
||||
public class OAuthClientTest {
|
||||
|
||||
@InjectOAuthClient
|
||||
OAuthClient oAuthClient;
|
||||
OAuthClient oauth;
|
||||
|
||||
@InjectRealm
|
||||
ManagedRealm managedRealm;
|
||||
|
||||
@InjectClient(config = OAuthClientConfig.class)
|
||||
ManagedClient client;
|
||||
|
||||
@InjectUser(config = OAuthUserConfig.class)
|
||||
ManagedUser user;
|
||||
|
||||
@Test
|
||||
public void testConfig() {
|
||||
Assertions.assertEquals(managedRealm.getName(), oAuthClient.config().getRealm());
|
||||
Assertions.assertEquals(managedRealm.getBaseUrl() + "/protocol/openid-connect/token", oAuthClient.getEndpoints().getToken());
|
||||
Assertions.assertEquals(managedRealm.getName(), oauth.config().getRealm());
|
||||
Assertions.assertEquals(managedRealm.getBaseUrl() + "/protocol/openid-connect/token", oauth.getEndpoints().getToken());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLogin() {
|
||||
AuthorizationEndpointResponse response = oauth.doLogin(user.getUsername(), user.getPassword());
|
||||
Assertions.assertTrue(response.isRedirected());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPasswordGrant() {
|
||||
AccessTokenResponse accessTokenResponse = oAuthClient.doPasswordGrantRequest(user.getUsername(), user.getPassword());
|
||||
AccessTokenResponse accessTokenResponse = oauth.doPasswordGrantRequest(user.getUsername(), user.getPassword());
|
||||
Assertions.assertTrue(accessTokenResponse.isSuccess());
|
||||
|
||||
accessTokenResponse = oAuthClient.passwordGrantRequest(user.getUsername(), "invalid").send();
|
||||
accessTokenResponse = oauth.passwordGrantRequest(user.getUsername(), "invalid").send();
|
||||
Assertions.assertFalse(accessTokenResponse.isSuccess());
|
||||
Assertions.assertEquals("Invalid user credentials", accessTokenResponse.getErrorDescription());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClientCredential() {
|
||||
AccessTokenResponse accessTokenResponse = oAuthClient.doClientCredentialsGrantAccessTokenRequest();
|
||||
AccessTokenResponse accessTokenResponse = oauth.doClientCredentialsGrantAccessTokenRequest();
|
||||
Assertions.assertTrue(accessTokenResponse.isSuccess());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserInfo() {
|
||||
AccessTokenResponse accessTokenResponse = oAuthClient.doPasswordGrantRequest(user.getUsername(), user.getPassword());
|
||||
AccessTokenResponse accessTokenResponse = oauth.doPasswordGrantRequest(user.getUsername(), user.getPassword());
|
||||
|
||||
UserInfoResponse userInfoResponse = oAuthClient.doUserInfoRequest(accessTokenResponse.getAccessToken());
|
||||
UserInfoResponse userInfoResponse = oauth.doUserInfoRequest(accessTokenResponse.getAccessToken());
|
||||
Assertions.assertTrue(userInfoResponse.isSuccess());
|
||||
Assertions.assertEquals(user.getUsername(), userInfoResponse.getUserInfo().getPreferredUsername());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefresh() {
|
||||
AccessTokenResponse accessTokenResponse = oAuthClient.doPasswordGrantRequest(user.getUsername(), user.getPassword());
|
||||
AccessTokenResponse accessTokenResponse = oauth.doPasswordGrantRequest(user.getUsername(), user.getPassword());
|
||||
|
||||
AccessTokenResponse refreshResponse = oAuthClient.doRefreshTokenRequest(accessTokenResponse.getRefreshToken());
|
||||
AccessTokenResponse refreshResponse = oauth.doRefreshTokenRequest(accessTokenResponse.getRefreshToken());
|
||||
Assertions.assertTrue(refreshResponse.isSuccess());
|
||||
Assertions.assertNotEquals(accessTokenResponse.getAccessToken(), refreshResponse.getAccessToken());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRevocation() {
|
||||
AccessTokenResponse accessTokenResponse = oAuthClient.doPasswordGrantRequest(user.getUsername(), user.getPassword());
|
||||
AccessTokenResponse accessTokenResponse = oauth.doPasswordGrantRequest(user.getUsername(), user.getPassword());
|
||||
|
||||
TokenRevocationResponse tokenRevocationResponse = oAuthClient.doTokenRevoke(accessTokenResponse.getRefreshToken());
|
||||
TokenRevocationResponse tokenRevocationResponse = oauth.doTokenRevoke(accessTokenResponse.getRefreshToken());
|
||||
Assertions.assertTrue(tokenRevocationResponse.isSuccess());
|
||||
|
||||
AccessTokenResponse refreshResponse = oAuthClient.doRefreshTokenRequest(accessTokenResponse.getRefreshToken());
|
||||
AccessTokenResponse refreshResponse = oauth.doRefreshTokenRequest(accessTokenResponse.getRefreshToken());
|
||||
Assertions.assertFalse(refreshResponse.isSuccess());
|
||||
}
|
||||
|
||||
public static class OAuthClientConfig implements ClientConfig {
|
||||
|
||||
@Override
|
||||
public ClientConfigBuilder configure(ClientConfigBuilder client) {
|
||||
return client.clientId("myclient").secret("mysecret").directAccessGrants().serviceAccount();
|
||||
}
|
||||
}
|
||||
|
||||
public static class OAuthUserConfig implements UserConfig {
|
||||
|
||||
@Override
|
||||
|
||||
@ -1,14 +1,22 @@
|
||||
package org.keycloak.test.examples;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.keycloak.testframework.ui.annotations.InjectPage;
|
||||
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
import org.keycloak.testframework.ui.annotations.InjectPage;
|
||||
import org.keycloak.testframework.ui.annotations.InjectWebDriver;
|
||||
import org.keycloak.testframework.ui.page.LoginPage;
|
||||
import org.keycloak.testframework.ui.page.WelcomePage;
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
|
||||
|
||||
@KeycloakIntegrationTest
|
||||
public class PagesTest {
|
||||
|
||||
@InjectWebDriver
|
||||
WebDriver webDriver;
|
||||
|
||||
@InjectPage
|
||||
WelcomePage welcomePage;
|
||||
|
||||
@ -18,8 +26,25 @@ public class PagesTest {
|
||||
@Test
|
||||
public void testLoginFromWelcome() {
|
||||
welcomePage.navigateTo();
|
||||
loginPage.fillLogin("admin", "admin");
|
||||
loginPage.submit();
|
||||
|
||||
if (welcomePage.isActivePage()) {
|
||||
welcomePage.fillRegistration("admin", "admin");
|
||||
welcomePage.submit();
|
||||
welcomePage.clickOpenAdminConsole();
|
||||
}
|
||||
|
||||
if (webDriver instanceof HtmlUnitDriver) {
|
||||
String pageId = webDriver.findElement(By.xpath("//body")).getAttribute("data-page-id");
|
||||
Assertions.assertEquals("admin", pageId);
|
||||
Assertions.assertTrue(webDriver.getCurrentUrl().endsWith("/admin/master/console/"));
|
||||
} else {
|
||||
loginPage.waitForPage();
|
||||
|
||||
Assertions.assertTrue(loginPage.isActivePage());
|
||||
|
||||
loginPage.fillLogin("admin", "admin");
|
||||
loginPage.submit();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,50 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<artifactId>keycloak-test-framework-parent</artifactId>
|
||||
<groupId>org.keycloak.testframework</groupId>
|
||||
<version>999.0.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>keycloak-test-framework-oauth-nimbus-poc</artifactId>
|
||||
<name>Keycloak Test Framework</name>
|
||||
<packaging>jar</packaging>
|
||||
<description>Nimbus OAuth PoC extension for Keycloak Test Framework</description>
|
||||
|
||||
<properties>
|
||||
<nimbus-sdk.version>11.13</nimbus-sdk.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.keycloak.testframework</groupId>
|
||||
<artifactId>keycloak-test-framework-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.nimbusds</groupId>
|
||||
<artifactId>oauth2-oidc-sdk</artifactId>
|
||||
<version>${nimbus-sdk.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@ -1,15 +0,0 @@
|
||||
package org.keycloak.testframework.oauth.nimbus;
|
||||
|
||||
import org.keycloak.testframework.TestFrameworkExtension;
|
||||
import org.keycloak.testframework.injection.Supplier;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class NimbusTestFrameworkExtension implements TestFrameworkExtension {
|
||||
|
||||
@Override
|
||||
public List<Supplier<?, ?>> suppliers() {
|
||||
return List.of(new OAuthClientSupplier());
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,146 +0,0 @@
|
||||
package org.keycloak.testframework.oauth.nimbus;
|
||||
|
||||
import com.nimbusds.oauth2.sdk.AuthorizationCode;
|
||||
import com.nimbusds.oauth2.sdk.AuthorizationCodeGrant;
|
||||
import com.nimbusds.oauth2.sdk.AuthorizationGrant;
|
||||
import com.nimbusds.oauth2.sdk.AuthorizationRequest;
|
||||
import com.nimbusds.oauth2.sdk.ClientCredentialsGrant;
|
||||
import com.nimbusds.oauth2.sdk.GeneralException;
|
||||
import com.nimbusds.oauth2.sdk.ResourceOwnerPasswordCredentialsGrant;
|
||||
import com.nimbusds.oauth2.sdk.ResponseType;
|
||||
import com.nimbusds.oauth2.sdk.TokenIntrospectionRequest;
|
||||
import com.nimbusds.oauth2.sdk.TokenIntrospectionResponse;
|
||||
import com.nimbusds.oauth2.sdk.TokenRequest;
|
||||
import com.nimbusds.oauth2.sdk.TokenResponse;
|
||||
import com.nimbusds.oauth2.sdk.TokenRevocationRequest;
|
||||
import com.nimbusds.oauth2.sdk.auth.ClientAuthentication;
|
||||
import com.nimbusds.oauth2.sdk.auth.ClientSecretBasic;
|
||||
import com.nimbusds.oauth2.sdk.auth.Secret;
|
||||
import com.nimbusds.oauth2.sdk.http.HTTPResponse;
|
||||
import com.nimbusds.oauth2.sdk.id.ClientID;
|
||||
import com.nimbusds.oauth2.sdk.id.Issuer;
|
||||
import com.nimbusds.oauth2.sdk.id.State;
|
||||
import com.nimbusds.oauth2.sdk.token.AccessToken;
|
||||
import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.testframework.realm.ClientConfig;
|
||||
import org.keycloak.testframework.realm.ClientConfigBuilder;
|
||||
import org.keycloak.testframework.realm.ManagedClient;
|
||||
import org.keycloak.testframework.realm.ManagedRealm;
|
||||
import org.keycloak.testframework.util.ApiUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
|
||||
public class OAuthClient {
|
||||
|
||||
private final ManagedRealm realm;
|
||||
private final ManagedClient client;
|
||||
private final OAuthCallbackServer callbackServer;
|
||||
private OIDCProviderMetadata oidcProviderMetadata;
|
||||
|
||||
public OAuthClient(ManagedRealm realm, ClientConfig clientConfig) {
|
||||
this.realm = realm;
|
||||
this.client = registerClient(clientConfig);
|
||||
this.callbackServer = new OAuthCallbackServer();
|
||||
}
|
||||
|
||||
private ManagedClient registerClient(ClientConfig clientConfig) {
|
||||
ClientRepresentation clientRepresentation = clientConfig.configure(ClientConfigBuilder.create()).build();
|
||||
Response response = realm.admin().clients().create(clientRepresentation);
|
||||
String id = ApiUtil.handleCreatedResponse(response);
|
||||
clientRepresentation.setId(id);
|
||||
|
||||
return new ManagedClient(clientRepresentation, realm.admin().clients().get(id));
|
||||
}
|
||||
|
||||
public TokenResponse clientCredentialGrant() throws IOException, GeneralException {
|
||||
AuthorizationGrant clientGrant = new ClientCredentialsGrant();
|
||||
ClientAuthentication clientAuthentication = getClientAuthentication();
|
||||
URI tokenEndpoint = getOIDCProviderMetadata().getTokenEndpointURI();
|
||||
|
||||
TokenRequest tokenRequest = new TokenRequest(tokenEndpoint, clientAuthentication, clientGrant);
|
||||
return TokenResponse.parse(tokenRequest.toHTTPRequest().send());
|
||||
}
|
||||
|
||||
public TokenResponse resourceOwnerCredentialGrant(String username, String password) {
|
||||
try {
|
||||
ResourceOwnerPasswordCredentialsGrant credentialsGrant = new ResourceOwnerPasswordCredentialsGrant(username, new Secret(password));
|
||||
ClientAuthentication clientAuthentication = getClientAuthentication();
|
||||
URI tokenEndpoint = getOIDCProviderMetadata().getTokenEndpointURI();
|
||||
|
||||
TokenRequest tokenRequest = new TokenRequest(tokenEndpoint, clientAuthentication, credentialsGrant);
|
||||
return TokenResponse.parse(tokenRequest.toHTTPRequest().send());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public TokenResponse tokenRequest(AuthorizationCode authorizationCode) throws IOException, GeneralException {
|
||||
AuthorizationGrant grant = new AuthorizationCodeGrant(authorizationCode, callbackServer.getRedirectionUri());
|
||||
ClientAuthentication clientAuthentication = getClientAuthentication();
|
||||
URI tokenEndpoint = getOIDCProviderMetadata().getTokenEndpointURI();
|
||||
|
||||
TokenRequest tokenRequest = new TokenRequest(tokenEndpoint, clientAuthentication, grant);
|
||||
return TokenResponse.parse(tokenRequest.toHTTPRequest().send());
|
||||
}
|
||||
|
||||
public TokenIntrospectionResponse introspection(AccessToken accessToken) throws IOException, GeneralException {
|
||||
ClientAuthentication clientAuthentication = getClientAuthentication();
|
||||
URI introspectionEndpoint = getOIDCProviderMetadata().getIntrospectionEndpointURI();
|
||||
|
||||
TokenIntrospectionRequest introspectionRequest = new TokenIntrospectionRequest(introspectionEndpoint, clientAuthentication, accessToken);
|
||||
return TokenIntrospectionResponse.parse(introspectionRequest.toHTTPRequest().send());
|
||||
}
|
||||
|
||||
public HTTPResponse revokeAccessToken(AccessToken token) throws GeneralException, IOException {
|
||||
URI revocationEndpoint = getOIDCProviderMetadata().getRevocationEndpointURI();
|
||||
TokenRevocationRequest revocationRequest = new TokenRevocationRequest(revocationEndpoint, getClientAuthentication(), token);
|
||||
return revocationRequest.toHTTPRequest().send();
|
||||
}
|
||||
|
||||
public URL authorizationRequest() {
|
||||
try {
|
||||
URI authorizationEndpoint = getOIDCProviderMetadata().getAuthorizationEndpointURI();
|
||||
State state = new State();
|
||||
ClientID clientID = new ClientID(client.getClientId());
|
||||
|
||||
AuthorizationRequest authorizationRequest = new AuthorizationRequest.Builder(new ResponseType(ResponseType.Value.CODE), clientID)
|
||||
.state(state)
|
||||
.redirectionURI(callbackServer.getRedirectionUri())
|
||||
.endpointURI(authorizationEndpoint)
|
||||
.build();
|
||||
|
||||
return authorizationRequest.toURI().toURL();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public List<URI> getCallbacks() {
|
||||
return callbackServer.getCallbacks();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
client.admin().remove();
|
||||
callbackServer.close();
|
||||
}
|
||||
|
||||
private ClientAuthentication getClientAuthentication() {
|
||||
ClientID clientID = new ClientID(client.getClientId());
|
||||
Secret clientSecret = new Secret(client.getSecret());
|
||||
return new ClientSecretBasic(clientID, clientSecret);
|
||||
}
|
||||
|
||||
private OIDCProviderMetadata getOIDCProviderMetadata() throws GeneralException, IOException {
|
||||
if (oidcProviderMetadata == null) {
|
||||
Issuer issuer = new Issuer(realm.getBaseUrl());
|
||||
oidcProviderMetadata = OIDCProviderMetadata.resolve(issuer);
|
||||
}
|
||||
return oidcProviderMetadata;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
package org.keycloak.testframework.oauth.nimbus;
|
||||
|
||||
import org.keycloak.testframework.oauth.nimbus.annotations.InjectOAuthClient;
|
||||
import org.keycloak.testframework.injection.InstanceContext;
|
||||
import org.keycloak.testframework.injection.LifeCycle;
|
||||
import org.keycloak.testframework.injection.RequestedInstance;
|
||||
import org.keycloak.testframework.injection.Supplier;
|
||||
import org.keycloak.testframework.injection.SupplierHelpers;
|
||||
import org.keycloak.testframework.realm.ClientConfig;
|
||||
import org.keycloak.testframework.realm.ManagedRealm;
|
||||
|
||||
public class OAuthClientSupplier implements Supplier<OAuthClient, InjectOAuthClient> {
|
||||
|
||||
@Override
|
||||
public OAuthClient getValue(InstanceContext<OAuthClient, InjectOAuthClient> instanceContext) {
|
||||
ManagedRealm realm = instanceContext.getDependency(ManagedRealm.class);
|
||||
ClientConfig clientConfig = SupplierHelpers.getInstance(instanceContext.getAnnotation().config());
|
||||
return new OAuthClient(realm, clientConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean compatible(InstanceContext<OAuthClient, InjectOAuthClient> a, RequestedInstance<OAuthClient, InjectOAuthClient> b) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LifeCycle getDefaultLifecycle() {
|
||||
return LifeCycle.GLOBAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(InstanceContext<OAuthClient, InjectOAuthClient> instanceContext) {
|
||||
instanceContext.getValue().close();
|
||||
}
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
package org.keycloak.testframework.oauth.nimbus.annotations;
|
||||
|
||||
import org.keycloak.testframework.oauth.nimbus.DefaultOAuthClientConfiguration;
|
||||
import org.keycloak.testframework.realm.ClientConfig;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface InjectOAuthClient {
|
||||
|
||||
Class<? extends ClientConfig> config() default DefaultOAuthClientConfiguration.class;
|
||||
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
org.keycloak.testframework.oauth.nimbus.NimbusTestFrameworkExtension
|
||||
@ -1,4 +1,4 @@
|
||||
package org.keycloak.testframework.oauth.nimbus;
|
||||
package org.keycloak.testframework.oauth;
|
||||
|
||||
import org.keycloak.testframework.realm.ClientConfig;
|
||||
import org.keycloak.testframework.realm.ClientConfigBuilder;
|
||||
@ -7,7 +7,7 @@ public class DefaultOAuthClientConfiguration implements ClientConfig {
|
||||
|
||||
@Override
|
||||
public ClientConfigBuilder configure(ClientConfigBuilder client) {
|
||||
return client.clientId("test-oauth-client")
|
||||
return client.clientId("test-app")
|
||||
.serviceAccount()
|
||||
.directAccessGrants()
|
||||
.redirectUris("http://127.0.0.1/callback/oauth")
|
||||
@ -2,9 +2,11 @@ package org.keycloak.testframework.oauth;
|
||||
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.testframework.ui.page.LoginPage;
|
||||
import org.keycloak.testsuite.util.oauth.AbstractOAuthClient;
|
||||
import org.keycloak.testsuite.util.oauth.OAuthClientConfig;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.support.PageFactory;
|
||||
|
||||
public class OAuthClient extends AbstractOAuthClient<OAuthClient> {
|
||||
|
||||
@ -15,6 +17,14 @@ public class OAuthClient extends AbstractOAuthClient<OAuthClient> {
|
||||
.responseType(OAuth2Constants.CODE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillLoginForm(String username, String password) {
|
||||
LoginPage loginPage = new LoginPage(driver);
|
||||
PageFactory.initElements(driver, loginPage);
|
||||
loginPage.fillLogin(username, password);
|
||||
loginPage.submit();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
}
|
||||
|
||||
|
||||
@ -2,15 +2,18 @@ package org.keycloak.testframework.oauth;
|
||||
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.testframework.injection.InstanceContext;
|
||||
import org.keycloak.testframework.injection.LifeCycle;
|
||||
import org.keycloak.testframework.injection.RequestedInstance;
|
||||
import org.keycloak.testframework.injection.StringUtil;
|
||||
import org.keycloak.testframework.injection.Supplier;
|
||||
import org.keycloak.testframework.injection.SupplierHelpers;
|
||||
import org.keycloak.testframework.oauth.annotations.InjectOAuthClient;
|
||||
import org.keycloak.testframework.realm.ManagedClient;
|
||||
import org.keycloak.testframework.realm.ClientConfig;
|
||||
import org.keycloak.testframework.realm.ClientConfigBuilder;
|
||||
import org.keycloak.testframework.realm.ManagedRealm;
|
||||
import org.keycloak.testframework.server.KeycloakUrls;
|
||||
import org.keycloak.testframework.util.ApiUtil;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
|
||||
public class OAuthClientSupplier implements Supplier<OAuthClient, InjectOAuthClient> {
|
||||
@ -19,24 +22,27 @@ public class OAuthClientSupplier implements Supplier<OAuthClient, InjectOAuthCli
|
||||
public OAuthClient getValue(InstanceContext<OAuthClient, InjectOAuthClient> instanceContext) {
|
||||
InjectOAuthClient annotation = instanceContext.getAnnotation();
|
||||
|
||||
String clientId = StringUtil.convertEmptyToNull(annotation.clientId());
|
||||
String clientSecret = StringUtil.convertEmptyToNull(annotation.clientSecret());
|
||||
|
||||
KeycloakUrls keycloakUrls = instanceContext.getDependency(KeycloakUrls.class);
|
||||
CloseableHttpClient httpClient = (CloseableHttpClient) instanceContext.getDependency(HttpClient.class);
|
||||
WebDriver webDriver = instanceContext.getDependency(WebDriver.class);
|
||||
TestApp testApp = instanceContext.getDependency(TestApp.class);
|
||||
|
||||
ManagedRealm realm = instanceContext.getDependency(ManagedRealm.class, annotation.realmRef());
|
||||
// ClientConfig clientConfig = SupplierHelpers.getInstance(instanceContext.getAnnotation().config());
|
||||
|
||||
if ("".equals(annotation.clientId())) {
|
||||
ManagedClient managedClient = instanceContext.getDependency(ManagedClient.class, annotation.clientRef());
|
||||
clientId = managedClient.getClientId();
|
||||
clientSecret = managedClient.getSecret();
|
||||
}
|
||||
String redirectUri = testApp.getRedirectionUri().toString();
|
||||
|
||||
ClientConfig clientConfig = SupplierHelpers.getInstance(annotation.config());
|
||||
ClientRepresentation testAppClient = clientConfig.configure(ClientConfigBuilder.create())
|
||||
.redirectUris(redirectUri)
|
||||
.build();
|
||||
|
||||
String clientId = testAppClient.getClientId();
|
||||
String clientSecret = testAppClient.getSecret();
|
||||
|
||||
ApiUtil.handleCreatedResponse(realm.admin().clients().create(testAppClient));
|
||||
|
||||
OAuthClient oAuthClient = new OAuthClient(keycloakUrls.getBase(), httpClient, webDriver);
|
||||
oAuthClient.config().realm(realm.getName()).client(clientId, clientSecret);
|
||||
oAuthClient.config().realm(realm.getName()).client(clientId, clientSecret).redirectUri(redirectUri);
|
||||
return oAuthClient;
|
||||
}
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ public class OAuthTestFrameworkExtension implements TestFrameworkExtension {
|
||||
|
||||
@Override
|
||||
public List<Supplier<?, ?>> suppliers() {
|
||||
return List.of(new OAuthClientSupplier());
|
||||
return List.of(new OAuthClientSupplier(), new TestAppSupplier());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package org.keycloak.testframework.oauth.nimbus;
|
||||
package org.keycloak.testframework.oauth;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
@ -11,13 +11,13 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
class OAuthCallbackServer {
|
||||
public class TestApp {
|
||||
|
||||
private final HttpServer httpServer;
|
||||
private final OAuthCallbackHandler callbackHandler;
|
||||
private final URI redirectionUri;
|
||||
|
||||
public OAuthCallbackServer() {
|
||||
public TestApp() {
|
||||
this.callbackHandler = new OAuthCallbackHandler();
|
||||
|
||||
try {
|
||||
@ -0,0 +1,25 @@
|
||||
package org.keycloak.testframework.oauth;
|
||||
|
||||
import org.keycloak.testframework.injection.InstanceContext;
|
||||
import org.keycloak.testframework.injection.LifeCycle;
|
||||
import org.keycloak.testframework.injection.RequestedInstance;
|
||||
import org.keycloak.testframework.injection.Supplier;
|
||||
import org.keycloak.testframework.oauth.annotations.InjectTestApp;
|
||||
|
||||
public class TestAppSupplier implements Supplier<TestApp, InjectTestApp> {
|
||||
|
||||
@Override
|
||||
public TestApp getValue(InstanceContext<TestApp, InjectTestApp> instanceContext) {
|
||||
return new TestApp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean compatible(InstanceContext<TestApp, InjectTestApp> a, RequestedInstance<TestApp, InjectTestApp> b) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LifeCycle getDefaultLifecycle() {
|
||||
return LifeCycle.GLOBAL;
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,8 @@
|
||||
package org.keycloak.testframework.oauth.annotations;
|
||||
|
||||
import org.keycloak.testframework.oauth.DefaultOAuthClientConfiguration;
|
||||
import org.keycloak.testframework.realm.ClientConfig;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@ -9,10 +12,8 @@ import java.lang.annotation.Target;
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface InjectOAuthClient {
|
||||
|
||||
Class<? extends ClientConfig> config() default DefaultOAuthClientConfiguration.class;
|
||||
|
||||
String realmRef() default "";
|
||||
|
||||
String clientRef() default "";
|
||||
String clientId() default "";
|
||||
String clientSecret() default "";
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
package org.keycloak.testframework.oauth.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface InjectTestApp {
|
||||
|
||||
}
|
||||
@ -43,7 +43,6 @@
|
||||
<module>email-server</module>
|
||||
<module>examples</module>
|
||||
<module>oauth</module>
|
||||
<module>oauth-nimbus-poc</module>
|
||||
<module>remote</module>
|
||||
<module>remote-providers</module>
|
||||
<module>ui</module>
|
||||
|
||||
@ -1,9 +1,17 @@
|
||||
package org.keycloak.testframework.ui.page;
|
||||
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
import org.openqa.selenium.support.PageFactory;
|
||||
import org.openqa.selenium.support.ui.WebDriverWait;
|
||||
|
||||
public class AbstractPage {
|
||||
import java.time.Duration;
|
||||
|
||||
public abstract class AbstractPage {
|
||||
|
||||
@FindBy(xpath = "//body")
|
||||
private WebElement body;
|
||||
|
||||
protected final WebDriver driver;
|
||||
|
||||
@ -12,4 +20,22 @@ public class AbstractPage {
|
||||
PageFactory.initElements(driver, this);
|
||||
}
|
||||
|
||||
public abstract String getExpectedPageId();
|
||||
|
||||
public String getCurrentPageId() {
|
||||
return body.getAttribute("data-page-id");
|
||||
}
|
||||
|
||||
public void waitForPage() {
|
||||
try {
|
||||
new WebDriverWait(driver, Duration.ofSeconds(10)).until(d -> isActivePage());
|
||||
} catch (RuntimeException e) {
|
||||
throw new RuntimeException("Waiting for '" + getExpectedPageId() + "', but was '" + getCurrentPageId() + "'");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isActivePage() {
|
||||
return getExpectedPageId().equals(getCurrentPageId());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -28,4 +28,8 @@ public class LoginPage extends AbstractPage {
|
||||
submitButton.click();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExpectedPageId() {
|
||||
return "login-login";
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,6 +27,9 @@ public class WelcomePage extends AbstractPage {
|
||||
@FindBy(css = ".pf-v5-c-login__main-header-desc")
|
||||
private WebElement welcomeDescription;
|
||||
|
||||
@FindBy(css = ".pf-v5-c-button")
|
||||
private WebElement openAdminConsoleLink;
|
||||
|
||||
public WelcomePage(WebDriver driver) {
|
||||
super(driver);
|
||||
}
|
||||
@ -45,6 +48,10 @@ public class WelcomePage extends AbstractPage {
|
||||
submitButton.click();
|
||||
}
|
||||
|
||||
public void clickOpenAdminConsole() {
|
||||
openAdminConsoleLink.click();
|
||||
}
|
||||
|
||||
public String getWelcomeMessage() {
|
||||
return welcomeMessage.getText();
|
||||
}
|
||||
@ -57,4 +64,8 @@ public class WelcomePage extends AbstractPage {
|
||||
return pageAlert.getText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExpectedPageId() {
|
||||
return "welcome";
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,7 +78,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak.testframework</groupId>
|
||||
<artifactId>keycloak-test-framework-oauth-nimbus-poc</artifactId>
|
||||
<artifactId>keycloak-test-framework-oauth</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak.testframework</groupId>
|
||||
|
||||
@ -27,8 +27,8 @@ import org.keycloak.testframework.annotations.InjectUser;
|
||||
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
import org.keycloak.testframework.mail.MailServer;
|
||||
import org.keycloak.testframework.mail.annotations.InjectMailServer;
|
||||
import org.keycloak.testframework.oauth.nimbus.OAuthClient;
|
||||
import org.keycloak.testframework.oauth.nimbus.annotations.InjectOAuthClient;
|
||||
import org.keycloak.testframework.oauth.OAuthClient;
|
||||
import org.keycloak.testframework.oauth.annotations.InjectOAuthClient;
|
||||
import org.keycloak.testframework.realm.ManagedRealm;
|
||||
import org.keycloak.testframework.realm.ManagedUser;
|
||||
import org.keycloak.testframework.realm.RealmConfig;
|
||||
@ -53,7 +53,7 @@ public class EmailEventListenerTest {
|
||||
|
||||
@Test
|
||||
public void testFailedLoginEmailEvent() throws MessagingException {
|
||||
oAuthClient.resourceOwnerCredentialGrant(user.getUsername(), "invalid");
|
||||
oAuthClient.doPasswordGrantRequest(user.getUsername(), "invalid");
|
||||
|
||||
mail.waitForIncomingEmail(1);
|
||||
MimeMessage lastReceivedMessage = mail.getLastReceivedMessage();
|
||||
|
||||
@ -1,8 +1,5 @@
|
||||
package org.keycloak.tests.admin.metric;
|
||||
|
||||
import com.nimbusds.oauth2.sdk.AuthorizationResponse;
|
||||
import com.nimbusds.oauth2.sdk.GeneralException;
|
||||
import com.nimbusds.oauth2.sdk.TokenResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
@ -13,8 +10,8 @@ import org.keycloak.testframework.annotations.InjectKeycloakUrls;
|
||||
import org.keycloak.testframework.annotations.InjectRealm;
|
||||
import org.keycloak.testframework.annotations.InjectUser;
|
||||
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
import org.keycloak.testframework.oauth.nimbus.OAuthClient;
|
||||
import org.keycloak.testframework.oauth.nimbus.annotations.InjectOAuthClient;
|
||||
import org.keycloak.testframework.oauth.OAuthClient;
|
||||
import org.keycloak.testframework.oauth.annotations.InjectOAuthClient;
|
||||
import org.keycloak.testframework.realm.ManagedRealm;
|
||||
import org.keycloak.testframework.realm.ManagedUser;
|
||||
import org.keycloak.testframework.realm.UserConfig;
|
||||
@ -22,14 +19,10 @@ import org.keycloak.testframework.realm.UserConfigBuilder;
|
||||
import org.keycloak.testframework.server.KeycloakServerConfig;
|
||||
import org.keycloak.testframework.server.KeycloakServerConfigBuilder;
|
||||
import org.keycloak.testframework.server.KeycloakUrls;
|
||||
import org.keycloak.testframework.ui.annotations.InjectPage;
|
||||
import org.keycloak.testframework.ui.annotations.InjectWebDriver;
|
||||
import org.keycloak.testframework.ui.page.LoginPage;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.keycloak.testsuite.util.oauth.AccessTokenResponse;
|
||||
import org.keycloak.testsuite.util.oauth.AuthorizationEndpointResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@ -51,16 +44,10 @@ public class PasswordValidationMetricCustomTagsTest {
|
||||
@InjectHttpClient
|
||||
HttpClient httpClient;
|
||||
|
||||
@InjectWebDriver
|
||||
WebDriver webDriver;
|
||||
|
||||
@InjectPage
|
||||
LoginPage loginPage;
|
||||
|
||||
Pattern passValidationRegex = Pattern.compile("keycloak_credentials_password_hashing_validations_total\\{realm=\"([^\"]+)\"} ([.0-9]*)");
|
||||
|
||||
@Test
|
||||
void testValidAndInvalidPasswordValidation() throws GeneralException, IOException {
|
||||
void testValidAndInvalidPasswordValidation() throws IOException {
|
||||
runAuthorizationCodeFlow(user.getUsername(), "invalid_password", false);
|
||||
runAuthorizationCodeFlow(user.getUsername(), user.getPassword(), true);
|
||||
|
||||
@ -73,27 +60,14 @@ public class PasswordValidationMetricCustomTagsTest {
|
||||
Assertions.assertFalse(matcher.find());
|
||||
}
|
||||
|
||||
private void runAuthorizationCodeFlow(String username, String password, boolean success) throws GeneralException, IOException {
|
||||
URL authorizationRequestURL = oAuthClient.authorizationRequest();
|
||||
webDriver.navigate().to(authorizationRequestURL);
|
||||
loginPage.fillLogin(username, password);
|
||||
loginPage.submit();
|
||||
|
||||
private void runAuthorizationCodeFlow(String username, String password, boolean success) {
|
||||
AuthorizationEndpointResponse authorizationEndpointResponse = oAuthClient.doLogin(username, password);
|
||||
if (!success) {
|
||||
Assertions.assertTrue(oAuthClient.getCallbacks().isEmpty());
|
||||
Assertions.assertFalse(authorizationEndpointResponse.isRedirected());
|
||||
return;
|
||||
}
|
||||
|
||||
Assertions.assertEquals(1, oAuthClient.getCallbacks().size());
|
||||
URI callbackUri = oAuthClient.getCallbacks().remove(0);
|
||||
|
||||
AuthorizationResponse authorizationResponse = AuthorizationResponse.parse(callbackUri);
|
||||
Assertions.assertTrue(authorizationResponse.indicatesSuccess());
|
||||
Assertions.assertNotNull(authorizationResponse.toSuccessResponse().getAuthorizationCode());
|
||||
|
||||
TokenResponse tokenResponse = oAuthClient.tokenRequest(authorizationResponse.toSuccessResponse().getAuthorizationCode());
|
||||
Assertions.assertTrue(tokenResponse.indicatesSuccess());
|
||||
Assertions.assertNotNull(tokenResponse.toSuccessResponse().getTokens().getAccessToken());
|
||||
AccessTokenResponse accessTokenResponse = oAuthClient.doAccessTokenRequest(authorizationEndpointResponse.getCode());
|
||||
Assertions.assertTrue(accessTokenResponse.isSuccess());
|
||||
}
|
||||
|
||||
public static class ServerConfigWithMetrics implements KeycloakServerConfig {
|
||||
|
||||
@ -1,8 +1,5 @@
|
||||
package org.keycloak.tests.admin.metric;
|
||||
|
||||
import com.nimbusds.oauth2.sdk.AuthorizationResponse;
|
||||
import com.nimbusds.oauth2.sdk.GeneralException;
|
||||
import com.nimbusds.oauth2.sdk.TokenResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
@ -13,8 +10,8 @@ import org.keycloak.testframework.annotations.InjectKeycloakUrls;
|
||||
import org.keycloak.testframework.annotations.InjectRealm;
|
||||
import org.keycloak.testframework.annotations.InjectUser;
|
||||
import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
import org.keycloak.testframework.oauth.nimbus.OAuthClient;
|
||||
import org.keycloak.testframework.oauth.nimbus.annotations.InjectOAuthClient;
|
||||
import org.keycloak.testframework.oauth.OAuthClient;
|
||||
import org.keycloak.testframework.oauth.annotations.InjectOAuthClient;
|
||||
import org.keycloak.testframework.realm.ManagedRealm;
|
||||
import org.keycloak.testframework.realm.ManagedUser;
|
||||
import org.keycloak.testframework.realm.UserConfig;
|
||||
@ -22,14 +19,12 @@ import org.keycloak.testframework.realm.UserConfigBuilder;
|
||||
import org.keycloak.testframework.server.KeycloakServerConfig;
|
||||
import org.keycloak.testframework.server.KeycloakServerConfigBuilder;
|
||||
import org.keycloak.testframework.server.KeycloakUrls;
|
||||
import org.keycloak.testframework.ui.annotations.InjectPage;
|
||||
import org.keycloak.testframework.ui.annotations.InjectWebDriver;
|
||||
import org.keycloak.testframework.ui.page.LoginPage;
|
||||
import org.keycloak.testsuite.util.oauth.AccessTokenResponse;
|
||||
import org.keycloak.testsuite.util.oauth.AuthorizationEndpointResponse;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@ -54,13 +49,10 @@ public class PasswordValidationMetricTest {
|
||||
@InjectWebDriver
|
||||
WebDriver webDriver;
|
||||
|
||||
@InjectPage
|
||||
LoginPage loginPage;
|
||||
|
||||
Pattern passValidationRegex = Pattern.compile("keycloak_credentials_password_hashing_validations_total\\{algorithm=\"([^\"]+)\",hashing_strength=\"([^\"]+)\",outcome=\"([^\"]+)\",realm=\"([^\"]+)\"} ([.0-9]*)");
|
||||
|
||||
@Test
|
||||
void testValidAndInvalidPasswordValidation() throws GeneralException, IOException {
|
||||
void testValidAndInvalidPasswordValidation() throws IOException {
|
||||
runAuthorizationCodeFlow(user.getUsername(), "invalid_password");
|
||||
webDriver.manage().deleteAllCookies();
|
||||
runAuthorizationCodeFlow(user.getUsername(), user.getPassword());
|
||||
@ -89,25 +81,13 @@ public class PasswordValidationMetricTest {
|
||||
Assertions.assertFalse(matcher.find());
|
||||
}
|
||||
|
||||
private void runAuthorizationCodeFlow(String username, String password) throws GeneralException, IOException {
|
||||
URL authorizationRequestURL = oAuthClient.authorizationRequest();
|
||||
webDriver.navigate().to(authorizationRequestURL);
|
||||
loginPage.fillLogin(username, password);
|
||||
loginPage.submit();
|
||||
|
||||
if (oAuthClient.getCallbacks().isEmpty()) {
|
||||
return;
|
||||
private void runAuthorizationCodeFlow(String username, String password) {
|
||||
AuthorizationEndpointResponse authorizationEndpointResponse = oAuthClient.doLogin(username, password);
|
||||
if (authorizationEndpointResponse.isRedirected()) {
|
||||
AccessTokenResponse tokenResponse = oAuthClient.doAccessTokenRequest(authorizationEndpointResponse.getCode());
|
||||
Assertions.assertTrue(tokenResponse.isSuccess());
|
||||
Assertions.assertNotNull(tokenResponse.getAccessToken());
|
||||
}
|
||||
|
||||
URI callbackUri = oAuthClient.getCallbacks().remove(0);
|
||||
|
||||
AuthorizationResponse authorizationResponse = AuthorizationResponse.parse(callbackUri);
|
||||
Assertions.assertTrue(authorizationResponse.indicatesSuccess());
|
||||
Assertions.assertNotNull(authorizationResponse.toSuccessResponse().getAuthorizationCode());
|
||||
|
||||
TokenResponse tokenResponse = oAuthClient.tokenRequest(authorizationResponse.toSuccessResponse().getAuthorizationCode());
|
||||
Assertions.assertTrue(tokenResponse.indicatesSuccess());
|
||||
Assertions.assertNotNull(tokenResponse.toSuccessResponse().getTokens().getAccessToken());
|
||||
}
|
||||
|
||||
public static class ServerConfigWithMetrics implements KeycloakServerConfig {
|
||||
|
||||
@ -5,19 +5,28 @@ import org.openqa.selenium.WebDriver;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class AbstractOAuthClient<T> {
|
||||
public abstract class AbstractOAuthClient<T> {
|
||||
|
||||
protected String baseUrl;
|
||||
protected OAuthClientConfig config;
|
||||
|
||||
protected Map<String, String> customParameters;
|
||||
protected String codeChallenge;
|
||||
protected String codeChallengeMethod;
|
||||
protected String codeVerifier;
|
||||
protected String clientSessionState;
|
||||
protected String clientSessionHost;
|
||||
protected String dpopJkt;
|
||||
protected String dpopProof;
|
||||
protected String request;
|
||||
protected String requestUri;
|
||||
protected String claims;
|
||||
protected String kcAction;
|
||||
protected String uiLocales;
|
||||
protected String maxAge;
|
||||
protected String prompt;
|
||||
protected StateParamProvider state;
|
||||
protected String nonce;
|
||||
|
||||
protected HttpClientManager httpClientManager;
|
||||
protected WebDriver driver;
|
||||
@ -38,6 +47,26 @@ public class AbstractOAuthClient<T> {
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public String getLoginFormUrl() {
|
||||
return new LoginUrlBuilder(this).toString();
|
||||
}
|
||||
|
||||
public void openLoginForm() {
|
||||
driver.navigate().to(getLoginFormUrl());
|
||||
}
|
||||
|
||||
public AuthorizationEndpointResponse doLogin(String username, String password) {
|
||||
openLoginForm();
|
||||
fillLoginForm(username, password);
|
||||
return parseLoginResponse();
|
||||
}
|
||||
|
||||
public abstract void fillLoginForm(String username, String password);
|
||||
|
||||
public AuthorizationEndpointResponse parseLoginResponse() {
|
||||
return new AuthorizationEndpointResponse(this);
|
||||
}
|
||||
|
||||
public PasswordGrantRequest passwordGrantRequest(String username, String password) {
|
||||
return new PasswordGrantRequest(username, password, this);
|
||||
}
|
||||
@ -120,6 +149,14 @@ public class AbstractOAuthClient<T> {
|
||||
return clientSessionHost;
|
||||
}
|
||||
|
||||
String getCodeChallenge() {
|
||||
return codeChallenge;
|
||||
}
|
||||
|
||||
String getCodeChallengeMethod() {
|
||||
return codeChallengeMethod;
|
||||
}
|
||||
|
||||
String getCodeVerifier() {
|
||||
return codeVerifier;
|
||||
}
|
||||
@ -128,6 +165,10 @@ public class AbstractOAuthClient<T> {
|
||||
return customParameters;
|
||||
}
|
||||
|
||||
String getDpopJkt() {
|
||||
return dpopJkt;
|
||||
}
|
||||
|
||||
String getDpopProof() {
|
||||
return dpopProof;
|
||||
}
|
||||
@ -144,4 +185,34 @@ public class AbstractOAuthClient<T> {
|
||||
return claims;
|
||||
}
|
||||
|
||||
String getKcAction() {
|
||||
return kcAction;
|
||||
}
|
||||
|
||||
String getUiLocales() {
|
||||
return uiLocales;
|
||||
}
|
||||
|
||||
public String getState() {
|
||||
return state != null ? state.getState() : null;
|
||||
}
|
||||
|
||||
String getNonce() {
|
||||
return nonce;
|
||||
}
|
||||
|
||||
String getMaxAge() {
|
||||
return maxAge;
|
||||
}
|
||||
|
||||
String getPrompt() {
|
||||
return prompt;
|
||||
}
|
||||
|
||||
protected interface StateParamProvider {
|
||||
|
||||
String getState();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
package org.keycloak.testsuite.util.oauth;
|
||||
|
||||
import jakarta.ws.rs.core.UriBuilder;
|
||||
|
||||
public abstract class AbstractUrlBuilder {
|
||||
|
||||
protected final AbstractOAuthClient<?> client;
|
||||
protected UriBuilder uriBuilder;
|
||||
|
||||
public AbstractUrlBuilder(AbstractOAuthClient<?> client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public abstract String getEndpoint();
|
||||
|
||||
protected abstract void initRequest();
|
||||
|
||||
public void open() {
|
||||
client.driver.navigate().to(toString());
|
||||
}
|
||||
|
||||
protected void parameter(String name, String value) {
|
||||
if (value != null) {
|
||||
uriBuilder.queryParam(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
uriBuilder = UriBuilder.fromUri(getEndpoint());
|
||||
initRequest();
|
||||
return uriBuilder.build().toString();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,123 @@
|
||||
package org.keycloak.testsuite.util.oauth;
|
||||
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.utils.URLEncodedUtils;
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.protocol.oidc.utils.OIDCResponseMode;
|
||||
import org.keycloak.protocol.oidc.utils.OIDCResponseType;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class AuthorizationEndpointResponse {
|
||||
|
||||
private boolean isRedirected;
|
||||
private Map<String, String> params;
|
||||
|
||||
public AuthorizationEndpointResponse(AbstractOAuthClient<?> client) {
|
||||
WebDriver driver = client.driver;
|
||||
String currentUrl = driver.getCurrentUrl();
|
||||
|
||||
boolean fragment = isFragment(client);
|
||||
int parametersIndex = fragment ? currentUrl.indexOf('#') : currentUrl.indexOf('?');
|
||||
if (parametersIndex != -1) {
|
||||
String urlWithoutParameters = currentUrl.substring(0, parametersIndex);
|
||||
String parameters = currentUrl.substring(parametersIndex + 1);
|
||||
|
||||
isRedirected = urlWithoutParameters.equals(client.getRedirectUri());
|
||||
|
||||
params = new HashMap<>();
|
||||
URLEncodedUtils.parse(parameters, StandardCharsets.UTF_8)
|
||||
.stream().filter(p -> p.getValue() != null)
|
||||
.forEach(p -> params.put(p.getName(), p.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
private URI getCurrentUri(WebDriver driver) {
|
||||
try {
|
||||
return new URI(driver.getCurrentUrl());
|
||||
} catch (URISyntaxException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, String> getCurrentQuery(WebDriver driver) {
|
||||
Map<String, String> m = new HashMap<>();
|
||||
List<NameValuePair> pairs = URLEncodedUtils.parse(getCurrentUri(driver), StandardCharsets.UTF_8);
|
||||
for (NameValuePair p : pairs) {
|
||||
m.put(p.getName(), p.getValue());
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
private boolean isFragment(AbstractOAuthClient<?> client) {
|
||||
try {
|
||||
OIDCResponseType responseType = OIDCResponseType.parse(client.config().getResponseType());
|
||||
OIDCResponseMode responseMode = OIDCResponseMode.parse(client.config().getResponseMode(), responseType);
|
||||
return switch (responseMode) {
|
||||
case FRAGMENT, FRAGMENT_JWT -> true;
|
||||
default -> false;
|
||||
};
|
||||
} catch (IllegalArgumentException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRedirected() {
|
||||
return isRedirected;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return params.get(OAuth2Constants.CODE);
|
||||
}
|
||||
|
||||
public String getState() {
|
||||
return params.get(OAuth2Constants.STATE);
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
return params.get(OAuth2Constants.ERROR);
|
||||
}
|
||||
|
||||
public String getErrorDescription() {
|
||||
return params.get(OAuth2Constants.ERROR_DESCRIPTION);
|
||||
}
|
||||
|
||||
public String getSessionState() {
|
||||
return params.get(OAuth2Constants.SESSION_STATE);
|
||||
}
|
||||
|
||||
public String getAccessToken() {
|
||||
return params.get(OAuth2Constants.ACCESS_TOKEN);
|
||||
}
|
||||
|
||||
public String getIdToken() {
|
||||
return params.get(OAuth2Constants.ID_TOKEN);
|
||||
}
|
||||
|
||||
public String getTokenType() {
|
||||
return params.get(OAuth2Constants.TOKEN_TYPE);
|
||||
}
|
||||
|
||||
public String getExpiresIn() {
|
||||
return params.get(OAuth2Constants.EXPIRES_IN);
|
||||
}
|
||||
|
||||
public String getResponse() {
|
||||
return params.get(OAuth2Constants.RESPONSE);
|
||||
}
|
||||
|
||||
public String getIssuer() {
|
||||
return params.get(OAuth2Constants.ISSUER);
|
||||
}
|
||||
|
||||
public String getKcActionStatus() {
|
||||
return params.get("kc_action_status");
|
||||
}
|
||||
|
||||
}
|
||||
@ -16,6 +16,14 @@ public class Endpoints {
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
public String getAuthorization() {
|
||||
return asString(OIDCLoginProtocolService.authUrl(getBase()));
|
||||
}
|
||||
|
||||
public String getRegistration() {
|
||||
return asString(OIDCLoginProtocolService.registrationsUrl(getBase()));
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return asString(OIDCLoginProtocolService.tokenUrl(getBase()));
|
||||
}
|
||||
|
||||
@ -0,0 +1,48 @@
|
||||
package org.keycloak.testsuite.util.oauth;
|
||||
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||
|
||||
public class LoginUrlBuilder extends AbstractUrlBuilder {
|
||||
|
||||
public LoginUrlBuilder(AbstractOAuthClient<?> client) {
|
||||
super(client);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEndpoint() {
|
||||
return client.getEndpoints().getAuthorization();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initRequest() {
|
||||
parameter(OAuth2Constants.RESPONSE_TYPE, client.config().getResponseType());
|
||||
parameter(OIDCLoginProtocol.RESPONSE_MODE_PARAM, client.config().getResponseMode());
|
||||
parameter(OAuth2Constants.CLIENT_ID, client.config().getClientId());
|
||||
parameter(OAuth2Constants.REDIRECT_URI, client.config().getRedirectUri());
|
||||
|
||||
parameter(OAuth2Constants.STATE, client.getState());
|
||||
parameter(OIDCLoginProtocol.NONCE_PARAM, client.getNonce());
|
||||
parameter(OAuth2Constants.SCOPE, client.config().getScope());
|
||||
|
||||
parameter(OAuth2Constants.CODE_CHALLENGE, client.getCodeChallenge());
|
||||
parameter(OAuth2Constants.CODE_CHALLENGE_METHOD, client.getCodeChallengeMethod());
|
||||
|
||||
parameter(OIDCLoginProtocol.DPOP_JKT, client.getDpopJkt());
|
||||
|
||||
parameter(OIDCLoginProtocol.REQUEST_PARAM, client.getRequest());
|
||||
parameter(OIDCLoginProtocol.REQUEST_URI_PARAM, client.getRequestUri());
|
||||
parameter(OIDCLoginProtocol.CLAIMS_PARAM, client.getClaims());
|
||||
|
||||
parameter(Constants.KC_ACTION, client.getKcAction());
|
||||
parameter(OAuth2Constants.UI_LOCALES_PARAM, client.getUiLocales());
|
||||
parameter(OIDCLoginProtocol.MAX_AGE_PARAM, client.getMaxAge());
|
||||
parameter(OIDCLoginProtocol.PROMPT_PARAM, client.getPrompt());
|
||||
|
||||
if (client.getCustomParameters() != null) {
|
||||
client.getCustomParameters().forEach(this::parameter);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package org.keycloak.testsuite.util.oauth;
|
||||
|
||||
public class RegistrationUrlBuilder extends LoginUrlBuilder {
|
||||
|
||||
public RegistrationUrlBuilder(AbstractOAuthClient<?> client) {
|
||||
super(client);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEndpoint() {
|
||||
return client.getEndpoints().getRegistration();
|
||||
}
|
||||
|
||||
}
|
||||
@ -42,7 +42,7 @@ public abstract class Login extends LoginBase {
|
||||
setUriParameter(PROTOCOL, protocol);
|
||||
}
|
||||
|
||||
public String getProtocol() {
|
||||
private String getProtocol() {
|
||||
return getUriParameter(PROTOCOL).toString();
|
||||
}
|
||||
|
||||
|
||||
@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 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.auth.page.login;
|
||||
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
|
||||
import static org.keycloak.testsuite.util.UIUtils.clickLink;
|
||||
import static org.keycloak.testsuite.util.UIUtils.getTextFromElement;
|
||||
|
||||
/**
|
||||
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||
*/
|
||||
public class LoginError extends LoginBase {
|
||||
@FindBy(xpath = "//div[@id='kc-error-message']/p[@class='instruction']")
|
||||
private WebElement errorMessage;
|
||||
|
||||
@FindBy(id = "backToApplication")
|
||||
private WebElement backToApplicationLink;
|
||||
|
||||
public String getErrorMessage() {
|
||||
return getTextFromElement(errorMessage);
|
||||
}
|
||||
|
||||
public void backToApplication() {
|
||||
clickLink(backToApplicationLink);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCurrent() {
|
||||
return getTitleText().equals("We are sorry...");
|
||||
}
|
||||
}
|
||||
@ -34,6 +34,7 @@ import static org.keycloak.testsuite.util.UIUtils.getTextFromElement;
|
||||
*
|
||||
* @author tkyjovsk
|
||||
*/
|
||||
@Deprecated
|
||||
public class LoginForm extends Form {
|
||||
|
||||
@Page
|
||||
|
||||
@ -1,124 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 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.auth.page.login;
|
||||
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.openqa.selenium.NoSuchElementException;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
|
||||
import static org.keycloak.testsuite.util.UIUtils.clickLink;
|
||||
|
||||
/**
|
||||
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||
*/
|
||||
public class OTPSetup extends RequiredActions {
|
||||
@Page
|
||||
private LoginForm.TotpSetupForm form;
|
||||
|
||||
@FindBy(id = "kc-totp-secret-qr-code")
|
||||
private WebElement barcodeImg;
|
||||
|
||||
@FindBy(id = "kc-totp-secret-key")
|
||||
private WebElement secretKey;
|
||||
|
||||
@FindBy(id = "mode-manual")
|
||||
private WebElement manualModeLink;
|
||||
|
||||
@FindBy(id = "mode-barcode")
|
||||
private WebElement barcodeModeLink;
|
||||
|
||||
@FindBy(id = "kc-totp-type")
|
||||
private WebElement otpType;
|
||||
|
||||
@FindBy(id = "kc-totp-algorithm")
|
||||
private WebElement otpAlgorithm;
|
||||
|
||||
@FindBy(id = "kc-totp-digits")
|
||||
private WebElement otpDigits;
|
||||
|
||||
@FindBy(id = "kc-totp-period")
|
||||
private WebElement otpPeriod;
|
||||
|
||||
@FindBy(id = "kc-totp-counter")
|
||||
private WebElement otpCounter;
|
||||
|
||||
public void setTotp(String value) {
|
||||
form.setTotp(value);
|
||||
}
|
||||
|
||||
public boolean isBarcodePresent() {
|
||||
try {
|
||||
return barcodeImg.isDisplayed();
|
||||
}
|
||||
catch (NoSuchElementException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public String getSecretKey() {
|
||||
return secretKey.getText().replace(" ", "");
|
||||
}
|
||||
|
||||
public boolean isSecretKeyPresent() {
|
||||
try {
|
||||
return secretKey.isDisplayed();
|
||||
}
|
||||
catch (NoSuchElementException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void clickManualMode() {
|
||||
clickLink(manualModeLink);
|
||||
}
|
||||
|
||||
public void clickBarcodeMode() {
|
||||
clickLink(barcodeModeLink);
|
||||
}
|
||||
|
||||
public String getOtpType() {
|
||||
return otpType.getText();
|
||||
}
|
||||
|
||||
public String getOtpAlgorithm() {
|
||||
return otpAlgorithm.getText();
|
||||
}
|
||||
|
||||
public String getOtpDigits() {
|
||||
return otpDigits.getText();
|
||||
}
|
||||
|
||||
public String getOtpPeriod() {
|
||||
return otpPeriod.getText();
|
||||
}
|
||||
|
||||
public String getOtpCounter() {
|
||||
return otpCounter.getText();
|
||||
}
|
||||
|
||||
public void setUserLabel(String value) {
|
||||
form.setUserLabel(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActionId() {
|
||||
return UserModel.RequiredAction.CONFIGURE_TOTP.name();
|
||||
}
|
||||
}
|
||||
@ -83,8 +83,4 @@ public class UpdateEmailPage extends LogoutSessionsPage {
|
||||
clickLink(submitActionButton);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() throws Exception {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,91 +0,0 @@
|
||||
/*
|
||||
* 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.console.page;
|
||||
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
|
||||
import org.keycloak.testsuite.auth.page.AuthServer;
|
||||
import org.keycloak.testsuite.auth.page.login.PageWithLoginUrl;
|
||||
import org.keycloak.testsuite.console.page.fragment.Menu;
|
||||
import org.keycloak.testsuite.console.page.fragment.ModalDialog;
|
||||
import org.keycloak.testsuite.page.PageWithLogOutAction;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
|
||||
import jakarta.ws.rs.core.UriBuilder;
|
||||
import java.net.URI;
|
||||
|
||||
import static org.keycloak.testsuite.auth.page.AuthRealm.MASTER;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Petr Mensik
|
||||
*/
|
||||
public class AdminConsole extends AuthServer implements PageWithLoginUrl, PageWithLogOutAction {
|
||||
|
||||
public static final String ADMIN_REALM = "adminRealm";
|
||||
|
||||
public AdminConsole() {
|
||||
setUriParameter(ADMIN_REALM, MASTER);
|
||||
}
|
||||
|
||||
public AdminConsole setAdminRealm(String adminRealm) {
|
||||
setUriParameter(ADMIN_REALM, adminRealm);
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getAdminRealm() {
|
||||
return getUriParameter(ADMIN_REALM).toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UriBuilder createUriBuilder() {
|
||||
return super.createUriBuilder().path("admin/{" + ADMIN_REALM + "}/console");
|
||||
}
|
||||
|
||||
@Page
|
||||
private Menu menu;
|
||||
|
||||
@FindBy(xpath = "//div[@class='modal-dialog']")
|
||||
protected ModalDialog modalDialog;
|
||||
|
||||
/**
|
||||
*
|
||||
* @return OIDC Login URL for adminRealm parameter
|
||||
*/
|
||||
@Override
|
||||
public URI getOIDCLoginUrl() {
|
||||
return OIDCLoginProtocolService.authUrl(UriBuilder.fromPath(getAuthRoot()))
|
||||
.build(getAdminRealm());
|
||||
}
|
||||
|
||||
@FindBy(css = ".btn-danger")
|
||||
protected WebElement dangerButton;
|
||||
|
||||
//@FindByJQuery(".btn-primary:visible")
|
||||
@FindBy(css = ".btn-primary")
|
||||
protected WebElement primaryButton;
|
||||
|
||||
@FindBy(css = "navbar-brand")
|
||||
protected WebElement brandLink;
|
||||
|
||||
@Override
|
||||
public void logOut() {
|
||||
menu.logOut();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,65 +0,0 @@
|
||||
/*
|
||||
* 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.console.page;
|
||||
|
||||
import jakarta.ws.rs.core.UriBuilder;
|
||||
|
||||
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
|
||||
import static org.keycloak.testsuite.console.page.AdminConsoleRealm.CONSOLE_REALM;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author tkyjovsk
|
||||
*/
|
||||
public class AdminConsoleCreate extends AdminConsole {
|
||||
|
||||
public static final String ENTITY = "entity";
|
||||
|
||||
public AdminConsoleCreate() {
|
||||
setUriParameter(CONSOLE_REALM, TEST);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UriBuilder createUriBuilder() {
|
||||
return super.createUriBuilder().path("/");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUriFragment() {
|
||||
return "/create/{" + ENTITY + "}/{" + CONSOLE_REALM + "}";
|
||||
}
|
||||
|
||||
public AdminConsoleCreate setEntity(String entity) {
|
||||
setUriParameter(ENTITY, entity);
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getEntity() {
|
||||
return getUriParameter(ENTITY).toString();
|
||||
}
|
||||
|
||||
public AdminConsoleCreate setConsoleRealm(String consoleRealm) {
|
||||
setUriParameter(CONSOLE_REALM, consoleRealm);
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getConsoleRealm() {
|
||||
return getUriParameter(CONSOLE_REALM).toString();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,228 +0,0 @@
|
||||
/*
|
||||
* 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.console.page;
|
||||
|
||||
import org.keycloak.testsuite.util.UIUtils;
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.NoSuchElementException;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
|
||||
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author tkyjovsk
|
||||
*/
|
||||
public class AdminConsoleRealm extends AdminConsoleRealmsRoot {
|
||||
|
||||
public static final String CONSOLE_REALM = "consoleRealm";
|
||||
|
||||
public AdminConsoleRealm() {
|
||||
setUriParameter(CONSOLE_REALM, TEST);
|
||||
}
|
||||
|
||||
public AdminConsoleRealm setConsoleRealm(String realm) {
|
||||
setUriParameter(CONSOLE_REALM, realm);
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getConsoleRealm() {
|
||||
return getUriParameter(CONSOLE_REALM).toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUriFragment() {
|
||||
return super.getUriFragment() + "/{" + CONSOLE_REALM + "}";
|
||||
}
|
||||
|
||||
@FindBy(xpath = "//div[./h2[text()='Configure']]")
|
||||
private ConfigureMenu configureMenu;
|
||||
|
||||
public ConfigureMenu configure() {
|
||||
waitUntilElement(By.xpath("//div[./h2[text()='Configure']]")).is().present();
|
||||
return configureMenu;
|
||||
}
|
||||
|
||||
public static class ConfigureMenu {
|
||||
|
||||
@FindBy(partialLinkText = "Realm Settings")
|
||||
private WebElement realmSettingsLink;
|
||||
@FindBy(partialLinkText = "Clients")
|
||||
private WebElement clientsLink;
|
||||
@FindBy(partialLinkText = "Client Scopes")
|
||||
private WebElement clientScopesLink;
|
||||
@FindBy(partialLinkText = "Roles")
|
||||
private WebElement rolesLink;
|
||||
@FindBy(partialLinkText = "Identity Providers")
|
||||
private WebElement identityProvidersLink;
|
||||
@FindBy(partialLinkText = "User Federation")
|
||||
private WebElement userFederationLink;
|
||||
@FindBy(partialLinkText = "Authentication")
|
||||
private WebElement authenticationLink;
|
||||
|
||||
public void realmSettings() {
|
||||
navigateToTab(realmSettingsLink);
|
||||
}
|
||||
|
||||
public void clients() {
|
||||
navigateToTab(clientsLink);
|
||||
}
|
||||
|
||||
public void clientScopesLink() {
|
||||
navigateToTab(clientScopesLink);
|
||||
}
|
||||
|
||||
public void roles() {
|
||||
navigateToTab(rolesLink);
|
||||
}
|
||||
|
||||
public void identityProviders() {
|
||||
navigateToTab(identityProvidersLink);
|
||||
}
|
||||
|
||||
public void userFederation() {
|
||||
navigateToTab(userFederationLink);
|
||||
}
|
||||
|
||||
public void authentication() {
|
||||
navigateToTab(authenticationLink);
|
||||
}
|
||||
|
||||
// Elements
|
||||
public WebElement getRealmSettingsTab() {
|
||||
return realmSettingsLink;
|
||||
}
|
||||
|
||||
public WebElement getClientsTab() {
|
||||
return clientsLink;
|
||||
}
|
||||
|
||||
public WebElement getClientScopesTab() {
|
||||
return clientScopesLink;
|
||||
}
|
||||
|
||||
public WebElement getRolesTab() {
|
||||
return rolesLink;
|
||||
}
|
||||
|
||||
public WebElement getUserFederationTab() {
|
||||
return userFederationLink;
|
||||
}
|
||||
|
||||
public WebElement getIdentityProvidersTab() {
|
||||
return identityProvidersLink;
|
||||
}
|
||||
|
||||
public WebElement getAuthenticationTab() {
|
||||
return authenticationLink;
|
||||
}
|
||||
}
|
||||
|
||||
@FindBy(xpath = "//div[./h2[text()='Manage']]")
|
||||
protected ManageMenu manageMenu;
|
||||
|
||||
public ManageMenu manage() {
|
||||
waitUntilElement(By.xpath("//div[./h2[text()='Manage']]")).is().present();
|
||||
return manageMenu;
|
||||
}
|
||||
|
||||
public static class ManageMenu {
|
||||
@FindBy(partialLinkText = "Groups")
|
||||
private WebElement groupsLink;
|
||||
@FindBy(partialLinkText = "Users")
|
||||
private WebElement usersLink;
|
||||
@FindBy(partialLinkText = "Sessions")
|
||||
private WebElement sessionsLink;
|
||||
@FindBy(partialLinkText = "Events")
|
||||
private WebElement eventsLink;
|
||||
@FindBy(partialLinkText = "Import")
|
||||
private WebElement importLink;
|
||||
@FindBy(partialLinkText = "Export")
|
||||
private WebElement exportLink;
|
||||
|
||||
public void groups() {
|
||||
navigateToTab(groupsLink);
|
||||
}
|
||||
|
||||
public void users() {
|
||||
navigateToTab(usersLink);
|
||||
}
|
||||
|
||||
public void sessions() {
|
||||
navigateToTab(sessionsLink);
|
||||
}
|
||||
|
||||
public void events() {
|
||||
navigateToTab(eventsLink);
|
||||
}
|
||||
|
||||
public void importTab() {
|
||||
navigateToTab(importLink);
|
||||
}
|
||||
|
||||
public void exportTab() {
|
||||
navigateToTab(exportLink);
|
||||
}
|
||||
|
||||
// Elements
|
||||
public WebElement getGroupsTab() {
|
||||
return groupsLink;
|
||||
}
|
||||
|
||||
public WebElement getUsersTab() {
|
||||
return groupsLink;
|
||||
}
|
||||
|
||||
public WebElement getSessionsTab() {
|
||||
return groupsLink;
|
||||
}
|
||||
|
||||
public WebElement getEventsTab() {
|
||||
return groupsLink;
|
||||
}
|
||||
|
||||
public WebElement getImportTab() {
|
||||
return groupsLink;
|
||||
}
|
||||
|
||||
public WebElement getExportTab() {
|
||||
return groupsLink;
|
||||
}
|
||||
}
|
||||
|
||||
public static void navigateToTab(WebElement tab) {
|
||||
if (tab == null) return;
|
||||
UIUtils.clickLink(tab);
|
||||
}
|
||||
|
||||
public static boolean isTabActive(WebElement tab) {
|
||||
try {
|
||||
final WebElement parent = tab != null ? tab.findElement(By.xpath("./..")) : null;
|
||||
|
||||
return parent != null && Optional.ofNullable(parent.getAttribute("class"))
|
||||
.map(f -> f.equals("active"))
|
||||
.orElse(false);
|
||||
} catch (NoSuchElementException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,66 +0,0 @@
|
||||
/*
|
||||
* 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.console.page;
|
||||
|
||||
import org.keycloak.testsuite.console.page.fragment.RealmSelector;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
|
||||
import jakarta.ws.rs.core.UriBuilder;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author tkyjovsk
|
||||
*/
|
||||
public class AdminConsoleRealmsRoot extends AdminConsole {
|
||||
|
||||
@FindBy(xpath = "//tr[@data-ng-repeat='r in realms']//a[contains(@class,'ng-binding')]")
|
||||
private List<WebElement> realmLinks;
|
||||
|
||||
@Override
|
||||
public UriBuilder createUriBuilder() {
|
||||
return super.createUriBuilder().path("/");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUriFragment() {
|
||||
return "/realms";
|
||||
}
|
||||
|
||||
public void clickRealm(String realm) {
|
||||
boolean linkFound = false;
|
||||
for (WebElement realmLink : realmLinks) {
|
||||
if (realmLink.getText().equals(realm)) {
|
||||
linkFound = true;
|
||||
realmLink.click();
|
||||
}
|
||||
}
|
||||
if (!linkFound) {
|
||||
throw new IllegalStateException("A link for realm '" + realm + "' not found on the Realms page.");
|
||||
}
|
||||
}
|
||||
|
||||
@FindBy(css = "realm-selector")
|
||||
protected RealmSelector realmSelector;
|
||||
|
||||
// public RealmsResource realmsResource() {
|
||||
// return keycloak.realms();
|
||||
// }
|
||||
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
/*
|
||||
* 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.console.page;
|
||||
|
||||
import jakarta.ws.rs.core.UriBuilder;
|
||||
|
||||
public class ForbiddenPage extends AdminConsole {
|
||||
|
||||
@Override
|
||||
public UriBuilder createUriBuilder() {
|
||||
return super.createUriBuilder().path("/");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUriFragment() {
|
||||
return "/forbidden";
|
||||
}
|
||||
}
|
||||
@ -1,124 +0,0 @@
|
||||
/*
|
||||
* 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.console.page.events;
|
||||
|
||||
import org.keycloak.testsuite.console.page.fragment.DataTable;
|
||||
import org.keycloak.testsuite.page.Form;
|
||||
import org.keycloak.testsuite.util.UIUtils;
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
|
||||
/**
|
||||
* @author tkyjovsk
|
||||
* @author mhajas
|
||||
*/
|
||||
public class AdminEvents extends Events {
|
||||
|
||||
@Override
|
||||
public String getUriFragment() {
|
||||
return super.getUriFragment() + "/admin-events";
|
||||
}
|
||||
|
||||
@FindBy(tagName = "table")
|
||||
private AdminEventsTable table;
|
||||
|
||||
public AdminEventsTable table() {
|
||||
return table;
|
||||
}
|
||||
|
||||
public static class AdminEventsTable extends DataTable {
|
||||
|
||||
@FindBy(xpath = "//button[text()[contains(.,'Filter')]]")
|
||||
private WebElement filterButton;
|
||||
|
||||
@FindBy(tagName = "form")
|
||||
private AdminEventsTableFilterForm filterForm;
|
||||
|
||||
public void update() {
|
||||
clickHeaderButton("Update");
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
clickHeaderButton("Reset");
|
||||
}
|
||||
|
||||
public void filter() {
|
||||
filterButton.click();
|
||||
}
|
||||
|
||||
public AdminEventsTableFilterForm filterForm() {
|
||||
return filterForm;
|
||||
}
|
||||
|
||||
public class AdminEventsTableFilterForm extends Form {
|
||||
|
||||
@FindBy(id = "resource")
|
||||
private WebElement resourcePathInput;
|
||||
|
||||
@FindBy(id = "realm")
|
||||
private WebElement realmInput;
|
||||
|
||||
@FindBy(id = "client")
|
||||
private WebElement clientInput;
|
||||
|
||||
@FindBy(id = "user")
|
||||
private WebElement userInput;
|
||||
|
||||
@FindBy(id = "ipAddress")
|
||||
private WebElement ipAddressInput;
|
||||
|
||||
@FindBy(xpath = "//div[@id='s2id_adminEnabledEventOperations']/ul")
|
||||
private WebElement operationTypesInput;
|
||||
|
||||
@FindBy(xpath = "//div[@id='select2-drop']")
|
||||
private WebElement operationTypesValues;
|
||||
|
||||
public void addOperationType(String type) {
|
||||
operationTypesInput.click();
|
||||
operationTypesValues.findElement(By.xpath("//div[text() = '" + type + "']")).click();
|
||||
}
|
||||
|
||||
public void removeOperationType(String type) {
|
||||
operationTypesInput.findElement(By.xpath("//div[text()='" + type + "']/../a")).click();
|
||||
}
|
||||
|
||||
public void setResourcePathInput(String value) {
|
||||
UIUtils.setTextInputValue(resourcePathInput, value);
|
||||
}
|
||||
|
||||
public void setRealmInput(String value) {
|
||||
UIUtils.setTextInputValue(realmInput, value);
|
||||
}
|
||||
|
||||
public void setClientInput(String value) {
|
||||
UIUtils.setTextInputValue(clientInput, value);
|
||||
}
|
||||
|
||||
public void setUserInput(String value) {
|
||||
UIUtils.setTextInputValue(userInput, value);
|
||||
}
|
||||
|
||||
public void setIpAddressInput(String value) {
|
||||
UIUtils.setTextInputValue(ipAddressInput, value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,129 +0,0 @@
|
||||
/*
|
||||
* 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.console.page.events;
|
||||
|
||||
import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
|
||||
import org.keycloak.testsuite.page.Form;
|
||||
import org.keycloak.testsuite.util.UIUtils;
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
import org.openqa.selenium.support.ui.Select;
|
||||
|
||||
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
|
||||
|
||||
/**
|
||||
* @author tkyjovsk
|
||||
* @author mhajas
|
||||
*/
|
||||
public class Config extends Events {
|
||||
|
||||
@Override
|
||||
public String getUriFragment() {
|
||||
return super.getUriFragment() + "/events-settings";
|
||||
}
|
||||
|
||||
@FindBy(xpath = "//form")
|
||||
private ConfigForm form;
|
||||
|
||||
public ConfigForm form() {
|
||||
return form;
|
||||
}
|
||||
|
||||
public static class ConfigForm extends Form {
|
||||
@FindBy(id = "s2id_autogen1")
|
||||
private WebElement eventListenersInput;
|
||||
|
||||
@FindBy(xpath = "//div[@id='s2id_autogen1']/..//select")
|
||||
private Select eventListenersSelect;
|
||||
|
||||
@FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='enabled']]")
|
||||
private OnOffSwitch SaveEvents;
|
||||
|
||||
@FindBy(xpath = "//div[@id='s2id_enabledEventTypes']//input")
|
||||
private WebElement savedTypesInput;
|
||||
|
||||
@FindBy(xpath = "//div[@id='select2-drop']/ul")
|
||||
private WebElement savedTypesOptions;
|
||||
|
||||
@FindBy(id = "expiration")
|
||||
private WebElement expirationInput;
|
||||
|
||||
@FindBy(name = "expirationUnit")
|
||||
private Select expirationUnitSelect;
|
||||
|
||||
@FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='adminEventsEnabled']]")
|
||||
private OnOffSwitch saveAdminEvents;
|
||||
|
||||
@FindBy(xpath = ".//div[@class='onoffswitch' and ./input[@id='adminEventsDetailsEnabled']]")
|
||||
private OnOffSwitch includeRepresentation;
|
||||
|
||||
@FindBy(xpath = "//button[@data-ng-click='clearEvents()']")
|
||||
private WebElement clearLoginEventsButton;
|
||||
|
||||
@FindBy(xpath = "//button[@data-ng-click='clearAdminEvents()']")
|
||||
private WebElement clearAdminEventsButton;
|
||||
|
||||
public void addEventListener(String listener) {
|
||||
eventListenersInput.click();
|
||||
eventListenersSelect.selectByVisibleText(listener);
|
||||
}
|
||||
|
||||
public void removeEventListener(String listener) {
|
||||
eventListenersInput.findElement(By.xpath("//div[text()='" + listener + "']/../a")).click();
|
||||
}
|
||||
|
||||
public void setSaveEvents(boolean value) {
|
||||
SaveEvents.setOn(value);
|
||||
}
|
||||
|
||||
public void addSaveType(String type) {
|
||||
savedTypesInput.click();
|
||||
savedTypesOptions.findElement(By.xpath("//div[text()='" + type + "']")).click();
|
||||
}
|
||||
|
||||
public void removeSaveType(String type) {
|
||||
savedTypesInput.findElement(By.xpath("//div[text()='" + type + "']/../a")).click();
|
||||
}
|
||||
|
||||
public void clearLoginEvents() {
|
||||
clearLoginEventsButton.click();
|
||||
}
|
||||
|
||||
public void setExpiration(String value, String unit) {
|
||||
expirationUnitSelect.selectByVisibleText(unit);
|
||||
UIUtils.setTextInputValue(expirationInput, value);
|
||||
}
|
||||
|
||||
public void setSaveAdminEvents(boolean value) {
|
||||
saveAdminEvents.setOn(value);
|
||||
}
|
||||
|
||||
public void setIncludeRepresentation(boolean value) {
|
||||
includeRepresentation.setOn(value);
|
||||
}
|
||||
|
||||
public void clearAdminEvents() {
|
||||
clearAdminEventsButton.click();
|
||||
}
|
||||
|
||||
public void waitForClearEventsButtonPresent() {
|
||||
waitUntilElement(clearLoginEventsButton).is().present();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,52 +0,0 @@
|
||||
/*
|
||||
* 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.console.page.events;
|
||||
|
||||
import org.keycloak.testsuite.console.page.AdminConsoleRealm;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author tkyjovsk
|
||||
*/
|
||||
public class Events extends AdminConsoleRealm {
|
||||
|
||||
@Override
|
||||
public String getUriFragment() {
|
||||
return super.getUriFragment();
|
||||
}
|
||||
|
||||
@FindBy(linkText = "Login Events")
|
||||
private WebElement loginEventsTab;
|
||||
@FindBy(linkText = "Admin Events")
|
||||
private WebElement adminEventsTab;
|
||||
@FindBy(linkText = "Config")
|
||||
private WebElement configTab;
|
||||
|
||||
public void loginEvents() {
|
||||
loginEventsTab.click();
|
||||
}
|
||||
public void adminEvents() {
|
||||
adminEventsTab.click();
|
||||
}
|
||||
public void config() {
|
||||
configTab.click();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,101 +0,0 @@
|
||||
/*
|
||||
* 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.console.page.events;
|
||||
|
||||
import org.keycloak.testsuite.console.page.fragment.DataTable;
|
||||
import org.keycloak.testsuite.page.Form;
|
||||
import org.keycloak.testsuite.util.UIUtils;
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
|
||||
/**
|
||||
* @author tkyjovsk
|
||||
* @author mhajas
|
||||
*/
|
||||
public class LoginEvents extends Events {
|
||||
|
||||
@Override
|
||||
public String getUriFragment() {
|
||||
return super.getUriFragment() + "/events";
|
||||
}
|
||||
|
||||
@FindBy(tagName = "table")
|
||||
private LoginEventsTable table;
|
||||
|
||||
public LoginEventsTable table() {
|
||||
return table;
|
||||
}
|
||||
|
||||
public static class LoginEventsTable extends DataTable {
|
||||
|
||||
@FindBy(xpath = "//button[text()[contains(.,'Filter')]]")
|
||||
private WebElement filterButton;
|
||||
|
||||
@FindBy(tagName = "form")
|
||||
private LoginEventsTableFilterForm filterForm;
|
||||
|
||||
public void update() {
|
||||
clickHeaderButton("Update");
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
clickHeaderButton("Reset");
|
||||
}
|
||||
|
||||
public void filter() {
|
||||
filterButton.click();
|
||||
}
|
||||
|
||||
public LoginEventsTableFilterForm filterForm() {
|
||||
return filterForm;
|
||||
}
|
||||
|
||||
public class LoginEventsTableFilterForm extends Form {
|
||||
|
||||
@FindBy(id = "client")
|
||||
private WebElement clientInput;
|
||||
|
||||
@FindBy(id = "user")
|
||||
private WebElement userInput;
|
||||
|
||||
@FindBy(xpath = "//div[@id='s2id_eventTypes']/ul")
|
||||
private WebElement eventTypeInput;
|
||||
|
||||
@FindBy(xpath = "//div[@id='select2-drop']")
|
||||
private WebElement eventTypeValues;
|
||||
|
||||
public void addEventType(String type) {
|
||||
eventTypeInput.click();
|
||||
eventTypeValues.findElement(By.xpath("//div[text()='" + type + "']")).click();
|
||||
}
|
||||
|
||||
public void removeOperationType(String type) {
|
||||
eventTypeInput.findElement(By.xpath("//div[text()='" + type + "']/../a]")).click();
|
||||
}
|
||||
|
||||
public void setClientInput(String value) {
|
||||
UIUtils.setTextInputValue(clientInput, value);
|
||||
}
|
||||
|
||||
public void setUserInput(String value) {
|
||||
UIUtils.setTextInputValue(userInput, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,160 +0,0 @@
|
||||
/*
|
||||
* 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.console.page.fragment;
|
||||
|
||||
import org.jboss.arquillian.drone.api.annotation.Drone;
|
||||
import org.jboss.arquillian.graphene.fragment.Root;
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.JavascriptExecutor;
|
||||
import org.openqa.selenium.Keys;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static org.keycloak.testsuite.util.UIUtils.clickLink;
|
||||
import static org.keycloak.testsuite.util.WaitUtils.pause;
|
||||
import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public abstract class AbstractMultipleSelect2<R> {
|
||||
|
||||
@Root
|
||||
private WebElement root;
|
||||
|
||||
@Drone
|
||||
private WebDriver driver;
|
||||
|
||||
@FindBy(xpath = "//input[contains(@class,'select2-focused')]")
|
||||
private WebElement search;
|
||||
|
||||
@FindBy(xpath = "//div[contains(@class,'select2-result-label')]")
|
||||
private List<WebElement> result;
|
||||
|
||||
public void update(Set<R> values) {
|
||||
Set<R> selection = getSelected();
|
||||
|
||||
for (R value : values) {
|
||||
if (!selection.contains(value)) {
|
||||
select(value);
|
||||
}
|
||||
}
|
||||
|
||||
for (R selected : selection) {
|
||||
boolean isSelected = false;
|
||||
|
||||
for (R value : values) {
|
||||
if (selected.equals(value)) {
|
||||
isSelected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isSelected) {
|
||||
deselect(selected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void select(R value) {
|
||||
pause(500);
|
||||
root.click();
|
||||
pause(500);
|
||||
|
||||
String id = identity().apply(value);
|
||||
|
||||
search.sendKeys(id);
|
||||
waitForPageToLoad();
|
||||
|
||||
if (result.isEmpty()) {
|
||||
search.sendKeys(Keys.ESCAPE);
|
||||
return;
|
||||
}
|
||||
|
||||
for (WebElement result : result) {
|
||||
if (match(result.getText(), id)) {
|
||||
clickLink(result);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Function<R, String> identity();
|
||||
|
||||
protected boolean match(String result, String search) {
|
||||
return result != null && result.equalsIgnoreCase(search);
|
||||
};
|
||||
|
||||
public Set<R> getSelected() {
|
||||
Set<R> values = new HashSet<>();
|
||||
|
||||
for (WebElement selected : getSelectedElements()) {
|
||||
R value = representation().apply(selected);
|
||||
|
||||
if (value != null) {
|
||||
values.add(value);
|
||||
}
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
protected abstract List<WebElement> getSelectedElements();
|
||||
|
||||
protected abstract Function<WebElement, R> representation();
|
||||
|
||||
public void deselect(R value) {
|
||||
onDeselect(value);
|
||||
}
|
||||
|
||||
protected void onDeselect(R value) {
|
||||
for (WebElement selected : getSelectedElements()) {
|
||||
if (deselect().apply(selected, value)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected BiFunction<WebElement, R, Boolean> deselect() {
|
||||
return (selected, value) -> {
|
||||
WebElement selection = selected.findElements(By.tagName("div")).get(0);
|
||||
if (identity().apply(value).equals(selection.getText())) {
|
||||
WebElement element = selected.findElement(By.xpath(".//a[contains(@class,'select2-search-choice-close')]"));
|
||||
JavascriptExecutor executor = (JavascriptExecutor) driver;
|
||||
executor.executeScript("arguments[0].click();", element);
|
||||
pause(500);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
protected WebElement getRoot() {
|
||||
return root;
|
||||
}
|
||||
|
||||
protected WebDriver getDriver() {
|
||||
return driver;
|
||||
}
|
||||
}
|
||||
@ -1,52 +0,0 @@
|
||||
/*
|
||||
* 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.console.page.fragment;
|
||||
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author tkyjovsk
|
||||
*/
|
||||
public class Breadcrumb {
|
||||
|
||||
public static final String BREADCRUMB_XPATH = "//ol[@class='breadcrumb']";
|
||||
|
||||
@FindBy(xpath = "./li[not(contains(@class,'ng-hide'))]/a")
|
||||
private List<WebElement> items;
|
||||
|
||||
public int size() {
|
||||
return items.size();
|
||||
}
|
||||
|
||||
public WebElement getItem(int index) {
|
||||
return items.get(index);
|
||||
}
|
||||
|
||||
public WebElement getItemFromEnd(int index) {
|
||||
return items.get(size() - index - 1);
|
||||
}
|
||||
|
||||
public void clickItemOneLevelUp() {
|
||||
getItemFromEnd(0).click();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,139 +0,0 @@
|
||||
/*
|
||||
* 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.console.page.fragment;
|
||||
|
||||
import org.jboss.arquillian.drone.api.annotation.Drone;
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.NoSuchElementException;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.keycloak.testsuite.util.UIUtils.clickLink;
|
||||
import static org.keycloak.testsuite.util.UIUtils.getTextFromElement;
|
||||
import static org.keycloak.testsuite.util.WaitUtils.pause;
|
||||
import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
|
||||
import static org.openqa.selenium.By.tagName;
|
||||
import static org.openqa.selenium.By.xpath;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author tkyjovsk
|
||||
*/
|
||||
public class DataTable {
|
||||
|
||||
@Drone
|
||||
protected WebDriver driver;
|
||||
|
||||
@FindBy(css = "input[class*='search']")
|
||||
private WebElement searchInput;
|
||||
@FindBy(css = "div[class='input-group-addon'] i")
|
||||
private WebElement searchButton;
|
||||
|
||||
@FindBy(tagName = "thead")
|
||||
private WebElement header;
|
||||
@FindBy(css = "tbody")
|
||||
private WebElement body;
|
||||
@FindBy(xpath = "tbody/tr[@class='ng-scope']")
|
||||
private List<WebElement> rows;
|
||||
|
||||
@FindBy(tagName = "tfoot")
|
||||
private WebElement footer;
|
||||
|
||||
public void search(String pattern) {
|
||||
searchInput.sendKeys(pattern);
|
||||
clickLink(searchButton);
|
||||
}
|
||||
|
||||
public void clickHeaderButton(String buttonText) {
|
||||
clickLink(header.findElement(By.xpath(".//button[text()='" + buttonText + "']")));
|
||||
}
|
||||
|
||||
public void clickHeaderLink(String linkText) {
|
||||
clickLink(header.findElement(By.linkText(linkText)));
|
||||
}
|
||||
|
||||
public WebElement body() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public WebElement footer() {
|
||||
return footer;
|
||||
}
|
||||
|
||||
|
||||
public List<WebElement> rows() {
|
||||
waitForPageToLoad();
|
||||
pause(500); // wait a bit to ensure the table is no more changing
|
||||
return rows;
|
||||
}
|
||||
|
||||
public WebElement getRowByLinkText(String text) {
|
||||
WebElement row = body.findElement(By.xpath(".//tr[./td/a[text()='" + text + "']]"));
|
||||
return row;
|
||||
}
|
||||
|
||||
public void clickRowByLinkText(String text) {
|
||||
clickLink(body.findElement(By.xpath(".//tr/td/a[text()='" + text + "']")));
|
||||
}
|
||||
|
||||
public WebElement getActionButton(WebElement row, String buttonText) {
|
||||
return row.findElement(xpath(".//td[contains(@class, 'kc-action-cell') and text()='" + buttonText + "']"));
|
||||
}
|
||||
|
||||
public WebElement getActionButton(String rowLinkText, String buttonText) {
|
||||
return getActionButton(getRowByLinkText(rowLinkText), buttonText);
|
||||
}
|
||||
|
||||
public boolean isActionButtonVisible(String rowLinkText, String buttonText) {
|
||||
try {
|
||||
return getActionButton(rowLinkText, buttonText).isDisplayed();
|
||||
}
|
||||
catch (NoSuchElementException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void clickRowActionButton(WebElement row, String buttonText) {
|
||||
clickLink(getActionButton(row, buttonText));
|
||||
}
|
||||
|
||||
public void clickRowActionButton(String rowLinkText, String buttonText) {
|
||||
clickLink(getActionButton(rowLinkText, buttonText));
|
||||
}
|
||||
|
||||
public String getColumnText(WebElement row, int colIndex) {
|
||||
return getTextFromElement(row.findElements(tagName("td")).get(colIndex));
|
||||
}
|
||||
|
||||
public String getColumnText(String rowLinkText, int colIndex) {
|
||||
return getColumnText(getRowByLinkText(rowLinkText), colIndex);
|
||||
}
|
||||
|
||||
public boolean isRowPresent(String rowLinkText) {
|
||||
try {
|
||||
return getRowByLinkText(rowLinkText).isDisplayed();
|
||||
}
|
||||
catch (NoSuchElementException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,47 +0,0 @@
|
||||
/*
|
||||
* 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.console.page.fragment;
|
||||
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.keycloak.testsuite.util.UIUtils.getTextInputValue;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author tkyjovsk
|
||||
*/
|
||||
public class InputList {
|
||||
|
||||
@FindBy(xpath=".//input[@ng-model='client.redirectUris[i]']")
|
||||
private List<WebElement> inputs;
|
||||
|
||||
public List<String> getValues() {
|
||||
List<String> values = new ArrayList<>();
|
||||
for (WebElement input: inputs) {
|
||||
values.add(getTextInputValue(input));
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 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.console.page.fragment;
|
||||
|
||||
import org.jboss.arquillian.graphene.fragment.Root;
|
||||
import org.openqa.selenium.ElementNotInteractableException;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
|
||||
import static org.keycloak.testsuite.util.UIUtils.setTextInputValue;
|
||||
|
||||
/**
|
||||
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||
*/
|
||||
public class KcPassword {
|
||||
@Root
|
||||
private WebElement inputField;
|
||||
|
||||
@FindBy(xpath = "../span[contains(@class,'input-group-addon') and ./span[contains(@class,'fa-eye')]]")
|
||||
private WebElement eyeButton;
|
||||
|
||||
public void setValue(final String value) {
|
||||
setTextInputValue(inputField, value);
|
||||
}
|
||||
|
||||
public boolean isMasked() {
|
||||
return inputField.getAttribute("class").contains("password-conceal");
|
||||
}
|
||||
|
||||
public boolean isEyeButtonDisabled() {
|
||||
return eyeButton.getAttribute("class").contains("disabled");
|
||||
}
|
||||
|
||||
public void clickEyeButton() {
|
||||
if (isEyeButtonDisabled()) {
|
||||
throw new ElementNotInteractableException("The eye button is disabled and cannot be clicked");
|
||||
}
|
||||
eyeButton.click();
|
||||
}
|
||||
|
||||
public WebElement getElement() {
|
||||
return inputField;
|
||||
}
|
||||
}
|
||||
@ -1,89 +0,0 @@
|
||||
/*
|
||||
* 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.console.page.fragment;
|
||||
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.keycloak.testsuite.util.UIUtils.clickLink;
|
||||
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Petr Mensik
|
||||
*/
|
||||
public class Menu {
|
||||
|
||||
private static final String MENU_LOCATOR = "ul[class='dropdown-menu']";
|
||||
|
||||
@FindBy(css = MENU_LOCATOR)
|
||||
private List<WebElement> menuList;
|
||||
|
||||
@FindBy(css = ".dropdown-toggle")
|
||||
private List<WebElement> toggle;
|
||||
|
||||
public void logOut() {
|
||||
clickOnMenuElement(MenuType.USER, "Sign Out");
|
||||
}
|
||||
|
||||
public void goToAccountManagement() {
|
||||
clickOnMenuElement(MenuType.USER, "Manage Account");
|
||||
}
|
||||
|
||||
public void switchRealm(String realmName) {
|
||||
if (!realmName.equals(getCurrentRealm())) {
|
||||
clickOnMenuElement(MenuType.REALM, realmName);
|
||||
}
|
||||
}
|
||||
|
||||
public String getCurrentRealm() {
|
||||
waitUntilElement(By.cssSelector(MENU_LOCATOR)).is().present();
|
||||
return toggle.get(1).getText();
|
||||
}
|
||||
|
||||
private void clickOnMenuElement(MenuType menuType, String linkText) {
|
||||
int menuOrder = 0;
|
||||
switch (menuType) {
|
||||
case REALM:
|
||||
menuOrder = 1;
|
||||
break;
|
||||
case USER:
|
||||
menuOrder = 0;
|
||||
break;
|
||||
}
|
||||
waitUntilElement(By.cssSelector(MENU_LOCATOR)).is().present();
|
||||
if (!menuList.get(menuOrder).isDisplayed()) {
|
||||
toggle.get(menuOrder).click();
|
||||
}
|
||||
for (WebElement item : menuList.get(menuOrder).findElements(By.cssSelector(MENU_LOCATOR + " a"))) {
|
||||
if (item.getText().contains(linkText)) {
|
||||
clickLink(item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("Could not find menu item containing \"" + linkText + "\"");
|
||||
}
|
||||
|
||||
private enum MenuType {
|
||||
|
||||
USER, REALM
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,80 +0,0 @@
|
||||
/*
|
||||
* 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.console.page.fragment;
|
||||
|
||||
import org.jboss.arquillian.drone.api.annotation.Drone;
|
||||
import org.jboss.arquillian.graphene.fragment.Root;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
|
||||
import static org.keycloak.testsuite.util.WaitUtils.waitForModalFadeIn;
|
||||
import static org.keycloak.testsuite.util.WaitUtils.waitForModalFadeOut;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author tkyjovsk
|
||||
*/
|
||||
public class ModalDialog {
|
||||
|
||||
@Root
|
||||
private WebElement root;
|
||||
|
||||
@Drone
|
||||
private WebDriver driver;
|
||||
|
||||
@FindBy(xpath = ".//button[text()='Cancel']")
|
||||
private WebElement cancelButton;
|
||||
@FindBy(xpath = ".//button[text()='Delete']")
|
||||
private WebElement deleteButton;
|
||||
|
||||
@FindBy(xpath = ".//button[@ng-click='ok()']")
|
||||
private WebElement okButton;
|
||||
@FindBy(id = "name")
|
||||
private WebElement nameInput;
|
||||
|
||||
@FindBy(className = "modal-body")
|
||||
private WebElement message;
|
||||
|
||||
public void ok() {
|
||||
waitForModalFadeIn();
|
||||
okButton.click();
|
||||
waitForModalFadeOut();
|
||||
}
|
||||
|
||||
public void confirmDeletion() {
|
||||
waitForModalFadeIn();
|
||||
deleteButton.click();
|
||||
waitForModalFadeOut();
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
waitForModalFadeIn();
|
||||
cancelButton.click();
|
||||
waitForModalFadeOut();
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
nameInput.clear();
|
||||
nameInput.sendKeys(name);
|
||||
}
|
||||
|
||||
public WebElement getMessage() {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 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.console.page.fragment;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.WebElement;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class MultipleStringSelect2 extends AbstractMultipleSelect2<String> {
|
||||
|
||||
@Override
|
||||
protected Function<String, String> identity() {
|
||||
return r -> r.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<WebElement> getSelectedElements() {
|
||||
return getRoot().findElements(By.xpath(".//li[contains(@class,'select2-search-choice')]"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Function<WebElement, String> representation() {
|
||||
return webElement -> {
|
||||
List<WebElement> element = webElement.findElements(By.tagName("div"));
|
||||
|
||||
if (element.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String value = element.get(0).getText();
|
||||
|
||||
return "".equals(value) ? null : value;
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -1,60 +0,0 @@
|
||||
/*
|
||||
* 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.console.page.fragment;
|
||||
|
||||
import org.jboss.arquillian.graphene.fragment.Root;
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
import org.openqa.selenium.support.ui.Select;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Petr Mensik
|
||||
*/
|
||||
|
||||
public class PickList {
|
||||
|
||||
@Root
|
||||
private WebElement root;
|
||||
|
||||
private Select firstSelect;
|
||||
private Select secondSelect;
|
||||
|
||||
@FindBy(className = "kc-icon-arrow-right")
|
||||
private WebElement rightArrow;
|
||||
|
||||
@FindBy(className = "kc-icon-arrow-left")
|
||||
private WebElement leftArrow;
|
||||
|
||||
public void addItems(String... values) {
|
||||
for(String value : values) {
|
||||
firstSelect.selectByVisibleText(value);
|
||||
}
|
||||
rightArrow.click();
|
||||
}
|
||||
|
||||
public void setFirstSelect(By locator) {
|
||||
firstSelect = new Select(root.findElement(locator));
|
||||
}
|
||||
|
||||
public void setSecondSelect(By locator) {
|
||||
secondSelect = new Select(root.findElement(locator));
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
/*
|
||||
* 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.console.page.fragment;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author tkyjovsk
|
||||
*/
|
||||
public class RealmSelector {
|
||||
|
||||
// TODO
|
||||
|
||||
}
|
||||
@ -1,64 +0,0 @@
|
||||
/*
|
||||
* 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.console.page.fragment;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.keycloak.testsuite.util.WaitUtils;
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.JavascriptExecutor;
|
||||
import org.openqa.selenium.WebElement;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||
*/
|
||||
public class SingleStringSelect2 extends AbstractMultipleSelect2<String> {
|
||||
|
||||
@Override
|
||||
protected Function<String, String> identity() {
|
||||
return r -> r.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<WebElement> getSelectedElements() {
|
||||
return getRoot().findElements(By.xpath(".//span[contains(@class,'select2-chosen')]"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Function<WebElement, String> representation() {
|
||||
return webElement -> {
|
||||
String value = webElement.getText();
|
||||
return "".equals(value) ? null : value;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BiFunction<WebElement, String, Boolean> deselect() {
|
||||
return (selected, value) -> {
|
||||
if (identity().apply(value).equals(selected.getText())) {
|
||||
WebElement element = selected.findElement(By.xpath(".//a[contains(@class,'select2-search-choice-close')]"));
|
||||
JavascriptExecutor executor = (JavascriptExecutor) getDriver();
|
||||
executor.executeScript("arguments[0].click();", element);
|
||||
WaitUtils.pause(500);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -17,22 +17,23 @@
|
||||
|
||||
package org.keycloak.testsuite.page;
|
||||
|
||||
import jakarta.ws.rs.core.UriBuilder;
|
||||
import org.jboss.arquillian.drone.api.annotation.Drone;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.junit.Assert;
|
||||
import org.keycloak.testsuite.util.DroneUtils;
|
||||
import org.keycloak.testsuite.util.URLUtils;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
|
||||
import jakarta.ws.rs.core.UriBuilder;
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.junit.Assert;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author tkyjovsk
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class AbstractPage {
|
||||
|
||||
protected final Logger log = Logger.getLogger(this.getClass());
|
||||
|
||||
@ -17,10 +17,8 @@
|
||||
|
||||
package org.keycloak.testsuite.page;
|
||||
|
||||
import org.keycloak.testsuite.util.ServerURLs;
|
||||
|
||||
import jakarta.ws.rs.core.UriBuilder;
|
||||
import java.net.MalformedURLException;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
|
||||
@ -28,6 +26,7 @@ import java.net.URL;
|
||||
*
|
||||
* @author tkyjovsk
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class AbstractPageWithInjectedUrl extends AbstractPage {
|
||||
|
||||
public abstract URL getInjectedUrl();
|
||||
|
||||
@ -42,6 +42,7 @@ import static org.keycloak.testsuite.util.WaitUtils.PAGELOAD_TIMEOUT_MILLIS;
|
||||
*
|
||||
* @author tkyjovsk
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class AbstractPatternFlyAlert {
|
||||
public static final String ALERT_CLASS_NAME = "pf-v5-c-alert";
|
||||
|
||||
|
||||
@ -31,6 +31,7 @@ import static org.keycloak.testsuite.util.UIUtils.clickLink;
|
||||
*
|
||||
* @author tkyjovsk
|
||||
*/
|
||||
@Deprecated
|
||||
public class Form {
|
||||
|
||||
protected final Logger log = Logger.getLogger(this.getClass());
|
||||
|
||||
@ -1,72 +0,0 @@
|
||||
/*
|
||||
* 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.page;
|
||||
|
||||
import org.jboss.arquillian.drone.api.annotation.Drone;
|
||||
import org.junit.Assert;
|
||||
import org.keycloak.testsuite.pages.PageUtils;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
|
||||
import static org.keycloak.testsuite.util.UIUtils.getTextFromElement;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class LoginPasswordUpdatePage {
|
||||
|
||||
@Drone
|
||||
protected WebDriver driver;
|
||||
|
||||
@FindBy(id = "password-new")
|
||||
private WebElement newPasswordInput;
|
||||
|
||||
@FindBy(id = "password-confirm")
|
||||
private WebElement passwordConfirmInput;
|
||||
|
||||
@FindBy(css = "button[type=\"submit\"]")
|
||||
private WebElement submitButton;
|
||||
|
||||
@FindBy(css = "div[class^='pf-v5-c-alert'], div[class^='alert-error']")
|
||||
private WebElement loginErrorMessage;
|
||||
|
||||
public void changePassword(String newPassword, String passwordConfirm) {
|
||||
newPasswordInput.sendKeys(newPassword);
|
||||
passwordConfirmInput.sendKeys(passwordConfirm);
|
||||
|
||||
submitButton.click();
|
||||
}
|
||||
|
||||
public boolean isCurrent() {
|
||||
return driver.getTitle().equals("Update password");
|
||||
}
|
||||
|
||||
public void assertCurrent() {
|
||||
Assert.assertEquals("Update password", PageUtils.getPageTitle(driver));
|
||||
}
|
||||
|
||||
public void open() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
return loginErrorMessage != null ? getTextFromElement(loginErrorMessage) : null;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
package org.keycloak.testsuite.page;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author tkyjovsk
|
||||
*/
|
||||
public interface PageWithLogOutAction {
|
||||
|
||||
public void logOut();
|
||||
|
||||
}
|
||||
@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 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.page;
|
||||
|
||||
import org.keycloak.testsuite.util.WaitUtils;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Petr Mensik
|
||||
* @author tkyjovsk
|
||||
*/
|
||||
public class PatternFlyClosableAlert extends AbstractPatternFlyAlert {
|
||||
|
||||
@FindBy(xpath = ".//button[@class='close']")
|
||||
protected WebElement closeButton;
|
||||
|
||||
public boolean isInfo() {
|
||||
return checkAlertType("info");
|
||||
}
|
||||
|
||||
public boolean isWarning() {
|
||||
return checkAlertType("warning");
|
||||
}
|
||||
|
||||
public boolean isDanger() {
|
||||
return checkAlertType("danger");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assertSuccess(String expectedText) {
|
||||
super.assertSuccess(expectedText);
|
||||
close();
|
||||
}
|
||||
|
||||
public void assertInfo() {
|
||||
assertInfo(null);
|
||||
}
|
||||
|
||||
public void assertInfo(String expectedText) {
|
||||
assertDisplayed();
|
||||
assertTrue("Alert type should be info", isInfo());
|
||||
if (expectedText != null) assertEquals(expectedText, getText());
|
||||
close();
|
||||
}
|
||||
|
||||
public void assertWarning() {
|
||||
assertWarning(null);
|
||||
}
|
||||
|
||||
public void assertWarning(String expectedText) {
|
||||
assertDisplayed();
|
||||
assertTrue("Alert type should be warning", isWarning());
|
||||
if (expectedText != null) assertEquals(expectedText, getText());
|
||||
close();
|
||||
}
|
||||
|
||||
public void assertDanger() {
|
||||
assertDanger(null);
|
||||
}
|
||||
|
||||
public void assertDanger(String expectedText) {
|
||||
assertDisplayed();
|
||||
assertTrue("Alert type should be danger", isDanger());
|
||||
if (expectedText != null) assertEquals(expectedText, getText());
|
||||
close();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
closeButton.click();
|
||||
WaitUtils.pause(500);
|
||||
// Sometimes, when a test is too fast,
|
||||
// one of the consecutive alerts is not displayed;
|
||||
// to prevent this we need to slow down a bit
|
||||
}
|
||||
|
||||
}
|
||||
@ -19,23 +19,14 @@ package org.keycloak.testsuite.pages;
|
||||
|
||||
import org.jboss.arquillian.test.api.ArquillianResource;
|
||||
import org.junit.Assert;
|
||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||
import org.keycloak.testsuite.arquillian.SuiteContext;
|
||||
import org.keycloak.testsuite.util.DroneUtils;
|
||||
import org.keycloak.testsuite.util.oauth.OAuthClient;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public abstract class AbstractPage {
|
||||
|
||||
@ArquillianResource
|
||||
protected SuiteContext suiteContext;
|
||||
|
||||
@ArquillianResource
|
||||
protected WebDriver driver;
|
||||
|
||||
@ -44,30 +35,16 @@ public abstract class AbstractPage {
|
||||
|
||||
public void assertCurrent() {
|
||||
String name = getClass().getSimpleName();
|
||||
Assert.assertTrue("Expected " + name + " but was " + DroneUtils.getCurrentDriver().getTitle() + " (" + DroneUtils.getCurrentDriver().getCurrentUrl() + ")",
|
||||
Assert.assertTrue("Expected " + name + " but was " + driver.getTitle() + " (" + driver.getCurrentUrl() + ")",
|
||||
isCurrent());
|
||||
}
|
||||
|
||||
protected URI getAuthServerRoot() {
|
||||
try {
|
||||
return KeycloakUriBuilder.fromUri(suiteContext.getAuthServerInfo().getBrowserContextRoot().toURI()).path("/auth/").build();
|
||||
} catch (URISyntaxException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
abstract public boolean isCurrent();
|
||||
|
||||
public boolean isCurrent(String expectedTitle) {
|
||||
return PageUtils.getPageTitle(driver).equals(expectedTitle);
|
||||
}
|
||||
|
||||
abstract public void open() throws Exception;
|
||||
|
||||
public WebDriver getDriver() {
|
||||
return driver;
|
||||
}
|
||||
|
||||
public void setDriver(WebDriver driver) {
|
||||
this.driver = driver ;
|
||||
oauth.setDriver(driver);
|
||||
|
||||
@ -33,7 +33,6 @@ public class AppPage extends AbstractPage {
|
||||
@FindBy(id = "account")
|
||||
private WebElement accountLink;
|
||||
|
||||
@Override
|
||||
public void open() {
|
||||
DroneUtils.getCurrentDriver().navigate().to(OAuthClient.APP_AUTH_ROOT);
|
||||
}
|
||||
|
||||
@ -48,9 +48,4 @@ public class ConsentPage extends AbstractPage {
|
||||
public boolean isCurrent(WebDriver driver1) {
|
||||
return PageUtils.getPageTitle(driver1).contains("Grant Access to ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() throws Exception {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,9 +53,4 @@ public class DeleteCredentialPage extends AbstractPage {
|
||||
public void assertCredentialInMessage(String expectedLabel) {
|
||||
Assert.assertEquals("Do you want to delete " + expectedLabel + "?", message.getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,11 +53,6 @@ public class EmailUpdatePage extends AbstractPage {
|
||||
return PageUtils.getPageTitle(driver).equals("Update email");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() throws Exception {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public String getEmailError() {
|
||||
try {
|
||||
return getTextFromElement(emailError);
|
||||
|
||||
@ -50,11 +50,6 @@ public class EnterRecoveryAuthnCodePage extends LanguageComboboxAwarePage {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() throws Exception {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public String getFeedbackText() {
|
||||
return feedbackText.getText().trim();
|
||||
}
|
||||
|
||||
@ -56,9 +56,4 @@ public class ErrorPage extends LanguageComboboxAwarePage {
|
||||
return PageUtils.getPageTitle(driver) != null && PageUtils.getPageTitle(driver).equals("We are sorry...");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -51,8 +51,4 @@ public class IdpConfirmLinkPage extends LanguageComboboxAwarePage {
|
||||
linkAccountButton.click();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() throws Exception {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,8 +41,4 @@ public class IdpConfirmOverrideLinkPage extends LanguageComboboxAwarePage {
|
||||
confirmOverrideButton.click();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() throws Exception {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,11 +39,6 @@ public class IdpLinkEmailPage extends AbstractPage {
|
||||
return PageUtils.getPageTitle(driver).startsWith("Link ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() throws Exception {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message.getText();
|
||||
}
|
||||
|
||||
@ -56,11 +56,6 @@ public class InfoPage extends LanguageComboboxAwarePage {
|
||||
return DroneUtils.getCurrentDriver().getPageSource().contains("kc-info-message");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void clickBackToApplicationLink() {
|
||||
UIUtils.clickLink(backToApplicationLink);
|
||||
}
|
||||
|
||||
@ -47,12 +47,6 @@ public class InstalledAppRedirectPage extends AbstractPage {
|
||||
@FindBy(css = "div[class^='pf-v5-c-alert'], div[class^='alert-error']")
|
||||
private WebElement errorBox;
|
||||
|
||||
@Override
|
||||
public void open() {
|
||||
throw new UnsupportedOperationException("Use method: open(code, error, errorDescription)");
|
||||
}
|
||||
|
||||
|
||||
public void open(String realmName, String code, String error, String errorDescription) {
|
||||
try {
|
||||
KeycloakUriBuilder kcUriBuilder = KeycloakUriBuilder.fromUri(Urls.realmInstalledAppUrnCallback(new URI(oauth.AUTH_SERVER_ROOT), realmName));
|
||||
|
||||
@ -89,10 +89,6 @@ public class LoginConfigTotpPage extends LogoutSessionsPage {
|
||||
}
|
||||
}
|
||||
|
||||
public void open() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void clickManual() {
|
||||
UIUtils.clickLink(manualLink);
|
||||
}
|
||||
|
||||
@ -47,7 +47,4 @@ public class LoginExpiredPage extends AbstractPage {
|
||||
return PageUtils.getPageTitle(driver).equals("Page has expired");
|
||||
}
|
||||
|
||||
public void open() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
@ -274,7 +274,6 @@ public class LoginPage extends LanguageComboboxAwarePage {
|
||||
return rememberMe.isSelected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() {
|
||||
oauth.openLoginForm();
|
||||
assertCurrent();
|
||||
|
||||
@ -62,10 +62,6 @@ public class LoginPasswordResetPage extends LanguageComboboxAwarePage {
|
||||
return PageUtils.getPageTitle(driver).equals("Forgot Your Password?");
|
||||
}
|
||||
|
||||
public void open() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public String getSuccessMessage() {
|
||||
return emailSuccessMessage != null ? emailSuccessMessage.getText() : null;
|
||||
}
|
||||
|
||||
@ -59,10 +59,6 @@ public class LoginPasswordUpdatePage extends LogoutSessionsPage {
|
||||
return PageUtils.getPageTitle(driver).equals("Update password");
|
||||
}
|
||||
|
||||
public void open() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
return loginErrorMessage != null ? loginErrorMessage.getText() : null;
|
||||
}
|
||||
|
||||
@ -87,12 +87,6 @@ public class LoginTotpPage extends LanguageComboboxAwarePage {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
// If false, we don't expect that credentials combobox is available. If true, we expect that it is available on the page
|
||||
public void assertOtpCredentialSelectorAvailability(boolean expectedAvailability) {
|
||||
try {
|
||||
|
||||
@ -46,11 +46,6 @@ public class LoginUpdateProfileEditUsernameAllowedPage extends LoginUpdateProfil
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public static class Update extends LoginUpdateProfilePage.Update {
|
||||
|
||||
private final LoginUpdateProfileEditUsernameAllowedPage page;
|
||||
|
||||
@ -140,11 +140,6 @@ public class LoginUpdateProfilePage extends AbstractPage {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public boolean isCancelDisplayed() {
|
||||
try {
|
||||
return cancelAIAButton.isDisplayed();
|
||||
|
||||
@ -44,12 +44,6 @@ public class LogoutConfirmPage extends LanguageComboboxAwarePage {
|
||||
return "Logging out".equals(PageUtils.getPageTitle(driver1));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void open() throws Exception {
|
||||
throw new UnsupportedOperationException("Not supported to directly open logout confirmation page");
|
||||
}
|
||||
|
||||
public void confirmLogout() {
|
||||
UIUtils.clickLink(confirmLogoutButton);
|
||||
}
|
||||
|
||||
@ -127,7 +127,4 @@ public class OAuth2DeviceVerificationPage extends LanguageComboboxAwarePage {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() {
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,10 +60,6 @@ public class OAuthGrantPage extends LanguageComboboxAwarePage {
|
||||
return PageUtils.getPageTitle(driver).contains("Grant Access to ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() {
|
||||
}
|
||||
|
||||
public List<String> getDisplayedGrants() {
|
||||
List<String> table = new ArrayList<>();
|
||||
WebElement divKcOauth = driver.findElement(By.id("kc-oauth"));
|
||||
|
||||
@ -91,9 +91,4 @@ public class PasswordPage extends LanguageComboboxAwarePage {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void open() throws Exception {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,11 +39,6 @@ public class ProceedPage extends AbstractPage {
|
||||
return driver.getPageSource().contains("kc-info-message") && proceedLink.isDisplayed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void clickProceedLink() {
|
||||
proceedLink.click();
|
||||
}
|
||||
|
||||
@ -33,11 +33,6 @@ public class PushTheButtonPage extends AbstractPage {
|
||||
@FindBy(name = "submit1")
|
||||
private WebElement submitButton;
|
||||
|
||||
@Override
|
||||
public void open() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCurrent() {
|
||||
return DroneUtils.getCurrentDriver().getTitle().equals("PushTheButton")
|
||||
|
||||
@ -276,12 +276,6 @@ public class RegisterPage extends LanguageComboboxAwarePage
|
||||
return passwordErrors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() {
|
||||
oauth.openRegistrationForm();
|
||||
assertCurrent();
|
||||
}
|
||||
|
||||
public void openWithLoginHint(String loginHint) {
|
||||
oauth.addCustomParameter(OIDCLoginProtocol.LOGIN_HINT_PARAM, loginHint).openRegistrationForm();
|
||||
assertCurrent();
|
||||
|
||||
@ -17,11 +17,6 @@ public class ResetOtpPage extends AbstractPage {
|
||||
return description.getText().equals("Which OTP configuration should be removed?");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() throws Exception {
|
||||
// This page is part of the reset credentials flow, so you shouldn't be able to open it by itself.
|
||||
}
|
||||
|
||||
public void selectOtp(int index) {
|
||||
driver.findElement(By.id("kc-otp-credential-" + index)).click();
|
||||
}
|
||||
|
||||
@ -94,8 +94,4 @@ public class SelectAuthenticatorPage extends LanguageComboboxAwarePage {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() throws Exception {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user