mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
New Azure sign in experience (#8872)
* update * Prepare for release for all * Remove unused import * Proper branding * Handle error cases
This commit is contained in:
@@ -23,6 +23,8 @@ import { AddressInfo } from 'net';
|
|||||||
import { AuthenticationContext, TokenResponse, ErrorResponse } from 'adal-node';
|
import { AuthenticationContext, TokenResponse, ErrorResponse } from 'adal-node';
|
||||||
import { promisify } from 'util';
|
import { promisify } from 'util';
|
||||||
import * as events from 'events';
|
import * as events from 'events';
|
||||||
|
import { promises as fs } from 'fs';
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
const localize = nls.loadMessageBundle();
|
const localize = nls.loadMessageBundle();
|
||||||
const notInitalizedMessage = localize('accountProviderNotInitialized', "Account provider not initialized, cannot perform action");
|
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) {
|
constructor(private metadata: AzureAccountProviderMetadata, private _tokenCache: TokenCache) {
|
||||||
this.commonAuthorityUrl = url.resolve(this.metadata.settings.host, AzureAccountProvider.AadCommonTenant);
|
this.commonAuthorityUrl = url.resolve(this.metadata.settings.host, AzureAccountProvider.AadCommonTenant);
|
||||||
// Temporary override
|
|
||||||
this.metadata.settings.clientId = 'aebc6443-996d-45c2-90f0-388ff96faa56';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// interface method
|
// interface method
|
||||||
@@ -187,7 +187,27 @@ export class AzureAccountProvider implements azdata.AccountProvider {
|
|||||||
nonce: string,
|
nonce: string,
|
||||||
authUrl: 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<void> => {
|
||||||
|
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, '+');
|
const receivedNonce = (reqUrl.query.nonce as string || '').replace(/ /g, '+');
|
||||||
if (receivedNonce !== nonce) {
|
if (receivedNonce !== nonce) {
|
||||||
res.writeHead(400, { 'content-type': 'text/html' });
|
res.writeHead(400, { 'content-type': 'text/html' });
|
||||||
@@ -197,9 +217,9 @@ export class AzureAccountProvider implements azdata.AccountProvider {
|
|||||||
}
|
}
|
||||||
res.writeHead(302, { Location: authUrl });
|
res.writeHead(302, { Location: authUrl });
|
||||||
res.end();
|
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 state = reqUrl.query.state as string ?? '';
|
||||||
const code = reqUrl.query.code as string ?? '';
|
const code = reqUrl.query.code as string ?? '';
|
||||||
|
|
||||||
@@ -218,16 +238,19 @@ export class AzureAccountProvider implements azdata.AccountProvider {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
res.writeHead(200, { 'content-type': 'text/html' });
|
sendFile(res, path.join(__dirname, 'media/landing.html'), 'text/html; charset=utf-8').catch(console.error);
|
||||||
res.write(localize('azureAuth.authSuccessful', "Authentication was successful, you can now close this page."));
|
this.handleAuthentication(code).catch((e) => console.error(e));
|
||||||
res.end();
|
};
|
||||||
|
|
||||||
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('/signin', initialSignIn);
|
||||||
pathMappings.set('/callback', callback);
|
pathMappings.set('/callback', authCallback);
|
||||||
|
pathMappings.set('/landing.css', css);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async makeWebRequest(accessToken: TokenResponse, uri: string): Promise<any> {
|
private async makeWebRequest(accessToken: TokenResponse, uri: string): Promise<any> {
|
||||||
const params = {
|
const params = {
|
||||||
headers: {
|
headers: {
|
||||||
@@ -298,8 +321,8 @@ export class AzureAccountProvider implements azdata.AccountProvider {
|
|||||||
* @param code Code from authenticating
|
* @param code Code from authenticating
|
||||||
*/
|
*/
|
||||||
private async handleAuthentication(code: string): Promise<void> {
|
private async handleAuthentication(code: string): Promise<void> {
|
||||||
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);
|
const tenants = await this.getTenants(token.userId, token.tenantId);
|
||||||
let identityProvider = token.identityProvider;
|
let identityProvider = token.identityProvider;
|
||||||
if (identityProvider) {
|
if (identityProvider) {
|
||||||
@@ -383,7 +406,7 @@ export class AzureAccountProvider implements azdata.AccountProvider {
|
|||||||
if (method) {
|
if (method) {
|
||||||
method(req, res, reqUrl);
|
method(req, res, reqUrl);
|
||||||
} else {
|
} else {
|
||||||
console.error('undefined request ', reqUrl, req);
|
console.log('undefined request ', reqUrl.pathname, req);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import * as path from 'path';
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import CredentialServiceTokenCache from './tokenCache';
|
import CredentialServiceTokenCache from './tokenCache';
|
||||||
import providerSettings from './providerSettings';
|
import providerSettings from './providerSettings';
|
||||||
import { AzureAccountProvider as AzureAccountProviderDeprecated } from './azureAccountProvider';
|
|
||||||
import { AzureAccountProvider as AzureAccountProvider } from './azureAccountProvider2';
|
import { AzureAccountProvider as AzureAccountProvider } from './azureAccountProvider2';
|
||||||
import { AzureAccountProviderMetadata, ProviderSettings } from './interfaces';
|
import { AzureAccountProviderMetadata, ProviderSettings } from './interfaces';
|
||||||
|
|
||||||
@@ -139,13 +138,7 @@ export class AzureAccountProviderService implements vscode.Disposable {
|
|||||||
let tokenCacheKey = `azureTokenCache-${provider.metadata.id}`;
|
let tokenCacheKey = `azureTokenCache-${provider.metadata.id}`;
|
||||||
let tokenCachePath = path.join(this._userStoragePath, tokenCacheKey);
|
let tokenCachePath = path.join(this._userStoragePath, tokenCacheKey);
|
||||||
let tokenCache = new CredentialServiceTokenCache(self._credentialProvider, tokenCacheKey, tokenCachePath);
|
let tokenCache = new CredentialServiceTokenCache(self._credentialProvider, tokenCacheKey, tokenCachePath);
|
||||||
let accountProvider: azdata.AccountProvider;
|
let accountProvider = new AzureAccountProvider(provider.metadata as AzureAccountProviderMetadata, tokenCache);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
self._accountProviders[provider.metadata.id] = accountProvider;
|
self._accountProviders[provider.metadata.id] = accountProvider;
|
||||||
self._accountDisposals[provider.metadata.id] = azdata.accounts.registerAccountProvider(provider.metadata, accountProvider);
|
self._accountDisposals[provider.metadata.id] = azdata.accounts.registerAccountProvider(provider.metadata, accountProvider);
|
||||||
resolve();
|
resolve();
|
||||||
|
|||||||
100
extensions/azurecore/src/account-provider/media/landing.css
Normal file
100
extensions/azurecore/src/account-provider/media/landing.css
Normal file
@@ -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,iVBORw0KGgoAAAANSUhEUgAAAEYAAABGCAYAAABxLuKEAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4QwUFQAAEaou1QAABeZJREFUeNrtmm1sFEUYx397d22xBdoihwak0sYq4KHYUCm+sELCxVpQ0ITEckbRcIlKJCpfFKkBlRr1TESC2mCCZCmSkPBBa+NFopvIm9QXYE2sJSEchV6vEGxp6dverR+6B9ez7Z14pVuc35fNzszOzv3vmed5ZmZBIBAIBAKBQCAQCAQCgUAgiKNCDaRVqAHpWr5TsrAYE4BjwJS4qnvs2I+/KU8J/++EqVADJ4Fp8eUOCS7qBh3hcHO2wzGlckFe+H8jTIUa0IA7YwfYGzEIdvfSGTYwzDIJeoCC6rLCM8MxDscIi5APPAasAGYCHYAzVpQ2PcLZzh7skhQVJEo6sNV8/vqxmAo1sBTYO1CdYV479DBnO3VsQ49ycnVZYdN1YTEVamA5sDu2zG6Dpk6di73hy3+XYZBIFID3gKdGvcVUqIE84FT/6RIm2KVf7YDOAQeB6uqywi9TNU7bCBhMaT9ResMEO/V4//FvmAgsAXaV1zTsK69pyBgVU6lWK8oAMgFHqeuXFuDFaF0Yg7NdvdillBnuAuA74EHLClOrFU0EvgGmA1nAfmA+cHu0TUtXOJWiRI3wActNpVqtSKrVipy1WpEfaAGKgXHmeyaYzY5Hf0F7eHjys/KahnVW8zEFQAhYNEBdNGn7MPrfRiLDNoPTrCaMmsCiHgK+vwYOfoNlhPn299njBljwxVO5Uc4LAiUkl6NcDUeqywoNywjzcu2hXElKOJ6SWq3olY1y3mEDnsh0pDxbOAYstFa4NhxGqH0azqxTiVr6arWi1lJX3ueAVF7TsBG4D8j5D29vA/zVZYXvltc0pMQOU2bM7iptqk2KBF6atxKJSDJdnwHmho204OJZh8NYjJQKAwQkKYKcX03x5K/RI+nJPHoB6AQiAJJk4LDpPPvFJrp6MwD+CPnci661MClP8AzDxr4Tz3A4sJQZzv1Mdx7gthuP0KNnokfSMWKSf0kysNsiuWPSunPbu7NQ64s5dPIujp6ejt12OZafHwmLGZbM127T6dTH8nPTwxw8vYwIdvJzjuLMCjDG0Y7d1kPwXAddegbn27Opb84ncH4yWRmXSLPrsaKMGI7hnadGW4bj0niAYHsBwfYC06oMjv7ZfwslJ7PNUj5muFfXZYxShlUYv9f1I7BdCNOf983rnpT0JiuSeb01rnzSaBOm0rSamtSswjwGsmIAH8XVNCMrl5AV22gQ5gLQ6q7S3jDvd19lP5vjMuIfADeycgRZCSErP5nlr6F6IqNBmC1+rysCvGDeP8+Vzf+kLS7kc68J+dzTzCkzC5gF3ADMoe+Ypdhsu6TfdLNY5nt5k9vvdUnuKi0b+Mt0vqtMKxo7WLgeAGeoLnQzUGJaSgPQDaxD9fhifEwN8AgQAB4H5qJ6tlopj2kBngaazfud5tXl97p0d5X2KbAWOABsSdBXd8jnPoesbAaejF2do3p+i/M9ZcjKO8DrQJ0plh/Vc8ISFjOABXXQtwkOkO33utrcVZoBTPV7XY1JRqI04A76tkO/QvU8Oki7dPqOURqB2UAvqsewhMVEF5GDVO8yk70av9fVuPCTY89pJ4LbEqVBwOpQXSi6Et02RMTqQVZ6gBmonh7LLwlimO+u0tL9XtdiAJskfZbEMxGgC4huSTgT5jh9FmO5qKQPUTc2+sMWVWnzJAl7gr7uD/ncpaG6UFs0HwI+GKJ9LjAeuAVZWY2sOCwjjN/rajKjxmDsMZ2anER30cP+DcBy+j75yEFWBjujbuTKycDHqB7dannMqiHqSmIz4kShetKr/pswWA/MRPVkAE3ADmRlH7KyFlkpRVYqkZWTZm6zBtUjxbzHGnlMjBNeBuyI5ixx7ARWJJnHrAz53NvjfMmvZtSJZz2q521LZ75+r2uv3+saZ0ai1rjqFUn4qQAw5x+iXPFV9fQd+64E7jbL7x01G1V+r6vcXaU56DuanQhsYuCvny6YdbuBtpDP3ZoghOegeupNgUBWTgNvIRAIBAKBQCAQCAQCgUAwOvgbg/bzfXFXAb8AAAAASUVORK5CYII=");
|
||||||
|
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
|
||||||
|
}
|
||||||
35
extensions/azurecore/src/account-provider/media/landing.html
Normal file
35
extensions/azurecore/src/account-provider/media/landing.html
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<title>Azure Account - Sign In</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="stylesheet" type="text/css" media="screen" href="landing.css" />
|
||||||
|
<link rel="shortcut icon"type="image/x-icon" href="data:image/x-icon;base64,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">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a class="branding" href="https://docs.microsoft.com/en-us/sql/azure-data-studio/download-azure-data-studio">
|
||||||
|
Azure Data Studio
|
||||||
|
</a>
|
||||||
|
<div class="message-container">
|
||||||
|
<div class="message">
|
||||||
|
You are signed in now and can close this page.
|
||||||
|
</div>
|
||||||
|
<div class="error-message">
|
||||||
|
An error occurred while signing in:
|
||||||
|
<div class="error-text"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
var search = window.location.search;
|
||||||
|
var error = (/[?&^]error=([^&]+)/.exec(search) || [])[1];
|
||||||
|
if (error) {
|
||||||
|
document.querySelector('.error-text')
|
||||||
|
.textContent = decodeURIComponent(error);
|
||||||
|
document.querySelector('body')
|
||||||
|
.classList.add('error');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user