-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Expand file tree
/
Copy pathAuthority.ts
More file actions
167 lines (146 loc) · 5.63 KB
/
Authority.ts
File metadata and controls
167 lines (146 loc) · 5.63 KB
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { AuthorityType } from "./AuthorityType";
import { TenantDiscoveryResponse } from "./TenantDiscoveryResponse";
import { UrlString } from "./../url/UrlString";
import { IUri } from "./../url/IUri";
import { ClientAuthError } from "./../error/ClientAuthError";
import { INetworkModule } from "./../network/INetworkModule";
import {NetworkResponse} from "..";
/**
* The authority class validates the authority URIs used by the user, and retrieves the OpenID Configuration Data from the
* endpoint. It will store the pertinent config data in this object for use during token calls.
*/
export abstract class Authority {
// Canonical authority url string
private _canonicalAuthority: UrlString;
// Canonicaly authority url components
private _canonicalAuthorityUrlComponents: IUri;
// Tenant discovery response retrieved from OpenID Configuration Endpoint
private tenantDiscoveryResponse: TenantDiscoveryResponse;
// Network interface to make requests with.
protected networkInterface: INetworkModule;
// See above for AuthorityType
public abstract get authorityType(): AuthorityType;
/**
* A URL that is the authority set by the developer
*/
public get canonicalAuthority(): string {
return this._canonicalAuthority.urlString;
}
/**
* Sets canonical authority.
*/
public set canonicalAuthority(url: string) {
this._canonicalAuthority = new UrlString(url);
this._canonicalAuthority.validateAsUri();
this._canonicalAuthorityUrlComponents = null;
}
/**
* Get authority components.
*/
public get canonicalAuthorityUrlComponents(): IUri {
if (!this._canonicalAuthorityUrlComponents) {
this._canonicalAuthorityUrlComponents = this._canonicalAuthority.getUrlComponents();
}
return this._canonicalAuthorityUrlComponents;
}
/**
* Get tenant for authority.
*/
public get tenant(): string {
return this.canonicalAuthorityUrlComponents.PathSegments[0];
}
/**
* OAuth /authorize endpoint for requests
*/
public get authorizationEndpoint(): string {
if(this.discoveryComplete()) {
return this.replaceTenant(this.tenantDiscoveryResponse.authorization_endpoint);
} else {
throw ClientAuthError.createEndpointDiscoveryIncompleteError("Discovery incomplete.");
}
}
/**
* OAuth /token endpoint for requests
*/
public get tokenEndpoint(): string {
if(this.discoveryComplete()) {
return this.replaceTenant(this.tenantDiscoveryResponse.token_endpoint);
} else {
throw ClientAuthError.createEndpointDiscoveryIncompleteError("Discovery incomplete.");
}
}
public get deviceCodeEndpoint(): string {
if(this.discoveryComplete()) {
return this.tenantDiscoveryResponse.token_endpoint.replace("/token", "/devicecode");
} else {
throw ClientAuthError.createEndpointDiscoveryIncompleteError("Discovery incomplete.");
}
}
/**
* OAuth logout endpoint for requests
*/
public get endSessionEndpoint(): string {
if(this.discoveryComplete()) {
return this.replaceTenant(this.tenantDiscoveryResponse.end_session_endpoint);
} else {
throw ClientAuthError.createEndpointDiscoveryIncompleteError("Discovery incomplete.");
}
}
/**
* OAuth issuer for requests
*/
public get selfSignedJwtAudience(): string {
if(this.discoveryComplete()) {
return this.replaceTenant(this.tenantDiscoveryResponse.issuer);
} else {
throw ClientAuthError.createEndpointDiscoveryIncompleteError("Discovery incomplete.");
}
}
/**
* Replaces tenant in url path with current tenant. Defaults to common.
* @param urlString
*/
private replaceTenant(urlString: string): string {
return urlString.replace(/{tenant}|{tenantid}/g, this.tenant);
}
/**
* The default open id configuration endpoint for any canonical authority.
*/
protected get defaultOpenIdConfigurationEndpoint(): string {
return `${this.canonicalAuthority}v2.0/.well-known/openid-configuration`;
}
constructor(authority: string, networkInterface: INetworkModule) {
this.canonicalAuthority = authority;
this._canonicalAuthority.validateAsUri();
this.networkInterface = networkInterface;
}
/**
* Boolean that returns whethr or not tenant discovery has been completed.
*/
discoveryComplete(): boolean {
return !!this.tenantDiscoveryResponse;
}
/**
* Gets OAuth endpoints from the given OpenID configuration endpoint.
* @param openIdConfigurationEndpoint
*/
private async discoverEndpoints(openIdConfigurationEndpoint: string): Promise<NetworkResponse<TenantDiscoveryResponse>> {
return this.networkInterface.sendGetRequestAsync<TenantDiscoveryResponse>(openIdConfigurationEndpoint);
}
/**
* Abstract function which will get the OpenID configuration endpoint.
*/
public abstract async getOpenIdConfigurationEndpointAsync(): Promise<string>;
/**
* Perform endpoint discovery to discover the /authorize, /token and logout endpoints.
*/
public async resolveEndpointsAsync(): Promise<void> {
const openIdConfigEndpoint = await this.getOpenIdConfigurationEndpointAsync();
const response = await this.discoverEndpoints(openIdConfigEndpoint);
this.tenantDiscoveryResponse = response.body;
}
}