🐛Fixed format of the logout token

This commit is contained in:
Anton SHEPILOV
2024-05-29 17:19:51 +02:00
committed by Anton Shepilov
parent ff2b3ab7f9
commit c3c039d1f9
3 changed files with 50 additions and 37 deletions
@@ -281,40 +281,44 @@ export class ConsoleRemoteClient implements ConsoleServiceClient {
async backChannelLogout(logoutToken: string): Promise<void> { async backChannelLogout(logoutToken: string): Promise<void> {
const payload = await this.verifier.verifyLogoutToken(logoutToken); 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); throw new CrudException("Missing required 'iss' claim", 400);
} }
if (!payload.aud) { if (!payload.claims.aud) {
throw new CrudException("Missing required 'aud' claim", 400); throw new CrudException("Missing required 'aud' claim", 400);
} }
if (!payload.iat) { if (!payload.claims.iat) {
throw new CrudException("Missing required 'iat' claim", 400); throw new CrudException("Missing required 'iat' claim", 400);
} }
if (!payload.jti) { if (!payload.claims.jti) {
throw new CrudException("Missing required 'jti' claim", 400); throw new CrudException("Missing required 'jti' claim", 400);
} }
if (!payload.events) { if (!payload.claims.events) {
throw new CrudException("Missing required 'events' claim", 400); throw new CrudException("Missing required 'events' claim", 400);
} }
if (payload.nonce) { if (payload.claims.nonce) {
throw new CrudException("Nonce claim is prohibited", 400); throw new CrudException("Nonce claim is prohibited", 400);
} }
if (!payload.sub) { if (!payload.claims.sub) {
throw new CrudException("Missing 'sub' claim", 400); throw new CrudException("Missing 'sub' claim", 400);
} }
if (!payload.sid) { if (!payload.claims.sid) {
throw new CrudException("Missing 'sid' claim", 400); throw new CrudException("Missing 'sid' claim", 400);
} }
const sessionRepository = gr.services.console.getSessionRepo(); 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) { if (session) {
await sessionRepository.remove(session); await sessionRepository.remove(session);
} }
@@ -117,15 +117,17 @@ export default class UserApi {
public async logout() { public async logout() {
const payload = { const payload = {
iss: "tdrive_lemonldap", claims: {
sub: this.user.id, iss: "tdrive_lemonldap",
sid: this.session, sub: this.user.id,
aud: "your-audience", sid: this.session,
iat: Math.floor(Date.now() / 1000), aud: "your-audience",
jti: "jwt-id", iat: Math.floor(Date.now() / 1000),
events: { jti: "jwt-id",
"http://schemas.openid.net/event/backchannel-logout": {}, events: {
}, "http://schemas.openid.net/event/backchannel-logout": {},
},
}
}; };
const verifierMock = jest.spyOn(OidcJwtVerifier.prototype, "verifyLogoutToken"); const verifierMock = jest.spyOn(OidcJwtVerifier.prototype, "verifyLogoutToken");
verifierMock.mockImplementation(() => { verifierMock.mockImplementation(() => {
@@ -20,22 +20,29 @@ describe("Test back-channel logout", () => {
const verifyTokenMock = jest.spyOn(OidcJwtVerifier.prototype, "verifyLogoutToken"); const verifyTokenMock = jest.spyOn(OidcJwtVerifier.prototype, "verifyLogoutToken");
const validToken = { const validToken = {
"sid": "Ev81/QODom0HXu9MGjCwnn1tDTpji+j0jopjRAE0ypo", "header": {
"aud": [ "typ": "JWT",
"twakedrive" "alg": "RS256",
], "kid": "UrLwYyzqASOKT5wUedHERA"
"sub": "shepilov3@stg.lin-saas.com",
"iat": 1716986356,
"jti": "F9R6DYPE",
"events": {
"http://schemas.openid.net/event/backchannel-logout": {}
}, },
"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); const token = _.cloneDeep(validToken);
token[prop] = null token.claims[claim] = null
verifyTokenMock.mockImplementation(() => { verifyTokenMock.mockImplementation(() => {
return Promise.resolve(token); // Return the predefined payload 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", () => { it("backChannelLogout should throw error if 'iss' claim is missing", () => {
//given //given
mockTokenWithoutProperty("iss") mockTokenWithoutClaim("iss")
//when //when
let logout = subj.backChannelLogout(''); let logout = subj.backChannelLogout('');
//then //then
@@ -53,7 +60,7 @@ describe("Test back-channel logout", () => {
it("backChannelLogout should throw error if 'aud' claim is missing", () => { it("backChannelLogout should throw error if 'aud' claim is missing", () => {
//given //given
mockTokenWithoutProperty("aud") mockTokenWithoutClaim("aud")
//when //when
let logout = subj.backChannelLogout(''); let logout = subj.backChannelLogout('');
//then //then
@@ -62,7 +69,7 @@ describe("Test back-channel logout", () => {
it("backChannelLogout should throw error if 'jti' claim is missing", () => { it("backChannelLogout should throw error if 'jti' claim is missing", () => {
//given //given
mockTokenWithoutProperty("jti") mockTokenWithoutClaim("jti")
//when //when
let logout = subj.backChannelLogout(''); let logout = subj.backChannelLogout('');
//then //then
@@ -71,7 +78,7 @@ describe("Test back-channel logout", () => {
it("backChannelLogout should throw error if 'iat' claim is missing", () => { it("backChannelLogout should throw error if 'iat' claim is missing", () => {
//given //given
mockTokenWithoutProperty("iat") mockTokenWithoutClaim("iat")
//when //when
let logout = subj.backChannelLogout(''); let logout = subj.backChannelLogout('');
//then //then
@@ -80,7 +87,7 @@ describe("Test back-channel logout", () => {
it("backChannelLogout should throw error if 'events' claim is missing", () => { it("backChannelLogout should throw error if 'events' claim is missing", () => {
//given //given
mockTokenWithoutProperty("events") mockTokenWithoutClaim("events")
//when //when
let logout = subj.backChannelLogout(''); let logout = subj.backChannelLogout('');
//then //then
@@ -89,7 +96,7 @@ describe("Test back-channel logout", () => {
it("backChannelLogout should throw error if 'sub' claim is missing", () => { it("backChannelLogout should throw error if 'sub' claim is missing", () => {
//given //given
mockTokenWithoutProperty("sub") mockTokenWithoutClaim("sub")
//when //when
let logout = subj.backChannelLogout(''); let logout = subj.backChannelLogout('');
//then //then
@@ -98,7 +105,7 @@ describe("Test back-channel logout", () => {
it("backChannelLogout should throw error if 'sid' claim is missing", () => { it("backChannelLogout should throw error if 'sid' claim is missing", () => {
//given //given
mockTokenWithoutProperty("sid") mockTokenWithoutClaim("sid")
//when //when
let logout = subj.backChannelLogout(''); let logout = subj.backChannelLogout('');
//then //then