Skip to content

Commit

Permalink
add clock service to options so custom clock can be used
Browse files Browse the repository at this point in the history
  • Loading branch information
brockallen committed Oct 4, 2020
1 parent fe2d286 commit e3b23e2
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 36 deletions.
5 changes: 5 additions & 0 deletions src/ClockService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export class ClockService {
getEpochTime() {
return Promise.resolve(Date.now() / 1000 | 0);
}
}
11 changes: 10 additions & 1 deletion src/OidcClientSettings.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.

import { Log } from './Log.js';
import { ClockService } from './ClockService.js';
import { WebStorageStateStore } from './WebStorageStateStore.js';
import { ResponseValidator } from './ResponseValidator.js';
import { MetadataService } from './MetadataService.js';
Expand All @@ -24,7 +25,9 @@ export class OidcClientSettings {
prompt, display, max_age, ui_locales, acr_values, resource, response_mode,
// behavior flags
filterProtocolClaims = true, loadUserInfo = true,
staleStateAge = DefaultStaleStateAge, clockSkew = DefaultClockSkewInSeconds,
staleStateAge = DefaultStaleStateAge,
clockSkew = DefaultClockSkewInSeconds,
clockService = new ClockService(),
userInfoJwtIssuer = 'OP',
// other behavior
stateStore = new WebStorageStateStore(),
Expand Down Expand Up @@ -59,6 +62,7 @@ export class OidcClientSettings {
this._loadUserInfo = !!loadUserInfo;
this._staleStateAge = staleStateAge;
this._clockSkew = clockSkew;
this._clockService = clockService;
this._userInfoJwtIssuer = userInfoJwtIssuer;

this._stateStore = stateStore;
Expand Down Expand Up @@ -218,4 +222,9 @@ export class OidcClientSettings {
this._extraTokenParams = {};
}
}

// get the time
getEpochTime() {
return this._clockService.getEpochTime();
}
}
30 changes: 16 additions & 14 deletions src/ResponseValidator.js
Original file line number Diff line number Diff line change
Expand Up @@ -282,20 +282,22 @@ export class ResponseValidator {
let clockSkewInSeconds = this._settings.clockSkew;
Log.debug("ResponseValidator._validateIdTokenAttributes: Validaing JWT attributes; using clock skew (in seconds) of: ", clockSkewInSeconds);

return this._joseUtil.validateJwtAttributes(response.id_token, issuer, audience, clockSkewInSeconds).then(payload => {

if (state.nonce && state.nonce !== payload.nonce) {
Log.error("ResponseValidator._validateIdTokenAttributes: Invalid nonce in id_token");
return Promise.reject(new Error("Invalid nonce in id_token"));
}

if (!payload.sub) {
Log.error("ResponseValidator._validateIdTokenAttributes: No sub present in id_token");
return Promise.reject(new Error("No sub present in id_token"));
}

response.profile = payload;
return response;
return this._settings.getEpochTime().then(now => {
return this._joseUtil.validateJwtAttributes(response.id_token, issuer, audience, clockSkewInSeconds, now).then(payload => {

if (state.nonce && state.nonce !== payload.nonce) {
Log.error("ResponseValidator._validateIdTokenAttributes: Invalid nonce in id_token");
return Promise.reject(new Error("Invalid nonce in id_token"));
}

if (!payload.sub) {
Log.error("ResponseValidator._validateIdTokenAttributes: No sub present in id_token");
return Promise.reject(new Error("No sub present in id_token"));
}

response.profile = payload;
return response;
});
});
});
}
Expand Down
44 changes: 23 additions & 21 deletions src/UserManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,27 +218,29 @@ export class UserManager extends OidcClient {

_validateIdTokenFromTokenRefreshToken(profile, id_token) {
return this._metadataService.getIssuer().then(issuer => {
return this._joseUtil.validateJwtAttributes(id_token, issuer, this._settings.client_id, this._settings.clockSkew).then(payload => {
if (!payload) {
Log.error("UserManager._validateIdTokenFromTokenRefreshToken: Failed to validate id_token");
return Promise.reject(new Error("Failed to validate id_token"));
}
if (payload.sub !== profile.sub) {
Log.error("UserManager._validateIdTokenFromTokenRefreshToken: sub in id_token does not match current sub");
return Promise.reject(new Error("sub in id_token does not match current sub"));
}
if (payload.auth_time && payload.auth_time !== profile.auth_time) {
Log.error("UserManager._validateIdTokenFromTokenRefreshToken: auth_time in id_token does not match original auth_time");
return Promise.reject(new Error("auth_time in id_token does not match original auth_time"));
}
if (payload.azp && payload.azp !== profile.azp) {
Log.error("UserManager._validateIdTokenFromTokenRefreshToken: azp in id_token does not match original azp");
return Promise.reject(new Error("azp in id_token does not match original azp"));
}
if (!payload.azp && profile.azp) {
Log.error("UserManager._validateIdTokenFromTokenRefreshToken: azp not in id_token, but present in original id_token");
return Promise.reject(new Error("azp not in id_token, but present in original id_token"));
}
return this.settings.getEpochTime().then(now => {
return this._joseUtil.validateJwtAttributes(id_token, issuer, this._settings.client_id, this._settings.clockSkew, now).then(payload => {
if (!payload) {
Log.error("UserManager._validateIdTokenFromTokenRefreshToken: Failed to validate id_token");
return Promise.reject(new Error("Failed to validate id_token"));
}
if (payload.sub !== profile.sub) {
Log.error("UserManager._validateIdTokenFromTokenRefreshToken: sub in id_token does not match current sub");
return Promise.reject(new Error("sub in id_token does not match current sub"));
}
if (payload.auth_time && payload.auth_time !== profile.auth_time) {
Log.error("UserManager._validateIdTokenFromTokenRefreshToken: auth_time in id_token does not match original auth_time");
return Promise.reject(new Error("auth_time in id_token does not match original auth_time"));
}
if (payload.azp && payload.azp !== profile.azp) {
Log.error("UserManager._validateIdTokenFromTokenRefreshToken: azp in id_token does not match original azp");
return Promise.reject(new Error("azp in id_token does not match original azp"));
}
if (!payload.azp && profile.azp) {
Log.error("UserManager._validateIdTokenFromTokenRefreshToken: azp not in id_token, but present in original id_token");
return Promise.reject(new Error("azp not in id_token, but present in original id_token"));
}
});
});
});
}
Expand Down

0 comments on commit e3b23e2

Please sign in to comment.