Skip to content

Commit 765ecd7

Browse files
authored
feat: hash email and send it as a sub (#444)
* feat: hash email and send it as a sub * fix: remove legacy localdev terraform folder * fix: use a new claim to hold otp guid and use email as sub
1 parent f4e9ffb commit 765ecd7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+80
-2876
lines changed

.github/workflows/publish-otp-provider-image.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ jobs:
2727
CUSTOM_DOMAIN_NAME=otp-sandbox.loginproxy.gov.bc.ca
2828
CORS_ORIGINS=https://dev.sandbox.loginproxy.gov.bc.ca,https://test.sandbox.loginproxy.gov.bc.ca,https://sandbox.loginproxy.gov.bc.ca,https://sso-playground.apps.gold.devops.gov.bc.ca
2929
NODE_ENV=production
30+
HASH_SALT=${{ secrets.DEV_HASH_SALT }}
3031
3132
EOF
3233
- name: Checkout repository
@@ -77,6 +78,7 @@ jobs:
7778
app_env="${{ env.APP_ENV }}"
7879
node_env="${{ env.NODE_ENV }}"
7980
app_url="${{ env.APP_URL }}"
81+
hash_salt="${{ env.HASH_SALT }}"
8082
EOF
8183
8284
working-directory: ./docker/otp-provider/terraform

docker/otp-provider/.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ LOG_LEVEL=info
1414
COOKIE_SECRETS="s3cr3t1,s3cr3t1,s3cr3t2"
1515
JWKS=
1616
CORS_ORIGINS=*
17+
HASH_SALT=

docker/otp-provider/src/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,5 @@ export const config = {
2020
JWKS: process.env.JWKS ? JSON.parse(process.env.JWKS) : {},
2121
CORS_ORIGINS: process.env.CORS_ORIGINS || '',
2222
DB_CLEANUP_CRON: process.env.DB_CLEANUP_CRON || '0 1 * * *',
23+
HASH_SALT: process.env.HASH_SALT || '',
2324
};

docker/otp-provider/src/mailer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ const fetchChesToken = async () => {
4343
}
4444
};
4545

46-
export const sendEmail = async ({ from = 'bcgov.sso@gov.bc.ca', to, body, ...rest }: EmailOptions) => {
46+
export const sendEmail = async ({ from = 'no-reply-sso@gov.bc.ca', to, body, ...rest }: EmailOptions) => {
4747
try {
4848
const [accessToken, error] = await fetchChesToken();
4949
if (error) {

docker/otp-provider/src/server.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { createMigrator } from './modules/sequelize/umzug';
1313
import logger from './modules/winston.config';
1414
import SequelizeAdapter from './modules/sequelize/adapter';
1515
import Keygrip from 'keygrip';
16-
import { isOrigin } from './utils/helpers';
16+
import { isOrigin, hashEmail } from './utils/helpers';
1717
import * as crypto from 'crypto';
1818
import cron from 'node-cron';
1919
import { cleanupTables } from './modules/cron/cleanup';
@@ -70,6 +70,10 @@ app.disable('x-powered-by');
7070
const corsProp = 'allowedCorsOrigins';
7171

7272
const clientsConfig: Configuration = {
73+
claims: {
74+
openid: ['sub', 'otp_guid'],
75+
email: ['sub', 'otp_guid', 'email'],
76+
},
7377
pkce: {
7478
required: (ctx, client) => {
7579
// Require PKCE for all clients except those using 'none' client authentication
@@ -86,6 +90,7 @@ const clientsConfig: Configuration = {
8690
return true;
8791
},
8892
features: {
93+
claimsParameter: { enabled: true },
8994
revocation: { enabled: true },
9095
devInteractions: { enabled: false },
9196
introspection: { enabled: true },
@@ -165,12 +170,14 @@ const clientsConfig: Configuration = {
165170
InitialAccessToken: 300, // 5 minutes
166171
RegistrationAccessToken: 300, // 5 minutes
167172
},
168-
findAccount: async (ctx, incomingEmail) => {
173+
findAccount: async (ctx, sub) => {
169174
return {
170-
accountId: incomingEmail,
175+
accountId: sub,
171176
async claims() {
172177
return {
173-
sub: incomingEmail,
178+
sub,
179+
otp_guid: hashEmail(sub),
180+
email: sub,
174181
};
175182
},
176183
};

docker/otp-provider/src/utils/helpers.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import * as crypto from 'crypto';
2+
import { config } from '../config';
3+
4+
const { HASH_SALT } = config;
25

36
export const generateOtpWithExpiry = () => {
47
const otp = crypto.getRandomValues(new Uint32Array(1))[0].toString().slice(-6);
@@ -17,3 +20,9 @@ export const isOtpValid = (otp: string, expiresAt: Date): boolean => {
1720
export const isOrigin = (value: string) => {
1821
return typeof value === 'string' && URL.parse(value)?.origin === value;
1922
};
23+
24+
export const hashEmail = (email: string) => {
25+
const salt = Buffer.from(HASH_SALT);
26+
const combined = Buffer.concat([Buffer.from(email, 'utf8'), salt]);
27+
return crypto.createHash('sha256').update(combined).digest('hex');
28+
};

docker/otp-provider/terraform/.terraform.lock.hcl

Lines changed: 45 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docker/otp-provider/terraform/ecs.tf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,10 @@ resource "aws_ecs_task_definition" "this" {
137137
{
138138
name = "DB_CLEANUP_CRON",
139139
value = var.db_cleanup_cron
140+
},
141+
{
142+
name = "HASH_SALT",
143+
value = var.hash_salt
140144
}
141145
]
142146
secrets = [

docker/otp-provider/terraform/variables.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,3 +155,9 @@ variable "db_cleanup_cron" {
155155
type = string
156156
default = "0 1 * * *"
157157
}
158+
159+
variable "hash_salt" {
160+
description = "Salt used for hashing email"
161+
type = string
162+
default = ""
163+
}

localdev/terraform/.terraform.lock.hcl

Lines changed: 0 additions & 26 deletions
This file was deleted.

0 commit comments

Comments
 (0)