UNPKG

angular-auth-oidc-client

Version:

An OpenID Connect Code Flow with PKCE,Implicit Flow client for Angular

674 lines 71.4 kB
/** * @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