로그인 플러그인을 통해 JWT의 클레임을 Discourse 사용자에게 매핑하기

IdP에서 가져온 claims를 Discourse 사용자에게 활용할 수 있는 SSO 플러그인을 찾아보고 있습니다.

OIDC 플러그인은 사실상 userinfo 엔드포인트에 종속됩니다. 나쁘지는 않지만, 저는 우리 아이덴티티 스토어의 다른 정보를 사용하려고 했으며 userinfo 결과는 조정할 수 없습니다. OIDC 플러그인이 id_token_info를 사용하여 사용자를 생성하도록 강제해 보았지만 성공하지 못했습니다.

oauth 플러그인으로 돌아왔는데, 표면적으로 보면 특정 엔드포인트의 사용자 정보에 의존한다는 동일한 기본 제한이 있는 것 같습니다. JWT claims의 내용을 반환하는 플러그인을 찾아보고 있지만, 이는 일반적인 사용 사례가 아니므로 큰 기대를 하지 않고 있습니다.

처음에는 oauth basic의 "callback userinfo paths"를 사용하여 claims를 User에 매핑할 수 있을 것 같았지만, 응답에서 항상 null을 반환하고 삽입이 실패했습니다. IdP에서 토큰을 디코딩하면 iss, exp 등과 같은 JSON 루트 레벨의 올바른 claims를 볼 수 있지만, 이를 ActiveRecord 쪽과 연결할 수 없습니다.

jwt를 보고 있지만, claims를 사용자로 매핑하는 기능이 전혀 없는 것 같습니다. 기본적으로 200 응답을 받으면 성공인 구조인데, 이는 제가 찾던 것과도 다릅니다.

또한 omniauth-jwt도 발견했는데, 제 목표에 더 가깝지만 플러그인 형태가 아니며 적극적으로 유지 관리되고 있지 않는 것으로 보입니다. 제가 수정할 수도 있겠지만, 예상보다 훨씬 큰 작업이 될 것 같습니다.

JWT claims를 User로 매핑할 수 있는 현재 유지 관리 중인 플러그인에 대한 방향을 알려주시거나, 기존 플러그인 중 제가 어디에서 잘못 가고 있는지 알려주시면 감사하겠습니다.

정확한 내용은 모르겠지만, 저는 https://github.com/discourse/all-the-plugins를 받아서 OmniAuth로 grep을 해볼 거예요. 그러면 OmniAuth를 사용하는 플러그인 목록이 나올 텐데 그러면 https://github.com/discourse/discourse-jwt가 나오는데, 아마도 당신이 찾고 있는 것이 이것일 겁니다.

네, 그 부분은 이미 확인해 봤습니다.

오늘 제가 유난히 둔한 게 아니라면, 그건 고정된 속성에 대한 인증만 다루고 있는 것 같습니다. 클레임 매핑을 할 수 있는 방법을 찾지 못했습니다. 만약 포크를 해야 한다면, 아마도 거기서 시작할 것 같지만, 제가 뻔한 걸 놓치고 있는 건 아닌지 확인하고 싶었습니다.

이 주제에 우연히 도착한 분들을 위해 조금 더 맥락을 추가하겠습니다.

OAuth basic은 정의된 사용자 데이터 엔드포인트에서 속성을 가져오는 것만 지원하는 것 같으며, JWT 클레임 매핑을 지원하지 않습니다. 따라서 OIDC 플러그인과 유사하지만, discovery doc에서 제공하는 userinfo 위치 대신 임의의 JSON 엔드포인트를 대상으로 지정하고 경로별로 매핑할 수 있습니다. 헤더에 인증 정보를 포함하도록 설정을 추가하면, 우리가 Entra 기반 OAuth에 사용하는 https://graph.microsoft.com/v1.0/me와 같은 위치까지 도달할 수 있습니다.

Entra ID는 핵심 객체에 대한 확장성을提供一些하지만, 선택적 클레임을 추가하는 것만큼 간단하지 않으며, 제 판단으로는 전역적인 변경이 될 것입니다. 따라서 우리에게 실질적인 옵션이 될 수 있을지 모르겠습니다. 한 단계 더 뒤로 물러나서 성숙도 경로를 살펴보면, JWT 플러그인을 사용하는 것이 유일한 경로처럼 보이지만, 클레임 매핑 지원을 추가하려면 일부 PR 작업이 필요합니다. 기본적으로 기존 oauth2-basic이 Discourse 필드를 JSON 속성으로 매핑하는 것을 커스터마이징할 수 있게 허용하는 것과 동일한 방식으로, 필드를 JWT 클레임으로 매핑하는 것을 더 커스터마이징할 수 있도록 허용해야 합니다.

이것은 우리에게 하나의 경로이지만, 모든 것을 막아버린다고 생각하는 다른 문제에 부딪혔습니다.

oauth2-basic을 작동시킨 후 새 사용자를 프롬프트하면, 기존 OIDC 플러그인 사용과 동일한 이메일을 사용하는 기존 사용자를 감지합니다. 동일한 mail 속성을 공유하더라도, 동일한 Discourse 사용자의 경우 프로바이더 간 이동이 불가능하다고 생각합니다. 모든 사용자가 처음부터 시작하는 것은 실질적인 옵션이 아니며, user_associated_accounts 테이블에서 oidc 프로바이더에서 oauth 프로바이더 레코드를 마이그레이션하는 해킹을 할 수는 있겠지만, 이는 문제를 자초하는 것과 같다고 느낍니다. 따라서 JWT에 클레임 매핑 지원이 있더라도, 데이터베이스 조작이나 관련 계정을 변경할 수 있도록 하는 “기존 사용자” 핸들러를 구축하지 않는 한 모든 기존 사용자는 OIDC 프로바이더에 고정되어 있어 막다른 골목에 빠지는 것 같습니다.

그건 좀 이상하네요. 이메일 주소가 일치하면 같은 계정으로 연결되어야 할 것 같습니다. OAuth 로그인도 그렇게 작동하거든요.

Discourse 사용자당(제공자 ID별) user_associated 레코드가 1개 이상 허용되도록 하거나, 하나의 제공자에서 새 제공자로 전환할 수 있도록 하는 “연결” 프롬프트를 제공해 두 가지 방식 중 하나로 연결되기를 희망했습니다. 하지만 테스트 결과, 이메일이 이미 사용 중이라는 메시지만 표시되고 새 사용자를 생성하도록 안내할 뿐이었습니다.

같은 플러그인을 계속 사용하는 경우라면 문제가 없었을 것이라고 생각하지만, 이 경우에는 각 제공자가 고유한 제공자 ID와 자체 메타데이터를 가지고 있습니다.