@itwin/core-electron 3.0.0-dev.98 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +95 -7
- package/LICENSE.md +1 -1
- package/lib/cjs/ElectronBackend.d.ts +0 -1
- package/lib/cjs/ElectronBackend.d.ts.map +1 -1
- package/lib/cjs/ElectronBackend.js +0 -1
- package/lib/cjs/ElectronBackend.js.map +1 -1
- package/lib/cjs/backend/ElectronHost.d.ts +1 -9
- package/lib/cjs/backend/ElectronHost.d.ts.map +1 -1
- package/lib/cjs/backend/ElectronHost.js +1 -9
- package/lib/cjs/backend/ElectronHost.js.map +1 -1
- package/package.json +16 -17
- package/lib/cjs/backend/ElectronAuthorizationBackend.d.ts +0 -71
- package/lib/cjs/backend/ElectronAuthorizationBackend.d.ts.map +0 -1
- package/lib/cjs/backend/ElectronAuthorizationBackend.js +0 -265
- package/lib/cjs/backend/ElectronAuthorizationBackend.js.map +0 -1
- package/lib/cjs/backend/ElectronAuthorizationEvents.d.ts +0 -20
- package/lib/cjs/backend/ElectronAuthorizationEvents.d.ts.map +0 -1
- package/lib/cjs/backend/ElectronAuthorizationEvents.js +0 -26
- package/lib/cjs/backend/ElectronAuthorizationEvents.js.map +0 -1
- package/lib/cjs/backend/ElectronAuthorizationRequestHandler.d.ts +0 -25
- package/lib/cjs/backend/ElectronAuthorizationRequestHandler.d.ts.map +0 -1
- package/lib/cjs/backend/ElectronAuthorizationRequestHandler.js +0 -63
- package/lib/cjs/backend/ElectronAuthorizationRequestHandler.js.map +0 -1
- package/lib/cjs/backend/ElectronTokenStore.d.ts +0 -18
- package/lib/cjs/backend/ElectronTokenStore.d.ts.map +0 -1
- package/lib/cjs/backend/ElectronTokenStore.js +0 -66
- package/lib/cjs/backend/ElectronTokenStore.js.map +0 -1
- package/lib/cjs/backend/LoopbackWebServer.d.ts +0 -19
- package/lib/cjs/backend/LoopbackWebServer.d.ts.map +0 -1
- package/lib/cjs/backend/LoopbackWebServer.js +0 -101
- package/lib/cjs/backend/LoopbackWebServer.js.map +0 -1
|
@@ -1,265 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*---------------------------------------------------------------------------------------------
|
|
3
|
-
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
4
|
-
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
5
|
-
*--------------------------------------------------------------------------------------------*/
|
|
6
|
-
// Code based on the blog article @ https://authguidance.com
|
|
7
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.ElectronAuthorizationBackend = void 0;
|
|
9
|
-
/** @packageDocumentation
|
|
10
|
-
* @module Authentication
|
|
11
|
-
*/
|
|
12
|
-
// cSpell:ignore openid appauth signin Pkce Signout
|
|
13
|
-
/* eslint-disable @typescript-eslint/naming-convention */
|
|
14
|
-
const core_bentley_1 = require("@itwin/core-bentley");
|
|
15
|
-
const core_backend_1 = require("@itwin/core-backend");
|
|
16
|
-
const appauth_1 = require("@openid/appauth");
|
|
17
|
-
const node_support_1 = require("@openid/appauth/built/node_support");
|
|
18
|
-
const ElectronAuthorizationEvents_1 = require("./ElectronAuthorizationEvents");
|
|
19
|
-
const ElectronAuthorizationRequestHandler_1 = require("./ElectronAuthorizationRequestHandler");
|
|
20
|
-
const ElectronTokenStore_1 = require("./ElectronTokenStore");
|
|
21
|
-
const LoopbackWebServer_1 = require("./LoopbackWebServer");
|
|
22
|
-
const loggerCategory = "electron-auth";
|
|
23
|
-
/**
|
|
24
|
-
* Utility to generate OIDC/OAuth tokens for Desktop Applications
|
|
25
|
-
* @beta
|
|
26
|
-
*/
|
|
27
|
-
class ElectronAuthorizationBackend extends core_backend_1.NativeAppAuthorizationBackend {
|
|
28
|
-
constructor(config) {
|
|
29
|
-
super(config);
|
|
30
|
-
}
|
|
31
|
-
get tokenStore() { return this._tokenStore; }
|
|
32
|
-
get redirectUri() { var _a, _b; return (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.redirectUri) !== null && _b !== void 0 ? _b : ElectronAuthorizationBackend.defaultRedirectUri; }
|
|
33
|
-
/**
|
|
34
|
-
* Used to initialize the client - must be awaited before any other methods are called.
|
|
35
|
-
* The call attempts a silent sign-if possible.
|
|
36
|
-
*/
|
|
37
|
-
async initialize(config) {
|
|
38
|
-
await super.initialize(config);
|
|
39
|
-
(0, core_bentley_1.assert)(this.config !== undefined && this.issuerUrl !== undefined, "URL of authorization provider was not initialized");
|
|
40
|
-
this._tokenStore = new ElectronTokenStore_1.ElectronTokenStore(this.config.clientId);
|
|
41
|
-
const tokenRequestor = new node_support_1.NodeRequestor(); // the Node.js based HTTP client
|
|
42
|
-
this._configuration = await appauth_1.AuthorizationServiceConfiguration.fetchFromIssuer(this.issuerUrl, tokenRequestor);
|
|
43
|
-
core_bentley_1.Logger.logTrace(loggerCategory, "Initialized service configuration", () => ({ configuration: this._configuration }));
|
|
44
|
-
// Attempt to load the access token from store
|
|
45
|
-
await this.loadAccessToken();
|
|
46
|
-
}
|
|
47
|
-
async refreshToken() {
|
|
48
|
-
if (this._tokenResponse === undefined || this._tokenResponse.refreshToken === undefined)
|
|
49
|
-
return "";
|
|
50
|
-
const token = `Bearer ${this._tokenResponse.refreshToken}`;
|
|
51
|
-
return this.refreshAccessToken(token);
|
|
52
|
-
}
|
|
53
|
-
/** Loads the access token from the store, and refreshes it if necessary and possible
|
|
54
|
-
* @return AccessToken if it's possible to get a valid access token, and undefined otherwise.
|
|
55
|
-
*/
|
|
56
|
-
async loadAccessToken() {
|
|
57
|
-
const tokenResponse = await this.tokenStore.load();
|
|
58
|
-
if (tokenResponse === undefined || tokenResponse.refreshToken === undefined)
|
|
59
|
-
return "";
|
|
60
|
-
try {
|
|
61
|
-
return await this.refreshAccessToken(tokenResponse.refreshToken);
|
|
62
|
-
}
|
|
63
|
-
catch (err) {
|
|
64
|
-
return "";
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Sign-in completely.
|
|
69
|
-
* This is a wrapper around [[signIn]] - the only difference is that the promise resolves
|
|
70
|
-
* with the access token after sign in is complete and successful.
|
|
71
|
-
*/
|
|
72
|
-
async signInComplete() {
|
|
73
|
-
return new Promise((resolve, reject) => {
|
|
74
|
-
core_backend_1.NativeHost.onAccessTokenChanged.addOnce((token) => {
|
|
75
|
-
if (token !== "") {
|
|
76
|
-
resolve(token);
|
|
77
|
-
}
|
|
78
|
-
else {
|
|
79
|
-
reject(new Error("Failed to sign in"));
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
this.signIn().catch((err) => reject(err));
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Start the sign-in process
|
|
87
|
-
* - calls the onAccessTokenChanged() call back after the authorization completes
|
|
88
|
-
* or if there is an error.
|
|
89
|
-
* - will attempt in order:
|
|
90
|
-
* (i) load any existing authorized user from storage,
|
|
91
|
-
* (ii) an interactive signin that requires user input.
|
|
92
|
-
*/
|
|
93
|
-
async signIn() {
|
|
94
|
-
if (!this._configuration)
|
|
95
|
-
throw new core_bentley_1.BentleyError(core_bentley_1.AuthStatus.Error, "Not initialized. First call initialize()");
|
|
96
|
-
(0, core_bentley_1.assert)(this.config !== undefined);
|
|
97
|
-
// Attempt to load the access token from store
|
|
98
|
-
const token = await this.loadAccessToken();
|
|
99
|
-
if (token)
|
|
100
|
-
return this.setAccessToken(token);
|
|
101
|
-
// Create the authorization request
|
|
102
|
-
const nativeConfig = this.config;
|
|
103
|
-
const authReqJson = {
|
|
104
|
-
client_id: nativeConfig.clientId,
|
|
105
|
-
redirect_uri: this.redirectUri,
|
|
106
|
-
scope: nativeConfig.scope,
|
|
107
|
-
response_type: appauth_1.AuthorizationRequest.RESPONSE_TYPE_CODE,
|
|
108
|
-
extras: { prompt: "consent", access_type: "offline" },
|
|
109
|
-
};
|
|
110
|
-
const authorizationRequest = new appauth_1.AuthorizationRequest(authReqJson, new node_support_1.NodeCrypto(), true /* = usePkce */);
|
|
111
|
-
await authorizationRequest.setupCodeVerifier();
|
|
112
|
-
// Create events for this signin attempt
|
|
113
|
-
const authorizationEvents = new ElectronAuthorizationEvents_1.ElectronAuthorizationEvents();
|
|
114
|
-
// Ensure that completion callbacks are correlated to the correct authorization request
|
|
115
|
-
LoopbackWebServer_1.LoopbackWebServer.addCorrelationState(authorizationRequest.state, authorizationEvents);
|
|
116
|
-
// Start a web server to listen to the browser requests
|
|
117
|
-
LoopbackWebServer_1.LoopbackWebServer.start(nativeConfig);
|
|
118
|
-
const authorizationHandler = new ElectronAuthorizationRequestHandler_1.ElectronAuthorizationRequestHandler(authorizationEvents);
|
|
119
|
-
// Setup a notifier to obtain the result of authorization
|
|
120
|
-
const notifier = new appauth_1.AuthorizationNotifier();
|
|
121
|
-
authorizationHandler.setAuthorizationNotifier(notifier);
|
|
122
|
-
notifier.setAuthorizationListener(async (authRequest, authResponse, authError) => {
|
|
123
|
-
core_bentley_1.Logger.logTrace(loggerCategory, "Authorization listener invoked", () => ({ authRequest, authResponse, authError }));
|
|
124
|
-
const tokenResponse = await this._onAuthorizationResponse(authRequest, authResponse, authError);
|
|
125
|
-
authorizationEvents.onAuthorizationResponseCompleted.raiseEvent(authError ? authError : undefined);
|
|
126
|
-
if (!tokenResponse)
|
|
127
|
-
await this.clearTokenResponse();
|
|
128
|
-
else
|
|
129
|
-
await this.setTokenResponse(tokenResponse);
|
|
130
|
-
});
|
|
131
|
-
// Start the signin
|
|
132
|
-
await authorizationHandler.performAuthorizationRequest(this._configuration, authorizationRequest);
|
|
133
|
-
}
|
|
134
|
-
async _onAuthorizationResponse(authRequest, authResponse, authError) {
|
|
135
|
-
// Phase 1 of login has completed to fetch the authorization code - check for errors
|
|
136
|
-
if (authError) {
|
|
137
|
-
core_bentley_1.Logger.logError(loggerCategory, "Authorization error. Unable to get authorization code.", () => authError);
|
|
138
|
-
return undefined;
|
|
139
|
-
}
|
|
140
|
-
if (!authResponse || authResponse.state !== authRequest.state) {
|
|
141
|
-
core_bentley_1.Logger.logError(loggerCategory, "Authorization error. Unable to get authorization code", () => ({
|
|
142
|
-
error: "invalid_state",
|
|
143
|
-
errorDescription: "The login response state did not match the login request state.",
|
|
144
|
-
}));
|
|
145
|
-
return undefined;
|
|
146
|
-
}
|
|
147
|
-
// Phase 2: Swap the authorization code for the access token
|
|
148
|
-
const tokenResponse = await this.swapAuthorizationCodeForTokens(authResponse.code, authRequest.internal.code_verifier);
|
|
149
|
-
core_bentley_1.Logger.logTrace(loggerCategory, "Authorization completed, and issued access token");
|
|
150
|
-
return tokenResponse;
|
|
151
|
-
}
|
|
152
|
-
/**
|
|
153
|
-
* Start the sign-out process
|
|
154
|
-
* - calls the onAccessTokenChanged() call back after the authorization completes
|
|
155
|
-
* or if there is an error.
|
|
156
|
-
* - redirects application to the postSignoutRedirectUri specified in the configuration when the sign out is
|
|
157
|
-
* complete
|
|
158
|
-
*/
|
|
159
|
-
async signOut() {
|
|
160
|
-
await this.makeRevokeTokenRequest();
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
|
-
* Sign out completely
|
|
164
|
-
* This is a wrapper around [[signOut]] - the only difference is that the promise resolves
|
|
165
|
-
* after the sign out is complete.
|
|
166
|
-
*/
|
|
167
|
-
async signOutComplete() {
|
|
168
|
-
return new Promise((resolve, reject) => {
|
|
169
|
-
core_backend_1.NativeHost.onAccessTokenChanged.addOnce((token) => {
|
|
170
|
-
if (token === "") {
|
|
171
|
-
resolve();
|
|
172
|
-
}
|
|
173
|
-
else {
|
|
174
|
-
reject(new Error("Failed to sign out"));
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
this.signOut().catch((err) => reject(err));
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
async clearTokenResponse() {
|
|
181
|
-
this._tokenResponse = undefined;
|
|
182
|
-
await this.tokenStore.delete();
|
|
183
|
-
this.setAccessToken("");
|
|
184
|
-
}
|
|
185
|
-
async setTokenResponse(tokenResponse) {
|
|
186
|
-
var _a;
|
|
187
|
-
const accessToken = tokenResponse.accessToken;
|
|
188
|
-
this._tokenResponse = tokenResponse;
|
|
189
|
-
const expiresAtMilliseconds = (tokenResponse.issuedAt + ((_a = tokenResponse.expiresIn) !== null && _a !== void 0 ? _a : 0)) * 1000;
|
|
190
|
-
this._expiresAt = new Date(expiresAtMilliseconds);
|
|
191
|
-
await this.tokenStore.save(this._tokenResponse);
|
|
192
|
-
const bearerToken = `${tokenResponse.tokenType} ${accessToken}`;
|
|
193
|
-
this.setAccessToken(bearerToken);
|
|
194
|
-
return bearerToken;
|
|
195
|
-
}
|
|
196
|
-
get _hasExpired() {
|
|
197
|
-
if (!this._expiresAt)
|
|
198
|
-
return false;
|
|
199
|
-
return this._expiresAt.getTime() - Date.now() <= 1 * 60 * 1000; // Consider 1 minute before expiry as expired
|
|
200
|
-
}
|
|
201
|
-
async getAccessToken() {
|
|
202
|
-
if (this._hasExpired || !this._accessToken)
|
|
203
|
-
this.setAccessToken(await this.refreshToken());
|
|
204
|
-
return this._accessToken;
|
|
205
|
-
}
|
|
206
|
-
async refreshAccessToken(refreshToken) {
|
|
207
|
-
const tokenResponse = await this.makeRefreshAccessTokenRequest(refreshToken);
|
|
208
|
-
core_bentley_1.Logger.logTrace(loggerCategory, "Refresh token completed, and issued access token");
|
|
209
|
-
return this.setTokenResponse(tokenResponse);
|
|
210
|
-
}
|
|
211
|
-
/** Swap the authorization code for a refresh token and access token */
|
|
212
|
-
async swapAuthorizationCodeForTokens(authCode, codeVerifier) {
|
|
213
|
-
if (!this._configuration)
|
|
214
|
-
throw new core_bentley_1.BentleyError(core_bentley_1.AuthStatus.Error, "Not initialized. First call initialize()");
|
|
215
|
-
(0, core_bentley_1.assert)(this.config !== undefined);
|
|
216
|
-
const nativeConfig = this.config;
|
|
217
|
-
const extras = { code_verifier: codeVerifier };
|
|
218
|
-
const tokenRequestJson = {
|
|
219
|
-
grant_type: appauth_1.GRANT_TYPE_AUTHORIZATION_CODE,
|
|
220
|
-
code: authCode,
|
|
221
|
-
redirect_uri: this.redirectUri,
|
|
222
|
-
client_id: nativeConfig.clientId,
|
|
223
|
-
extras,
|
|
224
|
-
};
|
|
225
|
-
const tokenRequest = new appauth_1.TokenRequest(tokenRequestJson);
|
|
226
|
-
const tokenRequestor = new node_support_1.NodeRequestor();
|
|
227
|
-
const tokenHandler = new appauth_1.BaseTokenRequestHandler(tokenRequestor);
|
|
228
|
-
return tokenHandler.performTokenRequest(this._configuration, tokenRequest);
|
|
229
|
-
}
|
|
230
|
-
async makeRefreshAccessTokenRequest(refreshToken) {
|
|
231
|
-
if (!this._configuration)
|
|
232
|
-
throw new core_bentley_1.BentleyError(core_bentley_1.AuthStatus.Error, "Not initialized. First call initialize()");
|
|
233
|
-
(0, core_bentley_1.assert)(this.config !== undefined);
|
|
234
|
-
const tokenRequestJson = {
|
|
235
|
-
grant_type: appauth_1.GRANT_TYPE_REFRESH_TOKEN,
|
|
236
|
-
refresh_token: refreshToken,
|
|
237
|
-
redirect_uri: this.redirectUri,
|
|
238
|
-
client_id: this.config.clientId,
|
|
239
|
-
};
|
|
240
|
-
const tokenRequest = new appauth_1.TokenRequest(tokenRequestJson);
|
|
241
|
-
const tokenRequestor = new node_support_1.NodeRequestor();
|
|
242
|
-
const tokenHandler = new appauth_1.BaseTokenRequestHandler(tokenRequestor);
|
|
243
|
-
return tokenHandler.performTokenRequest(this._configuration, tokenRequest);
|
|
244
|
-
}
|
|
245
|
-
async makeRevokeTokenRequest() {
|
|
246
|
-
if (!this._tokenResponse)
|
|
247
|
-
throw new core_bentley_1.BentleyError(core_bentley_1.AuthStatus.Error, "Missing refresh token. First call signIn() and ensure it's successful");
|
|
248
|
-
(0, core_bentley_1.assert)(this.config !== undefined);
|
|
249
|
-
const refreshToken = this._tokenResponse.refreshToken;
|
|
250
|
-
const revokeTokenRequestJson = {
|
|
251
|
-
token: refreshToken,
|
|
252
|
-
token_type_hint: "refresh_token",
|
|
253
|
-
client_id: this.config.clientId,
|
|
254
|
-
};
|
|
255
|
-
const revokeTokenRequest = new appauth_1.RevokeTokenRequest(revokeTokenRequestJson);
|
|
256
|
-
const tokenRequestor = new node_support_1.NodeRequestor();
|
|
257
|
-
const tokenHandler = new appauth_1.BaseTokenRequestHandler(tokenRequestor);
|
|
258
|
-
await tokenHandler.performRevokeTokenRequest(this._configuration, revokeTokenRequest);
|
|
259
|
-
core_bentley_1.Logger.logTrace(loggerCategory, "Authorization revoked, and removed access token");
|
|
260
|
-
await this.clearTokenResponse();
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
exports.ElectronAuthorizationBackend = ElectronAuthorizationBackend;
|
|
264
|
-
ElectronAuthorizationBackend.defaultRedirectUri = "http://localhost:3000/signin-callback";
|
|
265
|
-
//# sourceMappingURL=ElectronAuthorizationBackend.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ElectronAuthorizationBackend.js","sourceRoot":"","sources":["../../../src/backend/ElectronAuthorizationBackend.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n// Code based on the blog article @ https://authguidance.com\r\n\r\n/** @packageDocumentation\r\n * @module Authentication\r\n */\r\n\r\n// cSpell:ignore openid appauth signin Pkce Signout\r\n/* eslint-disable @typescript-eslint/naming-convention */\r\n\r\nimport { AccessToken, assert, AuthStatus, BentleyError, Logger } from \"@itwin/core-bentley\";\r\nimport { NativeAppAuthorizationBackend, NativeHost } from \"@itwin/core-backend\";\r\nimport { NativeAppAuthorizationConfiguration } from \"@itwin/core-common\";\r\nimport {\r\n AuthorizationError, AuthorizationNotifier, AuthorizationRequest, AuthorizationRequestJson, AuthorizationResponse, AuthorizationServiceConfiguration,\r\n BaseTokenRequestHandler, GRANT_TYPE_AUTHORIZATION_CODE, GRANT_TYPE_REFRESH_TOKEN, RevokeTokenRequest, RevokeTokenRequestJson, StringMap,\r\n TokenRequest, TokenRequestHandler, TokenRequestJson, TokenResponse,\r\n} from \"@openid/appauth\";\r\nimport { NodeCrypto, NodeRequestor } from \"@openid/appauth/built/node_support\";\r\nimport { ElectronAuthorizationEvents } from \"./ElectronAuthorizationEvents\";\r\nimport { ElectronAuthorizationRequestHandler } from \"./ElectronAuthorizationRequestHandler\";\r\nimport { ElectronTokenStore } from \"./ElectronTokenStore\";\r\nimport { LoopbackWebServer } from \"./LoopbackWebServer\";\r\n\r\nconst loggerCategory = \"electron-auth\";\r\n\r\n/**\r\n * Utility to generate OIDC/OAuth tokens for Desktop Applications\r\n * @beta\r\n */\r\nexport class ElectronAuthorizationBackend extends NativeAppAuthorizationBackend {\r\n public static defaultRedirectUri = \"http://localhost:3000/signin-callback\";\r\n private _configuration: AuthorizationServiceConfiguration | undefined;\r\n private _tokenResponse: TokenResponse | undefined;\r\n private _tokenStore?: ElectronTokenStore;\r\n private _expiresAt?: Date;\r\n public get tokenStore() { return this._tokenStore!; }\r\n\r\n public constructor(config?: NativeAppAuthorizationConfiguration) {\r\n super(config);\r\n }\r\n\r\n public get redirectUri() { return this.config?.redirectUri ?? ElectronAuthorizationBackend.defaultRedirectUri; }\r\n\r\n /**\r\n * Used to initialize the client - must be awaited before any other methods are called.\r\n * The call attempts a silent sign-if possible.\r\n */\r\n public override async initialize(config?: NativeAppAuthorizationConfiguration): Promise<void> {\r\n await super.initialize(config);\r\n assert(this.config !== undefined && this.issuerUrl !== undefined, \"URL of authorization provider was not initialized\");\r\n\r\n this._tokenStore = new ElectronTokenStore(this.config.clientId);\r\n\r\n const tokenRequestor = new NodeRequestor(); // the Node.js based HTTP client\r\n this._configuration = await AuthorizationServiceConfiguration.fetchFromIssuer(this.issuerUrl, tokenRequestor);\r\n Logger.logTrace(loggerCategory, \"Initialized service configuration\", () => ({ configuration: this._configuration }));\r\n\r\n // Attempt to load the access token from store\r\n await this.loadAccessToken();\r\n }\r\n\r\n public async refreshToken(): Promise<AccessToken> {\r\n if (this._tokenResponse === undefined || this._tokenResponse.refreshToken === undefined)\r\n return \"\";\r\n\r\n const token = `Bearer ${this._tokenResponse.refreshToken}`;\r\n return this.refreshAccessToken(token);\r\n }\r\n\r\n /** Loads the access token from the store, and refreshes it if necessary and possible\r\n * @return AccessToken if it's possible to get a valid access token, and undefined otherwise.\r\n */\r\n private async loadAccessToken(): Promise<AccessToken> {\r\n const tokenResponse = await this.tokenStore.load();\r\n if (tokenResponse === undefined || tokenResponse.refreshToken === undefined)\r\n return \"\";\r\n try {\r\n return await this.refreshAccessToken(tokenResponse.refreshToken);\r\n } catch (err) {\r\n return \"\";\r\n }\r\n }\r\n\r\n /**\r\n * Sign-in completely.\r\n * This is a wrapper around [[signIn]] - the only difference is that the promise resolves\r\n * with the access token after sign in is complete and successful.\r\n */\r\n public async signInComplete(): Promise<AccessToken> {\r\n return new Promise<AccessToken>((resolve, reject) => {\r\n NativeHost.onAccessTokenChanged.addOnce((token) => {\r\n if (token !== \"\") {\r\n resolve(token);\r\n } else {\r\n reject(new Error(\"Failed to sign in\"));\r\n }\r\n });\r\n this.signIn().catch((err) => reject(err));\r\n });\r\n }\r\n\r\n /**\r\n * Start the sign-in process\r\n * - calls the onAccessTokenChanged() call back after the authorization completes\r\n * or if there is an error.\r\n * - will attempt in order:\r\n * (i) load any existing authorized user from storage,\r\n * (ii) an interactive signin that requires user input.\r\n */\r\n public async signIn(): Promise<void> {\r\n if (!this._configuration)\r\n throw new BentleyError(AuthStatus.Error, \"Not initialized. First call initialize()\");\r\n assert(this.config !== undefined);\r\n\r\n // Attempt to load the access token from store\r\n const token = await this.loadAccessToken();\r\n if (token)\r\n return this.setAccessToken(token);\r\n\r\n // Create the authorization request\r\n const nativeConfig = this.config;\r\n const authReqJson: AuthorizationRequestJson = {\r\n client_id: nativeConfig.clientId,\r\n redirect_uri: this.redirectUri,\r\n scope: nativeConfig.scope,\r\n response_type: AuthorizationRequest.RESPONSE_TYPE_CODE,\r\n extras: { prompt: \"consent\", access_type: \"offline\" },\r\n };\r\n const authorizationRequest = new AuthorizationRequest(authReqJson, new NodeCrypto(), true /* = usePkce */);\r\n await authorizationRequest.setupCodeVerifier();\r\n\r\n // Create events for this signin attempt\r\n const authorizationEvents = new ElectronAuthorizationEvents();\r\n\r\n // Ensure that completion callbacks are correlated to the correct authorization request\r\n LoopbackWebServer.addCorrelationState(authorizationRequest.state, authorizationEvents);\r\n\r\n // Start a web server to listen to the browser requests\r\n LoopbackWebServer.start(nativeConfig);\r\n\r\n const authorizationHandler = new ElectronAuthorizationRequestHandler(authorizationEvents);\r\n\r\n // Setup a notifier to obtain the result of authorization\r\n const notifier = new AuthorizationNotifier();\r\n authorizationHandler.setAuthorizationNotifier(notifier);\r\n notifier.setAuthorizationListener(async (authRequest: AuthorizationRequest, authResponse: AuthorizationResponse | null, authError: AuthorizationError | null) => {\r\n Logger.logTrace(loggerCategory, \"Authorization listener invoked\", () => ({ authRequest, authResponse, authError }));\r\n\r\n const tokenResponse = await this._onAuthorizationResponse(authRequest, authResponse, authError);\r\n\r\n authorizationEvents.onAuthorizationResponseCompleted.raiseEvent(authError ? authError : undefined);\r\n\r\n if (!tokenResponse)\r\n await this.clearTokenResponse();\r\n else\r\n await this.setTokenResponse(tokenResponse);\r\n });\r\n\r\n // Start the signin\r\n await authorizationHandler.performAuthorizationRequest(this._configuration, authorizationRequest);\r\n }\r\n\r\n private async _onAuthorizationResponse(authRequest: AuthorizationRequest, authResponse: AuthorizationResponse | null, authError: AuthorizationError | null): Promise<TokenResponse | undefined> {\r\n\r\n // Phase 1 of login has completed to fetch the authorization code - check for errors\r\n if (authError) {\r\n Logger.logError(loggerCategory, \"Authorization error. Unable to get authorization code.\", () => authError);\r\n return undefined;\r\n }\r\n\r\n if (!authResponse || authResponse.state !== authRequest.state) {\r\n Logger.logError(loggerCategory, \"Authorization error. Unable to get authorization code\", () => ({\r\n error: \"invalid_state\",\r\n errorDescription: \"The login response state did not match the login request state.\",\r\n }));\r\n return undefined;\r\n }\r\n\r\n // Phase 2: Swap the authorization code for the access token\r\n const tokenResponse = await this.swapAuthorizationCodeForTokens(authResponse.code, authRequest.internal!.code_verifier);\r\n Logger.logTrace(loggerCategory, \"Authorization completed, and issued access token\");\r\n return tokenResponse;\r\n }\r\n\r\n /**\r\n * Start the sign-out process\r\n * - calls the onAccessTokenChanged() call back after the authorization completes\r\n * or if there is an error.\r\n * - redirects application to the postSignoutRedirectUri specified in the configuration when the sign out is\r\n * complete\r\n */\r\n public async signOut(): Promise<void> {\r\n await this.makeRevokeTokenRequest();\r\n }\r\n\r\n /**\r\n * Sign out completely\r\n * This is a wrapper around [[signOut]] - the only difference is that the promise resolves\r\n * after the sign out is complete.\r\n */\r\n public async signOutComplete(): Promise<void> {\r\n return new Promise<void>((resolve, reject) => {\r\n NativeHost.onAccessTokenChanged.addOnce((token) => {\r\n if (token === \"\") {\r\n resolve();\r\n } else {\r\n reject(new Error(\"Failed to sign out\"));\r\n }\r\n });\r\n this.signOut().catch((err) => reject(err));\r\n });\r\n }\r\n\r\n private async clearTokenResponse() {\r\n this._tokenResponse = undefined;\r\n await this.tokenStore.delete();\r\n this.setAccessToken(\"\");\r\n }\r\n\r\n private async setTokenResponse(tokenResponse: TokenResponse): Promise<AccessToken> {\r\n const accessToken = tokenResponse.accessToken;\r\n this._tokenResponse = tokenResponse;\r\n const expiresAtMilliseconds = (tokenResponse.issuedAt + (tokenResponse.expiresIn ?? 0)) * 1000;\r\n this._expiresAt = new Date(expiresAtMilliseconds);\r\n\r\n await this.tokenStore.save(this._tokenResponse);\r\n const bearerToken = `${tokenResponse.tokenType} ${accessToken}`;\r\n this.setAccessToken(bearerToken);\r\n return bearerToken;\r\n }\r\n\r\n private get _hasExpired(): boolean {\r\n if (!this._expiresAt)\r\n return false;\r\n\r\n return this._expiresAt.getTime() - Date.now() <= 1 * 60 * 1000; // Consider 1 minute before expiry as expired\r\n }\r\n\r\n public override async getAccessToken(): Promise<AccessToken> {\r\n if (this._hasExpired || !this._accessToken)\r\n this.setAccessToken(await this.refreshToken());\r\n return this._accessToken;\r\n }\r\n\r\n private async refreshAccessToken(refreshToken: string): Promise<AccessToken> {\r\n const tokenResponse = await this.makeRefreshAccessTokenRequest(refreshToken);\r\n Logger.logTrace(loggerCategory, \"Refresh token completed, and issued access token\");\r\n return this.setTokenResponse(tokenResponse);\r\n }\r\n\r\n /** Swap the authorization code for a refresh token and access token */\r\n private async swapAuthorizationCodeForTokens(authCode: string, codeVerifier: string): Promise<TokenResponse> {\r\n if (!this._configuration)\r\n throw new BentleyError(AuthStatus.Error, \"Not initialized. First call initialize()\");\r\n assert(this.config !== undefined);\r\n\r\n const nativeConfig = this.config;\r\n const extras: StringMap = { code_verifier: codeVerifier };\r\n const tokenRequestJson: TokenRequestJson = {\r\n grant_type: GRANT_TYPE_AUTHORIZATION_CODE,\r\n code: authCode,\r\n redirect_uri: this.redirectUri,\r\n client_id: nativeConfig.clientId,\r\n extras,\r\n };\r\n\r\n const tokenRequest = new TokenRequest(tokenRequestJson);\r\n const tokenRequestor = new NodeRequestor();\r\n const tokenHandler: TokenRequestHandler = new BaseTokenRequestHandler(tokenRequestor);\r\n return tokenHandler.performTokenRequest(this._configuration, tokenRequest);\r\n }\r\n\r\n private async makeRefreshAccessTokenRequest(refreshToken: string): Promise<TokenResponse> {\r\n if (!this._configuration)\r\n throw new BentleyError(AuthStatus.Error, \"Not initialized. First call initialize()\");\r\n assert(this.config !== undefined);\r\n\r\n const tokenRequestJson: TokenRequestJson = {\r\n grant_type: GRANT_TYPE_REFRESH_TOKEN,\r\n refresh_token: refreshToken,\r\n redirect_uri: this.redirectUri,\r\n client_id: this.config.clientId,\r\n };\r\n\r\n const tokenRequest = new TokenRequest(tokenRequestJson);\r\n const tokenRequestor = new NodeRequestor();\r\n const tokenHandler: TokenRequestHandler = new BaseTokenRequestHandler(tokenRequestor);\r\n return tokenHandler.performTokenRequest(this._configuration, tokenRequest);\r\n }\r\n\r\n private async makeRevokeTokenRequest(): Promise<void> {\r\n if (!this._tokenResponse)\r\n throw new BentleyError(AuthStatus.Error, \"Missing refresh token. First call signIn() and ensure it's successful\");\r\n assert(this.config !== undefined);\r\n\r\n const refreshToken = this._tokenResponse.refreshToken!;\r\n\r\n const revokeTokenRequestJson: RevokeTokenRequestJson = {\r\n token: refreshToken,\r\n token_type_hint: \"refresh_token\",\r\n client_id: this.config.clientId,\r\n };\r\n\r\n const revokeTokenRequest = new RevokeTokenRequest(revokeTokenRequestJson);\r\n const tokenRequestor = new NodeRequestor();\r\n const tokenHandler: TokenRequestHandler = new BaseTokenRequestHandler(tokenRequestor);\r\n await tokenHandler.performRevokeTokenRequest(this._configuration!, revokeTokenRequest);\r\n\r\n Logger.logTrace(loggerCategory, \"Authorization revoked, and removed access token\");\r\n await this.clearTokenResponse();\r\n }\r\n}\r\n"]}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/** @packageDocumentation
|
|
2
|
-
* @module Authentication
|
|
3
|
-
*/
|
|
4
|
-
import { BeEvent } from "@itwin/core-bentley";
|
|
5
|
-
import { AuthorizationErrorJson, AuthorizationResponseJson } from "@openid/appauth";
|
|
6
|
-
/** @internal */
|
|
7
|
-
export declare type AuthorizationResponseCompletedListener = (error?: AuthorizationErrorJson) => void;
|
|
8
|
-
/** @internal */
|
|
9
|
-
export declare type AuthorizationResponseListener = (error: AuthorizationErrorJson | null, response: AuthorizationResponseJson | null) => void;
|
|
10
|
-
/**
|
|
11
|
-
* Internal events used by authorization by DesktopAuthorizationClient and related classes
|
|
12
|
-
* @internal
|
|
13
|
-
*/
|
|
14
|
-
export declare class ElectronAuthorizationEvents {
|
|
15
|
-
/** Event raised when the authorization is completed */
|
|
16
|
-
readonly onAuthorizationResponseCompleted: BeEvent<AuthorizationResponseCompletedListener>;
|
|
17
|
-
/** Event raised when a response is received from the authorization server with the authorization code */
|
|
18
|
-
readonly onAuthorizationResponse: BeEvent<AuthorizationResponseListener>;
|
|
19
|
-
}
|
|
20
|
-
//# sourceMappingURL=ElectronAuthorizationEvents.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ElectronAuthorizationEvents.d.ts","sourceRoot":"","sources":["../../../src/backend/ElectronAuthorizationEvents.ts"],"names":[],"mappings":"AAMA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAEpF,gBAAgB;AAChB,oBAAY,sCAAsC,GAAG,CAAC,KAAK,CAAC,EAAE,sBAAsB,KAAK,IAAI,CAAC;AAE9F,gBAAgB;AAChB,oBAAY,6BAA6B,GAAG,CAAC,KAAK,EAAE,sBAAsB,GAAG,IAAI,EAAE,QAAQ,EAAE,yBAAyB,GAAG,IAAI,KAAK,IAAI,CAAC;AAEvI;;;GAGG;AACH,qBAAa,2BAA2B;IACtC,uDAAuD;IACvD,SAAgB,gCAAgC,kDAAyD;IAEzG,yGAAyG;IACzG,SAAgB,uBAAuB,yCAAgD;CACxF"}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*---------------------------------------------------------------------------------------------
|
|
3
|
-
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
4
|
-
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
5
|
-
*--------------------------------------------------------------------------------------------*/
|
|
6
|
-
// Code based on the blog article @ https://authguidance.com
|
|
7
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.ElectronAuthorizationEvents = void 0;
|
|
9
|
-
/** @packageDocumentation
|
|
10
|
-
* @module Authentication
|
|
11
|
-
*/
|
|
12
|
-
const core_bentley_1 = require("@itwin/core-bentley");
|
|
13
|
-
/**
|
|
14
|
-
* Internal events used by authorization by DesktopAuthorizationClient and related classes
|
|
15
|
-
* @internal
|
|
16
|
-
*/
|
|
17
|
-
class ElectronAuthorizationEvents {
|
|
18
|
-
constructor() {
|
|
19
|
-
/** Event raised when the authorization is completed */
|
|
20
|
-
this.onAuthorizationResponseCompleted = new core_bentley_1.BeEvent();
|
|
21
|
-
/** Event raised when a response is received from the authorization server with the authorization code */
|
|
22
|
-
this.onAuthorizationResponse = new core_bentley_1.BeEvent();
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
exports.ElectronAuthorizationEvents = ElectronAuthorizationEvents;
|
|
26
|
-
//# sourceMappingURL=ElectronAuthorizationEvents.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ElectronAuthorizationEvents.js","sourceRoot":"","sources":["../../../src/backend/ElectronAuthorizationEvents.ts"],"names":[],"mappings":";AAAA;;;+FAG+F;AAC/F,4DAA4D;;;AAE5D;;GAEG;AAEH,sDAA8C;AAS9C;;;GAGG;AACH,MAAa,2BAA2B;IAAxC;QACE,uDAAuD;QACvC,qCAAgC,GAAG,IAAI,sBAAO,EAA0C,CAAC;QAEzG,yGAAyG;QACzF,4BAAuB,GAAG,IAAI,sBAAO,EAAiC,CAAC;IACzF,CAAC;CAAA;AAND,kEAMC","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n// Code based on the blog article @ https://authguidance.com\r\n\r\n/** @packageDocumentation\r\n * @module Authentication\r\n */\r\n\r\nimport { BeEvent } from \"@itwin/core-bentley\";\r\nimport { AuthorizationErrorJson, AuthorizationResponseJson } from \"@openid/appauth\";\r\n\r\n/** @internal */\r\nexport type AuthorizationResponseCompletedListener = (error?: AuthorizationErrorJson) => void;\r\n\r\n/** @internal */\r\nexport type AuthorizationResponseListener = (error: AuthorizationErrorJson | null, response: AuthorizationResponseJson | null) => void;\r\n\r\n/**\r\n * Internal events used by authorization by DesktopAuthorizationClient and related classes\r\n * @internal\r\n */\r\nexport class ElectronAuthorizationEvents {\r\n /** Event raised when the authorization is completed */\r\n public readonly onAuthorizationResponseCompleted = new BeEvent<AuthorizationResponseCompletedListener>();\r\n\r\n /** Event raised when a response is received from the authorization server with the authorization code */\r\n public readonly onAuthorizationResponse = new BeEvent<AuthorizationResponseListener>();\r\n}\r\n"]}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { AuthorizationRequest, AuthorizationRequestHandler, AuthorizationRequestResponse, AuthorizationServiceConfiguration } from "@openid/appauth";
|
|
2
|
-
import { ElectronAuthorizationEvents } from "./ElectronAuthorizationEvents";
|
|
3
|
-
/**
|
|
4
|
-
* Utility to setup a local web server that listens to authorization responses to the browser and make the necessary redirections
|
|
5
|
-
* @internal
|
|
6
|
-
*/
|
|
7
|
-
export declare class ElectronAuthorizationRequestHandler extends AuthorizationRequestHandler {
|
|
8
|
-
private _authorizationPromise;
|
|
9
|
-
private _authorizationEvents;
|
|
10
|
-
/**
|
|
11
|
-
* Constructor
|
|
12
|
-
*/
|
|
13
|
-
constructor(authorizationEvents: ElectronAuthorizationEvents);
|
|
14
|
-
/**
|
|
15
|
-
* Makes an authorization request on the system browser
|
|
16
|
-
*/
|
|
17
|
-
performAuthorizationRequest(serviceConfiguration: AuthorizationServiceConfiguration, authRequest: AuthorizationRequest): Promise<void>;
|
|
18
|
-
/**
|
|
19
|
-
* Checks if an authorization flow can be completed, and completes it.
|
|
20
|
-
* The handler returns a `Promise<AuthorizationRequestResponse>` if ready, or a `Promise<null>`
|
|
21
|
-
* if not ready.
|
|
22
|
-
*/
|
|
23
|
-
protected completeAuthorizationRequest(): Promise<AuthorizationRequestResponse | null>;
|
|
24
|
-
}
|
|
25
|
-
//# sourceMappingURL=ElectronAuthorizationRequestHandler.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ElectronAuthorizationRequestHandler.d.ts","sourceRoot":"","sources":["../../../src/backend/ElectronAuthorizationRequestHandler.ts"],"names":[],"mappings":"AAYA,OAAO,EACuC,oBAAoB,EAAE,2BAA2B,EAAE,4BAA4B,EAChG,iCAAiC,EAC7D,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAE5E;;;GAGG;AACH,qBAAa,mCAAoC,SAAQ,2BAA2B;IAClF,OAAO,CAAC,qBAAqB,CAAsD;IACnF,OAAO,CAAC,oBAAoB,CAA8B;IAE1D;;OAEG;gBACgB,mBAAmB,EAAE,2BAA2B;IAKnE;;OAEG;IACU,2BAA2B,CAAC,oBAAoB,EAAE,iCAAiC,EAAE,WAAW,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IA2BnJ;;;;OAIG;cACa,4BAA4B,IAAI,OAAO,CAAC,4BAA4B,GAAG,IAAI,CAAC;CAG7F"}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*---------------------------------------------------------------------------------------------
|
|
3
|
-
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
4
|
-
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
5
|
-
*--------------------------------------------------------------------------------------------*/
|
|
6
|
-
// Code based on the blog article @ https://authguidance.com
|
|
7
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.ElectronAuthorizationRequestHandler = void 0;
|
|
9
|
-
/** @packageDocumentation
|
|
10
|
-
* @module Authentication
|
|
11
|
-
*/
|
|
12
|
-
const open = require("open");
|
|
13
|
-
const core_bentley_1 = require("@itwin/core-bentley");
|
|
14
|
-
const appauth_1 = require("@openid/appauth");
|
|
15
|
-
const node_support_1 = require("@openid/appauth/built/node_support");
|
|
16
|
-
/**
|
|
17
|
-
* Utility to setup a local web server that listens to authorization responses to the browser and make the necessary redirections
|
|
18
|
-
* @internal
|
|
19
|
-
*/
|
|
20
|
-
class ElectronAuthorizationRequestHandler extends appauth_1.AuthorizationRequestHandler {
|
|
21
|
-
/**
|
|
22
|
-
* Constructor
|
|
23
|
-
*/
|
|
24
|
-
constructor(authorizationEvents) {
|
|
25
|
-
super(new appauth_1.BasicQueryStringUtils(), new node_support_1.NodeCrypto());
|
|
26
|
-
this._authorizationPromise = null;
|
|
27
|
-
this._authorizationEvents = authorizationEvents;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Makes an authorization request on the system browser
|
|
31
|
-
*/
|
|
32
|
-
async performAuthorizationRequest(serviceConfiguration, authRequest) {
|
|
33
|
-
core_bentley_1.Logger.logTrace("electron-auth", "Making authorization request", () => ({ serviceConfiguration, authRequest }));
|
|
34
|
-
// Setup a promise to process the authorization response
|
|
35
|
-
this._authorizationPromise = new Promise((resolve, _reject) => {
|
|
36
|
-
// Wrap the response from the web browser (with the authorization code)
|
|
37
|
-
this._authorizationEvents.onAuthorizationResponse.addOnce((authErrorJson, authResponseJson) => {
|
|
38
|
-
// Resolve the full response including the request
|
|
39
|
-
const authRequestResponse = {
|
|
40
|
-
request: authRequest,
|
|
41
|
-
error: authErrorJson ? new appauth_1.AuthorizationError(authErrorJson) : null,
|
|
42
|
-
response: authResponseJson ? new appauth_1.AuthorizationResponse(authResponseJson) : null,
|
|
43
|
-
};
|
|
44
|
-
resolve(authRequestResponse);
|
|
45
|
-
// Ask the base class to call our completeAuthorizationRequest - this calls the registered notifier to broadcast the event outside of the client
|
|
46
|
-
this.completeAuthorizationRequestIfPossible(); // eslint-disable-line @typescript-eslint/no-floating-promises
|
|
47
|
-
});
|
|
48
|
-
});
|
|
49
|
-
// Compose the request and invoke in the browser
|
|
50
|
-
const authUrl = this.buildRequestUrl(serviceConfiguration, authRequest);
|
|
51
|
-
await open(authUrl);
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Checks if an authorization flow can be completed, and completes it.
|
|
55
|
-
* The handler returns a `Promise<AuthorizationRequestResponse>` if ready, or a `Promise<null>`
|
|
56
|
-
* if not ready.
|
|
57
|
-
*/
|
|
58
|
-
async completeAuthorizationRequest() {
|
|
59
|
-
return this._authorizationPromise;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
exports.ElectronAuthorizationRequestHandler = ElectronAuthorizationRequestHandler;
|
|
63
|
-
//# sourceMappingURL=ElectronAuthorizationRequestHandler.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ElectronAuthorizationRequestHandler.js","sourceRoot":"","sources":["../../../src/backend/ElectronAuthorizationRequestHandler.ts"],"names":[],"mappings":";AAAA;;;+FAG+F;AAC/F,4DAA4D;;;AAE5D;;GAEG;AAEH,6BAA6B;AAC7B,sDAA6C;AAC7C,6CAGyB;AACzB,qEAAgE;AAGhE;;;GAGG;AACH,MAAa,mCAAoC,SAAQ,qCAA2B;IAIlF;;OAEG;IACH,YAAmB,mBAAgD;QACjE,KAAK,CAAC,IAAI,+BAAqB,EAAE,EAAE,IAAI,yBAAU,EAAE,CAAC,CAAC;QAP/C,0BAAqB,GAAiD,IAAI,CAAC;QAQjF,IAAI,CAAC,oBAAoB,GAAG,mBAAmB,CAAC;IAClD,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,2BAA2B,CAAC,oBAAuD,EAAE,WAAiC;QACjI,qBAAM,CAAC,QAAQ,CAAC,eAAe,EAAE,8BAA8B,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,oBAAoB,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC;QAEhH,wDAAwD;QACxD,IAAI,CAAC,qBAAqB,GAAG,IAAI,OAAO,CAA+B,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE;YAE1F,uEAAuE;YACvE,IAAI,CAAC,oBAAoB,CAAC,uBAAuB,CAAC,OAAO,CAAC,CAAC,aAA4C,EAAE,gBAAkD,EAAE,EAAE;gBAE7J,kDAAkD;gBAClD,MAAM,mBAAmB,GAAiC;oBACxD,OAAO,EAAE,WAAW;oBACpB,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,IAAI,4BAAkB,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,IAAI;oBACnE,QAAQ,EAAE,gBAAgB,CAAC,CAAC,CAAC,IAAI,+BAAqB,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,IAAI;iBAChF,CAAC;gBACF,OAAO,CAAC,mBAAmB,CAAC,CAAC;gBAE7B,gJAAgJ;gBAChJ,IAAI,CAAC,sCAAsC,EAAE,CAAC,CAAC,8DAA8D;YAC/G,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,gDAAgD;QAChD,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAAC;QACxE,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC;IACtB,CAAC;IAED;;;;OAIG;IACO,KAAK,CAAC,4BAA4B;QAC1C,OAAO,IAAI,CAAC,qBAAqB,CAAC;IACpC,CAAC;CACF;AAlDD,kFAkDC","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n// Code based on the blog article @ https://authguidance.com\r\n\r\n/** @packageDocumentation\r\n * @module Authentication\r\n */\r\n\r\nimport * as open from \"open\";\r\nimport { Logger } from \"@itwin/core-bentley\";\r\nimport {\r\n AuthorizationError, AuthorizationErrorJson, AuthorizationRequest, AuthorizationRequestHandler, AuthorizationRequestResponse, AuthorizationResponse,\r\n AuthorizationResponseJson, AuthorizationServiceConfiguration, BasicQueryStringUtils,\r\n} from \"@openid/appauth\";\r\nimport { NodeCrypto } from \"@openid/appauth/built/node_support\";\r\nimport { ElectronAuthorizationEvents } from \"./ElectronAuthorizationEvents\";\r\n\r\n/**\r\n * Utility to setup a local web server that listens to authorization responses to the browser and make the necessary redirections\r\n * @internal\r\n */\r\nexport class ElectronAuthorizationRequestHandler extends AuthorizationRequestHandler {\r\n private _authorizationPromise: Promise<AuthorizationRequestResponse> | null = null;\r\n private _authorizationEvents: ElectronAuthorizationEvents;\r\n\r\n /**\r\n * Constructor\r\n */\r\n public constructor(authorizationEvents: ElectronAuthorizationEvents) {\r\n super(new BasicQueryStringUtils(), new NodeCrypto());\r\n this._authorizationEvents = authorizationEvents;\r\n }\r\n\r\n /**\r\n * Makes an authorization request on the system browser\r\n */\r\n public async performAuthorizationRequest(serviceConfiguration: AuthorizationServiceConfiguration, authRequest: AuthorizationRequest): Promise<void> {\r\n Logger.logTrace(\"electron-auth\", \"Making authorization request\", () => ({ serviceConfiguration, authRequest }));\r\n\r\n // Setup a promise to process the authorization response\r\n this._authorizationPromise = new Promise<AuthorizationRequestResponse>((resolve, _reject) => {\r\n\r\n // Wrap the response from the web browser (with the authorization code)\r\n this._authorizationEvents.onAuthorizationResponse.addOnce((authErrorJson: AuthorizationErrorJson | null, authResponseJson: AuthorizationResponseJson | null) => {\r\n\r\n // Resolve the full response including the request\r\n const authRequestResponse: AuthorizationRequestResponse = {\r\n request: authRequest,\r\n error: authErrorJson ? new AuthorizationError(authErrorJson) : null,\r\n response: authResponseJson ? new AuthorizationResponse(authResponseJson) : null,\r\n };\r\n resolve(authRequestResponse);\r\n\r\n // Ask the base class to call our completeAuthorizationRequest - this calls the registered notifier to broadcast the event outside of the client\r\n this.completeAuthorizationRequestIfPossible(); // eslint-disable-line @typescript-eslint/no-floating-promises\r\n });\r\n });\r\n\r\n // Compose the request and invoke in the browser\r\n const authUrl = this.buildRequestUrl(serviceConfiguration, authRequest);\r\n await open(authUrl);\r\n }\r\n\r\n /**\r\n * Checks if an authorization flow can be completed, and completes it.\r\n * The handler returns a `Promise<AuthorizationRequestResponse>` if ready, or a `Promise<null>`\r\n * if not ready.\r\n */\r\n protected async completeAuthorizationRequest(): Promise<AuthorizationRequestResponse | null> {\r\n return this._authorizationPromise;\r\n }\r\n}\r\n"]}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { TokenResponse } from "@openid/appauth";
|
|
2
|
-
/**
|
|
3
|
-
* Utility to store OIDC AppAuth in secure storage
|
|
4
|
-
* @internal
|
|
5
|
-
*/
|
|
6
|
-
export declare class ElectronTokenStore {
|
|
7
|
-
private _appStorageKey;
|
|
8
|
-
constructor(clientId: string);
|
|
9
|
-
private _userName?;
|
|
10
|
-
private getUserName;
|
|
11
|
-
/** Load token if available */
|
|
12
|
-
load(): Promise<TokenResponse | undefined>;
|
|
13
|
-
/** Save token after signin */
|
|
14
|
-
save(tokenResponse: TokenResponse): Promise<void>;
|
|
15
|
-
/** Delete token after signout */
|
|
16
|
-
delete(): Promise<void>;
|
|
17
|
-
}
|
|
18
|
-
//# sourceMappingURL=ElectronTokenStore.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ElectronTokenStore.d.ts","sourceRoot":"","sources":["../../../src/backend/ElectronTokenStore.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,aAAa,EAAqB,MAAM,iBAAiB,CAAC;AAGnE;;;GAGG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,cAAc,CAAS;gBAEZ,QAAQ,EAAE,MAAM;IAInC,OAAO,CAAC,SAAS,CAAC,CAAS;YACb,WAAW;IAMzB,8BAA8B;IACjB,IAAI,IAAI,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC;IAiBvD,8BAA8B;IACjB,IAAI,CAAC,aAAa,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB9D,iCAAiC;IACpB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CAUrC"}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*---------------------------------------------------------------------------------------------
|
|
3
|
-
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
4
|
-
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
5
|
-
*--------------------------------------------------------------------------------------------*/
|
|
6
|
-
// Code based on the blog article @ https://authguidance.com
|
|
7
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.ElectronTokenStore = void 0;
|
|
9
|
-
/** @packageDocumentation
|
|
10
|
-
* @module Authentication
|
|
11
|
-
*/
|
|
12
|
-
const OperatingSystemUserName = require("username");
|
|
13
|
-
const appauth_1 = require("@openid/appauth");
|
|
14
|
-
const core_backend_1 = require("@itwin/core-backend");
|
|
15
|
-
/**
|
|
16
|
-
* Utility to store OIDC AppAuth in secure storage
|
|
17
|
-
* @internal
|
|
18
|
-
*/
|
|
19
|
-
class ElectronTokenStore {
|
|
20
|
-
constructor(clientId) {
|
|
21
|
-
this._appStorageKey = `Bentley.iModelJs.OidcTokenStore.${clientId}`;
|
|
22
|
-
}
|
|
23
|
-
async getUserName() {
|
|
24
|
-
if (!this._userName)
|
|
25
|
-
this._userName = await OperatingSystemUserName();
|
|
26
|
-
return this._userName;
|
|
27
|
-
}
|
|
28
|
-
/** Load token if available */
|
|
29
|
-
async load() {
|
|
30
|
-
if (undefined === core_backend_1.IModelHost.platform.KeyTar) // no keytar on Linux yet
|
|
31
|
-
return undefined;
|
|
32
|
-
const userName = await this.getUserName();
|
|
33
|
-
if (!userName)
|
|
34
|
-
return;
|
|
35
|
-
const tokenResponseStr = await core_backend_1.IModelHost.platform.KeyTar.getPassword(this._appStorageKey, userName);
|
|
36
|
-
if (!tokenResponseStr) {
|
|
37
|
-
return undefined;
|
|
38
|
-
}
|
|
39
|
-
const tokenResponseJson = JSON.parse(tokenResponseStr);
|
|
40
|
-
return new appauth_1.TokenResponse(tokenResponseJson);
|
|
41
|
-
}
|
|
42
|
-
/** Save token after signin */
|
|
43
|
-
async save(tokenResponse) {
|
|
44
|
-
if (undefined === core_backend_1.IModelHost.platform.KeyTar) // no keytar on Linux yet
|
|
45
|
-
return;
|
|
46
|
-
const userName = await this.getUserName();
|
|
47
|
-
if (!userName)
|
|
48
|
-
return;
|
|
49
|
-
const tokenResponseObj = new appauth_1.TokenResponse(tokenResponse.toJson()); // Workaround for 'stub received bad data' error on windows - see https://github.com/atom/node-keytar/issues/112
|
|
50
|
-
tokenResponseObj.accessToken = "";
|
|
51
|
-
tokenResponseObj.idToken = "";
|
|
52
|
-
const tokenResponseStr = JSON.stringify(tokenResponseObj.toJson());
|
|
53
|
-
await core_backend_1.IModelHost.platform.KeyTar.setPassword(this._appStorageKey, userName, tokenResponseStr);
|
|
54
|
-
}
|
|
55
|
-
/** Delete token after signout */
|
|
56
|
-
async delete() {
|
|
57
|
-
if (undefined === core_backend_1.IModelHost.platform.KeyTar) // no keytar on Linux yet
|
|
58
|
-
return;
|
|
59
|
-
const userName = await this.getUserName();
|
|
60
|
-
if (!userName)
|
|
61
|
-
return;
|
|
62
|
-
await core_backend_1.IModelHost.platform.KeyTar.deletePassword(this._appStorageKey, userName);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
exports.ElectronTokenStore = ElectronTokenStore;
|
|
66
|
-
//# sourceMappingURL=ElectronTokenStore.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ElectronTokenStore.js","sourceRoot":"","sources":["../../../src/backend/ElectronTokenStore.ts"],"names":[],"mappings":";AAAA;;;+FAG+F;AAC/F,4DAA4D;;;AAE5D;;GAEG;AAEH,oDAAoD;AACpD,6CAAmE;AACnE,sDAAiD;AAEjD;;;GAGG;AACH,MAAa,kBAAkB;IAG7B,YAAmB,QAAgB;QACjC,IAAI,CAAC,cAAc,GAAG,mCAAmC,QAAQ,EAAE,CAAC;IACtE,CAAC;IAGO,KAAK,CAAC,WAAW;QACvB,IAAI,CAAC,IAAI,CAAC,SAAS;YACjB,IAAI,CAAC,SAAS,GAAG,MAAM,uBAAuB,EAAE,CAAC;QACnD,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED,8BAA8B;IACvB,KAAK,CAAC,IAAI;QACf,IAAI,SAAS,KAAK,yBAAU,CAAC,QAAQ,CAAC,MAAM,EAAE,yBAAyB;YACrE,OAAO,SAAS,CAAC;QAEnB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QAC1C,IAAI,CAAC,QAAQ;YACX,OAAO;QAET,MAAM,gBAAgB,GAAG,MAAM,yBAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC;QACrG,IAAI,CAAC,gBAAgB,EAAE;YACrB,OAAO,SAAS,CAAC;SAClB;QAED,MAAM,iBAAiB,GAAG,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAsB,CAAC;QAC5E,OAAO,IAAI,uBAAa,CAAC,iBAAiB,CAAC,CAAC;IAC9C,CAAC;IAED,8BAA8B;IACvB,KAAK,CAAC,IAAI,CAAC,aAA4B;QAC5C,IAAI,SAAS,KAAK,yBAAU,CAAC,QAAQ,CAAC,MAAM,EAAE,yBAAyB;YACrE,OAAO;QAET,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QAC1C,IAAI,CAAC,QAAQ;YACX,OAAO;QAET,MAAM,gBAAgB,GAAG,IAAI,uBAAa,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,gHAAgH;QACpL,gBAAgB,CAAC,WAAW,GAAG,EAAE,CAAC;QAClC,gBAAgB,CAAC,OAAO,GAAG,EAAE,CAAC;QAE9B,MAAM,gBAAgB,GAAG,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,MAAM,EAAE,CAAC,CAAC;QACnE,MAAM,yBAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,cAAc,EAAE,QAAQ,EAAE,gBAAgB,CAAC,CAAC;IAChG,CAAC;IAED,iCAAiC;IAC1B,KAAK,CAAC,MAAM;QACjB,IAAI,SAAS,KAAK,yBAAU,CAAC,QAAQ,CAAC,MAAM,EAAE,yBAAyB;YACrE,OAAO;QAET,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QAC1C,IAAI,CAAC,QAAQ;YACX,OAAO;QAET,MAAM,yBAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC;IACjF,CAAC;CACF;AA5DD,gDA4DC","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n// Code based on the blog article @ https://authguidance.com\r\n\r\n/** @packageDocumentation\r\n * @module Authentication\r\n */\r\n\r\nimport * as OperatingSystemUserName from \"username\";\r\nimport { TokenResponse, TokenResponseJson } from \"@openid/appauth\";\r\nimport { IModelHost } from \"@itwin/core-backend\";\r\n\r\n/**\r\n * Utility to store OIDC AppAuth in secure storage\r\n * @internal\r\n */\r\nexport class ElectronTokenStore {\r\n private _appStorageKey: string;\r\n\r\n public constructor(clientId: string) {\r\n this._appStorageKey = `Bentley.iModelJs.OidcTokenStore.${clientId}`;\r\n }\r\n\r\n private _userName?: string; // Cached user name\r\n private async getUserName(): Promise<string | undefined> {\r\n if (!this._userName)\r\n this._userName = await OperatingSystemUserName();\r\n return this._userName;\r\n }\r\n\r\n /** Load token if available */\r\n public async load(): Promise<TokenResponse | undefined> {\r\n if (undefined === IModelHost.platform.KeyTar) // no keytar on Linux yet\r\n return undefined;\r\n\r\n const userName = await this.getUserName();\r\n if (!userName)\r\n return;\r\n\r\n const tokenResponseStr = await IModelHost.platform.KeyTar.getPassword(this._appStorageKey, userName);\r\n if (!tokenResponseStr) {\r\n return undefined;\r\n }\r\n\r\n const tokenResponseJson = JSON.parse(tokenResponseStr) as TokenResponseJson;\r\n return new TokenResponse(tokenResponseJson);\r\n }\r\n\r\n /** Save token after signin */\r\n public async save(tokenResponse: TokenResponse): Promise<void> {\r\n if (undefined === IModelHost.platform.KeyTar) // no keytar on Linux yet\r\n return;\r\n\r\n const userName = await this.getUserName();\r\n if (!userName)\r\n return;\r\n\r\n const tokenResponseObj = new TokenResponse(tokenResponse.toJson()); // Workaround for 'stub received bad data' error on windows - see https://github.com/atom/node-keytar/issues/112\r\n tokenResponseObj.accessToken = \"\";\r\n tokenResponseObj.idToken = \"\";\r\n\r\n const tokenResponseStr = JSON.stringify(tokenResponseObj.toJson());\r\n await IModelHost.platform.KeyTar.setPassword(this._appStorageKey, userName, tokenResponseStr);\r\n }\r\n\r\n /** Delete token after signout */\r\n public async delete(): Promise<void> {\r\n if (undefined === IModelHost.platform.KeyTar) // no keytar on Linux yet\r\n return;\r\n\r\n const userName = await this.getUserName();\r\n if (!userName)\r\n return;\r\n\r\n await IModelHost.platform.KeyTar.deletePassword(this._appStorageKey, userName);\r\n }\r\n}\r\n"]}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { NativeAppAuthorizationConfiguration } from "@itwin/core-common";
|
|
2
|
-
import { ElectronAuthorizationEvents } from "./ElectronAuthorizationEvents";
|
|
3
|
-
/**
|
|
4
|
-
* Web server to listen to authorization requests/responses for the DesktopAuthorizationClient
|
|
5
|
-
* @internal
|
|
6
|
-
*/
|
|
7
|
-
export declare class LoopbackWebServer {
|
|
8
|
-
private static _httpServer?;
|
|
9
|
-
private static _authState;
|
|
10
|
-
/** Start a web server to listen to the browser requests */
|
|
11
|
-
static start(clientConfiguration: NativeAppAuthorizationConfiguration): void;
|
|
12
|
-
/** Add to the authorization state so that the correct response data is used for each request */
|
|
13
|
-
static addCorrelationState(state: string, authEvents: ElectronAuthorizationEvents): void;
|
|
14
|
-
/** Stop the web server after the authorization was completed */
|
|
15
|
-
private static stop;
|
|
16
|
-
/** Listen/Handle browser events */
|
|
17
|
-
private static onBrowserRequest;
|
|
18
|
-
}
|
|
19
|
-
//# sourceMappingURL=LoopbackWebServer.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"LoopbackWebServer.d.ts","sourceRoot":"","sources":["../../../src/backend/LoopbackWebServer.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,mCAAmC,EAAE,MAAM,oBAAoB,CAAC;AAEzE,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AA2B5E;;;GAGG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAc;IACzC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAgD;IAEzE,2DAA2D;WAC7C,KAAK,CAAC,mBAAmB,EAAE,mCAAmC;IAS5E,gGAAgG;WAClF,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,2BAA2B,GAAG,IAAI;IAI/F,gEAAgE;IAChE,OAAO,CAAC,MAAM,CAAC,IAAI;IAOnB,mCAAmC;IACnC,OAAO,CAAC,MAAM,CAAC,gBAAgB;CA4ChC"}
|