diff --git a/src/openshift/cluster.ts b/src/openshift/cluster.ts index fc2f176b5..5b5248194 100644 --- a/src/openshift/cluster.ts +++ b/src/openshift/cluster.ts @@ -351,6 +351,19 @@ export class Cluster extends OpenShiftItem { } @vsCommand('openshift.explorer.login.clipboard') + static async loginUsingClipboardToken(apiEndpointUrl: string, oauthRequestTokenUrl: string): Promise { + const clipboard = await Cluster.readFromClipboard(); + if(!clipboard) { + const choice = await window.showErrorMessage('Cannot parse token in clipboard. Please click `Get token` button below, copy token into clipboard and press `Login to Sandbox` button again.', + 'Get token'); + if (choice === 'Get token') { + await commands.executeCommand('vscode.open', Uri.parse(oauthRequestTokenUrl)); + } + return; + } + return Cluster.tokenLogin(apiEndpointUrl, true, clipboard); + } + static async loginUsingClipboardInfo(dashboardUrl: string): Promise { const clipboard = await Cluster.readFromClipboard(); if(!Cluster.ocLoginCommandMatches(clipboard)) { diff --git a/src/openshift/sandbox.ts b/src/openshift/sandbox.ts index 9549122bd..f57e2ae91 100644 --- a/src/openshift/sandbox.ts +++ b/src/openshift/sandbox.ts @@ -43,6 +43,18 @@ export interface VerificationCodeResponse{ json: SBResponseData; } +export const OAUTH_SERVER_INFO_PATH = '.well-known/oauth-authorization-server'; + +export interface OauthServerInfo { + issuer: string; + authorization_endpoint: string; + token_endpoint: string; + scopes_supported: string[]; + response_types_supported: string[]; + grant_types_supported: string[]; + code_challenge_methods_supported: string[]; + } + export function getSandboxAPIUrl(): string { return workspace.getConfiguration('openshiftConnector').get('sandboxApiHostUrl'); } @@ -56,6 +68,7 @@ export interface SandboxAPI { signUp(token: string): Promise; requestVerificationCode(token: string, areaCode: string, phoneNumber: string): Promise; validateVerificationCode(token: string, code: string): Promise; + getOauthServerInfo(apiEndpointUrl: string): Promise; } export async function getSignUpStatus(token: string): Promise { @@ -112,11 +125,21 @@ export async function validateVerificationCode(token: string, code: string): Pro return validationRequestResponse.ok; } +export async function getOauthServerInfo(apiEndpointUrl: string): Promise { + const oauthServerInfoResponse = await fetch(`${apiEndpointUrl}/${OAUTH_SERVER_INFO_PATH}`, { + method: 'GET', + timeout: getSandboxAPITimeout() + }); + const oauthInfoText = await oauthServerInfoResponse.text(); + return (oauthInfoText ? JSON.parse(oauthInfoText) : {}) as OauthServerInfo; +} + export function createSandboxAPI(): SandboxAPI { return { getSignUpStatus, signUp, requestVerificationCode, - validateVerificationCode + validateVerificationCode, + getOauthServerInfo }; } diff --git a/src/webview/cluster/app/sandboxView.tsx b/src/webview/cluster/app/sandboxView.tsx index 33da91fce..449800c1b 100644 --- a/src/webview/cluster/app/sandboxView.tsx +++ b/src/webview/cluster/app/sandboxView.tsx @@ -60,6 +60,8 @@ export default function addSandboxView(props): JSX.Element { action: 'sandboxPageDetectAuthSession', statusInfo: '', consoleDashboard: '', + apiEndpoint: '', + oauthTokenEndpoint: '', errorCode: undefined }); @@ -150,6 +152,8 @@ export default function addSandboxView(props): JSX.Element { action: currentState.action, consoleDashboard: currentState.consoleDashboard, statusInfo: currentState.statusInfo, + apiEndpoint: '', + oauthTokenEndpoint: '', errorCode: undefined }); postMessage('sandboxDetectStatus'); @@ -299,6 +303,8 @@ export default function addSandboxView(props): JSX.Element { action: 'sandboxPageRequestVerificationCode', statusInfo: '', consoleDashboard: '', + apiEndpoint: '', + oauthTokenEndpoint: '', errorCode: undefined }); } @@ -376,7 +382,7 @@ export default function addSandboxView(props): JSX.Element { const Provisioned = () => { const handleLoginButton = () => { - postMessage('sandboxLoginUsingDataInClipboard', {url: currentState.consoleDashboard}); + postMessage('sandboxLoginUsingDataInClipboard', {apiEndpointUrl: currentState.apiEndpoint, oauthRequestTokenUrl: `${currentState.oauthTokenEndpoint}/request`}); }; return ( @@ -399,16 +405,19 @@ export default function addSandboxView(props): JSX.Element { Next steps to connect with Developer Sandbox:

- 1. Click on Open Dashboard button. In the browser, login using DevSandbox and once loggedin, click on username dropdown.

- 2. Select Copy Login command. Once the new tab is opened, copy the entire Log in with this token command.

- 3. Come back to IDE and press 'Login To Sandbox' Button. This will login your DevSandbox in OpenShift Application View.

+ 1. Click on Get token button. In the browser, login using DevSandbox button.

+ 2. Click on Display token link and copy token to clipboard.

+ 3. Switch back to IDE and press 'Login To DevSandbox' button. This will login you to DevSandbox with token from clipboard.

4. Once successfully logged in, start creating applications and deploy on cluster.
- + - - + + + + + )} diff --git a/src/webview/cluster/clusterViewLoader.ts b/src/webview/cluster/clusterViewLoader.ts index c5d114b48..ecde12650 100644 --- a/src/webview/cluster/clusterViewLoader.ts +++ b/src/webview/cluster/clusterViewLoader.ts @@ -108,7 +108,8 @@ async function clusterEditorMessageListener (event: any ): Promise { panel.webview.postMessage({action: 'sandboxPageRequestSignup'}); } else { if (signupStatus.status.ready) { - panel.webview.postMessage({action: 'sandboxPageProvisioned', statusInfo: signupStatus.username, consoleDashboard: signupStatus.consoleURL }); + const oauthInfo = await sandboxAPI.getOauthServerInfo(signupStatus.apiEndpoint); + panel.webview.postMessage({action: 'sandboxPageProvisioned', statusInfo: signupStatus.username, consoleDashboard: signupStatus.consoleURL, apiEndpoint: signupStatus.apiEndpoint, oauthTokenEndpoint: oauthInfo.token_endpoint }); } else { // cluster is not ready and the reason is if (signupStatus.status.verificationRequired) { @@ -118,8 +119,6 @@ async function clusterEditorMessageListener (event: any ): Promise { // if (signupStatus.status.reason === 'PendingApproval') { panel.webview.postMessage({action: 'sandboxPageWaitingForApproval'}); - } else if (signupStatus.status.reason === 'Provisioned') { - panel.webview.postMessage({action: 'sandboxPageProvisioned', statusInfo: signupStatus.username, consoleDashboard: signupStatus.consoleURL}); } else { panel.webview.postMessage({action: 'sandboxPageWaitingForProvision'}) } @@ -174,7 +173,7 @@ async function clusterEditorMessageListener (event: any ): Promise { case 'sandboxLoginUsingDataInClipboard': const telemetryEventLoginToSandbox = new ExtCommandTelemetryEvent('openshift.explorer.addCluster.sandboxLoginUsingDataInClipboard'); try { - const result = await Cluster.loginUsingClipboardInfo(event.payload.url); + const result = await Cluster.loginUsingClipboardToken(event.payload.apiEndpointUrl, event.payload.oauthRequestTokenUrl); if (result) vscode.window.showInformationMessage(`${result}`); telemetryEventLoginToSandbox.send(); } catch (err) {