Skip to content

Commit 7dba876

Browse files
committed
add process signout logic
1 parent dea6055 commit 7dba876

10 files changed

+291
-102
lines changed
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import Log from './Log';
22
import UrlUtility from './UrlUtility';
33

4-
export default class SigninResponseError {
4+
export default class ErrorResponse {
55
constructor({error, error_description, error_uri, state}={}
66
) {
77
if (!error){
8-
Log.error("No error passed to SigninResponseError");
8+
Log.error("No error passed to ErrorResponse");
99
throw new Error("error");
1010
}
1111

@@ -21,7 +21,7 @@ export default class SigninResponseError {
2121
return this.error_description || this.error;
2222
}
2323
get name(){
24-
return "SigninResponseError";
24+
return "ErrorResponse";
2525
}
2626
get stack(){
2727
return this._stack;

src/OidcClientService.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import MetadataService from './MetadataService';
44
import SigninRequest from './SigninRequest';
55
import SigninResponse from './SigninResponse';
66
import SignoutRequest from './SignoutRequest';
7+
import SignoutResponse from './SignoutResponse';
78
import WebStorageStateStore from './WebStorageStateStore';
89
import ResponseValidator from './ResponseValidator';
910

@@ -122,6 +123,27 @@ export default class OidcClientService {
122123
processSignoutResponse(url){
123124
Log.info("OidcClientService.processSignoutResponse");
124125

126+
var response = new SignoutResponse(url);
127+
if (!response.state) {
128+
Log.error("No state in response");
129+
return Promise.reject(new Error("No state in response"));
130+
}
131+
132+
var stateKey = response.state;
133+
134+
return this._stateStore.remove(stateKey).then(state => {
135+
if (!state){
136+
Log.error("No matching state found in storage");
137+
throw new Error("Failed to process response");
138+
}
139+
140+
Log.info("Received state from storage; validating response");
141+
return this._validator.validateSignoutResponse(state, response);
142+
143+
}, err => {
144+
Log.error("Failed to process response", err);
145+
return Promise.reject(new Error("Failed to process response"));
146+
});
125147
}
126148

127149
// OidcClient.prototype.processResponseAsync = function (queryString) {

src/ResponseValidator.js

Lines changed: 50 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,43 @@ export default class ResponseValidator {
2020
validateSigninResponse(state, response) {
2121
Log.info("ResponseValidator.validateSigninResponse");
2222

23-
return this.processState(state, response).then(response => {
23+
return this.processSigninParams(state, response).then(response => {
2424
Log.info("state processed");
2525
return this.validateTokens(state, response).then(response => {
2626
Log.info("tokens validated");
27-
return this.processClaims(response).then(response=>{
27+
return this.processClaims(response).then(response => {
2828
Log.info("claims processed");
2929
return response;
3030
});
3131
});
3232
});
3333
}
3434

35-
processState(state, response){
36-
Log.info("ResponseValidator.processState");
35+
validateSignoutResponse(state, response) {
36+
Log.info("ResponseValidator.validateSignoutResponse");
37+
38+
if (state.id !== response.state) {
39+
Log.error("State does not match");
40+
return Promise.reject(new Error("State does not match"));
41+
}
42+
43+
// now that we know the state matches, take the stored data
44+
// and set it into the response so callers can get their state
45+
// this is important for both success & error outcomes
46+
Log.info("state validated");
47+
response.state = state.data;
48+
49+
if (response.error) {
50+
Log.warn("Response was error", response.error);
51+
return Promise.reject(response);
52+
}
3753

54+
return Promise.resolve(response);
55+
}
56+
57+
processSigninParams(state, response) {
58+
Log.info("ResponseValidator.processSigninParams");
59+
3860
if (state.id !== response.state) {
3961
Log.error("State does not match");
4062
return Promise.reject(new Error("State does not match"));
@@ -60,13 +82,13 @@ export default class ResponseValidator {
6082
Log.error("Not expecting id_token in response");
6183
return Promise.reject(new Error("Unexpected id_token in response"));
6284
}
63-
85+
6486
return Promise.resolve(response);
6587
}
66-
67-
processClaims(response){
88+
89+
processClaims(response) {
6890
Log.info("ResponseValidator.processClaims");
69-
91+
7092
response.profile = this.filterProtocolClaims(response.profile);
7193

7294
// if (this._settings.loadUserInfo) {
@@ -84,24 +106,6 @@ export default class ResponseValidator {
84106
return Promise.resolve(response);
85107
}
86108

87-
validateTokens(state, response) {
88-
Log.info("ResponseValidator.validateTokens");
89-
90-
if (response.id_token) {
91-
92-
if (response.access_token) {
93-
Log.info("Validating id_token and access_token");
94-
return this.validateIdTokenAndAccessToken(state, response);
95-
}
96-
97-
Log.info("Validating id_token");
98-
return this.validateIdToken(state, response);
99-
}
100-
101-
Log.info("No id_token to validate");
102-
return Promise.resolve(response);
103-
}
104-
105109
// mergeClaims(claims1, claims2){
106110
// return claims1;
107111
// }
@@ -119,17 +123,35 @@ export default class ResponseValidator {
119123
return claims;
120124
}
121125

126+
validateTokens(state, response) {
127+
Log.info("ResponseValidator.validateTokens");
128+
129+
if (response.id_token) {
130+
131+
if (response.access_token) {
132+
Log.info("Validating id_token and access_token");
133+
return this.validateIdTokenAndAccessToken(state, response);
134+
}
135+
136+
Log.info("Validating id_token");
137+
return this.validateIdToken(state, response);
138+
}
139+
140+
Log.info("No id_token to validate");
141+
return Promise.resolve(response);
142+
}
143+
122144
validateIdTokenAndAccessToken(state, response) {
123145
Log.info("ResponseValidator.validateIdTokenAndAccessToken");
124-
146+
125147
return this.validateIdToken(state, response).then(response => {
126148
return this.validateAccessToken(response);
127149
});
128150
}
129151

130152
validateIdToken(state, response) {
131153
Log.info("ResponseValidator.validateIdToken");
132-
154+
133155
return Promise.resolve(response);
134156

135157
// log("OidcClient.validateIdTokenAsync");

src/SigninResponse.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import Log from './Log';
22
import UrlUtility from './UrlUtility';
3-
import SigninResponseError from './SigninResponseError';
3+
import ErrorResponse from './ErrorResponse';
44

55
export default class SigninResponse {
66
constructor(url) {
77

88
var values = UrlUtility.parseUrlFragment(url);
99

1010
if (values.error){
11-
return new SigninResponseError(values);
11+
return new ErrorResponse(values);
1212
}
1313

1414
this._state = values.state;

src/SignoutResponse.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import Log from './Log';
2+
import UrlUtility from './UrlUtility';
3+
import ErrorResponse from './ErrorResponse';
4+
5+
export default class SignoutResponse {
6+
constructor(url) {
7+
8+
var values = UrlUtility.parseUrlFragment(url);
9+
10+
if (values.error){
11+
return new ErrorResponse(values);
12+
}
13+
14+
this._state = values.state;
15+
}
16+
17+
get state(){
18+
return this._state;
19+
}
20+
set state(value){
21+
this._state = value;
22+
}
23+
}
Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
import Log from '../src/Log';
2-
import SigninResponseError from '../src/SigninResponseError';
2+
import ErrorResponse from '../src/ErrorResponse';
33

44
import chai from 'chai';
55
chai.should();
66
let assert = chai.assert;
77
let expect = chai.expect;
88

9-
describe("SigninResponseError", function() {
9+
describe("ErrorResponse", function() {
1010

1111
describe("constructor", function() {
1212

1313
it("should require a error param", function() {
1414
try {
15-
new SigninResponseError({});
15+
new ErrorResponse({});
1616
}
1717
catch (e) {
1818
e.message.should.contain('error');
@@ -22,51 +22,51 @@ describe("SigninResponseError", function() {
2222
});
2323

2424
it("should read error", function() {
25-
let subject = new SigninResponseError({error:"foo"});
25+
let subject = new ErrorResponse({error:"foo"});
2626
subject.error.should.equal("foo");
2727
});
2828

2929
it("should read error_description", function() {
30-
let subject = new SigninResponseError({error:"error", error_description:"foo"});
30+
let subject = new ErrorResponse({error:"error", error_description:"foo"});
3131
subject.error_description.should.equal("foo");
3232
});
3333

3434
it("should read error_uri", function() {
35-
let subject = new SigninResponseError({error:"error", error_uri:"foo"});
35+
let subject = new ErrorResponse({error:"error", error_uri:"foo"});
3636
subject.error_uri.should.equal("foo");
3737
});
3838

3939
it("should read state", function() {
40-
let subject = new SigninResponseError({error:"error", state:"foo"});
40+
let subject = new ErrorResponse({error:"error", state:"foo"});
4141
subject.state.should.equal("foo");
4242
});
4343
});
4444

4545
describe("message", function() {
4646
it("should be description if set", function() {
47-
let subject = new SigninResponseError({error:"error", error_description:"foo"});
47+
let subject = new ErrorResponse({error:"error", error_description:"foo"});
4848
subject.message.should.equal("foo");
4949
});
5050

5151
it("should be error if description not set", function() {
52-
let subject = new SigninResponseError({error:"error"});
52+
let subject = new ErrorResponse({error:"error"});
5353
subject.message.should.equal("error");
5454
});
5555

5656
});
5757

5858
describe("name", function() {
5959
it("should be class name", function() {
60-
let subject = new SigninResponseError({error:"error"});
61-
subject.name.should.equal("SigninResponseError");
60+
let subject = new ErrorResponse({error:"error"});
61+
subject.name.should.equal("ErrorResponse");
6262
});
6363

6464
});
6565

6666
describe("stack", function() {
6767

6868
it("should be set", function() {
69-
let subject = new SigninResponseError({error:"error"});
69+
let subject = new ErrorResponse({error:"error"});
7070
subject.stack.should.be.ok;
7171
});
7272

0 commit comments

Comments
 (0)