UNPKG

4.8 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 * Handles Common Oidc login functions (Like fetching the configuration)
29 */
30
31import { injectable, inject } from "tsyringe";
32import {
33 IClientRegistrar,
34 IIssuerConfig,
35 IIssuerConfigFetcher,
36 ILoginOptions,
37 ILoginHandler,
38 IOidcHandler,
39 IOidcOptions,
40 IStorageUtility,
41 ConfigurationError,
42 LoginResult,
43} from "@inrupt/solid-client-authn-core";
44
45import { IClient } from "@inrupt/oidc-client-ext";
46
47function hasIssuer(
48 options: ILoginOptions
49): options is ILoginOptions & { oidcIssuer: string } {
50 return typeof options.oidcIssuer === "string";
51}
52
53function hasRedirectUrl(
54 options: ILoginOptions
55): options is ILoginOptions & { redirectUrl: string } {
56 return typeof options.redirectUrl === "string";
57}
58
59/**
60 * @hidden
61 */
62@injectable()
63export default class OidcLoginHandler implements ILoginHandler {
64 constructor(
65 @inject("storageUtility") private storageUtility: IStorageUtility,
66 @inject("oidcHandler") private oidcHandler: IOidcHandler,
67 @inject("issuerConfigFetcher")
68 private issuerConfigFetcher: IIssuerConfigFetcher,
69 @inject("clientRegistrar") private clientRegistrar: IClientRegistrar
70 ) {}
71
72 async canHandle(options: ILoginOptions): Promise<boolean> {
73 return hasIssuer(options) && hasRedirectUrl(options);
74 }
75
76 async handle(options: ILoginOptions): Promise<LoginResult> {
77 if (!hasIssuer(options)) {
78 throw new ConfigurationError(
79 `OidcLoginHandler requires an OIDC issuer: missing property 'oidcIssuer' in ${JSON.stringify(
80 options
81 )}`
82 );
83 }
84 if (!hasRedirectUrl(options)) {
85 throw new ConfigurationError(
86 `OidcLoginHandler requires a redirect URL: missing property 'redirectUrl' in ${JSON.stringify(
87 options
88 )}`
89 );
90 }
91
92 // Fetch OpenId Config
93 const issuerConfig: IIssuerConfig = await this.issuerConfigFetcher.fetchConfig(
94 options.oidcIssuer
95 );
96
97 let dynamicClientRegistration: IClient;
98 if (options.clientId) {
99 dynamicClientRegistration = {
100 clientId: options.clientId,
101 clientSecret: options.clientSecret,
102 clientName: options.clientName,
103 };
104 } else {
105 const clientId = await this.storageUtility.getForUser(
106 "clientApplicationRegistrationInfo",
107 "clientId"
108 );
109
110 if (clientId) {
111 dynamicClientRegistration = {
112 clientId,
113 clientSecret: await this.storageUtility.getForUser(
114 "clientApplicationRegistrationInfo",
115 "clientSecret"
116 ),
117 clientName: options.clientName,
118 };
119 } else {
120 dynamicClientRegistration = await this.clientRegistrar.getClient(
121 {
122 sessionId: options.sessionId,
123 clientName: options.clientName,
124 redirectUrl: options.redirectUrl,
125 },
126 issuerConfig
127 );
128
129 await this.storageUtility.setForUser(
130 "clientApplicationRegistrationInfo",
131 {
132 clientId: dynamicClientRegistration.clientId,
133 clientSecret: dynamicClientRegistration.clientSecret as string,
134 }
135 );
136 }
137 }
138
139 // Construct OIDC Options
140 const OidcOptions: IOidcOptions = {
141 issuer: options.oidcIssuer,
142 // TODO: differentiate if DPoP should be true
143 dpop: options.tokenType.toLowerCase() === "dpop",
144 redirectUrl: options.redirectUrl,
145 issuerConfiguration: issuerConfig,
146 client: dynamicClientRegistration,
147 sessionId: options.sessionId,
148 handleRedirect: options.handleRedirect,
149 };
150
151 // Call proper OIDC Handler
152 return this.oidcHandler.handle(OidcOptions);
153 }
154}