diff --git a/tdrive/backend/node/src/services/console/clients/remote.ts b/tdrive/backend/node/src/services/console/clients/remote.ts index e6d99578..979c74f7 100644 --- a/tdrive/backend/node/src/services/console/clients/remote.ts +++ b/tdrive/backend/node/src/services/console/clients/remote.ts @@ -281,40 +281,44 @@ export class ConsoleRemoteClient implements ConsoleServiceClient { async backChannelLogout(logoutToken: string): Promise { const payload = await this.verifier.verifyLogoutToken(logoutToken); - if (!payload.iss) { + if (!payload.claims) { + throw new CrudException("Claims are missing in the jwt", 400); + } + + if (!payload.claims.iss) { throw new CrudException("Missing required 'iss' claim", 400); } - if (!payload.aud) { + if (!payload.claims.aud) { throw new CrudException("Missing required 'aud' claim", 400); } - if (!payload.iat) { + if (!payload.claims.iat) { throw new CrudException("Missing required 'iat' claim", 400); } - if (!payload.jti) { + if (!payload.claims.jti) { throw new CrudException("Missing required 'jti' claim", 400); } - if (!payload.events) { + if (!payload.claims.events) { throw new CrudException("Missing required 'events' claim", 400); } - if (payload.nonce) { + if (payload.claims.nonce) { throw new CrudException("Nonce claim is prohibited", 400); } - if (!payload.sub) { + if (!payload.claims.sub) { throw new CrudException("Missing 'sub' claim", 400); } - if (!payload.sid) { + if (!payload.claims.sid) { throw new CrudException("Missing 'sid' claim", 400); } const sessionRepository = gr.services.console.getSessionRepo(); - const session = await sessionRepository.findOne({ sid: payload.sid }); + const session = await sessionRepository.findOne({ sid: payload.claims.sid }); if (session) { await sessionRepository.remove(session); } diff --git a/tdrive/backend/node/test/e2e/common/user-api.ts b/tdrive/backend/node/test/e2e/common/user-api.ts index 24000c1e..07f56dfd 100644 --- a/tdrive/backend/node/test/e2e/common/user-api.ts +++ b/tdrive/backend/node/test/e2e/common/user-api.ts @@ -117,15 +117,17 @@ export default class UserApi { public async logout() { const payload = { - iss: "tdrive_lemonldap", - sub: this.user.id, - sid: this.session, - aud: "your-audience", - iat: Math.floor(Date.now() / 1000), - jti: "jwt-id", - events: { - "http://schemas.openid.net/event/backchannel-logout": {}, - }, + claims: { + iss: "tdrive_lemonldap", + sub: this.user.id, + sid: this.session, + aud: "your-audience", + iat: Math.floor(Date.now() / 1000), + jti: "jwt-id", + events: { + "http://schemas.openid.net/event/backchannel-logout": {}, + }, + } }; const verifierMock = jest.spyOn(OidcJwtVerifier.prototype, "verifyLogoutToken"); verifierMock.mockImplementation(() => { diff --git a/tdrive/backend/node/test/unit/services/console/clients/remote.test.ts b/tdrive/backend/node/test/unit/services/console/clients/remote.test.ts index af2a7cd2..731d6e35 100644 --- a/tdrive/backend/node/test/unit/services/console/clients/remote.test.ts +++ b/tdrive/backend/node/test/unit/services/console/clients/remote.test.ts @@ -20,22 +20,29 @@ describe("Test back-channel logout", () => { const verifyTokenMock = jest.spyOn(OidcJwtVerifier.prototype, "verifyLogoutToken"); const validToken = { - "sid": "Ev81/QODom0HXu9MGjCwnn1tDTpji+j0jopjRAE0ypo", - "aud": [ - "twakedrive" - ], - "sub": "shepilov3@stg.lin-saas.com", - "iat": 1716986356, - "jti": "F9R6DYPE", - "events": { - "http://schemas.openid.net/event/backchannel-logout": {} + "header": { + "typ": "JWT", + "alg": "RS256", + "kid": "UrLwYyzqASOKT5wUedHERA" }, - "iss": "https://sign-up.stg.lin-saas.com/" + "claims": { + "iat": 1716995003, + "sub": "shepilov3@stg.lin-saas.com", + "sid": "WSqrLJG8wNLECdxKIBrR9mdu3PmLFDUd4zHZ+1RLOYI", + "events": { + "http://schemas.openid.net/event/backchannel-logout": {} + }, + "jti": "K9B59EPB", + "aud": [ + "twakedrive" + ], + "iss": "https://sign-up.stg.lin-saas.com/" + } }; - const mockTokenWithoutProperty = (prop: string) => { + const mockTokenWithoutClaim = (claim: string) => { const token = _.cloneDeep(validToken); - token[prop] = null + token.claims[claim] = null verifyTokenMock.mockImplementation(() => { return Promise.resolve(token); // Return the predefined payload }); @@ -43,7 +50,7 @@ describe("Test back-channel logout", () => { it("backChannelLogout should throw error if 'iss' claim is missing", () => { //given - mockTokenWithoutProperty("iss") + mockTokenWithoutClaim("iss") //when let logout = subj.backChannelLogout(''); //then @@ -53,7 +60,7 @@ describe("Test back-channel logout", () => { it("backChannelLogout should throw error if 'aud' claim is missing", () => { //given - mockTokenWithoutProperty("aud") + mockTokenWithoutClaim("aud") //when let logout = subj.backChannelLogout(''); //then @@ -62,7 +69,7 @@ describe("Test back-channel logout", () => { it("backChannelLogout should throw error if 'jti' claim is missing", () => { //given - mockTokenWithoutProperty("jti") + mockTokenWithoutClaim("jti") //when let logout = subj.backChannelLogout(''); //then @@ -71,7 +78,7 @@ describe("Test back-channel logout", () => { it("backChannelLogout should throw error if 'iat' claim is missing", () => { //given - mockTokenWithoutProperty("iat") + mockTokenWithoutClaim("iat") //when let logout = subj.backChannelLogout(''); //then @@ -80,7 +87,7 @@ describe("Test back-channel logout", () => { it("backChannelLogout should throw error if 'events' claim is missing", () => { //given - mockTokenWithoutProperty("events") + mockTokenWithoutClaim("events") //when let logout = subj.backChannelLogout(''); //then @@ -89,7 +96,7 @@ describe("Test back-channel logout", () => { it("backChannelLogout should throw error if 'sub' claim is missing", () => { //given - mockTokenWithoutProperty("sub") + mockTokenWithoutClaim("sub") //when let logout = subj.backChannelLogout(''); //then @@ -98,7 +105,7 @@ describe("Test back-channel logout", () => { it("backChannelLogout should throw error if 'sid' claim is missing", () => { //given - mockTokenWithoutProperty("sid") + mockTokenWithoutClaim("sid") //when let logout = subj.backChannelLogout(''); //then