+
Skip to content

Admin and User event configuration representation incomplete, leading to two chained calls to update realm #40843

Open
@MaikKingma

Description

@MaikKingma

Before reporting an issue

  • I have read and understood the above terms for submitting issues, and I understand that my issue may be closed without action if I do not follow them.

Area

core

Describe the bug

org/keycloak/representations/idm/RealmEventsConfigRepresentation.java is missing a field for the expiration time for the admin events:

public class RealmEventsConfigRepresentation {
    protected boolean eventsEnabled;
    protected Long eventsExpiration;
    protected List<String> eventsListeners;
    protected List<String> enabledEventTypes;
    
    protected Boolean adminEventsEnabled;
    protected Boolean adminEventsDetailsEnabled;
// missing the expiration time of admin events here

    // other methods
}

Effect:
That way it is not possible to update the expiration time of the admin events via the keycloak services method in org/keycloak/services/resources/admin/RealmAdminResource.java:

    @PUT
    @Path("events/config")
    @Consumes(MediaType.APPLICATION_JSON)
    @Tag(name = KeycloakOpenAPI.Admin.Tags.REALMS_ADMIN)
    @Operation( description = "Update the events provider Change the events provider and/or its configuration")
    @APIResponses(value = {
        @APIResponse(responseCode = "204", description = "No Content"),
        @APIResponse(responseCode = "403", description = "Forbidden")
    })
    public void updateRealmEventsConfig(final RealmEventsConfigRepresentation rep) {
        auth.realm().requireManageEvents();

        logger.debugf("updating realm events config: %s", realm.getName());
        new RealmManager(session).updateRealmEventsConfig(rep, realm);
        adminEvent.operation(OperationType.UPDATE).resource(ResourceType.REALM)
                .resourcePath(session.getContext().getUri()).representation(rep)
                // refresh the builder to consider old and new config
                .refreshRealmEventsConfig(session)
                .success();
    }

Now it seems to me that one of these calls should suffice for the purpose of persisting the new event settings. The two of them could lead to unwanted behaviour at this moment, depending on which call is executed first, as the second documented call updating the config directly via the serialised RealmEventsConfigRepresentation, misses the admin event expiration time.

Version

26.2.5

Regression

  • The issue is a regression

Expected behavior

  1. The representation RealmEventsConfigRepresentation should include the setting for admin events expiration.
  2. Ideally, one call is fired to update the realm event settings and not two. seems the direct call to the config endpoint is more precise.
  3. The placement of the fields is currently quite inconsistent, as eventsExpiration is located in the root of the realm representation, while adminEventsExpiration is nested in the attributes map of the realm representation. (Maybe this has a reason, which is not that apparent at first sight?)

Actual behavior

  • Two consecutive PUT calls are being triggered, one to {HOST}/admin/realms/example and another to {HSOT}/admin/realms/example/events/config.
  • the direct call on the realm includes a full realm representation including all event settings and the desired admin events expiration setting
  • the second call updates the config settings a second time, bu directly putting updated RealmEventsConfigRepresentation to the server, unfortunately missing a field for the admin event expiration settings.

How to Reproduce?

More details:
When using the admin UI to configure the admin and user events at URL {HOST}/admin/master/console/#/example/realm-settings/events an update to the settings of either user events or admin events and subsequently clicking save, will trigger two consecutive PUT calls, one to

