diff --git a/extensions/azurecore/src/account-provider/azureAccountProvider2.ts b/extensions/azurecore/src/account-provider/azureAccountProvider2.ts index 7b1f7f1dcc..641aac565a 100644 --- a/extensions/azurecore/src/account-provider/azureAccountProvider2.ts +++ b/extensions/azurecore/src/account-provider/azureAccountProvider2.ts @@ -23,6 +23,8 @@ import { AddressInfo } from 'net'; import { AuthenticationContext, TokenResponse, ErrorResponse } from 'adal-node'; import { promisify } from 'util'; import * as events from 'events'; +import { promises as fs } from 'fs'; +import * as path from 'path'; const localize = nls.loadMessageBundle(); const notInitalizedMessage = localize('accountProviderNotInitialized', "Account provider not initialized, cannot perform action"); @@ -41,8 +43,6 @@ export class AzureAccountProvider implements azdata.AccountProvider { constructor(private metadata: AzureAccountProviderMetadata, private _tokenCache: TokenCache) { this.commonAuthorityUrl = url.resolve(this.metadata.settings.host, AzureAccountProvider.AadCommonTenant); - // Temporary override - this.metadata.settings.clientId = 'aebc6443-996d-45c2-90f0-388ff96faa56'; } // interface method @@ -187,7 +187,27 @@ export class AzureAccountProvider implements azdata.AccountProvider { nonce: string, authUrl: string) { - const initialSignIn = ((req: http.IncomingMessage, res: http.ServerResponse, reqUrl: url.UrlWithParsedQuery) => { + // Utility function + const sendFile = async (res: http.ServerResponse, filePath: string, contentType: string): Promise => { + let fileContents; + try { + fileContents = await fs.readFile(filePath); + } catch (ex) { + console.error(ex); + res.writeHead(200); + res.end(); + return; + } + + res.writeHead(200, { + 'Content-Length': fileContents.length, + 'Content-Type': contentType + }); + + res.end(fileContents); + }; + + const initialSignIn = (req: http.IncomingMessage, res: http.ServerResponse, reqUrl: url.UrlWithParsedQuery) => { const receivedNonce = (reqUrl.query.nonce as string || '').replace(/ /g, '+'); if (receivedNonce !== nonce) { res.writeHead(400, { 'content-type': 'text/html' }); @@ -197,9 +217,9 @@ export class AzureAccountProvider implements azdata.AccountProvider { } res.writeHead(302, { Location: authUrl }); res.end(); - }); + }; - const callback = ((req: http.IncomingMessage, res: http.ServerResponse, reqUrl: url.UrlWithParsedQuery) => { + const authCallback = (req: http.IncomingMessage, res: http.ServerResponse, reqUrl: url.UrlWithParsedQuery) => { const state = reqUrl.query.state as string ?? ''; const code = reqUrl.query.code as string ?? ''; @@ -218,16 +238,19 @@ export class AzureAccountProvider implements azdata.AccountProvider { return; } - res.writeHead(200, { 'content-type': 'text/html' }); - res.write(localize('azureAuth.authSuccessful', "Authentication was successful, you can now close this page.")); - res.end(); + sendFile(res, path.join(__dirname, 'media/landing.html'), 'text/html; charset=utf-8').catch(console.error); + this.handleAuthentication(code).catch((e) => console.error(e)); + }; - this.handleAuthentication(code).catch(console.error); - }); + const css = (req: http.IncomingMessage, res: http.ServerResponse, reqUrl: url.UrlWithParsedQuery) => { + sendFile(res, path.join(__dirname, 'media/landing.css'), 'text/css; charset=utf-8').catch(console.error); + }; pathMappings.set('/signin', initialSignIn); - pathMappings.set('/callback', callback); + pathMappings.set('/callback', authCallback); + pathMappings.set('/landing.css', css); } + private async makeWebRequest(accessToken: TokenResponse, uri: string): Promise { const params = { headers: { @@ -298,8 +321,8 @@ export class AzureAccountProvider implements azdata.AccountProvider { * @param code Code from authenticating */ private async handleAuthentication(code: string): Promise { - const token = await this.getTokenWithAuthCode(code, AzureAccountProvider.redirectUrlAAD); - + let token: TokenResponse; + token = await this.getTokenWithAuthCode(code, AzureAccountProvider.redirectUrlAAD); const tenants = await this.getTenants(token.userId, token.tenantId); let identityProvider = token.identityProvider; if (identityProvider) { @@ -383,7 +406,7 @@ export class AzureAccountProvider implements azdata.AccountProvider { if (method) { method(req, res, reqUrl); } else { - console.error('undefined request ', reqUrl, req); + console.log('undefined request ', reqUrl.pathname, req); } }); diff --git a/extensions/azurecore/src/account-provider/azureAccountProviderService.ts b/extensions/azurecore/src/account-provider/azureAccountProviderService.ts index 08a12b9aa5..22c69a5cda 100644 --- a/extensions/azurecore/src/account-provider/azureAccountProviderService.ts +++ b/extensions/azurecore/src/account-provider/azureAccountProviderService.ts @@ -11,7 +11,6 @@ import * as path from 'path'; import * as vscode from 'vscode'; import CredentialServiceTokenCache from './tokenCache'; import providerSettings from './providerSettings'; -import { AzureAccountProvider as AzureAccountProviderDeprecated } from './azureAccountProvider'; import { AzureAccountProvider as AzureAccountProvider } from './azureAccountProvider2'; import { AzureAccountProviderMetadata, ProviderSettings } from './interfaces'; @@ -139,13 +138,7 @@ export class AzureAccountProviderService implements vscode.Disposable { let tokenCacheKey = `azureTokenCache-${provider.metadata.id}`; let tokenCachePath = path.join(this._userStoragePath, tokenCacheKey); let tokenCache = new CredentialServiceTokenCache(self._credentialProvider, tokenCacheKey, tokenCachePath); - let accountProvider: azdata.AccountProvider; - - if (/*config.get('useNewSignInExperience') === true && */ Boolean(process.env['NEW_SIGN_IN_EXPERIENCE']) === true) { - accountProvider = new AzureAccountProvider(provider.metadata as AzureAccountProviderMetadata, tokenCache); - } else { - accountProvider = new AzureAccountProviderDeprecated(provider.metadata as AzureAccountProviderMetadata, tokenCache); - } + let accountProvider = new AzureAccountProvider(provider.metadata as AzureAccountProviderMetadata, tokenCache); self._accountProviders[provider.metadata.id] = accountProvider; self._accountDisposals[provider.metadata.id] = azdata.accounts.registerAccountProvider(provider.metadata, accountProvider); resolve(); diff --git a/extensions/azurecore/src/account-provider/media/landing.css b/extensions/azurecore/src/account-provider/media/landing.css new file mode 100644 index 0000000000..3a41ed13dd --- /dev/null +++ b/extensions/azurecore/src/account-provider/media/landing.css @@ -0,0 +1,100 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +html { + height: 100%; +} + +body { + box-sizing: border-box; + min-height: 100%; + margin: 0; + padding: 15px 30px; + display: flex; + flex-direction: column; + color: white; + font-family: "Segoe UI","Helvetica Neue","Helvetica",Arial,sans-serif; + background-color: #007acc; +} + +.branding { + background-image: url("data:image/png;base64,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"); + background-size: contain; + background-repeat: no-repeat; + background-position: left 50%; + padding-left: 36px; + font-size: 20px; + letter-spacing: -0.04rem; + font-weight: 400; + color: white; + text-decoration: none; +} + +.message-container { + flex-grow: 1; + display: flex; + align-items: center; + justify-content: center; + margin: 0 30px; +} + +.message { + font-weight: 300; + font-size: 1.3rem; +} + +body.error .message { + display: none; +} + +body.error .error-message { + display: block; +} + +.error-message { + display: none; + font-weight: 300; + font-size: 1.3rem; +} + +.error-text { + color: red; + font-size: 1rem; +} + +@font-face { + font-family: 'Segoe UI'; + src: url("https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/light/latest.eot"),url("https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/light/latest.eot?#iefix") format("embedded-opentype"); + src: local("Segoe UI Light"),url("https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/light/latest.woff2") format("woff2"),url("https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/light/latest.woff") format("woff"),url("https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/light/latest.ttf") format("truetype"),url("https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/light/latest.svg#web") format("svg"); + font-weight: 200 +} + +@font-face { + font-family: 'Segoe UI'; + src: url("https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/semilight/latest.eot"),url("https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/semilight/latest.eot?#iefix") format("embedded-opentype"); + src: local("Segoe UI Semilight"),url("https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/semilight/latest.woff2") format("woff2"),url("https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/semilight/latest.woff") format("woff"),url("https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/semilight/latest.ttf") format("truetype"),url("https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/semilight/latest.svg#web") format("svg"); + font-weight: 300 +} + +@font-face { + font-family: 'Segoe UI'; + src: url("https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/normal/latest.eot"),url("https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/normal/latest.eot?#iefix") format("embedded-opentype"); + src: local("Segoe UI"),url("https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/normal/latest.woff2") format("woff"),url("https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/normal/latest.woff") format("woff"),url("https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/normal/latest.ttf") format("truetype"),url("https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/normal/latest.svg#web") format("svg"); + font-weight: 400 +} + +@font-face { + font-family: 'Segoe UI'; + src: url("https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/semibold/latest.eot"),url("https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/semibold/latest.eot?#iefix") format("embedded-opentype"); + src: local("Segoe UI Semibold"),url("https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/semibold/latest.woff2") format("woff"),url("https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/semibold/latest.woff") format("woff"),url("https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/semibold/latest.ttf") format("truetype"),url("https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/semibold/latest.svg#web") format("svg"); + font-weight: 600 +} + +@font-face { + font-family: 'Segoe UI'; + src: url("https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/bold/latest.eot"),url("https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/bold/latest.eot?#iefix") format("embedded-opentype"); + src: local("Segoe UI Bold"),url("https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/bold/latest.woff2") format("woff"),url("https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/bold/latest.woff") format("woff"),url("https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/bold/latest.ttf") format("truetype"),url("https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/bold/latest.svg#web") format("svg"); + font-weight: 700 +} diff --git a/extensions/azurecore/src/account-provider/media/landing.html b/extensions/azurecore/src/account-provider/media/landing.html new file mode 100644 index 0000000000..c5f8d4bd6d --- /dev/null +++ b/extensions/azurecore/src/account-provider/media/landing.html @@ -0,0 +1,35 @@ + + + + + + Azure Account - Sign In + + + + + + + Azure Data Studio + +
+
+ You are signed in now and can close this page. +
+
+ An error occurred while signing in: +
+
+
+ + +