diff --git a/.ci/auth/keycloak/0-realm-pulsar-partial-export.json b/.ci/auth/keycloak/0-realm-pulsar-partial-export.json new file mode 100644 index 0000000..4c57c7a --- /dev/null +++ b/.ci/auth/keycloak/0-realm-pulsar-partial-export.json @@ -0,0 +1,1738 @@ +{ + "id": "a091a8f3-7639-4755-b93f-7d8ce91b2c2e", + "realm": "pulsar", + "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": false, + "permanentLockout": false, + "maxTemporaryLockouts": 0, + "bruteForceStrategy": "MULTIPLE", + "maxFailureWaitSeconds": 900, + "minimumQuickLoginWaitSeconds": 60, + "waitIncrementSeconds": 60, + "quickLoginCheckMilliSeconds": 1000, + "maxDeltaTimeSeconds": 43200, + "failureFactor": 30, + "defaultRole": { + "id": "51c3d6dc-705b-4ca3-b857-33cebbfffe68", + "name": "default-roles-pulsar-default", + "description": "${role_default-roles}", + "composite": true, + "clientRole": false, + "containerId": "a091a8f3-7639-4755-b93f-7d8ce91b2c2e" + }, + "requiredCredentials": [ + "password" + ], + "otpPolicyType": "totp", + "otpPolicyAlgorithm": "HmacSHA1", + "otpPolicyInitialCounter": 0, + "otpPolicyDigits": 6, + "otpPolicyLookAheadWindow": 1, + "otpPolicyPeriod": 30, + "otpPolicyCodeReusable": false, + "otpSupportedApplications": [ + "totpAppFreeOTPName", + "totpAppGoogleName", + "totpAppMicrosoftAuthenticatorName" + ], + "localizationTexts": {}, + "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": [], + "scopeMappings": [ + { + "clientScope": "offline_access", + "roles": [ + "offline_access" + ] + } + ], + "clientScopes": [ + { + "id": "7ce729fd-becc-41bc-84b0-4a9470018def", + "name": "organization", + "description": "Additional claims about the organization a subject belongs to", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${organizationScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "bbadeda2-3550-4a7a-83ba-2492762df0b0", + "name": "organization", + "protocol": "openid-connect", + "protocolMapper": "oidc-organization-membership-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "organization", + "jsonType.label": "String", + "multivalued": "true" + } + } + ] + }, + { + "id": "600cafce-81f5-4935-9023-c1b38174d0cd", + "name": "service_account", + "description": "Specific scope for a client enabled for service accounts", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "52742a30-0943-4276-b306-4b9b059450f9", + "name": "Client Host", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientHost", + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientHost", + "jsonType.label": "String" + } + }, + { + "id": "98121d81-40f1-41cd-932a-b5391e6d0ec0", + "name": "Client IP Address", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientAddress", + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientAddress", + "jsonType.label": "String" + } + }, + { + "id": "0ff70490-5fe2-4eb9-af9f-fdc5b83f2e36", + "name": "Client ID", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "client_id", + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "client_id", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "2247ad9c-e11a-47c7-b20f-56d491275721", + "name": "role_list", + "description": "SAML role list", + "protocol": "saml", + "attributes": { + "consent.screen.text": "${samlRoleListScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "e98451b7-e87e-4a46-8bdb-561ed167887a", + "name": "role list", + "protocol": "saml", + "protocolMapper": "saml-role-list-mapper", + "consentRequired": false, + "config": { + "single": "false", + "attribute.nameformat": "Basic", + "attribute.name": "Role" + } + } + ] + }, + { + "id": "74852642-b847-412a-92ac-05daa13dbe16", + "name": "phone", + "description": "OpenID Connect built-in scope: phone", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${phoneScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "081ac0e2-f730-464d-b7d1-ddcf4f84d465", + "name": "phone number", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "phoneNumber", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number", + "jsonType.label": "String" + } + }, + { + "id": "e8ef8882-4f54-42d6-b4ab-4e9fba4c436a", + "name": "phone number verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "phoneNumberVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number_verified", + "jsonType.label": "boolean" + } + } + ] + }, + { + "id": "26e36009-162d-4f44-8bc1-55abb41f5b8a", + "name": "email", + "description": "OpenID Connect built-in scope: email", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${emailScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "7fe7cfae-b6a8-42d4-8fb4-5c54175dc01f", + "name": "email", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "email", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email", + "jsonType.label": "String" + } + }, + { + "id": "17265e7f-afe8-45c5-b7b4-ff4f30a9d44a", + "name": "email verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "emailVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email_verified", + "jsonType.label": "boolean" + } + } + ] + }, + { + "id": "668419cd-3bbd-43fb-90ac-5d96a608bb41", + "name": "roles", + "description": "OpenID Connect scope for add user roles to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "consent.screen.text": "${rolesScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "7fd6189b-c50b-4392-b649-8c0b5cffdd40", + "name": "client roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-client-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "resource_access.${client_id}.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "4ccceb8f-605b-4e3f-91ee-e0f6003e8095", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": { + "access.token.claim": "true", + "introspection.token.claim": "true" + } + }, + { + "id": "8b99570f-b9da-4b7c-a621-b63889248391", + "name": "realm roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "realm_access.roles", + "jsonType.label": "String", + "multivalued": "true" + } + } + ] + }, + { + "id": "e7f8dbd0-c217-407c-961e-8627d2a94a82", + "name": "profile", + "description": "OpenID Connect built-in scope: profile", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${profileScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "6d297ee8-0fa9-4c56-8e45-6070f6b18565", + "name": "picture", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "picture", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "picture", + "jsonType.label": "String" + } + }, + { + "id": "74f5a2cb-af67-4a8c-ad68-b52a5b5ef2bf", + "name": "updated at", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "updatedAt", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "updated_at", + "jsonType.label": "long" + } + }, + { + "id": "107758b2-42ad-4c54-b795-1ccca64166b5", + "name": "nickname", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "nickname", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "nickname", + "jsonType.label": "String" + } + }, + { + "id": "063ba9e3-7573-420b-9958-80d9e50e1af0", + "name": "gender", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "gender", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "gender", + "jsonType.label": "String" + } + }, + { + "id": "0ba5e2a9-f6c4-4d88-ba31-c9cfd25e8ab2", + "name": "family name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "lastName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "family_name", + "jsonType.label": "String" + } + }, + { + "id": "37b16eb3-1662-4244-848d-c0c26008f302", + "name": "website", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "website", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "website", + "jsonType.label": "String" + } + }, + { + "id": "911832ac-6879-444a-b5db-febf45d5aa8b", + "name": "zoneinfo", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "zoneinfo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "zoneinfo", + "jsonType.label": "String" + } + }, + { + "id": "653aa529-92ee-4683-9819-63a9fd3580cd", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + }, + { + "id": "e9a49e58-f155-4cab-bff0-8f7b46be59de", + "name": "given name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "firstName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "given_name", + "jsonType.label": "String" + } + }, + { + "id": "d67f37d3-c49f-4fce-afd6-7b7b2225794b", + "name": "middle name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "middleName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "middle_name", + "jsonType.label": "String" + } + }, + { + "id": "86775475-1f98-4377-bb8c-523231dcec59", + "name": "username", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "preferred_username", + "jsonType.label": "String" + } + }, + { + "id": "7d22da0b-7f66-4837-bc51-8bec71a7043a", + "name": "profile", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "profile", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "profile", + "jsonType.label": "String" + } + }, + { + "id": "b39cf15f-7f2a-4895-989e-765b0ba984af", + "name": "birthdate", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "birthdate", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "birthdate", + "jsonType.label": "String" + } + }, + { + "id": "7ea8b254-2099-41e1-a5f2-ab4b9742336b", + "name": "full name", + "protocol": "openid-connect", + "protocolMapper": "oidc-full-name-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + } + ] + }, + { + "id": "f515f0db-361c-427e-81d2-e0c053bb514e", + "name": "saml_organization", + "description": "Organization Membership", + "protocol": "saml", + "attributes": { + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "ae9c427e-733b-4dba-8f6c-967177a0d432", + "name": "organization", + "protocol": "saml", + "protocolMapper": "saml-organization-membership-mapper", + "consentRequired": false, + "config": {} + } + ] + }, + { + "id": "9fc5f321-c573-4198-b21a-a7dc17b8c2f6", + "name": "web-origins", + "description": "OpenID Connect scope for add allowed web origins to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "consent.screen.text": "", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "6e49fcf9-b7a4-4cf3-b94e-f4b8a322d33e", + "name": "allowed web origins", + "protocol": "openid-connect", + "protocolMapper": "oidc-allowed-origins-mapper", + "consentRequired": false, + "config": { + "access.token.claim": "true", + "introspection.token.claim": "true" + } + } + ] + }, + { + "id": "7f64fc10-7b39-491a-87a5-1ac5d920de4d", + "name": "offline_access", + "description": "OpenID Connect built-in scope: offline_access", + "protocol": "openid-connect", + "attributes": { + "consent.screen.text": "${offlineAccessScopeConsentText}", + "display.on.consent.screen": "true" + } + }, + { + "id": "3a06b9ac-80c5-4640-b053-156600eab704", + "name": "microprofile-jwt", + "description": "Microprofile - JWT built-in scope", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "1cbebacf-5962-4d7e-90cb-a74bada80c6f", + "name": "upn", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "upn", + "jsonType.label": "String" + } + }, + { + "id": "01eb1bad-1ba4-42cb-a0e0-cee5eb0fa0f3", + "name": "groups", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "multivalued": "true", + "user.attribute": "foo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "groups", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "21ff18ac-fd0d-40c6-9f17-dad18cf1e1e4", + "name": "basic", + "description": "OpenID Connect scope for add all basic claims to the token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "3d67996d-3396-480d-9919-1d2f65ad5653", + "name": "auth_time", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "AUTH_TIME", + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "auth_time", + "jsonType.label": "long" + } + }, + { + "id": "3951ed0a-4414-4613-b0d5-1a52b792cb0e", + "name": "sub", + "protocol": "openid-connect", + "protocolMapper": "oidc-sub-mapper", + "consentRequired": false, + "config": { + "access.token.claim": "true", + "introspection.token.claim": "true" + } + } + ] + }, + { + "id": "e1105b2d-852e-499e-bfd5-bab0b443c946", + "name": "address", + "description": "OpenID Connect built-in scope: address", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${addressScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "da7e0faf-eefb-40f1-ad5f-7dd3da39d03a", + "name": "address", + "protocol": "openid-connect", + "protocolMapper": "oidc-address-mapper", + "consentRequired": false, + "config": { + "user.attribute.formatted": "formatted", + "user.attribute.country": "country", + "introspection.token.claim": "true", + "user.attribute.postal_code": "postal_code", + "userinfo.token.claim": "true", + "user.attribute.street": "street", + "id.token.claim": "true", + "user.attribute.region": "region", + "access.token.claim": "true", + "user.attribute.locality": "locality" + } + } + ] + }, + { + "id": "1aaa83b3-b912-41bb-bace-5d8e82464f7c", + "name": "acr", + "description": "OpenID Connect scope for add acr (authentication context class reference) to the token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "a437eb33-cbee-4e98-852d-4b8e5e789945", + "name": "acr loa level", + "protocol": "openid-connect", + "protocolMapper": "oidc-acr-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "access.token.claim": "true", + "introspection.token.claim": "true" + } + } + ] + } + ], + "defaultDefaultClientScopes": [ + "role_list", + "saml_organization", + "profile", + "email", + "roles", + "web-origins", + "acr", + "basic" + ], + "defaultOptionalClientScopes": [ + "offline_access", + "address", + "phone", + "microprofile-jwt", + "organization" + ], + "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": false, + "eventsListeners": [ + "jboss-logging" + ], + "enabledEventTypes": [], + "adminEventsEnabled": false, + "adminEventsDetailsEnabled": false, + "identityProviders": [], + "identityProviderMappers": [], + "components": { + "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [ + { + "id": "8f2ef069-15bf-4ac9-8974-ef7134bb29f2", + "name": "Consent Required", + "providerId": "consent-required", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "e7f82e79-c448-4b75-b59e-5feef58b7f7c", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "36043ecc-f0a2-4873-b15e-8d6956767ad2", + "name": "Full Scope Disabled", + "providerId": "scope", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "51b8b4d3-8436-45c0-8c5b-a4d3f97480e2", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "oidc-usermodel-attribute-mapper", + "oidc-sha256-pairwise-sub-mapper", + "saml-user-property-mapper", + "saml-role-list-mapper", + "oidc-address-mapper", + "oidc-usermodel-property-mapper", + "saml-user-attribute-mapper", + "oidc-full-name-mapper" + ] + } + }, + { + "id": "88c21878-9202-48d5-b43c-568ffc88affd", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "oidc-full-name-mapper", + "saml-user-property-mapper", + "oidc-usermodel-attribute-mapper", + "oidc-address-mapper", + "saml-user-attribute-mapper", + "oidc-usermodel-property-mapper", + "oidc-sha256-pairwise-sub-mapper", + "saml-role-list-mapper" + ] + } + }, + { + "id": "cca63435-8774-4083-8f82-7a9cf171e297", + "name": "Trusted Hosts", + "providerId": "trusted-hosts", + "subType": "anonymous", + "subComponents": {}, + "config": { + "host-sending-registration-request-must-match": [ + "true" + ], + "client-uris-must-match": [ + "true" + ] + } + }, + { + "id": "a685d2a8-45e9-4d60-b45e-39f6c1612218", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "ab420dca-cd02-413b-8afd-335b5a51d85e", + "name": "Max Clients Limit", + "providerId": "max-clients", + "subType": "anonymous", + "subComponents": {}, + "config": { + "max-clients": [ + "200" + ] + } + } + ], + "org.keycloak.keys.KeyProvider": [ + { + "id": "4194a570-993a-4222-b3ad-fd5830ebf13e", + "name": "hmac-generated-hs512", + "providerId": "hmac-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ], + "algorithm": [ + "HS512" + ] + } + }, + { + "id": "ea278047-e4ac-4db8-b2d8-460b48adb594", + "name": "rsa-enc-generated", + "providerId": "rsa-enc-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ], + "algorithm": [ + "RSA-OAEP" + ] + } + }, + { + "id": "eae7c636-e67c-46b3-9900-8b10ac49eeef", + "name": "aes-generated", + "providerId": "aes-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + }, + { + "id": "e63c3db9-5007-4e80-8fca-8a1ee62b9827", + "name": "rsa-generated", + "providerId": "rsa-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + } + ] + }, + "internationalizationEnabled": false, + "supportedLocales": [], + "authenticationFlows": [ + { + "id": "b1fed5ca-3de4-4b1e-a42e-de2c894dcc0f", + "alias": "Account verification options", + "description": "Method with which to verity the existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-email-verification", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Verify Existing Account by Re-authentication", + "userSetupAllowed": false + } + ] + }, + { + "id": "76e4213a-e9db-4f9a-a871-be77373f9342", + "alias": "Browser - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "2958eae7-cf87-47d8-8381-8ec2d586672e", + "alias": "Browser - Conditional Organization", + "description": "Flow to determine if the organization identity-first login is to be used", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "organization", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "7be60050-9b54-4401-b0d8-7a9cc49a58e6", + "alias": "Direct Grant - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "6e6bc876-0844-4d2f-99c6-4548aa022e7e", + "alias": "First Broker Login - Conditional Organization", + "description": "Flow to determine if the authenticator that adds organization members is to be used", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "idp-add-organization-member", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "aa69d07c-8fef-4ebc-978c-c9d28b213618", + "alias": "First broker login - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "24fb0ae5-64fb-47a2-a246-089b08f7ff42", + "alias": "Handle Existing Account", + "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-confirm-link", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Account verification options", + "userSetupAllowed": false + } + ] + }, + { + "id": "10582fd7-9dfd-4699-91df-803b20b02828", + "alias": "Organization", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 10, + "autheticatorFlow": true, + "flowAlias": "Browser - Conditional Organization", + "userSetupAllowed": false + } + ] + }, + { + "id": "7df1a254-1b40-4e96-9e7c-0fded2cebd2c", + "alias": "Reset - Conditional OTP", + "description": "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "ac9a27ff-dac0-434a-a919-db94d0d9f450", + "alias": "User creation or linking", + "description": "Flow for the existing/non-existing user alternatives", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "create unique user config", + "authenticator": "idp-create-user-if-unique", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Handle Existing Account", + "userSetupAllowed": false + } + ] + }, + { + "id": "a775b386-817a-4f35-a921-4764fac52a8c", + "alias": "Verify Existing Account by Re-authentication", + "description": "Reauthentication of existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "First broker login - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "747225a2-f79c-42f0-a5c3-76084573fa7e", + "alias": "browser", + "description": "Browser based authentication", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-cookie", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-spnego", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "identity-provider-redirector", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 25, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 26, + "autheticatorFlow": true, + "flowAlias": "Organization", + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "forms", + "userSetupAllowed": false + } + ] + }, + { + "id": "b832a068-5dab-45e6-aa12-9dfb77d8c57a", + "alias": "clients", + "description": "Base authentication for clients", + "providerId": "client-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "client-secret", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-secret-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-x509", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 40, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "ee1208e4-5ad5-447c-9219-d63aa909e8ae", + "alias": "direct grant", + "description": "OpenID Connect Resource Owner Grant", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "direct-grant-validate-username", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "Direct Grant - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "aca71852-24f7-4a05-9797-04d42d697e31", + "alias": "docker auth", + "description": "Used by Docker clients to authenticate against the IDP", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "docker-http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "cef0d3b4-12f2-4fd0-87a4-f6c9cd6b672d", + "alias": "first broker login", + "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "review profile config", + "authenticator": "idp-review-profile", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "User creation or linking", + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 50, + "autheticatorFlow": true, + "flowAlias": "First Broker Login - Conditional Organization", + "userSetupAllowed": false + } + ] + }, + { + "id": "94d70dbb-9be6-45c5-96a1-61fa75dabce3", + "alias": "forms", + "description": "Username, password, otp and other auth forms.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Browser - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "71834174-1282-4573-996a-c5e77dd4a9f7", + "alias": "registration", + "description": "Registration flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-page-form", + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": true, + "flowAlias": "registration form", + "userSetupAllowed": false + } + ] + }, + { + "id": "3bd54baa-1664-45a7-b3d2-a53a5a3537b9", + "alias": "registration form", + "description": "Registration form", + "providerId": "form-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-user-creation", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-password-action", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 50, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-recaptcha-action", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 60, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-terms-and-conditions", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 70, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "c1719d88-96c6-4c92-a51d-2de9cca6e911", + "alias": "reset credentials", + "description": "Reset credentials for a user if they forgot their password or something", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "reset-credentials-choose-user", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-credential-email", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 40, + "autheticatorFlow": true, + "flowAlias": "Reset - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "555ace85-f6a9-4bc0-ad4a-0a1137cbcb4e", + "alias": "saml ecp", + "description": "SAML ECP Profile Authentication Flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + } + ], + "authenticatorConfig": [ + { + "id": "f3aa7d48-1964-409a-b2a4-5711777f8a0b", + "alias": "create unique user config", + "config": { + "require.password.update.after.registration": "false" + } + }, + { + "id": "b6048c4f-1bab-428d-a135-e27a1ec1d8b6", + "alias": "review profile config", + "config": { + "update.profile.on.first.login": "missing" + } + } + ], + "requiredActions": [ + { + "alias": "CONFIGURE_TOTP", + "name": "Configure OTP", + "providerId": "CONFIGURE_TOTP", + "enabled": true, + "defaultAction": false, + "priority": 10, + "config": {} + }, + { + "alias": "TERMS_AND_CONDITIONS", + "name": "Terms and Conditions", + "providerId": "TERMS_AND_CONDITIONS", + "enabled": false, + "defaultAction": false, + "priority": 20, + "config": {} + }, + { + "alias": "UPDATE_PASSWORD", + "name": "Update Password", + "providerId": "UPDATE_PASSWORD", + "enabled": true, + "defaultAction": false, + "priority": 30, + "config": {} + }, + { + "alias": "UPDATE_PROFILE", + "name": "Update Profile", + "providerId": "UPDATE_PROFILE", + "enabled": true, + "defaultAction": false, + "priority": 40, + "config": {} + }, + { + "alias": "VERIFY_EMAIL", + "name": "Verify Email", + "providerId": "VERIFY_EMAIL", + "enabled": true, + "defaultAction": false, + "priority": 50, + "config": {} + }, + { + "alias": "delete_account", + "name": "Delete Account", + "providerId": "delete_account", + "enabled": false, + "defaultAction": false, + "priority": 60, + "config": {} + }, + { + "alias": "webauthn-register", + "name": "Webauthn Register", + "providerId": "webauthn-register", + "enabled": true, + "defaultAction": false, + "priority": 70, + "config": {} + }, + { + "alias": "webauthn-register-passwordless", + "name": "Webauthn Register Passwordless", + "providerId": "webauthn-register-passwordless", + "enabled": true, + "defaultAction": false, + "priority": 80, + "config": {} + }, + { + "alias": "VERIFY_PROFILE", + "name": "Verify Profile", + "providerId": "VERIFY_PROFILE", + "enabled": true, + "defaultAction": false, + "priority": 90, + "config": {} + }, + { + "alias": "delete_credential", + "name": "Delete Credential", + "providerId": "delete_credential", + "enabled": true, + "defaultAction": false, + "priority": 100, + "config": {} + }, + { + "alias": "update_user_locale", + "name": "Update User Locale", + "providerId": "update_user_locale", + "enabled": true, + "defaultAction": false, + "priority": 1000, + "config": {} + } + ], + "browserFlow": "browser", + "registrationFlow": "registration", + "directGrantFlow": "direct grant", + "resetCredentialsFlow": "reset credentials", + "clientAuthenticationFlow": "clients", + "dockerAuthenticationFlow": "docker auth", + "firstBrokerLoginFlow": "first broker login", + "attributes": { + "cibaBackchannelTokenDeliveryMode": "poll", + "cibaExpiresIn": "120", + "cibaAuthRequestedUserHint": "login_hint", + "oauth2DeviceCodeLifespan": "600", + "oauth2DevicePollingInterval": "5", + "parRequestUriLifespan": "60", + "cibaInterval": "5", + "realmReusableOtpCode": "false" + }, + "keycloakVersion": "26.2.3", + "userManagedAccessAllowed": false, + "organizationsEnabled": false, + "verifiableCredentialsEnabled": false, + "adminPermissionsEnabled": false, + "clientProfiles": { + "profiles": [] + }, + "clientPolicies": { + "policies": [] + } +} \ No newline at end of file diff --git a/.ci/auth/keycloak/1-client-template.json b/.ci/auth/keycloak/1-client-template.json new file mode 100644 index 0000000..bd6f8fb --- /dev/null +++ b/.ci/auth/keycloak/1-client-template.json @@ -0,0 +1,73 @@ +{ + "clientId": $ARGS.named.CLIENT_ID, + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": $ARGS.named.CLIENT_SECRET, + "standardFlowEnabled" : false, + "implicitFlowEnabled" : false, + "serviceAccountsEnabled": true, + "protocol": "openid-connect", + "attributes": { + "realm_client": "false", + "oidc.ciba.grant.enabled": "false", + "client.secret.creation.time": "1735689600", + "backchannel.logout.session.required": "true", + "standard.token.exchange.enabled": "false", + "frontchannel.logout.session.required": "true", + "oauth2.device.authorization.grant.enabled": "false", + "display.on.consent.screen": "false", + "backchannel.logout.revoke.offline.tokens": "false" + }, + "protocolMappers": [ + { + "name": "sub", + "protocol": "openid-connect", + "protocolMapper": "oidc-hardcoded-claim-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "claim.value": $ARGS.named.SUB_CLAIM_VALUE, + "userinfo.token.claim": "true", + "id.token.claim": "true", + "lightweight.claim": "false", + "access.token.claim": "true", + "claim.name": "sub", + "jsonType.label": "String", + "access.tokenResponse.claim": "false" + } + }, + { + "name": "nbf", + "protocol": "openid-connect", + "protocolMapper": "oidc-hardcoded-claim-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "claim.value": "1735689600", + "userinfo.token.claim": "true", + "id.token.claim": "true", + "lightweight.claim": "false", + "access.token.claim": "true", + "claim.name": "nbf", + "jsonType.label": "long", + "access.tokenResponse.claim": "false" + } + } + ], + "defaultClientScopes": [ + "web-origins", + "service_account", + "acr", + "profile", + "roles", + "basic", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "organization", + "offline_access", + "microprofile-jwt" + ] +} \ No newline at end of file diff --git a/.ci/auth/keycloak/README.md b/.ci/auth/keycloak/README.md new file mode 100644 index 0000000..93638b5 --- /dev/null +++ b/.ci/auth/keycloak/README.md @@ -0,0 +1,26 @@ +# Keycloak + +Keycloak is used to validate OIDC configuration. + +To create the pulsar realm configuration, we use : + +* `0-realm-pulsar-partial-export.json` : after creating pulsar realm in Keycloack UI, this file is the result of the partial export in Keycloak UI without options. +* `1-client-template.json` : this is the template to create pulsar clients. + +To create the final `realm-pulsar.json`, merge files with `jq` command : + +* create a client with `CLIENT_ID`, `CLIENT_SECRET` and `SUB_CLAIM_VALUE` : + +``` +CLIENT_ID=xx +CLIENT_SECRET=yy +SUB_CLAIM_VALUE=zz + +jq -n --arg CLIENT_ID "$CLIENT_ID" --arg CLIENT_SECRET "$CLIENT_SECRET" --arg SUB_CLAIM_VALUE "$SUB_CLAIM_VALUE" 1-client-template.json > client.json +``` + +* then merge the realm and the client : + +``` +jq '.clients += [input]' 0-realm-pulsar-partial-export.json client.json > realm-pulsar.json +``` diff --git a/.ci/auth/keycloak/values.yaml b/.ci/auth/keycloak/values.yaml new file mode 100644 index 0000000..8334008 --- /dev/null +++ b/.ci/auth/keycloak/values.yaml @@ -0,0 +1,34 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +tls: + enabled: false +# This block sets up an example Pulsar Realm +# https://www.keycloak.org/server/importExport#_importing_a_realm_from_a_directory +extraEnvVars: + - name: KEYCLOAK_EXTRA_ARGS + value: "--import-realm" +extraVolumes: + - name: realm-config + secret: + secretName: keycloak-ci-realm-config +extraVolumeMounts: + - name: realm-config + mountPath: "/opt/bitnami/keycloak/data/import" + readOnly: true diff --git a/.ci/auth/oauth2/credentials_file.json b/.ci/auth/oauth2/credentials_file.json new file mode 100644 index 0000000..0773619 --- /dev/null +++ b/.ci/auth/oauth2/credentials_file.json @@ -0,0 +1,5 @@ +{ + "type": "client_credentials", + "client_id": $ARGS.named.CLIENT_ID, + "client_secret": $ARGS.named.CLIENT_SECRET +} \ No newline at end of file diff --git a/.ci/clusters/values-jwt-asymmetric.yaml b/.ci/clusters/values-jwt-asymmetric.yaml index d2f37f7..7ebe4d1 100644 --- a/.ci/clusters/values-jwt-asymmetric.yaml +++ b/.ci/clusters/values-jwt-asymmetric.yaml @@ -21,9 +21,9 @@ auth: authentication: enabled: true - provider: "jwt" jwt: # Enable JWT authentication + enabled: true # If the token is generated by a secret key, set the usingSecretKey as true. # If the token is generated by a private key, set the usingSecretKey as false. usingSecretKey: false diff --git a/.ci/clusters/values-jwt-symmetric.yaml b/.ci/clusters/values-jwt-symmetric.yaml index d9fb9f8..014268a 100644 --- a/.ci/clusters/values-jwt-symmetric.yaml +++ b/.ci/clusters/values-jwt-symmetric.yaml @@ -21,9 +21,9 @@ auth: authentication: enabled: true - provider: "jwt" jwt: # Enable JWT authentication + enabled: true # If the token is generated by a secret key, set the usingSecretKey as true. # If the token is generated by a private key, set the usingSecretKey as false. usingSecretKey: true diff --git a/.ci/clusters/values-openid.yaml b/.ci/clusters/values-openid.yaml new file mode 100644 index 0000000..8305f89 --- /dev/null +++ b/.ci/clusters/values-openid.yaml @@ -0,0 +1,94 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# Mount crendentials to each component +proxy: + configData: + # Authentication settings of the broker itself. Used when the broker connects to other brokers, or when the proxy connects to brokers, either in same or other clusters + brokerClientAuthenticationPlugin: "org.apache.pulsar.client.impl.auth.oauth2.AuthenticationOAuth2" + brokerClientAuthenticationParameters: '{"privateKey":"file:///pulsar/auth/proxy/credentials_file.json","audience":"account","issuerUrl":"http://keycloak-ci-headless:8080/realms/pulsar"}' + extraVolumes: + - name: pulsar-proxy-credentials + secret: + secretName: pulsar-proxy-credentials + extraVolumeMounts: + - name: pulsar-proxy-credentials + mountPath: "/pulsar/auth/proxy" + readOnly: true + +broker: + configData: + # Authentication settings of the broker itself. Used when the broker connects to other brokers, or when the proxy connects to brokers, either in same or other clusters + brokerClientAuthenticationPlugin: "org.apache.pulsar.client.impl.auth.oauth2.AuthenticationOAuth2" + brokerClientAuthenticationParameters: '{"privateKey":"file:///pulsar/auth/broker/credentials_file.json","audience":"account","issuerUrl":"http://keycloak-ci-headless:8080/realms/pulsar"}' + extraVolumes: + - name: pulsar-broker-credentials + secret: + secretName: pulsar-broker-credentials + extraVolumeMounts: + - name: pulsar-broker-credentials + mountPath: "/pulsar/auth/broker" + readOnly: true + +toolset: + configData: + authPlugin: "org.apache.pulsar.client.impl.auth.oauth2.AuthenticationOAuth2" + authParams: '{"privateKey":"file:///pulsar/auth/admin/credentials_file.json","audience":"account","issuerUrl":"http://keycloak-ci-headless:8080/realms/pulsar"}' + extraVolumes: + - name: pulsar-admin-credentials + secret: + secretName: pulsar-admin-credentials + extraVolumeMounts: + - name: pulsar-admin-credentials + mountPath: "/pulsar/auth/admin" + readOnly: true + +auth: + authentication: + enabled: true + openid: + # Enable openid authentication + enabled: true + # https://pulsar.apache.org/docs/next/security-openid-connect/#enable-openid-connect-authentication-in-the-broker-and-proxy + openIDAllowedTokenIssuers: + - http://keycloak-ci-headless:8080/realms/pulsar + openIDAllowedAudiences: + - account + #openIDTokenIssuerTrustCertsFilePath: + openIDRoleClaim: "sub" + openIDAcceptedTimeLeewaySeconds: "0" + openIDCacheSize: "5" + openIDCacheRefreshAfterWriteSeconds: "64800" + openIDCacheExpirationSeconds: "86400" + openIDHttpConnectionTimeoutMillis: "10000" + openIDHttpReadTimeoutMillis: "10000" + openIDKeyIdCacheMissRefreshSeconds: "300" + openIDRequireIssuersUseHttps: "false" + openIDFallbackDiscoveryMode: "DISABLED" + authorization: + enabled: true + superUsers: + # broker to broker communication + broker: "broker-admin" + # proxy to broker communication + proxy: "proxy-admin" + # pulsar-admin client to broker/proxy communication + client: "admin" + # pulsar manager to broker + manager: "manager-admin" diff --git a/.ci/helm.sh b/.ci/helm.sh index 481b5c3..7d5bc0b 100755 --- a/.ci/helm.sh +++ b/.ci/helm.sh @@ -90,8 +90,8 @@ function ci::helm_repo_add() { } function ci::print_pod_logs() { - echo "Logs for all pulsar containers:" - for k8sobject in $(${KUBECTL} get pods,jobs -n ${NAMESPACE} -l app=pulsar -o=name); do + echo "Logs for all containers:" + for k8sobject in $(${KUBECTL} get pods,jobs -n ${NAMESPACE} -o=name); do ${KUBECTL} logs -n ${NAMESPACE} "$k8sobject" --all-containers=true --ignore-errors=true --prefix=true --tail=100 || true done; } @@ -99,7 +99,7 @@ function ci::print_pod_logs() { function ci::collect_k8s_logs() { mkdir -p "${K8S_LOGS_DIR}" && cd "${K8S_LOGS_DIR}" echo "Collecting k8s logs to ${K8S_LOGS_DIR}" - for k8sobject in $(${KUBECTL} get pods,jobs -n ${NAMESPACE} -l app=pulsar -o=name); do + for k8sobject in $(${KUBECTL} get pods,jobs -n ${NAMESPACE} -o=name); do filebase="${k8sobject//\//_}" ${KUBECTL} logs -n ${NAMESPACE} "$k8sobject" --all-containers=true --ignore-errors=true --prefix=true > "${filebase}.$$.log.txt" || true ${KUBECTL} logs -n ${NAMESPACE} "$k8sobject" --all-containers=true --ignore-errors=true --prefix=true --previous=true > "${filebase}.previous.$$.log.txt" || true @@ -149,6 +149,11 @@ function ci::install_pulsar_chart() { # configure metallb ${KUBECTL} apply -f ${BINDIR}/metallb/metallb-config.yaml install_args="" + + # create auth resources + if [[ "x${AUTHENTICATION_PROVIDER}" == "xopenid" ]]; then + ci::create_openid_resources + fi else install_args="--wait --wait-for-jobs --timeout 360s --debug" fi @@ -272,6 +277,7 @@ function ci::retry() { } function ci::test_pulsar_admin_api_access() { + echo "Test pulsar admin api access" ci::retry ${KUBECTL} exec -n ${NAMESPACE} ${CLUSTER}-toolset-0 -- bin/pulsar-admin tenants list } @@ -483,6 +489,77 @@ function _ci::validate_kustomize_yaml() { }' } +# Create all resources needed for openid authentication +function ci::create_openid_resources() { + + echo "Creating openid resources" + + cp ${PULSAR_HOME}/.ci/auth/keycloak/0-realm-pulsar-partial-export.json /tmp/realm-pulsar.json + + for component in broker proxy admin manager; do + + echo "Creating openid resources for ${component}" + + local client_id=pulsar-${component} + + # Github action hang up when read string from /dev/urandom, so use python to generate a random string + local client_secret=$(python -c "import secrets; import string; length = 32; random_string = ''.join(secrets.choice(string.ascii_letters + string.digits) for _ in range(length)); print(random_string);") + + if [[ "${component}" == "admin" ]]; then + local sub_claim_value="admin" + else + local sub_claim_value="${component}-admin" + fi + + # Create the client credentials file + jq -n --arg CLIENT_ID $client_id --arg CLIENT_SECRET "$client_secret" -f ${PULSAR_HOME}/.ci/auth/oauth2/credentials_file.json > /tmp/${component}-credentials_file.json + + # Create the secret for the client credentials + local secret_name="pulsar-${component}-credentials" + ${KUBECTL} create secret generic ${secret_name} --from-file=credentials_file.json=/tmp/${component}-credentials_file.json -n ${NAMESPACE} + + # Create the keycloak client file + jq -n --arg CLIENT_ID $client_id --arg CLIENT_SECRET "$client_secret" --arg SUB_CLAIM_VALUE "$sub_claim_value" -f ${PULSAR_HOME}/.ci/auth/keycloak/1-client-template.json > /tmp/${component}-keycloak-client.json + + # Merge the keycloak client file with the realm + jq '.clients += [input]' /tmp/realm-pulsar.json /tmp/${component}-keycloak-client.json > /tmp/realm-pulsar.json.tmp + mv /tmp/realm-pulsar.json.tmp /tmp/realm-pulsar.json + + done + + echo "Create keycloak realm configuration" + ${KUBECTL} create secret generic keycloak-ci-realm-config --from-file=realm-pulsar.json=/tmp/realm-pulsar.json -n ${NAMESPACE} + + echo "Installing keycloak helm chart" + ${HELM} install keycloak-ci oci://registry-1.docker.io/bitnamicharts/keycloak --version 24.6.4 --values ${PULSAR_HOME}/.ci/auth/keycloak/values.yaml -n ${NAMESPACE} + + echo "Wait until keycloak is running" + WC=$(${KUBECTL} get pods -n ${NAMESPACE} --field-selector=status.phase=Running | grep keycloak-ci-0 | wc -l) + counter=1 + while [[ ${WC} -lt 1 ]]; do + ((counter++)) + echo ${WC}; + sleep 15 + ${KUBECTL} get pods,jobs -n ${NAMESPACE} + ${KUBECTL} get events --sort-by=.lastTimestamp -A | tail -n 30 || true + if [[ $((counter % 20)) -eq 0 ]]; then + ci::print_pod_logs + if [[ $counter -gt 100 ]]; then + echo >&2 "Timeout waiting..." + exit 1 + fi + fi + WC=$(${KUBECTL} get pods -n ${NAMESPACE} --field-selector=status.phase=Running | grep keycloak-ci-0 | wc -l) + done + + echo "Wait until keycloak is ready" + ${KUBECTL} wait --for=condition=Ready pod/keycloak-ci-0 -n ${NAMESPACE} --timeout 180s + + echo "Check keycloack realm pulsar issuer url" + ${KUBECTL} exec -n ${NAMESPACE} keycloak-ci-0 -c keycloak -- bash -c 'curl -sSL http://keycloak-ci-headless:8080/realms/pulsar' + +} + # lists all available functions in this tool function ci::list_functions() { declare -F | awk '{print $NF}' | sort | grep -E '^ci::' | sed 's/^ci:://' diff --git a/.github/workflows/pulsar-helm-chart-ci.yaml b/.github/workflows/pulsar-helm-chart-ci.yaml index b0f6584..1244020 100644 --- a/.github/workflows/pulsar-helm-chart-ci.yaml +++ b/.github/workflows/pulsar-helm-chart-ci.yaml @@ -32,6 +32,7 @@ concurrency: cancel-in-progress: true jobs: + preconditions: name: Preconditions runs-on: ubuntu-24.04 @@ -229,6 +230,9 @@ jobs: - name: Oxia values_file: .ci/clusters/values-oxia.yaml shortname: oxia + - name: OpenID + values_file: .ci/clusters/values-openid.yaml + shortname: openid include: - k8sVersion: version: "1.25.16" @@ -289,6 +293,9 @@ jobs: "jwt-asymmetric") export EXTRA_SUPERUSERS=manager-admin ;; + "openid") + export AUTHENTICATION_PROVIDER=openid + ;; esac if [[ "${{ matrix.testScenario.type || 'install' }}" == "upgrade" ]]; then export UPGRADE_FROM_VERSION="${{ matrix.testScenario.upgradeFromVersion || 'latest' }}" diff --git a/README.md b/README.md index b150764..8303964 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,13 @@ existing security implementations. As per the [Pulsar Proxy documentation](https://pulsar.apache.org/docs/3.1.x/administration-proxy/), it is explicitly stated that the Pulsar proxy is not designed for exposure to the public internet. The design assumes that deployments will be protected by network perimeter security measures. It is crucial to understand that relying solely on the default configuration can expose your deployment to significant security vulnerabilities. -### Important Change in 4.0.0 version of the Apache Pulsar Helm chart +### Upgrading + +#### To 4.1.0 + +This version introduces `OpenID` authentication. Setting `auth.authentication.provider` is no longer supported, you need to enable the provider with `auth.authentication..enabled`. + +#### To 4.0.0 The default service type for the Pulsar proxy has changed from `LoadBalancer` to `ClusterIP` for security reasons. This limits access to within the Kubernetes environment by default. @@ -157,6 +163,7 @@ It includes support for: - [x] ZooKeeper - [x] Authentication - [x] JWT + - [x] OpenID - [ ] Mutal TLS - [ ] Kerberos - [x] Authorization diff --git a/charts/pulsar/templates/_values_validation.tpl b/charts/pulsar/templates/_values_validation.tpl new file mode 100644 index 0000000..fface25 --- /dev/null +++ b/charts/pulsar/templates/_values_validation.tpl @@ -0,0 +1,25 @@ +{{/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/}} + +{{/* +Check deprecated setting auth.authentication.provider since 4.1.0 +*/}} +{{- if (and .Values.auth.authentication.enabled (not (empty .Values.auth.authentication.provider))) }} + {{- fail "ERROR: Setting auth.authentication.provider is no longer supported. For details, see the migration guide in README.md." }} +{{- end }} diff --git a/charts/pulsar/templates/broker-configmap.yaml b/charts/pulsar/templates/broker-configmap.yaml index ca64bc2..59e7ac4 100644 --- a/charts/pulsar/templates/broker-configmap.yaml +++ b/charts/pulsar/templates/broker-configmap.yaml @@ -217,9 +217,14 @@ data: proxyRoles: {{ .Values.auth.superUsers.proxy }} {{- end }} {{- end }} - {{- if eq .Values.auth.authentication.provider "jwt" }} + {{- if and .Values.auth.authentication.enabled .Values.auth.authentication.jwt.enabled }} # token authentication configuration + {{- if and .Values.auth.authentication.enabled .Values.auth.authentication.jwt.enabled .Values.auth.authentication.openid.enabled }} + authenticationProviders: "org.apache.pulsar.broker.authentication.AuthenticationProviderToken,org.apache.pulsar.broker.authentication.oidc.AuthenticationProviderOpenID" + {{- end }} + {{- if and .Values.auth.authentication.enabled .Values.auth.authentication.jwt.enabled ( not .Values.auth.authentication.openid.enabled ) }} authenticationProviders: "org.apache.pulsar.broker.authentication.AuthenticationProviderToken" + {{- end }} brokerClientAuthenticationParameters: "file:///pulsar/tokens/broker/token" brokerClientAuthenticationPlugin: "org.apache.pulsar.client.impl.auth.AuthenticationToken" {{- if .Values.auth.authentication.jwt.usingSecretKey }} @@ -228,6 +233,25 @@ data: tokenPublicKey: "file:///pulsar/keys/token/public.key" {{- end }} {{- end }} + {{- if and .Values.auth.authentication.enabled .Values.auth.authentication.openid.enabled }} + # openid authentication configuration + {{- if and .Values.auth.authentication.enabled .Values.auth.authentication.openid.enabled ( not .Values.auth.authentication.jwt.enabled ) }} + authenticationProviders: "org.apache.pulsar.broker.authentication.oidc.AuthenticationProviderOpenID" + {{- end }} + PULSAR_PREFIX_openIDAllowedTokenIssuers: {{ .Values.auth.authentication.openid.openIDAllowedTokenIssuers | uniq | compact | sortAlpha | join "," | quote }} + PULSAR_PREFIX_openIDAllowedAudiences: {{ .Values.auth.authentication.openid.openIDAllowedAudiences | uniq | compact | sortAlpha | join "," | quote }} + PULSAR_PREFIX_openIDTokenIssuerTrustCertsFilePath: {{ .Values.auth.authentication.openid.openIDTokenIssuerTrustCertsFilePath | quote }} + PULSAR_PREFIX_openIDRoleClaim: {{ .Values.auth.authentication.openid.openIDRoleClaim | quote }} + PULSAR_PREFIX_openIDAcceptedTimeLeewaySeconds: {{ .Values.auth.authentication.openid.openIDAcceptedTimeLeewaySeconds | quote }} + PULSAR_PREFIX_openIDCacheSize: {{ .Values.auth.authentication.openid.openIDCacheSize | quote }} + PULSAR_PREFIX_openIDCacheRefreshAfterWriteSeconds: {{ .Values.auth.authentication.openid.openIDCacheRefreshAfterWriteSeconds | quote }} + PULSAR_PREFIX_openIDCacheExpirationSeconds: {{ .Values.auth.authentication.openid.openIDCacheExpirationSeconds | quote }} + PULSAR_PREFIX_openIDHttpConnectionTimeoutMillis: {{ .Values.auth.authentication.openid.openIDHttpConnectionTimeoutMillis | quote }} + PULSAR_PREFIX_openIDHttpReadTimeoutMillis: {{ .Values.auth.authentication.openid.openIDHttpReadTimeoutMillis | quote }} + PULSAR_PREFIX_openIDKeyIdCacheMissRefreshSeconds: {{ .Values.auth.authentication.openid.openIDKeyIdCacheMissRefreshSeconds | quote }} + PULSAR_PREFIX_openIDRequireIssuersUseHttps: {{ .Values.auth.authentication.openid.openIDRequireIssuersUseHttps | quote }} + PULSAR_PREFIX_openIDFallbackDiscoveryMode: {{ .Values.auth.authentication.openid.openIDFallbackDiscoveryMode | quote }} + {{- end }} {{- end }} {{- if and .Values.tls.enabled .Values.tls.bookie.enabled }} diff --git a/charts/pulsar/templates/broker-statefulset.yaml b/charts/pulsar/templates/broker-statefulset.yaml index 26034f2..80b002b 100644 --- a/charts/pulsar/templates/broker-statefulset.yaml +++ b/charts/pulsar/templates/broker-statefulset.yaml @@ -276,7 +276,7 @@ spec: name: "{{ template "pulsar.fullname" . }}-{{ .Values.broker.component }}" volumeMounts: {{- if .Values.auth.authentication.enabled }} - {{- if eq .Values.auth.authentication.provider "jwt" }} + {{- if .Values.auth.authentication.jwt.enabled }} - mountPath: "/pulsar/keys" name: token-keys readOnly: true @@ -329,7 +329,7 @@ spec: {{ toYaml .Values.broker.extraVolumes | indent 6 }} {{- end }} {{- if .Values.auth.authentication.enabled }} - {{- if eq .Values.auth.authentication.provider "jwt" }} + {{- if .Values.auth.authentication.jwt.enabled }} - name: token-keys secret: {{- if not .Values.auth.authentication.jwt.usingSecretKey }} diff --git a/charts/pulsar/templates/proxy-configmap.yaml b/charts/pulsar/templates/proxy-configmap.yaml index 959c23d..01105fe 100644 --- a/charts/pulsar/templates/proxy-configmap.yaml +++ b/charts/pulsar/templates/proxy-configmap.yaml @@ -70,9 +70,14 @@ data: superUserRoles: {{ .Values.auth.superUsers | values | compact | sortAlpha | join "," }} {{- end }} {{- end }} - {{- if eq .Values.auth.authentication.provider "jwt" }} + {{- if and .Values.auth.authentication.enabled .Values.auth.authentication.jwt.enabled }} # token authentication configuration + {{- if and .Values.auth.authentication.enabled .Values.auth.authentication.jwt.enabled .Values.auth.authentication.openid.enabled }} + authenticationProviders: "org.apache.pulsar.broker.authentication.AuthenticationProviderToken,org.apache.pulsar.broker.authentication.oidc.AuthenticationProviderOpenID" + {{- end }} + {{- if and .Values.auth.authentication.enabled .Values.auth.authentication.jwt.enabled ( not .Values.auth.authentication.openid.enabled ) }} authenticationProviders: "org.apache.pulsar.broker.authentication.AuthenticationProviderToken" + {{- end }} brokerClientAuthenticationParameters: "file:///pulsar/tokens/proxy/token" brokerClientAuthenticationPlugin: "org.apache.pulsar.client.impl.auth.AuthenticationToken" {{- if .Values.auth.authentication.jwt.usingSecretKey }} @@ -81,6 +86,25 @@ data: tokenPublicKey: "file:///pulsar/keys/token/public.key" {{- end }} {{- end }} + {{- if and .Values.auth.authentication.enabled .Values.auth.authentication.openid.enabled }} + # openid authentication configuration + {{- if and .Values.auth.authentication.enabled .Values.auth.authentication.openid.enabled ( not .Values.auth.authentication.jwt.enabled ) }} + authenticationProviders: "org.apache.pulsar.broker.authentication.oidc.AuthenticationProviderOpenID" + {{- end }} + PULSAR_PREFIX_openIDAllowedTokenIssuers: {{ .Values.auth.authentication.openid.openIDAllowedTokenIssuers | uniq | compact | sortAlpha | join "," | quote }} + PULSAR_PREFIX_openIDAllowedAudiences: {{ .Values.auth.authentication.openid.openIDAllowedAudiences | uniq | compact | sortAlpha | join "," | quote }} + PULSAR_PREFIX_openIDTokenIssuerTrustCertsFilePath: {{ .Values.auth.authentication.openid.openIDTokenIssuerTrustCertsFilePath | quote }} + PULSAR_PREFIX_openIDRoleClaim: {{ .Values.auth.authentication.openid.openIDRoleClaim | quote }} + PULSAR_PREFIX_openIDAcceptedTimeLeewaySeconds: {{ .Values.auth.authentication.openid.openIDAcceptedTimeLeewaySeconds | quote }} + PULSAR_PREFIX_openIDCacheSize: {{ .Values.auth.authentication.openid.openIDCacheSize | quote }} + PULSAR_PREFIX_openIDCacheRefreshAfterWriteSeconds: {{ .Values.auth.authentication.openid.openIDCacheRefreshAfterWriteSeconds | quote }} + PULSAR_PREFIX_openIDCacheExpirationSeconds: {{ .Values.auth.authentication.openid.openIDCacheExpirationSeconds | quote }} + PULSAR_PREFIX_openIDHttpConnectionTimeoutMillis: {{ .Values.auth.authentication.openid.openIDHttpConnectionTimeoutMillis | quote }} + PULSAR_PREFIX_openIDHttpReadTimeoutMillis: {{ .Values.auth.authentication.openid.openIDHttpReadTimeoutMillis | quote }} + PULSAR_PREFIX_openIDKeyIdCacheMissRefreshSeconds: {{ .Values.auth.authentication.openid.openIDKeyIdCacheMissRefreshSeconds | quote }} + PULSAR_PREFIX_openIDRequireIssuersUseHttps: {{ .Values.auth.authentication.openid.openIDRequireIssuersUseHttps | quote }} + PULSAR_PREFIX_openIDFallbackDiscoveryMode: {{ .Values.auth.authentication.openid.openIDFallbackDiscoveryMode | quote }} + {{- end }} {{- end }} {{ toYaml .Values.proxy.configData | indent 2 }} {{- end }} diff --git a/charts/pulsar/templates/proxy-statefulset.yaml b/charts/pulsar/templates/proxy-statefulset.yaml index 8c1adc6..3ea2475 100644 --- a/charts/pulsar/templates/proxy-statefulset.yaml +++ b/charts/pulsar/templates/proxy-statefulset.yaml @@ -237,7 +237,7 @@ spec: {{- if or .Values.proxy.extraVolumeMounts .Values.auth.authentication.enabled (and .Values.tls.enabled (or .Values.tls.proxy.enabled .Values.tls.broker.enabled)) }} volumeMounts: {{- if .Values.auth.authentication.enabled }} - {{- if eq .Values.auth.authentication.provider "jwt" }} + {{- if .Values.auth.authentication.jwt.enabled }} - mountPath: "/pulsar/keys" name: token-keys readOnly: true @@ -267,7 +267,7 @@ spec: {{ toYaml .Values.proxy.extraVolumes | indent 8 }} {{- end }} {{- if .Values.auth.authentication.enabled }} - {{- if eq .Values.auth.authentication.provider "jwt" }} + {{- if .Values.auth.authentication.jwt.enabled }} - name: token-keys secret: {{- if not .Values.auth.authentication.jwt.usingSecretKey }} diff --git a/charts/pulsar/templates/pulsar-manager-configmap.yaml b/charts/pulsar/templates/pulsar-manager-configmap.yaml index df70ecd..e5ebef9 100644 --- a/charts/pulsar/templates/pulsar-manager-configmap.yaml +++ b/charts/pulsar/templates/pulsar-manager-configmap.yaml @@ -31,7 +31,7 @@ data: PULSAR_MANAGER_OPTS: "-Dlog4j2.formatMsgNoLookups=true" {{- if .Values.auth.authentication.enabled }} # auth - {{- if eq .Values.auth.authentication.provider "jwt" }} + {{- if .Values.auth.authentication.jwt.enabled }} {{- if .Values.auth.authentication.jwt.usingSecretKey }} SECRET_KEY: "file:///pulsar-manager/keys/token/secret.key" {{- else }} diff --git a/charts/pulsar/templates/pulsar-manager-statefulset.yaml b/charts/pulsar/templates/pulsar-manager-statefulset.yaml index 770f36a..945130f 100755 --- a/charts/pulsar/templates/pulsar-manager-statefulset.yaml +++ b/charts/pulsar/templates/pulsar-manager-statefulset.yaml @@ -82,7 +82,7 @@ spec: {{ toYaml .Values.pulsar_manager.extraVolumeMounts | indent 10 }} {{- end }} {{- if .Values.auth.authentication.enabled }} - {{- if eq .Values.auth.authentication.provider "jwt" }} + {{- if .Values.auth.authentication.jwt.enabled }} - name: pulsar-manager-keys mountPath: /pulsar-manager/keys {{- end }} @@ -110,7 +110,7 @@ spec: {{- end }} key: DB_PASSWORD {{- if .Values.auth.authentication.enabled }} - {{- if eq .Values.auth.authentication.provider "jwt" }} + {{- if .Values.auth.authentication.jwt.enabled }} {{- if .Values.auth.superUsers.manager }} - name: JWT_TOKEN valueFrom: @@ -126,7 +126,7 @@ spec: {{ toYaml .Values.pulsar_manager.extraVolumes | indent 8 }} {{- end }} {{- if .Values.auth.authentication.enabled }} - {{- if eq .Values.auth.authentication.provider "jwt" }} + {{- if .Values.auth.authentication.jwt.enabled }} - name: pulsar-manager-keys secret: defaultMode: 420 diff --git a/charts/pulsar/templates/toolset-configmap.yaml b/charts/pulsar/templates/toolset-configmap.yaml index 7a1cafe..9ecdec7 100644 --- a/charts/pulsar/templates/toolset-configmap.yaml +++ b/charts/pulsar/templates/toolset-configmap.yaml @@ -61,7 +61,7 @@ data: {{- end }} # Authentication Settings {{- if .Values.auth.authentication.enabled }} - {{- if eq .Values.auth.authentication.provider "jwt" }} + {{- if .Values.auth.authentication.jwt.enabled }} authParams: "file:///pulsar/tokens/client/token" authPlugin: "org.apache.pulsar.client.impl.auth.AuthenticationToken" {{- end }} diff --git a/charts/pulsar/templates/toolset-statefulset.yaml b/charts/pulsar/templates/toolset-statefulset.yaml index 714e991..ac386db 100644 --- a/charts/pulsar/templates/toolset-statefulset.yaml +++ b/charts/pulsar/templates/toolset-statefulset.yaml @@ -96,7 +96,7 @@ spec: name: "{{ template "pulsar.fullname" . }}-{{ .Values.toolset.component }}" volumeMounts: {{- if .Values.auth.authentication.enabled }} - {{- if eq .Values.auth.authentication.provider "jwt" }} + {{- if .Values.auth.authentication.jwt.enabled }} - mountPath: "/pulsar/tokens" name: client-token readOnly: true @@ -113,7 +113,7 @@ spec: {{- include "pulsar.toolset.certs.volumeMounts" . | nindent 8 }} volumes: {{- if .Values.auth.authentication.enabled }} - {{- if eq .Values.auth.authentication.provider "jwt" }} + {{- if .Values.auth.authentication.jwt.enabled }} - name: client-token secret: secretName: "{{ .Release.Name }}-token-{{ .Values.auth.superUsers.client }}" diff --git a/charts/pulsar/values.yaml b/charts/pulsar/values.yaml index b13534c..1e18d96 100755 --- a/charts/pulsar/values.yaml +++ b/charts/pulsar/values.yaml @@ -273,12 +273,28 @@ tls: auth: authentication: enabled: false - provider: "jwt" jwt: + enabled: false # Enable JWT authentication # If the token is generated by a secret key, set the usingSecretKey as true. # If the token is generated by a private key, set the usingSecretKey as false. usingSecretKey: false + openid: + enabled: false +# # https://pulsar.apache.org/docs/next/security-openid-connect/#enable-openid-connect-authentication-in-the-broker-and-proxy + openIDAllowedTokenIssuers: [] + openIDAllowedAudiences: [] + openIDTokenIssuerTrustCertsFilePath: + openIDRoleClaim: + openIDAcceptedTimeLeewaySeconds: "0" + openIDCacheSize: "5" + openIDCacheRefreshAfterWriteSeconds: "64800" + openIDCacheExpirationSeconds: "86400" + openIDHttpConnectionTimeoutMillis: "10000" + openIDHttpReadTimeoutMillis: "10000" + openIDKeyIdCacheMissRefreshSeconds: "300" + openIDRequireIssuersUseHttps: "true" + openIDFallbackDiscoveryMode: "DISABLED" authorization: enabled: false superUsers: