UNPKG

6.21 kBPlain TextView Raw
1/*
2 * Copyright 2021 Inrupt Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal in
6 * the Software without restriction, including without limitation the rights to use,
7 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
8 * Software, and to permit persons to whom the Software is furnished to do so,
9 * subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
16 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
18 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
19 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 */
21
22/**
23 * @hidden
24 * @packageDocumentation
25 */
26
27/**
28 * Responsible for fetching an IDP configuration
29 */
30import {
31 IIssuerConfig,
32 IIssuerConfigFetcher,
33 IStorageUtility,
34 ConfigurationError,
35} from "@inrupt/solid-client-authn-core";
36import { injectable, inject } from "tsyringe";
37import { appendToUrlPathname } from "../../util/urlPath";
38
39export const WELL_KNOWN_OPENID_CONFIG = ".well-known/openid-configuration";
40
41/* eslint-disable camelcase */
42const 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/* eslint-enable camelcase */
129
130function 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 // TODO: PMcB55: Validate URL if "issuerConfigKeyMap[key].convertToUrl"
137 // if (issuerConfigKeyMap[key].convertToUrl) {
138 // validateUrl(config[key]);
139 // }
140 parsedConfig[issuerConfigKeyMap[key].toKey] = config[key];
141 }
142 });
143
144 return (parsedConfig as unknown) as IIssuerConfig;
145}
146
147/**
148 * @hidden
149 */
150@injectable()
151export default class IssuerConfigFetcher implements IIssuerConfigFetcher {
152 constructor(
153 @inject("storageUtility") private storageUtility: IStorageUtility
154 ) {}
155
156 // This method needs no state (so can be static), and can be exposed to allow
157 // callers to know where this implementation puts state it needs.
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 // Check the validity of the fetched config
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 // Update store with fetched config
180 await this.storageUtility.set(
181 IssuerConfigFetcher.getLocalStorageKey(issuer),
182 JSON.stringify(issuerConfig)
183 );
184
185 return issuerConfig;
186 }
187}