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

Enhance service account access token validation for improved security #1877

Merged
merged 6 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions .jenkins/projectBuilder.Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ projectBuilderV5 (
API_BASE_URL: '@vault(secret/configs/upgrade/${environment}/API_BASE_URL)',
BASE_HREF_PREFIX: '@vault(secret/configs/upgrade/${environment}/BASE_HREF_PREFIX)',
GOOGLE_CLIENT_ID: '@vault(secret/configs/upgrade/${environment}/GOOGLE_CLIENT_ID)',
GOOGLE_SERVICE_ACCOUNT_ID: '@vault(secret/configs/upgrade/${environment}/GOOGLE_SERVICE_ACCOUNT_ID)',
],
],
"scheduler-lambda": [
Expand Down
5 changes: 4 additions & 1 deletion backend/packages/Upgrade/.env.docker.local.example
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,12 @@ SWAGGER_API=**/controllers/*.ts
SWAGGER_JSON=/swagger.json

#
# Google Client Id
# Google Authentication Configuration
# Note: GOOGLE_CLIENT_ID and GOOGLE_SERVICE_ACCOUNT_ID can be a single ID or multiple comma-separated IDs (no spaces)
# Example: id1,id2,id3
#
GOOGLE_CLIENT_ID=google_project_id
zackcl marked this conversation as resolved.
Show resolved Hide resolved
GOOGLE_SERVICE_ACCOUNT_ID=google_service_account_id
DOMAIN_NAME=domain_name
SCHEDULER_STEP_FUNCTION=arn_name
AWS_REGION=aws-region
Expand Down
5 changes: 4 additions & 1 deletion backend/packages/Upgrade/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,12 @@ SWAGGER_API=**/controllers/*.ts
SWAGGER_JSON=/swagger.json

#
# Google Client Id
# Google Authentication Configuration
# Note: GOOGLE_CLIENT_ID and GOOGLE_SERVICE_ACCOUNT_ID can be a single ID or multiple comma-separated IDs (no spaces)
# Example: id1,id2,id3
#
GOOGLE_CLIENT_ID=google_project_id
GOOGLE_SERVICE_ACCOUNT_ID=google_service_account_id
DOMAIN_NAME=domain_name
SCHEDULER_STEP_FUNCTION=arn_name
AWS_REGION=aws-region
Expand Down
1 change: 1 addition & 0 deletions backend/packages/Upgrade/.env.test
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ MONITOR_PASSWORD=<replaceme>
# Google Client Id
#
GOOGLE_CLIENT_ID=google_project_id
GOOGLE_SERVICE_ACCOUNT_ID=google_service_account_id
DOMAIN_NAME =
SCHEDULER_STEP_FUNCTION=arn:aws:states:us-east-1:781188149671:stateMachine:development-upgrade-experiment-scheduler
# SCHEDULER_STEP_FUNCTION=arn:aws:states:us-east-1:781188149671:stateMachine:staging-upgrade-experiment-scheduler
Expand Down
22 changes: 14 additions & 8 deletions backend/packages/Upgrade/src/auth/AuthService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,25 +20,31 @@ export class AuthService {
}

public async validateUser(token: string, request: express.Request): Promise<User> {
const client = new OAuth2Client(env.google.clientId);
request.logger.info({ message: 'Validating Token' });
// env.google.clientId can be a single client ID or multiple comma-separated client IDs
const clientIds = env.google.clientId.split(',');
const client = new OAuth2Client(clientIds[0]);
request.logger.info({ message: 'Validating token' });

let payload;
try {
// First, try to verify the token as an ID token
const ticket = await client.verifyIdToken({
idToken: token,
audience: env.google.clientId, // Specify the CLIENT_ID of the app that accesses the backend
// Or, if multiple clients access the backend:
// [CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3]
audience: clientIds,
});
payload = ticket.getPayload();
request.logger.info({ message: 'ID Token Validated' });
request.logger.info({ message: 'ID token validated' });
} catch (error) {
// If ID token verification fails, try to verify it as an access token
try {
await client.getTokenInfo(token);
request.logger.info({ message: 'Access Token Validated' });
// env.google.serviceAccountId can be a single service account ID or multiple comma-separated service account IDs
const serviceAccountIds = env.google.serviceAccountId.split(',');
const tokenInfo = await client.getTokenInfo(token);

if (!tokenInfo || !serviceAccountIds.includes(tokenInfo.aud)) {
throw new Error('Invalid or unauthorized access token');
}
request.logger.info({ message: 'Access token validated' });
// For service account access tokens, we'll return null
// We might want to implement specific handling for service accounts here
return null;
Expand Down
1 change: 1 addition & 0 deletions backend/packages/Upgrade/src/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export const env = {
},
google: {
clientId: getOsEnv('GOOGLE_CLIENT_ID'),
serviceAccountId: getOsEnv('GOOGLE_SERVICE_ACCOUNT_ID'),
domainName: getOsEnvOptional('DOMAIN_NAME'),
},
scheduler: {
Expand Down
2 changes: 2 additions & 0 deletions cloudformation/backend/app-infrastructure.yml
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ Resources:
ValueFrom: !Sub arn:aws:ssm:us-east-1:${AWS::AccountId}:parameter/UPGRADE_CLIENT_API_SECRET
- Name: GOOGLE_CLIENT_ID
ValueFrom: !Sub arn:aws:ssm:us-east-1:${AWS::AccountId}:parameter/UPGRADE_GOOGLE_CLIENT_ID
- Name: GOOGLE_SERVICE_ACCOUNT_ID
ValueFrom: !Sub arn:aws:ssm:us-east-1:${AWS::AccountId}:parameter/UPGRADE_GOOGLE_SERVICE_ACCOUNT_ID
- Name: RDS_PASSWORD
ValueFrom: !Sub arn:aws:ssm:us-east-1:${AWS::AccountId}:parameter/UPGRADE_DB_PASSWORD
- Name: RDS_USERNAME
Expand Down
Loading