Remove legacy Account Console tests
Signed-off-by: Jon Koops <jonkoops@gmail.com>
This commit is contained in:
parent
0826a12ca4
commit
0327787645
57 changed files with 26 additions and 4511 deletions
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
|
@ -47,4 +47,3 @@
|
|||
/js/ @keycloak/ui-maintainers
|
||||
/adapters/oidc/js/ @keycloak/ui-maintainers
|
||||
/rest/admin-ui-ext/ @keycloak/ui-maintainers
|
||||
/testsuite/integration-arquillian/tests/other/base-ui/ @keycloak/ui-maintainers
|
||||
|
|
|
@ -352,17 +352,6 @@ mvn -f testsuite/integration-arquillian/tests/other/springboot-tests/pom.xml \
|
|||
[-Pspringboot27]
|
||||
```
|
||||
|
||||
## Base UI tests
|
||||
Similarly to Admin Console tests, these tests are focused on UI, specifically on the parts of the server that are accessed by an end user (like Login page, or Account Console).
|
||||
They are designed to work with mobile browsers (alongside the standard desktop browsers). For details on the supported browsers and their configuration please refer to [Different Browsers chapter](#different-browsers).
|
||||
#### Execution example
|
||||
```
|
||||
mvn -f testsuite/integration-arquillian/tests/other/base-ui/pom.xml \
|
||||
clean test \
|
||||
-Pandroid \
|
||||
-Dappium.avd=Nexus_5X_API_27
|
||||
```
|
||||
|
||||
## Disabling features
|
||||
Some features in Keycloak can be disabled. To run the testsuite with a specific feature disabled use the `auth.server.feature` system property. For example to run the tests with authorization disabled run:
|
||||
```
|
||||
|
@ -454,23 +443,17 @@ You can use many different real-world browsers to run the integration tests.
|
|||
Although technically they can be run with almost every test in the testsuite, they can fail with some of them as the tests often require specific optimizations for given browser. Therefore, only some of the test modules have support to be run with specific browsers.
|
||||
|
||||
#### Mozilla Firefox
|
||||
* **Supported test modules:** `console`, `base-ui`
|
||||
* **Supported test modules:** `console`
|
||||
* **Supported version:** latest stable
|
||||
* **Driver download required:** [GeckoDriver](https://github.com/mozilla/geckodriver/releases)
|
||||
* **Run with:** `-Dbrowser=firefox -Dwebdriver.gecko.driver=path/to/geckodriver`; optionally you can specify `-Dfirefox_binary=path/to/firefox/binary`
|
||||
|
||||
#### Google Chrome
|
||||
* **Supported test modules:** `console`, `base-ui`
|
||||
* **Supported test modules:** `console`
|
||||
* **Supported version:** latest stable
|
||||
* **Driver download required:** [ChromeDriver](https://sites.google.com/a/chromium.org/chromedriver/) that corresponds with your version of the browser
|
||||
* **Run with:** `-Dbrowser=chrome -Dwebdriver.chrome.driver=path/to/chromedriver`
|
||||
|
||||
#### Apple Safari
|
||||
* **Supported test modules:** `base-ui`
|
||||
* **Supported version:** latest stable
|
||||
* **Driver download required:** no (the driver is bundled with macOS)
|
||||
* **Run with:** `-Dbrowser=safari`
|
||||
|
||||
#### [DEPRECATED] Mozilla Firefox with legacy driver
|
||||
* **Supported test modules:** `console`
|
||||
* **Supported version:** [52 ESR](http://ftp.mozilla.org/pub/firefox/releases/52.9.0esr/) ([Extended Support Release](https://www.mozilla.org/en-US/firefox/organizations/))
|
||||
|
@ -490,25 +473,11 @@ The tests will try to start the Appium server automatically but you can do it ma
|
|||
|
||||
To use a mobile browser you need to create a virtual device. The most convenient way to do so is to install the desired platform's IDE - either [Android Studio](https://developer.android.com/studio/) (for Android devices) or [Xcode](https://developer.apple.com/xcode/) (for iOS devices) - then you can create a device (smartphone/tablet) there. For details please refer to documentation of those IDEs.
|
||||
|
||||
#### Google Chrome on Android
|
||||
* **Supported test modules:** `base-ui`
|
||||
* **Supported host OS:** Windows, Linux, macOS
|
||||
* **Supported browser version:** latest stable
|
||||
* **Supported mobile OS version:** Android 7.x, 8.x
|
||||
* **Run with:** `mvn clean test -Pandroid -Dappium.avd=name_of_the_AVD` where AVD is the name of your Android Virtual Device (e.g. `Nexus_5X_API_27`)
|
||||
|
||||
**Tips & tricks:**
|
||||
* If the AVD name contains any spaces, you need to replace them with underscores when specifying the `-Dappium.avd=...`.
|
||||
* It's probable that a freshly created device will contain an outdated Chrome version. To update to the latest version (without using the Play Store) you need to download an `.apk` for Chrome and install it with `adb install -r path/to/chrome.apk`.
|
||||
* Chrome on Android uses ChromeDriver similarly to regular desktop Chrome. The ChromeDriver is bundled with the Appium server. To use a newer ChromeDriver please follow the [Appium documentation](http://appium.io/docs/en/writing-running-appium/web/chromedriver/).
|
||||
|
||||
#### Apple Safari on iOS
|
||||
* **Supported test modules:** `base-ui`
|
||||
* **Supported host OS:** macOS
|
||||
* **Supported browser version:** _depends on the mobile OS version_
|
||||
* **Supported mobile OS version:** iOS 11.x
|
||||
* **Run with:** `mvn clean test -Pios -Dappium.deviceName=device_name` where the device name is your device identification (e.g. `iPhone X`)
|
||||
|
||||
## Disabling TLS (SSL) in the tests
|
||||
|
||||
All tests are executed with TLS by default. In order to disable it, you need to switch the `auth.server.ssl.required` property off.
|
||||
|
|
|
@ -110,15 +110,6 @@ UI testing is sometimes very tricky due to different demands and behaviours of d
|
|||
The base testsuite contains custom Arquillian extensions and most functional tests.
|
||||
The other test modules depend on this module.
|
||||
|
||||
### Base UI Testsuite
|
||||
Contains most of the UI-focused tests that don't cover Admin Console, i.e. all the parts of the server that are intended to be accessed by an end user.
|
||||
The tests placed here are exclusively covering the UI functionality of the server, i.e. checking if all the page elements are visible, links clickable etc., and are focused on simplicity and stability.
|
||||
This differs them from other integration tests and Admin Console UI tests.
|
||||
|
||||
They are designed to work with most of the desktop browsers (HtmlUnit included) as well as mobile browsers (Chrome on Android and Safari on iOS). Please see [HOW-TO-RUN.md](HOW-TO-RUN.md) for details on supported browsers.
|
||||
|
||||
The tests are place in a separate module (`tests/other/base-ui`) and are disabled by default.
|
||||
|
||||
#### Types of adapter tests
|
||||
|
||||
1. Using *custom test servlets*
|
||||
|
|
|
@ -1,184 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<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/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>integration-arquillian-tests-other</artifactId>
|
||||
<groupId>org.keycloak.testsuite</groupId>
|
||||
<version>999.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>integration-arquillian-tests-base-ui</artifactId>
|
||||
<name>Base UI TestSuite</name>
|
||||
|
||||
<properties>
|
||||
<droneInstantiationTimeoutInSeconds>600</droneInstantiationTimeoutInSeconds>
|
||||
<keycloak.theme.dir>${auth.server.home}/themes</keycloak.theme.dir>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>properties-maven-plugin</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>process-resources</phase>
|
||||
<goals>
|
||||
<goal>read-project-properties</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<files>
|
||||
<file>${testsuite.constants}</file>
|
||||
</files>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-theme-files</id>
|
||||
<phase>process-resources</phase>
|
||||
<goals>
|
||||
<goal>copy-resources</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${keycloak.theme.dir}</outputDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources/themes</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<systemProperties>
|
||||
<keycloak.theme.dir>${keycloak.theme.dir}</keycloak.theme.dir>
|
||||
</systemProperties>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jboss.arquillian.extension</groupId>
|
||||
<artifactId>arquillian-drone-appium-extension</artifactId>
|
||||
<version>${arquillian-drone.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<profiles>
|
||||
|
||||
<profile>
|
||||
<id>android</id>
|
||||
<properties>
|
||||
<browser>appium</browser>
|
||||
<appium.platformName>android</appium.platformName>
|
||||
<appium.browserName>chrome</appium.browserName>
|
||||
<appium.deviceName>doesn't matter</appium.deviceName> <!-- ignored but required by AndroidDriver -->
|
||||
<appium.automationName>Appium</appium.automationName>
|
||||
<auth.server.browserHost>10.0.2.2</auth.server.browserHost>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>enforce</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<rules>
|
||||
<requireProperty>
|
||||
<property>appium.avd</property>
|
||||
<regex>\S+.*</regex>
|
||||
</requireProperty>
|
||||
</rules>
|
||||
<fail>true</fail>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>ios</id>
|
||||
<properties>
|
||||
<browser>appium</browser>
|
||||
<appium.platformName>ios</appium.platformName>
|
||||
<appium.browserName>safari</appium.browserName>
|
||||
<appium.automationName>XCUITest</appium.automationName>
|
||||
<appium.noReset>true</appium.noReset>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>enforce</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<rules>
|
||||
<requireProperty>
|
||||
<property>appium.deviceName</property>
|
||||
<regex>\S+.*</regex>
|
||||
</requireProperty>
|
||||
</rules>
|
||||
<fail>true</fail>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
</profiles>
|
||||
|
||||
</project>
|
|
@ -1,107 +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.ui.account3.page;
|
||||
|
||||
import org.keycloak.testsuite.util.UIUtils;
|
||||
import org.openqa.selenium.By;
|
||||
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.WaitUtils.waitUntilElement;
|
||||
|
||||
/**
|
||||
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||
*/
|
||||
public class ApplicationsPage extends AbstractLoggedInPage {
|
||||
@FindBy(xpath = "//li[starts-with(@id,'application-client-id')]")
|
||||
private List<WebElement> applications;
|
||||
|
||||
@Override
|
||||
public String getPageId() {
|
||||
return "applications";
|
||||
}
|
||||
|
||||
public void toggleApplicationDetails(String clientId) {
|
||||
By selector = By.xpath("//button[@id='application-toggle-" + clientId + "']");
|
||||
waitUntilElement(selector).is().clickable();
|
||||
driver.findElement(selector).click();
|
||||
}
|
||||
|
||||
public List<ClientRepresentation> getApplications() {
|
||||
ArrayList<ClientRepresentation> apps = new ArrayList<>();
|
||||
for(WebElement app : applications) {
|
||||
String clientId = app.getAttribute("id").replace("application-client-id-", "");
|
||||
apps.add(toRepresentation(app, clientId));
|
||||
}
|
||||
return apps;
|
||||
}
|
||||
|
||||
private ClientRepresentation toRepresentation(WebElement app, String clientId) {
|
||||
String clientName = UIUtils.getTextFromElement(app.findElement(By.xpath("//div[@id='application-name-" + clientId + "']")));
|
||||
boolean userConsentRequired = !UIUtils.getTextFromElement(app.findElement(By.xpath("//div[@id='application-internal-" + clientId + "']"))).equals("Internal");
|
||||
boolean inUse = UIUtils.getTextFromElement(app.findElement(By.xpath("//div[@id='application-status-" + clientId + "']"))).equals("In use");
|
||||
boolean applicationDetailsVisible = app.findElement(By.xpath("//section[@id='application-expandable-" + clientId + "']")).isDisplayed();
|
||||
String effectiveURL = UIUtils.getTextFromElement(app.findElement(By.id("application-effectiveurl-" + clientId)));
|
||||
return new ClientRepresentation(clientId, clientName, userConsentRequired, inUse, effectiveURL, applicationDetailsVisible);
|
||||
}
|
||||
|
||||
public class ClientRepresentation {
|
||||
private final String clientId;
|
||||
private final String clientName;
|
||||
private final boolean userConsentRequired;
|
||||
private final boolean inUse;
|
||||
private final String effectiveUrl;
|
||||
private final boolean applicationDetailsVisible;
|
||||
|
||||
public ClientRepresentation(String clientId, String clientName, boolean userConsentRequired, boolean inUse, String effectiveUrl, boolean applicationDetailsVisible) {
|
||||
this.clientId = clientId;
|
||||
this.clientName = clientName;
|
||||
this.userConsentRequired = userConsentRequired;
|
||||
this.inUse = inUse;
|
||||
this.effectiveUrl = effectiveUrl;
|
||||
this.applicationDetailsVisible = applicationDetailsVisible;
|
||||
}
|
||||
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
public String getClientName() {
|
||||
return clientName;
|
||||
}
|
||||
|
||||
public boolean isUserConsentRequired() {
|
||||
return userConsentRequired;
|
||||
}
|
||||
|
||||
public boolean isInUse() {
|
||||
return inUse;
|
||||
}
|
||||
|
||||
public String getEffectiveUrl() {
|
||||
return effectiveUrl;
|
||||
}
|
||||
|
||||
public boolean isApplicationDetailsVisible() {
|
||||
return applicationDetailsVisible;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,215 +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.ui.account3.page;
|
||||
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.NoSuchElementException;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static org.keycloak.testsuite.util.UIUtils.clickLink;
|
||||
import static org.keycloak.testsuite.util.UIUtils.getTextFromElement;
|
||||
import static org.keycloak.testsuite.util.UIUtils.isElementVisible;
|
||||
|
||||
/**
|
||||
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||
*/
|
||||
public class DeviceActivityPage extends AbstractLoggedInPage {
|
||||
@FindBy(id = "sign-out-all")
|
||||
private WebElement signOutAllBtn;
|
||||
|
||||
@FindBy(className = "signed-in-device-grid")
|
||||
private List<WebElement> sessions;
|
||||
|
||||
@Override
|
||||
public String getPageId() {
|
||||
return "device-activity";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParentPageId() {
|
||||
return ACCOUNT_SECURITY_ID;
|
||||
}
|
||||
|
||||
public boolean isSignOutAllDisplayed() {
|
||||
return isElementVisible(signOutAllBtn);
|
||||
}
|
||||
|
||||
public void clickSignOutAll() {
|
||||
clickLink(signOutAllBtn);
|
||||
}
|
||||
|
||||
public int getSessionsCount() {
|
||||
return sessions.size();
|
||||
}
|
||||
|
||||
public Optional<Session> getSessionByIndex(int index) {
|
||||
try {
|
||||
return Optional.of(new Session(sessions.get(index)));
|
||||
} catch (Exception e) {
|
||||
log.warn(e.getMessage());
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public Optional<Session> getSession(String sessionId) {
|
||||
try {
|
||||
return Optional.of(new Session(getSessionElement(sessionId)));
|
||||
} catch (Exception e) {
|
||||
log.warn(e.getMessage());
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private WebElement getSessionElement(String sessionId) {
|
||||
return sessions.stream()
|
||||
.filter(f -> getTrimmedSessionId(sessionId).equals(getSessionId(f)))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private static String getSessionId(WebElement sessionElement) {
|
||||
if (sessionElement == null) return null;
|
||||
return sessionElement.getAttribute("id").split("-")[1]; // the id looks like session-71891504-item
|
||||
}
|
||||
|
||||
public static String getTrimmedSessionId(String fullSessionId) {
|
||||
return fullSessionId.substring(0, 7);
|
||||
}
|
||||
|
||||
// We cannot use standard Page Fragment as there's no root element. Even though the sessions are placed in rows,
|
||||
// there's no element that would encapsulate it. Hence we cannot simply use e.g. @FindBy annotations.
|
||||
public class Session {
|
||||
private static final String SESSION = "session";
|
||||
private static final String DEVICE_ICON = "device-icon";
|
||||
private static final String IP = "ip";
|
||||
private static final String SIGN_OUT = "sign-out";
|
||||
|
||||
private final WebElement element;
|
||||
private final String sessionId;
|
||||
|
||||
// we don't want Session to be instantiated outside DeviceActivityPage
|
||||
private Session(WebElement element) {
|
||||
this.element = element;
|
||||
this.sessionId = DeviceActivityPage.getSessionId(element);
|
||||
}
|
||||
|
||||
public String getSessionId() {
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
public boolean isPresent() {
|
||||
return isItemDisplayed(IP); // no root element hence this workaround
|
||||
}
|
||||
|
||||
public String getIcon() {
|
||||
final WebElement icon = (WebElement) Optional.ofNullable(element.findElement(By.className(DEVICE_ICON)))
|
||||
.map(f -> (WebElement) f)
|
||||
.map(f -> f.findElement(By.tagName("svg")))
|
||||
.orElse(null);
|
||||
|
||||
if (icon == null) return "";
|
||||
return icon.getAttribute("id").split("-")[3]; // the id looks like session-71891504-icon-desktop
|
||||
}
|
||||
|
||||
public String getIp() {
|
||||
return getTextFromItem(IP);
|
||||
}
|
||||
|
||||
public boolean hasCurrentBadge() {
|
||||
return isItemDisplayed("current-badge");
|
||||
}
|
||||
|
||||
public boolean isBrowserDisplayed() {
|
||||
return !"".equals(getBrowser());
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return getTextFromElement(element.findElement(By.className("session-title")));
|
||||
}
|
||||
|
||||
public String getBrowser() {
|
||||
try {
|
||||
return getTitle().split("/", 2)[1].trim();
|
||||
} catch (Exception e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public String getLastAccess() {
|
||||
return getTextFromItem("last-access");
|
||||
}
|
||||
|
||||
public String getClients() {
|
||||
return getTextFromItem("clients");
|
||||
}
|
||||
|
||||
public String getStarted() {
|
||||
return getTextFromItem("started");
|
||||
}
|
||||
|
||||
public String getExpires() {
|
||||
return getTextFromItem("expires");
|
||||
}
|
||||
|
||||
public boolean isSignOutDisplayed() {
|
||||
return getSignOutButton() != null;
|
||||
}
|
||||
|
||||
public void clickSignOut() {
|
||||
WebElement signOutButton = getSignOutButton();
|
||||
if (signOutButton != null) {
|
||||
clickLink(signOutButton);
|
||||
} else {
|
||||
log.warn("Cannot click sign out button; not present");
|
||||
}
|
||||
}
|
||||
|
||||
private WebElement getSignOutButton() {
|
||||
try {
|
||||
return driver.findElement(By.xpath(String.format("//button[@id='%s']", getFullItemId(SIGN_OUT))));
|
||||
} catch (NoSuchElementException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String getFullItemId(String itemId) {
|
||||
return String.format("%s-%s-%s", SESSION, sessionId, itemId);
|
||||
}
|
||||
|
||||
private WebElement getItemElement(String itemId) {
|
||||
return element.findElement(By.id(getFullItemId(itemId)));
|
||||
}
|
||||
|
||||
private String getTextFromItem(String itemId) {
|
||||
return getTextFromElement(getItemElement(itemId).findElement(By.tagName("div")));
|
||||
}
|
||||
|
||||
private boolean isItemDisplayed(String itemId) {
|
||||
try {
|
||||
return getItemElement(itemId).isDisplayed();
|
||||
} catch (NoSuchElementException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,39 +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.ui.account3.page;
|
||||
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
|
||||
/**
|
||||
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||
*/
|
||||
public class ForbiddenPage extends AbstractLoggedInPage {
|
||||
@FindBy(tagName = "main")
|
||||
private WebElement mainTag;
|
||||
|
||||
@Override
|
||||
public String getPageId() {
|
||||
return "forbidden";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCurrent() {
|
||||
return mainTag.getText().contains("You do not have access rights to this request.");
|
||||
}
|
||||
}
|
|
@ -1,142 +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.ui.account3.page;
|
||||
|
||||
import org.jboss.arquillian.graphene.Graphene;
|
||||
import org.jboss.arquillian.graphene.fragment.Root;
|
||||
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.UIUtils.isElementVisible;
|
||||
import static org.openqa.selenium.By.id;
|
||||
import static org.openqa.selenium.By.xpath;
|
||||
|
||||
/**
|
||||
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||
*/
|
||||
public class LinkedAccountsPage extends AbstractLoggedInPage {
|
||||
public static final String LINKED_ACCOUNTS_ID = "linked-accounts";
|
||||
public static final String LINKED_IDPS_LIST_ID = "linked-idps";
|
||||
public static final String UNLINKED_IDPS_LIST_ID = "unlinked-idps";
|
||||
|
||||
@FindBy(id = LINKED_IDPS_LIST_ID)
|
||||
private List<WebElement> linkedIdPsList;
|
||||
|
||||
@FindBy(id = UNLINKED_IDPS_LIST_ID)
|
||||
private List<WebElement> unlinkedIdPsList;
|
||||
|
||||
@Override
|
||||
public String getPageId() {
|
||||
return LINKED_ACCOUNTS_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParentPageId() {
|
||||
return ACCOUNT_SECURITY_ID;
|
||||
}
|
||||
|
||||
public IdentityProvider getProvider(String providerAlias) {
|
||||
WebElement root = driver.findElement(id(providerAlias + "-idp"));
|
||||
return Graphene.createPageFragment(IdentityProvider.class, root);
|
||||
}
|
||||
|
||||
public int getLinkedProvidersCount() {
|
||||
return linkedIdPsList.size();
|
||||
}
|
||||
|
||||
public int getUnlinkedProvidersCount() {
|
||||
return unlinkedIdPsList.size();
|
||||
}
|
||||
|
||||
public class IdentityProvider {
|
||||
@Root
|
||||
private WebElement root;
|
||||
|
||||
@FindBy(xpath = ".//*[contains(@id,'idp-name')]")
|
||||
private WebElement nameElement;
|
||||
|
||||
@FindBy(xpath = ".//*[contains(@id,'idp-icon')]")
|
||||
private WebElement iconElement;
|
||||
|
||||
@FindBy(xpath = ".//*[contains(@id,'idp-label')]")
|
||||
private WebElement badgeElement;
|
||||
|
||||
@FindBy(xpath = ".//*[contains(@id,'idp-username')]")
|
||||
private WebElement usernameElement;
|
||||
|
||||
@FindBy(xpath = ".//*[contains(@id,'idp-link')]")
|
||||
private WebElement linkBtn;
|
||||
|
||||
@FindBy(xpath = ".//*[contains(@id,'idp-unlink')]")
|
||||
private WebElement unlinkBtn;
|
||||
|
||||
public boolean isLinked() {
|
||||
String parentListId = root.findElement(xpath("ancestor::ul")).getAttribute("id");
|
||||
|
||||
if (parentListId.equals(LINKED_IDPS_LIST_ID)) {
|
||||
return true;
|
||||
}
|
||||
else if (parentListId.equals(UNLINKED_IDPS_LIST_ID)) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("Unexpected parent list ID: " + parentListId);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasSocialLoginBadge() {
|
||||
return getTextFromElement(badgeElement).equals("Social login");
|
||||
}
|
||||
|
||||
public boolean hasSystemDefinedBadge() {
|
||||
return getTextFromElement(badgeElement).equals("System defined");
|
||||
}
|
||||
|
||||
public boolean hasSocialIcon() {
|
||||
return iconElement.getAttribute("id").contains("social");
|
||||
}
|
||||
|
||||
public boolean hasDefaultIcon() {
|
||||
return iconElement.getAttribute("id").contains("default");
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return getTextFromElement(usernameElement);
|
||||
}
|
||||
|
||||
public boolean isLinkBtnVisible() {
|
||||
return isElementVisible(linkBtn);
|
||||
}
|
||||
|
||||
public boolean isUnlinkBtnVisible() {
|
||||
return isElementVisible(unlinkBtn);
|
||||
}
|
||||
|
||||
public void clickLinkBtn() {
|
||||
clickLink(linkBtn);
|
||||
}
|
||||
|
||||
public void clickUnlinkBtn() {
|
||||
clickLink(unlinkBtn);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,182 +0,0 @@
|
|||
package org.keycloak.testsuite.ui.account3.page;
|
||||
|
||||
import org.keycloak.testsuite.util.UIUtils;
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.jboss.arquillian.graphene.Graphene.waitGui;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.keycloak.testsuite.util.UIUtils.clickLink;
|
||||
|
||||
public class MyResourcesPage extends AbstractLoggedInPage {
|
||||
|
||||
@FindBy(xpath = "//ul[@id='resourcesList']/li")
|
||||
private List<WebElement> resourcesList;
|
||||
|
||||
@FindBy(id = "refresh-page")
|
||||
private WebElement refreshButton;
|
||||
|
||||
@Override
|
||||
public String getPageId() {
|
||||
return "resources";
|
||||
}
|
||||
|
||||
public int getResourcesListCount() {
|
||||
return resourcesList.size();
|
||||
}
|
||||
|
||||
public void clickRefreshButton() {
|
||||
clickLink(refreshButton);
|
||||
}
|
||||
|
||||
public void clickExpandButton(int row) {
|
||||
driver.findElement(By.id("resourceToggle-" + row)).click();
|
||||
waitGui().until().element(By.id("ex-expand" + row)).is().visible();
|
||||
}
|
||||
|
||||
public void clickCollapseButton(int row) {
|
||||
driver.findElement(By.id("resourceToggle-" + row)).click();
|
||||
waitGui().until().element(By.id("ex-expand" + row)).is().not().visible();
|
||||
}
|
||||
|
||||
public String getCellText(String cell, int row) {
|
||||
return getCell(cell, row).getText();
|
||||
}
|
||||
|
||||
public String getCellHref(String cell, int row) {
|
||||
return getCell(cell, row).findElement(By.tagName("a")).getAttribute("href");
|
||||
}
|
||||
|
||||
private WebElement getCell(String cell, int row) {
|
||||
final String name = Character.toUpperCase(cell.charAt(0)) + cell.substring(1);
|
||||
return driver.findElement(By.id(String.format("resource%s-%d", name, row)));
|
||||
}
|
||||
|
||||
public String getSharedWith(int row) {
|
||||
final WebElement element = driver.findElement(By.id("shared-with-user-message-" + row));
|
||||
return element.getText();
|
||||
}
|
||||
|
||||
public void clickShareButton(int row) {
|
||||
driver.findElement(By.id("share-" + row)).click();
|
||||
waitForModalFadeIn();
|
||||
}
|
||||
|
||||
public void clickEditButton(int row) {
|
||||
final WebElement webElement = driver.findElement(By.id("action-menu-" + row));
|
||||
webElement.click();
|
||||
webElement.findElement(By.id("edit-" + row)).click();
|
||||
waitForModalFadeIn();
|
||||
}
|
||||
|
||||
public String getEditDialogUsername(int row) {
|
||||
return driver.findElement(By.id("username-" + row)).getAttribute("value");
|
||||
}
|
||||
|
||||
public void clickRemoveButton(int row) {
|
||||
final WebElement webElement = driver.findElement(By.id("action-menu-" + row));
|
||||
webElement.click();
|
||||
webElement.findElement(By.id("remove-" + row)).click();
|
||||
}
|
||||
|
||||
public String getPendingRequestRequestor(int row) {
|
||||
return driver.findElement(By.id("requestor" + row)).getText();
|
||||
}
|
||||
|
||||
public String getPendingRequestPermissions(int row) {
|
||||
return driver.findElement(By.id("permissions" + row)).getText();
|
||||
}
|
||||
|
||||
private WebElement getPendingRequest(String resourceName) {
|
||||
return driver.findElement(By.id("shareRequest-" + resourceNameToId(resourceName)));
|
||||
}
|
||||
|
||||
public String getPendingRequestText(String resourceName) {
|
||||
return getPendingRequest(resourceName).getText();
|
||||
}
|
||||
|
||||
public void clickPendingRequest(String resourceName) {
|
||||
getPendingRequest(resourceName).click();
|
||||
}
|
||||
|
||||
public void acceptRequest(String resourceName, int row) {
|
||||
clickApproveDenyButton(resourceName, row, true);
|
||||
}
|
||||
|
||||
public void denyRequest(String resourceName, int row) {
|
||||
clickApproveDenyButton(resourceName, row, false);
|
||||
}
|
||||
|
||||
private void clickApproveDenyButton(String resourceName, int row, boolean approve) {
|
||||
final By id = By.id(String.format("%s-%d-shareRequest-%s", approve ? "accept" : "deny", row, resourceNameToId(resourceName)));
|
||||
driver.findElement(id).click();
|
||||
waitForModalFadeOut();
|
||||
}
|
||||
|
||||
private String resourceNameToId(String resourceName) {
|
||||
return resourceName.replace(" ", "-");
|
||||
}
|
||||
|
||||
public void clickSignOut() {
|
||||
driver.findElement(By.id("signOutButton")).click();
|
||||
}
|
||||
|
||||
public void clickNextPage() {
|
||||
final WebElement webElement = driver.findElements(By.className("pf-m-primary")).get(1);
|
||||
assertEquals("Next>", webElement.getText());
|
||||
webElement.click();
|
||||
}
|
||||
|
||||
public void clickSharedWithMeTab() {
|
||||
final WebElement sharedWithMe = driver.findElement(By.id("pf-tab-1-sharedwithMe"));
|
||||
sharedWithMe.click();
|
||||
|
||||
final WebElement tab = sharedWithMe.findElement(By.xpath("./.."));
|
||||
//test to see that the tab is really clicked
|
||||
assertEquals("pf-v5-c-tabs__item pf-m-current", tab.getAttribute("class"));
|
||||
}
|
||||
|
||||
public boolean containsResource(String resourceName) {
|
||||
return driver.findElement(By.id("sharedResourcesList")).getText().contains(resourceName);
|
||||
}
|
||||
|
||||
public void createShare(String userName) {
|
||||
driver.findElement(By.id("username")).sendKeys(userName);
|
||||
driver.findElement(By.id("add")).click();
|
||||
driver.findElement(By.className("pf-v5-c-select__toggle-typeahead")).click();
|
||||
driver.findElement(By.xpath("//button[@class='pf-v5-c-select__menu-item' and text()='Scope A']")).click();
|
||||
driver.findElement(By.id("done")).click();
|
||||
waitForModalFadeOut();
|
||||
}
|
||||
|
||||
public void removeAllPermissions() {
|
||||
assertThat(getScopesTexts(), containsInAnyOrder("Scope A", "Scope B"));
|
||||
driver.findElement(By.className("pf-v5-c-select__toggle-clear")).click();
|
||||
driver.findElement(By.id("save-0")).click();
|
||||
driver.findElement(By.id("done")).click();
|
||||
waitForModalFadeOut();
|
||||
}
|
||||
|
||||
private List<String> getScopesTexts() {
|
||||
return driver.findElements(By.xpath("//span[contains(@id,'pf-random-id-')]"))
|
||||
.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(UIUtils::getTextFromElement)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private void waitForModalFadeIn() {
|
||||
waitGui().until().element(By.className("pf-v5-c-modal-box")).is().present();
|
||||
}
|
||||
|
||||
private void waitForModalFadeOut() {
|
||||
waitGui().until().element(By.className("pf-v5-c-backdrop")).is().not().present();
|
||||
}
|
||||
}
|
|
@ -1,33 +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.ui.account3.page;
|
||||
|
||||
/**
|
||||
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||
*/
|
||||
public class PageNotFound extends AbstractLoggedInPage {
|
||||
@Override
|
||||
public String getPageId() {
|
||||
return "some-nonexisting-id";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCurrent() {
|
||||
return driver.getPageSource().contains("Page not found");
|
||||
}
|
||||
}
|
|
@ -1,195 +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.ui.account3.page;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.keycloak.testsuite.util.UIAssert.assertElementDisabled;
|
||||
import static org.keycloak.testsuite.util.UIAssert.assertInputElementValid;
|
||||
import static org.keycloak.testsuite.util.UIUtils.clickLink;
|
||||
import static org.keycloak.testsuite.util.UIUtils.getTextInputValue;
|
||||
import static org.keycloak.testsuite.util.UIUtils.isElementVisible;
|
||||
import static org.keycloak.testsuite.util.UIUtils.setTextInputValue;
|
||||
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
import org.openqa.selenium.support.ui.Select;
|
||||
|
||||
/**
|
||||
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||
*/
|
||||
public class PersonalInfoPage extends AbstractLoggedInPage {
|
||||
@FindBy(id = "user-name")
|
||||
private WebElement username;
|
||||
@FindBy(id = "email-address")
|
||||
private WebElement email;
|
||||
@FindBy(id = "first-name")
|
||||
private WebElement firstName;
|
||||
@FindBy(id = "last-name")
|
||||
private WebElement lastName;
|
||||
@FindBy(id = "locale-select")
|
||||
private Select localeSelector;
|
||||
@FindBy(id = "save-btn")
|
||||
private WebElement saveBtn;
|
||||
@FindBy(id = "cancel-btn")
|
||||
private WebElement cancelBtn;
|
||||
@FindBy(id = "delete-account")
|
||||
private WebElement deleteAccountSection;
|
||||
@FindBy(id = "update-email-btn")
|
||||
private WebElement updateEmailLink;
|
||||
|
||||
@Override
|
||||
public String getPageId() {
|
||||
return "/";
|
||||
}
|
||||
|
||||
public void assertUsernameDisabled(boolean expected) {
|
||||
assertEquals(isUsernameDisabled(), expected);
|
||||
}
|
||||
|
||||
public boolean isUsernameDisabled() {
|
||||
return isElementDisabled(username);
|
||||
}
|
||||
|
||||
public boolean isEmailDisabled() {
|
||||
return isElementDisabled(email);
|
||||
}
|
||||
|
||||
private boolean isElementDisabled(WebElement element) {
|
||||
return element.getAttribute("readonly") != null || element.getAttribute("disabled") != null;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return getTextInputValue(username);
|
||||
}
|
||||
|
||||
public void setUsername(String value) {
|
||||
setTextInputValue(username, value);
|
||||
}
|
||||
|
||||
public void assertUsernameValid(boolean expected) {
|
||||
assertInputElementValid(expected, username);
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return getTextInputValue(email);
|
||||
}
|
||||
|
||||
public void setEmail(String value) {
|
||||
setTextInputValue(email, value);
|
||||
}
|
||||
|
||||
public void assertEmailValid(boolean expected) {
|
||||
assertInputElementValid(expected, email);
|
||||
}
|
||||
|
||||
public void assertUpdateEmailLinkVisible(boolean expected){
|
||||
if (updateEmailLink == null) {
|
||||
assertFalse(expected);
|
||||
return;
|
||||
}
|
||||
assertEquals(expected, isElementVisible(updateEmailLink));
|
||||
}
|
||||
|
||||
public void clickUpdateEmailLink(){
|
||||
clickLink(updateEmailLink);
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return getTextInputValue(firstName);
|
||||
}
|
||||
|
||||
public void setFirstName(String value) {
|
||||
setTextInputValue(firstName, value);
|
||||
}
|
||||
|
||||
public void assertFirstNameValid(boolean expected) {
|
||||
assertInputElementValid(expected, firstName);
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return getTextInputValue(lastName);
|
||||
}
|
||||
|
||||
public void setLastName(String value) {
|
||||
setTextInputValue(lastName, value);
|
||||
}
|
||||
|
||||
public void assertLastNameValid(boolean expected) {
|
||||
assertInputElementValid(expected, lastName);
|
||||
}
|
||||
|
||||
public void assertSaveDisabled(boolean expected) {
|
||||
assertElementDisabled(expected, saveBtn);
|
||||
}
|
||||
|
||||
public void assertDeleteAccountSectionVisible(boolean expected) {
|
||||
if (deleteAccountSection == null) {
|
||||
assertFalse(expected);
|
||||
return;
|
||||
}
|
||||
assertEquals(expected, isElementVisible(deleteAccountSection));
|
||||
}
|
||||
|
||||
public void clickSave() {
|
||||
clickSave(true);
|
||||
}
|
||||
|
||||
public void clickSave(boolean assertAlert) {
|
||||
saveBtn.click();
|
||||
if (assertAlert) {
|
||||
alert().assertIsDisplayed();
|
||||
}
|
||||
}
|
||||
|
||||
public void clickCancel() {
|
||||
cancelBtn.click();
|
||||
}
|
||||
|
||||
public void clickOpenDeleteExapandable() {
|
||||
clickLink(driver.findElement(By.cssSelector(".pf-c-expandable-section__toggle")));
|
||||
}
|
||||
|
||||
public void clickDeleteAccountButton() {
|
||||
clickLink(driver.findElement(By.id("delete-account-btn")));
|
||||
}
|
||||
|
||||
public void setValues(UserRepresentation user, boolean includeUsername) {
|
||||
if (includeUsername) {
|
||||
setUsername(user.getUsername());
|
||||
}
|
||||
if (!isEmailDisabled()) {
|
||||
setEmail(user.getEmail());
|
||||
}
|
||||
setFirstName(user.getFirstName());
|
||||
setLastName(user.getLastName());
|
||||
}
|
||||
|
||||
public boolean valuesEqual(UserRepresentation user) {
|
||||
return user.getUsername().equals(getUsername())
|
||||
&& user.getEmail().equals(getEmail())
|
||||
&& user.getFirstName().equals(getFirstName())
|
||||
&& user.getLastName().equals(getLastName());
|
||||
}
|
||||
|
||||
public void selectLocale(String customLocale) {
|
||||
localeSelector.selectByValue(customLocale);
|
||||
}
|
||||
}
|
|
@ -1,141 +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.ui.account3.page;
|
||||
|
||||
import org.keycloak.testsuite.ui.account3.page.fragment.WelcomeScreenHeader;
|
||||
import org.keycloak.testsuite.util.URLUtils;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
|
||||
import jakarta.ws.rs.core.UriBuilder;
|
||||
|
||||
import static org.keycloak.testsuite.util.UIAssert.assertElementVisible;
|
||||
import static org.keycloak.testsuite.util.UIUtils.clickLink;
|
||||
import static org.keycloak.testsuite.util.UIUtils.getTextFromElement;
|
||||
import static org.keycloak.testsuite.util.UIUtils.isElementVisible;
|
||||
|
||||
/**
|
||||
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||
*/
|
||||
public class WelcomeScreen extends AbstractAccountPage {
|
||||
public static final String ROOT_ELEMENT_ID = "welcomeScreen";
|
||||
|
||||
@FindBy(id = ROOT_ELEMENT_ID)
|
||||
private WebElement welcomeScreenRoot;
|
||||
|
||||
@FindBy(xpath = "//*[@id='" + ROOT_ELEMENT_ID + "']//header")
|
||||
private WelcomeScreenHeader header;
|
||||
|
||||
@FindBy(xpath = "//a[@id='landing-personal-info']")
|
||||
private WebElement personalInfoLink;
|
||||
@FindBy(xpath = "//*[@id='landingChangePasswordLink']/a")
|
||||
private WebElement changePasswordLink;
|
||||
@FindBy(xpath = "//a[@id='landing-authenticator']")
|
||||
private WebElement authenticatorLink;
|
||||
@FindBy(xpath = "//*[@id='landing-device-activity']/a")
|
||||
private WebElement deviceActivityLink;
|
||||
@FindBy(xpath = "//*[@id='landing-linked-accounts']/a")
|
||||
private WebElement linkedAccountsLink;
|
||||
@FindBy(xpath = "//a[@id='landing-applications']")
|
||||
private WebElement applicationsLink;
|
||||
@FindBy(id = "landing-resources")
|
||||
private WebElement myResourcesCard;
|
||||
@FindBy(xpath = "//a[@id='landing-resources']")
|
||||
private WebElement myResourcesLink;
|
||||
@FindBy(id = "landingLogo")
|
||||
private WebElement logoLink;
|
||||
|
||||
@FindBy(id = "landingWelcomeMessage")
|
||||
private WebElement welcomeMessage; // used only for i18n testing
|
||||
|
||||
private String referrer;
|
||||
private String referrerUri;
|
||||
|
||||
@Override
|
||||
public boolean isCurrent() {
|
||||
return URLUtils.currentUrlEquals(toString() + "#/") && isElementVisible(welcomeScreenRoot); // the hash will be eventually added after the page is loaded
|
||||
}
|
||||
|
||||
@Override
|
||||
public UriBuilder getUriBuilder() {
|
||||
UriBuilder uriBuilder = super.getUriBuilder();
|
||||
if (referrer != null) {
|
||||
uriBuilder.queryParam("referrer", referrer);
|
||||
}
|
||||
if (referrerUri != null) {
|
||||
uriBuilder.queryParam("referrer_uri", referrerUri);
|
||||
}
|
||||
return uriBuilder;
|
||||
}
|
||||
|
||||
public WelcomeScreenHeader header() {
|
||||
return header;
|
||||
}
|
||||
|
||||
public void clickLogoImage() {
|
||||
clickLink(logoLink);
|
||||
}
|
||||
|
||||
public void clickPersonalInfoLink() {
|
||||
clickLink(personalInfoLink);
|
||||
}
|
||||
|
||||
public void clickChangePasswordLink() {
|
||||
clickLink(changePasswordLink);
|
||||
}
|
||||
|
||||
public void clickAuthenticatorLink() {
|
||||
clickLink(authenticatorLink);
|
||||
}
|
||||
|
||||
public void clickDeviceActivityLink() {
|
||||
clickLink(deviceActivityLink);
|
||||
}
|
||||
|
||||
public void assertLinkedAccountsLinkVisible(boolean expected) {
|
||||
assertElementVisible(expected, linkedAccountsLink);
|
||||
}
|
||||
|
||||
public void clickLinkedAccountsLink() {
|
||||
clickLink(linkedAccountsLink);
|
||||
}
|
||||
|
||||
public void clickApplicationsLink() {
|
||||
clickLink(applicationsLink);
|
||||
}
|
||||
|
||||
public void assertMyResourcesCardVisible(boolean expected) {
|
||||
assertElementVisible(expected, myResourcesCard);
|
||||
}
|
||||
|
||||
public void clickMyResourcesLink() {
|
||||
clickLink(myResourcesLink);
|
||||
}
|
||||
|
||||
public String getWelcomeMessage() {
|
||||
return getTextFromElement(welcomeMessage);
|
||||
}
|
||||
|
||||
public void navigateTo(String referrer, String referrerUri) {
|
||||
this.referrer = referrer;
|
||||
this.referrerUri = referrerUri;
|
||||
navigateTo();
|
||||
this.referrer = null;
|
||||
this.referrerUri = null;
|
||||
}
|
||||
}
|
|
@ -1,87 +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.ui.account3.page.fragment;
|
||||
|
||||
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 WelcomeScreenHeader extends AbstractHeader {
|
||||
@FindBy(id = "landingSignOutButton")
|
||||
private WebElement logoutBtn;
|
||||
@FindBy(id = "landingSignOutLink")
|
||||
private WebElement logoutBtnMobile;
|
||||
|
||||
@FindBy(id = "landingSignInButton")
|
||||
private WebElement loginBtn;
|
||||
@FindBy(id = "landingSignInLink")
|
||||
private WebElement loginBtnMobile;
|
||||
|
||||
@FindBy(xpath = "//*[@id='landing-locale-dropdown']/button")
|
||||
private WebElement localeBtn;
|
||||
@FindBy(id = "landing-mobile-local-toggle")
|
||||
private WebElement localeBtnMobile;
|
||||
|
||||
@FindBy(id = "landingReferrerLink")
|
||||
private WebElement referrerLink;
|
||||
@FindBy(id = "landingMobileReferrerLink")
|
||||
private WebElement referrerLinkMobile;
|
||||
|
||||
@FindBy(id = "landingMobileDropdown")
|
||||
private WebElement mobileKebab;
|
||||
|
||||
@FindBy(id = "landingLoggedInUser")
|
||||
private WebElement toolbarLoggedInUser;
|
||||
|
||||
@Override
|
||||
public void clickOptions() {
|
||||
clickLink(mobileKebab);
|
||||
}
|
||||
|
||||
public void clickLoginBtn() {
|
||||
clickToolsBtn(isMobileLayout() ? loginBtnMobile : loginBtn);
|
||||
}
|
||||
|
||||
public void assertLoginBtnVisible(boolean expected) {
|
||||
assertToolsBtnVisible(expected, isMobileLayout() ? loginBtnMobile : loginBtn);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WebElement getLogoutBtn() {
|
||||
return isMobileLayout() ? logoutBtnMobile : logoutBtn;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WebElement getReferrerLink() {
|
||||
return isMobileLayout() ? referrerLinkMobile : referrerLink;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLocaleElementIdPrefix() {
|
||||
return "landing-" + super.getLocaleElementIdPrefix();
|
||||
}
|
||||
|
||||
public String getToolbarLoggedInUser() {
|
||||
return getTextFromElement(toolbarLoggedInUser);
|
||||
}
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
locale_test=Přísný jazyk
|
||||
client_localized-client=Přespříliš lokalizovaný klient
|
|
@ -1,3 +0,0 @@
|
|||
locale_test=Přísný jazyk
|
||||
accountManagementWelcomeMessage=Vítejte v Keycloaku
|
||||
personalInfoHtmlTitle=Osobní údaje
|
|
@ -1,2 +0,0 @@
|
|||
parent=${theme-default-name}.v2
|
||||
locales=en,de,lang01,lang02,lang03,lang04,lang05,test,lang06,lang07,lang08,lang09,lang10
|
|
@ -1,2 +0,0 @@
|
|||
locale_test=Přísný jazyk
|
||||
client_localized-client=Přespříliš lokalizovaný klient
|
|
@ -1,3 +0,0 @@
|
|||
locale_test=Přísný jazyk
|
||||
accountManagementWelcomeMessage=Vítejte v Keycloaku
|
||||
personalInfoHtmlTitle=Osobní údaje
|
|
@ -1,2 +0,0 @@
|
|||
parent=${theme-default-name}
|
||||
locales=en,lang01,lang02,lang03,lang04,lang05,test,lang06,lang07,lang08,lang09,lang10
|
|
@ -1 +0,0 @@
|
|||
locale_test=Přísný jazyk
|
|
@ -1 +0,0 @@
|
|||
locale_test=Přísný jazyk
|
|
@ -1,2 +0,0 @@
|
|||
parent=${theme-default-name}
|
||||
locales=en,lang01,lang02,lang03,lang04,lang05,test,lang06,lang07,lang08,lang09,lang10
|
|
@ -1 +0,0 @@
|
|||
locale_test=Přísný jazyk
|
|
@ -1,11 +0,0 @@
|
|||
locale_test=Přísný jazyk
|
||||
termsText=[TEST LOCALE] souhlas s podmínkami
|
||||
notMatchPasswordMessage=[TEST LOCALE] hesla se neshodují
|
||||
firstName=[TEST LOCALE] křestní jméno
|
||||
updateProfileMessage=[TEST LOCALE] aktualizovat profil
|
||||
verifyEmailMessage=[TEST LOCALE] je třeba ověřit emailovou adresu
|
||||
invalidTotpMessage=[TEST LOCALE] vložen chybný kód
|
||||
oauthGrantTitle=[TEST LOCALE] Udělit přístup {0}
|
||||
rememberMe=[TEST LOCALE] Zapamatuj si mě
|
||||
invalidUserMessage=[TEST LOCALE] Chybné jméno nebo heslo
|
||||
emailForgotTitle=[TEST LOCALE] Zapomenuté heslo
|
|
@ -1,2 +0,0 @@
|
|||
parent=${theme-default-name}
|
||||
locales=en,de,lang01,lang02,lang03,lang04,lang05,test,lang06,lang07,lang08,lang09,lang10
|
|
@ -1,84 +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.ui;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.testsuite.AbstractAuthTest;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.junit.Assume.assumeFalse;
|
||||
|
||||
/**
|
||||
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||
*/
|
||||
public abstract class AbstractUiTest extends AbstractAuthTest {
|
||||
public static final String LOCALIZED_THEME = "localized-theme";
|
||||
public static final String LOCALIZED_THEME_PREVIEW = "localized-theme-preview";
|
||||
public static final String CUSTOM_LOCALE = "test";
|
||||
public static final String CUSTOM_LOCALE_NAME = "Přísný jazyk";
|
||||
public static final String DEFAULT_LOCALE="en";
|
||||
public static final String DEFAULT_LOCALE_NAME = "English";
|
||||
public static final String LOCALE_CLIENT_NAME = "${client_localized-client}";
|
||||
public static final String LOCALE_CLIENT_NAME_LOCALIZED = "Přespříliš lokalizovaný klient";
|
||||
|
||||
@BeforeClass
|
||||
public static void assumeSupportedBrowser() {
|
||||
assumeFalse("Browser must not be htmlunit", System.getProperty("browser").equals("htmlUnit"));
|
||||
assumeFalse("Browser must not be PhantomJS", System.getProperty("browser").equals("phantomjs"));
|
||||
}
|
||||
|
||||
@Before
|
||||
public void addTestUser() {
|
||||
createTestUserWithAdminClient(false);
|
||||
}
|
||||
|
||||
protected boolean isAccountPreviewTheme() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void configureInternationalizationForRealm(RealmRepresentation realm) {
|
||||
final String localizedTheme = isAccountPreviewTheme() ? LOCALIZED_THEME_PREVIEW : LOCALIZED_THEME;
|
||||
|
||||
// fetch the supported locales for the special test theme that includes some fake test locales
|
||||
Set<String> supportedLocales = adminClient.serverInfo().getInfo().getThemes().get("login").stream()
|
||||
.filter(x -> x.getName().equals(LOCALIZED_THEME))
|
||||
.flatMap(x -> Arrays.stream(x.getLocales()))
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
realm.setInternationalizationEnabled(true);
|
||||
realm.setSupportedLocales(supportedLocales);
|
||||
realm.setLoginTheme(LOCALIZED_THEME);
|
||||
realm.setAccountTheme(localizedTheme);
|
||||
realm.setEmailTheme(LOCALIZED_THEME);
|
||||
}
|
||||
|
||||
protected IdentityProviderRepresentation createIdentityProviderRepresentation(String alias, String providerId) {
|
||||
IdentityProviderRepresentation idpRep = new IdentityProviderRepresentation();
|
||||
idpRep.setProviderId(providerId);
|
||||
idpRep.setAlias(alias);
|
||||
idpRep.setConfig(new HashMap<>());
|
||||
return idpRep;
|
||||
}
|
||||
}
|
|
@ -1,73 +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.ui.account3;
|
||||
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.junit.Before;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
|
||||
import org.keycloak.testsuite.ui.AbstractUiTest;
|
||||
import org.keycloak.testsuite.ui.account3.page.PageNotFound;
|
||||
import org.keycloak.testsuite.ui.account3.page.WelcomeScreen;
|
||||
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWithLoginUrlOf;
|
||||
|
||||
/**
|
||||
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||
*/
|
||||
public abstract class AbstractAccountTest extends AbstractUiTest {
|
||||
public static final String ACCOUNT_THEME_NAME_KC = "keycloak.v2";
|
||||
public static final DateTimeFormatter DEFAULT_TIME_FORMATTER = DateTimeFormatter.ofPattern("MMMM d, yyyy 'at' h:mm a", Locale.ENGLISH);
|
||||
|
||||
@Page
|
||||
protected WelcomeScreen accountWelcomeScreen;
|
||||
|
||||
@Page
|
||||
protected PageNotFound pageNotFound;
|
||||
|
||||
@Override
|
||||
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
||||
super.addTestRealms(testRealms);
|
||||
RealmRepresentation testRealmRep = testRealms.get(0);
|
||||
testRealmRep.setAccountTheme(getAccountThemeName());
|
||||
}
|
||||
|
||||
@Before
|
||||
public void navigateBeforeTest() {
|
||||
accountWelcomeScreen.navigateTo();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isAccountPreviewTheme() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void loginToAccount() {
|
||||
assertCurrentUrlStartsWithLoginUrlOf(accountWelcomeScreen);
|
||||
loginPage.form().login(testUser);
|
||||
}
|
||||
|
||||
protected String getAccountThemeName() {
|
||||
return ACCOUNT_THEME_NAME_KC;
|
||||
}
|
||||
}
|
|
@ -1,121 +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.ui.account3;
|
||||
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.testsuite.ui.account3.page.AbstractLoggedInPage;
|
||||
import org.keycloak.testsuite.ui.account3.page.ApplicationsPage;
|
||||
import org.keycloak.testsuite.util.ClientBuilder;
|
||||
import org.keycloak.testsuite.util.OAuthClient;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.keycloak.testsuite.util.OAuthClient.APP_ROOT;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
|
||||
/**
|
||||
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||
*/
|
||||
public class ApplicationsTest extends BaseAccountPageTest {
|
||||
@Page
|
||||
private ApplicationsPage applicationsPage;
|
||||
|
||||
@Override
|
||||
protected AbstractLoggedInPage getAccountPage() {
|
||||
return applicationsPage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
||||
super.addTestRealms(testRealms);
|
||||
RealmRepresentation realm = testRealms.get(0);
|
||||
|
||||
realm.setClients(Arrays.asList(
|
||||
ClientBuilder
|
||||
.create()
|
||||
.clientId("always-display-client")
|
||||
.id(KeycloakModelUtils.generateId())
|
||||
.name("Always Display Client")
|
||||
.baseUrl(APP_ROOT + "/always-display-client")
|
||||
.directAccessGrants()
|
||||
.secret("secret1")
|
||||
.alwaysDisplayInConsole(true)
|
||||
.build(),
|
||||
ClientBuilder
|
||||
.create()
|
||||
.clientId("third-party-client")
|
||||
.id(KeycloakModelUtils.generateId())
|
||||
.name("Third Party Client")
|
||||
.baseUrl(APP_ROOT + "/third-party-client")
|
||||
.directAccessGrants()
|
||||
.secret("secret1")
|
||||
.consentRequired(true)
|
||||
.build()
|
||||
));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void applicationListTest() throws Exception {
|
||||
List<ApplicationsPage.ClientRepresentation> applications = applicationsPage.getApplications();
|
||||
assertFalse(applications.isEmpty());
|
||||
Map<String, ApplicationsPage.ClientRepresentation> apps = applications.stream().collect(Collectors.toMap(x -> x.getClientId(), x -> x));
|
||||
assertThat(apps.keySet(), containsInAnyOrder("always-display-client", "account-console"));
|
||||
assertClientRep(apps.get("account-console"), "Account Console", false, true, getAuthServerRoot() + "realms/test/account/", false);
|
||||
assertClientRep(apps.get("always-display-client"), "Always Display Client", false, false, getAuthServerRoot() + "realms/master/app/always-display-client", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toggleApplicationDetailsTest() throws Exception {
|
||||
applicationsPage.toggleApplicationDetails("account-console");
|
||||
List<ApplicationsPage.ClientRepresentation> applications = applicationsPage.getApplications();
|
||||
assertFalse(applications.isEmpty());
|
||||
Map<String, ApplicationsPage.ClientRepresentation> apps = applications.stream().collect(Collectors.toMap(x -> x.getClientId(), x -> x));
|
||||
assertThat(apps.keySet(), containsInAnyOrder("always-display-client", "account-console"));
|
||||
assertClientRep(apps.get("account-console"), "Account Console", false, true, getAuthServerRoot() + "realms/test/account/", true);
|
||||
assertClientRep(apps.get("always-display-client"), "Always Display Client", false, false, getAuthServerRoot() + "realms/master/app/always-display-client", false);
|
||||
|
||||
applicationsPage.toggleApplicationDetails("account-console");
|
||||
applications = applicationsPage.getApplications();
|
||||
assertFalse(applications.isEmpty());
|
||||
apps = applications.stream().collect(Collectors.toMap(x -> x.getClientId(), x -> x));
|
||||
assertThat(apps.keySet(), containsInAnyOrder("always-display-client", "account-console"));
|
||||
assertClientRep(apps.get("account-console"), "Account Console", false, true, getAuthServerRoot() + "realms/test/account/", false);
|
||||
assertClientRep(apps.get("always-display-client"), "Always Display Client", false, false, getAuthServerRoot() + "realms/master/app/always-display-client", false);
|
||||
}
|
||||
|
||||
private void assertClientRep(ApplicationsPage.ClientRepresentation clientRep, String name, boolean userConsentRequired, boolean inUse, String effectiveUrl, boolean applicationDetailsVisible) {
|
||||
assertNotNull(clientRep);
|
||||
assertEquals(name, clientRep.getClientName());
|
||||
assertEquals(userConsentRequired, clientRep.isUserConsentRequired());
|
||||
assertEquals(inUse, clientRep.isInUse());
|
||||
assertEquals(applicationDetailsVisible, clientRep.isApplicationDetailsVisible());
|
||||
if (applicationDetailsVisible) assertEquals(effectiveUrl, clientRep.getEffectiveUrl());
|
||||
}
|
||||
|
||||
}
|
|
@ -1,56 +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.ui.account3;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.keycloak.testsuite.ui.account3.page.AbstractLoggedInPage;
|
||||
import org.keycloak.testsuite.ui.account3.page.utils.SigningInPageUtils;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||
*/
|
||||
public abstract class BaseAccountPageTest extends AbstractAccountTest {
|
||||
protected abstract AbstractLoggedInPage getAccountPage();
|
||||
|
||||
@Override
|
||||
public void navigateBeforeTest() {
|
||||
getAccountPage().navigateTo();
|
||||
loginToAccount();
|
||||
getAccountPage().assertCurrent();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void navigationTest() {
|
||||
pageNotFound.navigateTo();
|
||||
pageNotFound.assertCurrent();
|
||||
|
||||
getAccountPage().navigateToUsingSidebar();
|
||||
getAccountPage().assertCurrent();
|
||||
|
||||
if (getAccountPage().getParentPageId() != null) {
|
||||
assertTrue("Nav bar subsection should be expanded after clicking nav item",
|
||||
getAccountPage().sidebar().isNavSubsectionExpanded(getAccountPage().getParentPageId()));
|
||||
}
|
||||
}
|
||||
|
||||
protected void testModalDialog(Runnable triggerModal, Runnable onCancel) {
|
||||
SigningInPageUtils.testModalDialog(getAccountPage(), triggerModal, onCancel);
|
||||
}
|
||||
}
|
|
@ -1,165 +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.ui.account3;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.models.AccountRoles;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.RequiredActionProviderRepresentation;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
import org.keycloak.testsuite.AssertEvents;
|
||||
import org.keycloak.testsuite.admin.ApiUtil;
|
||||
import org.keycloak.testsuite.pages.PasswordPage;
|
||||
import org.keycloak.testsuite.ui.account3.page.AbstractLoggedInPage;
|
||||
import org.keycloak.testsuite.auth.page.login.DeleteAccountActionConfirmPage;
|
||||
import org.keycloak.testsuite.ui.account3.page.PersonalInfoPage;
|
||||
|
||||
import static org.keycloak.testsuite.util.UIUtils.refreshPageAndWaitForLoad;
|
||||
|
||||
/**
|
||||
* @author Zakaria Amine <zakaria.amine88@gmail.com>
|
||||
*/
|
||||
public class DeleteAccountTest extends BaseAccountPageTest {
|
||||
|
||||
@Page
|
||||
private PersonalInfoPage personalInfoPage;
|
||||
|
||||
@Page
|
||||
private DeleteAccountActionConfirmPage deleteAccountActionConfirmPage;
|
||||
|
||||
@Page
|
||||
private PasswordPage passwordPage;
|
||||
|
||||
@Rule
|
||||
public AssertEvents events = new AssertEvents(this);
|
||||
|
||||
@Override
|
||||
protected AbstractLoggedInPage getAccountPage() {
|
||||
return personalInfoPage;
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
enableDeleteAccountRequiredAction();
|
||||
addDeleteAccountRoleToUserClientRoles();
|
||||
}
|
||||
|
||||
@After
|
||||
public void clean() {
|
||||
disableDeleteAccountRequiredAction();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteOwnAccountSectionNotVisibleWithoutClientRole() {
|
||||
removeDeleteAccountRoleFromUserClientRoles();
|
||||
refreshPageAndWaitForLoad();
|
||||
personalInfoPage.assertDeleteAccountSectionVisible(false);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void deleteOwnAccountSectionNotVisibleWithoutDeleteAccountActionEnabled() {
|
||||
disableDeleteAccountRequiredAction();
|
||||
refreshPageAndWaitForLoad();
|
||||
personalInfoPage.assertDeleteAccountSectionVisible(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteOwnAccountAIACancellationSucceeds() {
|
||||
refreshPageAndWaitForLoad();
|
||||
personalInfoPage.assertDeleteAccountSectionVisible(true);
|
||||
personalInfoPage.clickOpenDeleteExapandable();
|
||||
personalInfoPage.clickDeleteAccountButton();
|
||||
|
||||
reauthenticateUser();
|
||||
|
||||
Assert.assertTrue(deleteAccountActionConfirmPage.isCurrent());
|
||||
deleteAccountActionConfirmPage.clickCancelAIA();
|
||||
Assert.assertTrue(personalInfoPage.isCurrent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteOwnAccountForbiddenWithoutClientRole() {
|
||||
refreshPageAndWaitForLoad();
|
||||
personalInfoPage.assertDeleteAccountSectionVisible(true);
|
||||
personalInfoPage.clickOpenDeleteExapandable();
|
||||
personalInfoPage.clickDeleteAccountButton();
|
||||
|
||||
reauthenticateUser();
|
||||
|
||||
Assert.assertTrue(deleteAccountActionConfirmPage.isCurrent());
|
||||
removeDeleteAccountRoleFromUserClientRoles();
|
||||
deleteAccountActionConfirmPage.clickConfirmAction();
|
||||
Assert.assertTrue(deleteAccountActionConfirmPage.isErrorMessageDisplayed());
|
||||
Assert.assertEquals(deleteAccountActionConfirmPage.getErrorMessageText(), "You do not have enough permissions to delete your own account, contact admin.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteOwnAccountSucceeds() {
|
||||
personalInfoPage.navigateTo();
|
||||
personalInfoPage.assertDeleteAccountSectionVisible(true);
|
||||
personalInfoPage.clickOpenDeleteExapandable();
|
||||
personalInfoPage.clickDeleteAccountButton();
|
||||
|
||||
reauthenticateUser();
|
||||
|
||||
deleteAccountActionConfirmPage.isCurrent();
|
||||
deleteAccountActionConfirmPage.clickConfirmAction();
|
||||
events.expectAccount(EventType.DELETE_ACCOUNT);
|
||||
Assert.assertTrue(testRealmResource().users().search(testUser.getUsername()).isEmpty());
|
||||
}
|
||||
|
||||
private void reauthenticateUser() {
|
||||
passwordPage.assertCurrent();
|
||||
passwordPage.login("password");
|
||||
}
|
||||
|
||||
private void addDeleteAccountRoleToUserClientRoles() {
|
||||
ApiUtil.assignClientRoles(testRealmResource(), testUser.getId(), "account",AccountRoles.DELETE_ACCOUNT);
|
||||
}
|
||||
|
||||
private void disableDeleteAccountRequiredAction() {
|
||||
RequiredActionProviderRepresentation deleteAccount = testRealmResource().flows().getRequiredAction("delete_account");
|
||||
deleteAccount.setEnabled(false);
|
||||
testRealmResource().flows().updateRequiredAction("delete_account", deleteAccount);
|
||||
}
|
||||
|
||||
private void enableDeleteAccountRequiredAction() {
|
||||
RequiredActionProviderRepresentation deleteAccount = testRealmResource().flows().getRequiredAction("delete_account");
|
||||
deleteAccount.setEnabled(true);
|
||||
testRealmResource().flows().updateRequiredAction("delete_account", deleteAccount);
|
||||
}
|
||||
|
||||
private void removeDeleteAccountRoleFromUserClientRoles() {
|
||||
ClientRepresentation clientRepresentation = testRealmResource().clients().findByClientId("account").get(0);
|
||||
String deleteRoleId = testUserResource().roles().clientLevel(clientRepresentation.getId()).listAll().stream().filter(role -> Objects.equals(role.getName(), "delete-account")).findFirst().get().getId();
|
||||
RoleRepresentation deleteRole = new RoleRepresentation();
|
||||
deleteRole.setName("delete-account");
|
||||
deleteRole.setId(deleteRoleId);
|
||||
testUserResource().roles().clientLevel(clientRepresentation.getId()).remove(Arrays.asList(deleteRole));
|
||||
}
|
||||
}
|
|
@ -1,461 +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.ui.account3;
|
||||
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.common.util.Time;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.testsuite.ui.account3.page.AbstractLoggedInPage;
|
||||
import org.keycloak.testsuite.ui.account3.page.DeviceActivityPage;
|
||||
import org.keycloak.testsuite.util.ClientBuilder;
|
||||
import org.keycloak.testsuite.util.OAuthClient;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.either;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD;
|
||||
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
|
||||
import static org.keycloak.testsuite.util.UIUtils.refreshPageAndWaitForLoad;
|
||||
|
||||
/**
|
||||
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||
*/
|
||||
public class DeviceActivityTest extends BaseAccountPageTest {
|
||||
public static final String TEST_CLIENT_ID = "test-client";
|
||||
public static final String TEST_CLIENT_SECRET = "top secret stuff";
|
||||
public static final String TEST_CLIENT2_ID = "test-client2";
|
||||
public static final String TEST_CLIENT2_SECRET = "even more top secret stuff";
|
||||
public static final String TEST_CLIENT3_ID = "test-client3";
|
||||
public static final String TEST_CLIENT3_SECRET = "dunno";
|
||||
public static final String TEST_CLIENT3_NAME = "Příliš žluťoučký kůň";
|
||||
|
||||
@Page
|
||||
private DeviceActivityPage deviceActivityPage;
|
||||
|
||||
@Override
|
||||
protected AbstractLoggedInPage getAccountPage() {
|
||||
return deviceActivityPage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
||||
super.addTestRealms(testRealms);
|
||||
RealmRepresentation realm = testRealms.get(0);
|
||||
|
||||
realm.setClients(Arrays.asList(
|
||||
ClientBuilder
|
||||
.create()
|
||||
.clientId(TEST_CLIENT_ID) // client with no name
|
||||
.secret(TEST_CLIENT_SECRET)
|
||||
.directAccessGrants()
|
||||
.build(),
|
||||
ClientBuilder
|
||||
.create().
|
||||
clientId(TEST_CLIENT2_ID)
|
||||
.name(LOCALE_CLIENT_NAME) // client with localized name
|
||||
.secret(TEST_CLIENT2_SECRET)
|
||||
.directAccessGrants().build(),
|
||||
ClientBuilder
|
||||
.create().
|
||||
clientId(TEST_CLIENT3_ID)
|
||||
.name(TEST_CLIENT3_NAME) // client without localized name
|
||||
.secret(TEST_CLIENT3_SECRET)
|
||||
.directAccessGrants().build()
|
||||
|
||||
));
|
||||
|
||||
realm.setAccountTheme(LOCALIZED_THEME_PREVIEW); // using localized custom theme for the client localized name
|
||||
configureInternationalizationForRealm(testRealms.get(0));
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeDeviceActivityTest() {
|
||||
oauth.clientId(TEST_CLIENT3_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void browsersTest() {
|
||||
Map<Browsers, String> browserSessions = new HashMap<>();
|
||||
Arrays.stream(Browsers.values()).forEach(b -> {
|
||||
browserSessions.put(b, DeviceActivityPage.getTrimmedSessionId(createSession(b)));
|
||||
});
|
||||
|
||||
deviceActivityPage.clickRefreshPage();
|
||||
|
||||
browserSessions.forEach((browser, sessionId) -> {
|
||||
final Optional<DeviceActivityPage.Session> session = deviceActivityPage.getSession(sessionId);
|
||||
assertThat(session.isPresent(), is(true));
|
||||
assertSession(browser, session.get());
|
||||
});
|
||||
|
||||
assertEquals(Browsers.values().length + 1, deviceActivityPage.getSessionsCount()); // + 1 for the current session
|
||||
}
|
||||
|
||||
@Test
|
||||
public void currentSessionTest() {
|
||||
createSession(Browsers.CHROME);
|
||||
createSession(Browsers.SAFARI);
|
||||
|
||||
deviceActivityPage.clickRefreshPage();
|
||||
|
||||
assertEquals(3, deviceActivityPage.getSessionsCount());
|
||||
|
||||
Optional<DeviceActivityPage.Session> currentSession = deviceActivityPage.getSessionByIndex(0); // current session should be first
|
||||
assertThat(currentSession.isPresent(), is(true));
|
||||
assertSessionRowsAreNotEmpty(currentSession.get(), false);
|
||||
assertTrue("Browser identification should be present", currentSession.get().isBrowserDisplayed());
|
||||
assertTrue("Current session badge should be present", currentSession.get().hasCurrentBadge());
|
||||
assertFalse("Icon should be present", currentSession.get().getIcon().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void signOutTest() {
|
||||
assertFalse("Sign out all shouldn't be displayed", deviceActivityPage.isSignOutAllDisplayed());
|
||||
final String chromeSessionId = createSession(Browsers.CHROME);
|
||||
deviceActivityPage.clickRefreshPage();
|
||||
|
||||
Optional<DeviceActivityPage.Session> chromeSessionOptional = deviceActivityPage.getSession(chromeSessionId);
|
||||
assertThat(chromeSessionOptional.isPresent(), is(true));
|
||||
DeviceActivityPage.Session chromeSession = chromeSessionOptional.get();
|
||||
|
||||
createSession(Browsers.SAFARI);
|
||||
deviceActivityPage.clickRefreshPage();
|
||||
|
||||
assertTrue("Sign out all should be displayed", deviceActivityPage.isSignOutAllDisplayed());
|
||||
assertEquals(3, testUserResource().getUserSessions().size());
|
||||
|
||||
assertThat(testUserResource()
|
||||
.getUserSessions()
|
||||
.stream()
|
||||
.map(f -> f.getId())
|
||||
.map(DeviceActivityPage::getTrimmedSessionId)
|
||||
.collect(Collectors.toList()),
|
||||
hasItem(chromeSession.getSessionId()));
|
||||
|
||||
// sign out one session
|
||||
assertThat(chromeSession.isSignOutDisplayed(), is(true));
|
||||
testModalDialog(chromeSession::clickSignOut, () -> {
|
||||
assertEquals(3, testUserResource().getUserSessions().size()); // no change, all sessions still present
|
||||
});
|
||||
deviceActivityPage.alert().assertSuccess();
|
||||
assertFalse("Chrome session should be gone", chromeSession.isPresent());
|
||||
assertEquals(2, testUserResource().getUserSessions().size());
|
||||
assertThat(testUserResource()
|
||||
.getUserSessions()
|
||||
.stream()
|
||||
.map(f -> f.getId())
|
||||
.map(DeviceActivityPage::getTrimmedSessionId)
|
||||
.collect(Collectors.toList()),
|
||||
not(hasItem(chromeSession.getSessionId())));
|
||||
|
||||
// sign out all sessions
|
||||
testModalDialog(deviceActivityPage::clickSignOutAll, () -> {
|
||||
assertEquals(2, testUserResource().getUserSessions().size()); // no change
|
||||
});
|
||||
accountWelcomeScreen.assertCurrent();
|
||||
assertEquals(0, testUserResource().getUserSessions().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clientsTest() {
|
||||
String sessionId = createSession(Browsers.CHROME);
|
||||
|
||||
// attach more clients to the session
|
||||
testingClient.server().run(session -> {
|
||||
RealmModel realm = session.realms().getRealmByName(TEST);
|
||||
UserSessionModel userSession = session.sessions().getUserSession(realm, sessionId);
|
||||
|
||||
ClientModel client2 = session.clients().getClientByClientId(realm, TEST_CLIENT2_ID);
|
||||
ClientModel client3 = session.clients().getClientByClientId(realm, TEST_CLIENT3_ID);
|
||||
|
||||
session.sessions().createClientSession(realm, client2, userSession);
|
||||
session.sessions().createClientSession(realm, client3, userSession);
|
||||
});
|
||||
|
||||
deviceActivityPage.clickRefreshPage();
|
||||
|
||||
List<String> expectedClients = Arrays.asList(TEST_CLIENT_ID, LOCALE_CLIENT_NAME_LOCALIZED, TEST_CLIENT3_NAME);
|
||||
|
||||
final Optional<DeviceActivityPage.Session> sessionById = deviceActivityPage.getSession(sessionId);
|
||||
assertThat(sessionById.isPresent(), is(true));
|
||||
String[] actualClients = sessionById.get().getClients().split(", ");
|
||||
assertThat(expectedClients, containsInAnyOrder(actualClients));
|
||||
|
||||
final Optional<DeviceActivityPage.Session> session = deviceActivityPage.getSessionByIndex(0);
|
||||
assertThat(session.isPresent(), is(true));
|
||||
assertEquals("Account Console", session.get().getClients());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void timesTests() {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
LocalDateTime nowPlus1 = now.plusMinutes(1);
|
||||
String nowStr = now.format(DEFAULT_TIME_FORMATTER);
|
||||
String nowStrPlus1 = nowPlus1.format(DEFAULT_TIME_FORMATTER);
|
||||
|
||||
String sessionId = createSession(Browsers.CHROME);
|
||||
|
||||
testingClient.server().run(session -> {
|
||||
RealmModel realm = session.realms().getRealmByName(TEST);
|
||||
UserSessionModel userSession = session.sessions().getUserSession(realm, sessionId);
|
||||
|
||||
userSession.setLastSessionRefresh(Time.currentTime() + 120);
|
||||
});
|
||||
|
||||
deviceActivityPage.clickRefreshPage();
|
||||
|
||||
final Optional<DeviceActivityPage.Session> session = deviceActivityPage.getSession(sessionId);
|
||||
assertThat(session.isPresent(), is(true));
|
||||
|
||||
String startedAtStr = session.get().getStarted();
|
||||
LocalDateTime startedAt = LocalDateTime.parse(startedAtStr, DEFAULT_TIME_FORMATTER);
|
||||
LocalDateTime lastAccessed = LocalDateTime.parse(session.get().getLastAccess(), DEFAULT_TIME_FORMATTER);
|
||||
LocalDateTime expiresAt = LocalDateTime.parse(session.get().getExpires(), DEFAULT_TIME_FORMATTER);
|
||||
|
||||
assertTrue("Last access should be after started at", lastAccessed.isAfter(startedAt));
|
||||
assertTrue("Expires at should be after last access", expiresAt.isAfter(lastAccessed));
|
||||
assertTrue("Last accessed should be in the future", lastAccessed.isAfter(now));
|
||||
assertThat(startedAtStr, either(equalTo(nowStr)).or(equalTo(nowStrPlus1)));
|
||||
|
||||
int ssoLifespan = testRealmResource().toRepresentation().getSsoSessionMaxLifespan();
|
||||
assertEquals(startedAt.plusSeconds(ssoLifespan), expiresAt);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void timeLocaleTest() {
|
||||
String sessionId = createSession(Browsers.CHROME);
|
||||
UserRepresentation user = testUserResource().toRepresentation();
|
||||
final Locale locale = Locale.GERMAN;
|
||||
user.setAttributes(new HashMap<String, List<String>>() {{
|
||||
put("locale", Collections.singletonList(locale.toLanguageTag()));
|
||||
}});
|
||||
testUserResource().update(user);
|
||||
|
||||
refreshPageAndWaitForLoad();
|
||||
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d. MMMM yyyy 'um' H:mm", locale);
|
||||
Optional<DeviceActivityPage.Session> session = deviceActivityPage.getSession(sessionId);
|
||||
assertThat(session.isPresent(), is(true));
|
||||
try {
|
||||
LocalDateTime.parse(session.get().getLastAccess(), formatter);
|
||||
} catch (DateTimeParseException e) {
|
||||
fail("Time was not formatted with the locale");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ipTest() {
|
||||
final String ip = "146.58.69.12";
|
||||
|
||||
String sessionId = "abcdefg";
|
||||
testingClient.server().run(session -> {
|
||||
RealmModel realm = session.realms().getRealmByName(TEST);
|
||||
ClientModel client = session.clients().getClientByClientId(realm, TEST_CLIENT_ID);
|
||||
UserModel user = session.users().getUserByUsername(realm, "test"); // cannot use testUser.getUsername() because it throws NotSerializableException for no apparent reason (or maybe I'm just stupid :D)
|
||||
|
||||
UserSessionModel userSession = session.sessions().createUserSession(sessionId, realm, user, "test", ip, "form", false, null, null, null);
|
||||
session.sessions().createClientSession(realm, client, userSession);
|
||||
});
|
||||
|
||||
deviceActivityPage.clickRefreshPage();
|
||||
|
||||
final Optional<DeviceActivityPage.Session> session = deviceActivityPage.getSession(sessionId);
|
||||
assertThat(session.isPresent(), is(true));
|
||||
assertEquals(ip, session.get().getIp());
|
||||
}
|
||||
|
||||
private String createSession(Browsers browser) {
|
||||
log.info("Creating session for " + browser);
|
||||
OAuthClient.AccessTokenResponse res;
|
||||
try {
|
||||
// using direct grant not to use current browser
|
||||
res = oauth.doGrantAccessTokenRequest(
|
||||
TEST, testUser.getUsername(), PASSWORD, null, TEST_CLIENT_ID, TEST_CLIENT_SECRET, browser.userAgent);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return res.getSessionState(); // session id
|
||||
}
|
||||
|
||||
private void assertSession(Browsers browser, DeviceActivityPage.Session session) {
|
||||
log.infof("Asserting %s (session %s)", browser, session.getSessionId());
|
||||
assertTrue("Session should be present", session.isPresent());
|
||||
assertTrue("Browser name should be present", session.isBrowserDisplayed());
|
||||
|
||||
if (browser.sessionBrowser != null) {
|
||||
assertEquals(browser.sessionBrowser, session.getBrowser());
|
||||
} else {
|
||||
assertEquals("Other/Unknown", session.getBrowser());
|
||||
}
|
||||
|
||||
assertEquals(browser.iconName, session.getIcon());
|
||||
assertFalse("Session shouldn't have current badge", session.hasCurrentBadge()); // we don't test current session
|
||||
assertSessionRowsAreNotEmpty(session, true);
|
||||
}
|
||||
|
||||
private void assertSessionRowsAreNotEmpty(DeviceActivityPage.Session session, boolean expectSignOutPresent) {
|
||||
assertFalse("IP address shouldn't be empty", session.getIp().isEmpty());
|
||||
assertFalse("Last accessed shouldn't be empty", session.getLastAccess().isEmpty());
|
||||
assertFalse("Started shouldn't be empty", session.getStarted().isEmpty());
|
||||
assertFalse("Expires shouldn't be empty", session.getExpires().isEmpty());
|
||||
assertFalse("Clients shouldn't be empty", session.getClients().isEmpty());
|
||||
assertEquals("Sign out button visibility", expectSignOutPresent, session.isSignOutDisplayed());
|
||||
}
|
||||
|
||||
public enum Browsers {
|
||||
CHROME(
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36",
|
||||
"Chrome/78.0.3904",
|
||||
DeviceType.DESKTOP
|
||||
),
|
||||
CHROMIUM(
|
||||
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.30 (KHTML, like Gecko) Ubuntu/11.04 Chromium/12.0.742.112 Chrome/12.0.742.112 Safari/534.30",
|
||||
"Chromium/12.0.742",
|
||||
DeviceType.DESKTOP
|
||||
),
|
||||
FIREFOX(
|
||||
"Mozilla/5.0 (X11; Fedora;Linux x86; rv:60.0) Gecko/20100101 Firefox/60.0",
|
||||
"Firefox/60.0",
|
||||
DeviceType.DESKTOP
|
||||
),
|
||||
EDGE(
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763",
|
||||
"Edge/18.17763",
|
||||
DeviceType.DESKTOP
|
||||
),
|
||||
// TODO uncomment this once KEYCLOAK-12445 is resolved
|
||||
// CHREDGE( // Edge based on Chromium
|
||||
// "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.74 Safari/537.36 Edg/79.0.309.43",
|
||||
// "Edge/79.0.309 / Mac OS X 10.15.1",
|
||||
// "edge"
|
||||
// ),
|
||||
IE(
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko",
|
||||
"IE/11.0",
|
||||
DeviceType.DESKTOP
|
||||
),
|
||||
SAFARI(
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Safari/605.1.15",
|
||||
"Safari/13.0.3",
|
||||
DeviceType.DESKTOP
|
||||
),
|
||||
OPERA(
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36 OPR/56.0.3051.52",
|
||||
"Opera/56.0.3051",
|
||||
DeviceType.DESKTOP
|
||||
),
|
||||
YANDEX(
|
||||
"Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 YaBrowser/17.6.1.749 Yowser/2.5 Safari/537.36",
|
||||
"Yandex Browser/17.6.1",
|
||||
DeviceType.DESKTOP
|
||||
),
|
||||
CHROME_ANDROID(
|
||||
"Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Mobile Safari/537.36",
|
||||
"Chrome Mobile/68.0.3440",
|
||||
DeviceType.MOBILE
|
||||
),
|
||||
SAFARI_IOS(
|
||||
"Mozilla/5.0 (iPhone; CPU iPhone OS 13_1_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.1 Mobile/15E148 Safari/604.1",
|
||||
"Mobile Safari/13.0.1",
|
||||
DeviceType.MOBILE
|
||||
),
|
||||
UNKNOWN_BROWSER(
|
||||
"Top-secret government browser running on top-secret OS",
|
||||
null,
|
||||
DeviceType.UNKNOWN
|
||||
),
|
||||
UNKNOWN_OS(
|
||||
"Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36",
|
||||
"Chrome/78.0.3904",
|
||||
DeviceType.UNKNOWN
|
||||
),
|
||||
UNKNOWN_OS_VERSION(
|
||||
"Mozilla/5.0 (Windows 256.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36",
|
||||
"Chrome/78.0.3904",
|
||||
DeviceType.UNKNOWN
|
||||
);
|
||||
// not sure what "Amazon" browser is supposed to be (it's specified in DeviceActivityPage.tsx)
|
||||
|
||||
private final String userAgent;
|
||||
private final String sessionBrowser; // how the browser is interpreted by the sessions endpoint
|
||||
private final DeviceType deviceType;
|
||||
private final String iconName;
|
||||
|
||||
Browsers(String userAgent, String sessionBrowser, DeviceType deviceType) {
|
||||
this.userAgent = userAgent;
|
||||
this.sessionBrowser = sessionBrowser;
|
||||
this.deviceType = deviceType;
|
||||
this.iconName = deviceType.getIconName();
|
||||
}
|
||||
|
||||
public String userAgent() {
|
||||
return userAgent;
|
||||
}
|
||||
|
||||
public String sessionBrowser() {
|
||||
return sessionBrowser;
|
||||
}
|
||||
|
||||
public String iconName() {
|
||||
return iconName;
|
||||
}
|
||||
|
||||
private enum DeviceType {
|
||||
DESKTOP("desktop"),
|
||||
MOBILE("mobile"),
|
||||
UNKNOWN("desktop"); // Default icon
|
||||
|
||||
private final String iconName;
|
||||
|
||||
DeviceType(String iconName) {
|
||||
this.iconName = iconName;
|
||||
}
|
||||
|
||||
public String getIconName() {
|
||||
return iconName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,196 +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.ui.account3;
|
||||
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.credential.PasswordCredentialModel;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.testsuite.ui.account3.page.PersonalInfoPage;
|
||||
import org.keycloak.testsuite.ui.account3.page.SigningInPage;
|
||||
import org.keycloak.testsuite.ui.account3.page.WelcomeScreen;
|
||||
import org.keycloak.testsuite.util.WaitUtils;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||
*/
|
||||
public class InternationalizationTest extends AbstractAccountTest {
|
||||
@Page
|
||||
private WelcomeScreen welcomeScreen;
|
||||
|
||||
@Page
|
||||
private PersonalInfoPage personalInfoPage;
|
||||
|
||||
@Page
|
||||
private SigningInPage signingInPage;
|
||||
private SigningInPage.CredentialType passwordCredentialType;
|
||||
|
||||
@Override
|
||||
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
||||
super.addTestRealms(testRealms);
|
||||
configureInternationalizationForRealm(testRealms.get(0));
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeI18nTest() {
|
||||
assertTestUserLocale(null);
|
||||
passwordCredentialType = signingInPage.getCredentialType(PasswordCredentialModel.TYPE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loggedInPageTest() {
|
||||
personalInfoPage.navigateTo();
|
||||
loginToAccount();
|
||||
assertTestUserLocale(null);
|
||||
personalInfoPage.selectLocale(CUSTOM_LOCALE);
|
||||
personalInfoPage.clickSave(false);
|
||||
WaitUtils.waitForPageToLoad();
|
||||
|
||||
assertTestUserLocale(CUSTOM_LOCALE);
|
||||
assertCustomLocalePersonalInfo();
|
||||
|
||||
// check if selected locale is preserved
|
||||
personalInfoPage.header().clickLogoutBtn();
|
||||
welcomeScreen.assertCurrent();
|
||||
assertCustomLocaleWelcomeScreen();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void realmLocalizationMessagesAreApplied() {
|
||||
String messageKey = "personalInfoHtmlTitle";
|
||||
|
||||
String localeEn = Locale.ENGLISH.toLanguageTag();
|
||||
String messageEn = "personalInfoHtmlTitle EN";
|
||||
testRealmResource().localization().saveRealmLocalizationText(localeEn,
|
||||
messageKey, messageEn);
|
||||
getCleanup().addLocalization(localeEn);
|
||||
|
||||
String localeDe = Locale.GERMAN.toLanguageTag();
|
||||
String messageDe = "personalInfoHtmlTitle DE";
|
||||
testRealmResource().localization().saveRealmLocalizationText(localeDe,
|
||||
messageKey, messageDe);
|
||||
getCleanup().addLocalization(localeDe);
|
||||
|
||||
// default locale should be "en"
|
||||
personalInfoPage.navigateTo();
|
||||
loginToAccount();
|
||||
assertTestUserLocale(null);
|
||||
assertPersonalInfo(messageEn);
|
||||
|
||||
// switch to locale "de"
|
||||
personalInfoPage.selectLocale(localeDe);
|
||||
personalInfoPage.clickSave(false);
|
||||
WaitUtils.waitForPageToLoad();
|
||||
|
||||
assertTestUserLocale(localeDe);
|
||||
assertPersonalInfo(messageDe);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void loginFormTest() {
|
||||
personalInfoPage.navigateTo();
|
||||
loginPage.localeDropdown().selectAndAssert(CUSTOM_LOCALE_NAME);
|
||||
loginPage.form().login(testUser); // cannot use loginToAccount() because it asserts URL which is now different
|
||||
assertTestUserLocale(CUSTOM_LOCALE);
|
||||
assertCustomLocalePersonalInfo();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore // TODO: Enable once chromedriver version 113.0.5672.92 is available in https://chromedriver.storage.googleapis.com/
|
||||
public void userAttributeTest() {
|
||||
testUser.setAttributes(singletonMap(UserModel.LOCALE, singletonList(CUSTOM_LOCALE)));
|
||||
testUserResource().update(testUser);
|
||||
|
||||
welcomeScreen.navigateTo();
|
||||
welcomeScreen.clickPersonalInfoLink();
|
||||
assertEquals(DEFAULT_LOCALE_NAME, loginPage.localeDropdown().getSelected());
|
||||
loginToAccount();
|
||||
assertCustomLocalePersonalInfo();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void shouldDisplayTimeUsingSelectedLocale() {
|
||||
signingInPage.navigateTo();
|
||||
loginToAccount();
|
||||
SigningInPage.UserCredential passwordCred =
|
||||
passwordCredentialType.getUserCredential(testUserResource().credentials().get(0).getId());
|
||||
|
||||
try {
|
||||
LocalDateTime.parse(passwordCred.getCreatedAtStr(), DEFAULT_TIME_FORMATTER);
|
||||
} catch (DateTimeParseException e) {
|
||||
fail("Time was not formatted with the locale");
|
||||
}
|
||||
|
||||
signingInPage.header().clickLogoutBtn();
|
||||
signingInPage.navigateTo();
|
||||
loginPage.localeDropdown().selectAndAssert("Deutsch");
|
||||
loginPage.form().login(testUser);
|
||||
|
||||
DateTimeFormatter formatterDe = DateTimeFormatter.ofPattern("d. MMMM yyyy 'um' H:mm", Locale.GERMAN);
|
||||
|
||||
try {
|
||||
LocalDateTime.parse(passwordCred.getCreatedAtStr(), formatterDe);
|
||||
} catch (DateTimeParseException e) {
|
||||
fail("Time was not formatted with the locale");
|
||||
}
|
||||
}
|
||||
|
||||
private void assertCustomLocaleWelcomeScreen() {
|
||||
assertEquals("Vítejte v Keycloaku", welcomeScreen.getWelcomeMessage());
|
||||
}
|
||||
|
||||
private void assertCustomLocalePersonalInfo() {
|
||||
assertPersonalInfo("Osobní údaje");
|
||||
}
|
||||
|
||||
private void assertPersonalInfo(String expectedText) {
|
||||
assertEquals(expectedText, personalInfoPage.getPageTitle());
|
||||
}
|
||||
|
||||
private void assertTestUserLocale(String expectedLocale) {
|
||||
String actualLocale = null;
|
||||
List <String> userLocales;
|
||||
Map<String, List<String>> userAttributes = testUserResource().toRepresentation().getAttributes();
|
||||
|
||||
if (userAttributes != null) {
|
||||
userLocales = userAttributes.get(UserModel.LOCALE);
|
||||
if (userLocales != null) {
|
||||
actualLocale = userLocales.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(expectedLocale, actualLocale);
|
||||
}
|
||||
}
|
|
@ -1,163 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 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.ui.account3;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD;
|
||||
import static org.keycloak.testsuite.admin.Users.setPasswordFor;
|
||||
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
|
||||
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.junit.Before;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.models.LDAPConstants;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.credential.PasswordCredentialModel;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.storage.UserStorageProvider;
|
||||
import org.keycloak.storage.ldap.LDAPStorageProvider;
|
||||
import org.keycloak.storage.ldap.idm.model.LDAPObject;
|
||||
import org.keycloak.testsuite.admin.ApiUtil;
|
||||
import org.keycloak.testsuite.federation.ldap.LDAPTestContext;
|
||||
import org.keycloak.testsuite.ui.account3.page.PersonalInfoPage;
|
||||
import org.keycloak.testsuite.ui.account3.page.SigningInPage;
|
||||
import org.keycloak.testsuite.util.LDAPRule;
|
||||
import org.keycloak.testsuite.util.LDAPTestUtils;
|
||||
|
||||
/**
|
||||
* @author Alfredo Moises Boullosa <aboullos@redhat.com>
|
||||
*/
|
||||
public class LDAPAccountTest extends AbstractAccountTest {
|
||||
|
||||
@Page
|
||||
private SigningInPage signingInPage;
|
||||
|
||||
@Page
|
||||
private PersonalInfoPage personalInfoPage;
|
||||
|
||||
private SigningInPage.CredentialType passwordCredentialType;
|
||||
@ClassRule
|
||||
public static LDAPRule ldapRule = new LDAPRule();
|
||||
|
||||
@Before
|
||||
public void beforeSigningInTest() {
|
||||
passwordCredentialType = signingInPage.getCredentialType(PasswordCredentialModel.TYPE);
|
||||
|
||||
testingClient.testing().ldap(TEST).createLDAPProvider(ldapRule.getConfig(), true);
|
||||
log.infof("LDAP Provider created");
|
||||
|
||||
String userName = "johnkeycloak";
|
||||
String firstName = "Jonh";
|
||||
String lastName = "Doe";
|
||||
String email = "john@email.org";
|
||||
|
||||
testingClient.server().run(session -> {
|
||||
LDAPTestContext ctx = LDAPTestContext.init(session);
|
||||
RealmModel appRealm = ctx.getRealm();
|
||||
|
||||
// Delete all LDAP users and add some new for testing
|
||||
LDAPTestUtils.removeAllLDAPUsers(ctx.getLdapProvider(), appRealm);
|
||||
|
||||
LDAPObject john = LDAPTestUtils.addLDAPUser(ctx.getLdapProvider(), appRealm, userName, firstName, lastName, email, null, "1234");
|
||||
LDAPTestUtils.updateLDAPPassword(ctx.getLdapProvider(), john, PASSWORD);
|
||||
});
|
||||
|
||||
testRealmLoginPage.setAuthRealm(testRealmPage);
|
||||
|
||||
testUser = createUserRepresentation(userName, email, firstName, lastName, true);
|
||||
setPasswordFor(testUser, PASSWORD);
|
||||
|
||||
resetTestRealmSession();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createdNotVisibleTest() {
|
||||
signingInPage.navigateTo();
|
||||
loginPage.form().login(testUser);
|
||||
|
||||
SigningInPage.UserCredential userCredential = passwordCredentialType.getUserCredential("password");
|
||||
|
||||
assertTrue("ROW is not present", userCredential.isPresent());
|
||||
assertFalse("Created at is present", userCredential.hasCreatedAt());
|
||||
}
|
||||
|
||||
// KEYCLOAK-15634
|
||||
@Test
|
||||
public void updateProfileWithAttributePresent() {
|
||||
|
||||
RealmResource testRealm = adminClient.realm("test");
|
||||
assertEquals(getAccountThemeName(), testRealm.toRepresentation().getAccountTheme());
|
||||
|
||||
UserRepresentation userRepBefore = ApiUtil.findUserByUsername(testRealm,"keycloak-15634");
|
||||
assertNull("User should not exist", userRepBefore);
|
||||
|
||||
testingClient.server().run(session -> {
|
||||
LDAPTestContext ctx = LDAPTestContext.init(session);
|
||||
RealmModel appRealm = ctx.getRealm();
|
||||
|
||||
LDAPStorageProvider ldapFedProvider = LDAPTestUtils.getLdapProvider(session, ctx.getLdapModel());
|
||||
ldapFedProvider.getModel().put(LDAPConstants.EDIT_MODE, UserStorageProvider.EditMode.UNSYNCED.toString());
|
||||
appRealm.updateComponent(ldapFedProvider.getModel());
|
||||
|
||||
LDAPObject testUser = LDAPTestUtils.addLDAPUser(ctx.getLdapProvider(),
|
||||
appRealm, "keycloak-15634",
|
||||
"firstName",
|
||||
"lastName",
|
||||
"keycloak-15634@test.local",
|
||||
null,
|
||||
"1234");
|
||||
LDAPTestUtils.updateLDAPPassword(ctx.getLdapProvider(), testUser, PASSWORD);
|
||||
});
|
||||
|
||||
// Check our test user is ok before updating profile
|
||||
userRepBefore = ApiUtil.findUserByUsername(testRealm,"keycloak-15634");
|
||||
assertEquals("Test user should have an email address set", "keycloak-15634@test.local", userRepBefore.getEmail());
|
||||
assertTrue("Test user should have the LDAP_ID attribute set", userRepBefore.getAttributes().containsKey("LDAP_ID"));
|
||||
assertFalse("Test user should not have locale attribute set", userRepBefore.getAttributes().containsKey("locale"));
|
||||
|
||||
personalInfoPage.navigateTo();
|
||||
loginPage.assertCurrent();
|
||||
loginPage.form().login("keycloak-15634","password");
|
||||
personalInfoPage.assertCurrent();
|
||||
assertEquals("keycloak-15634@test.local", personalInfoPage.getEmail());
|
||||
|
||||
// Trigger the JS involved in KEYCLOAK-15634
|
||||
personalInfoPage.setEmail("keycloak-15634@domain.local");
|
||||
personalInfoPage.clickSave();
|
||||
|
||||
// Check if updateProfile went well and if user is still there
|
||||
UserRepresentation userRepAfter = ApiUtil.findUserByUsername(testRealm,"keycloak-15634");
|
||||
assertNotNull("Test user should still be there", userRepAfter);
|
||||
assertEquals("Email should have been updated","keycloak-15634@domain.local", userRepAfter.getEmail());
|
||||
assertTrue("LDAP_ID attribute should still be there", userRepAfter.getAttributes().containsKey("LDAP_ID"));
|
||||
|
||||
// Clean up
|
||||
ApiUtil.removeUserByUsername(testRealm, "keycloak-15634");
|
||||
testingClient.server().run(session -> {
|
||||
LDAPTestContext ctx = LDAPTestContext.init(session);
|
||||
RealmModel appRealm = ctx.getRealm();
|
||||
LDAPTestUtils.removeAllLDAPUsers(ctx.getLdapProvider(), appRealm);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,209 +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.ui.account3;
|
||||
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.broker.oidc.OIDCIdentityProviderFactory;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.FederatedIdentityRepresentation;
|
||||
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.social.google.GoogleIdentityProviderFactory;
|
||||
import org.keycloak.testsuite.pages.LoginPage;
|
||||
import org.keycloak.testsuite.ui.account3.page.AbstractLoggedInPage;
|
||||
import org.keycloak.testsuite.ui.account3.page.LinkedAccountsPage;
|
||||
import org.keycloak.testsuite.util.ClientBuilder;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
|
||||
|
||||
/**
|
||||
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||
*/
|
||||
public class LinkedAccountsTest extends BaseAccountPageTest {
|
||||
public static final String SOCIAL_IDP_ALIAS = "fake-google-account";
|
||||
public static final String SYSTEM_IDP_ALIAS = "kc-to-kc-account";
|
||||
|
||||
public static final String REALM2_NAME = "test-realm2";
|
||||
public static final String CLIENT_ID = "cross-realm-client";
|
||||
public static final String CLIENT_SECRET = "top secret";
|
||||
|
||||
private UserRepresentation homerUser;
|
||||
|
||||
private LinkedAccountsPage.IdentityProvider socialIdp;
|
||||
private LinkedAccountsPage.IdentityProvider systemIdp;
|
||||
|
||||
@Page
|
||||
private LinkedAccountsPage linkedAccountsPage;
|
||||
|
||||
@Page
|
||||
private LoginPage loginPageWithSocialBtns;
|
||||
|
||||
public LinkedAccountsTest() {
|
||||
// needs to be done here (setting fields in addTestRealms acts really weird resulting in Homer being null)
|
||||
homerUser = createUserRepresentation("hsimpson", "hsimpson@keycloak.org",
|
||||
"Homer", "Simpson", true, "Mmm donuts");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractLoggedInPage getAccountPage() {
|
||||
return linkedAccountsPage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
||||
super.addTestRealms(testRealms);
|
||||
RealmRepresentation realm1 = testRealms.get(0);
|
||||
|
||||
realm1.addIdentityProvider(createIdentityProviderRepresentation(SOCIAL_IDP_ALIAS,
|
||||
GoogleIdentityProviderFactory.PROVIDER_ID));
|
||||
|
||||
String oidcRoot = getAuthServerRoot() + "realms/" + REALM2_NAME + "/protocol/openid-connect/";
|
||||
|
||||
IdentityProviderRepresentation systemIdp = createIdentityProviderRepresentation(SYSTEM_IDP_ALIAS,
|
||||
OIDCIdentityProviderFactory.PROVIDER_ID);
|
||||
systemIdp.getConfig().put("clientId", CLIENT_ID);
|
||||
systemIdp.getConfig().put("clientSecret", CLIENT_SECRET);
|
||||
systemIdp.getConfig().put("clientAuthMethod", OIDCLoginProtocol.CLIENT_SECRET_POST);
|
||||
systemIdp.getConfig().put("authorizationUrl", oidcRoot + "auth");
|
||||
systemIdp.getConfig().put("tokenUrl", oidcRoot + "token");
|
||||
realm1.addIdentityProvider(systemIdp);
|
||||
|
||||
ClientRepresentation client = ClientBuilder.create()
|
||||
.clientId(CLIENT_ID)
|
||||
.secret(CLIENT_SECRET)
|
||||
.redirectUris(getAuthServerRoot() + "realms/" + TEST + "/broker/" + SYSTEM_IDP_ALIAS + "/endpoint")
|
||||
.build();
|
||||
|
||||
// using REALM2 as an identity provider
|
||||
RealmRepresentation realm2 = new RealmRepresentation();
|
||||
realm2.setId(REALM2_NAME);
|
||||
realm2.setRealm(REALM2_NAME);
|
||||
realm2.setEnabled(true);
|
||||
realm2.setClients(Collections.singletonList(client));
|
||||
realm2.setUsers(Collections.singletonList(homerUser));
|
||||
testRealms.add(realm2);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeLinkedAccountsTest() {
|
||||
socialIdp = linkedAccountsPage.getProvider(SOCIAL_IDP_ALIAS);
|
||||
systemIdp = linkedAccountsPage.getProvider(SYSTEM_IDP_ALIAS);
|
||||
assertProvidersCount();
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterLinkedAccountsTest() {
|
||||
assertProvidersCount();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void linkAccountTest() {
|
||||
assertEquals(0, testUserResource().getFederatedIdentity().size());
|
||||
|
||||
assertProvider(socialIdp, false, true, "");
|
||||
assertProvider(systemIdp, false, false, "");
|
||||
|
||||
systemIdp.clickLinkBtn();
|
||||
loginPage.form().login(homerUser);
|
||||
linkedAccountsPage.assertCurrent();
|
||||
assertProvider(systemIdp, true, false, homerUser.getUsername());
|
||||
|
||||
assertProvider(socialIdp, false, true, "");
|
||||
|
||||
// check through admin REST endpoints
|
||||
List<FederatedIdentityRepresentation> fids = testUserResource().getFederatedIdentity();
|
||||
assertEquals(1, fids.size());
|
||||
FederatedIdentityRepresentation fid = fids.get(0);
|
||||
assertEquals(SYSTEM_IDP_ALIAS, fid.getIdentityProvider());
|
||||
assertEquals(homerUser.getUsername(), fid.getUserName());
|
||||
|
||||
// logout user and try to login using IdP
|
||||
testUserResource().logout();
|
||||
linkedAccountsPage.navigateTo();
|
||||
loginPageWithSocialBtns.clickSocial(SYSTEM_IDP_ALIAS);
|
||||
linkedAccountsPage.assertCurrent(); // no need for re-login to REALM2
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unlinkAccountTest() {
|
||||
FederatedIdentityRepresentation fid = new FederatedIdentityRepresentation();
|
||||
fid.setIdentityProvider(SOCIAL_IDP_ALIAS);
|
||||
fid.setUserId("Homer lost his ID at Moe's last night");
|
||||
fid.setUserName(homerUser.getUsername());
|
||||
testUserResource().addFederatedIdentity(SOCIAL_IDP_ALIAS, fid);
|
||||
assertEquals(1, testUserResource().getFederatedIdentity().size());
|
||||
linkedAccountsPage.navigateTo();
|
||||
|
||||
assertProvider(systemIdp, false, false, "");
|
||||
assertProvider(socialIdp, true, true, homerUser.getUsername());
|
||||
|
||||
socialIdp.clickUnlinkBtn();
|
||||
linkedAccountsPage.assertCurrent();
|
||||
assertProvider(systemIdp, false, false, "");
|
||||
assertProvider(socialIdp, false, true, "");
|
||||
|
||||
assertEquals(0, testUserResource().getFederatedIdentity().size());
|
||||
}
|
||||
|
||||
private void assertProvider(
|
||||
LinkedAccountsPage.IdentityProvider provider,
|
||||
boolean expectLinked,
|
||||
boolean expectSocial,
|
||||
String expectedUsername
|
||||
) {
|
||||
if (expectLinked) {
|
||||
assertTrue("Account should be in the \"Linked\" list", provider.isLinked());
|
||||
assertTrue("Unlink button should be visible", provider.isUnlinkBtnVisible());
|
||||
assertFalse("Link button shouldn't be visible", provider.isLinkBtnVisible());
|
||||
}
|
||||
else {
|
||||
assertFalse("Account should be in the \"Unlinked\" list", provider.isLinked());
|
||||
assertFalse("Unlink button shouldn't be visible", provider.isUnlinkBtnVisible());
|
||||
assertTrue("Link button should be visible", provider.isLinkBtnVisible());
|
||||
}
|
||||
|
||||
if (expectSocial) {
|
||||
assertTrue("Social badge should be visible", provider.hasSocialLoginBadge());
|
||||
assertTrue("Social icon should be visible", provider.hasSocialIcon());
|
||||
assertFalse("Default icon shouldn't be visible", provider.hasDefaultIcon());
|
||||
}
|
||||
else {
|
||||
assertFalse("Social badge shouldn't be visible", provider.hasSocialLoginBadge());
|
||||
assertFalse("Social icon shouldn't be visible", provider.hasSocialIcon());
|
||||
assertTrue("Default icon should be visible", provider.hasDefaultIcon());
|
||||
}
|
||||
|
||||
assertEquals(expectedUsername, provider.getUsername());
|
||||
}
|
||||
|
||||
private void assertProvidersCount() {
|
||||
assertEquals(2,
|
||||
linkedAccountsPage.getLinkedProvidersCount() + linkedAccountsPage.getUnlinkedProvidersCount());
|
||||
}
|
||||
}
|
|
@ -1,316 +0,0 @@
|
|||
package org.keycloak.testsuite.ui.account3;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.junit.After;
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.Test;
|
||||
import org.junit.runners.MethodSorters;
|
||||
import org.keycloak.admin.client.resource.AuthorizationResource;
|
||||
import org.keycloak.admin.client.resource.ClientResource;
|
||||
import org.keycloak.admin.client.resource.ClientsResource;
|
||||
import org.keycloak.authorization.client.AuthzClient;
|
||||
import org.keycloak.authorization.client.Configuration;
|
||||
import org.keycloak.jose.jws.JWSInput;
|
||||
import org.keycloak.models.AccountRoles;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.PermissionTicketRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||
import org.keycloak.testsuite.ui.account3.page.AbstractLoggedInPage;
|
||||
import org.keycloak.testsuite.ui.account3.page.MyResourcesPage;
|
||||
import org.keycloak.testsuite.util.ClientBuilder;
|
||||
import org.keycloak.testsuite.util.UserBuilder;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
import org.openqa.selenium.NoSuchElementException;
|
||||
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.hamcrest.core.StringEndsWith.endsWith;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.keycloak.representations.idm.CredentialRepresentation.PASSWORD;
|
||||
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
|
||||
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
public class MyResourcesTest extends BaseAccountPageTest {
|
||||
private static final String[] userNames = new String[]{"alice", "jdoe"};
|
||||
|
||||
@Page
|
||||
private MyResourcesPage myResourcesPage;
|
||||
|
||||
private RealmRepresentation testRealm;
|
||||
private CloseableHttpClient httpClient;
|
||||
|
||||
@Override
|
||||
protected AbstractLoggedInPage getAccountPage() {
|
||||
return myResourcesPage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
||||
super.addTestRealms(testRealms);
|
||||
testRealm = testRealms.get(0);
|
||||
testRealm.setUserManagedAccessAllowed(true);
|
||||
|
||||
testRealm.setUsers(Lists.asList("admin", userNames).stream().map(this::createUser).collect(Collectors.toList()));
|
||||
|
||||
ClientRepresentation client = ClientBuilder.create()
|
||||
.clientId("my-resource-server")
|
||||
.authorizationServicesEnabled(true)
|
||||
.serviceAccountsEnabled(true)
|
||||
.secret("secret")
|
||||
.name("My Resource Server")
|
||||
.baseUrl("http://resourceserver.com")
|
||||
.directAccessGrants().build();
|
||||
|
||||
testRealm.setClients(singletonList(client));
|
||||
}
|
||||
|
||||
private UserRepresentation createUser(String userName) {
|
||||
return UserBuilder.create()
|
||||
.username(userName)
|
||||
.enabled(true)
|
||||
.password(PASSWORD)
|
||||
.role("account", AccountRoles.MANAGE_ACCOUNT)
|
||||
.build();
|
||||
}
|
||||
|
||||
@After
|
||||
public void after() {
|
||||
if (httpClient != null) {
|
||||
try {
|
||||
httpClient.close();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterAbstractKeycloakTestRealmImport() {
|
||||
ClientResource resourceServer = getResourceServer();
|
||||
AuthzClient authzClient = createAuthzClient(resourceServer.toRepresentation());
|
||||
AuthorizationResource authorization = resourceServer.authorization();
|
||||
ResourceRepresentation resource13 = null;
|
||||
for (int i = 1; i < 15; i++) {
|
||||
ResourceRepresentation resource = createResource(authzClient, authorization, i);
|
||||
if (i == 13) {
|
||||
resource13 = resource;
|
||||
}
|
||||
|
||||
for (String scope : Arrays.asList("Scope A", "Scope B")) {
|
||||
createTicket(authzClient, i, resource, scope, userNames[i % userNames.length]);
|
||||
}
|
||||
}
|
||||
|
||||
createTicket(authzClient, 13, resource13, "Scope A", "admin");
|
||||
}
|
||||
|
||||
private void createTicket(AuthzClient authzClient, int i, ResourceRepresentation resource, String scope, String userName) {
|
||||
PermissionTicketRepresentation ticket = new PermissionTicketRepresentation();
|
||||
|
||||
ticket.setGranted(!(i == 12 || i == 13));
|
||||
ticket.setOwner(resource.getOwner().getId());
|
||||
ticket.setRequesterName(userName);
|
||||
ticket.setResource(resource.getId());
|
||||
ticket.setScopeName(scope);
|
||||
|
||||
authzClient.protection("jdoe", PASSWORD).permission().create(ticket);
|
||||
}
|
||||
|
||||
private ResourceRepresentation createResource(AuthzClient authzClient, AuthorizationResource authorization, int i) {
|
||||
ResourceRepresentation resource = new ResourceRepresentation();
|
||||
|
||||
resource.setOwnerManagedAccess(true);
|
||||
|
||||
try {
|
||||
final byte[] content = new JWSInput(authzClient.obtainAccessToken("jdoe", PASSWORD).getToken()).getContent();
|
||||
final AccessToken accessToken = JsonSerialization.readValue(content, AccessToken.class);
|
||||
resource.setOwner(accessToken.getSubject());
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
resource.setName("Resource " + i);
|
||||
resource.setDisplayName("Display Name " + i);
|
||||
resource.setIconUri("Icon Uri " + i);
|
||||
resource.addScope("Scope A", "Scope B", "Scope C", "Scope D");
|
||||
resource.setUri("http://resourceServer.com/resources/" + i);
|
||||
|
||||
try (Response response1 = authorization.resources().create(resource)) {
|
||||
resource.setId(response1.readEntity(ResourceRepresentation.class).getId());
|
||||
}
|
||||
return resource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTestUser() {
|
||||
testUser = createUser("jdoe");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDisplayTheResources() {
|
||||
assertEquals(6, myResourcesPage.getResourcesListCount());
|
||||
|
||||
assertEquals("Resource 0", myResourcesPage.getCellText("name", 0));
|
||||
assertEquals("Resource 1", myResourcesPage.getCellText("name", 1));
|
||||
assertEquals("My Resource Server", myResourcesPage.getCellText("client", 0));
|
||||
assertEquals("http://resourceserver.com/", myResourcesPage.getCellHref("client", 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldShowMyResourcesAndUpdatePermissions() {
|
||||
final int row = 1;
|
||||
myResourcesPage.clickExpandButton(row);
|
||||
myResourcesPage.clickCollapseButton(row);
|
||||
myResourcesPage.clickExpandButton(row);
|
||||
|
||||
assertEquals("Resource is shared with jdoe.", myResourcesPage.getSharedWith(row));
|
||||
|
||||
myResourcesPage.clickEditButton(row);
|
||||
assertEquals("jdoe", myResourcesPage.getEditDialogUsername(0));
|
||||
myResourcesPage.removeAllPermissions();
|
||||
|
||||
myResourcesPage.alert().assertSuccess();
|
||||
assertEquals("This resource is not shared.", myResourcesPage.getSharedWith(row));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldShowMyResourcesAndRemoveShares() {
|
||||
final int row = 2;
|
||||
myResourcesPage.clickExpandButton(row);
|
||||
|
||||
testModalDialog(() -> myResourcesPage.clickRemoveButton(row), () ->
|
||||
assertEquals("Resource is shared with alice.", myResourcesPage.getSharedWith(row)));
|
||||
|
||||
myResourcesPage.alert().assertSuccess();
|
||||
assertEquals("This resource is not shared.", myResourcesPage.getSharedWith(row));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldShowMyResourcesAndShare() {
|
||||
final int row = 3;
|
||||
myResourcesPage.clickExpandButton(row);
|
||||
|
||||
assertEquals("Resource is shared with jdoe.", myResourcesPage.getSharedWith(row));
|
||||
|
||||
myResourcesPage.clickShareButton(row);
|
||||
myResourcesPage.createShare("alice");
|
||||
|
||||
myResourcesPage.alert().assertSuccess();
|
||||
assertThat(myResourcesPage.getSharedWith(row), endsWith("and 1 other users."));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void firstShouldRefreshOnRefreshButtonClick() {
|
||||
ClientResource resourceServer = getResourceServer();
|
||||
AuthzClient authzClient = createAuthzClient(resourceServer.toRepresentation());
|
||||
AuthorizationResource authorization = resourceServer.authorization();
|
||||
|
||||
createResource(authzClient, authorization, 0);
|
||||
|
||||
assertEquals("Resource 1", myResourcesPage.getCellText("name", 0));
|
||||
myResourcesPage.clickRefreshButton();
|
||||
assertEquals("Resource 0", myResourcesPage.getCellText("name", 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldAllowRequestToShare() {
|
||||
final String resourceName = "Resource 12";
|
||||
assertEquals("1", myResourcesPage.getPendingRequestText(resourceName));
|
||||
|
||||
switchUserSharedWithMeTab();
|
||||
assertFalse(myResourcesPage.containsResource(resourceName));
|
||||
login("jdoe");
|
||||
|
||||
myResourcesPage.clickPendingRequest(resourceName);
|
||||
assertEquals("alice", myResourcesPage.getPendingRequestRequestor(0));
|
||||
final String permissions = myResourcesPage.getPendingRequestPermissions(0);
|
||||
assertTrue(permissions.contains("Scope A"));
|
||||
assertTrue(permissions.contains("Scope B"));
|
||||
myResourcesPage.acceptRequest(resourceName, 0);
|
||||
|
||||
assertNoPendingRequest(resourceName);
|
||||
switchUserSharedWithMeTab();
|
||||
|
||||
assertTrue(myResourcesPage.containsResource(resourceName));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDenyRequestToShare() {
|
||||
final String resourceName = "Resource 13";
|
||||
|
||||
switchUserSharedWithMeTab();
|
||||
assertFalse(myResourcesPage.containsResource(resourceName));
|
||||
login("jdoe");
|
||||
|
||||
myResourcesPage.clickNextPage();
|
||||
assertEquals("2", myResourcesPage.getPendingRequestText(resourceName));
|
||||
myResourcesPage.clickPendingRequest(resourceName);
|
||||
myResourcesPage.denyRequest(resourceName, 0);
|
||||
|
||||
assertEquals("1", myResourcesPage.getPendingRequestText(resourceName));
|
||||
|
||||
switchUserSharedWithMeTab();
|
||||
assertFalse(myResourcesPage.containsResource(resourceName));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotHaveRequestToShareButton() {
|
||||
assertNoPendingRequest("Resource 0");
|
||||
assertNoPendingRequest("Resource 1");
|
||||
}
|
||||
|
||||
private void assertNoPendingRequest(String resourceName) {
|
||||
try {
|
||||
myResourcesPage.getPendingRequestText(resourceName);
|
||||
fail("should not have a pending request button");
|
||||
} catch (NoSuchElementException e) {
|
||||
// success
|
||||
}
|
||||
}
|
||||
|
||||
private void switchUserSharedWithMeTab() {
|
||||
login("alice");
|
||||
myResourcesPage.clickSharedWithMeTab();
|
||||
}
|
||||
|
||||
private void login(String user) {
|
||||
myResourcesPage.clickSignOut();
|
||||
myResourcesPage.navigateTo();
|
||||
loginPage.form().login(createUser(user));
|
||||
}
|
||||
|
||||
private AuthzClient createAuthzClient(ClientRepresentation client) {
|
||||
Map<String, Object> credentials = new HashMap<>();
|
||||
|
||||
credentials.put("secret", "secret");
|
||||
httpClient = HttpClientBuilder.create().build();
|
||||
|
||||
return AuthzClient
|
||||
.create(new Configuration(suiteContext.getAuthServerInfo().getContextRoot().toString() + "/auth",
|
||||
testRealm.getRealm(), client.getClientId(),
|
||||
credentials, httpClient));
|
||||
}
|
||||
|
||||
private ClientResource getResourceServer() {
|
||||
ClientsResource clients = adminClient.realm(TEST).clients();
|
||||
return clients.get(clients.findByClientId("my-resource-server").get(0).getId());
|
||||
}
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 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.ui.account3;
|
||||
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.resource.RoleScopeResource;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
import org.keycloak.testsuite.ui.account3.page.ForbiddenPage;
|
||||
import org.keycloak.testsuite.ui.account3.page.PersonalInfoPage;
|
||||
import org.keycloak.testsuite.ui.account3.page.SigningInPage;
|
||||
import org.keycloak.testsuite.ui.account3.page.WelcomeScreen;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.keycloak.models.Constants.ACCOUNT_MANAGEMENT_CLIENT_ID;
|
||||
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
|
||||
|
||||
/**
|
||||
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||
*/
|
||||
public class PermissionsTest extends AbstractAccountTest {
|
||||
@Page
|
||||
private WelcomeScreen welcomeScreen;
|
||||
|
||||
@Page
|
||||
private PersonalInfoPage personalInfoPage;
|
||||
|
||||
@Page
|
||||
private SigningInPage signingInPage;
|
||||
|
||||
@Page
|
||||
private ForbiddenPage forbiddenPage;
|
||||
|
||||
private static final String DEFAULT_ROLE_NAME = "default-roles-" + TEST;
|
||||
|
||||
@Test
|
||||
public void manageAccountRoleRequired() throws Exception {
|
||||
// remove realm level roles (no "default-roles-test") and any roles in the account client
|
||||
testUserResource().roles().realmLevel().remove(testUserResource().roles().realmLevel().listAll());
|
||||
String accountClientId = testRealmResource().clients().findByClientId(ACCOUNT_MANAGEMENT_CLIENT_ID).get(0).getId();
|
||||
RoleScopeResource roleScopes = testUserResource().roles().clientLevel(accountClientId);
|
||||
List<RoleRepresentation> roles = roleScopes.listAll();
|
||||
if (!roles.isEmpty()) {
|
||||
roleScopes.remove(roles);
|
||||
}
|
||||
|
||||
welcomeScreen.header().clickLoginBtn();
|
||||
loginToAccount();
|
||||
welcomeScreen.assertCurrent(); // no forbidden at welcome screen yet
|
||||
|
||||
welcomeScreen.clickPersonalInfoLink();
|
||||
forbiddenPage.assertCurrent();
|
||||
|
||||
signingInPage.navigateToUsingSidebar();
|
||||
forbiddenPage.assertCurrent();
|
||||
|
||||
// still possible to sign out
|
||||
forbiddenPage.header().clickLogoutBtn();
|
||||
welcomeScreen.assertCurrent();
|
||||
welcomeScreen.header().assertLoginBtnVisible(true);
|
||||
welcomeScreen.header().assertLogoutBtnVisible(false);
|
||||
}
|
||||
}
|
|
@ -1,277 +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.ui.account3;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.keycloak.testsuite.admin.Users.setPasswordFor;
|
||||
import static org.keycloak.testsuite.util.UIUtils.refreshPageAndWaitForLoad;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.testsuite.admin.ApiUtil;
|
||||
import org.keycloak.testsuite.forms.VerifyProfileTest;
|
||||
import org.keycloak.testsuite.ui.account3.page.AbstractLoggedInPage;
|
||||
import org.keycloak.testsuite.ui.account3.page.PersonalInfoPage;
|
||||
import org.keycloak.testsuite.util.UserBuilder;
|
||||
|
||||
/**
|
||||
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||
*/
|
||||
public class PersonalInfoTest extends BaseAccountPageTest {
|
||||
@Page
|
||||
private PersonalInfoPage personalInfoPage;
|
||||
|
||||
private UserRepresentation testUser2;
|
||||
|
||||
@Before
|
||||
public void setTestUser() {
|
||||
testUser2 = new UserRepresentation();
|
||||
testUser2.setUsername("vmuzikar");
|
||||
testUser2.setEmail("vmuzikar@redhat.com");
|
||||
testUser2.setFirstName("Václav");
|
||||
testUser2.setLastName("Muzikář");
|
||||
ApiUtil.removeUserByUsername(testRealmResource(), testUser2.getUsername());
|
||||
|
||||
VerifyProfileTest.enableUnmanagedAttributes(testRealmResource().users().userProfile());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractLoggedInPage getAccountPage() {
|
||||
return personalInfoPage;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateUserInfo() {
|
||||
setEditUsernameAllowed(true);
|
||||
|
||||
assertTrue(personalInfoPage.valuesEqual(testUser));
|
||||
personalInfoPage.assertUsernameDisabled(false);
|
||||
personalInfoPage.assertSaveDisabled(false);
|
||||
|
||||
personalInfoPage.setValues(testUser2, true);
|
||||
//assertEquals("test user", personalInfoPage.header().getToolbarLoggedInUser());
|
||||
assertTrue(personalInfoPage.valuesEqual(testUser2));
|
||||
personalInfoPage.assertSaveDisabled(false);
|
||||
personalInfoPage.clickSave();
|
||||
personalInfoPage.alert().assertSuccess();
|
||||
personalInfoPage.assertSaveDisabled(false);
|
||||
|
||||
personalInfoPage.navigateTo();
|
||||
personalInfoPage.valuesEqual(testUser2);
|
||||
//assertEquals("Václav Muzikář", personalInfoPage.header().getToolbarLoggedInUser());
|
||||
|
||||
// change just first and last name
|
||||
testUser2.setFirstName("Another");
|
||||
testUser2.setLastName("Name");
|
||||
personalInfoPage.setValues(testUser2, true);
|
||||
personalInfoPage.clickSave();
|
||||
personalInfoPage.alert().assertSuccess();
|
||||
personalInfoPage.navigateTo();
|
||||
personalInfoPage.valuesEqual(testUser2);
|
||||
//assertEquals("Another Name", personalInfoPage.header().getToolbarLoggedInUser());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void formValidationTest() {
|
||||
setEditUsernameAllowed(true);
|
||||
|
||||
// clear username
|
||||
personalInfoPage.setUsername("");
|
||||
personalInfoPage.assertSaveDisabled(true);
|
||||
personalInfoPage.assertUsernameValid(false);
|
||||
personalInfoPage.setUsername("hsimpson");
|
||||
personalInfoPage.assertUsernameValid(true);
|
||||
|
||||
// clear email
|
||||
personalInfoPage.setEmail("edewit@");
|
||||
personalInfoPage.assertEmailValid(false);
|
||||
personalInfoPage.setEmail("");
|
||||
personalInfoPage.assertEmailValid(false);
|
||||
personalInfoPage.setEmail("hsimpson@springfield.com");
|
||||
personalInfoPage.assertEmailValid(true);
|
||||
|
||||
// clear first name
|
||||
personalInfoPage.setFirstName("");
|
||||
personalInfoPage.assertFirstNameValid(false);
|
||||
personalInfoPage.setFirstName("Homer");
|
||||
personalInfoPage.assertFirstNameValid(true);
|
||||
|
||||
// clear last name
|
||||
personalInfoPage.setLastName("");
|
||||
personalInfoPage.assertLastNameValid(false);
|
||||
personalInfoPage.setLastName("Simpson");
|
||||
personalInfoPage.assertLastNameValid(true);
|
||||
|
||||
// duplicity tests
|
||||
ApiUtil.createUserWithAdminClient(testRealmResource(), testUser2);
|
||||
// duplicate username
|
||||
personalInfoPage.setUsername(testUser2.getUsername());
|
||||
personalInfoPage.clickSave();
|
||||
personalInfoPage.alert().assertDanger();
|
||||
// TODO assert actual error message and that the field is marked as invalid (KEYCLOAK-12102)
|
||||
personalInfoPage.setUsername(testUser.getUsername());
|
||||
// duplicate email
|
||||
personalInfoPage.setEmail(testUser2.getEmail());
|
||||
personalInfoPage.clickSave();
|
||||
personalInfoPage.alert().assertDanger();
|
||||
// TODO assert actual error message and that the field is marked as invalid (KEYCLOAK-12102)
|
||||
// check no changes were saved
|
||||
personalInfoPage.navigateTo();
|
||||
personalInfoPage.valuesEqual(testUser);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cancelForm() {
|
||||
setEditUsernameAllowed(false);
|
||||
|
||||
personalInfoPage.setValues(testUser2, false);
|
||||
personalInfoPage.setEmail("hsimpson@springfield.com");
|
||||
personalInfoPage.clickCancel();
|
||||
personalInfoPage.valuesEqual(testUser2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disabledEditUsername() {
|
||||
setEditUsernameAllowed(false);
|
||||
|
||||
personalInfoPage.assertUsernameDisabled(true);
|
||||
personalInfoPage.setValues(testUser2, false);
|
||||
personalInfoPage.clickSave();
|
||||
personalInfoPage.alert().assertSuccess();
|
||||
|
||||
testUser2.setUsername(testUser.getUsername()); // the username should remain the same
|
||||
personalInfoPage.navigateTo();
|
||||
personalInfoPage.valuesEqual(testUser2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clickLogoTest() {
|
||||
personalInfoPage.clickBrandLink();
|
||||
accountWelcomeScreen.assertCurrent();
|
||||
}
|
||||
|
||||
@Ignore("Username is not included in the account console anymore, but it should be there.")
|
||||
@Test
|
||||
public void testNameInToolbar() {
|
||||
assertEquals("test user", personalInfoPage.header().getToolbarLoggedInUser());
|
||||
|
||||
UserRepresentation user = new UserRepresentation();
|
||||
user.setUsername("edewit");
|
||||
user.setEnabled(true);
|
||||
setPasswordFor(user, "password");
|
||||
try {
|
||||
ApiUtil.removeUserByUsername(testRealmResource(), testUser.getUsername());
|
||||
personalInfoPage.navigateTo();
|
||||
ApiUtil.createUserWithAdminClient(testRealmResource(), user);
|
||||
loginPage.form().login(user);
|
||||
|
||||
assertEquals("edewit", personalInfoPage.header().getToolbarLoggedInUser());
|
||||
} finally {
|
||||
ApiUtil.removeUserByUsername(testRealmResource(), user.getUsername());
|
||||
}
|
||||
}
|
||||
|
||||
private void setEditUsernameAllowed(boolean value) {
|
||||
RealmRepresentation realm = testRealmResource().toRepresentation();
|
||||
realm.setEditUsernameAllowed(value);
|
||||
testRealmResource().update(realm);
|
||||
refreshPageAndWaitForLoad();
|
||||
}
|
||||
|
||||
private void addUser(String username, String email) {
|
||||
UserRepresentation user = UserBuilder.create()
|
||||
.username(username)
|
||||
.enabled(true)
|
||||
.email(email)
|
||||
.firstName("first")
|
||||
.lastName("last")
|
||||
.build();
|
||||
RealmResource testRealm = adminClient.realm("test");
|
||||
ApiUtil.createUserAndResetPasswordWithAdminClient(testRealm, user, "password");
|
||||
}
|
||||
|
||||
// KEYCLOAK-15634
|
||||
@Test
|
||||
public void updateProfileWithAttributePresent() {
|
||||
|
||||
RealmResource testRealm = adminClient.realm("test");
|
||||
assertEquals(getAccountThemeName(), testRealm.toRepresentation().getAccountTheme());
|
||||
|
||||
// Add a user and set a test attribute
|
||||
addUser("keycloak-15634","keycloak-15634@test.local");
|
||||
UserRepresentation userRepBefore = ApiUtil.findUserByUsername(testRealm,"keycloak-15634");
|
||||
Map<String, List<String>> userAttributes = new HashMap<>();
|
||||
userAttributes.put("testAttribute", Collections.singletonList("testValue"));
|
||||
userRepBefore.setAttributes(userAttributes);
|
||||
testRealm.users().get(userRepBefore.getId()).update(userRepBefore);
|
||||
|
||||
// Check our test user is ok before updating profile with account v2
|
||||
UserRepresentation updatedUserRep = ApiUtil.findUserByUsername(testRealm,"keycloak-15634");
|
||||
assertEquals("keycloak-15634@test.local", updatedUserRep.getEmail());
|
||||
assertEquals("testAttribute should be set", "testValue", updatedUserRep.getAttributes().get("testAttribute").get(0));
|
||||
assertFalse("locale attribute should not be set", updatedUserRep.getAttributes().containsKey("locale"));
|
||||
|
||||
personalInfoPage.assertCurrent();
|
||||
personalInfoPage.header().clickLogoutBtn();
|
||||
personalInfoPage.navigateTo();
|
||||
loginPage.assertCurrent();
|
||||
loginPage.form().login("keycloak-15634","password");
|
||||
personalInfoPage.assertCurrent();
|
||||
|
||||
// Trigger the JS involved in KEYCLOAK-15634
|
||||
assertEquals("keycloak-15634@test.local", personalInfoPage.getEmail());
|
||||
personalInfoPage.setEmail("keycloak-15634@domain.local");
|
||||
personalInfoPage.clickSave();
|
||||
|
||||
// Check if updateProfile went well and if testAttribute is still there
|
||||
UserRepresentation userRepAfter = ApiUtil.findUserByUsername(testRealm,"keycloak-15634");
|
||||
assertEquals("keycloak-15634@domain.local", userRepAfter.getEmail());
|
||||
assertEquals("testAttribute should still be there","testValue", userRepAfter.getAttributes().get("testAttribute").get(0));
|
||||
|
||||
ApiUtil.removeUserByUsername(testRealm, "keycloak-15634");
|
||||
}
|
||||
|
||||
@Test
|
||||
// https://issues.redhat.com/browse/KEYCLOAK-16890
|
||||
// Stored personal info triggers attack via the display of user name in header.
|
||||
// If user name is left unsanitized, this test will fail with
|
||||
// org.openqa.selenium.UnhandledAlertException: unexpected alert open: {Alert text : XSS}
|
||||
public void storedXSSAttack() {
|
||||
personalInfoPage.navigateTo();
|
||||
testUser.setFirstName("<img src=x onerror=\"alert('XSS');\">");
|
||||
personalInfoPage.setValues(testUser, false);
|
||||
personalInfoPage.clickSave();
|
||||
|
||||
personalInfoPage.header().clickLogoutBtn();
|
||||
accountWelcomeScreen.header().clickLoginBtn();
|
||||
loginPage.form().login(testUser);
|
||||
personalInfoPage.navigateTo();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,192 +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.ui.account3;
|
||||
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.testsuite.ui.account3.page.PersonalInfoPage;
|
||||
import org.keycloak.testsuite.ui.account3.page.WelcomeScreen;
|
||||
import org.keycloak.testsuite.ui.account3.page.fragment.AbstractHeader;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlEquals;
|
||||
|
||||
/**
|
||||
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||
*/
|
||||
public class ReferrerTest extends AbstractAccountTest {
|
||||
public static final String FAKE_CLIENT_ID = "fake-client-name";
|
||||
public static final String REFERRER_LINK_TEXT = "Back to " + LOCALE_CLIENT_NAME_LOCALIZED;
|
||||
public static final String FAKE_CLIENT_URL_CONTEXT = "auth/non-existing-page/";
|
||||
public static final String FAKE_CLIENT_URL_FRAGMENT = "?foo=bar&bar=foo#anchor";
|
||||
|
||||
@Page
|
||||
private WelcomeScreen welcomeScreen;
|
||||
|
||||
@Page
|
||||
private PersonalInfoPage personalInfoPage;
|
||||
|
||||
@Override
|
||||
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
||||
super.addTestRealms(testRealms);
|
||||
RealmRepresentation testRealm = testRealms.get(0);
|
||||
|
||||
ClientRepresentation testClient = new ClientRepresentation();
|
||||
testClient.setClientId(FAKE_CLIENT_ID);
|
||||
testClient.setName(LOCALE_CLIENT_NAME);
|
||||
|
||||
// Redirect URIs are no longer allowed to contain a fragment, so we
|
||||
// need the wildcard in order to use fragments in tests
|
||||
testClient.setRedirectUris(Collections.singletonList(getFakeClientUrl("*")));
|
||||
|
||||
testClient.setEnabled(true);
|
||||
|
||||
ClientRepresentation rootUrlClient = new ClientRepresentation();
|
||||
rootUrlClient.setClientId("test-client-with-root-url");
|
||||
rootUrlClient.setRootUrl(getFakeClientUrl("foo"));
|
||||
rootUrlClient.setBaseUrl("/bar");
|
||||
testClient.setRedirectUris(Collections.singletonList(getFakeClientUrl("*")));
|
||||
rootUrlClient.setEnabled(true);
|
||||
|
||||
testRealm.setClients(Arrays.asList(testClient, rootUrlClient));
|
||||
testRealm.setAccountTheme(LOCALIZED_THEME_PREVIEW); // using localized custom theme for the fake client localized name
|
||||
}
|
||||
|
||||
@Test
|
||||
// https://issues.redhat.com/browse/KEYCLOAK-17033
|
||||
// If the referrer is unescaped, this test will throw an exception.
|
||||
// org.openqa.selenium.UnhandledAlertException: unexpected alert open: {Alert text : XSS}
|
||||
public void reflectedXSSTest() {
|
||||
String attackUrl = getFakeClientUrl("'+alert('XSS')+'");
|
||||
welcomeScreen.navigateTo(FAKE_CLIENT_ID, attackUrl);
|
||||
|
||||
welcomeScreen.header().clickLoginBtn();
|
||||
loginToAccount();
|
||||
welcomeScreen.clickPersonalInfoLink();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loggedInWelcomeScreenTest() {
|
||||
welcomeScreen.header().clickLoginBtn();
|
||||
loginToAccount();
|
||||
|
||||
welcomeScreen.navigateTo(FAKE_CLIENT_ID, getFakeClientUrl(FAKE_CLIENT_URL_FRAGMENT));
|
||||
welcomeScreen.header().assertLoginBtnVisible(false);
|
||||
welcomeScreen.header().assertLogoutBtnVisible(true);
|
||||
|
||||
testReferrer(welcomeScreen.header(), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loggedOutWelcomeScreenTest() {
|
||||
welcomeScreen.navigateTo(FAKE_CLIENT_ID, getFakeClientUrl(FAKE_CLIENT_URL_FRAGMENT));
|
||||
welcomeScreen.header().assertLoginBtnVisible(true);
|
||||
welcomeScreen.header().assertLogoutBtnVisible(false);
|
||||
|
||||
testReferrer(welcomeScreen.header(), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loggedInPageTest() {
|
||||
welcomeScreen.header().clickLoginBtn();
|
||||
loginToAccount();
|
||||
|
||||
welcomeScreen.navigateTo(FAKE_CLIENT_ID, getFakeClientUrl(FAKE_CLIENT_URL_FRAGMENT));
|
||||
welcomeScreen.clickPersonalInfoLink();
|
||||
|
||||
testReferrer(personalInfoPage.header(), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loggedOutPageTest() {
|
||||
welcomeScreen.navigateTo(FAKE_CLIENT_ID, getFakeClientUrl(FAKE_CLIENT_URL_FRAGMENT));
|
||||
welcomeScreen.clickPersonalInfoLink();
|
||||
loginToAccount();
|
||||
|
||||
testReferrer(personalInfoPage.header(), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void badClientNameTest() {
|
||||
welcomeScreen.navigateTo(FAKE_CLIENT_ID + "-bad", getFakeClientUrl(FAKE_CLIENT_URL_FRAGMENT));
|
||||
testReferrer(welcomeScreen.header(), false);
|
||||
|
||||
welcomeScreen.navigateTo(FAKE_CLIENT_ID + "-bad", getFakeClientUrl(FAKE_CLIENT_URL_FRAGMENT));
|
||||
welcomeScreen.clickPersonalInfoLink();
|
||||
loginToAccount();
|
||||
testReferrer(personalInfoPage.header(), false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void badClientUriTest() {
|
||||
welcomeScreen.navigateTo(FAKE_CLIENT_ID, getFakeClientUrlWithBadContext());
|
||||
testReferrer(welcomeScreen.header(), false);
|
||||
|
||||
welcomeScreen.navigateTo(FAKE_CLIENT_ID, getFakeClientUrlWithBadContext());
|
||||
welcomeScreen.clickPersonalInfoLink();
|
||||
loginToAccount();
|
||||
testReferrer(personalInfoPage.header(), false);
|
||||
}
|
||||
|
||||
// Issue 16484
|
||||
@Test
|
||||
public void loggedInWithoutProvidedReferrerUrl() {
|
||||
welcomeScreen.header().clickLoginBtn();
|
||||
loginToAccount();
|
||||
|
||||
welcomeScreen.navigateTo("test-client-with-root-url", null);
|
||||
welcomeScreen.header().assertLoginBtnVisible(false);
|
||||
welcomeScreen.header().assertLogoutBtnVisible(true);
|
||||
|
||||
// referrer_uri parameter was not provided. So it should be set by Keycloak based on the client rootUrl and baseUrl
|
||||
assertEquals("Back to test-client-with-root-url", welcomeScreen.header().getReferrerLinkText());
|
||||
welcomeScreen.header().clickReferrerLink();
|
||||
assertCurrentUrlEquals(getFakeClientUrl("foo/bar"));
|
||||
}
|
||||
|
||||
private void testReferrer(AbstractHeader header, boolean expectReferrerVisible) {
|
||||
if (expectReferrerVisible) {
|
||||
assertEquals(REFERRER_LINK_TEXT, header.getReferrerLinkText());
|
||||
header.clickReferrerLink();
|
||||
assertCurrentUrlEquals(getFakeClientUrl(FAKE_CLIENT_URL_FRAGMENT));
|
||||
}
|
||||
else {
|
||||
header.assertReferrerLinkVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
private String getFakeClientUrl(String suffix) {
|
||||
// we need to use some page which host exists – Firefox is throwing exceptions like crazy if we try to load
|
||||
// a page on a non-existing host, like e.g. http://non-existing-server/
|
||||
// also we need to do this here as getAuthServerRoot is not ready when firing this class' constructor
|
||||
return getAuthServerRoot() + FAKE_CLIENT_URL_CONTEXT + suffix;
|
||||
}
|
||||
|
||||
private String getFakeClientUrlWithBadContext() {
|
||||
// we need to use some page which host exists – Firefox is throwing exceptions like crazy if we try to load
|
||||
// a page on a non-existing host, like e.g. http://non-existing-server/
|
||||
// also we need to do this here as getAuthServerRoot is not ready when firing this class' constructor
|
||||
return getAuthServerRoot() + "bad/" + FAKE_CLIENT_URL_CONTEXT;
|
||||
}
|
||||
}
|
|
@ -1,110 +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.ui.account3;
|
||||
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.testsuite.ui.account3.page.DeviceActivityPage;
|
||||
import org.keycloak.testsuite.ui.account3.page.PersonalInfoPage;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.keycloak.testsuite.util.UIUtils.refreshPageAndWaitForLoad;
|
||||
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWithLoginUrlOf;
|
||||
import static org.keycloak.testsuite.util.WaitUtils.pause;
|
||||
|
||||
/**
|
||||
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||
*/
|
||||
public class SessionTest extends AbstractAccountTest {
|
||||
public static final int SSO_SESSION_IDLE_TIMEOUT = 10;
|
||||
public static final int ACCESS_TOKEN_LIFESPAN = 10;
|
||||
|
||||
@Page
|
||||
private PersonalInfoPage personalInfoPage;
|
||||
|
||||
@Page
|
||||
private DeviceActivityPage deviceActivityPage;
|
||||
|
||||
@Override
|
||||
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
||||
super.addTestRealms(testRealms);
|
||||
RealmRepresentation realm = testRealms.get(0);
|
||||
|
||||
// in seconds
|
||||
realm.setSsoSessionIdleTimeout(SSO_SESSION_IDLE_TIMEOUT);
|
||||
realm.setAccessTokenLifespan(ACCESS_TOKEN_LIFESPAN);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeSessionTest() {
|
||||
personalInfoPage.navigateTo();
|
||||
loginToAccount();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void reactPageSsoTimeoutTest() {
|
||||
deviceActivityPage.navigateToUsingSidebar();
|
||||
deviceActivityPage.assertCurrent();
|
||||
personalInfoPage.navigateToUsingSidebar();
|
||||
personalInfoPage.assertCurrent();
|
||||
|
||||
waitForSessionToExpire();
|
||||
deviceActivityPage.navigateToUsingSidebar();
|
||||
assertCurrentUrlStartsWithLoginUrlOf(accountWelcomeScreen);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void reactPageAsyncLogoutTest() {
|
||||
testRealmResource().logoutAll();
|
||||
deviceActivityPage.navigateToUsingSidebar();
|
||||
assertCurrentUrlStartsWithLoginUrlOf(accountWelcomeScreen);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void welcomeScreenSsoTimeoutTest() {
|
||||
accountWelcomeScreen.navigateTo();
|
||||
accountWelcomeScreen.header().assertLoginBtnVisible(false);
|
||||
accountWelcomeScreen.header().assertLogoutBtnVisible(true);
|
||||
|
||||
waitForSessionToExpire();
|
||||
refreshPageAndWaitForLoad();
|
||||
accountWelcomeScreen.header().assertLoginBtnVisible(true);
|
||||
accountWelcomeScreen.header().assertLogoutBtnVisible(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void welcomeScreenAsyncLogoutTest() {
|
||||
accountWelcomeScreen.navigateTo();
|
||||
accountWelcomeScreen.header().assertLoginBtnVisible(false);
|
||||
accountWelcomeScreen.header().assertLogoutBtnVisible(true);
|
||||
|
||||
testRealmResource().logoutAll();
|
||||
refreshPageAndWaitForLoad();
|
||||
accountWelcomeScreen.header().assertLoginBtnVisible(true);
|
||||
accountWelcomeScreen.header().assertLogoutBtnVisible(false);
|
||||
}
|
||||
|
||||
private void waitForSessionToExpire() {
|
||||
// +3 to add some toleration
|
||||
log.info("Waiting for SSO session to expire");
|
||||
pause((SSO_SESSION_IDLE_TIMEOUT + 3) * 1000);
|
||||
}
|
||||
}
|
|
@ -1,219 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 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.ui.account3;
|
||||
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.models.credential.OTPCredentialModel;
|
||||
import org.keycloak.models.credential.PasswordCredentialModel;
|
||||
import org.keycloak.models.utils.Base32;
|
||||
import org.keycloak.models.utils.TimeBasedOTP;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.RequiredActionProviderRepresentation;
|
||||
import org.keycloak.testsuite.admin.Users;
|
||||
import org.keycloak.testsuite.auth.page.login.OTPSetup;
|
||||
import org.keycloak.testsuite.auth.page.login.UpdatePassword;
|
||||
import org.keycloak.testsuite.ui.account3.page.AbstractLoggedInPage;
|
||||
import org.keycloak.testsuite.ui.account3.page.SigningInPage;
|
||||
import org.keycloak.testsuite.ui.account3.page.utils.SigningInPageUtils;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.keycloak.models.UserModel.RequiredAction.CONFIGURE_TOTP;
|
||||
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
|
||||
import static org.keycloak.testsuite.ui.account3.page.utils.SigningInPageUtils.assertUserCredential;
|
||||
import static org.keycloak.testsuite.ui.account3.page.utils.SigningInPageUtils.testSetUpLink;
|
||||
import static org.keycloak.testsuite.util.UIUtils.refreshPageAndWaitForLoad;
|
||||
import static org.keycloak.testsuite.util.WaitUtils.pause;
|
||||
|
||||
/**
|
||||
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||
*/
|
||||
public class SigningInTest extends BaseAccountPageTest {
|
||||
public static final String PASSWORD_LABEL = "My password";
|
||||
|
||||
@Page
|
||||
private SigningInPage signingInPage;
|
||||
|
||||
@Page
|
||||
private UpdatePassword updatePasswordPage;
|
||||
|
||||
@Page
|
||||
private OTPSetup otpSetupPage;
|
||||
|
||||
private SigningInPage.CredentialType passwordCredentialType;
|
||||
private SigningInPage.CredentialType otpCredentialType;
|
||||
private TimeBasedOTP otpGenerator;
|
||||
|
||||
@Override
|
||||
protected AbstractLoggedInPage getAccountPage() {
|
||||
return signingInPage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultPageUriParameters() {
|
||||
super.setDefaultPageUriParameters();
|
||||
updatePasswordPage.setAuthRealm(TEST);
|
||||
otpSetupPage.setAuthRealm(TEST);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeSigningInTest() {
|
||||
passwordCredentialType = signingInPage.getCredentialType(PasswordCredentialModel.TYPE);
|
||||
otpCredentialType = signingInPage.getCredentialType(OTPCredentialModel.TYPE);
|
||||
|
||||
RealmRepresentation realm = testRealmResource().toRepresentation();
|
||||
otpGenerator = new TimeBasedOTP(realm.getOtpPolicyAlgorithm(), realm.getOtpPolicyDigits(), realm.getOtpPolicyPeriod(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void categoriesTest() {
|
||||
testContext.setTestRealmReps(emptyList()); // reimport realm after this test
|
||||
|
||||
assertThat(signingInPage.getCategoriesCount(), is(2));
|
||||
assertThat(signingInPage.getCategoryTitle("basic-authentication"), is("Basic authentication"));
|
||||
assertThat(signingInPage.getCategoryTitle("two-factor"), is("Two-factor authentication"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updatePasswordTest() {
|
||||
SigningInPage.UserCredential passwordCred = passwordCredentialType.getUserCredential(
|
||||
testUserResource()
|
||||
.credentials()
|
||||
.get(0)
|
||||
.getId()
|
||||
);
|
||||
|
||||
assertThat(passwordCredentialType.isSetUpLinkVisible(), is(false));
|
||||
assertThat(passwordCredentialType.isSetUp(), is(true));
|
||||
assertUserCredential(PASSWORD_LABEL, false, passwordCred);
|
||||
|
||||
LocalDateTime previousCreatedAt = passwordCred.getCreatedAt();
|
||||
log.info("Waiting one minute to ensure createdAt will change");
|
||||
pause(60000);
|
||||
|
||||
final String newPwd = "Keycloak is the best!";
|
||||
passwordCred.clickUpdateBtn();
|
||||
updatePasswordPage.assertCurrent();
|
||||
updatePasswordPage.updatePasswords(newPwd, newPwd);
|
||||
signingInPage.assertCurrent();
|
||||
|
||||
assertUserCredential(PASSWORD_LABEL, false, passwordCred);
|
||||
assertThat(passwordCred.getCreatedAt(), is(not(previousCreatedAt)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updatePasswordTestForUserWithoutPassword() {
|
||||
// Remove password from the user through admin REST API
|
||||
String passwordId = testUserResource().credentials().get(0).getId();
|
||||
testUserResource().removeCredential(passwordId);
|
||||
|
||||
// Refresh the page
|
||||
refreshPageAndWaitForLoad();
|
||||
|
||||
// Test user doesn't have password set
|
||||
assertThat(passwordCredentialType.isSetUpLinkVisible(), is(true));
|
||||
assertThat(passwordCredentialType.isSetUp(), is(false));
|
||||
|
||||
// Set password
|
||||
passwordCredentialType.clickSetUpLink();
|
||||
updatePasswordPage.assertCurrent();
|
||||
String originalPassword = Users.getPasswordOf(testUser);
|
||||
updatePasswordPage.updatePasswords(originalPassword, originalPassword);
|
||||
signingInPage.assertCurrent();
|
||||
|
||||
// Credential set-up now
|
||||
assertThat(passwordCredentialType.isSetUpLinkVisible(), is(false));
|
||||
assertThat(passwordCredentialType.isSetUp(), is(true));
|
||||
SigningInPage.UserCredential passwordCred =
|
||||
passwordCredentialType.getUserCredential(testUserResource().credentials().get(0).getId());
|
||||
assertUserCredential(PASSWORD_LABEL, false, passwordCred);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void otpTest() {
|
||||
testContext.setTestRealmReps(emptyList());
|
||||
|
||||
assertThat(otpCredentialType.isSetUp(), is(false));
|
||||
otpCredentialType.clickSetUpLink();
|
||||
otpSetupPage.cancel();
|
||||
|
||||
signingInPage.assertCurrent();
|
||||
assertThat(otpCredentialType.isSetUp(), is(false));
|
||||
assertThat(otpCredentialType.getTitle(), is("authenticator application"));
|
||||
|
||||
final String label1 = "OTP is secure";
|
||||
final String label2 = "OTP is inconvenient";
|
||||
|
||||
SigningInPage.UserCredential otp1 = addOtpCredential(label1);
|
||||
assertThat(otpCredentialType.isSetUp(), is(true));
|
||||
assertThat(otpCredentialType.getUserCredentialsCount(), is(1));
|
||||
assertUserCredential(label1, true, otp1);
|
||||
|
||||
SigningInPage.UserCredential otp2 = addOtpCredential(label2);
|
||||
assertThat(otpCredentialType.getUserCredentialsCount(), is(2));
|
||||
assertUserCredential(label2, true, otp2);
|
||||
|
||||
assertThat("Set up link is not visible", otpCredentialType.isSetUpLinkVisible(), is(true));
|
||||
RequiredActionProviderRepresentation requiredAction = new RequiredActionProviderRepresentation();
|
||||
requiredAction.setEnabled(false);
|
||||
testRealmResource().flows().updateRequiredAction(CONFIGURE_TOTP.name(), requiredAction);
|
||||
|
||||
refreshPageAndWaitForLoad();
|
||||
|
||||
assertThat("Set up link for \"otp\" is visible", otpCredentialType.isSetUpLinkVisible(), is(false));
|
||||
assertThat("Not set up link for \"otp\" is visible", otpCredentialType.isNotSetUpLabelVisible(), is(false));
|
||||
assertThat("Title for \"otp\" is not visible", otpCredentialType.isTitleVisible(), is(true));
|
||||
assertThat(otpCredentialType.getUserCredentialsCount(), is(2));
|
||||
|
||||
testRemoveCredential(otp1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setUpLinksTest() {
|
||||
testSetUpLink(testRealmResource(), otpCredentialType, CONFIGURE_TOTP.name());
|
||||
}
|
||||
|
||||
private SigningInPage.UserCredential addOtpCredential(String label) {
|
||||
otpCredentialType.clickSetUpLink();
|
||||
otpSetupPage.assertCurrent();
|
||||
otpSetupPage.clickManualMode();
|
||||
|
||||
String secret = new String(Base32.decode(otpSetupPage.getSecretKey()));
|
||||
String code = otpGenerator.generateTOTP(secret);
|
||||
otpSetupPage.setTotp(code);
|
||||
otpSetupPage.setUserLabel(label);
|
||||
otpSetupPage.submit();
|
||||
signingInPage.assertCurrent();
|
||||
|
||||
return getNewestUserCredential(otpCredentialType);
|
||||
}
|
||||
|
||||
private SigningInPage.UserCredential getNewestUserCredential(SigningInPage.CredentialType credentialType) {
|
||||
return SigningInPageUtils.getNewestUserCredential(testUserResource(), credentialType);
|
||||
}
|
||||
|
||||
private void testRemoveCredential(SigningInPage.UserCredential userCredential) {
|
||||
SigningInPageUtils.testRemoveCredential(getAccountPage(), userCredential);
|
||||
}
|
||||
}
|
|
@ -1,46 +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.ui.account3;
|
||||
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.testsuite.ui.account3.page.DeviceActivityPage;
|
||||
import org.keycloak.testsuite.ui.account3.page.PersonalInfoPage;
|
||||
|
||||
/**
|
||||
* Basic sanity check for Account Console
|
||||
*
|
||||
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||
*/
|
||||
public class SmokeTest extends AbstractAccountTest {
|
||||
@Page
|
||||
private PersonalInfoPage personalInfoPage;
|
||||
|
||||
@Page
|
||||
private DeviceActivityPage deviceActivityPage;
|
||||
|
||||
@Test
|
||||
public void baseFunctionalityTest() {
|
||||
accountWelcomeScreen.assertCurrent();
|
||||
accountWelcomeScreen.clickPersonalInfoLink();
|
||||
loginToAccount();
|
||||
personalInfoPage.assertCurrent();
|
||||
deviceActivityPage.navigateToUsingSidebar();
|
||||
deviceActivityPage.assertCurrent();
|
||||
}
|
||||
}
|
|
@ -1,164 +0,0 @@
|
|||
/*
|
||||
* Copyright 2021 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.ui.account3;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.keycloak.testsuite.util.UIUtils.refreshPageAndWaitForLoad;
|
||||
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.events.Details;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.RequiredActionProviderRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.testsuite.AssertEvents;
|
||||
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
|
||||
import org.keycloak.testsuite.auth.page.login.UpdateEmailPage;
|
||||
import org.keycloak.testsuite.ui.account3.page.AbstractLoggedInPage;
|
||||
import org.keycloak.testsuite.ui.account3.page.PersonalInfoPage;
|
||||
|
||||
@EnableFeature(Profile.Feature.UPDATE_EMAIL)
|
||||
public class UpdateEmailTest extends BaseAccountPageTest {
|
||||
|
||||
@Page
|
||||
private PersonalInfoPage personalInfoPage;
|
||||
|
||||
@Page
|
||||
private UpdateEmailPage updateEmailPage;
|
||||
|
||||
@Rule
|
||||
public AssertEvents events = new AssertEvents(this);
|
||||
|
||||
@Override
|
||||
protected AbstractLoggedInPage getAccountPage() {
|
||||
return personalInfoPage;
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
enableUpdateEmailRequiredAction();
|
||||
}
|
||||
|
||||
@After
|
||||
public void clean() {
|
||||
disableUpdateEmailRequiredAction();
|
||||
disableRegistration();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateEmailLinkVisibleWithUpdateEmailActionEnabled() {
|
||||
refreshPageAndWaitForLoad();
|
||||
personalInfoPage.assertUpdateEmailLinkVisible(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateEmailLinkNotVisibleWithoutUpdateEmailActionEnabled() {
|
||||
disableUpdateEmailRequiredAction();
|
||||
refreshPageAndWaitForLoad();
|
||||
personalInfoPage.assertUpdateEmailLinkVisible(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateEmailLinkVisibleWithUpdateEmailActionEnabledAndRegistrationEmailAsUsernameAndEditUsernameNotAllowed() {
|
||||
enableRegistration(true, false);
|
||||
refreshPageAndWaitForLoad();
|
||||
personalInfoPage.assertUpdateEmailLinkVisible(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateUserInfoWithRegistrationEnabled() {
|
||||
enableRegistration(false, true);
|
||||
refreshPageAndWaitForLoad();
|
||||
|
||||
assertTrue(personalInfoPage.valuesEqual(testUser));
|
||||
personalInfoPage.assertSaveDisabled(false);
|
||||
|
||||
UserRepresentation newInfo = new UserRepresentation();
|
||||
newInfo.setUsername(testUser.getUsername());
|
||||
newInfo.setEmail(testUser.getEmail());
|
||||
newInfo.setFirstName("New First");
|
||||
newInfo.setLastName("New Last");
|
||||
|
||||
personalInfoPage.setValues(newInfo, true);
|
||||
assertTrue(personalInfoPage.valuesEqual(newInfo));
|
||||
personalInfoPage.assertSaveDisabled(false);
|
||||
personalInfoPage.clickSave();
|
||||
personalInfoPage.alert().assertSuccess();
|
||||
personalInfoPage.assertSaveDisabled(false);
|
||||
|
||||
personalInfoPage.navigateTo();
|
||||
personalInfoPage.valuesEqual(newInfo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void aiaCancellationSucceeds() {
|
||||
refreshPageAndWaitForLoad();
|
||||
personalInfoPage.assertUpdateEmailLinkVisible(true);
|
||||
personalInfoPage.clickUpdateEmailLink();
|
||||
Assert.assertTrue(updateEmailPage.isCurrent());
|
||||
updateEmailPage.clickCancelAIA();
|
||||
Assert.assertTrue(personalInfoPage.isCurrent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateEmailSucceeds() {
|
||||
personalInfoPage.navigateTo();
|
||||
personalInfoPage.assertUpdateEmailLinkVisible(true);
|
||||
personalInfoPage.clickUpdateEmailLink();
|
||||
Assert.assertTrue(updateEmailPage.isCurrent());
|
||||
updateEmailPage.changeEmail("new-email@example.org");
|
||||
events.expectAccount(EventType.UPDATE_EMAIL).detail(Details.UPDATED_EMAIL, "new-email@example.org");
|
||||
Assert.assertEquals("new-email@example.org", testRealmResource().users().get(testUser.getId()).toRepresentation().getEmail());
|
||||
}
|
||||
|
||||
private void disableUpdateEmailRequiredAction() {
|
||||
RequiredActionProviderRepresentation updateEmail = testRealmResource().flows().getRequiredAction(UserModel.RequiredAction.UPDATE_EMAIL.name());
|
||||
updateEmail.setEnabled(false);
|
||||
testRealmResource().flows().updateRequiredAction(UserModel.RequiredAction.UPDATE_EMAIL.name(), updateEmail);
|
||||
}
|
||||
|
||||
private void enableUpdateEmailRequiredAction() {
|
||||
RequiredActionProviderRepresentation updateEmail = testRealmResource().flows().getRequiredAction(UserModel.RequiredAction.UPDATE_EMAIL.name());
|
||||
updateEmail.setEnabled(true);
|
||||
testRealmResource().flows().updateRequiredAction(UserModel.RequiredAction.UPDATE_EMAIL.name(), updateEmail);
|
||||
}
|
||||
|
||||
private void enableRegistration(boolean emailAsUsername, boolean usernameEditionAllowed) {
|
||||
RealmRepresentation realmRepresentation = testRealmResource().toRepresentation();
|
||||
realmRepresentation.setRegistrationAllowed(true);
|
||||
realmRepresentation.setRegistrationEmailAsUsername(emailAsUsername);
|
||||
realmRepresentation.setEditUsernameAllowed(usernameEditionAllowed);
|
||||
testRealmResource().update(realmRepresentation);
|
||||
}
|
||||
|
||||
private void disableRegistration() {
|
||||
RealmRepresentation realmRepresentation = testRealmResource().toRepresentation();
|
||||
realmRepresentation.setRegistrationAllowed(false);
|
||||
realmRepresentation.setRegistrationEmailAsUsername(false);
|
||||
realmRepresentation.setEditUsernameAllowed(false);
|
||||
testRealmResource().update(realmRepresentation);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,150 +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.ui.account3;
|
||||
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.testsuite.ui.account3.page.ApplicationsPage;
|
||||
import org.keycloak.testsuite.ui.account3.page.DeviceActivityPage;
|
||||
import org.keycloak.testsuite.ui.account3.page.LinkedAccountsPage;
|
||||
import org.keycloak.testsuite.ui.account3.page.MyResourcesPage;
|
||||
import org.keycloak.testsuite.ui.account3.page.PersonalInfoPage;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWithLoginUrlOf;
|
||||
|
||||
/**
|
||||
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||
*/
|
||||
public class WelcomeScreenTest extends AbstractAccountTest {
|
||||
@Page
|
||||
private PersonalInfoPage personalInfoPage;
|
||||
@Page
|
||||
private DeviceActivityPage deviceActivityPage;
|
||||
@Page
|
||||
private LinkedAccountsPage linkedAccountsPage;
|
||||
@Page
|
||||
private ApplicationsPage applicationsPage;
|
||||
@Page
|
||||
private MyResourcesPage myResourcesPage;
|
||||
|
||||
@Test
|
||||
public void loginLogoutTest() {
|
||||
accountWelcomeScreen.assertCurrent();
|
||||
accountWelcomeScreen.header().assertLogoutBtnVisible(false);
|
||||
assertEquals("", accountWelcomeScreen.header().getToolbarLoggedInUser());
|
||||
|
||||
// login
|
||||
accountWelcomeScreen.header().clickLoginBtn();
|
||||
loginToAccount();
|
||||
accountWelcomeScreen.assertCurrent();
|
||||
accountWelcomeScreen.header().assertLoginBtnVisible(false);
|
||||
assertEquals("test user", accountWelcomeScreen.header().getToolbarLoggedInUser());
|
||||
|
||||
// try if we're really logged in
|
||||
personalInfoPage.navigateTo();
|
||||
personalInfoPage.assertCurrent();
|
||||
accountWelcomeScreen.navigateTo();
|
||||
accountWelcomeScreen.assertCurrent();
|
||||
|
||||
// logout
|
||||
accountWelcomeScreen.header().assertLoginBtnVisible(false);
|
||||
accountWelcomeScreen.header().clickLogoutBtn();
|
||||
accountWelcomeScreen.assertCurrent();
|
||||
accountWelcomeScreen.header().assertLogoutBtnVisible(false);
|
||||
accountWelcomeScreen.header().assertLoginBtnVisible(true);
|
||||
assertEquals("", accountWelcomeScreen.header().getToolbarLoggedInUser());
|
||||
personalInfoPage.navigateTo();
|
||||
assertCurrentUrlStartsWithLoginUrlOf(personalInfoPage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void personalInfoTest() {
|
||||
accountWelcomeScreen.clickPersonalInfoLink();
|
||||
loginToAccount();
|
||||
personalInfoPage.assertCurrent();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clickLogoTest() {
|
||||
accountWelcomeScreen.clickLogoImage();
|
||||
accountWelcomeScreen.assertCurrent();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accountSecurityTest() {
|
||||
// TODO rewrite this! (KEYCLOAK-12105)
|
||||
// // change password link
|
||||
// accountWelcomeScreen.accountSecurityCard().clickChangePassword();
|
||||
// loginToAccount();
|
||||
// changePasswordPage.assertCurrent();
|
||||
//
|
||||
// // authenticator link
|
||||
// accountWelcomeScreen.navigateTo();
|
||||
// accountWelcomeScreen.accountSecurityCard().clickAuthenticator();
|
||||
// authenticatorPage.assertCurrent();
|
||||
|
||||
assertEquals("", accountWelcomeScreen.header().getToolbarLoggedInUser());
|
||||
// device activity link
|
||||
accountWelcomeScreen.navigateTo();
|
||||
accountWelcomeScreen.clickDeviceActivityLink();
|
||||
loginToAccount();
|
||||
deviceActivityPage.assertCurrent();
|
||||
|
||||
// linked accounts nav item (this doesn't test welcome page directly but the sidebar after login)
|
||||
personalInfoPage.navigateTo();
|
||||
personalInfoPage.sidebar().assertNavNotPresent(LinkedAccountsPage.LINKED_ACCOUNTS_ID);
|
||||
|
||||
// linked accounts link
|
||||
accountWelcomeScreen.navigateTo();
|
||||
accountWelcomeScreen.assertLinkedAccountsLinkVisible(false);
|
||||
// add simple IdP
|
||||
testRealmResource().identityProviders().create(createIdentityProviderRepresentation("test-idp", "google"));
|
||||
// test link appeared
|
||||
accountWelcomeScreen.navigateTo();
|
||||
accountWelcomeScreen.clickLinkedAccountsLink();
|
||||
linkedAccountsPage.assertCurrent();
|
||||
// no need to remove the IdP
|
||||
}
|
||||
|
||||
@Test
|
||||
public void applicationsTest() {
|
||||
accountWelcomeScreen.clickApplicationsLink();
|
||||
loginToAccount();
|
||||
applicationsPage.assertCurrent();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resourcesTest() {
|
||||
accountWelcomeScreen.assertMyResourcesCardVisible(false);
|
||||
|
||||
// set user managed access
|
||||
RealmRepresentation testRealm = testRealmResource().toRepresentation();
|
||||
testRealm.setUserManagedAccessAllowed(true);
|
||||
testRealmResource().update(testRealm);
|
||||
|
||||
// test my resources appeared
|
||||
accountWelcomeScreen.navigateTo();
|
||||
accountWelcomeScreen.assertMyResourcesCardVisible(true);
|
||||
accountWelcomeScreen.clickMyResourcesLink();
|
||||
loginToAccount();
|
||||
myResourcesPage.assertCurrent();
|
||||
// no need to disable user managed access
|
||||
}
|
||||
}
|
|
@ -151,7 +151,6 @@
|
|||
<profile>
|
||||
<id>webauthn</id>
|
||||
<modules>
|
||||
<module>base-ui</module>
|
||||
<module>webauthn</module>
|
||||
</modules>
|
||||
</profile>
|
||||
|
|
|
@ -23,11 +23,6 @@
|
|||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.keycloak.testsuite</groupId>
|
||||
<artifactId>integration-arquillian-tests-base-ui</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.arquillian.extension</groupId>
|
||||
<artifactId>arquillian-drone-bom</artifactId>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.ui.account3.page;
|
||||
package org.keycloak.testsuite.webauthn.pages;
|
||||
|
||||
import org.keycloak.testsuite.auth.page.AuthRealm;
|
||||
|
|
@ -15,13 +15,13 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.ui.account3.page;
|
||||
package org.keycloak.testsuite.webauthn.pages;
|
||||
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.keycloak.testsuite.ui.account3.page.fragment.ContentAlert;
|
||||
import org.keycloak.testsuite.ui.account3.page.fragment.ContinueCancelModal;
|
||||
import org.keycloak.testsuite.ui.account3.page.fragment.LoggedInPageHeader;
|
||||
import org.keycloak.testsuite.ui.account3.page.fragment.Sidebar;
|
||||
import org.keycloak.testsuite.webauthn.pages.fragments.ContentAlert;
|
||||
import org.keycloak.testsuite.webauthn.pages.fragments.ContinueCancelModal;
|
||||
import org.keycloak.testsuite.webauthn.pages.fragments.LoggedInPageHeader;
|
||||
import org.keycloak.testsuite.webauthn.pages.fragments.Sidebar;
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
||||
|
||||
|
@ -53,7 +53,7 @@ public abstract class AbstractLoggedInPage extends AbstractAccountPage {
|
|||
|
||||
@FindBy(id = "refresh-page")
|
||||
private WebElement refreshPageBtn;
|
||||
|
||||
|
||||
@FindBy(id = "brandLink")
|
||||
private WebElement brandLink;
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.ui.account3.page;
|
||||
package org.keycloak.testsuite.webauthn.pages;
|
||||
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.NoSuchElementException;
|
||||
|
@ -212,8 +212,8 @@ public class SigningInPage extends AbstractLoggedInPage {
|
|||
String lastCreateAtText = getTextFromItem(CREATED_AT);
|
||||
|
||||
return lastCreateAtText
|
||||
.substring(lastCreatedAtLabel.length(), lastCreateAtText.length() - 1) // remove label, drop last dot
|
||||
.trim();
|
||||
.substring(lastCreatedAtLabel.length(), lastCreateAtText.length() - 1) // remove label, drop last dot
|
||||
.trim();
|
||||
}
|
||||
|
||||
public LocalDateTime getCreatedAt() {
|
|
@ -15,7 +15,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.ui.account3.page.fragment;
|
||||
package org.keycloak.testsuite.webauthn.pages.fragments;
|
||||
|
||||
import org.jboss.arquillian.drone.api.annotation.Drone;
|
||||
import org.openqa.selenium.WebDriver;
|
|
@ -15,7 +15,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.ui.account3.page.fragment;
|
||||
package org.keycloak.testsuite.webauthn.pages.fragments;
|
||||
|
||||
import org.openqa.selenium.WebElement;
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.ui.account3.page.fragment;
|
||||
package org.keycloak.testsuite.webauthn.pages.fragments;
|
||||
|
||||
import org.jboss.arquillian.graphene.fragment.Root;
|
||||
import org.openqa.selenium.By;
|
|
@ -15,7 +15,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.ui.account3.page.fragment;
|
||||
package org.keycloak.testsuite.webauthn.pages.fragments;
|
||||
|
||||
import org.jboss.arquillian.drone.api.annotation.Drone;
|
||||
import org.openqa.selenium.WebDriver;
|
|
@ -15,7 +15,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.ui.account3.page.fragment;
|
||||
package org.keycloak.testsuite.webauthn.pages.fragments;
|
||||
|
||||
import org.openqa.selenium.WebElement;
|
||||
import org.openqa.selenium.support.FindBy;
|
|
@ -15,7 +15,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.ui.account3.page.fragment;
|
||||
package org.keycloak.testsuite.webauthn.pages.fragments;
|
||||
|
||||
import org.jboss.arquillian.graphene.fragment.Root;
|
||||
import org.openqa.selenium.By;
|
|
@ -15,14 +15,14 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.testsuite.ui.account3.page.utils;
|
||||
package org.keycloak.testsuite.webauthn.utils;
|
||||
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.admin.client.resource.UserResource;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.representations.idm.RequiredActionProviderRepresentation;
|
||||
import org.keycloak.testsuite.ui.account3.page.AbstractLoggedInPage;
|
||||
import org.keycloak.testsuite.ui.account3.page.SigningInPage;
|
||||
import org.keycloak.testsuite.webauthn.pages.AbstractLoggedInPage;
|
||||
import org.keycloak.testsuite.webauthn.pages.SigningInPage;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
|
@ -33,8 +33,8 @@ import org.keycloak.representations.idm.RealmRepresentation;
|
|||
import org.keycloak.representations.idm.RequiredActionProviderSimpleRepresentation;
|
||||
import org.keycloak.testsuite.AbstractAuthTest;
|
||||
import org.keycloak.testsuite.page.AbstractPatternFlyAlert;
|
||||
import org.keycloak.testsuite.ui.account3.page.SigningInPage;
|
||||
import org.keycloak.testsuite.ui.account3.page.utils.SigningInPageUtils;
|
||||
import org.keycloak.testsuite.webauthn.pages.SigningInPage;
|
||||
import org.keycloak.testsuite.webauthn.utils.SigningInPageUtils;
|
||||
import org.keycloak.testsuite.updaters.RealmAttributeUpdater;
|
||||
import org.keycloak.testsuite.util.FlowUtil;
|
||||
import org.keycloak.testsuite.webauthn.AbstractWebAuthnVirtualTest;
|
||||
|
|
|
@ -26,7 +26,7 @@ import org.keycloak.authentication.requiredactions.WebAuthnRegisterFactory;
|
|||
import org.keycloak.models.credential.WebAuthnCredentialModel;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.representations.idm.RequiredActionProviderRepresentation;
|
||||
import org.keycloak.testsuite.ui.account3.page.SigningInPage;
|
||||
import org.keycloak.testsuite.webauthn.pages.SigningInPage;
|
||||
import org.keycloak.testsuite.webauthn.pages.WebAuthnAuthenticatorsList;
|
||||
import org.keycloak.theme.DateTimeFormatterUtil;
|
||||
|
||||
|
@ -49,8 +49,8 @@ import static org.hamcrest.CoreMatchers.notNullValue;
|
|||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.keycloak.testsuite.ui.account3.page.utils.SigningInPageUtils.assertUserCredential;
|
||||
import static org.keycloak.testsuite.ui.account3.page.utils.SigningInPageUtils.testSetUpLink;
|
||||
import static org.keycloak.testsuite.webauthn.utils.SigningInPageUtils.assertUserCredential;
|
||||
import static org.keycloak.testsuite.webauthn.utils.SigningInPageUtils.testSetUpLink;
|
||||
import static org.keycloak.testsuite.util.UIUtils.refreshPageAndWaitForLoad;
|
||||
import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
|
||||
|
||||
|
|
Loading…
Reference in a new issue