Skip to content

Commit

Permalink
Fix credential_type in update/remove credential email template
Browse files Browse the repository at this point in the history
Closes keycloak#34687

Signed-off-by: Achim Rolle <[email protected]>
Signed-off-by: rmartinc <[email protected]>
Co-authored-by: rmartinc <[email protected]>
(cherry picked from commit 83065b8)
  • Loading branch information
hauptrolle authored and ahus1 committed Nov 8, 2024
1 parent 8df4e88 commit 5aa874e
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ public List<DetailBean> getDetails() {
return details;
}

public String getDetail(String name) {
return event.getDetails() != null
? event.getDetails().get(name)
: null;
}

public static class DetailBean {

private Map.Entry<String, String> entry;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,21 @@

package org.keycloak.testsuite.actions;

import java.util.List;

import jakarta.mail.internet.MimeMessage;
import jakarta.ws.rs.core.Response;
import java.util.List;
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.jboss.arquillian.graphene.page.Page;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.keycloak.authentication.requiredactions.DeleteCredentialAction;
import org.keycloak.events.Details;
import org.keycloak.events.Errors;
import org.keycloak.events.EventType;
import org.keycloak.events.email.EmailEventListenerProviderFactory;
import org.keycloak.models.credential.OTPCredentialModel;
import org.keycloak.models.credential.PasswordCredentialModel;
import org.keycloak.models.utils.TimeBasedOTP;
Expand All @@ -41,13 +45,19 @@
import org.keycloak.testsuite.pages.ErrorPage;
import org.keycloak.testsuite.pages.LoginConfigTotpPage;
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;

/**
* @author <a href="mailto:[email protected]">Marek Posolda</a>
*/
public class AppInitiatedActionDeleteCredentialTest extends AbstractAppInitiatedActionTest {

@Rule
public GreenMailRule greenMail = new GreenMailRule();

@Override
protected String getAiaAction() {
return DeleteCredentialAction.PROVIDER_ID;
Expand Down Expand Up @@ -76,9 +86,11 @@ public void configureTestRealm(RealmRepresentation testRealm) {

@Before
public void beforeTest() {
ApiUtil.removeUserByUsername(testRealm(), "test-user@localhost");
UserRepresentation user = UserBuilder.create()
.username("john")
.email("[email protected]")
.email("test-user@localhost")
.emailVerified(true)
.firstName("John")
.lastName("Bar")
.enabled(true)
Expand All @@ -92,33 +104,48 @@ public void beforeTest() {

@Test
public void removeOtpSuccess() throws Exception {
String credentialId = getCredentialIdByType(OTPCredentialModel.TYPE);
oauth.kcAction(getKcActionParamForDeleteCredential(credentialId));

loginPasswordAndOtp();

deleteCredentialPage.assertCurrent();
deleteCredentialPage.assertCredentialInMessage(OTPCredentialModel.TYPE);

deleteCredentialPage.confirm();

appPage.assertCurrent();
assertKcActionStatus("success");

Assert.assertNull(getCredentialIdByType(OTPCredentialModel.TYPE));

events.expect(EventType.REMOVE_TOTP)
.user(userId)
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE)
.detail(Details.CREDENTIAL_ID, credentialId)
.detail(Details.CUSTOM_REQUIRED_ACTION, DeleteCredentialAction.PROVIDER_ID)
.assertEvent();
events.expect(EventType.REMOVE_CREDENTIAL)
.user(userId)
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE)
.detail(Details.CREDENTIAL_ID, credentialId)
.detail(Details.CUSTOM_REQUIRED_ACTION, DeleteCredentialAction.PROVIDER_ID)
.assertEvent();
try (RealmAttributeUpdater updater = new RealmAttributeUpdater(testRealm())
.addEventsListener(EmailEventListenerProviderFactory.ID)
.update()) {

String credentialId = getCredentialIdByType(OTPCredentialModel.TYPE);
oauth.kcAction(getKcActionParamForDeleteCredential(credentialId));

loginPasswordAndOtp();

deleteCredentialPage.assertCurrent();
deleteCredentialPage.assertCredentialInMessage(OTPCredentialModel.TYPE);

deleteCredentialPage.confirm();

appPage.assertCurrent();
assertKcActionStatus("success");

Assert.assertNull(getCredentialIdByType(OTPCredentialModel.TYPE));

events.expect(EventType.REMOVE_TOTP)
.user(userId)
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE)
.detail(Details.CREDENTIAL_ID, credentialId)
.detail(Details.CUSTOM_REQUIRED_ACTION, DeleteCredentialAction.PROVIDER_ID)
.assertEvent();
events.expect(EventType.REMOVE_CREDENTIAL)
.user(userId)
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE)
.detail(Details.CREDENTIAL_ID, credentialId)
.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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
*/
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.graphene.page.Page;
import org.junit.After;
Expand All @@ -26,6 +29,7 @@
import org.keycloak.cookie.CookieType;
import org.keycloak.events.Details;
import org.keycloak.events.EventType;
import org.keycloak.events.email.EmailEventListenerProviderFactory;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.credential.PasswordCredentialModel;
Expand All @@ -35,7 +39,10 @@
import org.keycloak.representations.idm.UserSessionRepresentation;
import org.keycloak.testsuite.admin.ApiUtil;
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.MailUtils;
import org.keycloak.testsuite.util.OAuthClient;
import org.keycloak.testsuite.util.SecondBrowser;
import org.openqa.selenium.Cookie;
Expand Down Expand Up @@ -81,48 +88,66 @@ public void after() {

@Test
public void resetPassword() throws Exception {
loginPage.open();
loginPage.login("test-user@localhost", "password");
try (RealmAttributeUpdater realmUpdater = new RealmAttributeUpdater(testRealm())
.addEventsListener(EmailEventListenerProviderFactory.ID)
.update();
UserAttributeUpdater userUpdater = new UserAttributeUpdater(ApiUtil.findUserByUsernameId(testRealm(), "test-user@localhost"))
.setEmailVerified(true)
.update()) {

events.expectLogin().assertEvent();
loginPage.open();
loginPage.login("test-user@localhost", "password");

doAIA();
events.expectLogin().assertEvent();

changePasswordPage.assertCurrent();
assertTrue(changePasswordPage.isCancelDisplayed());
doAIA();

Cookie authSessionCookie = driver.manage().getCookieNamed(CookieType.AUTH_SESSION_ID.getName());
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.assertCurrent();
assertTrue(changePasswordPage.isCancelDisplayed());

changePasswordPage.changePassword("new-password", "new-password");
Cookie authSessionCookie = driver.manage().getCookieNamed(CookieType.AUTH_SESSION_ID.getName());
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 -> {
// ensure that the authentication session has been terminated
RealmModel realm = session.realms().getRealm(TEST_REALM_NAME);
assertNull(session.authenticationSessions().getRootAuthenticationSession(realm, authSessionId));
});

events.expectRequiredAction(EventType.UPDATE_PASSWORD).assertEvent();
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).assertEvent();
events.expectRequiredAction(EventType.UPDATE_PASSWORD).assertEvent();
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).assertEvent();

assertKcActionStatus(SUCCESS);
MimeMessage[] receivedMessages = greenMail.getReceivedMessages();
Assert.assertEquals(2, receivedMessages.length);

Assert.assertEquals("Update password", receivedMessages[0].getSubject());
Assert.assertEquals("Update credential", receivedMessages[1].getSubject());
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"));

EventRepresentation loginEvent = events.expectLogin().assertEvent();
assertKcActionStatus(SUCCESS);

OAuthClient.AccessTokenResponse tokenResponse = sendTokenRequestAndGetResponse(loginEvent);
oauth.idTokenHint(tokenResponse.getIdToken()).openLogout();
EventRepresentation loginEvent = events.expectLogin().assertEvent();

events.expectLogout(loginEvent.getSessionId()).assertEvent();
OAuthClient.AccessTokenResponse tokenResponse = sendTokenRequestAndGetResponse(loginEvent);
oauth.idTokenHint(tokenResponse.getIdToken()).openLogout();

loginPage.open();
loginPage.login("test-user@localhost", "new-password");
events.expectLogout(loginEvent.getSessionId()).assertEvent();

events.expectLogin().assertEvent();
loginPage.open();
loginPage.login("test-user@localhost", "new-password");

events.expectLogin().assertEvent();
}
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<#import "template.ftl" as layout>
<@layout.emailLayout>
${kcSanitize(msg("eventRemoveCredentialBodyHtml", event.details.credential_type!"unknown", event.date, event.ipAddress))?no_esc}
${kcSanitize(msg("eventRemoveCredentialBodyHtml", event.getDetail("credential_type")!"unknown", event.date, event.ipAddress))?no_esc}
</@layout.emailLayout>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<#import "template.ftl" as layout>
<@layout.emailLayout>
${kcSanitize(msg("eventUpdateCredentialBodyHtml", event.details.credential_type!"unknown", event.date, event.ipAddress))?no_esc}
${kcSanitize(msg("eventUpdateCredentialBodyHtml", event.getDetail("credential_type")!"unknown", event.date, event.ipAddress))?no_esc}
</@layout.emailLayout>
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
<#ftl output_format="plainText">
${msg("eventRemoveCredentialBody", event.details.credential_type!"unknown", event.date, event.ipAddress)}
${msg("eventRemoveCredentialBody", event.getDetail("credential_type")!"unknown", event.date, event.ipAddress)}
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
<#ftl output_format="plainText">
${msg("eventUpdateCredentialBody", event.details.credential_type!"unknown", event.date, event.ipAddress)}
${msg("eventUpdateCredentialBody", event.getDetail("credential_type")!"unknown", event.date, event.ipAddress)}

0 comments on commit 5aa874e

Please sign in to comment.