ReSSO v0.9.68
RP-Initiated Logout이 RP가 실제로 들고 있는 id_token_hint를 거절하고 있었습니다. hint를 접근용 토큰과 같은 경로(Verify)로 검증해서 만료를 함께 봤는데, 사람이 로그아웃을 누르는 시점에 RP가 저장해둔 ID Token은 보통 이미 만료된 상태입니다 — 기본 Access Token TTL이 5분입니다. 즉 평범한 경우가 거절되고 있었습니다.
수정
- 거절이 거절로 보이지 않았습니다. hint가 통과하지 못하면
client가 nil로 남고, 그러면post_logout_redirect_uri가 말없이 버려집니다. 세션은 끝나고 쿠키도 지워진 채, 브라우저는 RP가 지정한 주소가 아니라 이 서비스의/login?logged_out=1에 남습니다. RP 입장에서는 사람이 그냥 돌아오지 않고, 응답에는 무시된 파라미터의 이름조차 없습니다. - 만료를 보지 않는 이유는 이미 이 저장소에 적혀 있었습니다. 인가 엔드포인트의 같은 파라미터를 읽는
SubjectFromIDTokenHint에 그대로 쓰여 있습니다 — hint는 토큰이 만료됐기 때문에 제시되는 것입니다. RP-Initiated Logout 1.0 §4도 OP에게 같은 것을 요구합니다. 로그아웃만 그것을 따르지 않고 있었습니다. - 새
IDTokenHint로 읽습니다. hint를 믿을 만하게 만드는 검사는 그대로 남습니다 — 우리 서명, 우리 issuer. 빠지는 것은 이 파라미터가 존재하는 이유인 그 경우를 거절하던 검사 하나뿐입니다. - 느슨해지는 것은 없습니다. 리다이렉트 대상은 여전히 Client에 등록된 목록과 대조하므로 open redirect가 되지 않고, 꺼진 Client는 여전히 거절됩니다.
- 같은 함수가 반대쪽은 조입니다. Access Token은 옆에서 함께 발급된 ID Token과 issuer·
azp·sub가 같아서 그대로 hint로 통과하고 있었습니다. ID Token만이 ID Token이므로typ을 확인하고, 이 검사는SubjectFromIDTokenHint를 통해 인가 엔드포인트에도 적용됩니다. - 테스트가 양쪽을 모두 덮고, 아무것도 받지 않는 서비스 위에서는 아무것도 증명하지 않겠다고 거부합니다 — 만료되지 않은 hint가 먼저 받아들여져야 하고, 아니면 그 자리에서 실패합니다. 만료된 hint는 기다리지 않고 Realm의 키로 직접 서명했습니다. Realm의 Access Token TTL 하한이 60초이기 때문입니다.
Upgrade notes
동작이 달라집니다: /realms/{realm}/protocol/openid-connect/logout이 만료된 id_token_hint를 받아들여 post_logout_redirect_uri로 돌려보냅니다(그 주소가 Client에 등록되어 있을 때만입니다). 반대로 Access Token을 id_token_hint로 보내던 곳은 이제 거절되므로, 그렇게 붙여둔 RP가 있다면 ID Token을 보내도록 고치셔야 합니다 — 스펙이 요구하는 값입니다. 저장되는 데이터는 바뀌지 않고 되돌릴 때 이전 이미지도 그대로 동작합니다.
Docker image: resso:v0.9.68
Archive: resso-v0.9.68.tar.gz
SHA-256: c5e92044cc45b21c1141474b921678044d7c6ae2ccb9d070a528ecaaece1f5c2