introduce event types to update/remove credentials
Closes #10114 Signed-off-by: Theresa Henze <theresa.henze@bare.id>
This commit is contained in:
parent
ba861fc5d7
commit
a1c23fef8c
43 changed files with 464 additions and 133 deletions
|
@ -162,3 +162,9 @@ In {project_name} 26, this feature is enabled by default. This means that all us
|
|||
It is possible to revert this behavior to the previous state by disabling the feature. Follow the `Volatile user sessions` section in https://www.keycloak.org/server/caching[Configuring distributed caches] guide for more details.
|
||||
|
||||
For information on how to upgrade, see the link:{upgradingguide_link}[{upgradingguide_name}].
|
||||
|
||||
= New generalized event types for credentials
|
||||
|
||||
There are now generalized events for updating (`UPDATE_CREDENTIAL`) and removing (`REMOVE_CREDENTIAL`) a credential. The credential type is described in the `credential_type` attribute of the events. The new event types are supported by the Email Event Listener.
|
||||
|
||||
The following event types are now deprecated and will be removed in a future version: `UPDATE_PASSWORD`, `UPDATE_PASSWORD_ERROR`, `UPDATE_TOTP`, `UPDATE_TOTP_ERROR`, `REMOVE_TOTP`, `REMOVE_TOTP_ERROR`
|
||||
|
|
|
@ -492,13 +492,13 @@ You can turn on storage for all available ERROR events, not including auditing e
|
|||
+
|
||||
[options="nowrap"]
|
||||
----
|
||||
$ kcadm.sh update events/config -r demorealm -s eventsEnabled=true -s 'enabledEventTypes=["LOGIN_ERROR","REGISTER_ERROR","LOGOUT_ERROR","CODE_TO_TOKEN_ERROR","CLIENT_LOGIN_ERROR","FEDERATED_IDENTITY_LINK_ERROR","REMOVE_FEDERATED_IDENTITY_ERROR","UPDATE_EMAIL_ERROR","UPDATE_PROFILE_ERROR","UPDATE_PASSWORD_ERROR","UPDATE_TOTP_ERROR","VERIFY_EMAIL_ERROR","REMOVE_TOTP_ERROR","SEND_VERIFY_EMAIL_ERROR","SEND_RESET_PASSWORD_ERROR","SEND_IDENTITY_PROVIDER_LINK_ERROR","RESET_PASSWORD_ERROR","IDENTITY_PROVIDER_FIRST_LOGIN_ERROR","IDENTITY_PROVIDER_POST_LOGIN_ERROR","CUSTOM_REQUIRED_ACTION_ERROR","EXECUTE_ACTIONS_ERROR","CLIENT_REGISTER_ERROR","CLIENT_UPDATE_ERROR","CLIENT_DELETE_ERROR"]' -s eventsExpiration=172800
|
||||
$ kcadm.sh update events/config -r demorealm -s eventsEnabled=true -s 'enabledEventTypes=["LOGIN_ERROR","REGISTER_ERROR","LOGOUT_ERROR","CODE_TO_TOKEN_ERROR","CLIENT_LOGIN_ERROR","FEDERATED_IDENTITY_LINK_ERROR","REMOVE_FEDERATED_IDENTITY_ERROR","UPDATE_EMAIL_ERROR","UPDATE_PROFILE_ERROR","UPDATE_PASSWORD_ERROR","UPDATE_TOTP_ERROR","UPDATE_CREDENTIAL_ERROR","VERIFY_EMAIL_ERROR","REMOVE_TOTP_ERROR","REMOVE_CREDENTIAL_ERROR","SEND_VERIFY_EMAIL_ERROR","SEND_RESET_PASSWORD_ERROR","SEND_IDENTITY_PROVIDER_LINK_ERROR","RESET_PASSWORD_ERROR","IDENTITY_PROVIDER_FIRST_LOGIN_ERROR","IDENTITY_PROVIDER_POST_LOGIN_ERROR","CUSTOM_REQUIRED_ACTION_ERROR","EXECUTE_ACTIONS_ERROR","CLIENT_REGISTER_ERROR","CLIENT_UPDATE_ERROR","CLIENT_DELETE_ERROR"]' -s eventsExpiration=172800
|
||||
----
|
||||
* Windows:
|
||||
+
|
||||
[options="nowrap"]
|
||||
----
|
||||
c:\> kcadm update events/config -r demorealm -s eventsEnabled=true -s "enabledEventTypes=[\"LOGIN_ERROR\",\"REGISTER_ERROR\",\"LOGOUT_ERROR\",\"CODE_TO_TOKEN_ERROR\",\"CLIENT_LOGIN_ERROR\",\"FEDERATED_IDENTITY_LINK_ERROR\",\"REMOVE_FEDERATED_IDENTITY_ERROR\",\"UPDATE_EMAIL_ERROR\",\"UPDATE_PROFILE_ERROR\",\"UPDATE_PASSWORD_ERROR\",\"UPDATE_TOTP_ERROR\",\"VERIFY_EMAIL_ERROR\",\"REMOVE_TOTP_ERROR\",\"SEND_VERIFY_EMAIL_ERROR\",\"SEND_RESET_PASSWORD_ERROR\",\"SEND_IDENTITY_PROVIDER_LINK_ERROR\",\"RESET_PASSWORD_ERROR\",\"IDENTITY_PROVIDER_FIRST_LOGIN_ERROR\",\"IDENTITY_PROVIDER_POST_LOGIN_ERROR\",\"CUSTOM_REQUIRED_ACTION_ERROR\",\"EXECUTE_ACTIONS_ERROR\",\"CLIENT_REGISTER_ERROR\",\"CLIENT_UPDATE_ERROR\",\"CLIENT_DELETE_ERROR\"]" -s eventsExpiration=172800
|
||||
c:\> kcadm update events/config -r demorealm -s eventsEnabled=true -s "enabledEventTypes=[\"LOGIN_ERROR\",\"REGISTER_ERROR\",\"LOGOUT_ERROR\",\"CODE_TO_TOKEN_ERROR\",\"CLIENT_LOGIN_ERROR\",\"FEDERATED_IDENTITY_LINK_ERROR\",\"REMOVE_FEDERATED_IDENTITY_ERROR\",\"UPDATE_EMAIL_ERROR\",\"UPDATE_PROFILE_ERROR\",\"UPDATE_PASSWORD_ERROR\",\"UPDATE_TOTP_ERROR\",\"UPDATE_CREDENTIAL_ERROR\",\"VERIFY_EMAIL_ERROR\",\"REMOVE_TOTP_ERROR\",\"REMOVE_CREDENTIAL_ERROR\",\"SEND_VERIFY_EMAIL_ERROR\",\"SEND_RESET_PASSWORD_ERROR\",\"SEND_IDENTITY_PROVIDER_LINK_ERROR\",\"RESET_PASSWORD_ERROR\",\"IDENTITY_PROVIDER_FIRST_LOGIN_ERROR\",\"IDENTITY_PROVIDER_POST_LOGIN_ERROR\",\"CUSTOM_REQUIRED_ACTION_ERROR\",\"EXECUTE_ACTIONS_ERROR\",\"CLIENT_REGISTER_ERROR\",\"CLIENT_UPDATE_ERROR\",\"CLIENT_DELETE_ERROR\"]" -s eventsExpiration=172800
|
||||
----
|
||||
|
||||
You can reset stored event types to *all available event types*. Setting the value to an empty list is the same as enumerating all.
|
||||
|
|
|
@ -123,15 +123,21 @@ image:images/search-user-event.png[Search user event]
|
|||
|Send Password Reset
|
||||
|{project_name} sends a password reset email.
|
||||
|
||||
|Update Password
|
||||
|Update Password (deprecated)
|
||||
|The password for an account changes.
|
||||
|
||||
|Update TOTP
|
||||
|Update Credential
|
||||
|The password or (time-based) one-time Password (OTP/TOTP) settings for an account changes.
|
||||
|
||||
|Update TOTP (deprecated)
|
||||
|The Time-based One-time Password (TOTP) settings for an account changes.
|
||||
|
||||
|Remove TOTP
|
||||
|Remove TOTP (deprecated)
|
||||
|{project_name} removes TOTP from an account.
|
||||
|
||||
|Remove Credential
|
||||
|{project_name} removes a credential from an account.
|
||||
|
||||
|Send Verify Email
|
||||
|{project_name} sends an email verification email.
|
||||
|
||||
|
@ -191,6 +197,8 @@ The Email Event Listener sends a message to the user's email address when an eve
|
|||
* Update Password.
|
||||
* Update Time-based One-time Password (TOTP).
|
||||
* Remove One-time Password (OTP).
|
||||
* Update Credential.
|
||||
* Remove Credential.
|
||||
|
||||
The following conditions need to be met for an email to be sent:
|
||||
|
||||
|
@ -217,6 +225,6 @@ You can exclude events by using the `--spi-events-listener-email-exclude-events`
|
|||
|
||||
[source,bash]
|
||||
----
|
||||
kc.[sh|bat] --spi-events-listener-email-exclude-events=UPDATE_TOTP,REMOVE_TOTP
|
||||
kc.[sh|bat] --spi-events-listener-email-exclude-events=UPDATE_CREDENTIAL,REMOVE_CREDENTIAL
|
||||
----
|
||||
|
||||
|
|
|
@ -242,3 +242,10 @@ As part of this change the following related configuration options for the SPI h
|
|||
- `--spi-login-protocol-openid-connect-suppress-logout-confirmation-screen`
|
||||
|
||||
If you were still making use these options or the `redirect_uri` parameter for logout you should implement the link:https://openid.net/specs/openid-connect-rpinitiated-1_0.html[OpenID Connect RP-Initiated Logout specification] instead.
|
||||
|
||||
= New generalized event types for credentials
|
||||
|
||||
There are now generalized events for updating (`UPDATE_CREDENTIAL`) and removing (`REMOVE_CREDENTIAL`) a credential. The credential type is described in the `credential_type` attribute of the events.
|
||||
The new event types are supported by the Email Event Listener.
|
||||
|
||||
The following event types are now deprecated and will be removed in a future version: `UPDATE_PASSWORD`, `UPDATE_PASSWORD_ERROR`, `UPDATE_TOTP`, `UPDATE_TOTP_ERROR`, `REMOVE_TOTP`, `REMOVE_TOTP_ERROR`
|
||||
|
|
|
@ -2134,7 +2134,7 @@
|
|||
"smtpServer" : { },
|
||||
"eventsEnabled" : false,
|
||||
"eventsListeners" : [ "jboss-logging" ],
|
||||
"enabledEventTypes" : [ "SEND_RESET_PASSWORD", "SEND_VERIFY_EMAIL", "EXECUTE_ACTIONS_ERROR", "REMOVE_FEDERATED_IDENTITY", "UPDATE_TOTP", "REMOVE_TOTP", "REVOKE_GRANT", "LOGIN_ERROR", "CLIENT_LOGIN", "RESET_PASSWORD_ERROR", "CODE_TO_TOKEN_ERROR", "CUSTOM_REQUIRED_ACTION", "UPDATE_EMAIL", "REGISTER_ERROR", "LOGOUT_ERROR", "UPDATE_EMAIL_ERROR", "UPDATE_PROFILE_ERROR", "IMPERSONATE", "LOGIN", "UPDATE_PASSWORD_ERROR", "CLIENT_UPDATE_ERROR", "UPDATE_PROFILE", "REGISTER", "LOGOUT", "FEDERATED_IDENTITY_LINK", "CLIENT_REGISTER_ERROR", "CLIENT_REGISTER", "SEND_VERIFY_EMAIL_ERROR", "UPDATE_PASSWORD", "RESET_PASSWORD", "FEDERATED_IDENTITY_LINK_ERROR", "CLIENT_DELETE", "REMOVE_TOTP_ERROR", "VERIFY_EMAIL_ERROR", "VERIFY_EMAIL", "SEND_RESET_PASSWORD_ERROR", "CLIENT_DELETE_ERROR", "CLIENT_LOGIN_ERROR", "CLIENT_UPDATE", "REMOVE_FEDERATED_IDENTITY_ERROR", "EXECUTE_ACTIONS", "CUSTOM_REQUIRED_ACTION_ERROR", "UPDATE_TOTP_ERROR", "CODE_TO_TOKEN" ],
|
||||
"enabledEventTypes" : [ "SEND_RESET_PASSWORD", "SEND_VERIFY_EMAIL", "EXECUTE_ACTIONS_ERROR", "REMOVE_FEDERATED_IDENTITY", "REMOVE_CREDENTIAL", "UPDATE_TOTP", "REMOVE_TOTP", "REVOKE_GRANT", "LOGIN_ERROR", "CLIENT_LOGIN", "RESET_PASSWORD_ERROR", "CODE_TO_TOKEN_ERROR", "CUSTOM_REQUIRED_ACTION", "UPDATE_EMAIL", "REGISTER_ERROR", "LOGOUT_ERROR", "UPDATE_EMAIL_ERROR", "UPDATE_PROFILE_ERROR", "IMPERSONATE", "LOGIN", "UPDATE_PASSWORD_ERROR", "UPDATE_CREDENTIAL_ERROR", "CLIENT_UPDATE_ERROR", "UPDATE_PROFILE", "REGISTER", "LOGOUT", "FEDERATED_IDENTITY_LINK", "CLIENT_REGISTER_ERROR", "CLIENT_REGISTER", "SEND_VERIFY_EMAIL_ERROR", "UPDATE_CREDENTIAL", "UPDATE_PASSWORD" ,"RESET_PASSWORD", "FEDERATED_IDENTITY_LINK_ERROR", "CLIENT_DELETE", "REMOVE_CREDENTIAL_ERROR", "REMOVE_TOTP_ERROR", "VERIFY_EMAIL_ERROR", "VERIFY_EMAIL", "SEND_RESET_PASSWORD_ERROR", "CLIENT_DELETE_ERROR", "CLIENT_LOGIN_ERROR", "CLIENT_UPDATE", "REMOVE_FEDERATED_IDENTITY_ERROR", "EXECUTE_ACTIONS", "CUSTOM_REQUIRED_ACTION_ERROR", "UPDATE_TOTP_ERROR", "CODE_TO_TOKEN" ],
|
||||
"adminEventsEnabled" : true,
|
||||
"adminEventsDetailsEnabled" : true,
|
||||
"identityProviders" : [ {
|
||||
|
@ -4210,7 +4210,7 @@
|
|||
"smtpServer" : { },
|
||||
"eventsEnabled" : false,
|
||||
"eventsListeners" : [ "jboss-logging" ],
|
||||
"enabledEventTypes" : [ "SEND_RESET_PASSWORD", "SEND_VERIFY_EMAIL", "EXECUTE_ACTIONS_ERROR", "REMOVE_FEDERATED_IDENTITY", "UPDATE_TOTP", "REMOVE_TOTP", "REVOKE_GRANT", "LOGIN_ERROR", "CLIENT_LOGIN", "RESET_PASSWORD_ERROR", "CODE_TO_TOKEN_ERROR", "CUSTOM_REQUIRED_ACTION", "UPDATE_EMAIL", "REGISTER_ERROR", "LOGOUT_ERROR", "UPDATE_EMAIL_ERROR", "UPDATE_PROFILE_ERROR", "IMPERSONATE", "LOGIN", "UPDATE_PASSWORD_ERROR", "CLIENT_UPDATE_ERROR", "UPDATE_PROFILE", "REGISTER", "LOGOUT", "FEDERATED_IDENTITY_LINK", "CLIENT_REGISTER_ERROR", "CLIENT_REGISTER", "SEND_VERIFY_EMAIL_ERROR", "UPDATE_PASSWORD", "RESET_PASSWORD", "FEDERATED_IDENTITY_LINK_ERROR", "CLIENT_DELETE", "REMOVE_TOTP_ERROR", "VERIFY_EMAIL_ERROR", "VERIFY_EMAIL", "SEND_RESET_PASSWORD_ERROR", "CLIENT_DELETE_ERROR", "CLIENT_LOGIN_ERROR", "CLIENT_UPDATE", "REMOVE_FEDERATED_IDENTITY_ERROR", "EXECUTE_ACTIONS", "CUSTOM_REQUIRED_ACTION_ERROR", "UPDATE_TOTP_ERROR", "CODE_TO_TOKEN" ],
|
||||
"enabledEventTypes" : [ "SEND_RESET_PASSWORD", "SEND_VERIFY_EMAIL", "EXECUTE_ACTIONS_ERROR", "REMOVE_FEDERATED_IDENTITY", "REMOVE_CREDENTIAL", "UPDATE_TOTP", "REMOVE_TOTP", "REVOKE_GRANT", "LOGIN_ERROR", "CLIENT_LOGIN", "RESET_PASSWORD_ERROR", "CODE_TO_TOKEN_ERROR", "CUSTOM_REQUIRED_ACTION", "UPDATE_EMAIL", "REGISTER_ERROR", "LOGOUT_ERROR", "UPDATE_EMAIL_ERROR", "UPDATE_PROFILE_ERROR", "IMPERSONATE", "LOGIN", "UPDATE_PASSWORD_ERROR", "UPDATE_CREDENTIAL_ERROR", "CLIENT_UPDATE_ERROR", "UPDATE_PROFILE", "REGISTER", "LOGOUT", "FEDERATED_IDENTITY_LINK", "CLIENT_REGISTER_ERROR", "CLIENT_REGISTER", "SEND_VERIFY_EMAIL_ERROR", "UPDATE_CREDENTIAL", "UPDATE_PASSWORD", "RESET_PASSWORD", "FEDERATED_IDENTITY_LINK_ERROR", "CLIENT_DELETE", "REMOVE_CREDENTIAL_ERROR", "REMOVE_TOTP_ERROR", "VERIFY_EMAIL_ERROR", "VERIFY_EMAIL", "SEND_RESET_PASSWORD_ERROR", "CLIENT_DELETE_ERROR", "CLIENT_LOGIN_ERROR", "CLIENT_UPDATE", "REMOVE_FEDERATED_IDENTITY_ERROR", "EXECUTE_ACTIONS", "CUSTOM_REQUIRED_ACTION_ERROR", "UPDATE_TOTP_ERROR", "CODE_TO_TOKEN" ],
|
||||
"adminEventsEnabled" : true,
|
||||
"adminEventsDetailsEnabled" : true,
|
||||
"identityProviders" : [ {
|
||||
|
|
|
@ -3242,3 +3242,11 @@ addOrganizationAttributes.label=Add organization attributes
|
|||
addOrganizationAttributes.help=If enabled, the organization attributes will be available for each organization mapped to the token.
|
||||
disableConfirmUserTitle=Disable user?
|
||||
disableConfirmUser=Are you sure you want to disable this user?
|
||||
eventTypes.UPDATE_CREDENTIAL.name=Update credential
|
||||
eventTypes.UPDATE_CREDENTIAL.description=Update credential
|
||||
eventTypes.UPDATE_CREDENTIAL_ERROR.name=Update credential error
|
||||
eventTypes.UPDATE_CREDENTIAL_ERROR.description=Update credential error
|
||||
eventTypes.REMOVE_CREDENTIAL.name=Remove credential
|
||||
eventTypes.REMOVE_CREDENTIAL.description=Remove credential
|
||||
eventTypes.REMOVE_CREDENTIAL_ERROR.name=Remove credential error
|
||||
eventTypes.REMOVE_CREDENTIAL_ERROR.description=Remove credential error
|
|
@ -7212,6 +7212,8 @@
|
|||
"REMOVE_FEDERATED_IDENTITY_ERROR",
|
||||
"REMOVE_TOTP",
|
||||
"REMOVE_TOTP_ERROR",
|
||||
"REMOVE_CREDENTIAL",
|
||||
"REMOVE_CREDENTIAL_ERROR",
|
||||
"RESET_PASSWORD",
|
||||
"RESET_PASSWORD_ERROR",
|
||||
"RESTART_AUTHENTICATION",
|
||||
|
@ -7234,6 +7236,8 @@
|
|||
"UPDATE_EMAIL_ERROR",
|
||||
"UPDATE_PASSWORD",
|
||||
"UPDATE_PASSWORD_ERROR",
|
||||
"UPDATE_CREDENTIAL",
|
||||
"UPDATE_CREDENTIAL_ERROR",
|
||||
"UPDATE_PROFILE",
|
||||
"UPDATE_PROFILE_ERROR",
|
||||
"UPDATE_TOTP",
|
||||
|
|
|
@ -7074,6 +7074,8 @@
|
|||
"REMOVE_FEDERATED_IDENTITY_ERROR",
|
||||
"REMOVE_TOTP",
|
||||
"REMOVE_TOTP_ERROR",
|
||||
"REMOVE_CREDENTIAL",
|
||||
"REMOVE_CREDENTIAL_ERROR",
|
||||
"RESET_PASSWORD",
|
||||
"RESET_PASSWORD_ERROR",
|
||||
"RESTART_AUTHENTICATION",
|
||||
|
@ -7096,6 +7098,8 @@
|
|||
"UPDATE_EMAIL_ERROR",
|
||||
"UPDATE_PASSWORD",
|
||||
"UPDATE_PASSWORD_ERROR",
|
||||
"UPDATE_CREDENTIAL",
|
||||
"UPDATE_CREDENTIAL_ERROR",
|
||||
"UPDATE_PROFILE",
|
||||
"UPDATE_PROFILE_ERROR",
|
||||
"UPDATE_TOTP",
|
||||
|
|
|
@ -84,6 +84,10 @@ type EventType =
|
|||
| "TOKEN_EXCHANGE"
|
||||
| "TOKEN_EXCHANGE_ERROR"
|
||||
| "PERMISSION_TOKEN"
|
||||
| "PERMISSION_TOKEN_ERROR";
|
||||
| "PERMISSION_TOKEN_ERROR"
|
||||
| "UPDATE_CREDENTIAL"
|
||||
| "UPDATE_CREDENTIAL_ERROR"
|
||||
| "REMOVE_CREDENTIAL"
|
||||
| "REMOVE_CREDENTIAL_ERROR";
|
||||
|
||||
export default EventType;
|
||||
|
|
|
@ -62,16 +62,24 @@ public enum EventType implements EnumWithStableIndex {
|
|||
UPDATE_EMAIL_ERROR(0x10000 + UPDATE_EMAIL.getStableIndex(), true),
|
||||
UPDATE_PROFILE(11, true),
|
||||
UPDATE_PROFILE_ERROR(0x10000 + UPDATE_PROFILE.getStableIndex(), true),
|
||||
|
||||
@Deprecated
|
||||
UPDATE_PASSWORD(12, true),
|
||||
@Deprecated
|
||||
UPDATE_PASSWORD_ERROR(0x10000 + UPDATE_PASSWORD.getStableIndex(), true),
|
||||
|
||||
@Deprecated
|
||||
UPDATE_TOTP(13, true),
|
||||
@Deprecated
|
||||
UPDATE_TOTP_ERROR(0x10000 + UPDATE_TOTP.getStableIndex(), true),
|
||||
VERIFY_EMAIL(14, true),
|
||||
VERIFY_EMAIL_ERROR(0x10000 + VERIFY_EMAIL.getStableIndex(), true),
|
||||
VERIFY_PROFILE(15, true),
|
||||
VERIFY_PROFILE_ERROR(0x10000 + VERIFY_PROFILE.getStableIndex(), true),
|
||||
|
||||
@Deprecated
|
||||
REMOVE_TOTP(16, true),
|
||||
@Deprecated
|
||||
REMOVE_TOTP_ERROR(0x10000 + REMOVE_TOTP.getStableIndex(), true),
|
||||
|
||||
GRANT_CONSENT(17, true),
|
||||
|
@ -169,6 +177,13 @@ public enum EventType implements EnumWithStableIndex {
|
|||
|
||||
FEDERATED_IDENTITY_OVERRIDE_LINK(55, true),
|
||||
FEDERATED_IDENTITY_OVERRIDE_LINK_ERROR(0x10000 + FEDERATED_IDENTITY_OVERRIDE_LINK.getStableIndex(), true),
|
||||
|
||||
UPDATE_CREDENTIAL(56, true),
|
||||
UPDATE_CREDENTIAL_ERROR(0x10000 + UPDATE_CREDENTIAL.getStableIndex(), true),
|
||||
|
||||
REMOVE_CREDENTIAL(57, true),
|
||||
REMOVE_CREDENTIAL_ERROR(0x10000 + REMOVE_CREDENTIAL.getStableIndex(), true),
|
||||
|
||||
INVITE_ORG(60, true),
|
||||
INVITE_ORG_ERROR(0x10000 + INVITE_ORG.getStableIndex(), true);
|
||||
|
||||
|
|
|
@ -143,28 +143,31 @@ public class DeleteCredentialAction implements RequiredActionProvider, RequiredA
|
|||
context.challenge(challenge);
|
||||
}
|
||||
|
||||
private void setupEvent(CredentialModel credential, EventBuilder event) {
|
||||
if (credential != null) {
|
||||
if (OTPCredentialModel.TYPE.equals(credential.getType())) {
|
||||
event.event(EventType.REMOVE_TOTP);
|
||||
}
|
||||
event.detail(Details.CREDENTIAL_TYPE, credential.getType())
|
||||
.detail(Details.CREDENTIAL_ID, credential.getId())
|
||||
.detail(Details.CREDENTIAL_USER_LABEL, credential.getUserLabel());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processAction(RequiredActionContext context) {
|
||||
EventBuilder event = context.getEvent();
|
||||
event.event(EventType.REMOVE_CREDENTIAL);
|
||||
|
||||
EventBuilder deprecatedEvent = null;
|
||||
String credentialId = context.getAuthenticationSession().getClientNote(Constants.KC_ACTION_PARAMETER);
|
||||
|
||||
CredentialModel credential = context.getUser().credentialManager().getStoredCredentialById(credentialId);
|
||||
setupEvent(credential, event);
|
||||
if (credential != null) {
|
||||
event
|
||||
.detail(Details.CREDENTIAL_TYPE, credential.getType())
|
||||
.detail(Details.CREDENTIAL_ID, credential.getId())
|
||||
.detail(Details.CREDENTIAL_USER_LABEL, credential.getUserLabel());
|
||||
if (OTPCredentialModel.TYPE.equals(credential.getType())) {
|
||||
deprecatedEvent = event.clone().event(EventType.REMOVE_TOTP);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
CredentialDeleteHelper.removeCredential(context.getSession(), context.getUser(), credentialId, () -> getCurrentLoa(context.getSession(), context.getAuthenticationSession()));
|
||||
context.success();
|
||||
if (deprecatedEvent != null) {
|
||||
deprecatedEvent.success();
|
||||
}
|
||||
|
||||
} catch (WebApplicationException wae) {
|
||||
Response response = context.getSession().getProvider(LoginFormsProvider.class)
|
||||
|
@ -174,6 +177,10 @@ public class DeleteCredentialAction implements RequiredActionProvider, RequiredA
|
|||
.createErrorPage(Response.Status.BAD_REQUEST);
|
||||
event.detail(Details.REASON, wae.getMessage())
|
||||
.error(Errors.DELETE_CREDENTIAL_FAILED);
|
||||
if (deprecatedEvent != null) {
|
||||
deprecatedEvent.detail(Details.REASON, wae.getMessage())
|
||||
.error(Errors.DELETE_CREDENTIAL_FAILED);
|
||||
}
|
||||
context.challenge(response);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ import org.keycloak.models.RequiredActionConfigModel;
|
|||
import org.keycloak.models.RequiredActionProviderModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.credential.PasswordCredentialModel;
|
||||
import org.keycloak.models.utils.FormMessage;
|
||||
import org.keycloak.policy.MaxAuthAgePasswordPolicyProviderFactory;
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
|
@ -147,13 +148,18 @@ public class UpdatePassword implements RequiredActionProvider, RequiredActionFac
|
|||
AuthenticationSessionModel authSession = context.getAuthenticationSession();
|
||||
UserModel user = context.getUser();
|
||||
MultivaluedMap<String, String> formData = context.getHttpRequest().getDecodedFormParameters();
|
||||
event.event(EventType.UPDATE_PASSWORD);
|
||||
|
||||
event.event(EventType.UPDATE_CREDENTIAL);
|
||||
event.detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.PASSWORD);
|
||||
EventBuilder deprecatedEvent = event.clone().event(EventType.UPDATE_PASSWORD);
|
||||
|
||||
String passwordNew = formData.getFirst("password-new");
|
||||
String passwordConfirm = formData.getFirst("password-confirm");
|
||||
|
||||
EventBuilder errorEvent = event.clone().event(EventType.UPDATE_PASSWORD_ERROR)
|
||||
EventBuilder errorEvent = event.clone().event(EventType.UPDATE_CREDENTIAL_ERROR)
|
||||
.client(authSession.getClient())
|
||||
.user(authSession.getAuthenticatedUser());
|
||||
EventBuilder deprecatedErrorEvent = errorEvent.clone().event(EventType.UPDATE_PASSWORD_ERROR);
|
||||
|
||||
if (Validation.isBlank(passwordNew)) {
|
||||
Response challenge = context.form()
|
||||
|
@ -162,6 +168,7 @@ public class UpdatePassword implements RequiredActionProvider, RequiredActionFac
|
|||
.createResponse(UserModel.RequiredAction.UPDATE_PASSWORD);
|
||||
context.challenge(challenge);
|
||||
errorEvent.error(Errors.PASSWORD_MISSING);
|
||||
deprecatedErrorEvent.error(Errors.PASSWORD_MISSING);
|
||||
return;
|
||||
} else if (!passwordNew.equals(passwordConfirm)) {
|
||||
Response challenge = context.form()
|
||||
|
@ -170,6 +177,7 @@ public class UpdatePassword implements RequiredActionProvider, RequiredActionFac
|
|||
.createResponse(UserModel.RequiredAction.UPDATE_PASSWORD);
|
||||
context.challenge(challenge);
|
||||
errorEvent.error(Errors.PASSWORD_CONFIRM_ERROR);
|
||||
deprecatedErrorEvent.error(Errors.PASSWORD_CONFIRM_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -180,8 +188,10 @@ public class UpdatePassword implements RequiredActionProvider, RequiredActionFac
|
|||
try {
|
||||
user.credentialManager().updateCredential(UserCredentialModel.password(passwordNew, false));
|
||||
context.success();
|
||||
deprecatedEvent.success();
|
||||
} catch (ModelException me) {
|
||||
errorEvent.detail(Details.REASON, me.getMessage()).error(Errors.PASSWORD_REJECTED);
|
||||
deprecatedErrorEvent.detail(Details.REASON, me.getMessage()).error(Errors.PASSWORD_REJECTED);
|
||||
Response challenge = context.form()
|
||||
.setAttribute("username", authSession.getAuthenticatedUser().getUsername())
|
||||
.setError(me.getMessage(), me.getParameters())
|
||||
|
@ -190,6 +200,7 @@ public class UpdatePassword implements RequiredActionProvider, RequiredActionFac
|
|||
return;
|
||||
} catch (Exception ape) {
|
||||
errorEvent.detail(Details.REASON, ape.getMessage()).error(Errors.PASSWORD_REJECTED);
|
||||
deprecatedErrorEvent.detail(Details.REASON, ape.getMessage()).error(Errors.PASSWORD_REJECTED);
|
||||
Response challenge = context.form()
|
||||
.setAttribute("username", authSession.getAuthenticatedUser().getUsername())
|
||||
.setError(ape.getMessage())
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.keycloak.authentication.RequiredActionProvider;
|
|||
import org.keycloak.credential.CredentialModel;
|
||||
import org.keycloak.credential.CredentialProvider;
|
||||
import org.keycloak.credential.OTPCredentialProvider;
|
||||
import org.keycloak.events.Details;
|
||||
import org.keycloak.events.EventBuilder;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
@ -71,7 +72,7 @@ public class UpdateTotp implements RequiredActionProvider, RequiredActionFactory
|
|||
@Override
|
||||
public void processAction(RequiredActionContext context) {
|
||||
EventBuilder event = context.getEvent();
|
||||
event.event(EventType.UPDATE_TOTP);
|
||||
event.event(EventType.UPDATE_CREDENTIAL);
|
||||
MultivaluedMap<String, String> formData = context.getHttpRequest().getDecodedFormParameters();
|
||||
String challengeResponse = formData.getFirst("totp");
|
||||
String totpSecret = formData.getFirst("totpSecret");
|
||||
|
@ -80,6 +81,9 @@ public class UpdateTotp implements RequiredActionProvider, RequiredActionFactory
|
|||
|
||||
OTPPolicy policy = context.getRealm().getOTPPolicy();
|
||||
OTPCredentialModel credentialModel = OTPCredentialModel.createFromPolicy(context.getRealm(), totpSecret, userLabel);
|
||||
event.detail(Details.CREDENTIAL_TYPE, credentialModel.getType());
|
||||
|
||||
EventBuilder deprecatedEvent = event.clone().event(EventType.UPDATE_TOTP);
|
||||
if (Validation.isBlank(challengeResponse)) {
|
||||
Response challenge = context.form()
|
||||
.setAttribute("mode", mode)
|
||||
|
@ -122,6 +126,7 @@ public class UpdateTotp implements RequiredActionProvider, RequiredActionFactory
|
|||
}
|
||||
context.getAuthenticationSession().removeAuthNote(Constants.TOTP_SECRET_KEY);
|
||||
context.success();
|
||||
deprecatedEvent.success();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -33,6 +33,8 @@ import jakarta.ws.rs.core.Response;
|
|||
import com.webauthn4j.WebAuthnRegistrationManager;
|
||||
import com.webauthn4j.data.AuthenticatorTransport;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.events.EventBuilder;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.http.HttpRequest;
|
||||
import org.keycloak.WebAuthnConstants;
|
||||
import org.keycloak.authentication.AuthenticatorUtil;
|
||||
|
@ -184,6 +186,15 @@ public class WebAuthnRegister implements RequiredActionProvider, CredentialRegis
|
|||
return WebAuthnCredentialProviderFactory.PROVIDER_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to provide removal and deprecation hint
|
||||
* @deprecated For compatibility sake as long as we use @link {@link EventType#UPDATE_PASSWORD} , {@link EventType#UPDATE_TOTP} a.s.o.
|
||||
*/
|
||||
@Deprecated
|
||||
protected EventType getOriginalEventTypeForBackwardsCompatibility(RequiredActionContext context) {
|
||||
return context.getEvent().getEvent().getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processAction(RequiredActionContext context) {
|
||||
|
||||
|
@ -195,12 +206,15 @@ public class WebAuthnRegister implements RequiredActionProvider, CredentialRegis
|
|||
return;
|
||||
}
|
||||
|
||||
context.getEvent().detail(Details.CREDENTIAL_TYPE, getCredentialType());
|
||||
EventType originalEventType = getOriginalEventTypeForBackwardsCompatibility(context);
|
||||
context.getEvent()
|
||||
.event(EventType.UPDATE_CREDENTIAL)
|
||||
.detail(Details.CREDENTIAL_TYPE, getCredentialType());
|
||||
|
||||
// receive error from navigator.credentials.create()
|
||||
String errorMsgFromWebAuthnApi = params.getFirst(WebAuthnConstants.ERROR);
|
||||
if (errorMsgFromWebAuthnApi != null && !errorMsgFromWebAuthnApi.isEmpty()) {
|
||||
setErrorResponse(context, WEBAUTHN_ERROR_REGISTER_VERIFICATION, errorMsgFromWebAuthnApi);
|
||||
setErrorResponse(context, WEBAUTHN_ERROR_REGISTER_VERIFICATION, errorMsgFromWebAuthnApi, originalEventType);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -269,14 +283,15 @@ public class WebAuthnRegister implements RequiredActionProvider, CredentialRegis
|
|||
.detail(WebAuthnConstants.PUBKEY_CRED_ID_ATTR, publicKeyCredentialId)
|
||||
.detail(WebAuthnConstants.PUBKEY_CRED_LABEL_ATTR, label)
|
||||
.detail(WebAuthnConstants.PUBKEY_CRED_AAGUID_ATTR, aaguid);
|
||||
context.getEvent().clone().event(originalEventType).success();
|
||||
context.success();
|
||||
} catch (WebAuthnException wae) {
|
||||
if (logger.isDebugEnabled()) logger.debug(wae.getMessage(), wae);
|
||||
setErrorResponse(context, WEBAUTHN_ERROR_REGISTRATION, wae.getMessage());
|
||||
setErrorResponse(context, WEBAUTHN_ERROR_REGISTRATION, wae.getMessage(), originalEventType);
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
if (logger.isDebugEnabled()) logger.debug(e.getMessage(), e);
|
||||
setErrorResponse(context, WEBAUTHN_ERROR_REGISTRATION, e.getMessage());
|
||||
setErrorResponse(context, WEBAUTHN_ERROR_REGISTRATION, e.getMessage(), originalEventType);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -387,15 +402,17 @@ public class WebAuthnRegister implements RequiredActionProvider, CredentialRegis
|
|||
// NOP
|
||||
}
|
||||
|
||||
private void setErrorResponse(RequiredActionContext context, final String errorCase, final String errorMessage) {
|
||||
private void setErrorResponse(RequiredActionContext context, final String errorCase, final String errorMessage, @Deprecated final EventType originalEventType) {
|
||||
Response errorResponse = null;
|
||||
switch (errorCase) {
|
||||
case WEBAUTHN_ERROR_REGISTER_VERIFICATION:
|
||||
logger.warnv("WebAuthn API .create() response validation failure. {0}", errorMessage);
|
||||
context.getEvent()
|
||||
EventBuilder registerVerificationEvent = context.getEvent()
|
||||
.detail(REG_ERR_LABEL, errorCase)
|
||||
.detail(REG_ERR_DETAIL_LABEL, errorMessage)
|
||||
.error(Errors.INVALID_USER_CREDENTIALS);
|
||||
.detail(REG_ERR_DETAIL_LABEL, errorMessage);
|
||||
EventBuilder deprecatedRegisterVerificationEvent = registerVerificationEvent.clone().event(originalEventType);
|
||||
registerVerificationEvent.error(Errors.INVALID_USER_CREDENTIALS);
|
||||
deprecatedRegisterVerificationEvent.error(Errors.INVALID_USER_CREDENTIALS);
|
||||
errorResponse = context.form()
|
||||
.setError(errorCase, errorMessage)
|
||||
.setAttribute(WEB_AUTHN_TITLE_ATTR, WEBAUTHN_REGISTER_TITLE)
|
||||
|
@ -404,10 +421,12 @@ public class WebAuthnRegister implements RequiredActionProvider, CredentialRegis
|
|||
break;
|
||||
case WEBAUTHN_ERROR_REGISTRATION:
|
||||
logger.warn(errorCase);
|
||||
context.getEvent()
|
||||
.detail(REG_ERR_LABEL, errorCase)
|
||||
.detail(REG_ERR_DETAIL_LABEL, errorMessage)
|
||||
.error(Errors.INVALID_REGISTRATION);
|
||||
EventBuilder registrationEvent = context.getEvent()
|
||||
.detail(REG_ERR_LABEL, errorCase)
|
||||
.detail(REG_ERR_DETAIL_LABEL, errorMessage);
|
||||
EventBuilder deprecatedRegistrationEvent = registrationEvent.clone().event(originalEventType);
|
||||
deprecatedRegistrationEvent.error(Errors.INVALID_REGISTRATION);
|
||||
registrationEvent.error(Errors.INVALID_REGISTRATION);
|
||||
errorResponse = context.form()
|
||||
.setError(errorCase, errorMessage)
|
||||
.setAttribute(WEB_AUTHN_TITLE_ATTR, WEBAUTHN_REGISTER_TITLE)
|
||||
|
|
|
@ -44,7 +44,7 @@ public class EmailEventListenerProviderFactory implements EventListenerProviderF
|
|||
public static final String ID = "email";
|
||||
|
||||
static {
|
||||
Collections.addAll(SUPPORTED_EVENTS, EventType.LOGIN_ERROR, EventType.UPDATE_PASSWORD, EventType.REMOVE_TOTP, EventType.UPDATE_TOTP);
|
||||
Collections.addAll(SUPPORTED_EVENTS, EventType.LOGIN_ERROR, EventType.UPDATE_PASSWORD, EventType.REMOVE_TOTP, EventType.UPDATE_TOTP, EventType.UPDATE_CREDENTIAL, EventType.REMOVE_CREDENTIAL);
|
||||
}
|
||||
|
||||
private Set<EventType> includedEvents = new HashSet<>();
|
||||
|
|
|
@ -307,10 +307,14 @@ public class AccountCredentialResource {
|
|||
realm.getName());
|
||||
CredentialModel credential = CredentialDeleteHelper.removeCredential(session, user, credentialId, this::getCurrentAuthenticatedLevel);
|
||||
|
||||
if (credential != null && OTPCredentialModel.TYPE.equals(credential.getType())) {
|
||||
event.event(EventType.REMOVE_TOTP)
|
||||
if (credential != null) {
|
||||
event.event(EventType.REMOVE_CREDENTIAL)
|
||||
.detail(Details.CREDENTIAL_TYPE, credential.getType())
|
||||
.detail(Details.SELECTED_CREDENTIAL_ID, credentialId)
|
||||
.detail(Details.CREDENTIAL_USER_LABEL, credential.getUserLabel());
|
||||
if (OTPCredentialModel.TYPE.equals(credential.getType())) {
|
||||
event.clone().event(EventType.REMOVE_TOTP).success();
|
||||
}
|
||||
event.success();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ public class Constants {
|
|||
|
||||
public static final EventType[] EXPOSED_LOG_EVENTS = {
|
||||
EventType.LOGIN, EventType.LOGOUT, EventType.REGISTER, EventType.REMOVE_FEDERATED_IDENTITY, EventType.REMOVE_TOTP, EventType.SEND_RESET_PASSWORD,
|
||||
EventType.SEND_VERIFY_EMAIL, EventType.FEDERATED_IDENTITY_LINK, EventType.UPDATE_EMAIL, EventType.UPDATE_PASSWORD, EventType.UPDATE_PROFILE, EventType.UPDATE_TOTP, EventType.VERIFY_EMAIL
|
||||
EventType.SEND_VERIFY_EMAIL, EventType.FEDERATED_IDENTITY_LINK, EventType.UPDATE_EMAIL, EventType.UPDATE_CREDENTIAL, EventType.REMOVE_CREDENTIAL, EventType.UPDATE_PROFILE, EventType.UPDATE_PASSWORD, EventType.UPDATE_PROFILE, EventType.UPDATE_TOTP, EventType.VERIFY_EMAIL
|
||||
};
|
||||
|
||||
public static final Set<String> EXPOSED_LOG_DETAILS = new HashSet<>();
|
||||
|
|
|
@ -886,6 +886,14 @@ public class AccountRestServiceTest extends AbstractRestServiceTest {
|
|||
.user(user.toRepresentation().getId())
|
||||
.detail(Details.SELECTED_CREDENTIAL_ID, otpCredential.getId())
|
||||
.detail(Details.CREDENTIAL_USER_LABEL, "totpCredentialUserLabel")
|
||||
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE)
|
||||
.assertEvent();
|
||||
events.expect(EventType.REMOVE_CREDENTIAL)
|
||||
.client("account")
|
||||
.user(user.toRepresentation().getId())
|
||||
.detail(Details.SELECTED_CREDENTIAL_ID, otpCredential.getId())
|
||||
.detail(Details.CREDENTIAL_USER_LABEL, "totpCredentialUserLabel")
|
||||
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE)
|
||||
.assertEvent();
|
||||
events.assertEmpty();
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ public class AppInitiatedActionDeleteCredentialTest extends AbstractAppInitiated
|
|||
}
|
||||
|
||||
@Test
|
||||
public void removeTotpSuccess() throws Exception {
|
||||
public void removeOtpSuccess() throws Exception {
|
||||
String credentialId = getCredentialIdByType(OTPCredentialModel.TYPE);
|
||||
oauth.kcAction(getKcActionParamForDeleteCredential(credentialId));
|
||||
|
||||
|
@ -113,10 +113,16 @@ public class AppInitiatedActionDeleteCredentialTest extends AbstractAppInitiated
|
|||
.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();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeTotpCancel() throws Exception {
|
||||
public void removeOtpCancel() throws Exception {
|
||||
String credentialId = getCredentialIdByType(OTPCredentialModel.TYPE);
|
||||
|
||||
loginPasswordAndOtp();
|
||||
|
@ -155,7 +161,7 @@ public class AppInitiatedActionDeleteCredentialTest extends AbstractAppInitiated
|
|||
|
||||
errorPage.assertCurrent();
|
||||
|
||||
events.expect(EventType.CUSTOM_REQUIRED_ACTION)
|
||||
events.expect(EventType.REMOVE_CREDENTIAL)
|
||||
.user(userId)
|
||||
.detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE)
|
||||
.detail(Details.CREDENTIAL_ID, credentialId)
|
||||
|
@ -218,7 +224,7 @@ public class AppInitiatedActionDeleteCredentialTest extends AbstractAppInitiated
|
|||
}
|
||||
|
||||
@Test
|
||||
public void removeTotpCustomLabel() throws Exception {
|
||||
public void removeOtpCustomLabel() throws Exception {
|
||||
String credentialId = getCredentialIdByType(OTPCredentialModel.TYPE);
|
||||
testRealm().users().get(userId).setCredentialUserLabel(credentialId, "custom-otp-authenticator");
|
||||
|
||||
|
@ -242,6 +248,13 @@ public class AppInitiatedActionDeleteCredentialTest extends AbstractAppInitiated
|
|||
.detail(Details.CREDENTIAL_USER_LABEL, "custom-otp-authenticator")
|
||||
.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.CREDENTIAL_USER_LABEL, "custom-otp-authenticator")
|
||||
.detail(Details.CUSTOM_REQUIRED_ACTION, DeleteCredentialAction.PROVIDER_ID)
|
||||
.assertEvent();
|
||||
}
|
||||
|
||||
private String getCredentialIdByType(String type) {
|
||||
|
|
|
@ -28,6 +28,7 @@ import org.keycloak.events.Details;
|
|||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.credential.PasswordCredentialModel;
|
||||
import org.keycloak.representations.idm.EventRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
|
@ -107,6 +108,7 @@ public class AppInitiatedActionResetPasswordTest extends AbstractAppInitiatedAct
|
|||
});
|
||||
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).assertEvent();
|
||||
|
||||
assertKcActionStatus(SUCCESS);
|
||||
|
||||
|
@ -145,6 +147,7 @@ public class AppInitiatedActionResetPasswordTest extends AbstractAppInitiatedAct
|
|||
changePasswordPage.changePassword("new-password", "new-password");
|
||||
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).assertEvent();
|
||||
assertKcActionStatus(SUCCESS);
|
||||
}
|
||||
|
||||
|
@ -188,6 +191,7 @@ public class AppInitiatedActionResetPasswordTest extends AbstractAppInitiatedAct
|
|||
changePasswordPage.changePassword("new-password", "new-password");
|
||||
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).assertEvent();
|
||||
assertKcActionStatus(SUCCESS);
|
||||
} finally {
|
||||
// reset password policy to previous state
|
||||
|
@ -232,6 +236,7 @@ public class AppInitiatedActionResetPasswordTest extends AbstractAppInitiatedAct
|
|||
changePasswordPage.changePassword("new-password", "new-password");
|
||||
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).assertEvent();
|
||||
|
||||
assertKcActionStatus(SUCCESS);
|
||||
}
|
||||
|
@ -261,6 +266,7 @@ public class AppInitiatedActionResetPasswordTest extends AbstractAppInitiatedAct
|
|||
changePasswordPage.changePassword("All Right Then, Keep Your Secrets", "All Right Then, Keep Your Secrets");
|
||||
events.expectLogout(event2.getSessionId()).detail(Details.LOGOUT_TRIGGERED_BY_REQUIRED_ACTION, UserModel.RequiredAction.UPDATE_PASSWORD.name()).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).assertEvent();
|
||||
assertKcActionStatus(SUCCESS);
|
||||
|
||||
sessions = testUser.getUserSessions();
|
||||
|
@ -289,6 +295,7 @@ public class AppInitiatedActionResetPasswordTest extends AbstractAppInitiatedAct
|
|||
changePasswordPage.uncheckLogoutSessions();
|
||||
changePasswordPage.changePassword("All Right Then, Keep Your Secrets", "All Right Then, Keep Your Secrets");
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).assertEvent();
|
||||
assertKcActionStatus(SUCCESS);
|
||||
|
||||
assertEquals(2, testUser.getUserSessions().size());
|
||||
|
|
|
@ -111,12 +111,21 @@ public class AppInitiatedActionTotpSetupTest extends AbstractAppInitiatedActionT
|
|||
totpPage.configure(totp.generateTOTP(totpPage.getTotpSecret()));
|
||||
|
||||
events.poll(); // skip to totp event
|
||||
String authSessionId = events.expectRequiredAction(EventType.UPDATE_TOTP).user(userId).detail(Details.USERNAME, "setuptotp").assertEvent()
|
||||
String authSessionId1 = events.expectRequiredAction(EventType.UPDATE_TOTP)
|
||||
.user(userId)
|
||||
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE)
|
||||
.detail(Details.USERNAME, "setuptotp").assertEvent()
|
||||
.getDetails().get(Details.CODE_ID);
|
||||
String authSessionId2 = events.expectRequiredAction(EventType.UPDATE_CREDENTIAL)
|
||||
.user(userId)
|
||||
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE)
|
||||
.detail(Details.USERNAME, "setuptotp").assertEvent()
|
||||
.getDetails().get(Details.CODE_ID);
|
||||
|
||||
assertKcActionStatus(SUCCESS);
|
||||
|
||||
events.expectLogin().user(userId).session(authSessionId).detail(Details.USERNAME, "setuptotp").assertEvent();
|
||||
assertEquals(authSessionId1, authSessionId2);
|
||||
events.expectLogin().user(userId).session(authSessionId2).detail(Details.USERNAME, "setuptotp").assertEvent();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -346,17 +355,22 @@ public class AppInitiatedActionTotpSetupTest extends AbstractAppInitiatedActionT
|
|||
|
||||
totpPage.configure(totp.generateTOTP(totpSecret));
|
||||
|
||||
String authSessionId = events.expectRequiredAction(EventType.UPDATE_TOTP).assertEvent()
|
||||
String authSessionId1 = events.expectRequiredAction(EventType.UPDATE_TOTP)
|
||||
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE).assertEvent()
|
||||
.getDetails().get(Details.CODE_ID);
|
||||
String authSessionId2 = events.expectRequiredAction(EventType.UPDATE_CREDENTIAL)
|
||||
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE).assertEvent()
|
||||
.getDetails().get(Details.CODE_ID);
|
||||
|
||||
assertKcActionStatus(SUCCESS);
|
||||
|
||||
EventRepresentation loginEvent = events.expectLogin().session(authSessionId).assertEvent();
|
||||
assertEquals(authSessionId1, authSessionId2);
|
||||
EventRepresentation loginEvent = events.expectLogin().session(authSessionId2).assertEvent();
|
||||
|
||||
OAuthClient.AccessTokenResponse tokenResponse = sendTokenRequestAndGetResponse(loginEvent);
|
||||
oauth.idTokenHint(tokenResponse.getIdToken()).openLogout();
|
||||
|
||||
events.expectLogout(authSessionId).assertEvent();
|
||||
events.expectLogout(authSessionId2).assertEvent();
|
||||
|
||||
setOtpTimeOffset(TimeBasedOTP.DEFAULT_INTERVAL_SECONDS, totp);
|
||||
|
||||
|
@ -389,7 +403,14 @@ public class AppInitiatedActionTotpSetupTest extends AbstractAppInitiatedActionT
|
|||
assertKcActionStatus(SUCCESS);
|
||||
|
||||
events.poll();
|
||||
events.expectRequiredAction(EventType.UPDATE_TOTP).user(userId).detail(Details.USERNAME, "setuptotp2").assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_TOTP)
|
||||
.user(userId)
|
||||
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE)
|
||||
.detail(Details.USERNAME, "setuptotp2").assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL)
|
||||
.user(userId)
|
||||
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE)
|
||||
.detail(Details.USERNAME, "setuptotp2").assertEvent();
|
||||
|
||||
EventRepresentation loginEvent = events.expectLogin().user(userId).detail(Details.USERNAME, "setuptotp2").assertEvent();
|
||||
|
||||
|
@ -448,12 +469,17 @@ public class AppInitiatedActionTotpSetupTest extends AbstractAppInitiatedActionT
|
|||
TimeBasedOTP timeBased = new TimeBasedOTP(HmacOTP.HMAC_SHA1, 8, 30, 1);
|
||||
totpPage.configure(timeBased.generateTOTP(totpSecret));
|
||||
|
||||
String sessionId = events.expectRequiredAction(EventType.UPDATE_TOTP).assertEvent()
|
||||
String sessionId1 = events.expectRequiredAction(EventType.UPDATE_TOTP)
|
||||
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE).assertEvent()
|
||||
.getDetails().get(Details.CODE_ID);
|
||||
String sessionId2 = events.expectRequiredAction(EventType.UPDATE_CREDENTIAL)
|
||||
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE).assertEvent()
|
||||
.getDetails().get(Details.CODE_ID);
|
||||
|
||||
assertKcActionStatus(SUCCESS);
|
||||
|
||||
EventRepresentation loginEvent = events.expectLogin().session(sessionId).assertEvent();
|
||||
assertEquals(sessionId1, sessionId2);
|
||||
EventRepresentation loginEvent = events.expectLogin().session(sessionId2).assertEvent();
|
||||
|
||||
OAuthClient.AccessTokenResponse tokenResponse = sendTokenRequestAndGetResponse(loginEvent);
|
||||
oauth.idTokenHint(tokenResponse.getIdToken()).openLogout();
|
||||
|
@ -503,12 +529,16 @@ public class AppInitiatedActionTotpSetupTest extends AbstractAppInitiatedActionT
|
|||
HmacOTP otpgen = new HmacOTP(6, HmacOTP.HMAC_SHA1, 1);
|
||||
totpPage.configure(otpgen.generateHOTP(totpSecret, 0));
|
||||
|
||||
String sessionId = events.expectRequiredAction(EventType.UPDATE_TOTP).assertEvent()
|
||||
String sessionId1 = events.expectRequiredAction(EventType.UPDATE_TOTP)
|
||||
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE).assertEvent()
|
||||
.getDetails().get(Details.CODE_ID);
|
||||
String sessionId2 = events.expectRequiredAction(EventType.UPDATE_CREDENTIAL)
|
||||
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE).assertEvent()
|
||||
.getDetails().get(Details.CODE_ID);
|
||||
|
||||
//RequestType reqType = appPage.getRequestType();
|
||||
assertKcActionStatus(SUCCESS);
|
||||
EventRepresentation loginEvent = events.expectLogin().session(sessionId).assertEvent();
|
||||
EventRepresentation loginEvent = events.expectLogin().session(sessionId1).assertEvent();
|
||||
|
||||
OAuthClient.AccessTokenResponse tokenResponse = sendTokenRequestAndGetResponse(loginEvent);
|
||||
oauth.idTokenHint(tokenResponse.getIdToken()).openLogout();
|
||||
|
|
|
@ -23,6 +23,8 @@ import org.junit.Test;
|
|||
import org.keycloak.events.Details;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.models.UserModel.RequiredAction;
|
||||
import org.keycloak.models.credential.PasswordCredentialModel;
|
||||
import org.keycloak.representations.idm.EventRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.testsuite.AssertEvents;
|
||||
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
|
||||
|
@ -86,11 +88,20 @@ public class RequiredActionMultipleActionsTest extends AbstractTestRealmKeycloak
|
|||
public String updatePassword(String codeId) {
|
||||
changePasswordPage.changePassword("new-password", "new-password");
|
||||
|
||||
AssertEvents.ExpectedEvent expectedEvent = events.expectRequiredAction(EventType.UPDATE_PASSWORD);
|
||||
AssertEvents.ExpectedEvent expectedEvent1 = events.expectRequiredAction(EventType.UPDATE_PASSWORD).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE);
|
||||
if (codeId != null) {
|
||||
expectedEvent.detail(Details.CODE_ID, codeId);
|
||||
expectedEvent1.detail(Details.CODE_ID, codeId);
|
||||
}
|
||||
return expectedEvent.assertEvent().getDetails().get(Details.CODE_ID);
|
||||
EventRepresentation eventRep1 = expectedEvent1.assertEvent();
|
||||
|
||||
AssertEvents.ExpectedEvent expectedEvent2 = events.expectRequiredAction(EventType.UPDATE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE);
|
||||
if (codeId != null) {
|
||||
expectedEvent2.detail(Details.CODE_ID, codeId);
|
||||
}
|
||||
EventRepresentation eventRep2 = expectedEvent2.assertEvent();
|
||||
|
||||
Assert.assertEquals(eventRep1.getDetails().get(Details.CODE_ID), eventRep2.getDetails().get(Details.CODE_ID));
|
||||
return eventRep2.getDetails().get(Details.CODE_ID);
|
||||
}
|
||||
|
||||
public String updateProfile(String codeId) {
|
||||
|
|
|
@ -33,6 +33,8 @@ import org.keycloak.events.Details;
|
|||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserModel.RequiredAction;
|
||||
import org.keycloak.models.credential.OTPCredentialModel;
|
||||
import org.keycloak.models.credential.PasswordCredentialModel;
|
||||
import org.keycloak.models.utils.TimeBasedOTP;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
|
||||
|
@ -139,7 +141,8 @@ public class RequiredActionPriorityTest extends AbstractTestRealmKeycloakTest {
|
|||
// Second, change password
|
||||
changePasswordPage.assertCurrent();
|
||||
changePasswordPage.changePassword(NEW_PASSWORD, NEW_PASSWORD);
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).assertEvent();
|
||||
|
||||
// Finally, update profile
|
||||
updateProfilePage.assertCurrent();
|
||||
|
@ -182,7 +185,8 @@ public class RequiredActionPriorityTest extends AbstractTestRealmKeycloakTest {
|
|||
// First, change password
|
||||
changePasswordPage.assertCurrent();
|
||||
changePasswordPage.changePassword(NEW_PASSWORD, NEW_PASSWORD);
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).assertEvent();
|
||||
|
||||
// Second, update profile
|
||||
updateProfilePage.assertCurrent();
|
||||
|
@ -236,6 +240,7 @@ public class RequiredActionPriorityTest extends AbstractTestRealmKeycloakTest {
|
|||
changePasswordPage.assertCurrent();
|
||||
changePasswordPage.changePassword(NEW_PASSWORD, NEW_PASSWORD);
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL).assertEvent();
|
||||
|
||||
// Second, update profile
|
||||
updateProfilePage.assertCurrent();
|
||||
|
@ -299,7 +304,8 @@ public class RequiredActionPriorityTest extends AbstractTestRealmKeycloakTest {
|
|||
// First, change password
|
||||
changePasswordPage.assertCurrent();
|
||||
changePasswordPage.changePassword(NEW_PASSWORD, NEW_PASSWORD);
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).assertEvent();
|
||||
|
||||
// Second, update profile
|
||||
updateProfilePage.assertCurrent();
|
||||
|
@ -395,7 +401,8 @@ public class RequiredActionPriorityTest extends AbstractTestRealmKeycloakTest {
|
|||
// change password
|
||||
changePasswordPage.assertCurrent();
|
||||
changePasswordPage.changePassword(NEW_PASSWORD, NEW_PASSWORD);
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).assertEvent();
|
||||
|
||||
// CONFIGURE_TOTP
|
||||
totpPage.assertCurrent();
|
||||
|
@ -407,7 +414,8 @@ public class RequiredActionPriorityTest extends AbstractTestRealmKeycloakTest {
|
|||
|
||||
TimeBasedOTP totp = new TimeBasedOTP();
|
||||
totpPage.configure(totp.generateTOTP(totpPage.getTotpSecret()), "userLabel");
|
||||
events.expectRequiredAction(EventType.UPDATE_TOTP).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_TOTP).detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE).assertEvent();
|
||||
|
||||
// Logged in
|
||||
appPage.assertCurrent();
|
||||
|
@ -448,7 +456,7 @@ public class RequiredActionPriorityTest extends AbstractTestRealmKeycloakTest {
|
|||
|
||||
appPage.assertCurrent();
|
||||
assertThat(appPage.getRequestType(), is(RequestType.AUTH_RESPONSE));
|
||||
events.expectLogin().assertEvent();
|
||||
events.expect(EventType.UPDATE_CREDENTIAL).assertEvent();
|
||||
}
|
||||
|
||||
private void enableRequiredActionForUser(final RequiredAction requiredAction) {
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.keycloak.events.Details;
|
|||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.models.AuthenticationExecutionModel;
|
||||
import org.keycloak.models.UserModel.RequiredAction;
|
||||
import org.keycloak.models.credential.PasswordCredentialModel;
|
||||
import org.keycloak.models.utils.DefaultAuthenticationFlows;
|
||||
import org.keycloak.representations.idm.EventRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
|
@ -106,7 +107,8 @@ public class RequiredActionResetPasswordTest extends AbstractTestRealmKeycloakTe
|
|||
|
||||
changePasswordPage.changePassword("new-password", "new-password");
|
||||
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).assertEvent();
|
||||
|
||||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
|
||||
|
@ -159,7 +161,8 @@ public class RequiredActionResetPasswordTest extends AbstractTestRealmKeycloakTe
|
|||
.assertEvent();
|
||||
}
|
||||
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).assertEvent();
|
||||
|
||||
EventRepresentation event2 = events.expectLogin().assertEvent();
|
||||
List<UserSessionRepresentation> sessions = testUser.getUserSessions();
|
||||
|
|
|
@ -171,12 +171,23 @@ public class RequiredActionTotpSetupTest extends AbstractTestRealmKeycloakTest {
|
|||
|
||||
totpPage.configure(totp.generateTOTP(totpPage.getTotpSecret()));
|
||||
|
||||
String authSessionId = events.expectRequiredAction(EventType.UPDATE_TOTP).user(userId).detail(Details.USERNAME, "setuptotp").assertEvent()
|
||||
String authSessionId1 = events.expectRequiredAction(EventType.UPDATE_TOTP)
|
||||
.user(userId)
|
||||
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE)
|
||||
.detail(Details.USERNAME, "setuptotp").assertEvent()
|
||||
.getDetails().get(Details.CODE_ID);
|
||||
|
||||
assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
|
||||
events.expectLogin().user(userId).session(authSessionId).detail(Details.USERNAME, "setuptotp").assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL)
|
||||
.user(userId)
|
||||
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE)
|
||||
.detail(Details.USERNAME, "setuptotp").assertEvent()
|
||||
.getDetails().get(Details.CODE_ID);
|
||||
|
||||
assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
|
||||
events.expectLogin().user(userId).session(authSessionId1).detail(Details.USERNAME, "setuptotp").assertEvent();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -380,17 +391,22 @@ public class RequiredActionTotpSetupTest extends AbstractTestRealmKeycloakTest {
|
|||
|
||||
totpPage.configure(firstCode);
|
||||
|
||||
String authSessionId = events.expectRequiredAction(EventType.UPDATE_TOTP).assertEvent()
|
||||
String authSessionId1 = events.expectRequiredAction(EventType.UPDATE_TOTP)
|
||||
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE).assertEvent()
|
||||
.getDetails().get(Details.CODE_ID);
|
||||
String authSessionId2 = events.expectRequiredAction(EventType.UPDATE_CREDENTIAL)
|
||||
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE).assertEvent()
|
||||
.getDetails().get(Details.CODE_ID);
|
||||
|
||||
assertEquals(authSessionId1, authSessionId2);
|
||||
assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
|
||||
EventRepresentation loginEvent = events.expectLogin().session(authSessionId).assertEvent();
|
||||
EventRepresentation loginEvent = events.expectLogin().session(authSessionId1).assertEvent();
|
||||
|
||||
OAuthClient.AccessTokenResponse tokenResponse = sendTokenRequestAndGetResponse(loginEvent);
|
||||
oauth.idTokenHint(tokenResponse.getIdToken()).openLogout();
|
||||
|
||||
events.expectLogout(authSessionId).assertEvent();
|
||||
events.expectLogout(authSessionId1).assertEvent();
|
||||
|
||||
loginPage.open();
|
||||
loginPage.login("test-user@localhost", "password");
|
||||
|
@ -448,7 +464,14 @@ public class RequiredActionTotpSetupTest extends AbstractTestRealmKeycloakTest {
|
|||
// After totp config, user should be on the app page
|
||||
assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
|
||||
events.expectRequiredAction(EventType.UPDATE_TOTP).user(userId).detail(Details.USERNAME, "setuptotp2").assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_TOTP)
|
||||
.user(userId)
|
||||
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE)
|
||||
.detail(Details.USERNAME, "setuptotp2").assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL)
|
||||
.user(userId)
|
||||
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE)
|
||||
.detail(Details.USERNAME, "setuptotp2").assertEvent();
|
||||
|
||||
EventRepresentation loginEvent = events.expectLogin().user(userId).detail(Details.USERNAME, "setuptotp2").assertEvent();
|
||||
|
||||
|
@ -488,12 +511,21 @@ public class RequiredActionTotpSetupTest extends AbstractTestRealmKeycloakTest {
|
|||
totpPage.assertCurrent();
|
||||
totpPage.configure(totp.generateTOTP(totpPage.getTotpSecret()));
|
||||
|
||||
String sessionId = events.expectRequiredAction(EventType.UPDATE_TOTP).user(userId).detail(Details.USERNAME, "setupTotp2").assertEvent()
|
||||
String sessionId1 = events.expectRequiredAction(EventType.UPDATE_TOTP)
|
||||
.user(userId)
|
||||
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE)
|
||||
.detail(Details.USERNAME, "setupTotp2").assertEvent()
|
||||
.getDetails().get(Details.CODE_ID);
|
||||
String sessionId2 = events.expectRequiredAction(EventType.UPDATE_CREDENTIAL)
|
||||
.user(userId)
|
||||
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE)
|
||||
.detail(Details.USERNAME, "setupTotp2").assertEvent()
|
||||
.getDetails().get(Details.CODE_ID);
|
||||
|
||||
assertEquals(sessionId1, sessionId2);
|
||||
assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
|
||||
events.expectLogin().user(userId).session(sessionId).detail(Details.USERNAME, "setupTotp2").assertEvent();
|
||||
events.expectLogin().user(userId).session(sessionId1).detail(Details.USERNAME, "setupTotp2").assertEvent();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -520,12 +552,17 @@ public class RequiredActionTotpSetupTest extends AbstractTestRealmKeycloakTest {
|
|||
TimeBasedOTP timeBased = new TimeBasedOTP(HmacOTP.HMAC_SHA1, 8, 30, 1);
|
||||
totpPage.configure(timeBased.generateTOTP(totpSecret));
|
||||
|
||||
String sessionId = events.expectRequiredAction(EventType.UPDATE_TOTP).assertEvent()
|
||||
String sessionId1 = events.expectRequiredAction(EventType.UPDATE_TOTP)
|
||||
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE).assertEvent()
|
||||
.getDetails().get(Details.CODE_ID);
|
||||
String sessionId2 = events.expectRequiredAction(EventType.UPDATE_CREDENTIAL)
|
||||
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE).assertEvent()
|
||||
.getDetails().get(Details.CODE_ID);
|
||||
|
||||
assertEquals(sessionId1, sessionId2);
|
||||
assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
|
||||
EventRepresentation loginEvent = events.expectLogin().session(sessionId).assertEvent();
|
||||
EventRepresentation loginEvent = events.expectLogin().session(sessionId1).assertEvent();
|
||||
|
||||
OAuthClient.AccessTokenResponse tokenResponse = sendTokenRequestAndGetResponse(loginEvent);
|
||||
oauth.idTokenHint(tokenResponse.getIdToken()).openLogout();
|
||||
|
@ -575,12 +612,17 @@ public class RequiredActionTotpSetupTest extends AbstractTestRealmKeycloakTest {
|
|||
HmacOTP otpgen = new HmacOTP(6, HmacOTP.HMAC_SHA1, 1);
|
||||
totpPage.configure(otpgen.generateHOTP(totpSecret, 0));
|
||||
String uri = driver.getCurrentUrl();
|
||||
String sessionId = events.expectRequiredAction(EventType.UPDATE_TOTP).assertEvent()
|
||||
.getDetails().get(Details.CODE_ID);
|
||||
String sessionId1 = events.expectRequiredAction(EventType.UPDATE_TOTP)
|
||||
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE).assertEvent()
|
||||
.getDetails().get(Details.CODE_ID);
|
||||
String sessionId2 = events.expectRequiredAction(EventType.UPDATE_CREDENTIAL)
|
||||
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE).assertEvent()
|
||||
.getDetails().get(Details.CODE_ID);
|
||||
|
||||
assertEquals(sessionId1, sessionId2);
|
||||
assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
|
||||
EventRepresentation loginEvent = events.expectLogin().session(sessionId).assertEvent();
|
||||
EventRepresentation loginEvent = events.expectLogin().session(sessionId1).assertEvent();
|
||||
|
||||
OAuthClient.AccessTokenResponse tokenResponse = sendTokenRequestAndGetResponse(loginEvent);
|
||||
oauth.idTokenHint(tokenResponse.getIdToken()).openLogout();
|
||||
|
@ -678,7 +720,14 @@ public class RequiredActionTotpSetupTest extends AbstractTestRealmKeycloakTest {
|
|||
.assertEvent();
|
||||
}
|
||||
|
||||
EventRepresentation event2 = events.expectRequiredAction(EventType.UPDATE_TOTP).user(event1.getUserId()).detail(Details.USERNAME, "test-user@localhost").assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_TOTP)
|
||||
.user(event1.getUserId())
|
||||
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE)
|
||||
.detail(Details.USERNAME, "test-user@localhost").assertEvent();
|
||||
EventRepresentation event2 = events.expectRequiredAction(EventType.UPDATE_CREDENTIAL)
|
||||
.user(event1.getUserId())
|
||||
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE)
|
||||
.detail(Details.USERNAME, "test-user@localhost").assertEvent();
|
||||
event2 = events.expectLogin().user(event2.getUserId()).session(event2.getDetails().get(Details.CODE_ID)).detail(Details.USERNAME, "test-user@localhost").assertEvent();
|
||||
|
||||
// assert old session is gone or is maintained
|
||||
|
|
|
@ -43,6 +43,7 @@ import org.keycloak.federation.kerberos.KerberosConfig;
|
|||
import org.keycloak.federation.kerberos.KerberosFederationProviderFactory;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.credential.PasswordCredentialModel;
|
||||
import org.keycloak.representations.idm.ComponentRepresentation;
|
||||
import org.keycloak.representations.idm.ErrorRepresentation;
|
||||
import org.keycloak.representations.idm.UserProfileAttributeMetadata;
|
||||
|
@ -271,7 +272,9 @@ public class KerberosStandaloneTest extends AbstractKerberosSingleRealmTest {
|
|||
driver.navigate().to(changePasswordUrl.trim());
|
||||
loginPasswordUpdatePage.assertCurrent();
|
||||
loginPasswordUpdatePage.changePassword("resetPassword", "resetPassword");
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).client(oauth.getClientId()).detail(Details.USERNAME, "test-user@localhost");
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).client(oauth.getClientId()).detail(Details.USERNAME, "test-user@localhost");
|
||||
events.poll();
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).client(oauth.getClientId()).detail(Details.USERNAME, "test-user@localhost");
|
||||
infoPage.assertCurrent();
|
||||
Assert.assertEquals("Your account has been updated.", infoPage.getInfo());
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.keycloak.admin.client.resource.RealmResource;
|
|||
import org.keycloak.admin.client.resource.UserResource;
|
||||
import org.keycloak.component.ComponentModel;
|
||||
import org.keycloak.credential.CredentialModel;
|
||||
import org.keycloak.events.Details;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.LDAPConstants;
|
||||
|
@ -570,7 +571,8 @@ public class LDAPProvidersIntegrationTest extends AbstractLDAPTest {
|
|||
requiredActionChangePasswordPage.changePassword("Password1-updated2", "Password1-updated2");
|
||||
|
||||
appPage.assertCurrent();
|
||||
events.expect(EventType.UPDATE_PASSWORD).user(userId).assertEvent();
|
||||
events.expect(EventType.UPDATE_PASSWORD).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).user(userId).assertEvent();
|
||||
events.expect(EventType.UPDATE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).user(userId).assertEvent();
|
||||
loginEvent = events.expectLogin().user(userId).assertEvent();
|
||||
tokenResponse = sendTokenRequestAndGetResponse(loginEvent);
|
||||
appPage.logout(tokenResponse.getIdToken());
|
||||
|
|
|
@ -32,6 +32,7 @@ import org.junit.Test;
|
|||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.admin.client.resource.UserResource;
|
||||
import org.keycloak.common.util.MultivaluedHashMap;
|
||||
import org.keycloak.events.Details;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.credential.OTPCredentialModel;
|
||||
|
@ -175,7 +176,12 @@ public class UserStorageOTPTest extends AbstractTestRealmKeycloakTest {
|
|||
appPage.assertCurrent();
|
||||
|
||||
// Logout
|
||||
events.expect(EventType.UPDATE_TOTP).user(userRep.getId()).assertEvent(); //remove the UPDATE_TOTP event
|
||||
events.expect(EventType.UPDATE_TOTP)
|
||||
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE)
|
||||
.user(userRep.getId()).assertEvent();
|
||||
events.expect(EventType.UPDATE_CREDENTIAL)
|
||||
.detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE)
|
||||
.user(userRep.getId()).assertEvent();
|
||||
EventRepresentation loginEvent = events.expectLogin().user(userRep.getId()).assertEvent();
|
||||
String idTokenHint = sendTokenRequestAndGetResponse(loginEvent).getIdToken();
|
||||
appPage.logout(idTokenHint);
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.keycloak.events.EventType;
|
|||
import org.keycloak.executors.ExecutorsProvider;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.credential.PasswordCredentialModel;
|
||||
import org.keycloak.models.utils.TimeBasedOTP;
|
||||
import org.keycloak.representations.idm.EventRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
|
@ -784,7 +785,8 @@ public class BruteForceTest extends AbstractTestRealmKeycloakTest {
|
|||
|
||||
updatePasswordPage.updatePasswords("password", "password");
|
||||
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).user(userId).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).user(userId).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).user(userId).assertEvent();
|
||||
|
||||
userRepresentation = testRealm().users().get(userId).toRepresentation();
|
||||
assertTrue(userRepresentation.isEnabled());
|
||||
|
|
|
@ -754,7 +754,8 @@ public class LevelOfAssuranceFlowTest extends AbstractTestRealmKeycloakTest {
|
|||
authenticateWithTotp();
|
||||
totpSetupPage.assertCurrent();
|
||||
totpSetupPage.configure(totp.generateTOTP(totpSetupPage.getTotpSecret()), "totp2-label");
|
||||
events.expectRequiredAction(EventType.UPDATE_TOTP).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_TOTP).detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE).assertEvent();
|
||||
TokenCtx token2 = assertLoggedInWithAcr("gold");
|
||||
|
||||
// Trying to add another OTP by "kc_action". Level 2 should be required and user can choose between 2 OTP codes
|
||||
|
@ -803,7 +804,8 @@ public class LevelOfAssuranceFlowTest extends AbstractTestRealmKeycloakTest {
|
|||
authenticateWithTotp();
|
||||
totpSetupPage.assertCurrent();
|
||||
totpSetupPage.configure(totp.generateTOTP(totpSetupPage.getTotpSecret()), "totp2-label");
|
||||
events.expectRequiredAction(EventType.UPDATE_TOTP).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_TOTP).detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE).assertEvent();
|
||||
TokenCtx token2 = assertLoggedInWithAcr("gold");
|
||||
|
||||
String otp2CredentialId = getCredentialIdByLabel("totp2-label");
|
||||
|
@ -818,7 +820,8 @@ public class LevelOfAssuranceFlowTest extends AbstractTestRealmKeycloakTest {
|
|||
deleteCredentialPage.assertCredentialInMessage("totp2-label");
|
||||
deleteCredentialPage.confirm();
|
||||
|
||||
events.expectRequiredAction(EventType.REMOVE_TOTP).assertEvent();
|
||||
events.expectRequiredAction(EventType.REMOVE_TOTP).detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE).assertEvent();
|
||||
events.expectRequiredAction(EventType.REMOVE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE).assertEvent();
|
||||
assertLoggedInWithAcr("gold");
|
||||
}
|
||||
|
||||
|
@ -841,7 +844,8 @@ public class LevelOfAssuranceFlowTest extends AbstractTestRealmKeycloakTest {
|
|||
deleteCredentialPage.assertCurrent();
|
||||
deleteCredentialPage.assertCredentialInMessage("otp");
|
||||
deleteCredentialPage.confirm();
|
||||
events.expectRequiredAction(EventType.REMOVE_TOTP).assertEvent();
|
||||
events.expectRequiredAction(EventType.REMOVE_TOTP).detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE).assertEvent();
|
||||
events.expectRequiredAction(EventType.REMOVE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE).assertEvent();
|
||||
assertLoggedInWithAcr("gold");
|
||||
|
||||
// Trying to add OTP. No 2nd factor should be required as user doesn't have any
|
||||
|
@ -850,7 +854,8 @@ public class LevelOfAssuranceFlowTest extends AbstractTestRealmKeycloakTest {
|
|||
totpSetupPage.assertCurrent();
|
||||
String totp2Secret = totpSetupPage.getTotpSecret();
|
||||
totpSetupPage.configure(totp.generateTOTP(totp2Secret), "totp2-label");
|
||||
events.expectRequiredAction(EventType.UPDATE_TOTP).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_TOTP).detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, OTPCredentialModel.TYPE).assertEvent();
|
||||
assertLoggedInWithAcr("silver");
|
||||
|
||||
// set time offset for OTP as it is not permitted to authenticate with same OTP code multiple times
|
||||
|
@ -881,7 +886,7 @@ public class LevelOfAssuranceFlowTest extends AbstractTestRealmKeycloakTest {
|
|||
deleteCredentialPage.assertCurrent();
|
||||
deleteCredentialPage.assertCredentialInMessage("Recovery codes");
|
||||
deleteCredentialPage.confirm();
|
||||
events.expectRequiredAction(EventType.CUSTOM_REQUIRED_ACTION).assertEvent();
|
||||
events.expectRequiredAction(EventType.REMOVE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, RecoveryAuthnCodesCredentialModel.TYPE).assertEvent();
|
||||
assertLoggedInWithAcr("gold");
|
||||
} finally {
|
||||
setOtpTimeOffset(0, totp);
|
||||
|
|
|
@ -44,6 +44,7 @@ import org.keycloak.models.BrowserSecurityHeaders;
|
|||
import org.keycloak.models.ClientScopeModel;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.UserModel.RequiredAction;
|
||||
import org.keycloak.models.credential.PasswordCredentialModel;
|
||||
import org.keycloak.models.utils.SessionTimeoutHelper;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
|
||||
|
@ -531,7 +532,8 @@ public class LoginTest extends AbstractTestRealmKeycloakTest {
|
|||
|
||||
setTimeOffset(0);
|
||||
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).user(userId).detail(Details.USERNAME, "login-test").assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).user(userId).detail(Details.USERNAME, "login-test").assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).user(userId).detail(Details.USERNAME, "login-test").assertEvent();
|
||||
|
||||
String currentUrl = driver.getCurrentUrl();
|
||||
String pageSource = driver.getPageSource();
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.keycloak.events.Errors;
|
|||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.models.AuthenticationExecutionModel;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.credential.PasswordCredentialModel;
|
||||
import org.keycloak.models.utils.SystemClientUtil;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.EventRepresentation;
|
||||
|
@ -239,6 +240,18 @@ public class ResetPasswordTest extends AbstractTestRealmKeycloakTest {
|
|||
updatePasswordPage.changePassword("resetPassword", "resetPassword");
|
||||
|
||||
event = events.expectRequiredAction(EventType.UPDATE_PASSWORD)
|
||||
.detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE)
|
||||
.client(expectedClientId)
|
||||
.user(userId).detail(Details.USERNAME, username);
|
||||
if (expectedRedirectUri != null) {
|
||||
event.detail(Details.REDIRECT_URI, expectedRedirectUri);
|
||||
} else {
|
||||
event.removeDetail(Details.REDIRECT_URI);
|
||||
}
|
||||
event.assertEvent();
|
||||
|
||||
event = events.expectRequiredAction(EventType.UPDATE_CREDENTIAL)
|
||||
.detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE)
|
||||
.client(expectedClientId)
|
||||
.user(userId).detail(Details.USERNAME, username);
|
||||
if (expectedRedirectUri != null) {
|
||||
|
@ -414,7 +427,8 @@ public class ResetPasswordTest extends AbstractTestRealmKeycloakTest {
|
|||
|
||||
updatePasswordPage.changePassword(password, password);
|
||||
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).user(userId).detail(Details.USERNAME, username.trim()).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).user(userId).detail(Details.USERNAME, username.trim()).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).user(userId).detail(Details.USERNAME, username.trim()).assertEvent();
|
||||
|
||||
assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
|
||||
|
@ -465,7 +479,8 @@ public class ResetPasswordTest extends AbstractTestRealmKeycloakTest {
|
|||
|
||||
updatePasswordPage.assertCurrent();
|
||||
assertEquals(error, updatePasswordPage.getError());
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_REJECTED).user(userId).detail(Details.USERNAME, "login-test").assertEvent().getSessionId();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL_ERROR).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).error(Errors.PASSWORD_REJECTED).user(userId).detail(Details.USERNAME, "login-test").assertEvent().getSessionId();
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD_ERROR).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).error(Errors.PASSWORD_REJECTED).user(userId).detail(Details.USERNAME, "login-test").assertEvent().getSessionId();
|
||||
}
|
||||
|
||||
private void initiateResetPasswordFromResetPasswordPage(String username) {
|
||||
|
@ -1040,11 +1055,13 @@ public class ResetPasswordTest extends AbstractTestRealmKeycloakTest {
|
|||
|
||||
assertEquals("Invalid password: minimum length 8.", resetPasswordPage.getErrorMessage());
|
||||
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_REJECTED).user(userId).detail(Details.USERNAME, "login-test").assertEvent().getSessionId();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL_ERROR).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).error(Errors.PASSWORD_REJECTED).user(userId).detail(Details.USERNAME, "login-test").assertEvent().getSessionId();
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD_ERROR).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).error(Errors.PASSWORD_REJECTED).user(userId).detail(Details.USERNAME, "login-test").assertEvent().getSessionId();
|
||||
|
||||
updatePasswordPage.changePassword("resetPasswordWithPasswordPolicy", "resetPasswordWithPasswordPolicy");
|
||||
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).user(userId).detail(Details.USERNAME, "login-test").assertEvent().getSessionId();
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).user(userId).detail(Details.USERNAME, "login-test").assertEvent().getSessionId();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).user(userId).detail(Details.USERNAME, "login-test").assertEvent().getSessionId();
|
||||
|
||||
assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
|
||||
|
@ -1397,6 +1414,12 @@ public class ResetPasswordTest extends AbstractTestRealmKeycloakTest {
|
|||
changePasswordOnUpdatePage(driver);
|
||||
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD)
|
||||
.detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE)
|
||||
.detail(Details.REDIRECT_URI, redirectUri)
|
||||
.client(clientId)
|
||||
.user(user.getId()).detail(Details.USERNAME, user.getUsername()).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL)
|
||||
.detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE)
|
||||
.detail(Details.REDIRECT_URI, redirectUri)
|
||||
.client(clientId)
|
||||
.user(user.getId()).detail(Details.USERNAME, user.getUsername()).assertEvent();
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.keycloak.OAuth2Constants;
|
|||
import org.keycloak.events.Details;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.credential.PasswordCredentialModel;
|
||||
import org.keycloak.representations.IDToken;
|
||||
import org.keycloak.representations.idm.EventRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
|
@ -191,7 +192,8 @@ public class SSOTest extends AbstractTestRealmKeycloakTest {
|
|||
updatePasswordPage.assertCurrent();
|
||||
|
||||
updatePasswordPage.changePassword("password", "password");
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_PASSWORD).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL).detail(Details.CREDENTIAL_TYPE, PasswordCredentialModel.TYPE).assertEvent();
|
||||
|
||||
assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
|
||||
|
|
|
@ -218,13 +218,22 @@ public class WebAuthnIdlessTest extends AbstractWebAuthnVirtualTest {
|
|||
|
||||
appPage.assertCurrent();
|
||||
assertThat(appPage.getRequestType(), is(RequestType.AUTH_RESPONSE));
|
||||
EventRepresentation eventRep = events.expectRequiredAction(EventType.CUSTOM_REQUIRED_ACTION)
|
||||
EventRepresentation eventRep1 = events.expectRequiredAction(EventType.CUSTOM_REQUIRED_ACTION)
|
||||
.user(userId)
|
||||
.detail(Details.CUSTOM_REQUIRED_ACTION, raProviderID)
|
||||
.detail(WebAuthnConstants.PUBKEY_CRED_LABEL_ATTR, authenticatorLabel)
|
||||
.detail(WebAuthnConstants.PUBKEY_CRED_AAGUID_ATTR, ALL_ZERO_AAGUID)
|
||||
.assertEvent();
|
||||
String credentialId = eventRep.getDetails().get(WebAuthnConstants.PUBKEY_CRED_ID_ATTR);
|
||||
EventRepresentation eventRep2 = events.expectRequiredAction(EventType.UPDATE_CREDENTIAL)
|
||||
.user(userId)
|
||||
.detail(Details.CUSTOM_REQUIRED_ACTION, raProviderID)
|
||||
.detail(WebAuthnConstants.PUBKEY_CRED_LABEL_ATTR, authenticatorLabel)
|
||||
.detail(WebAuthnConstants.PUBKEY_CRED_AAGUID_ATTR, ALL_ZERO_AAGUID)
|
||||
.assertEvent();
|
||||
String credentialId1 = eventRep1.getDetails().get(WebAuthnConstants.PUBKEY_CRED_ID_ATTR);
|
||||
String credentialId2 = eventRep2.getDetails().get(WebAuthnConstants.PUBKEY_CRED_ID_ATTR);
|
||||
|
||||
assertThat(credentialId1, equalTo(credentialId2));
|
||||
|
||||
assertThat(userRes.credentials().stream()
|
||||
.filter(cred -> cred.getType().equals(credType))
|
||||
|
@ -250,7 +259,7 @@ public class WebAuthnIdlessTest extends AbstractWebAuthnVirtualTest {
|
|||
.user(userId)
|
||||
.client("account")
|
||||
.assertEvent();
|
||||
return credentialId;
|
||||
return credentialId2;
|
||||
}
|
||||
|
||||
protected void checkTryAnotherWay() {
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.keycloak.authentication.requiredactions.WebAuthnPasswordlessRegisterF
|
|||
import org.keycloak.authentication.requiredactions.WebAuthnRegisterFactory;
|
||||
import org.keycloak.common.util.SecretGenerator;
|
||||
import org.keycloak.events.Details;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.models.credential.WebAuthnCredentialModel;
|
||||
import org.keycloak.models.credential.dto.WebAuthnCredentialData;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
|
@ -58,11 +59,11 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.hasItem;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.keycloak.events.EventType.CUSTOM_REQUIRED_ACTION;
|
||||
import static org.keycloak.models.AuthenticationExecutionModel.Requirement.ALTERNATIVE;
|
||||
import static org.keycloak.models.AuthenticationExecutionModel.Requirement.REQUIRED;
|
||||
|
||||
|
@ -127,13 +128,22 @@ public class WebAuthnRegisterAndLoginTest extends AbstractWebAuthnVirtualTest {
|
|||
// confirm that registration is successfully completed
|
||||
userId = events.expectRegister(username, email).assertEvent().getUserId();
|
||||
// confirm registration event
|
||||
EventRepresentation eventRep = events.expectRequiredAction(CUSTOM_REQUIRED_ACTION)
|
||||
EventRepresentation eventRep1 = events.expectRequiredAction(EventType.CUSTOM_REQUIRED_ACTION)
|
||||
.user(userId)
|
||||
.detail(Details.CUSTOM_REQUIRED_ACTION, WebAuthnRegisterFactory.PROVIDER_ID)
|
||||
.detail(WebAuthnConstants.PUBKEY_CRED_LABEL_ATTR, authenticatorLabel)
|
||||
.detail(WebAuthnConstants.PUBKEY_CRED_AAGUID_ATTR, ALL_ZERO_AAGUID)
|
||||
.assertEvent();
|
||||
String regPubKeyCredentialId = eventRep.getDetails().get(WebAuthnConstants.PUBKEY_CRED_ID_ATTR);
|
||||
EventRepresentation eventRep2 = events.expectRequiredAction(EventType.UPDATE_CREDENTIAL)
|
||||
.user(userId)
|
||||
.detail(Details.CUSTOM_REQUIRED_ACTION, WebAuthnRegisterFactory.PROVIDER_ID)
|
||||
.detail(WebAuthnConstants.PUBKEY_CRED_LABEL_ATTR, authenticatorLabel)
|
||||
.detail(WebAuthnConstants.PUBKEY_CRED_AAGUID_ATTR, ALL_ZERO_AAGUID)
|
||||
.assertEvent();
|
||||
String regPubKeyCredentialId1 = eventRep1.getDetails().get(WebAuthnConstants.PUBKEY_CRED_ID_ATTR);
|
||||
String regPubKeyCredentialId2 = eventRep2.getDetails().get(WebAuthnConstants.PUBKEY_CRED_ID_ATTR);
|
||||
|
||||
assertThat(regPubKeyCredentialId1, equalTo(regPubKeyCredentialId2));
|
||||
|
||||
// confirm login event
|
||||
String sessionId = events.expectLogin()
|
||||
|
@ -176,7 +186,7 @@ public class WebAuthnRegisterAndLoginTest extends AbstractWebAuthnVirtualTest {
|
|||
// confirm login event
|
||||
sessionId = events.expectLogin()
|
||||
.user(userId)
|
||||
.detail(WebAuthnConstants.PUBKEY_CRED_ID_ATTR, regPubKeyCredentialId)
|
||||
.detail(WebAuthnConstants.PUBKEY_CRED_ID_ATTR, regPubKeyCredentialId2)
|
||||
.detail(WebAuthnConstants.USER_VERIFICATION_CHECKED, Boolean.FALSE.toString())
|
||||
.assertEvent().getSessionId();
|
||||
|
||||
|
@ -235,7 +245,12 @@ public class WebAuthnRegisterAndLoginTest extends AbstractWebAuthnVirtualTest {
|
|||
|
||||
webAuthnRegisterPage.assertCurrent();
|
||||
|
||||
events.expectRequiredAction(CUSTOM_REQUIRED_ACTION)
|
||||
events.expectRequiredAction(EventType.CUSTOM_REQUIRED_ACTION)
|
||||
.user(userId)
|
||||
.detail(Details.CUSTOM_REQUIRED_ACTION, WebAuthnRegisterFactory.PROVIDER_ID)
|
||||
.detail(WebAuthnConstants.PUBKEY_CRED_LABEL_ATTR, WEBAUTHN_LABEL)
|
||||
.assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL)
|
||||
.user(userId)
|
||||
.detail(Details.CUSTOM_REQUIRED_ACTION, WebAuthnRegisterFactory.PROVIDER_ID)
|
||||
.detail(WebAuthnConstants.PUBKEY_CRED_LABEL_ATTR, WEBAUTHN_LABEL)
|
||||
|
@ -246,7 +261,12 @@ public class WebAuthnRegisterAndLoginTest extends AbstractWebAuthnVirtualTest {
|
|||
|
||||
appPage.assertCurrent();
|
||||
|
||||
events.expectRequiredAction(CUSTOM_REQUIRED_ACTION)
|
||||
events.expectRequiredAction(EventType.CUSTOM_REQUIRED_ACTION)
|
||||
.user(userId)
|
||||
.detail(Details.CUSTOM_REQUIRED_ACTION, WebAuthnPasswordlessRegisterFactory.PROVIDER_ID)
|
||||
.detail(WebAuthnConstants.PUBKEY_CRED_LABEL_ATTR, PASSWORDLESS_LABEL)
|
||||
.assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL)
|
||||
.user(userId)
|
||||
.detail(Details.CUSTOM_REQUIRED_ACTION, WebAuthnPasswordlessRegisterFactory.PROVIDER_ID)
|
||||
.detail(WebAuthnConstants.PUBKEY_CRED_LABEL_ATTR, PASSWORDLESS_LABEL)
|
||||
|
|
|
@ -86,6 +86,14 @@ public class WebAuthnOtherSettingsTest extends AbstractWebAuthnVirtualTest {
|
|||
.detail(WebAuthnConstants.PUBKEY_CRED_LABEL_ATTR, "webauthn")
|
||||
.detail(WebAuthnConstants.PUBKEY_CRED_AAGUID_ATTR, ALL_ZERO_AAGUID)
|
||||
.assertEvent();
|
||||
events.expectRequiredAction(EventType.UPDATE_CREDENTIAL)
|
||||
.user(userId)
|
||||
.detail(Details.CUSTOM_REQUIRED_ACTION, isPasswordless()
|
||||
? WebAuthnPasswordlessRegisterFactory.PROVIDER_ID
|
||||
: WebAuthnRegisterFactory.PROVIDER_ID)
|
||||
.detail(WebAuthnConstants.PUBKEY_CRED_LABEL_ATTR, "webauthn")
|
||||
.detail(WebAuthnConstants.PUBKEY_CRED_AAGUID_ATTR, ALL_ZERO_AAGUID)
|
||||
.assertEvent();
|
||||
|
||||
final String credentialType = getCredentialType();
|
||||
// Soft token in Firefox does not increment counter
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
"failureFactor" : 3,
|
||||
"eventsEnabled" : true,
|
||||
"eventsListeners" : [ "jboss-logging" ],
|
||||
"enabledEventTypes" : [ "SEND_RESET_PASSWORD", "UPDATE_TOTP", "REMOVE_TOTP", "REVOKE_GRANT", "LOGIN_ERROR", "CLIENT_LOGIN", "RESET_PASSWORD_ERROR", "IMPERSONATE_ERROR", "CODE_TO_TOKEN_ERROR", "CUSTOM_REQUIRED_ACTION", "RESTART_AUTHENTICATION", "UPDATE_PROFILE_ERROR", "IMPERSONATE", "LOGIN", "UPDATE_PASSWORD_ERROR", "CLIENT_INITIATED_ACCOUNT_LINKING", "REGISTER", "LOGOUT", "CLIENT_REGISTER", "IDENTITY_PROVIDER_LINK_ACCOUNT", "UPDATE_PASSWORD", "FEDERATED_IDENTITY_LINK_ERROR", "CLIENT_DELETE", "IDENTITY_PROVIDER_FIRST_LOGIN", "VERIFY_EMAIL", "CLIENT_DELETE_ERROR", "CLIENT_LOGIN_ERROR", "RESTART_AUTHENTICATION_ERROR", "REMOVE_FEDERATED_IDENTITY_ERROR", "EXECUTE_ACTIONS", "SEND_IDENTITY_PROVIDER_LINK_ERROR", "EXECUTE_ACTION_TOKEN_ERROR", "SEND_VERIFY_EMAIL", "EXECUTE_ACTIONS_ERROR", "REMOVE_FEDERATED_IDENTITY", "IDENTITY_PROVIDER_POST_LOGIN", "IDENTITY_PROVIDER_LINK_ACCOUNT_ERROR", "UPDATE_EMAIL", "REGISTER_ERROR", "REVOKE_GRANT_ERROR", "LOGOUT_ERROR", "UPDATE_EMAIL_ERROR", "EXECUTE_ACTION_TOKEN", "CLIENT_UPDATE_ERROR", "UPDATE_PROFILE", "FEDERATED_IDENTITY_LINK", "CLIENT_REGISTER_ERROR", "SEND_VERIFY_EMAIL_ERROR", "SEND_IDENTITY_PROVIDER_LINK", "RESET_PASSWORD", "CLIENT_INITIATED_ACCOUNT_LINKING_ERROR", "REMOVE_TOTP_ERROR", "VERIFY_EMAIL_ERROR", "SEND_RESET_PASSWORD_ERROR", "CLIENT_UPDATE", "IDENTITY_PROVIDER_POST_LOGIN_ERROR", "CUSTOM_REQUIRED_ACTION_ERROR", "UPDATE_TOTP_ERROR", "CODE_TO_TOKEN", "IDENTITY_PROVIDER_FIRST_LOGIN_ERROR" ],
|
||||
"enabledEventTypes" : [ "SEND_RESET_PASSWORD", "REMOVE_CREDENTIAL", "UPDATE_TOTP", "REMOVE_TOTP", "REVOKE_GRANT", "LOGIN_ERROR", "CLIENT_LOGIN", "RESET_PASSWORD_ERROR", "IMPERSONATE_ERROR", "CODE_TO_TOKEN_ERROR", "CUSTOM_REQUIRED_ACTION", "RESTART_AUTHENTICATION", "UPDATE_PROFILE_ERROR", "IMPERSONATE", "LOGIN", "UPDATE_CREDENTIAL_ERROR", "CLIENT_INITIATED_ACCOUNT_LINKING", "REGISTER", "LOGOUT", "CLIENT_REGISTER", "IDENTITY_PROVIDER_LINK_ACCOUNT", "UPDATE_CREDENTIAL", "UPDATE_PASSWORD", "FEDERATED_IDENTITY_LINK_ERROR", "CLIENT_DELETE", "IDENTITY_PROVIDER_FIRST_LOGIN", "VERIFY_EMAIL", "CLIENT_DELETE_ERROR", "CLIENT_LOGIN_ERROR", "RESTART_AUTHENTICATION_ERROR", "REMOVE_FEDERATED_IDENTITY_ERROR", "EXECUTE_ACTIONS", "SEND_IDENTITY_PROVIDER_LINK_ERROR", "EXECUTE_ACTION_TOKEN_ERROR", "SEND_VERIFY_EMAIL", "EXECUTE_ACTIONS_ERROR", "REMOVE_FEDERATED_IDENTITY", "IDENTITY_PROVIDER_POST_LOGIN", "IDENTITY_PROVIDER_LINK_ACCOUNT_ERROR", "UPDATE_EMAIL", "REGISTER_ERROR", "REVOKE_GRANT_ERROR", "LOGOUT_ERROR", "UPDATE_EMAIL_ERROR", "EXECUTE_ACTION_TOKEN", "CLIENT_UPDATE_ERROR", "UPDATE_PROFILE", "FEDERATED_IDENTITY_LINK", "CLIENT_REGISTER_ERROR", "SEND_VERIFY_EMAIL_ERROR", "SEND_IDENTITY_PROVIDER_LINK", "RESET_PASSWORD", "CLIENT_INITIATED_ACCOUNT_LINKING_ERROR", "REMOVE_CREDENTIAL_ERROR", "REMOVE_TOTP_ERROR", "VERIFY_EMAIL_ERROR", "SEND_RESET_PASSWORD_ERROR", "CLIENT_UPDATE", "IDENTITY_PROVIDER_POST_LOGIN_ERROR", "CUSTOM_REQUIRED_ACTION_ERROR", "UPDATE_TOTP_ERROR", "CODE_TO_TOKEN", "IDENTITY_PROVIDER_FIRST_LOGIN_ERROR" ],
|
||||
"adminEventsEnabled" : true,
|
||||
"adminEventsDetailsEnabled" : true,
|
||||
"requiredCredentials":[
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
"failureFactor" : 3,
|
||||
"eventsEnabled" : true,
|
||||
"eventsListeners" : [ "jboss-logging" ],
|
||||
"enabledEventTypes" : [ "SEND_RESET_PASSWORD", "UPDATE_TOTP", "REMOVE_TOTP", "REVOKE_GRANT", "LOGIN_ERROR", "CLIENT_LOGIN", "RESET_PASSWORD_ERROR", "IMPERSONATE_ERROR", "CODE_TO_TOKEN_ERROR", "CUSTOM_REQUIRED_ACTION", "RESTART_AUTHENTICATION", "UPDATE_PROFILE_ERROR", "IMPERSONATE", "LOGIN", "UPDATE_PASSWORD_ERROR", "CLIENT_INITIATED_ACCOUNT_LINKING", "REGISTER", "LOGOUT", "CLIENT_REGISTER", "IDENTITY_PROVIDER_LINK_ACCOUNT", "UPDATE_PASSWORD", "FEDERATED_IDENTITY_LINK_ERROR", "CLIENT_DELETE", "IDENTITY_PROVIDER_FIRST_LOGIN", "VERIFY_EMAIL", "CLIENT_DELETE_ERROR", "CLIENT_LOGIN_ERROR", "RESTART_AUTHENTICATION_ERROR", "REMOVE_FEDERATED_IDENTITY_ERROR", "EXECUTE_ACTIONS", "SEND_IDENTITY_PROVIDER_LINK_ERROR", "EXECUTE_ACTION_TOKEN_ERROR", "SEND_VERIFY_EMAIL", "EXECUTE_ACTIONS_ERROR", "REMOVE_FEDERATED_IDENTITY", "IDENTITY_PROVIDER_POST_LOGIN", "IDENTITY_PROVIDER_LINK_ACCOUNT_ERROR", "UPDATE_EMAIL", "REGISTER_ERROR", "REVOKE_GRANT_ERROR", "LOGOUT_ERROR", "UPDATE_EMAIL_ERROR", "EXECUTE_ACTION_TOKEN", "CLIENT_UPDATE_ERROR", "UPDATE_PROFILE", "FEDERATED_IDENTITY_LINK", "CLIENT_REGISTER_ERROR", "SEND_VERIFY_EMAIL_ERROR", "SEND_IDENTITY_PROVIDER_LINK", "RESET_PASSWORD", "CLIENT_INITIATED_ACCOUNT_LINKING_ERROR", "REMOVE_TOTP_ERROR", "VERIFY_EMAIL_ERROR", "SEND_RESET_PASSWORD_ERROR", "CLIENT_UPDATE", "IDENTITY_PROVIDER_POST_LOGIN_ERROR", "CUSTOM_REQUIRED_ACTION_ERROR", "UPDATE_TOTP_ERROR", "CODE_TO_TOKEN", "IDENTITY_PROVIDER_FIRST_LOGIN_ERROR" ],
|
||||
"enabledEventTypes" : [ "SEND_RESET_PASSWORD", "UPDATE_TOTP", "REMOVE_TOTP", "REMOVE_CREDENTIAL", "REVOKE_GRANT", "LOGIN_ERROR", "CLIENT_LOGIN", "RESET_PASSWORD_ERROR", "IMPERSONATE_ERROR", "CODE_TO_TOKEN_ERROR", "CUSTOM_REQUIRED_ACTION", "RESTART_AUTHENTICATION", "UPDATE_PROFILE_ERROR", "IMPERSONATE", "LOGIN", "UPDATE_PASSWORD_ERROR", "UPDATE_CREDENTIAL_ERROR", "CLIENT_INITIATED_ACCOUNT_LINKING", "REGISTER", "LOGOUT", "CLIENT_REGISTER", "IDENTITY_PROVIDER_LINK_ACCOUNT", "UPDATE_CREDENTIAL", "UPDATE_PASSWORD", "FEDERATED_IDENTITY_LINK_ERROR", "CLIENT_DELETE", "IDENTITY_PROVIDER_FIRST_LOGIN", "VERIFY_EMAIL", "CLIENT_DELETE_ERROR", "CLIENT_LOGIN_ERROR", "RESTART_AUTHENTICATION_ERROR", "REMOVE_FEDERATED_IDENTITY_ERROR", "EXECUTE_ACTIONS", "SEND_IDENTITY_PROVIDER_LINK_ERROR", "EXECUTE_ACTION_TOKEN_ERROR", "SEND_VERIFY_EMAIL", "EXECUTE_ACTIONS_ERROR", "REMOVE_FEDERATED_IDENTITY", "IDENTITY_PROVIDER_POST_LOGIN", "IDENTITY_PROVIDER_LINK_ACCOUNT_ERROR", "UPDATE_EMAIL", "REGISTER_ERROR", "REVOKE_GRANT_ERROR", "LOGOUT_ERROR", "UPDATE_EMAIL_ERROR", "EXECUTE_ACTION_TOKEN", "CLIENT_UPDATE_ERROR", "UPDATE_PROFILE", "FEDERATED_IDENTITY_LINK", "CLIENT_REGISTER_ERROR", "SEND_VERIFY_EMAIL_ERROR", "SEND_IDENTITY_PROVIDER_LINK", "RESET_PASSWORD", "CLIENT_INITIATED_ACCOUNT_LINKING_ERROR", "REMOVE_CREDENTIAL_ERROR", "REMOVE_TOTP_ERROR", "VERIFY_EMAIL_ERROR", "SEND_RESET_PASSWORD_ERROR", "CLIENT_UPDATE", "IDENTITY_PROVIDER_POST_LOGIN_ERROR", "CUSTOM_REQUIRED_ACTION_ERROR", "UPDATE_TOTP_ERROR", "CODE_TO_TOKEN", "IDENTITY_PROVIDER_FIRST_LOGIN_ERROR" ],
|
||||
"adminEventsEnabled" : true,
|
||||
"adminEventsDetailsEnabled" : true,
|
||||
"requiredCredentials":[
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
<#import "template.ftl" as layout>
|
||||
<@layout.emailLayout>
|
||||
${kcSanitize(msg("eventRemoveCredentialBodyHtml", event.details.credential_type!"unknown", event.date, event.ipAddress))?no_esc}
|
||||
</@layout.emailLayout>
|
|
@ -0,0 +1,4 @@
|
|||
<#import "template.ftl" as layout>
|
||||
<@layout.emailLayout>
|
||||
${kcSanitize(msg("eventUpdateCredentialBodyHtml", event.details.credential_type!"unknown", event.date, event.ipAddress))?no_esc}
|
||||
</@layout.emailLayout>
|
|
@ -33,6 +33,12 @@ eventUpdatePasswordBodyHtml=<p>Your password was changed on {0} from {1}. If thi
|
|||
eventUpdateTotpSubject=Update OTP
|
||||
eventUpdateTotpBody=OTP was updated for your account on {0} from {1}. If this was not you, please contact an administrator.
|
||||
eventUpdateTotpBodyHtml=<p>OTP was updated for your account on {0} from {1}. If this was not you, please contact an administrator.</p>
|
||||
eventUpdateCredentialSubject=Update credential
|
||||
eventUpdateCredentialBody=Your {0} credential was changed on {1} from {2}. If this was not you, please contact an administrator.
|
||||
eventUpdateCredentialBodyHtml=<p>Your {0} credential was changed on {1} from {2}. If this was not you, please contact an administrator.</p>
|
||||
eventRemoveCredentialSubject=Remove credential
|
||||
eventRemoveCredentialBody=Credential {0} was removed from your account on {1} from {2}. If this was not you, please contact an administrator.
|
||||
eventRemoveCredentialBodyHtml=<p>Credential {0} was removed from your account on {1} from {2}. If this was not you, please contact an administrator.</p>
|
||||
|
||||
requiredAction.CONFIGURE_TOTP=Configure OTP
|
||||
requiredAction.TERMS_AND_CONDITIONS=Terms and Conditions
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
<#ftl output_format="plainText">
|
||||
${msg("eventRemoveCredentialBody", event.details.credential_type!"unknown", event.date, event.ipAddress)}
|
|
@ -0,0 +1,2 @@
|
|||
<#ftl output_format="plainText">
|
||||
${msg("eventUpdateCredentialBody", event.details.credential_type!"unknown", event.date, event.ipAddress)}
|
Loading…
Reference in a new issue