angular-auth-oidc-client
Version:
An OpenID Connect Code Flow with PKCE,Implicit Flow client for Angular
674 lines • 71.4 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
import * as tslib_1 from "tslib";
import { Injectable } from '@angular/core';
import { hextob64u, KEYUTIL, KJUR } from 'jsrsasign';
import { EqualityHelperService } from './oidc-equality-helper.service';
import { TokenHelperService } from './oidc-token-helper.service';
import { LoggerService } from './oidc.logger.service';
// http://openid.net/specs/openid-connect-implicit-1_0.html
// id_token
// id_token C1: The Issuer Identifier for the OpenID Provider (which is typically obtained during Discovery)
// MUST exactly match the value of the iss (issuer) Claim.
//
// id_token C2: The Client MUST validate that the aud (audience) Claim contains its client_id value registered at the Issuer identified
// by the iss (issuer) Claim as an audience.The ID Token MUST be rejected if the ID Token does not list the Client as a valid audience,
// or if it contains additional audiences not trusted by the Client.
//
// id_token C3: If the ID Token contains multiple audiences, the Client SHOULD verify that an azp Claim is present.
//
// id_token C4: If an azp (authorized party) Claim is present, the Client SHOULD verify that its client_id is the Claim Value.
//
// id_token C5: The Client MUST validate the signature of the ID Token according to JWS [JWS] using the algorithm specified in the
// alg Header Parameter of the JOSE Header.The Client MUST use the keys provided by the Issuer.
//
// id_token C6: The alg value SHOULD be RS256. Validation of tokens using other signing algorithms is described in the OpenID Connect Core 1.0
// [OpenID.Core] specification.
//
// id_token C7: The current time MUST be before the time represented by the exp Claim (possibly allowing for some small leeway to account
// for clock skew).
//
// id_token C8: The iat Claim can be used to reject tokens that were issued too far away from the current time,
// limiting the amount of time that nonces need to be stored to prevent attacks.The acceptable range is Client specific.
//
// id_token C9: The value of the nonce Claim MUST be checked to verify that it is the same value as the one that was sent
// in the Authentication Request.The Client SHOULD check the nonce value for replay attacks.The precise method for detecting replay attacks
// is Client specific.
//
// id_token C10: If the acr Claim was requested, the Client SHOULD check that the asserted Claim Value is appropriate.
// The meaning and processing of acr Claim Values is out of scope for this document.
//
// id_token C11: When a max_age request is made, the Client SHOULD check the auth_time Claim value and request re- authentication
// if it determines too much time has elapsed since the last End- User authentication.
// Access Token Validation
// access_token C1: Hash the octets of the ASCII representation of the access_token with the hash algorithm specified in JWA[JWA]
// for the alg Header Parameter of the ID Token's JOSE Header. For instance, if the alg is RS256, the hash algorithm used is SHA-256.
// access_token C2: Take the left- most half of the hash and base64url- encode it.
// access_token C3: The value of at_hash in the ID Token MUST match the value produced in the previous step if at_hash is present in the ID Token.
var OidcSecurityValidation = /** @class */ (function () {
function OidcSecurityValidation(arrayHelperService, tokenHelperService, loggerService) {
this.arrayHelperService = arrayHelperService;
this.tokenHelperService = tokenHelperService;
this.loggerService = loggerService;
}
// id_token C7: The current time MUST be before the time represented by the exp Claim (possibly allowing for some small leeway to account for clock skew).
// id_token C7: The current time MUST be before the time represented by the exp Claim (possibly allowing for some small leeway to account for clock skew).
/**
* @param {?} token
* @param {?=} offsetSeconds
* @return {?}
*/
OidcSecurityValidation.prototype.isTokenExpired =
// id_token C7: The current time MUST be before the time represented by the exp Claim (possibly allowing for some small leeway to account for clock skew).
/**
* @param {?} token
* @param {?=} offsetSeconds
* @return {?}
*/
function (token, offsetSeconds) {
/** @type {?} */
var decoded;
decoded = this.tokenHelperService.getPayloadFromToken(token, false);
return !this.validate_id_token_exp_not_expired(decoded, offsetSeconds);
};
// id_token C7: The current time MUST be before the time represented by the exp Claim (possibly allowing for some small leeway to account for clock skew).
// id_token C7: The current time MUST be before the time represented by the exp Claim (possibly allowing for some small leeway to account for clock skew).
/**
* @param {?} decoded_id_token
* @param {?=} offsetSeconds
* @return {?}
*/
OidcSecurityValidation.prototype.validate_id_token_exp_not_expired =
// id_token C7: The current time MUST be before the time represented by the exp Claim (possibly allowing for some small leeway to account for clock skew).
/**
* @param {?} decoded_id_token
* @param {?=} offsetSeconds
* @return {?}
*/
function (decoded_id_token, offsetSeconds) {
/** @type {?} */
var tokenExpirationDate = this.tokenHelperService.getTokenExpirationDate(decoded_id_token);
offsetSeconds = offsetSeconds || 0;
if (!tokenExpirationDate) {
return false;
}
/** @type {?} */
var tokenExpirationValue = tokenExpirationDate.valueOf();
/** @type {?} */
var nowWithOffset = new Date().valueOf() + offsetSeconds * 1000;
/** @type {?} */
var tokenNotExpired = tokenExpirationValue > nowWithOffset;
this.loggerService.logDebug("Token not expired?: " + tokenExpirationValue + " > " + nowWithOffset + " (" + tokenNotExpired + ")");
// Token not expired?
return tokenNotExpired;
};
// iss
// REQUIRED. Issuer Identifier for the Issuer of the response.The iss value is a case-sensitive URL using the https scheme that contains scheme, host,
// and optionally, port number and path components and no query or fragment components.
//
// sub
// REQUIRED. Subject Identifier.Locally unique and never reassigned identifier within the Issuer for the End- User,
// which is intended to be consumed by the Client, e.g., 24400320 or AItOawmwtWwcT0k51BayewNvutrJUqsvl6qs7A4.
// It MUST NOT exceed 255 ASCII characters in length.The sub value is a case-sensitive string.
//
// aud
// REQUIRED. Audience(s) that this ID Token is intended for. It MUST contain the OAuth 2.0 client_id of the Relying Party as an audience value.
// It MAY also contain identifiers for other audiences.In the general case, the aud value is an array of case-sensitive strings.
// In the common special case when there is one audience, the aud value MAY be a single case-sensitive string.
//
// exp
// REQUIRED. Expiration time on or after which the ID Token MUST NOT be accepted for processing.
// The processing of this parameter requires that the current date/ time MUST be before the expiration date/ time listed in the value.
// Implementers MAY provide for some small leeway, usually no more than a few minutes, to account for clock skew.
// Its value is a JSON [RFC7159] number representing the number of seconds from 1970- 01 - 01T00: 00:00Z as measured in UTC until the date/ time.
// See RFC 3339 [RFC3339] for details regarding date/ times in general and UTC in particular.
//
// iat
// REQUIRED. Time at which the JWT was issued. Its value is a JSON number representing the number of seconds from 1970- 01 - 01T00: 00:00Z as measured
// in UTC until the date/ time.
// iss
// REQUIRED. Issuer Identifier for the Issuer of the response.The iss value is a case-sensitive URL using the https scheme that contains scheme, host,
// and optionally, port number and path components and no query or fragment components.
//
// sub
// REQUIRED. Subject Identifier.Locally unique and never reassigned identifier within the Issuer for the End- User,
// which is intended to be consumed by the Client, e.g., 24400320 or AItOawmwtWwcT0k51BayewNvutrJUqsvl6qs7A4.
// It MUST NOT exceed 255 ASCII characters in length.The sub value is a case-sensitive string.
//
// aud
// REQUIRED. Audience(s) that this ID Token is intended for. It MUST contain the OAuth 2.0 client_id of the Relying Party as an audience value.
// It MAY also contain identifiers for other audiences.In the general case, the aud value is an array of case-sensitive strings.
// In the common special case when there is one audience, the aud value MAY be a single case-sensitive string.
//
// exp
// REQUIRED. Expiration time on or after which the ID Token MUST NOT be accepted for processing.
// The processing of this parameter requires that the current date/ time MUST be before the expiration date/ time listed in the value.
// Implementers MAY provide for some small leeway, usually no more than a few minutes, to account for clock skew.
// Its value is a JSON [RFC7159] number representing the number of seconds from 1970- 01 - 01T00: 00:00Z as measured in UTC until the date/ time.
// See RFC 3339 [RFC3339] for details regarding date/ times in general and UTC in particular.
//
// iat
// REQUIRED. Time at which the JWT was issued. Its value is a JSON number representing the number of seconds from 1970- 01 - 01T00: 00:00Z as measured
// in UTC until the date/ time.
/**
* @param {?} dataIdToken
* @return {?}
*/
OidcSecurityValidation.prototype.validate_required_id_token =
// iss
// REQUIRED. Issuer Identifier for the Issuer of the response.The iss value is a case-sensitive URL using the https scheme that contains scheme, host,
// and optionally, port number and path components and no query or fragment components.
//
// sub
// REQUIRED. Subject Identifier.Locally unique and never reassigned identifier within the Issuer for the End- User,
// which is intended to be consumed by the Client, e.g., 24400320 or AItOawmwtWwcT0k51BayewNvutrJUqsvl6qs7A4.
// It MUST NOT exceed 255 ASCII characters in length.The sub value is a case-sensitive string.
//
// aud
// REQUIRED. Audience(s) that this ID Token is intended for. It MUST contain the OAuth 2.0 client_id of the Relying Party as an audience value.
// It MAY also contain identifiers for other audiences.In the general case, the aud value is an array of case-sensitive strings.
// In the common special case when there is one audience, the aud value MAY be a single case-sensitive string.
//
// exp
// REQUIRED. Expiration time on or after which the ID Token MUST NOT be accepted for processing.
// The processing of this parameter requires that the current date/ time MUST be before the expiration date/ time listed in the value.
// Implementers MAY provide for some small leeway, usually no more than a few minutes, to account for clock skew.
// Its value is a JSON [RFC7159] number representing the number of seconds from 1970- 01 - 01T00: 00:00Z as measured in UTC until the date/ time.
// See RFC 3339 [RFC3339] for details regarding date/ times in general and UTC in particular.
//
// iat
// REQUIRED. Time at which the JWT was issued. Its value is a JSON number representing the number of seconds from 1970- 01 - 01T00: 00:00Z as measured
// in UTC until the date/ time.
/**
* @param {?} dataIdToken
* @return {?}
*/
function (dataIdToken) {
/** @type {?} */
var validated = true;
if (!dataIdToken.hasOwnProperty('iss')) {
validated = false;
this.loggerService.logWarning('iss is missing, this is required in the id_token');
}
if (!dataIdToken.hasOwnProperty('sub')) {
validated = false;
this.loggerService.logWarning('sub is missing, this is required in the id_token');
}
if (!dataIdToken.hasOwnProperty('aud')) {
validated = false;
this.loggerService.logWarning('aud is missing, this is required in the id_token');
}
if (!dataIdToken.hasOwnProperty('exp')) {
validated = false;
this.loggerService.logWarning('exp is missing, this is required in the id_token');
}
if (!dataIdToken.hasOwnProperty('iat')) {
validated = false;
this.loggerService.logWarning('iat is missing, this is required in the id_token');
}
return validated;
};
// id_token C8: The iat Claim can be used to reject tokens that were issued too far away from the current time,
// limiting the amount of time that nonces need to be stored to prevent attacks.The acceptable range is Client specific.
// id_token C8: The iat Claim can be used to reject tokens that were issued too far away from the current time,
// limiting the amount of time that nonces need to be stored to prevent attacks.The acceptable range is Client specific.
/**
* @param {?} dataIdToken
* @param {?} max_offset_allowed_in_seconds
* @param {?} disable_iat_offset_validation
* @return {?}
*/
OidcSecurityValidation.prototype.validate_id_token_iat_max_offset =
// id_token C8: The iat Claim can be used to reject tokens that were issued too far away from the current time,
// limiting the amount of time that nonces need to be stored to prevent attacks.The acceptable range is Client specific.
/**
* @param {?} dataIdToken
* @param {?} max_offset_allowed_in_seconds
* @param {?} disable_iat_offset_validation
* @return {?}
*/
function (dataIdToken, max_offset_allowed_in_seconds, disable_iat_offset_validation) {
if (disable_iat_offset_validation) {
return true;
}
if (!dataIdToken.hasOwnProperty('iat')) {
return false;
}
/** @type {?} */
var dateTime_iat_id_token = new Date(0);
dateTime_iat_id_token.setUTCSeconds(dataIdToken.iat);
max_offset_allowed_in_seconds = max_offset_allowed_in_seconds || 0;
if (dateTime_iat_id_token == null) {
return false;
}
this.loggerService.logDebug('validate_id_token_iat_max_offset: ' +
(new Date().valueOf() - dateTime_iat_id_token.valueOf()) +
' < ' +
max_offset_allowed_in_seconds * 1000);
return new Date().valueOf() - dateTime_iat_id_token.valueOf() < max_offset_allowed_in_seconds * 1000;
};
// id_token C9: The value of the nonce Claim MUST be checked to verify that it is the same value as the one
// that was sent in the Authentication Request.The Client SHOULD check the nonce value for replay attacks.
// The precise method for detecting replay attacks is Client specific.
// id_token C9: The value of the nonce Claim MUST be checked to verify that it is the same value as the one
// that was sent in the Authentication Request.The Client SHOULD check the nonce value for replay attacks.
// The precise method for detecting replay attacks is Client specific.
/**
* @param {?} dataIdToken
* @param {?} local_nonce
* @return {?}
*/
OidcSecurityValidation.prototype.validate_id_token_nonce =
// id_token C9: The value of the nonce Claim MUST be checked to verify that it is the same value as the one
// that was sent in the Authentication Request.The Client SHOULD check the nonce value for replay attacks.
// The precise method for detecting replay attacks is Client specific.
/**
* @param {?} dataIdToken
* @param {?} local_nonce
* @return {?}
*/
function (dataIdToken, local_nonce) {
if (dataIdToken.nonce !== local_nonce) {
this.loggerService.logDebug('Validate_id_token_nonce failed, dataIdToken.nonce: ' + dataIdToken.nonce + ' local_nonce:' + local_nonce);
return false;
}
return true;
};
// id_token C1: The Issuer Identifier for the OpenID Provider (which is typically obtained during Discovery)
// MUST exactly match the value of the iss (issuer) Claim.
// id_token C1: The Issuer Identifier for the OpenID Provider (which is typically obtained during Discovery)
// MUST exactly match the value of the iss (issuer) Claim.
/**
* @param {?} dataIdToken
* @param {?} authWellKnownEndpoints_issuer
* @return {?}
*/
OidcSecurityValidation.prototype.validate_id_token_iss =
// id_token C1: The Issuer Identifier for the OpenID Provider (which is typically obtained during Discovery)
// MUST exactly match the value of the iss (issuer) Claim.
/**
* @param {?} dataIdToken
* @param {?} authWellKnownEndpoints_issuer
* @return {?}
*/
function (dataIdToken, authWellKnownEndpoints_issuer) {
if (((/** @type {?} */ (dataIdToken.iss))) !== ((/** @type {?} */ (authWellKnownEndpoints_issuer)))) {
this.loggerService.logDebug('Validate_id_token_iss failed, dataIdToken.iss: ' +
dataIdToken.iss +
' authWellKnownEndpoints issuer:' +
authWellKnownEndpoints_issuer);
return false;
}
return true;
};
// id_token C2: The Client MUST validate that the aud (audience) Claim contains its client_id value registered at the Issuer identified
// by the iss (issuer) Claim as an audience.
// The ID Token MUST be rejected if the ID Token does not list the Client as a valid audience, or if it contains additional audiences
// not trusted by the Client.
// id_token C2: The Client MUST validate that the aud (audience) Claim contains its client_id value registered at the Issuer identified
// by the iss (issuer) Claim as an audience.
// The ID Token MUST be rejected if the ID Token does not list the Client as a valid audience, or if it contains additional audiences
// not trusted by the Client.
/**
* @param {?} dataIdToken
* @param {?} aud
* @return {?}
*/
OidcSecurityValidation.prototype.validate_id_token_aud =
// id_token C2: The Client MUST validate that the aud (audience) Claim contains its client_id value registered at the Issuer identified
// by the iss (issuer) Claim as an audience.
// The ID Token MUST be rejected if the ID Token does not list the Client as a valid audience, or if it contains additional audiences
// not trusted by the Client.
/**
* @param {?} dataIdToken
* @param {?} aud
* @return {?}
*/
function (dataIdToken, aud) {
if (dataIdToken.aud instanceof Array) {
/** @type {?} */
var result = this.arrayHelperService.areEqual(dataIdToken.aud, aud);
if (!result) {
this.loggerService.logDebug('Validate_id_token_aud array failed, dataIdToken.aud: ' + dataIdToken.aud + ' client_id:' + aud);
return false;
}
return true;
}
else if (dataIdToken.aud !== aud) {
this.loggerService.logDebug('Validate_id_token_aud failed, dataIdToken.aud: ' + dataIdToken.aud + ' client_id:' + aud);
return false;
}
return true;
};
/**
* @param {?} state
* @param {?} local_state
* @return {?}
*/
OidcSecurityValidation.prototype.validateStateFromHashCallback = /**
* @param {?} state
* @param {?} local_state
* @return {?}
*/
function (state, local_state) {
if (((/** @type {?} */ (state))) !== ((/** @type {?} */ (local_state)))) {
this.loggerService.logDebug('ValidateStateFromHashCallback failed, state: ' + state + ' local_state:' + local_state);
return false;
}
return true;
};
/**
* @param {?} id_token_sub
* @param {?} userdata_sub
* @return {?}
*/
OidcSecurityValidation.prototype.validate_userdata_sub_id_token = /**
* @param {?} id_token_sub
* @param {?} userdata_sub
* @return {?}
*/
function (id_token_sub, userdata_sub) {
if (((/** @type {?} */ (id_token_sub))) !== ((/** @type {?} */ (userdata_sub)))) {
this.loggerService.logDebug('validate_userdata_sub_id_token failed, id_token_sub: ' + id_token_sub + ' userdata_sub:' + userdata_sub);
return false;
}
return true;
};
// id_token C5: The Client MUST validate the signature of the ID Token according to JWS [JWS] using the algorithm specified in the alg
// Header Parameter of the JOSE Header.The Client MUST use the keys provided by the Issuer.
// id_token C6: The alg value SHOULD be RS256. Validation of tokens using other signing algorithms is described in the
// OpenID Connect Core 1.0 [OpenID.Core] specification.
// id_token C5: The Client MUST validate the signature of the ID Token according to JWS [JWS] using the algorithm specified in the alg
// Header Parameter of the JOSE Header.The Client MUST use the keys provided by the Issuer.
// id_token C6: The alg value SHOULD be RS256. Validation of tokens using other signing algorithms is described in the
// OpenID Connect Core 1.0 [OpenID.Core] specification.
/**
* @param {?} id_token
* @param {?} jwtkeys
* @return {?}
*/
OidcSecurityValidation.prototype.validate_signature_id_token =
// id_token C5: The Client MUST validate the signature of the ID Token according to JWS [JWS] using the algorithm specified in the alg
// Header Parameter of the JOSE Header.The Client MUST use the keys provided by the Issuer.
// id_token C6: The alg value SHOULD be RS256. Validation of tokens using other signing algorithms is described in the
// OpenID Connect Core 1.0 [OpenID.Core] specification.
/**
* @param {?} id_token
* @param {?} jwtkeys
* @return {?}
*/
function (id_token, jwtkeys) {
var e_1, _a, e_2, _b, e_3, _c;
if (!jwtkeys || !jwtkeys.keys) {
return false;
}
/** @type {?} */
var header_data = this.tokenHelperService.getHeaderFromToken(id_token, false);
if (Object.keys(header_data).length === 0 && header_data.constructor === Object) {
this.loggerService.logWarning('id token has no header data');
return false;
}
/** @type {?} */
var kid = header_data.kid;
/** @type {?} */
var alg = header_data.alg;
if ('RS256' !== ((/** @type {?} */ (alg)))) {
this.loggerService.logWarning('Only RS256 supported');
return false;
}
/** @type {?} */
var isValid = false;
if (!header_data.hasOwnProperty('kid')) {
// exactly 1 key in the jwtkeys and no kid in the Jose header
// kty "RSA" use "sig"
/** @type {?} */
var amountOfMatchingKeys = 0;
try {
for (var _d = tslib_1.__values(jwtkeys.keys), _e = _d.next(); !_e.done; _e = _d.next()) {
var key = _e.value;
if (((/** @type {?} */ (key.kty))) === 'RSA' && ((/** @type {?} */ (key.use))) === 'sig') {
amountOfMatchingKeys = amountOfMatchingKeys + 1;
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_e && !_e.done && (_a = _d.return)) _a.call(_d);
}
finally { if (e_1) throw e_1.error; }
}
if (amountOfMatchingKeys === 0) {
this.loggerService.logWarning('no keys found, incorrect Signature, validation failed for id_token');
return false;
}
else if (amountOfMatchingKeys > 1) {
this.loggerService.logWarning('no ID Token kid claim in JOSE header and multiple supplied in jwks_uri');
return false;
}
else {
try {
for (var _f = tslib_1.__values(jwtkeys.keys), _g = _f.next(); !_g.done; _g = _f.next()) {
var key = _g.value;
if (((/** @type {?} */ (key.kty))) === 'RSA' && ((/** @type {?} */ (key.use))) === 'sig') {
/** @type {?} */
var publickey = KEYUTIL.getKey(key);
isValid = KJUR.jws.JWS.verify(id_token, publickey, ['RS256']);
if (!isValid) {
this.loggerService.logWarning('incorrect Signature, validation failed for id_token');
}
return isValid;
}
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (_g && !_g.done && (_b = _f.return)) _b.call(_f);
}
finally { if (e_2) throw e_2.error; }
}
}
}
else {
try {
// kid in the Jose header of id_token
for (var _h = tslib_1.__values(jwtkeys.keys), _j = _h.next(); !_j.done; _j = _h.next()) {
var key = _j.value;
if (((/** @type {?} */ (key.kid))) === ((/** @type {?} */ (kid)))) {
/** @type {?} */
var publickey = KEYUTIL.getKey(key);
isValid = KJUR.jws.JWS.verify(id_token, publickey, ['RS256']);
if (!isValid) {
this.loggerService.logWarning('incorrect Signature, validation failed for id_token');
}
return isValid;
}
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (_j && !_j.done && (_c = _h.return)) _c.call(_h);
}
finally { if (e_3) throw e_3.error; }
}
}
return isValid;
};
/**
* @param {?} response_type
* @return {?}
*/
OidcSecurityValidation.prototype.config_validate_response_type = /**
* @param {?} response_type
* @return {?}
*/
function (response_type) {
if (response_type === 'id_token token' || response_type === 'id_token') {
return true;
}
if (response_type === 'code') {
return true;
}
this.loggerService.logWarning('module configure incorrect, invalid response_type:' + response_type);
return false;
};
// Accepts ID Token without 'kid' claim in JOSE header if only one JWK supplied in 'jwks_url'
//// private validate_no_kid_in_header_only_one_allowed_in_jwtkeys(header_data: any, jwtkeys: any): boolean {
//// this.oidcSecurityCommon.logDebug('amount of jwtkeys.keys: ' + jwtkeys.keys.length);
//// if (!header_data.hasOwnProperty('kid')) {
//// // no kid defined in Jose header
//// if (jwtkeys.keys.length != 1) {
//// this.oidcSecurityCommon.logDebug('jwtkeys.keys.length != 1 and no kid in header');
//// return false;
//// }
//// }
//// return true;
//// }
// Access Token Validation
// access_token C1: Hash the octets of the ASCII representation of the access_token with the hash algorithm specified in JWA[JWA]
// for the alg Header Parameter of the ID Token's JOSE Header. For instance, if the alg is RS256, the hash algorithm used is SHA-256.
// access_token C2: Take the left- most half of the hash and base64url- encode it.
// access_token C3: The value of at_hash in the ID Token MUST match the value produced in the previous step if at_hash
// is present in the ID Token.
// Accepts ID Token without 'kid' claim in JOSE header if only one JWK supplied in 'jwks_url'
//// private validate_no_kid_in_header_only_one_allowed_in_jwtkeys(header_data: any, jwtkeys: any): boolean {
//// this.oidcSecurityCommon.logDebug('amount of jwtkeys.keys: ' + jwtkeys.keys.length);
//// if (!header_data.hasOwnProperty('kid')) {
//// // no kid defined in Jose header
//// if (jwtkeys.keys.length != 1) {
//// this.oidcSecurityCommon.logDebug('jwtkeys.keys.length != 1 and no kid in header');
//// return false;
//// }
//// }
//// return true;
//// }
// Access Token Validation
// access_token C1: Hash the octets of the ASCII representation of the access_token with the hash algorithm specified in JWA[JWA]
// for the alg Header Parameter of the ID Token's JOSE Header. For instance, if the alg is RS256, the hash algorithm used is SHA-256.
// access_token C2: Take the left- most half of the hash and base64url- encode it.
// access_token C3: The value of at_hash in the ID Token MUST match the value produced in the previous step if at_hash
// is present in the ID Token.
/**
* @param {?} access_token
* @param {?} at_hash
* @param {?} isCodeFlow
* @return {?}
*/
OidcSecurityValidation.prototype.validate_id_token_at_hash =
// Accepts ID Token without 'kid' claim in JOSE header if only one JWK supplied in 'jwks_url'
//// private validate_no_kid_in_header_only_one_allowed_in_jwtkeys(header_data: any, jwtkeys: any): boolean {
//// this.oidcSecurityCommon.logDebug('amount of jwtkeys.keys: ' + jwtkeys.keys.length);
//// if (!header_data.hasOwnProperty('kid')) {
//// // no kid defined in Jose header
//// if (jwtkeys.keys.length != 1) {
//// this.oidcSecurityCommon.logDebug('jwtkeys.keys.length != 1 and no kid in header');
//// return false;
//// }
//// }
//// return true;
//// }
// Access Token Validation
// access_token C1: Hash the octets of the ASCII representation of the access_token with the hash algorithm specified in JWA[JWA]
// for the alg Header Parameter of the ID Token's JOSE Header. For instance, if the alg is RS256, the hash algorithm used is SHA-256.
// access_token C2: Take the left- most half of the hash and base64url- encode it.
// access_token C3: The value of at_hash in the ID Token MUST match the value produced in the previous step if at_hash
// is present in the ID Token.
/**
* @param {?} access_token
* @param {?} at_hash
* @param {?} isCodeFlow
* @return {?}
*/
function (access_token, at_hash, isCodeFlow) {
this.loggerService.logDebug('at_hash from the server:' + at_hash);
// The at_hash is optional for the code flow
if (isCodeFlow) {
if (!((/** @type {?} */ (at_hash)))) {
this.loggerService.logDebug('Code Flow active, and no at_hash in the id_token, skipping check!');
return true;
}
}
/** @type {?} */
var testdata = this.generate_at_hash('' + access_token);
this.loggerService.logDebug('at_hash client validation not decoded:' + testdata);
if (testdata === ((/** @type {?} */ (at_hash)))) {
return true; // isValid;
}
else {
/** @type {?} */
var testValue = this.generate_at_hash('' + decodeURIComponent(access_token));
this.loggerService.logDebug('-gen access--' + testValue);
if (testValue === ((/** @type {?} */ (at_hash)))) {
return true; // isValid
}
}
return false;
};
/**
* @private
* @param {?} access_token
* @return {?}
*/
OidcSecurityValidation.prototype.generate_at_hash = /**
* @private
* @param {?} access_token
* @return {?}
*/
function (access_token) {
/** @type {?} */
var hash = KJUR.crypto.Util.hashString(access_token, 'sha256');
/** @type {?} */
var first128bits = hash.substr(0, hash.length / 2);
/** @type {?} */
var testdata = hextob64u(first128bits);
return testdata;
};
/**
* @param {?} code_challenge
* @return {?}
*/
OidcSecurityValidation.prototype.generate_code_verifier = /**
* @param {?} code_challenge
* @return {?}
*/
function (code_challenge) {
/** @type {?} */
var hash = KJUR.crypto.Util.hashString(code_challenge, 'sha256');
/** @type {?} */
var testdata = hextob64u(hash);
return testdata;
};
OidcSecurityValidation.decorators = [
{ type: Injectable }
];
/** @nocollapse */
OidcSecurityValidation.ctorParameters = function () { return [
{ type: EqualityHelperService },
{ type: TokenHelperService },
{ type: LoggerService }
]; };
return OidcSecurityValidation;
}());
export { OidcSecurityValidation };
if (false) {
/**
* @type {?}
* @private
*/
OidcSecurityValidation.prototype.arrayHelperService;
/**
* @type {?}
* @private
*/
OidcSecurityValidation.prototype.tokenHelperService;
/**
* @type {?}
* @private
*/
OidcSecurityValidation.prototype.loggerService;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib2lkYy5zZWN1cml0eS52YWxpZGF0aW9uLmpzIiwic291cmNlUm9vdCI6Im5nOi8vYW5ndWxhci1hdXRoLW9pZGMtY2xpZW50LyIsInNvdXJjZXMiOlsibGliL3NlcnZpY2VzL29pZGMuc2VjdXJpdHkudmFsaWRhdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0MsT0FBTyxFQUFFLFNBQVMsRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQ3JELE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQ3ZFLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQ2pFLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQTRDdEQ7SUFFSSxnQ0FDWSxrQkFBeUMsRUFDekMsa0JBQXNDLEVBQ3RDLGFBQTRCO1FBRjVCLHVCQUFrQixHQUFsQixrQkFBa0IsQ0FBdUI7UUFDekMsdUJBQWtCLEdBQWxCLGtCQUFrQixDQUFvQjtRQUN0QyxrQkFBYSxHQUFiLGFBQWEsQ0FBZTtJQUNyQyxDQUFDO0lBRUosMEpBQTBKOzs7Ozs7O0lBQzFKLCtDQUFjOzs7Ozs7O0lBQWQsVUFBZSxLQUFhLEVBQUUsYUFBc0I7O1lBQzVDLE9BQVk7UUFDaEIsT0FBTyxHQUFHLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxtQkFBbUIsQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFFcEUsT0FBTyxDQUFDLElBQUksQ0FBQyxpQ0FBaUMsQ0FBQyxPQUFPLEVBQUUsYUFBYSxDQUFDLENBQUM7SUFDM0UsQ0FBQztJQUVELDBKQUEwSjs7Ozs7OztJQUMxSixrRUFBaUM7Ozs7Ozs7SUFBakMsVUFBa0MsZ0JBQXdCLEVBQUUsYUFBc0I7O1lBQ3hF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YXIvY29yZSc7XG5pbXBvcnQgeyBoZXh0b2I2NHUsIEtFWVVUSUwsIEtKVVIgfSBmcm9tICdqc3JzYXNpZ24nO1xuaW1wb3J0IHsgRXF1YWxpdHlIZWxwZXJTZXJ2aWNlIH0gZnJvbSAnLi9vaWRjLWVxdWFsaXR5LWhlbHBlci5zZXJ2aWNlJztcbmltcG9ydCB7IFRva2VuSGVscGVyU2VydmljZSB9IGZyb20gJy4vb2lkYy10b2tlbi1oZWxwZXIuc2VydmljZSc7XG5pbXBvcnQgeyBMb2dnZXJTZXJ2aWNlIH0gZnJvbSAnLi9vaWRjLmxvZ2dlci5zZXJ2aWNlJztcblxuLy8gaHR0cDovL29wZW5pZC5uZXQvc3BlY3Mvb3BlbmlkLWNvbm5lY3QtaW1wbGljaXQtMV8wLmh0bWxcblxuLy8gaWRfdG9rZW5cbi8vIGlkX3Rva2VuIEMxOiBUaGUgSXNzdWVyIElkZW50aWZpZXIgZm9yIHRoZSBPcGVuSUQgUHJvdmlkZXIgKHdoaWNoIGlzIHR5cGljYWxseSBvYnRhaW5lZCBkdXJpbmcgRGlzY292ZXJ5KVxuLy8gTVVTVCBleGFjdGx5IG1hdGNoIHRoZSB2YWx1ZSBvZiB0aGUgaXNzIChpc3N1ZXIpIENsYWltLlxuLy9cbi8vIGlkX3Rva2VuIEMyOiBUaGUgQ2xpZW50IE1VU1QgdmFsaWRhdGUgdGhhdCB0aGUgYXVkIChhdWRpZW5jZSkgQ2xhaW0gY29udGFpbnMgaXRzIGNsaWVudF9pZCB2YWx1ZSByZWdpc3RlcmVkIGF0IHRoZSBJc3N1ZXIgaWRlbnRpZmllZFxuLy8gYnkgdGhlIGlzcyAoaXNzdWVyKSBDbGFpbSBhcyBhbiBhdWRpZW5jZS5UaGUgSUQgVG9rZW4gTVVTVCBiZSByZWplY3RlZCBpZiB0aGUgSUQgVG9rZW4gZG9lcyBub3QgbGlzdCB0aGUgQ2xpZW50IGFzIGEgdmFsaWQgYXVkaWVuY2UsXG4vLyBvciBpZiBpdCBjb250YWlucyBhZGRpdGlvbmFsIGF1ZGllbmNlcyBub3QgdHJ1c3RlZCBieSB0aGUgQ2xpZW50LlxuLy9cbi8vIGlkX3Rva2VuIEMzOiBJZiB0aGUgSUQgVG9rZW4gY29udGFpbnMgbXVsdGlwbGUgYXVkaWVuY2VzLCB0aGUgQ2xpZW50IFNIT1VMRCB2ZXJpZnkgdGhhdCBhbiBhenAgQ2xhaW0gaXMgcHJlc2VudC5cbi8vXG4vLyBpZF90b2tlbiBDNDogSWYgYW4gYXpwIChhdXRob3JpemVkIHBhcnR5KSBDbGFpbSBpcyBwcmVzZW50LCB0aGUgQ2xpZW50IFNIT1VMRCB2ZXJpZnkgdGhhdCBpdHMgY2xpZW50X2lkIGlzIHRoZSBDbGFpbSBWYWx1ZS5cbi8vXG4vLyBpZF90b2tlbiBDNTogVGhlIENsaWVudCBNVVNUIHZhbGlkYXRlIHRoZSBzaWduYXR1cmUgb2YgdGhlIElEIFRva2VuIGFjY29yZGluZyB0byBKV1MgW0pXU10gdXNpbmcgdGhlIGFsZ29yaXRobSBzcGVjaWZpZWQgaW4gdGhlXG4vLyBhbGcgSGVhZGVyIFBhcmFtZXRlciBvZiB0aGUgSk9TRSBIZWFkZXIuVGhlIENsaWVudCBNVVNUIHVzZSB0aGUga2V5cyBwcm92aWRlZCBieSB0aGUgSXNzdWVyLlxuLy9cbi8vIGlkX3Rva2VuIEM2OiBUaGUgYWxnIHZhbHVlIFNIT1VMRCBiZSBSUzI1Ni4gVmFsaWRhdGlvbiBvZiB0b2tlbnMgdXNpbmcgb3RoZXIgc2lnbmluZyBhbGdvcml0aG1zIGlzIGRlc2NyaWJlZCBpbiB0aGUgT3BlbklEIENvbm5lY3QgQ29yZSAxLjBcbi8vIFtPcGVuSUQuQ29yZV0gc3BlY2lmaWNhdGlvbi5cbi8vXG4vLyBpZF90b2tlbiBDNzogVGhlIGN1cnJlbnQgdGltZSBNVVNUIGJlIGJlZm9yZSB0aGUgdGltZSByZXByZXNlbnRlZCBieSB0aGUgZXhwIENsYWltIChwb3NzaWJseSBhbGxvd2luZyBmb3Igc29tZSBzbWFsbCBsZWV3YXkgdG8gYWNjb3VudFxuLy8gZm9yIGNsb2NrIHNrZXcpLlxuLy9cbi8vIGlkX3Rva2VuIEM4OiBUaGUgaWF0IENsYWltIGNhbiBiZSB1c2VkIHRvIHJlamVjdCB0b2tlbnMgdGhhdCB3ZXJlIGlzc3VlZCB0b28gZmFyIGF3YXkgZnJvbSB0aGUgY3VycmVudCB0aW1lLFxuLy8gbGltaXRpbmcgdGhlIGFtb3VudCBvZiB0aW1lIHRoYXQgbm9uY2VzIG5lZWQgdG8gYmUgc3RvcmVkIHRvIHByZXZlbnQgYXR0YWNrcy5UaGUgYWNjZXB0YWJsZSByYW5nZSBpcyBDbGllbnQgc3BlY2lmaWMuXG4vL1xuLy8gaWRfdG9rZW4gQzk6IFRoZSB2YWx1ZSBvZiB0aGUgbm9uY2UgQ2xhaW0gTVVTVCBiZSBjaGVja2VkIHRvIHZlcmlmeSB0aGF0IGl0IGlzIHRoZSBzYW1lIHZhbHVlIGFzIHRoZSBvbmUgdGhhdCB3YXMgc2VudFxuLy8gaW4gdGhlIEF1dGhlbnRpY2F0aW9uIFJlcXVlc3QuVGhlIENsaWVudCBTSE9VTEQgY2hlY2sgdGhlIG5vbmNlIHZhbHVlIGZvciByZXBsYXkgYXR0YWNrcy5UaGUgcHJlY2lzZSBtZXRob2QgZm9yIGRldGVjdGluZyByZXBsYXkgYXR0YWNrc1xuLy8gaXMgQ2xpZW50IHNwZWNpZmljLlxuLy9cbi8vIGlkX3Rva2VuIEMxMDogSWYgdGhlIGFjciBDbGFpbSB3YXMgcmVxdWVzdGVkLCB0aGUgQ2xpZW50IFNIT1VMRCBjaGVjayB0aGF0IHRoZSBhc3NlcnRlZCBDbGFpbSBWYWx1ZSBpcyBhcHByb3ByaWF0ZS5cbi8vIFRoZSBtZWFuaW5nIGFuZCBwcm9jZXNzaW5nIG9mIGFjciBDbGFpbSBWYWx1ZXMgaXMgb3V0IG9mIHNjb3BlIGZvciB0aGlzIGRvY3VtZW50LlxuLy9cbi8vIGlkX3Rva2VuIEMxMTogV2hlbiBhIG1heF9hZ2UgcmVxdWVzdCBpcyBtYWRlLCB0aGUgQ2xpZW50IFNIT1VMRCBjaGVjayB0aGUgYXV0aF90aW1lIENsYWltIHZh