Request URL {HOST}/admin/realms/example
Request Method PUT
Status Code 204 No Content
Payload: 
{
    "id": "example",
    "realm": "example",
    "displayName": "Example Product Realm",
    "notBefore": 0,
    "defaultSignatureAlgorithm": "RS256",
    "revokeRefreshToken": false,
    "refreshTokenMaxReuse": 0,
    "accessTokenLifespan": 300,
    "accessTokenLifespanForImplicitFlow": 900,
    "ssoSessionIdleTimeout": 1800,
    "ssoSessionMaxLifespan": 36000,
    "ssoSessionIdleTimeoutRememberMe": 0,
    "ssoSessionMaxLifespanRememberMe": 0,
    "offlineSessionIdleTimeout": 2592000,
    "offlineSessionMaxLifespanEnabled": false,
    "offlineSessionMaxLifespan": 5184000,
    "clientSessionIdleTimeout": 0,
    "clientSessionMaxLifespan": 0,
    "clientOfflineSessionIdleTimeout": 0,
    "clientOfflineSessionMaxLifespan": 0,
    "accessCodeLifespan": 60,
    "accessCodeLifespanUserAction": 300,
    "accessCodeLifespanLogin": 1800,
    "actionTokenGeneratedByAdminLifespan": 43200,
    "actionTokenGeneratedByUserLifespan": 300,
    "oauth2DeviceCodeLifespan": 600,
    "oauth2DevicePollingInterval": 5,
    "enabled": true,
    "sslRequired": "external",
    "registrationAllowed": false,
    "registrationEmailAsUsername": false,
    "rememberMe": false,
    "verifyEmail": false,
    "loginWithEmailAllowed": true,
    "duplicateEmailsAllowed": false,
    "resetPasswordAllowed": false,
    "editUsernameAllowed": false,
    "bruteForceProtected": true,
    "permanentLockout": false,
    "maxTemporaryLockouts": 0,
    "bruteForceStrategy": "MULTIPLE",
    "maxFailureWaitSeconds": 900,
    "minimumQuickLoginWaitSeconds": 60,
    "waitIncrementSeconds": 60,
    "quickLoginCheckMilliSeconds": 1000,
    "maxDeltaTimeSeconds": 43200,
    "failureFactor": 30,
    "defaultRole": {
        "id": "56119c93-934e-4ae3-b4bb-1f2b3551ae41",
        "name": "default-roles-example",
        "description": "${role_default-roles}",
        "composite": true,
        "clientRole": false,
        "containerId": "example"
    },
    "requiredCredentials": [
        "password"
    ],
    "otpPolicyType": "totp",
    "otpPolicyAlgorithm": "HmacSHA1",
    "otpPolicyInitialCounter": 0,
    "otpPolicyDigits": 6,
    "otpPolicyLookAheadWindow": 1,
    "otpPolicyPeriod": 30,
    "otpPolicyCodeReusable": false,
    "otpSupportedApplications": [
        "totpAppFreeOTPName",
        "totpAppGoogleName",
        "totpAppMicrosoftAuthenticatorName"
    ],
    "webAuthnPolicyRpEntityName": "keycloak",
    "webAuthnPolicySignatureAlgorithms": [
        "ES256",
        "RS256"
    ],
    "webAuthnPolicyRpId": "",
    "webAuthnPolicyAttestationConveyancePreference": "not specified",
    "webAuthnPolicyAuthenticatorAttachment": "not specified",
    "webAuthnPolicyRequireResidentKey": "not specified",
    "webAuthnPolicyUserVerificationRequirement": "not specified",
    "webAuthnPolicyCreateTimeout": 0,
    "webAuthnPolicyAvoidSameAuthenticatorRegister": false,
    "webAuthnPolicyAcceptableAaguids": [],
    "webAuthnPolicyExtraOrigins": [],
    "webAuthnPolicyPasswordlessRpEntityName": "keycloak",
    "webAuthnPolicyPasswordlessSignatureAlgorithms": [
        "ES256",
        "RS256"
    ],
    "webAuthnPolicyPasswordlessRpId": "",
    "webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified",
    "webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified",
    "webAuthnPolicyPasswordlessRequireResidentKey": "not specified",
    "webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified",
    "webAuthnPolicyPasswordlessCreateTimeout": 0,
    "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false,
    "webAuthnPolicyPasswordlessAcceptableAaguids": [],
    "webAuthnPolicyPasswordlessExtraOrigins": [],
    "browserSecurityHeaders": {
        "contentSecurityPolicyReportOnly": "",
        "xContentTypeOptions": "nosniff",
        "referrerPolicy": "no-referrer",
        "xRobotsTag": "none",
        "xFrameOptions": "SAMEORIGIN",
        "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';",
        "strictTransportSecurity": "max-age=31536000; includeSubDomains"
    },
    "smtpServer": {},
    "eventsEnabled": true,
    "eventsExpiration": 2592000,
    "eventsListeners": [
        "jboss-logging"
    ],
    "enabledEventTypes": [
        "SEND_RESET_PASSWORD",
        "UPDATE_CONSENT_ERROR",
        "GRANT_CONSENT",
        "VERIFY_PROFILE_ERROR",
        "REMOVE_TOTP",
        "REVOKE_GRANT",
        "UPDATE_TOTP",
        "LOGIN_ERROR",
        "CLIENT_LOGIN",
        "RESET_PASSWORD_ERROR",
        "UPDATE_CREDENTIAL",
        "IMPERSONATE_ERROR",
        "CODE_TO_TOKEN_ERROR",
        "CUSTOM_REQUIRED_ACTION",
        "OAUTH2_DEVICE_CODE_TO_TOKEN_ERROR",
        "RESTART_AUTHENTICATION",
        "IMPERSONATE",
        "UPDATE_PROFILE_ERROR",
        "LOGIN",
        "OAUTH2_DEVICE_VERIFY_USER_CODE",
        "UPDATE_PASSWORD_ERROR",
        "CLIENT_INITIATED_ACCOUNT_LINKING",
        "OAUTH2_EXTENSION_GRANT",
        "USER_DISABLED_BY_PERMANENT_LOCKOUT",
        "REMOVE_CREDENTIAL_ERROR",
        "TOKEN_EXCHANGE",
        "AUTHREQID_TO_TOKEN",
        "LOGOUT",
        "REGISTER",
        "DELETE_ACCOUNT_ERROR",
        "CLIENT_REGISTER",
        "IDENTITY_PROVIDER_LINK_ACCOUNT",
        "USER_DISABLED_BY_TEMPORARY_LOCKOUT",
        "DELETE_ACCOUNT",
        "UPDATE_PASSWORD",
        "CLIENT_DELETE",
        "FEDERATED_IDENTITY_LINK_ERROR",
        "IDENTITY_PROVIDER_FIRST_LOGIN",
        "CLIENT_DELETE_ERROR",
        "VERIFY_EMAIL",
        "CLIENT_LOGIN_ERROR",
        "RESTART_AUTHENTICATION_ERROR",
        "EXECUTE_ACTIONS",
        "REMOVE_FEDERATED_IDENTITY_ERROR",
        "TOKEN_EXCHANGE_ERROR",
        "PERMISSION_TOKEN",
        "FEDERATED_IDENTITY_OVERRIDE_LINK",
        "SEND_IDENTITY_PROVIDER_LINK_ERROR",
        "UPDATE_CREDENTIAL_ERROR",
        "EXECUTE_ACTION_TOKEN_ERROR",
        "OAUTH2_EXTENSION_GRANT_ERROR",
        "SEND_VERIFY_EMAIL",
        "OAUTH2_DEVICE_AUTH",
        "EXECUTE_ACTIONS_ERROR",
        "REMOVE_FEDERATED_IDENTITY",
        "OAUTH2_DEVICE_CODE_TO_TOKEN",
        "IDENTITY_PROVIDER_POST_LOGIN",
        "IDENTITY_PROVIDER_LINK_ACCOUNT_ERROR",
        "FEDERATED_IDENTITY_OVERRIDE_LINK_ERROR",
        "OAUTH2_DEVICE_VERIFY_USER_CODE_ERROR",
        "UPDATE_EMAIL",
        "REGISTER_ERROR",
        "REVOKE_GRANT_ERROR",
        "EXECUTE_ACTION_TOKEN",
        "LOGOUT_ERROR",
        "UPDATE_EMAIL_ERROR",
        "CLIENT_UPDATE_ERROR",
        "AUTHREQID_TO_TOKEN_ERROR",
        "INVITE_ORG_ERROR",
        "UPDATE_PROFILE",
        "CLIENT_REGISTER_ERROR",
        "FEDERATED_IDENTITY_LINK",
        "INVITE_ORG",
        "SEND_IDENTITY_PROVIDER_LINK",
        "SEND_VERIFY_EMAIL_ERROR",
        "RESET_PASSWORD",
        "CLIENT_INITIATED_ACCOUNT_LINKING_ERROR",
        "OAUTH2_DEVICE_AUTH_ERROR",
        "REMOVE_CREDENTIAL",
        "UPDATE_CONSENT",
        "REMOVE_TOTP_ERROR",
        "VERIFY_EMAIL_ERROR",
        "SEND_RESET_PASSWORD_ERROR",
        "CLIENT_UPDATE",
        "CUSTOM_REQUIRED_ACTION_ERROR",
        "IDENTITY_PROVIDER_POST_LOGIN_ERROR",
        "UPDATE_TOTP_ERROR",
        "CODE_TO_TOKEN",
        "VERIFY_PROFILE",
        "GRANT_CONSENT_ERROR",
        "IDENTITY_PROVIDER_FIRST_LOGIN_ERROR"
    ],
    "adminEventsEnabled": true,
    "adminEventsDetailsEnabled": true,
    "internationalizationEnabled": false,
    "supportedLocales": [],
    "browserFlow": "browser",
    "registrationFlow": "registration",
    "directGrantFlow": "direct grant",
    "resetCredentialsFlow": "reset credentials",
    "clientAuthenticationFlow": "clients",
    "dockerAuthenticationFlow": "docker auth",
    "firstBrokerLoginFlow": "first broker login",
    "attributes": {
        "cibaBackchannelTokenDeliveryMode": "poll",
        "cibaAuthRequestedUserHint": "login_hint",
        "oauth2DevicePollingInterval": "5",
        "clientOfflineSessionMaxLifespan": "0",
        "clientSessionIdleTimeout": "0",
        "clientOfflineSessionIdleTimeout": "0",
        "cibaInterval": "5",
        "realmReusableOtpCode": "false",
        "cibaExpiresIn": "120",
        "oauth2DeviceCodeLifespan": "600",
        "parRequestUriLifespan": "60",
        "clientSessionMaxLifespan": "0",
        "adminEventsExpiration": 2592000
    },
    "userManagedAccessAllowed": false,
    "organizationsEnabled": true,
    "verifiableCredentialsEnabled": false,
    "adminPermissionsEnabled": false,
    "clientProfiles": {
        "profiles": []
    },
    "clientPolicies": {
        "policies": []
    }
}

