feat(keycloak): add keycloak-focused secure sign-in resolvers#9117
feat(keycloak): add keycloak-focused secure sign-in resolvers#9117JessicaJHee wants to merge 1 commit into
Conversation
Signed-off-by: Jessica He <jhe@redhat.com>
Changed Packages
|
|
@kz-masa I'm proposing to contribute these 2 additional auth providers in Keycloak and thought that it may interest you, please take a look :) |
kz-masa
left a comment
There was a problem hiding this comment.
Hi, @JessicaJHee, thanks for reviewing my previous PR, and thank you for submitting this excellent contribution! Adding secure Keycloak-focused resolvers using OIDC sub claims and LDAP UUIDs is a great enhancement for security.
Overall, the implementation looks solid. I've left a few inline comments and suggestions. Specifically, I found a type mismatch where entityRef is passed in a format that signInWithCatalogUser does not accept, which needs to be fixed. I've also suggested adding a test case for the malformed UUID check to ensure our coverage remains robust.
Could you take a look at the suggested changes? Let me know if you have any questions.
| { | ||
| dangerousEntityRefFallback: | ||
| options?.dangerouslyAllowSignInWithoutUserInCatalog | ||
| ? { entityRef: uuidFromUserinfo.data } |
There was a problem hiding this comment.
The dengerousEntityRefFallback param accepts entityRef as either a full entity ref string (e.g. "user:default/alice") or an object { kind?, namespace?, name }.
The sibling resolvers referredUsernameMatchingUserEntityName and oidcSubClaimMatchingKeycloakUserId handle this correctly with the object form — would be great to stay consistent
| ? { entityRef: uuidFromUserinfo.data } | |
| ? { entityRef: { name: uuidFromUserinfo.data } } |
| expect(ctx.signInWithCatalogUser).toHaveBeenCalledWith( | ||
| { annotations: { 'backstage.io/ldap-uuid': ldapUuid } }, | ||
| { | ||
| dangerousEntityRefFallback: { entityRef: ldapUuid }, |
There was a problem hiding this comment.
Please make sure to update the corresponding test expectation as well.
| dangerousEntityRefFallback: { entityRef: ldapUuid }, | |
| dangerousEntityRefFallback: { entityRef: { name: ldapUuid } }, |
| await expect(resolver(info, ctx)).rejects.toThrow(/ldap_uuid/); | ||
| expect(ctx.signInWithCatalogUser).not.toHaveBeenCalled(); | ||
| }); | ||
|
|
There was a problem hiding this comment.
In resolvers.ts on lines 187-192, there is a check for a malformed UUID (z.string().uuid().safeParse), but it seems untested. Adding this test would be awesome for keeping our coverage robust.
| it('throws when id token claim is not a valid UUID string', async () => { | |
| const ctx = createMockContext(); | |
| const resolver = keycloakSignInResolvers.ldapUuidMatchingAnnotation(); | |
| const validUuid = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'; | |
| const idToken = await signTestIdToken({ | |
| sub: 'user-sub', | |
| ldap_uuid: 'not-a-uuid' | |
| }); | |
| const info = createInfo({ ldap_uuid: validUuid }, {}, idToken); | |
| await expect(resolver(info, ctx)).rejects.toThrow(/valid UUID string/); | |
| expect(ctx.signInWithCatalogUser).not.toHaveBeenCalled(); | |
| }); | |
Hey, I just made a Pull Request!
Added two secure Keycloak-focused sign-in resolvers that resolve users using immutable identifiers (like the OIDC sub claim and LDAP UUID). They provide a more secure way to resolver users compared to matching on email or username which users can change to help reduce risk of impersonation.
oidcSubClaimMatchingKeycloakUserId: Resolves users via thekeycloak.org/idannotation from the Keycloak catalog provider using OIDC sub fromuserinfo, verified to match with the ID token sub claim.ldapUuidMatchingAnnotation: Resolves users viabackstage.io/ldap-uuidusing a configurable claim (defaultldap_uuid), with UUID validation anduserinfo/ID-tokencheck✔️ Checklist
Signed-off-byline in the message. (more info)