Skip to content

Commit

Permalink
Merge pull request #167 from ThaminduDilshan/thamindu-002
Browse files Browse the repository at this point in the history
Removing Crypto Functionalities from Core JS Library and Provide as an Extension
  • Loading branch information
thivi authored Dec 17, 2021
2 parents 323410f + 9209a0c commit 913d215
Show file tree
Hide file tree
Showing 14 changed files with 4,548 additions and 23,489 deletions.
14,018 changes: 3,491 additions & 10,527 deletions lib/package-lock.json

Large diffs are not rendered by default.

10 changes: 0 additions & 10 deletions lib/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,6 @@
},
"author": "Asgardeo",
"license": "Apache-2.0",
"dependencies": {
"base64url": "^3.0.1",
"fast-sha256": "^1.3.0",
"jose": "^3.1.2",
"randombytes": "^2.1.0"
},
"peerDependencies": {
"@babel/runtime-corejs3": "^7.11.2",
"axios": "^0.21.0"
Expand All @@ -52,14 +46,10 @@
"@rollup/plugin-eslint": "^8.0.0",
"@rollup/plugin-node-resolve": "^10.0.0",
"@rollup/plugin-replace": "^2.3.4",
"@types/base64url": "^2.0.0",
"@types/crypto-js": "^3.1.43",
"@types/node": "^13.9.2",
"@types/randombytes": "^2.0.0",
"axios": "^0.21.0",
"core-js": "^3.6.5",
"cross-env": "^7.0.2",
"crypto-js": "^3.1.9-1",
"rimraf": "^3.0.2",
"rollup": "^2.33.3",
"rollup-plugin-analyzer": "^3.3.0",
Expand Down
2 changes: 2 additions & 0 deletions lib/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { DEFAULT_EXTENSIONS } from "@babel/core";
import babel from "@rollup/plugin-babel";
import commonjs from "@rollup/plugin-commonjs";
import eslint from "@rollup/plugin-eslint";
import json from "@rollup/plugin-json";
import resolve from "@rollup/plugin-node-resolve";
import replace from "@rollup/plugin-replace";
import analyze from "rollup-plugin-analyzer";
Expand Down Expand Up @@ -159,6 +160,7 @@ const generateConfig = (bundleType, polyfill, env) => {
}),
commonjs(),
eslint(),
json(),
typescript(),
replace({
"process.env.NODE_ENV": env === PRODUCTION
Expand Down
5 changes: 3 additions & 2 deletions lib/src/authentication-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { DataLayer } from "./data";
import {
AuthClientConfig,
BasicUserInfo,
CryptoUtils,
CustomGrantConfig,
DecodedIDTokenPayload,
GetAuthURLConfig,
Expand Down Expand Up @@ -74,14 +75,14 @@ export class AsgardeoAuthClient<T> {
* @link https://github.com/asgardeo/asgardeo-auth-js-sdk/tree/master#constructor
* @preserve
*/
public constructor(store: Store) {
public constructor(store: Store, cryptoUtils: CryptoUtils) {
if (!AsgardeoAuthClient._instanceID) {
AsgardeoAuthClient._instanceID = 0;
} else {
AsgardeoAuthClient._instanceID += 1;
}
this._dataLayer = new DataLayer<T>(`instance_${AsgardeoAuthClient._instanceID}`, store);
this._authenticationCore = new AuthenticationCore(this._dataLayer);
this._authenticationCore = new AuthenticationCore(this._dataLayer, cryptoUtils);
}

/**
Expand Down
4 changes: 4 additions & 0 deletions lib/src/constants/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,7 @@ export enum Stores {

export const REFRESH_TOKEN_TIMER = "refresh_token_timer";
export const PKCE_CODE_VERIFIER = "pkce_code_verifier";

export const SUPPORTED_SIGNATURE_ALGORITHMS = [
"RS256", "RS512", "RS384", "PS256"
];
1 change: 0 additions & 1 deletion lib/src/constants/environments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,3 @@
*/

export const REACT_NATIVE = "react-native";

19 changes: 12 additions & 7 deletions lib/src/core/authentication-core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,25 +32,28 @@ import {
AuthClientConfig,
AuthorizationURLParams,
BasicUserInfo,
CryptoUtils,
CustomGrantConfig,
DecodedIDTokenPayload,
OIDCEndpoints,
OIDCProviderMetaData,
TokenResponse
} from "../models";
import { AuthenticationUtils, CryptoUtils } from "../utils";
import { AuthenticationUtils } from "../utils";

export class AuthenticationCore<T> {
private _dataLayer: DataLayer<T>;
private _config: () => Promise<AuthClientConfig>;
private _oidcProviderMetaData: () => Promise<OIDCProviderMetaData>;
private _authenticationHelper: AuthenticationHelper<T>;
private _cryptoUtils: CryptoUtils;

public constructor(dataLayer: DataLayer<T>) {
this._authenticationHelper = new AuthenticationHelper(dataLayer);
public constructor(dataLayer: DataLayer<T>, cryptoUtils: CryptoUtils) {
this._authenticationHelper = new AuthenticationHelper(dataLayer, cryptoUtils);
this._dataLayer = dataLayer;
this._config = async () => await this._dataLayer.getConfigData();
this._oidcProviderMetaData = async () => await this._dataLayer.getOIDCProviderMetaData();
this._cryptoUtils = cryptoUtils;
}

public async getAuthorizationURL(config?: AuthorizationURLParams): Promise<string> {
Expand Down Expand Up @@ -93,8 +96,8 @@ export class AuthenticationCore<T> {
}

if (configData.enablePKCE) {
const codeVerifier = CryptoUtils.getCodeVerifier();
const codeChallenge = CryptoUtils.getCodeChallenge(codeVerifier);
const codeVerifier = this._cryptoUtils?.getCodeVerifier();
const codeChallenge = this._cryptoUtils?.getCodeChallenge(codeVerifier);
await this._dataLayer.setTemporaryDataParameter(PKCE_CODE_VERIFIER, codeVerifier);
authorizeRequest.searchParams.append("code_challenge_method", "S256");
authorizeRequest.searchParams.append("code_challenge", codeChallenge);
Expand Down Expand Up @@ -439,7 +442,9 @@ export class AuthenticationCore<T> {

public async getBasicUserInfo(): Promise<BasicUserInfo> {
const sessionData = await this._dataLayer.getSessionData();
const authenticatedUser = AuthenticationUtils.getAuthenticatedUserInfo(sessionData?.id_token);
const authenticatedUser = this._authenticationHelper.getAuthenticatedUserInfo(
sessionData?.id_token
);

let basicUserInfo: BasicUserInfo = {
allowedScopes: sessionData.scope,
Expand All @@ -462,7 +467,7 @@ export class AuthenticationCore<T> {

public async getDecodedIDToken(): Promise<DecodedIDTokenPayload> {
const idToken = (await this._dataLayer.getSessionData()).id_token;
const payload: DecodedIDTokenPayload = CryptoUtils.decodeIDToken(idToken);
const payload: DecodedIDTokenPayload = this._cryptoUtils.decodeIDToken(idToken);

return payload;
}
Expand Down
54 changes: 45 additions & 9 deletions lib/src/helpers/authentication-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
* under the License.
*/

import { KeyLike } from "crypto";
import axios, { AxiosError, AxiosResponse } from "axios";
import {
AUTHORIZATION_ENDPOINT,
Expand All @@ -35,18 +34,28 @@ import {
} from "../constants";
import { DataLayer } from "../data";
import { AsgardeoAuthException, AsgardeoAuthNetworkException } from "../exception";
import { AuthClientConfig, OIDCEndpointsInternal, OIDCProviderMetaData, TokenResponse } from "../models";
import { AuthenticationUtils, CryptoUtils } from "../utils";
import {
AuthClientConfig,
AuthenticatedUserInfo,
CryptoUtils,
DecodedIDTokenPayload,
OIDCEndpointsInternal,
OIDCProviderMetaData,
TokenResponse
} from "../models";
import { AuthenticationUtils } from "../utils";

export class AuthenticationHelper<T> {
private _dataLayer: DataLayer<T>;
private _config: () => Promise<AuthClientConfig>;
private _oidcProviderMetaData: () => Promise<OIDCProviderMetaData>;
private _cryptoUtils: CryptoUtils;

public constructor(dataLayer: DataLayer<T>) {
public constructor(dataLayer: DataLayer<T>, cryptoUtils: CryptoUtils) {
this._dataLayer = dataLayer;
this._config = async () => await this._dataLayer.getConfigData();
this._oidcProviderMetaData = async () => await this._dataLayer.getOIDCProviderMetaData();
this._cryptoUtils = cryptoUtils;
}

public async resolveWellKnownEndpoint(): Promise<string> {
Expand Down Expand Up @@ -142,14 +151,14 @@ export class AuthenticationHelper<T> {
return Promise.resolve(false);
}

return CryptoUtils.getJWKForTheIdToken(idToken.split(".")[0], response.data.keys)
.then(async (jwk: KeyLike) => {
return CryptoUtils.isValidIdToken(
return this._cryptoUtils.getJWKForTheIdToken(idToken.split(".")[0], response.data.keys)
.then(async (jwk: any) => {
return this._cryptoUtils.isValidIdToken(
idToken,
jwk,
(await this._config()).clientID,
issuer,
CryptoUtils.decodeIDToken(idToken).sub,
this._cryptoUtils.decodeIDToken(idToken).sub,
(await this._config()).clockTolerance
)
.then((response) => response)
Expand Down Expand Up @@ -196,6 +205,30 @@ export class AuthenticationHelper<T> {
});
}

public getAuthenticatedUserInfo(idToken: string): AuthenticatedUserInfo {
const payload: DecodedIDTokenPayload = this._cryptoUtils.decodeIDToken(idToken);
const tenantDomain: string = AuthenticationUtils.getTenantDomainFromIdTokenPayload(payload);
const username: string = payload?.username ?? "";
const givenName: string = payload.given_name ?? "";
const familyName: string = payload.family_name ?? "";
const fullName: string =
givenName && familyName
? `${givenName} ${familyName}`
: givenName
? givenName
: familyName
? familyName
: "";
const displayName: string = payload.preferred_username ?? fullName;

return {
displayName: displayName,
tenantDomain,
username: username,
...AuthenticationUtils.filterClaimsFromIDTokenPayload(payload)
};
}

public async replaceCustomGrantTemplateTags(text: string): Promise<string> {
let scope = OIDC_SCOPE;
const configData = await this._config();
Expand All @@ -210,7 +243,10 @@ export class AuthenticationHelper<T> {

return text
.replace(TOKEN_TAG, sessionData.access_token)
.replace(USERNAME_TAG, AuthenticationUtils.getAuthenticatedUserInfo(sessionData.id_token).username)
.replace(
USERNAME_TAG,
this.getAuthenticatedUserInfo(sessionData.id_token).username
)
.replace(SCOPE_TAG, scope)
.replace(CLIENT_ID_TAG, configData.clientID)
.replace(CLIENT_SECRET_TAG, configData.clientSecret ?? "");
Expand Down
17 changes: 17 additions & 0 deletions lib/src/models/crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
* under the License.
*/

import { DecodedIDTokenPayload } from ".";

/**
* JWK Model
*/
Expand All @@ -27,3 +29,18 @@ export interface JWKInterface {
alg: string;
n: string;
}

export interface CryptoUtils {
getCodeVerifier(): string;
getCodeChallenge(verifier: string): string;
getJWKForTheIdToken(jwtHeader: string, keys: JWKInterface[]): Promise<any>;
isValidIdToken(
idToken: string,
jwk: any,
clientID: string,
issuer: string,
username: string,
clockTolerance: number | undefined
): Promise<boolean>;
decodeIDToken(idToken: string): DecodedIDTokenPayload;
}
29 changes: 2 additions & 27 deletions lib/src/utils/authentication-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,38 +16,13 @@
* under the License.
*/

import { CryptoUtils } from "./crypto-utils";
import { AuthenticatedUserInfo, DecodedIDTokenPayload, TokenRequestHeader } from "../models";
import { DecodedIDTokenPayload, TokenRequestHeader } from "../models";

export class AuthenticationUtils {
// eslint-disable-next-line @typescript-eslint/no-empty-function
private constructor() {}

public static getAuthenticatedUserInfo(idToken: string): AuthenticatedUserInfo {
const payload: DecodedIDTokenPayload = CryptoUtils.decodeIDToken(idToken);
const tenantDomain: string = this.getTenantDomainFromIdTokenPayload(payload);
const username: string = payload?.username ?? "";
const givenName: string = payload.given_name ?? "";
const familyName: string = payload.family_name ?? "";
const fullName: string =
givenName && familyName
? `${givenName} ${familyName}`
: givenName
? givenName
: familyName
? familyName
: "";
const displayName: string = payload.preferred_username ?? fullName;

return {
displayName: displayName,
tenantDomain,
username: username,
...this.filterClaimsFromIDTokenPayload(payload)
};
}

private static filterClaimsFromIDTokenPayload(payload: DecodedIDTokenPayload) {
public static filterClaimsFromIDTokenPayload(payload: DecodedIDTokenPayload): any {
const optionalizedPayload: Partial<DecodedIDTokenPayload> = { ...payload };

delete optionalizedPayload?.iss;
Expand Down
Loading

0 comments on commit 913d215

Please sign in to comment.