Refactor: Address PR Comments

Create a new `OAuthState` type for storing the fields we want in the
`state` parameter.

Update the `encodeState` and `readState` fns to use the new `OAuthState`
type.

Update tests to reflect the new type
This commit is contained in:
Govindarajan Nagarajan
2020-08-04 14:45:03 +02:00
parent 51fad03460
commit 2d20cf389c
5 changed files with 35 additions and 39 deletions
@@ -28,20 +28,6 @@ export class EnvironmentHandler implements AuthProviderRouteHandlers {
private readonly envIdentifier: (req: express.Request) => string,
) {}
/* Return the value of `env` key, if it is exists, encoded within
the `state` parameter in the request
*/
private getEnv(stateParams: Array<string>): string {
const envParams = stateParams.filter(
param => param.split('=')[0] === 'env',
);
if (envParams.length > 0) {
return envParams[0].split('=')[1];
}
return '';
}
private getProviderForEnv(
req: express.Request,
res: express.Response,
+21 -20
View File
@@ -22,6 +22,7 @@ import {
OAuthProviderHandlers,
WebMessageResponse,
BackstageIdentity,
OAuthState,
} from '../providers/types';
import { InputError } from '@backstage/backend-common';
import { TokenIssuer } from '../identity';
@@ -39,27 +40,26 @@ export type Options = {
tokenIssuer: TokenIssuer;
};
/* Return the value of `env` key, if it is exists, encoded within
the `state` parameter in the request
*/
const readStateParameter = (
stateParams: Array<string>,
parameter: string,
): string => {
const envParams = stateParams.filter(
param => param.split('=')[0] === parameter,
);
if (envParams.length > 0) {
return envParams[0].split('=')[1];
const readState = (stateString: string): OAuthState => {
try {
const state = JSON.parse(decodeURIComponent(stateString));
return {
nonce: state.nonce,
env: state.env,
};
} catch (e) {
return {
nonce: undefined,
env: undefined,
};
}
return '';
};
const readState = (stateString: string): Array<string> => {
return decodeURIComponent(stateString).split('&');
export const encodeState = (state: OAuthState): string => {
return encodeURIComponent(JSON.stringify(state));
};
/*
export const encodeState = (stateObject: object): string => {
const vals = Object.keys(stateObject).map(
key =>
@@ -70,10 +70,11 @@ export const encodeState = (stateObject: object): string => {
return vals.join('&');
};
*/
export const verifyNonce = (req: express.Request, providerId: string) => {
const cookieNonce = req.cookies[`${providerId}-nonce`];
const state: Array<string> = readState(req.query.state?.toString() ?? '');
const stateNonce = readStateParameter(state, 'nonce');
const state: OAuthState = readState(req.query.state?.toString() ?? '');
const stateNonce = state.nonce;
if (!cookieNonce) {
throw new Error('Auth response is missing cookie nonce');
@@ -269,8 +270,8 @@ export class OAuthProvider implements AuthProviderRouteHandlers {
if (!stateParams) {
return '';
}
const env = readStateParameter(readState(stateParams), 'env');
return env;
const env = readState(stateParams).env;
return env ?? '';
}
/**
@@ -55,19 +55,21 @@ export const createAuthProviderRouter = (
const router = Router();
const envs = providerConfig.keys();
const envProviders: EnvironmentHandlers = {};
let envIdentifier: (req: express.Request) => string;
let envIdentifier: ((req: express.Request) => string) | undefined;
for (const env of envs) {
const envConfig = providerConfig.getConfig(env);
const provider = factory(globalConfig, env, envConfig, logger, issuer);
if (provider) {
envProviders[env] = provider;
if (envIdentifier === undefined) {
envIdentifier = provider.identifyEnv;
}
envIdentifier = provider.identifyEnv;
}
}
if (typeof envIdentifier === 'undefined') {
throw Error(`No envIdentifier provided for '${providerId}'`);
}
const handler = new EnvironmentHandler(
providerId,
envProviders,
@@ -107,7 +107,7 @@ export class SamlAuthProvider implements AuthProviderRouteHandlers {
res.send('noop');
}
identifyEnv(_req: express.Request): string {
identifyEnv(): string {
return '';
}
}
@@ -341,3 +341,10 @@ export type SAMLProviderConfig = {
export type SAMLEnvironmentProviderConfig = {
[key: string]: SAMLProviderConfig;
};
export type OAuthState = {
/* A type for the serialized value in the `state` parameter of the OAuth authorization flow
*/
nonce?: string;
env?: string;
};