and a second one to

Request URL {HSOT}/admin/realms/example/events/config
Request Method PUT
Status Code 204 No Content
Payload: 
{
    "eventsEnabled": true,
    "adminEventsEnabled": true,
    "adminEventsDetailsEnabled": true,
    "eventsExpiration": 2505600,
    "eventsListeners": [
        "jboss-logging"
    ],
    "enabledEventTypes": [
        "SEND_RESET_PASSWORD",
        "UPDATE_CONSENT_ERROR",
        "GRANT_CONSENT",
        "VERIFY_PROFILE_ERROR",
        "REMOVE_TOTP",
        "REVOKE_GRANT",
        "UPDATE_TOTP",
        "LOGIN_ERROR",
        "CLIENT_LOGIN",
        "RESET_PASSWORD_ERROR",
        "UPDATE_CREDENTIAL",
        "IMPERSONATE_ERROR",
        "CODE_TO_TOKEN_ERROR",
        "CUSTOM_REQUIRED_ACTION",
        "OAUTH2_DEVICE_CODE_TO_TOKEN_ERROR",
        "RESTART_AUTHENTICATION",
        "IMPERSONATE",
        "UPDATE_PROFILE_ERROR",
        "LOGIN",
        "OAUTH2_DEVICE_VERIFY_USER_CODE",
        "UPDATE_PASSWORD_ERROR",
        "CLIENT_INITIATED_ACCOUNT_LINKING",
        "OAUTH2_EXTENSION_GRANT",
        "USER_DISABLED_BY_PERMANENT_LOCKOUT",
        "REMOVE_CREDENTIAL_ERROR",
        "TOKEN_EXCHANGE",
        "AUTHREQID_TO_TOKEN",
        "LOGOUT",
        "REGISTER",
        "DELETE_ACCOUNT_ERROR",
        "CLIENT_REGISTER",
        "IDENTITY_PROVIDER_LINK_ACCOUNT",
        "USER_DISABLED_BY_TEMPORARY_LOCKOUT",
        "DELETE_ACCOUNT",
        "UPDATE_PASSWORD",
        "CLIENT_DELETE",
        "FEDERATED_IDENTITY_LINK_ERROR",
        "IDENTITY_PROVIDER_FIRST_LOGIN",
        "CLIENT_DELETE_ERROR",
        "VERIFY_EMAIL",
        "CLIENT_LOGIN_ERROR",
        "RESTART_AUTHENTICATION_ERROR",
        "EXECUTE_ACTIONS",
        "REMOVE_FEDERATED_IDENTITY_ERROR",
        "TOKEN_EXCHANGE_ERROR",
        "PERMISSION_TOKEN",
        "FEDERATED_IDENTITY_OVERRIDE_LINK",
        "SEND_IDENTITY_PROVIDER_LINK_ERROR",
        "UPDATE_CREDENTIAL_ERROR",
        "EXECUTE_ACTION_TOKEN_ERROR",
        "OAUTH2_EXTENSION_GRANT_ERROR",
        "SEND_VERIFY_EMAIL",
        "OAUTH2_DEVICE_AUTH",
        "EXECUTE_ACTIONS_ERROR",
        "REMOVE_FEDERATED_IDENTITY",
        "OAUTH2_DEVICE_CODE_TO_TOKEN",
        "IDENTITY_PROVIDER_POST_LOGIN",
        "IDENTITY_PROVIDER_LINK_ACCOUNT_ERROR",
        "FEDERATED_IDENTITY_OVERRIDE_LINK_ERROR",
        "OAUTH2_DEVICE_VERIFY_USER_CODE_ERROR",
        "UPDATE_EMAIL",
        "REGISTER_ERROR",
        "REVOKE_GRANT_ERROR",
        "EXECUTE_ACTION_TOKEN",
        "LOGOUT_ERROR",
        "UPDATE_EMAIL_ERROR",
        "CLIENT_UPDATE_ERROR",
        "AUTHREQID_TO_TOKEN_ERROR",
        "INVITE_ORG_ERROR",
        "UPDATE_PROFILE",
        "CLIENT_REGISTER_ERROR",
        "FEDERATED_IDENTITY_LINK",
        "INVITE_ORG",
        "SEND_IDENTITY_PROVIDER_LINK",
        "SEND_VERIFY_EMAIL_ERROR",
        "RESET_PASSWORD",
        "CLIENT_INITIATED_ACCOUNT_LINKING_ERROR",
        "OAUTH2_DEVICE_AUTH_ERROR",
        "REMOVE_CREDENTIAL",
        "UPDATE_CONSENT",
        "REMOVE_TOTP_ERROR",
        "VERIFY_EMAIL_ERROR",
        "SEND_RESET_PASSWORD_ERROR",
        "CLIENT_UPDATE",
        "CUSTOM_REQUIRED_ACTION_ERROR",
        "IDENTITY_PROVIDER_POST_LOGIN_ERROR",
        "UPDATE_TOTP_ERROR",
        "CODE_TO_TOKEN",
        "VERIFY_PROFILE",
        "GRANT_CONSENT_ERROR",
        "IDENTITY_PROVIDER_FIRST_LOGIN_ERROR"
    ]
}
Image Image

Anything else?

It affects core and services

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载