1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 | import {
|
31 | IIssuerConfig,
|
32 | IIssuerConfigFetcher,
|
33 | IStorageUtility,
|
34 | ConfigurationError,
|
35 | } from "@inrupt/solid-client-authn-core";
|
36 | import { injectable, inject } from "tsyringe";
|
37 | import { appendToUrlPathname } from "../../util/urlPath";
|
38 |
|
39 | export const WELL_KNOWN_OPENID_CONFIG = ".well-known/openid-configuration";
|
40 |
|
41 |
|
42 | const issuerConfigKeyMap: Record<
|
43 | string,
|
44 | { toKey: string; convertToUrl?: boolean }
|
45 | > = {
|
46 | issuer: {
|
47 | toKey: "issuer",
|
48 | convertToUrl: true,
|
49 | },
|
50 | authorization_endpoint: {
|
51 | toKey: "authorizationEndpoint",
|
52 | convertToUrl: true,
|
53 | },
|
54 | token_endpoint: {
|
55 | toKey: "tokenEndpoint",
|
56 | convertToUrl: true,
|
57 | },
|
58 | userinfo_endpoint: {
|
59 | toKey: "userinfoEndpoint",
|
60 | convertToUrl: true,
|
61 | },
|
62 | jwks_uri: {
|
63 | toKey: "jwksUri",
|
64 | convertToUrl: true,
|
65 | },
|
66 | registration_endpoint: {
|
67 | toKey: "registrationEndpoint",
|
68 | convertToUrl: true,
|
69 | },
|
70 | scopes_supported: { toKey: "scopesSupported" },
|
71 | response_types_supported: { toKey: "responseTypesSupported" },
|
72 | response_modes_supported: { toKey: "responseModesSupported" },
|
73 | grant_types_supported: { toKey: "grantTypesSupported" },
|
74 | acr_values_supported: { toKey: "acrValuesSupported" },
|
75 | subject_types_supported: { toKey: "subjectTypesSupported" },
|
76 | id_token_signing_alg_values_supported: {
|
77 | toKey: "idTokenSigningAlgValuesSupported",
|
78 | },
|
79 | id_token_encryption_alg_values_supported: {
|
80 | toKey: "idTokenEncryptionAlgValuesSupported",
|
81 | },
|
82 | id_token_encryption_enc_values_supported: {
|
83 | toKey: "idTokenEncryptionEncValuesSupported",
|
84 | },
|
85 | userinfo_signing_alg_values_supported: {
|
86 | toKey: "userinfoSigningAlgValuesSupported",
|
87 | },
|
88 | userinfo_encryption_alg_values_supported: {
|
89 | toKey: "userinfoEncryptionAlgValuesSupported",
|
90 | },
|
91 | userinfo_encryption_enc_values_supported: {
|
92 | toKey: "userinfoEncryptionEncValuesSupported",
|
93 | },
|
94 | request_object_signing_alg_values_supported: {
|
95 | toKey: "requestObjectSigningAlgValuesSupported",
|
96 | },
|
97 | request_object_encryption_alg_values_supported: {
|
98 | toKey: "requestObjectEncryptionAlgValuesSupported",
|
99 | },
|
100 | request_object_encryption_enc_values_supported: {
|
101 | toKey: "requestObjectEncryptionEncValuesSupported",
|
102 | },
|
103 | token_endpoint_auth_methods_supported: {
|
104 | toKey: "tokenEndpointAuthMethodsSupported",
|
105 | },
|
106 | token_endpoint_auth_signing_alg_values_supported: {
|
107 | toKey: "tokenEndpointAuthSigningAlgValuesSupported",
|
108 | },
|
109 | display_values_supported: { toKey: "displayValuesSupported" },
|
110 | claim_types_supported: { toKey: "claimTypesSupported" },
|
111 | claims_supported: { toKey: "claimsSupported" },
|
112 | service_documentation: { toKey: "serviceDocumentation" },
|
113 | claims_locales_supported: { toKey: "claimsLocalesSupported" },
|
114 | ui_locales_supported: { toKey: "uiLocalesSupported" },
|
115 | claims_parameter_supported: { toKey: "claimsParameterSupported" },
|
116 | request_parameter_supported: { toKey: "requestParameterSupported" },
|
117 | request_uri_parameter_supported: { toKey: "requestUriParameterSupported" },
|
118 | require_request_uri_registration: { toKey: "requireRequestUriRegistration" },
|
119 | op_policy_uri: {
|
120 | toKey: "opPolicyUri",
|
121 | convertToUrl: true,
|
122 | },
|
123 | op_tos_uri: {
|
124 | toKey: "opTosUri",
|
125 | convertToUrl: true,
|
126 | },
|
127 | };
|
128 |
|
129 |
|
130 | function processConfig(
|
131 | config: Record<string, string | string[]>
|
132 | ): IIssuerConfig {
|
133 | const parsedConfig: Record<string, string | string[]> = {};
|
134 | Object.keys(config).forEach((key) => {
|
135 | if (issuerConfigKeyMap[key]) {
|
136 |
|
137 |
|
138 |
|
139 |
|
140 | parsedConfig[issuerConfigKeyMap[key].toKey] = config[key];
|
141 | }
|
142 | });
|
143 |
|
144 | return (parsedConfig as unknown) as IIssuerConfig;
|
145 | }
|
146 |
|
147 |
|
148 |
|
149 |
|
150 | @injectable()
|
151 | export default class IssuerConfigFetcher implements IIssuerConfigFetcher {
|
152 | constructor(
|
153 | @inject("storageUtility") private storageUtility: IStorageUtility
|
154 | ) {}
|
155 |
|
156 |
|
157 |
|
158 | public static getLocalStorageKey(issuer: string): string {
|
159 | return `issuerConfig:${issuer}`;
|
160 | }
|
161 |
|
162 | async fetchConfig(issuer: string): Promise<IIssuerConfig> {
|
163 | let issuerConfig: IIssuerConfig;
|
164 |
|
165 | const openIdConfigUrl = appendToUrlPathname(
|
166 | issuer,
|
167 | WELL_KNOWN_OPENID_CONFIG
|
168 | );
|
169 | const issuerConfigRequestBody = await window.fetch(openIdConfigUrl);
|
170 |
|
171 | try {
|
172 | issuerConfig = processConfig(await issuerConfigRequestBody.json());
|
173 | } catch (err) {
|
174 | throw new ConfigurationError(
|
175 | `[${issuer.toString()}] has an invalid configuration: ${err.message}`
|
176 | );
|
177 | }
|
178 |
|
179 |
|
180 | await this.storageUtility.set(
|
181 | IssuerConfigFetcher.getLocalStorageKey(issuer),
|
182 | JSON.stringify(issuerConfig)
|
183 | );
|
184 |
|
185 | return issuerConfig;
|
186 | }
|
187 | }
|