Compare commits

..

1 commit

Author SHA1 Message Date
9bf20bb2cd Provide SCIM2 client capabilities behing an experimental Feature Profile
Some checks are pending
Keycloak CI / Base IT (new) (push) Blocked by required conditions
Keycloak CI / Status Check - Keycloak CI (push) Blocked by required conditions
CodeQL / Check conditional workflows and jobs (push) Waiting to run
CodeQL / CodeQL Java (push) Blocked by required conditions
CodeQL / CodeQL JavaScript (push) Blocked by required conditions
CodeQL / CodeQL TypeScript (push) Blocked by required conditions
CodeQL / Status Check - CodeQL (push) Blocked by required conditions
Keycloak Guides / Check conditional workflows and jobs (push) Waiting to run
Keycloak Guides / Build (push) Blocked by required conditions
Keycloak Guides / Status Check - Keycloak Guides (push) Blocked by required conditions
Keycloak JavaScript CI / Admin UI E2E (push) Blocked by required conditions
Keycloak JavaScript CI / Status Check - Keycloak JavaScript CI (push) Blocked by required conditions
Keycloak JavaScript CI / Build Keycloak (push) Blocked by required conditions
Keycloak JavaScript CI / Admin Client (push) Blocked by required conditions
Keycloak JavaScript CI / Account UI (push) Blocked by required conditions
Keycloak JavaScript CI / Admin UI (push) Blocked by required conditions
Keycloak JavaScript CI / Account UI E2E (push) Blocked by required conditions
Keycloak Documentation / Check conditional workflows and jobs (push) Waiting to run
Keycloak Documentation / Build (push) Blocked by required conditions
Keycloak Documentation / External links check (push) Blocked by required conditions
Keycloak Documentation / Status Check - Keycloak Documentation (push) Blocked by required conditions
Keycloak JavaScript CI / Check conditional workflows and jobs (push) Waiting to run
Keycloak JavaScript CI / UI Shared (push) Blocked by required conditions
Keycloak JavaScript CI / Generate Test Seed (push) Blocked by required conditions
Keycloak Operator CI / Test remote (push) Blocked by required conditions
Keycloak Operator CI / Check conditional workflows and jobs (push) Waiting to run
Keycloak Operator CI / Build distribution (push) Blocked by required conditions
Keycloak Operator CI / Test local (push) Blocked by required conditions
Keycloak Operator CI / Test OLM installation (push) Blocked by required conditions
Keycloak Operator CI / Status Check - Keycloak Operator CI (push) Blocked by required conditions
Closes #1234

Signed-off-by: Alex Morel <amorel@codelutin.com>
2024-11-07 11:05:29 +01:00
7 changed files with 57 additions and 115 deletions

View file

