Skip to content

Commit

Permalink
807: Authentication for UI in production mode (#851)
Browse files Browse the repository at this point in the history
* Reinstate auth stack in CDK app, but without Azure as IdP
* Add login to UI in prod mode only
* Add authentication header to UI requests in prod mode only
  • Loading branch information
chriswilty committed Mar 19, 2024
1 parent db73732 commit 67883c7
Show file tree
Hide file tree
Showing 20 changed files with 4,862 additions and 1,131 deletions.
7 changes: 2 additions & 5 deletions cloud/bin/cloud.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
resourceDescription,
stackName,
ApiStack,
AuthStack,
UiStack,
} from '../lib';

Expand All @@ -23,7 +24,6 @@ const tags = {
classification: 'unrestricted',
'environment-type': environmentName(app),
'keep-alive': '8-6-without-weekends',
IaC: 'CDK',
};

const generateStackName = stackName(app);
Expand All @@ -35,15 +35,12 @@ const uiStack = new UiStack(app, generateStackName('ui'), {
tags,
});

// Don't need this stack yet.
/*
const authStack = new AuthStack(app, generateStackName('auth'), {
/*const authStack = */ new AuthStack(app, generateStackName('auth'), {
description: generateDescription('Auth stack'),
env,
tags,
webappUrl: uiStack.cloudfrontUrl,
});
*/

new ApiStack(app, generateStackName('api'), {
description: generateDescription('API stack'),
Expand Down
8 changes: 4 additions & 4 deletions cloud/cdk.context.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"availability-zones:account=600982866784:region=eu-west-1": [
"eu-west-1a",
"eu-west-1b",
"eu-west-1c"
"availability-zones:account=992382568770:region=eu-north-1": [
"eu-north-1a",
"eu-north-1b",
"eu-north-1c"
]
}
63 changes: 19 additions & 44 deletions cloud/lib/auth-stack.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import {
AdvancedSecurityMode,
Mfa,
OAuthScope,
ProviderAttribute,
UserPool,
UserPoolClient,
UserPoolClientIdentityProvider,
UserPoolDomain,
UserPoolIdentityProviderSaml,
UserPoolIdentityProviderSamlMetadata,
} from 'aws-cdk-lib/aws-cognito';
import { CfnOutput, Duration, Stack, StackProps, Tags } from 'aws-cdk-lib/core';
import {
CfnOutput,
Duration,
RemovalPolicy,
Stack,
StackProps,
Tags,
} from 'aws-cdk-lib/core';
import { Construct } from 'constructs';

import { resourceName } from './resourceNamingUtils';
Expand All @@ -26,14 +30,6 @@ export class AuthStack extends Stack {
constructor(scope: Construct, id: string, props: AuthStackProps) {
super(scope, id, props);

const azureTenantId = process.env.AZURE_TENANT_ID;
const azureApplicationId = process.env.AZURE_APPLICATION_ID;
if (!azureTenantId || !azureApplicationId) {
throw new Error(
'Need AZURE_TENANT_ID and AZURE_APPLICATION_ID environment vars!'
);
}

const generateResourceName = resourceName(scope);

// Cognito UserPool
Expand All @@ -42,7 +38,6 @@ export class AuthStack extends Stack {
userPoolName,
enableSmsRole: false,
mfa: Mfa.OFF,
//email // not configured, we're not going to send email from here
signInCaseSensitive: false,
autoVerify: { email: false }, // will be sending email invite anyway
selfSignUpEnabled: false, // only users we explicity allow
Expand All @@ -52,7 +47,16 @@ export class AuthStack extends Stack {
email: { required: true },
},
signInAliases: { email: true },
advancedSecurityMode: AdvancedSecurityMode.AUDIT,
passwordPolicy: {
minLength: 16,
requireSymbols: false,
requireLowercase: true,
requireUppercase: true,
requireDigits: true,
},
deletionProtection: false,
removalPolicy: RemovalPolicy.DESTROY,
});
// Tags not correctly assigned from parent stack: https://github.com/aws/aws-cdk/issues/14127
Object.entries(props.tags ?? {}).forEach(([key, value]) => {
Expand All @@ -62,30 +66,6 @@ export class AuthStack extends Stack {
new CfnOutput(this, 'UserPool.Identifier', {
value: `urn:amazon:cognito:sp:${this.userPool.userPoolId}`,
});
new CfnOutput(this, 'UserPool.ReplyUrl', {
value: `https://${userPoolName}.auth.${this.region}.amazoncognito.com/saml2/idpresponse`,
});

const idpName = generateResourceName('userpool-idp');
const identityProvider = new UserPoolIdentityProviderSaml(this, idpName, {
name: idpName,
idpSignout: true,
metadata: UserPoolIdentityProviderSamlMetadata.url(
`https://login.microsoftonline.com/${azureTenantId}/federationmetadata/2007-06/federationmetadata.xml?appid=${azureApplicationId}`
),
userPool: this.userPool,
attributeMapping: {
email: ProviderAttribute.other(
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name'
),
familyName: ProviderAttribute.other(
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname'
),
givenName: ProviderAttribute.other(
'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname'
),
},
});

const callbackUrls = [`${props.webappUrl}/`];
const userPoolClientName = generateResourceName('userpool-client');
Expand All @@ -94,10 +74,6 @@ export class AuthStack extends Stack {
authFlows: {
userSrp: true,
},
supportedIdentityProviders: [
UserPoolClientIdentityProvider.custom(identityProvider.providerName),
],
generateSecret: true,
oAuth: {
flows: {
authorizationCodeGrant: true,
Expand All @@ -108,8 +84,7 @@ export class AuthStack extends Stack {
},
accessTokenValidity: Duration.minutes(60),
idTokenValidity: Duration.minutes(60),
refreshTokenValidity: Duration.days(30),
authSessionValidity: Duration.minutes(3),
refreshTokenValidity: Duration.days(14),
enableTokenRevocation: true,
preventUserExistenceErrors: true,
});
Expand Down
1 change: 1 addition & 0 deletions frontend/.env.example
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
VITE_BACKEND_URL=http://localhost:3001/
VITE_COGNITO_REDIRECT_URL=http://localhost:4173/
3 changes: 3 additions & 0 deletions frontend/.stylelintrc.cjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
module.exports = {
extends: ['stylelint-config-standard', 'stylelint-config-hudochenkov/order'],
ignoreFiles: ['node_modules/**/*', 'dist/**/*'],
rules: {
'selector-class-pattern': null,
},
};
Loading

0 comments on commit 67883c7

Please sign in to comment.