8000 Move AuthorizationCodeTest to the new testsuite by lhanusov · Pull Request #49772 · keycloak/keycloak · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,20 +1,74 @@
package org.keycloak.testframework.oauth;

import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;

import org.keycloak.OAuth2Constants;
import org.keycloak.common.util.HtmlUtils;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import org.apache.http.client.methods.HttpPost;

class OAuthCallbackHandler implements HttpHandler {

@Override
public void handle(HttpExchange exchange) throws IOException {
byte[] bytes = "<html><body>Happy days</body></html>".getBytes(StandardCharsets.UTF_8);
String requestBody = new String(exchange.getRequestBody().readAllBytes(), StandardCharsets.UTF_8);
String requestMethod = exchange.getRequestMethod();
String requestUriParam = exchange.getRequestURI().getQuery();

byte[] bytes = htmlResponseStringBuilder(requestBody, requestMethod, requestUriParam);

sendHttpResponse(exchange, bytes);
}

private void sendHttpResponse(HttpExchange exchange, byte[] bytes) throws IOException {
exchange.getResponseHeaders().set("Content-Type", "text/html");
exchange.sendResponseHeaders(200, bytes.length);
exchange.getResponseBody().write(bytes);
exchange.getResponseBody().close();
}

private byte[] htmlResponseStringBuilder(String requestBody, String requestMethod, String requestUriParam) {
StringBuilder sb = new StringBuilder();
sb.append("<html><body>");
if (requestMethod.equals(HttpPost.METHOD_NAME)) {
formPostStringBuilder(sb, requestBody);
} else {
if (requestUriParam != null && requestUriParam.contains(OAuth2Constants.CODE)) {
sb.append("<b>Happy days!</b><br>");
} else {
sb.append("<b>Not happy days!</b><br>");
}
}
sb.append("<br>");
sb.append("</body></html>");

return sb.toString().getBytes(StandardCharsets.UTF_8);
}

private void formPostStringBuilder(StringBuilder sb, String requestBody) {
String requestBodyDecoded = URLDecoder.decode(requestBody, StandardCharsets.UTF_8);
Map<String, String> formPostParams = Arrays.stream(requestBodyDecoded.split("&"))
.collect(Collectors.toMap(s -> s.split("=", 2)[0], s -> s.split("=", 2)[1]));

if (!formPostParams.containsKey(OAuth2Constants.ERROR)) {
sb.append("<b>Happy days!</b><br>");
} else {
sb.append("<b>Not happy days!</b><br>");
}
sb.append("<br>");
sb.append("<b>Form POST parameters: </b><br>");
for (String paramName : formPostParams.keySet()) {
sb.append(paramName).append(": ").append("<span id=\"")
.append(paramName).append("\">")
.append(HtmlUtils.escapeAttribute(formPostParams.get(paramName)))
.append("</span><br>");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
import org.keycloak.OAuth2Constants;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.client.registration.ClientRegistration;
import org.keycloak.protocol.oidc.utils.OIDCResponseMode;
import org.keycloak.testframework.ui.page.LoginPage;
import org.keycloak.testframework.ui.webdriver.ManagedWebDriver;
import org.keycloak.testsuite.util.oauth.AbstractOAuthClient;
import org.keycloak.testsuite.util.oauth.AuthorizationEndpointResponse;
import org.keycloak.testsuite.util.oauth.OAuthClientConfig;

import org.apache.http.impl.client.CloseableHttpClient;
import org.openqa.selenium.By;
import org.openqa.selenium.support.PageFactory;

/**
Expand Down Expand Up @@ -43,14 +45,24 @@ public void fillLoginForm(String username, String password) {

@Override
public AuthorizationEndpointResponse parseLoginResponse() {
managedWebDriver.waiting().waitForOAuthCallback();
if (config.getResponseMode() != null && config.getResponseMode().equals(OIDCResponseMode.FORM_POST.value())) {
managedWebDriver.waiting().waitForOAuthCallback(webdriver1 -> webdriver1.findElement(By.id(OAuth2Constants.CODE)).isDisplayed() || webdriver1.findElement(By.id(OAuth2Constants.ERROR)).isDisplayed());
} else if (config.getResponseMode() != null && config.getResponseMode().equals(OIDCResponseMode.FORM_POST_JWT.value())) {
managedWebDriver.waiting().waitForOAuthCallback(webdriver1 -> webdriver1.findElement(By.id(OAuth2Constants.RESPONSE)).isDisplayed());
} else {
managedWebDriver.waiting().waitForOAuthCallback();
}
return super.parseLoginResponse();
}

public ClientRegistration clientRegistration() {
return ClientRegistration.create().httpClient(httpClient().get()).url(baseUrl, config.getRealm()).build();
}

public ClientResource clientResource() {
return clientResource;
}

public void close() {
if (clientResource != null) {
clientResource.remove();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,15 @@ public void testMultipleWebDriverInstances() {
loginPage1.fillLogin(user.getUsername(), user.getPassword());
loginPage1.submit();

Assertions.assertNotNull(oauth1.parseLoginResponse().getCode());
Assertions.assertTrue(oauth1.parseLoginResponse().isSuccess());
EventAssertion.assertSuccess(events.poll()).userId(user.getId());

oauth2.openLoginForm();

loginPage2.fillLogin(user.getUsername(), user.getPassword());
loginPage2.submit();

Assertions.assertNotNull(oauth2.parseLoginResponse().getCode());
Assertions.assertTrue(oauth2.parseLoginResponse().isSuccess());
EventAssertion.assertSuccess(events.poll()).userId(user.getId());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@
*
*/

package org.keycloak.testsuite.pages;
package org.keycloak.testframework.ui.page;

import java.net.URI;
import java.net.URISyntaxException;

import org.keycloak.OAuth2Constants;
import org.keycloak.common.util.KeycloakUriBuilder;
import org.keycloak.services.Urls;
import org.keycloak.testframework.ui.webdriver.ManagedWebDriver;

import org.junit.jupiter.api.Assertions;
import org.openqa.selenium.By;
Expand All @@ -48,9 +49,13 @@ public class InstalledAppRedirectPage extends AbstractPage {
@FindBy(css = "div[class^='pf-v5-c-alert'], div[class^='alert-error']")
private WebElement errorBox;

public void open(String realmName, String code, String error, String errorDescription) {
public InstalledAppRedirectPage(ManagedWebDriver driver) {
super(driver);
}

public void open(String kcUrl, String realmName, String code, String error, String errorDescription) {
try {
KeycloakUriBuilder kcUriBuilder = KeycloakUriBuilder.fromUri(Urls.realmInstalledAppUrnCallback(new URI(oauth.AUTH_SERVER_ROOT), realmName));
KeycloakUriBuilder kcUriBuilder = KeycloakUriBuilder.fromUri(Urls.realmInstalledAppUrnCallback(new URI(kcUrl), realmName));
if (code != null) {
kcUriBuilder.queryParam(OAuth2Constants.CODE, code);
}
Expand All @@ -61,18 +66,12 @@ public void open(String realmName, String code, String error, String errorDescri
kcUriBuilder.queryParam(OAuth2Constants.ERROR_DESCRIPTION, errorDescription);
}
String oobEndpointUri = kcUriBuilder.build().toString();
driver.navigate().to(oobEndpointUri);
driver.driver().navigate().to(oobEndpointUri);
} catch (URISyntaxException use) {
throw new IllegalArgumentException(use);
}
}

@Override
public boolean isCurrent() {
throw new UnsupportedOperationException("Use method 'isCurrentExpectSuccess' or 'isCurrentExpectError'");
}


public String getSuccessCode() {
Assertions.assertEquals("Success code", getPageTitleText());
return code.getAttribute("value");
Expand All @@ -97,6 +96,10 @@ public void assertLinkBackToApplicationNotPresent() {
} catch (NoSuchElementException nsee) {
// Ignore
}
}

@Override
public String getExpectedPageId() {
return "login-code";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.time.Duration;
import java.util.function.Function;

import org.keycloak.OAuth2Constants;
import org.keycloak.testframework.ui.page.AbstractPage;

import org.junit.jupiter.api.Assertions;
Expand Down Expand Up @@ -30,8 +31,13 @@ public WaitUtils waitForPage(AbstractPage page) {
}

public WaitUtils waitForOAuthCallback() {
waitForOAuthCallback(webdriver1 -> webdriver1.getCurrentUrl().contains(OAuth2Constants.CODE + "=") || webdriver1.getCurrentUrl().contains(OAuth2Constants.ERROR + "="));
return this;
}

public WaitUtils waitForOAuthCallback(Function<? super WebDriver, Boolean> oAuthResponseIsPresent) {
try {
createDefaultWait().until(d -> d.getCurrentUrl().contains("code=") || d.getCurrentUrl().contains("error="));
createDefaultWait().until(oAuthResponseIsPresent);
} catch (TimeoutException e) {
Assertions.fail("Expected OAuth callback, but URL was '" + managed.getCurrentUrl() + "' after timeout");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public void updateProfile() {

updateProfilePage.prepareUpdate().username("test-user@localhost").firstName("New first").lastName("New last").email("new@email.com").submit();

Assertions.assertNotNull(oauth.parseLoginResponse().getCode());
Assertions.assertTrue(oauth.parseLoginResponse().isSuccess());

EventAssertion.expectRequiredAction(events.poll()).type(EventType.UPDATE_PROFILE).details(Details.PREVIOUS_FIRST_NAME, "Tom").details(Details.UPDATED_FIRST_NAME, "New first")
.details(Details.PREVIOUS_LAST_NAME, "Brady").details(Details.UPDATED_LAST_NAME, "New last")
Expand Down Expand Up @@ -152,7 +152,7 @@ public void updateUsername() {

updateProfilePage.prepareUpdate().username("new").firstName("New first").lastName("New last").email("john-doh@localhost").submit();

Assertions.assertNotNull(oauth.parseLoginResponse().getCode());
Assertions.assertTrue(oauth.parseLoginResponse().isSuccess());

EventAssertion.assertSuccess(events.poll())
.type(EventType.UPDATE_PROFILE)
Expand Down Expand Up @@ -445,7 +445,7 @@ public void updateProfileWithoutRemoveCustomAttributes() {

updateProfilePage.prepareUpdate().username("test-user@localhost").firstName("New first").lastName("New last").email("new@email.com").submit();

Assertions.assertNotNull(oauth.parseLoginResponse().getCode());
Assertions.assertTrue(oauth.parseLoginResponse().isSuccess());

EventAssertion.expectRequiredAction(events.poll()).type(EventType.UPDATE_PROFILE).details(Details.CONTEXT, UserProfileContext.UPDATE_PROFILE.name()).details(Details.PREVIOUS_EMAIL, "test-user@localhost").details(Details.UPDATED_EMAIL, "new@email.com");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ public void testConsents() {
consentPage.assertCurrent();
consentPage.confirm();

assertTrue(driver.page().getPageSource().contains("Happy days"), "Test user should be successfully logged in.");
Assertions.assertTrue(consumerRealmOAuth.parseLoginResponse().isSuccess());

UsersResource consumerUsers = consumerRealm.admin().users();
Assertions.assertTrue(consumerUsers.count() > 0, "There must be at least one user");
Expand Down Expand Up @@ -277,26 +277,25 @@ public void testConsentCancel() {
consentPage.cancel();

// check an error page after cancelling the consent
assertTrue(driver.page().getPageSource().contains("Happy days"));
Assertions.assertTrue(providerRealmOAuth.parseLoginResponse().isError());
assertTrue(driver.getCurrentUrl().contains("error=access_denied"));

providerRealmOAuth.openLoginForm();
loginPage.fillLogin(userFromProviderRealm.getUsername(), userFromProviderRealm.getPassword());
loginPage.submit();
consentPage.assertCurrent();
consentPage.confirm();

// successful login
assertFalse(driver.getCurrentUrl().contains("error"));
assertTrue(driver.page().getPageSource().contains("Happy days"), "Test user should be successfully logged in.");
Assertions.assertTrue(providerRealmOAuth.parseLoginResponse().isSuccess());
}

@Test
public void clientConsentRequiredAfterLogin() {
AuthorizationEndpointResponse response = userRealmOAuth.doLogin(userFromUserRealm.getUsername(), userFromUserRealm.getPassword());
AccessTokenResponse accessTokenResponse = userRealmOAuth.doAccessTokenRequest(response.getCode());

Assertions.assertNotNull(userRealmOAuth.parseLoginResponse().getCode());
assertTrue(driver.page().getPageSource().contains("Happy days"), "Test user should be successfully logged in.");
Assertions.assertTrue(userRealmOAuth.parseLoginResponse().isSuccess());

EventRepresentation loginEvent = userRealmEvents.poll();
EventAssertion.assertSuccess(loginEvent).type(EventType.LOGIN)
Expand Down Expand Up @@ -363,7 +362,7 @@ public void testConsentWithAdditionalClientAttributes() {
consentPage.confirm();

// successful login
assertTrue(driver.page().getPageSource().contains("Happy days"), "Test user should be successfully logged in.");
Assertions.assertTrue(providerRealmOAuth.parseLoginResponse().isSuccess());
AccountHelper.logout(providerRealm.admin(), userFromProviderRealm.getUsername());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public void resetUserPassword() {
loginPage.fillLogin("user1", "paSSw0rd");
loginPage.submit();

assertTrue(driver.page().getPageSource().contains("Happy days"));
Assertions.assertTrue(oauth.parseLoginResponse().isSuccess());

AccountHelper.logout(managedRealm.admin(), "user1");
}
Expand Down Expand Up @@ -118,7 +118,7 @@ public void loginShouldFailAfterPasswordDeleted() {
loginPage.assertCurrent();
loginPage.fillLogin(userName, userPass);
loginPage.submit();
assertTrue(driver.page().getPageSource().contains("Happy days"), "Test user should be successfully logged in.");
Assertions.assertTrue(oauth.parseLoginResponse().isSuccess());
AccountHelper.logout(managedRealm.admin(), userName);

Optional<CredentialRepresentation> passwordCredential =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;

@KeycloakIntegrationTest
Expand Down 10BC8 Expand Up @@ -79,7 +78,7 @@ public void updateUserWithHashedCredentials() {
loginPage.fillLogin("user_hashed_creds", "admin");
loginPage.submit();

assertTrue(driver.page().getPageSource().contains("Happy days"));
Assertions.assertTrue(oauth.parseLoginResponse().isSuccess());

AccountHelper.logout(managedRealm.admin(), "user_hashed_creds");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;

import static org.junit.jupiter.api.Assertions.assertTrue;

/**
* Test for default configuration of OIDC login protocol factory
Expand Down Expand Up @@ -95,8 +94,7 @@ protected void assertLogin(String loginHintExpected, String stateExpected) {
loginPage.fillLogin("test-user", "password");
loginPage.submit();

assertTrue(driver.page().getPageSource().contains("Happy days"));
// String currentUrl = driver.getCurrentUrl();
Assertions.assertTrue(oauth.parseLoginResponse().isSuccess());
String state = oauth.parseLoginResponse().getState();
Assertions.assertEquals(stateExpected, state);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

@KeycloakIntegrationTest
public class LoginSSLTest {
Expand Down Expand Up @@ -77,7 +78,7 @@ public void loginSuccessRealmSigningAlgorithms() throws JWSInputException {
loginPage.fillLogin("login-test", "test");
loginPage.submit();

assertNotNull(oauth.parseLoginResponse().getCode());
assertTrue(oauth.parseLoginResponse().isSuccess());

EventAssertion.assertSuccess(events.poll())
.type(EventType.LOGIN)
Expand Down
Loading
Loading
0