Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minimal idx factory for SIW gen3 (v2) #1476

Merged
merged 20 commits into from
Dec 4, 2023
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/core/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
* See the License for the specific language governing permissions and limitations under the License.
*/

import { createOAuthOptionsConstructor } from '../oidc';
import { createOAuthOptionsConstructor } from '../oidc/options';
import { AuthState, OktaAuthCoreInterface, OktaAuthCoreOptions, ServiceManagerOptions } from './types';


Expand Down
4 changes: 4 additions & 0 deletions lib/exports/cdn/idx-minimal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { OktaAuth } from '../idx-minimal';

// Export only a single object
export default OktaAuth;
43 changes: 43 additions & 0 deletions lib/exports/idx-minimal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import type {
OktaAuthOptionsConstructor,
} from '../base/types';

import {
IdxStorageManagerConstructor,
IdxTransactionManagerConstructor,
OktaAuthIdxOptions,
} from '../idx/types';
import { createIdxTransactionManager } from '../idx/IdxTransactionManager';
import { createMinimalOktaAuthIdx } from '../idx/factory/MinimalOktaAuthIdx';
import { createIdxStorageManager } from '../idx/storage';
import { createIdxOptionsConstructor } from '../idx/options';

const OptionsConstructor: OktaAuthOptionsConstructor<OktaAuthIdxOptions> = createIdxOptionsConstructor();
const StorageManager: IdxStorageManagerConstructor = createIdxStorageManager();
const TransactionManager: IdxTransactionManagerConstructor = createIdxTransactionManager();

const OktaAuthIdx = createMinimalOktaAuthIdx(StorageManager, OptionsConstructor, TransactionManager);

// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface OktaAuthOptions extends OktaAuthIdxOptions {}

class OktaAuth extends OktaAuthIdx {
constructor(options: OktaAuthOptions) {
super(options);
}
}

export default OktaAuth;
export { OktaAuth };

export * from '../base/types';
export * from '../constants';
export * from '../core/types';
export * from '../errors';
export * from '../http/types';
export * from '../oidc/types';
export * from '../session/types';
export * from '../storage/types';
export * from '../util/types';

export * from '../idx/types';
2 changes: 1 addition & 1 deletion lib/exports/idx.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {
OktaAuthOptionsConstructor,
} from '../base';
} from '../base/types';

