Skip to content

Commit 6f548d1

Browse files
authored
Merge pull request #93 from i-dot-ai/feature/move-to-internal-access
feature/move-to-internal-access
2 parents e9ef519 + 3d01561 commit 6f548d1

File tree

10 files changed

+83
-116
lines changed

10 files changed

+83
-116
lines changed

frontend/package-lock.json

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

frontend/src/auth.ts

Lines changed: 13 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,42 @@
11
import 'dotenv/config';
2-
import { jwtVerify, decodeJwt, errors, importSPKI } from 'jose';
2+
import { decodeJwt } from 'jose';
33

44

55
export async function parseAuthToken(header: string) {
66
if (!header) {
77
console.error('No auth token provided to parse');
8-
return null;
8+
return { email: null, roles: [] };
99
}
1010

11-
const tokenContent = await getDecodedJwt(header, false);
12-
13-
if (!tokenContent) {
14-
return null;
11+
// Decode without verification since we're using auth-at-the-edge and can trust all traffic
12+
let tokenContent;
13+
try {
14+
tokenContent = decodeJwt(header);
15+
} catch(error) {
16+
console.error('Malformed JWT during decoding: ' + header, error);
17+
return { email: null, roles: [] };
1518
}
1619

17-
const email = tokenContent.email;
20+
const email = tokenContent.email as string | undefined;
1821
if (!email) {
1922
console.error('No email found in token');
2023
return null;
2124
}
2225

23-
const realmAccess = tokenContent.realm_access;
26+
const realmAccess = tokenContent.realm_access as { roles?: string[] } | undefined;
2427
if (!realmAccess) {
2528
console.error('No realm access information found in token');
26-
return null;
29+
return { email: null, roles: [] };
2730
}
2831

29-
const roles = tokenContent.realm_access.roles || [];
32+
const roles = realmAccess.roles || [];
3033
// console.debug(`Roles found for user ${email}: ${roles}`);
3134
return {
3235
email,
3336
roles,
3437
};
3538
}
3639

37-
async function getDecodedJwt(header: string, verifyJwtSource: boolean) {
38-
let decodedToken = null;
39-
40-
try {
41-
if (verifyJwtSource) {
42-
const publicKeyEncoded = process.env.AUTH_PROVIDER_PUBLIC_KEY!; // This is passed into the environment by ECS
43-
const pemPublicKey = convertToPemPublicKey(publicKeyEncoded);
44-
const publicKey = await importSPKI(pemPublicKey, 'RS256');
45-
46-
try {
47-
// Verify with signature
48-
const { payload } = await jwtVerify(header, publicKey, {
49-
algorithms: ['RS256'],
50-
audience: 'account',
51-
});
52-
53-
decodedToken = payload;
54-
} catch(error) {
55-
if (error instanceof errors.JWTExpired) {
56-
console.error('JWT has expired:', error.message);
57-
return null;
58-
} else if (error instanceof errors.JWTInvalid) {
59-
console.error('Malformed JWT:', error.message);
60-
return null;
61-
}
62-
console.error('Unexpected JWT verification error:', error);
63-
return null;
64-
}
65-
} else {
66-
// Decode without verification
67-
try {
68-
decodedToken = decodeJwt(header);
69-
} catch(error) {
70-
console.error('Malformed JWT during decoding:', error);
71-
return null;
72-
}
73-
}
74-
return decodedToken;
75-
} catch(error) {
76-
console.error('Unexpected error in getDecodedJwt:', error);
77-
return null;
78-
}
79-
}
80-
81-
function convertToPemPublicKey(keyBase64: string): string {
82-
return `-----BEGIN PUBLIC KEY-----\n${keyBase64}\n-----END PUBLIC KEY-----`;
83-
}
8440

8541
/*
8642
*export async function getServerSideDecodedToken() {

frontend/src/layouts/Chat.astro

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,16 @@ const singleServer = mcpServers.find((server) => server.name.toLowerCase() === s
9292
<model-selector class="[tool-selector+&]:left-21 top-0 md:mt-0 md:absolute">
9393
<label class="sr-only" for="model-selector">Mode</label>
9494
<select class="border-pink border-solid border-1 cursor-pointer inline-block min-h-[36px] mr-5 outline-pink px-2 py-[5px] rounded-sm text-pink w-40 focus-visible:outline-2" id="model-selector" name="model">
95+
<option value="locai-l1" class="p-[4px]">
96+
<svg focusable="false" aria-hidden="true" fill="none" viewBox="0 0 124 124" width="20px" height="20px">
97+
<rect x="0" y="0" width="110" height="110" rx="60" fill="#CCFF00"/>
98+
<rect x="30" y="25" width="10" height="60" fill="#000000"/>
99+
<rect x="30" y="80" width="30" height="10" fill="#000000"/>
100+
<rect x="70" y="25" width="10" height="65" fill="#000000"/>
101+
<rect x="60" y="25" width="20" height="10" fill="#000000"/>
102+
</svg>
103+
Locai L1
104+
</option>
95105
<option value="bedrock-claude-3-7-sonnet" class="p-[4px]">
96106
<svg focusable="false" aria-hidden="true" width="20px" height="20px" viewBox="0 0 1200 1200"><path fill="#d97757" stroke="none" d="M 233.959793 800.214905 L 468.644287 668.536987 L 472.590637 657.100647 L 468.644287 650.738403 L 457.208069 650.738403 L 417.986633 648.322144 L 283.892639 644.69812 L 167.597321 639.865845 L 54.926208 633.825623 L 26.577238 627.785339 L 3.3e-05 592.751709 L 2.73832 575.27533 L 26.577238 559.248352 L 60.724873 562.228149 L 136.187973 567.382629 L 249.422867 575.194763 L 331.570496 580.026978 L 453.261841 592.671082 L 472.590637 592.671082 L 475.328857 584.859009 L 468.724915 580.026978 L 463.570557 575.194763 L 346.389313 495.785217 L 219.543671 411.865906 L 153.100723 363.543762 L 117.181267 339.060425 L 99.060455 316.107361 L 91.248367 266.01355 L 123.865784 230.093994 L 167.677887 233.073853 L 178.872513 236.053772 L 223.248367 270.201477 L 318.040283 343.570496 L 441.825592 434.738342 L 459.946411 449.798706 L 467.194672 444.64447 L 468.080597 441.020203 L 459.946411 427.409485 L 392.617493 305.718323 L 320.778564 181.932983 L 288.80542 130.630859 L 280.348999 99.865845 C 277.369171 87.221436 275.194641 76.590698 275.194641 63.624268 L 312.322174 13.20813 L 332.8591 6.604126 L 382.389313 13.20813 L 403.248352 31.328979 L 434.013519 101.71814 L 483.865753 212.537048 L 561.181274 363.221497 L 583.812134 407.919434 L 595.892639 449.315491 L 600.40271 461.959839 L 608.214783 461.959839 L 608.214783 454.711609 L 614.577271 369.825623 L 626.335632 265.61084 L 637.771851 131.516846 L 641.718201 93.745117 L 660.402832 48.483276 L 697.530334 24.000122 L 726.52356 37.852417 L 750.362549 72 L 747.060486 94.067139 L 732.886047 186.201416 L 705.100708 330.52356 L 686.979919 427.167847 L 697.530334 427.167847 L 709.61084 415.087341 L 758.496704 350.174561 L 840.644348 247.490051 L 876.885925 206.738342 L 919.167847 161.71814 L 946.308838 140.29541 L 997.61084 140.29541 L 1035.38269 196.429626 L 1018.469849 254.416199 L 965.637634 321.422852 L 921.825562 378.201538 L 859.006714 462.765259 L 819.785278 530.41626 L 823.409424 535.812073 L 832.75177 534.92627 L 974.657776 504.724915 L 1051.328979 490.872559 L 1142.818848 475.167786 L 1184.214844 494.496582 L 1188.724854 514.147644 L 1172.456421 554.335693 L 1074.604126 578.496765 L 959.838989 601.449829 L 788.939636 641.879272 L 786.845764 643.409485 L 789.261841 646.389343 L 866.255127 653.637634 L 899.194702 655.409424 L 979.812134 655.409424 L 1129.932861 666.604187 L 1169.154419 692.537109 L 1192.671265 724.268677 L 1188.724854 748.429688 L 1128.322144 779.194641 L 1046.818848 759.865845 L 856.590759 714.604126 L 791.355774 698.335754 L 782.335693 698.335754 L 782.335693 703.731567 L 836.69812 756.885986 L 936.322205 846.845581 L 1061.073975 962.81897 L 1067.436279 991.490112 L 1051.409424 1014.120911 L 1034.496704 1011.704712 L 924.885986 929.234924 L 882.604126 892.107544 L 786.845764 811.48999 L 780.483276 811.48999 L 780.483276 819.946289 L 802.550415 852.241699 L 919.087341 1027.409424 L 925.127625 1081.127686 L 916.671204 1098.604126 L 886.469849 1109.154419 L 853.288696 1103.114136 L 785.073914 1007.355835 L 714.684631 899.516785 L 657.906067 802.872498 L 650.979858 806.81897 L 617.476624 1167.704834 L 601.771851 1186.147705 L 565.530212 1200 L 535.328857 1177.046997 L 519.302124 1139.919556 L 535.328857 1066.550537 L 554.657776 970.792053 L 570.362488 894.68457 L 584.536926 800.134277 L 592.993347 768.724976 L 592.429626 766.630859 L 585.503479 767.516968 L 514.22821 865.369263 L 405.825531 1011.865906 L 320.053711 1103.677979 L 299.516815 1111.812256 L 263.919525 1093.369263 L 267.221497 1060.429688 L 287.114136 1031.114136 L 405.825531 880.107361 L 477.422913 786.52356 L 523.651062 732.483276 L 523.328918 724.671265 L 520.590698 724.671265 L 205.288605 929.395935 L 149.154434 936.644409 L 124.993355 914.01355 L 127.973183 876.885986 L 139.409409 864.80542 L 234.201385 799.570435 L 233.879227 799.8927 Z"/></svg>
97107
Claude Sonnet 3.7

frontend/src/logic/get-servers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ const getServerList = (): MCP_SERVER[] => {
5050
// if not, try pulling in list from yaml file
5151
try {
5252
const file = fs.readFileSync('../.mcp-servers.yaml', 'utf8');
53-
return YAML.parse(file).servers;
53+
return YAML.parse(file).servers || [];
5454
} catch(err) {
5555
console.error('Missing or invalid .mcp-servers.yaml file - no MCP servers have been added');
5656
console.log(err);

frontend/src/middleware.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export async function onRequest(context, next) {
2525
if (process.env.ENVIRONMENT == 'local') {
2626
token = TEST_AUTHORISATION_JWT;
2727
} else {
28-
token = context.request.headers.get('x-amzn-oidc-accesstoken');
28+
token = context.request.headers.get('x-amzn-oidc-data');
2929
}
3030

3131
if (!token) {

terraform/data.tf

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,6 @@ data "terraform_remote_state" "account" {
4242
}
4343
}
4444

45-
data "terraform_remote_state" "keycloak" {
46-
backend = "s3"
47-
workspace = terraform.workspace
48-
config = {
49-
bucket = var.state_bucket
50-
key = "core/keycloak/keycloak/terraform.tfstate"
51-
region = var.region
52-
}
53-
}
5445

5546
locals {
5647
name = "${var.team_name}-${var.env}-${var.project_name}"
@@ -60,13 +51,6 @@ locals {
6051
auth_ses_identity = "arn:aws:ses:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:identity/auth-notify.ai.cabinetoffice.gov.uk"
6152
}
6253

63-
data "aws_ssm_parameter" "client_secret" {
64-
name = "/${var.team_name}-${terraform.workspace}-core-keycloak/app_client_secret/${var.project_name}"
65-
}
66-
67-
data "aws_ssm_parameter" "auth_provider_public_key" {
68-
name = "/i-dot-ai-${terraform.workspace}-core-keycloak/realm_public_key"
69-
}
7054

7155
data "aws_secretsmanager_secret" "slack" {
7256
name = "i-dot-ai-${var.env}-platform-slack-webhook"

terraform/ecs.tf

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ module "frontend" {
1010
# checkov:skip=CKV_SECRET_4:Skip secret check as these have to be used within the Github Action
1111
# checkov:skip=CKV_TF_1: We're using semantic versions instead of commit hash
1212
#source = "../../i-dot-ai-core-terraform-modules//modules/infrastructure/ecs" # For testing local changes
13-
source = "git::https://github.com/i-dot-ai/i-dot-ai-core-terraform-modules.git//modules/infrastructure/ecs?ref=v5.4.0-ecs"
13+
source = "git::https://github.com/i-dot-ai/i-dot-ai-core-terraform-modules.git//modules/infrastructure/ecs?ref=v5.8.0-ecs"
1414
image_tag = var.image_tag
1515
ecr_repository_uri = "public.ecr.aws/idotai/gov-ai-client"
1616
vpc_id = data.terraform_remote_state.vpc.outputs.vpc_id
@@ -32,7 +32,6 @@ module "frontend" {
3232
"PORT" : local.frontend_port,
3333
"REPO" : "gov-ai-client",
3434
"DOCKER_BUILDER_CONTAINER" : "gov-ai-client",
35-
"AUTH_PROVIDER_PUBLIC_KEY" : data.aws_ssm_parameter.auth_provider_public_key.value,
3635

3736
"LLM_GATEWAY_URL" : local.llm_gateway_url
3837
}
@@ -66,12 +65,11 @@ module "frontend" {
6665
port = local.frontend_port
6766
}
6867

69-
authenticate_keycloak = {
68+
69+
authenticate_gds_internal_access = {
7070
enabled : true,
71-
realm_name : data.terraform_remote_state.keycloak.outputs.realm_name,
72-
client_id : var.project_name,
73-
client_secret : data.aws_ssm_parameter.client_secret.value,
74-
keycloak_dns : data.terraform_remote_state.keycloak.outputs.keycloak_dns
71+
client_id : aws_ssm_parameter.oidc_secrets["client_id"].value,
72+
client_secret : aws_ssm_parameter.oidc_secrets["client_secret"].value,
7573
}
7674
}
7775

0 commit comments

Comments
 (0)