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`
|
||||
|
|
|
@ -99,7 +99,7 @@ When you log in with the Admin CLI, you specify:
|
|||
* A realm
|
||||
* A user name
|
||||
|
||||
Another option is to specify a clientId only, which creates a unique service account for you to use.
|
||||
Another option is to specify a clientId only, which creates a unique service account for you to use.
|
||||
|
||||
When you log in using a user name, use a password for the specified user. When you log in using a clientId, you need the client secret only, not the user password. You can also use the `Signed JWT` rather than the client secret.
|
||||
|
||||
|
@ -119,7 +119,7 @@ The second mechanism authenticates each command invocation for the duration of t
|
|||
For example, when performing an operation, specify all the information required for authentication.
|
||||
[options="nowrap",subs="attributes+"]
|
||||
----
|
||||
$ kcadm.sh get realms --no-config --server http://localhost:8080{kc_base_path} --realm master --user admin
|
||||
$ kcadm.sh get realms --no-config --server http://localhost:8080{kc_base_path} --realm master --user admin
|
||||
----
|
||||
|
||||
Run the `kcadm.sh help` command for more information on using the Admin CLI.
|
||||
|
@ -131,9 +131,9 @@ If you do not specify the --password option (it is generally recommended to not
|
|||
[[_working_with_alternative_configurations]]
|
||||
=== Working with alternative configurations
|
||||
|
||||
By default, the Admin CLI maintains a configuration file named `kcadm.config`. {project_name} places this file in the user's home directory.
|
||||
In Linux-based systems, the full pathname is `$HOME/.keycloak/kcadm.config`.
|
||||
In Windows, the full pathname is `%HOMEPATH%\.keycloak\kcadm.config`.
|
||||
By default, the Admin CLI maintains a configuration file named `kcadm.config`. {project_name} places this file in the user's home directory.
|
||||
In Linux-based systems, the full pathname is `$HOME/.keycloak/kcadm.config`.
|
||||
In Windows, the full pathname is `%HOMEPATH%\.keycloak\kcadm.config`.
|
||||
|
||||
You can use the `--config` option to point to a different file or location so you can maintain multiple authenticated sessions in parallel.
|
||||
|
||||
|
@ -199,7 +199,7 @@ The `create` and `update` commands send a JSON body to the server. You can use `
|
|||
|
||||
[NOTE]
|
||||
====
|
||||
The value in name=value pairs used in --set, -s options, are assumed to be JSON. If it cannot be parsed as valid JSON, then it will be sent to the server as a text value.
|
||||
The value in name=value pairs used in --set, -s options, are assumed to be JSON. If it cannot be parsed as valid JSON, then it will be sent to the server as a text value.
|
||||
|
||||
If the value is enclosed in quotes after shell processing, but is not valid JSON, the quotes will be stripped and the rest of the value will be sent as text. This behavior is deprecated, please consider specifying your value without quotes or a valid JSON string literal with double quotes.
|
||||
====
|
||||
|
@ -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.
|
||||
|
@ -1218,7 +1218,7 @@ $ kcadm.sh remove-roles -r demorealm --uusername testuser --cclientid realm-mana
|
|||
[discrete]
|
||||
==== Listing a user's sessions
|
||||
|
||||
. Identify the user's ID,
|
||||
. Identify the user's ID,
|
||||
. Use the ID to compose an endpoint URI, such as `users/ID/sessions`.
|
||||
. Use the `get` command to retrieve a list of the user's sessions.
|
||||
+
|
||||
|
@ -1406,7 +1406,7 @@ $ kcadm.sh get-roles -r demorealm --gname Group --available
|
|||
|
||||
Use the `get-roles` command to list assigned, available, and effective client roles for a group.
|
||||
|
||||
. Specify the target group by name (`--gname` option) or ID (`--gid` option),
|
||||
. Specify the target group by name (`--gname` option) or ID (`--gid` option),
|
||||
. Specify the client by the clientId attribute (`--cclientid` option) or ID (`--id` option) to list *assigned* client roles for the user.
|
||||
+
|
||||
For example:
|
||||
|
@ -1895,7 +1895,7 @@ $ kcadm get "authentication/config/dd91611a-d25c-421a-87e2-227c18421833" -r demo
|
|||
==== Updating configuration for an execution
|
||||
|
||||
. Get the execution for the flow.
|
||||
. Get the flow's `authenticationConfig` attribute.
|
||||
. Get the flow's `authenticationConfig` attribute.
|
||||
. Note the config ID from the attribute.
|
||||
. Run the `update` command on the `authentication/config/ID` endpoint.
|
||||
|
||||
|
|
|
@ -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" : [ {
|
||||
|
|
|
@ -3241,4 +3241,12 @@ temporaryService=Temporary admin service account. Ensure it is replaced with a p
|
|||
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?
|
||||
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;
|
||||
|
@ -55,7 +56,7 @@ public class UpdateTotp implements RequiredActionProvider, RequiredActionFactory
|
|||
public InitiatedActionSupport initiatedActionSupport() {
|
||||
return InitiatedActionSupport.SUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void evaluateTriggers(RequiredActionContext context) {
|
||||
}
|
||||
|
@ -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<>();
|
||||
|
|
|
@ -107,7 +107,7 @@ import static org.keycloak.testsuite.forms.VerifyProfileTest.PERMISSIONS_ALL;
|
|||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class AccountRestServiceTest extends AbstractRestServiceTest {
|
||||
|
||||
|
||||
@Rule
|
||||
public AssertEvents events = new AssertEvents(this);
|
||||
|
||||
|
@ -227,7 +227,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest {
|
|||
UserRepresentation user = getUser(false);
|
||||
assertNull(user.getUserProfileMetadata());
|
||||
}
|
||||
|
||||
|
||||
protected static UserProfileAttributeMetadata getUserProfileAttributeMetadata(UserRepresentation user, String attName) {
|
||||
if(user.getUserProfileMetadata() == null)
|
||||
return null;
|
||||
|
@ -238,7 +238,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
protected static UserProfileAttributeMetadata assertUserProfileAttributeMetadata(UserRepresentation user, String attName, String displayName, boolean required, boolean readOnly) {
|
||||
UserProfileAttributeMetadata uam = getUserProfileAttributeMetadata(user, attName);
|
||||
|
||||
|
@ -310,7 +310,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reproducer for bugs KEYCLOAK-17424 and KEYCLOAK-17582
|
||||
*/
|
||||
|
@ -323,13 +323,13 @@ public class AccountRestServiceTest extends AbstractRestServiceTest {
|
|||
|
||||
realmRep.setRegistrationEmailAsUsername(false);
|
||||
adminClient.realm("test").update(realmRep);
|
||||
|
||||
|
||||
//set flag over adminClient to initial value
|
||||
UserResource userResource = adminClient.realm("test").users().get(user.getId());
|
||||
org.keycloak.representations.idm.UserRepresentation ur = userResource.toRepresentation();
|
||||
ur.setEmailVerified(true);
|
||||
userResource.update(ur);
|
||||
//make sure flag is correct before the test
|
||||
//make sure flag is correct before the test
|
||||
user = getUser();
|
||||
assertEquals(true, user.isEmailVerified());
|
||||
|
||||
|
@ -339,7 +339,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest {
|
|||
assertEquals(originalEmail, user.getEmail());
|
||||
assertEquals(true, user.isEmailVerified());
|
||||
|
||||
|
||||
|
||||
// Update email - flag must be reset to false
|
||||
user.setEmail("bobby@localhost");
|
||||
user = updateAndGet(user);
|
||||
|
@ -402,7 +402,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest {
|
|||
.detail(Details.UPDATED_LAST_NAME, "Simpsons")
|
||||
.assertEvent();
|
||||
events.assertEmpty();
|
||||
|
||||
|
||||
} finally {
|
||||
RealmRepresentation realmRep = adminClient.realm("test").toRepresentation();
|
||||
realmRep.setEditUsernameAllowed(true);
|
||||
|
@ -417,7 +417,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest {
|
|||
assertEquals(204, response.getStatus());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testUpdateProfile() throws IOException {
|
||||
String userProfileCfg = "{\"attributes\": ["
|
||||
|
@ -455,7 +455,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest {
|
|||
assertEquals("val1", user.getAttributes().get("attr1").get(0));
|
||||
assertEquals(1, user.getAttributes().get("attr2").size());
|
||||
assertEquals("val2", user.getAttributes().get("attr2").get(0));
|
||||
|
||||
|
||||
// Update attributes
|
||||
user.getAttributes().remove("attr1");
|
||||
user.getAttributes().get("attr2").add("val3");
|
||||
|
@ -637,7 +637,7 @@ public class AccountRestServiceTest extends AbstractRestServiceTest {
|
|||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected UserRepresentation updateAndGet(UserRepresentation user) throws IOException {
|
||||
SimpleHttp a = SimpleHttpDefault.doPost(getAccountUrl(null), httpClient).auth(tokenUtil.getToken()).json(user);
|
||||
try {
|
||||
|
@ -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;
|
||||
|
@ -210,7 +211,7 @@ public class LoginTest extends AbstractTestRealmKeycloakTest {
|
|||
//POST request to http://localhost:8180/auth/realms/test/protocol/openid-connect/auth;
|
||||
UriBuilder b = OIDCLoginProtocolService.authUrl(UriBuilder.fromUri(AUTH_SERVER_ROOT));
|
||||
Response response = client.target(b.build(oauth.getRealm())).request().post(oauth.getLoginEntityForPOST());
|
||||
|
||||
|
||||
assertThat(response.getStatus(), is(equalTo(200)));
|
||||
assertThat(response, Matchers.body(containsString("Sign in")));
|
||||
|
||||
|
@ -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();
|
||||
|
@ -710,14 +712,14 @@ public class LoginTest extends AbstractTestRealmKeycloakTest {
|
|||
//login without remember me
|
||||
loginPage.setRememberMe(false);
|
||||
loginPage.login("login-test", "password");
|
||||
|
||||
|
||||
// Expire session
|
||||
loginEvent = events.expectLogin().user(userId)
|
||||
.detail(Details.USERNAME, "login-test")
|
||||
.assertEvent();
|
||||
sessionId = loginEvent.getSessionId();
|
||||
testingClient.testing().removeUserSession("test", sessionId);
|
||||
|
||||
|
||||
// Assert rememberMe not checked nor username/email prefilled
|
||||
loginPage.open();
|
||||
assertFalse(loginPage.isRememberMeChecked());
|
||||
|
@ -726,7 +728,7 @@ public class LoginTest extends AbstractTestRealmKeycloakTest {
|
|||
setRememberMe(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
// KEYCLOAK-3181
|
||||
public void loginWithEmailUserAndRememberMe() {
|
||||
|
@ -752,7 +754,7 @@ public class LoginTest extends AbstractTestRealmKeycloakTest {
|
|||
// Assert rememberMe checked and username/email prefilled
|
||||
loginPage.open();
|
||||
assertTrue(loginPage.isRememberMeChecked());
|
||||
|
||||
|
||||
Assert.assertEquals("login@test.com", loginPage.getUsername());
|
||||
|
||||
loginPage.setRememberMe(false);
|
||||
|
|
|
@ -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