import {
IdxStorageManagerConstructor,
Expand Down
37 changes: 37 additions & 0 deletions lib/idx/factory/MinimalOktaAuthIdx.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { OktaAuthOptionsConstructor } from '../../base/types';
import { StorageManagerConstructor } from '../../storage/types';
import { IdxTransactionManagerInterface, MinimalOktaAuthIdxInterface, OktaAuthIdxConstructor } from '../types/api';
import { IdxTransactionMeta } from '../types/meta';
import { IdxStorageManagerInterface } from '../types/storage';
import { OktaAuthIdxOptions } from '../types/options';
import { TransactionManagerConstructor, OktaAuthBaseOAuthInterface } from '../../oidc/types';
import { mixinMinimalIdx } from '../mixinMinimal';
import { createOktaAuthBase } from '../../base/factory';
import { mixinStorage } from '../../storage/mixin';
import { mixinHttp } from '../../http/mixin';
import { mixinSession } from '../../session/mixin';
import { mixinMinimalOAuth } from '../../oidc/mixin/minimal';

export function createMinimalOktaAuthIdx<
M extends IdxTransactionMeta = IdxTransactionMeta,
S extends IdxStorageManagerInterface<M> = IdxStorageManagerInterface<M>,
O extends OktaAuthIdxOptions = OktaAuthIdxOptions,
TM extends IdxTransactionManagerInterface = IdxTransactionManagerInterface
>(
StorageManagerConstructor: StorageManagerConstructor<S>,
OptionsConstructor: OktaAuthOptionsConstructor<O>,
TransactionManagerConstructor: TransactionManagerConstructor<TM>
)
: OktaAuthIdxConstructor<
MinimalOktaAuthIdxInterface<M, S, O, TM> & OktaAuthBaseOAuthInterface<M, S, O, TM>
>
{
const Base = createOktaAuthBase(OptionsConstructor);
const WithStorage = mixinStorage<S, O>(Base, StorageManagerConstructor);
const WithHttp = mixinHttp<S, O>(WithStorage);
const WithSession = mixinSession<S, O>(WithHttp);
const WithOAuth = mixinMinimalOAuth<M, S, O, TM>(WithSession, TransactionManagerConstructor);
// do not mixin core
const WithIdx = mixinMinimalIdx(WithOAuth);
return WithIdx;
}
7 changes: 7 additions & 0 deletions lib/idx/factory/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,16 @@ import {
} from '../transactionMeta';
import { FlowIdentifier, IdxAPI, OktaAuthIdxInterface } from '../types';
import { unlockAccount } from '../unlockAccount';
import * as remediators from '../remediators';
import { getFlowSpecification } from '../flow/FlowSpecification';
import { setRemediatorsCtx } from '../util';

// Factory
export function createIdxAPI(sdk: OktaAuthIdxInterface): IdxAPI {
setRemediatorsCtx({
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See setRemediatorsCtx in utils - https://github.com/okta/okta-auth-js/pull/1476/files#diff-71b56cc120e09a7c5f1d47c7637461aece91f39807b35359697038d48b38ddd3
This is needed for minimal IDX API to not import all remediators and flow specifications (except GenericRemediator).
By default remediatorsCtx has empty list of remediators

remediators,
getFlowSpecification,
});
const boundStartTransaction = startTransaction.bind(null, sdk);
const idx = {
interact: interact.bind(null, sdk),
Expand Down
1 change: 1 addition & 0 deletions lib/idx/factory/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './api';
export * from './OktaAuthIdx';
export * from './MinimalOktaAuthIdx';
47 changes: 47 additions & 0 deletions lib/idx/factory/minimalApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*!
* Copyright (c) 2015-present, Okta, Inc. and/or its affiliates. All rights reserved.
* The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
*
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and limitations under the License.
*
*/

import { makeIdxState } from '../idxState';
import { canProceed, proceed } from '../proceed';
import { startTransaction } from '../startTransaction';
import {
clearTransactionMeta,
createTransactionMeta,
getSavedTransactionMeta,
getTransactionMeta,
isTransactionMetaValid,
saveTransactionMeta
} from '../transactionMeta';
import { MinimalIdxAPI, MinimalOktaAuthIdxInterface } from '../types';

// Factory
export function createMinimalIdxAPI(sdk: MinimalOktaAuthIdxInterface): MinimalIdxAPI {
const boundStartTransaction = startTransaction.bind(null, sdk);
const idx = {
makeIdxResponse: makeIdxState.bind(null, sdk),

start: boundStartTransaction,
startTransaction: boundStartTransaction, // Use `start` instead. `startTransaction` will be removed in 7.0
proceed: proceed.bind(null, sdk),
canProceed: canProceed.bind(null, sdk),

getSavedTransactionMeta: getSavedTransactionMeta.bind(null, sdk),
createTransactionMeta: createTransactionMeta.bind(null, sdk),
getTransactionMeta: getTransactionMeta.bind(null, sdk),
saveTransactionMeta: saveTransactionMeta.bind(null, sdk),
clearTransactionMeta: clearTransactionMeta.bind(null, sdk),
isTransactionMetaValid,
};
return idx;
}

10 changes: 1 addition & 9 deletions lib/idx/flow/FlowSpecification.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
import { OktaAuthIdxInterface, FlowIdentifier } from '../types';
import { OktaAuthIdxInterface, FlowIdentifier, FlowSpecification } from '../types';
import { AuthenticationFlow } from './AuthenticationFlow';
import { PasswordRecoveryFlow } from './PasswordRecoveryFlow';
import { RegistrationFlow } from './RegistrationFlow';
import { AccountUnlockFlow } from './AccountUnlockFlow';
import { RemediationFlow } from './RemediationFlow';

export interface FlowSpecification {
flow: FlowIdentifier;
remediators: RemediationFlow;
actions?: string[];
withCredentials?: boolean;
}

// eslint-disable-next-line complexity
export function getFlowSpecification(
Expand Down
4 changes: 2 additions & 2 deletions lib/idx/idxState/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { OktaAuthIdxInterface } from '../types'; // auth-js/types
import { MinimalOktaAuthIdxInterface } from '../types'; // auth-js/types
import { IdxResponse, IdxToPersist, RawIdxResponse } from '../types/idx-js'; // idx/types
import { IDX_API_VERSION } from '../../constants';
import v1 from './v1/parsers';
Expand Down Expand Up @@ -30,7 +30,7 @@ export function validateVersionConfig(version) {
}

export function makeIdxState (
authClient: OktaAuthIdxInterface,
authClient: MinimalOktaAuthIdxInterface,
rawIdxResponse: RawIdxResponse,
toPersist: IdxToPersist,
requestDidSucceed: boolean,
Expand Down
6 changes: 3 additions & 3 deletions lib/idx/idxState/v1/generateIdxAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@

/* eslint-disable max-len, complexity */
import { httpRequest } from '../../../http';
import { OktaAuthIdxInterface } from '../../types'; // auth-js/types
import { MinimalOktaAuthIdxInterface } from '../../types'; // auth-js/types
import { IdxActionFunction, IdxActionParams, IdxResponse, IdxToPersist } from '../../types/idx-js';
import { divideActionParamsByMutability } from './actionParser';
import AuthApiError from '../../../errors/AuthApiError';

const generateDirectFetch = function generateDirectFetch(authClient: OktaAuthIdxInterface, {
const generateDirectFetch = function generateDirectFetch(authClient: MinimalOktaAuthIdxInterface, {
actionDefinition,
defaultParamsForAction = {},
immutableParamsForAction = {},
Expand Down Expand Up @@ -86,7 +86,7 @@ const generateDirectFetch = function generateDirectFetch(authClient: OktaAuthIdx
// };
// };

const generateIdxAction = function generateIdxAction( authClient: OktaAuthIdxInterface, actionDefinition, toPersist ): IdxActionFunction {
const generateIdxAction = function generateIdxAction( authClient: MinimalOktaAuthIdxInterface, actionDefinition, toPersist ): IdxActionFunction {
// TODO: leaving this here to see where the polling is EXPECTED to drop into the code, but removing any accidental trigger of incomplete code
// const generator = actionDefinition.refresh ? generatePollingFetch : generateDirectFetch;
const generator = generateDirectFetch;
Expand Down
26 changes: 14 additions & 12 deletions lib/idx/idxState/v1/idxResponseParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,22 @@
*/

/* eslint-disable max-len */
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed @ts-nocheck in lib/idx/idxState/v1/*

import { OktaAuthIdxInterface } from '../../types'; // auth-js/types

import { MinimalOktaAuthIdxInterface, IdxResponse, IdxRemediation, IdxContext } from '../../types'; // auth-js/types
import { IdxActions } from '../../types/idx-js';
import { generateRemediationFunctions } from './remediationParser';
import generateIdxAction from './generateIdxAction';
import { jsonpath } from '../../../util/jsonpath';
import { AuthSdkError } from '../../../errors';

const SKIP_FIELDS = Object.fromEntries([
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using Object.fromEntries causes TS error:
Property 'fromEntries' does not exist on type 'ObjectConstructor'. Do you need to change your target library? Try changing the 'lib' compiler option to 'es2019' or later.
Changing lib in tsconfig doesn't help, so refactored code to not use fromEntries

'remediation', // remediations are put into proceed/neededToProceed
'context', // the API response of 'context' isn't externally useful. We ignore it and put all non-action (contextual) info into idxState.context
].map( (field) => [ field, !!'skip this field' ] ));
const SKIP_FIELDS = {
'remediation': true, // remediations are put into proceed/neededToProceed
'context': true, // the API response of 'context' isn't externally useful. We ignore it and put all non-action (contextual) info into idxState.context
};

export const parseNonRemediations = function parseNonRemediations( authClient: OktaAuthIdxInterface, idxResponse, toPersist = {} ) {
export const parseNonRemediations = function parseNonRemediations( authClient: MinimalOktaAuthIdxInterface, idxResponse: IdxResponse, toPersist = {} ) {
const actions = {};
const context = {};
const context = {} as IdxContext;

Object.keys(idxResponse)
.filter( field => !SKIP_FIELDS[field])
Expand Down Expand Up @@ -56,10 +56,12 @@ export const parseNonRemediations = function parseNonRemediations( authClient: O

// We are an object field containing an object value
context[field].value = {};
Object.entries(fieldValue)
Object.entries<IdxRemediation>(fieldValue)
.forEach( ([subField, value]) => {
if (value.rel) { // is [field].value[subField] an action?
// add any "action" value subfields to actions
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the TS error being ignored here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error in subField.name: Property 'name' does not exist on type 'string'
Looks like a valid remark from TS linter, as Object.entries enumerates string-keyed properties.
subField.name looks wrong

actions[`${field}-${subField.name || subField}`] = generateIdxAction(authClient, value, toPersist);
} else {
// add non-action value subfields to context
Expand Down Expand Up @@ -91,7 +93,7 @@ const expandRelatesTo = (idxResponse, value) => {
});
};

const convertRemediationAction = (authClient: OktaAuthIdxInterface, remediation, toPersist) => {
const convertRemediationAction = (authClient: MinimalOktaAuthIdxInterface, remediation, toPersist) => {
// Only remediation that has `rel` field (indicator for form submission) can have http action
if (remediation.rel) {
const remediationActions = generateRemediationFunctions( authClient, [remediation], toPersist );
Expand All @@ -105,7 +107,7 @@ const convertRemediationAction = (authClient: OktaAuthIdxInterface, remediation,
return remediation;
};

export const parseIdxResponse = function parseIdxResponse( authClient: OktaAuthIdxInterface, idxResponse, toPersist = {} ): {
export const parseIdxResponse = function parseIdxResponse( authClient: MinimalOktaAuthIdxInterface, idxResponse, toPersist = {} ): {
remediations: IdxRemediation[];
context: IdxContext;
actions: IdxActions;
Expand Down
8 changes: 4 additions & 4 deletions lib/idx/idxState/v1/makeIdxState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@
* See the License for the specific language governing permissions and limitations under the License.
*/

import { IdxResponse, IdxToPersist } from '../../types/idx-js';
import { OktaAuthIdxInterface, RawIdxResponse } from '../../types'; // auth-js/types
import { IdxResponse, IdxToPersist, IdxActionParams } from '../../types/idx-js';
import { MinimalOktaAuthIdxInterface, RawIdxResponse } from '../../types'; // auth-js/types
import { parseIdxResponse } from './idxResponseParser';

export function makeIdxState(
authClient: OktaAuthIdxInterface,
authClient: MinimalOktaAuthIdxInterface,
idxResponse: RawIdxResponse,
toPersist: IdxToPersist,
requestDidSucceed: boolean
Expand All @@ -41,7 +41,7 @@ export function makeIdxState(
return Promise.reject(`Current remediation cannot make form submit action: [${remediationChoice}]`);
}

return remediationChoiceObject.action(paramsFromUser);
return remediationChoiceObject.action!(paramsFromUser as IdxActionParams);
};

const findCode = item => item.name === 'interaction_code';
Expand Down
2 changes: 0 additions & 2 deletions lib/idx/idxState/v1/parsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
* See the License for the specific language governing permissions and limitations under the License.
*/

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
import { makeIdxState } from './makeIdxState';

export default {
Expand Down
18 changes: 7 additions & 11 deletions lib/idx/idxState/v1/remediationParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,16 @@
* See the License for the specific language governing permissions and limitations under the License.
*/

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
import { OktaAuthIdxInterface } from '../../types'; // auth-js/types
import { MinimalOktaAuthIdxInterface, IdxRemediation } from '../../types'; // auth-js/types
import generateIdxAction from './generateIdxAction';

export const generateRemediationFunctions = function generateRemediationFunctions(
authClient: OktaAuthIdxInterface,
remediationValue,
authClient: MinimalOktaAuthIdxInterface,
remediationValue: IdxRemediation[],
toPersist = {}
) {
return Object.fromEntries( remediationValue.map( remediation => {
return [
remediation.name,
generateIdxAction(authClient, remediation, toPersist),
];
}) );
return remediationValue.reduce((obj, remediation) => ({
...obj,
[remediation.name]: generateIdxAction(authClient, remediation, toPersist)
}), {});
};
2 changes: 1 addition & 1 deletion lib/idx/interact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
/* eslint complexity:[0,8] */
import { OktaAuthIdxInterface, IdxTransactionMeta, InteractOptions, InteractResponse } from './types';
import { getSavedTransactionMeta, saveTransactionMeta, createTransactionMeta } from './transactionMeta';
import { getOAuthBaseUrl } from '../oidc';
import { getOAuthBaseUrl } from '../oidc/util';
import { removeNils } from '../util';
import { httpRequest } from '../http';

Expand Down
2 changes: 1 addition & 1 deletion lib/idx/introspect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import { makeIdxState, validateVersionConfig } from './idxState';
import { IntrospectOptions, OktaAuthIdxInterface } from './types';
import { IdxResponse, isRawIdxResponse } from './types/idx-js';
import { getOAuthDomain } from '../oidc';
import { getOAuthDomain } from '../oidc/util';
import { IDX_API_VERSION } from '../constants';
import { httpRequest } from '../http';
import { isAuthApiError } from '../errors';
Expand Down
Loading