File tree 4 files changed +54
-3
lines changed
4 files changed +54
-3
lines changed Original file line number Diff line number Diff line change
1
+ ---
2
+ " @guardian/cdk " : patch
3
+ ---
4
+
5
+ Limit the length of the cognito user pool domainPrefix generated by the Ec2App googleAuth functionality to 63 characters
Original file line number Diff line number Diff line change 1
1
/* eslint "@guardian/tsdoc-required/tsdoc-required": 2 -- to begin rolling this out for public APIs. */
2
- import crypto from "crypto" ;
3
2
import { Duration , SecretValue , Tags } from "aws-cdk-lib" ;
4
3
import type { BlockDevice } from "aws-cdk-lib/aws-autoscaling" ;
5
4
import { HealthCheck } from "aws-cdk-lib/aws-autoscaling" ;
@@ -43,6 +42,7 @@ import {
43
42
import { AppAccess } from "../../types" ;
44
43
import type { GuAsgCapacity , GuDomainName } from "../../types" ;
45
44
import type { AmigoProps } from "../../types/amigo" ;
45
+ import { getUserPoolDomainPrefix } from "../../utils/cognito/cognito" ;
46
46
47
47
export interface AccessLoggingProps {
48
48
/**
@@ -573,11 +573,10 @@ export class GuEc2App extends Construct {
573
573
// These help ensure domain is deterministic but also unique. Key
574
574
// assumption is that app/stack/stage combo are unique within Guardian.
575
575
const domainPrefix = `com-gu-${ app . toLowerCase ( ) } -${ scope . stage . toLowerCase ( ) } ` ;
576
- const suffix = crypto . createHash ( "md5" ) . update ( domainPrefix ) . digest ( "hex" ) ;
577
576
578
577
const userPoolDomain = userPool . addDomain ( "domain" , {
579
578
cognitoDomain : {
580
- domainPrefix : ` ${ domainPrefix } - ${ suffix } ` ,
579
+ domainPrefix : getUserPoolDomainPrefix ( domainPrefix ) ,
581
580
} ,
582
581
} ) ;
583
582
Original file line number Diff line number Diff line change
1
+ import { getUserPoolDomainPrefix } from "./cognito" ;
2
+
3
+ describe ( "getUserPoolDomainPrefix" , ( ) => {
4
+ it ( "should use a full length hash where there is space" , ( ) => {
5
+ const shortPrefix = "hello" ;
6
+ const domainPrefix = getUserPoolDomainPrefix ( shortPrefix ) ;
7
+
8
+ expect ( domainPrefix . length ) . toEqual ( 32 + shortPrefix . length + 1 ) ;
9
+ } ) ;
10
+
11
+ it ( "should include the full prefix where there is space for a 5 character hash" , ( ) => {
12
+ const prefix55 = new Array ( 55 + 1 ) . join ( "#" ) ;
13
+ const domainPrefix = getUserPoolDomainPrefix ( prefix55 ) ;
14
+
15
+ expect ( domainPrefix . includes ( prefix55 ) ) . toEqual ( true ) ;
16
+ expect ( domainPrefix . length ) . toEqual ( 63 ) ;
17
+ } ) ;
18
+
19
+ it ( "should not include the full prefix where there is not space for a 5 character hash" , ( ) => {
20
+ const prefix56 = new Array ( 58 + 1 ) . join ( "#" ) ;
21
+ const domainPrefix = getUserPoolDomainPrefix ( prefix56 ) ;
22
+
23
+ expect ( domainPrefix . includes ( prefix56 ) ) . toEqual ( false ) ;
24
+ expect ( domainPrefix . length ) . toEqual ( 63 ) ;
25
+ } ) ;
26
+
27
+ it ( "should be 63 characters long even with a very long prefix" , ( ) => {
28
+ const prefix = new Array ( 63 + 1 ) . join ( "#" ) ;
29
+ const domainPrefix = getUserPoolDomainPrefix ( prefix ) ;
30
+
31
+ expect ( domainPrefix . length ) . toEqual ( 63 ) ;
32
+ } ) ;
33
+ } ) ;
Original file line number Diff line number Diff line change
1
+ import crypto from "crypto" ;
2
+
3
+ export const getUserPoolDomainPrefix = ( prefix : string ) : string => {
4
+ // the user pool domain prefix has a max length of 63 characters. We want them to be unique so we add a hash to the end
5
+ // here we hope that a 5 character hash is unique enough to avoid collisions
6
+ const maxLength = 63 ;
7
+ const prefixLengthWithHashSpace = maxLength - 6 ; // 6 = 5 char hash, 1 hyphen
8
+ const suffix = crypto . createHash ( "md5" ) . update ( prefix ) . digest ( "hex" ) ;
9
+
10
+ // make space in prefix for hash
11
+ const prefixTrimmed = prefix . slice ( 0 , prefixLengthWithHashSpace ) ;
12
+
13
+ return `${ prefixTrimmed } -${ suffix } ` . slice ( 0 , maxLength ) ;
14
+ } ;
You can’t perform that action at this time.
0 commit comments