@ -58,12 +58,6 @@ public class EventBean {
return details; return details;
} }
public String getDetail(String name) {
return event.getDetails() != null
? event.getDetails().get(name)
: null;
}
public static class DetailBean { public static class DetailBean {
private Map.Entry<String, String> entry; private Map.Entry<String, String> entry;

View file

@ -19,21 +19,17 @@
package org.keycloak.testsuite.actions; package org.keycloak.testsuite.actions;
import jakarta.mail.internet.MimeMessage;
import jakarta.ws.rs.core.Response;
import java.util.List; import java.util.List;
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers; import jakarta.ws.rs.core.Response;
import org.jboss.arquillian.graphene.page.Page; import org.jboss.arquillian.graphene.page.Page;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.keycloak.authentication.requiredactions.DeleteCredentialAction; import org.keycloak.authentication.requiredactions.DeleteCredentialAction;
import org.keycloak.events.Details; import org.keycloak.events.Details;
import org.keycloak.events.Errors; import org.keycloak.events.Errors;
import org.keycloak.events.EventType; import org.keycloak.events.EventType;
import org.keycloak.events.email.EmailEventListenerProviderFactory;
import org.keycloak.models.credential.OTPCredentialModel; import org.keycloak.models.credential.OTPCredentialModel;
import org.keycloak.models.credential.PasswordCredentialModel; import org.keycloak.models.credential.PasswordCredentialModel;
import org.keycloak.models.utils.TimeBasedOTP; import org.keycloak.models.utils.TimeBasedOTP;
@ -45,9 +41,6 @@ import org.keycloak.testsuite.pages.DeleteCredentialPage;
import org.keycloak.testsuite.pages.ErrorPage; import org.keycloak.testsuite.pages.ErrorPage;
import org.keycloak.testsuite.pages.LoginConfigTotpPage; import org.keycloak.testsuite.pages.LoginConfigTotpPage;
import org.keycloak.testsuite.pages.LoginTotpPage; import org.keycloak.testsuite.pages.LoginTotpPage;
import org.keycloak.testsuite.updaters.RealmAttributeUpdater;
import org.keycloak.testsuite.util.GreenMailRule;
import org.keycloak.testsuite.util.MailUtils;
import org.keycloak.testsuite.util.UserBuilder; import org.keycloak.testsuite.util.UserBuilder;
/** /**
@ -55,9 +48,6 @@ import org.keycloak.testsuite.util.UserBuilder;
*/ */
public class AppInitiatedActionDeleteCredentialTest extends AbstractAppInitiatedActionTest { public class AppInitiatedActionDeleteCredentialTest extends AbstractAppInitiatedActionTest {
@Rule
public GreenMailRule greenMail = new GreenMailRule();
@Override @Override
protected String getAiaAction() { protected String getAiaAction() {
return DeleteCredentialAction.PROVIDER_ID; return DeleteCredentialAction.PROVIDER_ID;
@ -86,11 +76,9 @@ public class AppInitiatedActionDeleteCredentialTest extends AbstractAppInitiated
@Before @Before
public void beforeTest() { public void beforeTest() {
ApiUtil.removeUserByUsername(testRealm(), "test-user@localhost");
UserRepresentation user = UserBuilder.create() UserRepresentation user = UserBuilder.create()
.username("john") .username("john")
.email("test-user@localhost") .email("john@email.cz")
.emailVerified(true)
.firstName("John") .firstName("John")
.lastName("Bar") .lastName("Bar")
.enabled(true) .enabled(true)
@ -104,48 +92,33 @@ public class AppInitiatedActionDeleteCredentialTest extends AbstractAppInitiated
@Test @Test
public void removeOtpSuccess() throws Exception { public void removeOtpSuccess() throws Exception {
try (RealmAttributeUpdater updater = new RealmAttributeUpdater(testRealm()) String credentialId = getCredentialIdByType(OTPCredentialModel.TYPE);
.addEventsListener(EmailEventListenerProviderFactory.ID) oauth.kcAction(getKcActionParamForDeleteCredential(credentialId));
.update()) {
String credentialId = getCredentialIdByType(OTPCredentialModel.TYPE); loginPasswordAndOtp();
oauth.kcAction(getKcActionParamForDeleteCredential(credentialId));
loginPasswordAndOtp(); deleteCredentialPage.assertCurrent();
deleteCredentialPage.assertCredentialInMessage(OTPCredentialModel.TYPE);
deleteCredentialPage.assertCurrent(); deleteCredentialPage.confirm();
deleteCredentialPage.assertCredentialInMessage(OTPCredentialModel.TYPE);
deleteCredentialPage.confirm(); appPage.assertCurrent();
assertKcActionStatus("success");
appPage.assertCurrent(); Assert.assertNull(getCredentialIdByType(OTPCredentialModel.TYPE));
assertKcActionStatus("success");
Assert.assertNull(getCredentialIdByType(OTPCredentialModel.TYPE)); events.expect(EventType.REMOVE_TOTP)
.user(userId)
events.expect(EventType.REMOVE_TOTP) .detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE)
.user(userId) .detail(Details.CREDENTIAL_ID, credentialId)
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE) .detail(Details.CUSTOM_REQUIRED_ACTION, DeleteCredentialAction.PROVIDER_ID)
.detail(Details.CREDENTIAL_ID, credentialId) .assertEvent();
.detail(Details.CUSTOM_REQUIRED_ACTION, DeleteCredentialAction.PROVIDER_ID) events.expect(EventType.REMOVE_CREDENTIAL)
.assertEvent(); .user(userId)
events.expect(EventType.REMOVE_CREDENTIAL) .detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE)
.user(userId) .detail(Details.CREDENTIAL_ID, credentialId)
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE) .detail(Details.CUSTOM_REQUIRED_ACTION, DeleteCredentialAction.PROVIDER_ID)
.detail(Details.CREDENTIAL_ID, credentialId) .assertEvent();
.detail(Details.CUSTOM_REQUIRED_ACTION, DeleteCredentialAction.PROVIDER_ID)
.assertEvent();
MimeMessage[] receivedMessages = greenMail.getReceivedMessages();
Assert.assertEquals(2, receivedMessages.length);
Assert.assertEquals("Remove OTP", receivedMessages[0].getSubject());
Assert.assertEquals("Remove credential", receivedMessages[1].getSubject());
MatcherAssert.assertThat(MailUtils.getBody(receivedMessages[1]).getText(),
Matchers.startsWith("Credential otp was removed from your account"));
MatcherAssert.assertThat(MailUtils.getBody(receivedMessages[1]).getHtml(),
Matchers.containsString("Credential otp was removed from your account"));
}
} }
@Test @Test

View file

@ -16,9 +16,6 @@
*/ */
package org.keycloak.testsuite.actions; package org.keycloak.testsuite.actions;
import jakarta.mail.internet.MimeMessage;
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.jboss.arquillian.drone.api.annotation.Drone; import org.jboss.arquillian.drone.api.annotation.Drone;
import org.jboss.arquillian.graphene.page.Page; import org.jboss.arquillian.graphene.page.Page;
import org.junit.After; import org.junit.After;
@ -29,7 +26,6 @@ import org.keycloak.admin.client.resource.UserResource;
import org.keycloak.cookie.CookieType; import org.keycloak.cookie.CookieType;
import org.keycloak.events.Details; import org.keycloak.events.Details;
import org.keycloak.events.EventType; import org.keycloak.events.EventType;
import org.keycloak.events.email.EmailEventListenerProviderFactory;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.credential.PasswordCredentialModel; import org.keycloak.models.credential.PasswordCredentialModel;
@ -39,10 +35,7 @@ import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.representations.idm.UserSessionRepresentation; import org.keycloak.representations.idm.UserSessionRepresentation;
import org.keycloak.testsuite.admin.ApiUtil; import org.keycloak.testsuite.admin.ApiUtil;
import org.keycloak.testsuite.pages.LoginPasswordUpdatePage; import org.keycloak.testsuite.pages.LoginPasswordUpdatePage;
import org.keycloak.testsuite.updaters.RealmAttributeUpdater;
import org.keycloak.testsuite.updaters.UserAttributeUpdater;
import org.keycloak.testsuite.util.GreenMailRule; import org.keycloak.testsuite.util.GreenMailRule;
import org.keycloak.testsuite.util.MailUtils;
import org.keycloak.testsuite.util.OAuthClient; import org.keycloak.testsuite.util.OAuthClient;
import org.keycloak.testsuite.util.SecondBrowser; import org.keycloak.testsuite.util.SecondBrowser;
import org.openqa.selenium.Cookie; import org.openqa.selenium.Cookie;
@ -88,66 +81,48 @@ public class AppInitiatedActionResetPasswordTest extends AbstractAppInitiatedAct
@Test @Test
public void resetPassword() throws Exception { public void resetPassword() throws Exception {
try (RealmAttributeUpdater realmUpdater = new RealmAttributeUpdater(testRealm()) loginPage.open();
.addEventsListener(EmailEventListenerProviderFactory.ID) loginPage.login("test-user@localhost", "password");
.update();
UserAttributeUpdater userUpdater = new UserAttributeUpdater(ApiUtil.findUserByUsernameId(testRealm(), "test-user@localhost"))
.setEmailVerified(true)
.update()) {
loginPage.open(); events.expectLogin().assertEvent();
loginPage.login("test-user@localhost", "password");
events.expectLogin().assertEvent(); doAIA();
doAIA(); changePasswordPage.assertCurrent();
assertTrue(changePasswordPage.isCancelDisplayed());
changePasswordPage.assertCurrent(); Cookie authSessionCookie = driver.manage().getCookieNamed(CookieType.AUTH_SESSION_ID.getName());
assertTrue(changePasswordPage.isCancelDisplayed()); String authSessionId = authSessionCookie.getValue().split("\\.")[0];
testingClient.server().run(session -> {
// ensure that our logic to detect the authentication session works as expected
RealmModel realm = session.realms().getRealm(TEST_REALM_NAME);
assertNotNull(session.authenticationSessions().getRootAuthenticationSession(realm, authSessionId));
});
Cookie authSessionCookie = driver.manage().getCookieNamed(CookieType.AUTH_SESSION_ID.getName()); changePasswordPage.changePassword("new-password", "new-password");
String authSessionId = authSessionCookie.getValue().split("\\.")[0];
testingClient.server().run(session -> {
// ensure that our logic to detect the authentication session works as expected
RealmModel realm = session.realms().getRealm(TEST_REALM_NAME);
assertNotNull(session.authenticationSessions().getRootAuthenticationSession(realm, authSessionId));
});
changePasswordPage.changePassword("new-password", "new-password"); testingClient.server().run(session -> {
// ensure that the authentication session has been terminated
RealmModel realm = session.realms().getRealm(TEST_REALM_NAME);
assertNull(session.authenticationSessions().getRootAuthenticationSession(realm, authSessionId));
});
testingClient.server().run(session -> { events.expectRequiredAction(EventType.UPDATE_PASSWORD).assertEvent();
// ensure that the authentication session has been terminated events.expectRequiredAction(EventType.UPDATE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).assertEvent();
RealmModel realm = session.realms().getRealm(TEST_REALM_NAME);
assertNull(session.authenticationSessions().getRootAuthenticationSession(realm, authSessionId));
});
events.expectRequiredAction(EventType.UPDATE_PASSWORD).assertEvent(); assertKcActionStatus(SUCCESS);
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).assertEvent();
MimeMessage[] receivedMessages = greenMail.getReceivedMessages(); EventRepresentation loginEvent = events.expectLogin().assertEvent();
Assert.assertEquals(2, receivedMessages.length);
Assert.assertEquals("Update password", receivedMessages[0].getSubject()); OAuthClient.AccessTokenResponse tokenResponse = sendTokenRequestAndGetResponse(loginEvent);
Assert.assertEquals("Update credential", receivedMessages[1].getSubject()); oauth.idTokenHint(tokenResponse.getIdToken()).openLogout();
MatcherAssert.assertThat(MailUtils.getBody(receivedMessages[1]).getText(),
Matchers.startsWith("Your password credential was changed"));
MatcherAssert.assertThat(MailUtils.getBody(receivedMessages[1]).getHtml(),
Matchers.containsString("Your password credential was changed"));
assertKcActionStatus(SUCCESS); events.expectLogout(loginEvent.getSessionId()).assertEvent();
EventRepresentation loginEvent = events.expectLogin().assertEvent(); loginPage.open();
loginPage.login("test-user@localhost", "new-password");
OAuthClient.AccessTokenResponse tokenResponse = sendTokenRequestAndGetResponse(loginEvent); events.expectLogin().assertEvent();
oauth.idTokenHint(tokenResponse.getIdToken()).openLogout();
events.expectLogout(loginEvent.getSessionId()).assertEvent();
loginPage.open();
loginPage.login("test-user@localhost", "new-password");
events.expectLogin().assertEvent();
}
} }
@Test @Test

View file

@ -1,4 +1,4 @@
<#import "template.ftl" as layout> <#import "template.ftl" as layout>
<@layout.emailLayout> <@layout.emailLayout>
${kcSanitize(msg("eventRemoveCredentialBodyHtml", event.getDetail("credential_type")!"unknown", event.date, event.ipAddress))?no_esc} ${kcSanitize(msg("eventRemoveCredentialBodyHtml", event.details.credential_type!"unknown", event.date, event.ipAddress))?no_esc}
</@layout.emailLayout> </@layout.emailLayout>

View file

@ -1,4 +1,4 @@
<#import "template.ftl" as layout> <#import "template.ftl" as layout>
<@layout.emailLayout> <@layout.emailLayout>
${kcSanitize(msg("eventUpdateCredentialBodyHtml", event.getDetail("credential_type")!"unknown", event.date, event.ipAddress))?no_esc} ${kcSanitize(msg("eventUpdateCredentialBodyHtml", event.details.credential_type!"unknown", event.date, event.ipAddress))?no_esc}
</@layout.emailLayout> </@layout.emailLayout>

View file

@ -1,2 +1,2 @@
<#ftl output_format="plainText"> <#ftl output_format="plainText">
${msg("eventRemoveCredentialBody", event.getDetail("credential_type")!"unknown", event.date, event.ipAddress)} ${msg("eventRemoveCredentialBody", event.details.credential_type!"unknown", event.date, event.ipAddress)}

View file

@ -1,2 +1,2 @@
<#ftl output_format="plainText"> <#ftl output_format="plainText">
${msg("eventUpdateCredentialBody", event.getDetail("credential_type")!"unknown", event.date, event.ipAddress)} ${msg("eventUpdateCredentialBody", event.details.credential_type!"unknown", event.date, event.ipAddress)}