Skip to content

Commit

Permalink
Add verification code to the SSO login view (#454)
Browse files Browse the repository at this point in the history
* Update webview to 0.2.13
  • Loading branch information
Or-Geva authored Dec 11, 2023
1 parent 612ed0c commit 6b063f7
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 22 deletions.
40 changes: 33 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@
"adm-zip": "~0.5.9",
"fs-extra": "~10.1.0",
"jfrog-client-js": "^2.7.1",
"jfrog-ide-webview": "https://releases.jfrog.io/artifactory/ide-webview-npm/jfrog-ide-webview/-/jfrog-ide-webview-0.2.12.tgz",
"jfrog-ide-webview": "https://releases.jfrog.io/artifactory/ide-webview-npm/jfrog-ide-webview/-/jfrog-ide-webview-0.2.13.tgz",
"js-yaml": "^4.1.0",
"json2csv": "~5.0.7",
"nuget-deps-tree": "^0.3.1",
Expand Down
8 changes: 4 additions & 4 deletions src/main/connect/connectionManager.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { execSync } from 'child_process';
import * as crypto from 'crypto';
import {
AccessTokenResponse,
ClientUtils,
Expand Down Expand Up @@ -437,17 +436,17 @@ export class ConnectionManager implements ExtensionComponent, vscode.Disposable
}
/**
* Initiates a web-based login process and obtains an access token.
* @param sessionId - The web login session ID.
* @param url - The platform URL.
* @param artifactoryUrl - The Artifactory URL.
* @param xrayUrl - The Xray URL.
* @returns A promise that resolves to the login status.
*/
public async startWebLogin(url: string, artifactoryUrl: string, xrayUrl: string): Promise<LoginStatus> {
public async startWebLogin(sessionId: string, url: string, artifactoryUrl: string, xrayUrl: string): Promise<LoginStatus> {
if (url === '' || artifactoryUrl === '' || xrayUrl === '') {
return LoginStatus.Failed;
}
this._logManager.logMessage('Start Web-Login with "' + url + '"', 'DEBUG');
const sessionId: string = crypto.randomUUID();
if (!(await this.registerWebLoginId(url, sessionId))) {
return LoginStatus.FailedServerNotSupported;
}
Expand Down Expand Up @@ -515,7 +514,8 @@ export class ConnectionManager implements ExtensionComponent, vscode.Disposable
}

public createWebLoginEndpoint(platformUrl: string, sessionId: string): vscode.Uri {
const endpoint: string = ClientUtils.addTrailingSlashIfMissing(platformUrl) + `ui/login?jfClientSession=${sessionId}&jfClientName=VS-Code`;
const endpoint: string =
ClientUtils.addTrailingSlashIfMissing(platformUrl) + `ui/login?jfClientSession=${sessionId}&jfClientName=VS-Code&jfClientCode=1`;
this._logManager.logMessage('Open browser at ' + endpoint, 'INFO');
return vscode.Uri.parse(endpoint);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,10 @@ export class RootNode extends DependenciesTreeNode {
* @param componentWithIssue - the version of the component used to build a path to the root.
*/
public createImpactedGraph(vulnerableDependencyName: string, vulnerableDependencyVersion: string): IImpactGraph {
const vulnerableDependencyId: string = vulnerableDependencyName + ':' + vulnerableDependencyVersion
const vulnerableDependencyId: string = vulnerableDependencyName + ':' + vulnerableDependencyVersion;
// Ensure we hit the direct impact first
RootNode.moveNodeToFirst(this.children, vulnerableDependencyId)
RootNode.moveNodeToFirst(this.children, vulnerableDependencyId);
return RootNode.collectPaths(vulnerableDependencyId, this.children, 0);

}

/**
Expand Down
22 changes: 18 additions & 4 deletions src/main/webview/event/tasks/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as vscode from 'vscode';
import { LogManager } from '../../../log/logManager';
import { ConnectionManager, LoginStatus } from '../../../connect/connectionManager';
import { ClientUtils } from 'jfrog-client-js';
import crypto from 'crypto'; // Important - Don't import '*'. It'll import deprecated encryption methods

/**
* Represents a login task that handles the authentication process and communicates with the webview.
Expand Down Expand Up @@ -36,9 +37,6 @@ export class LoginTask {
* Executes the login task.
*/
public async run() {
// Send initial page status to the webview
await this.send.loadPage(this.updatedPageStatus);

// Perform login and update page status
const requestStatus: LoginProgressStatus = await this.doLogin();
await this.send.loadPage({ ...this.updatedPageStatus, status: requestStatus });
Expand Down Expand Up @@ -69,9 +67,10 @@ export class LoginTask {
let status: LoginStatus;
switch (this.updatedPageStatus.connectionType) {
case LoginConnectionType.Sso:
status = await this.connectionManager.startWebLogin(this.platformUrl, this.artifactoryUrl, this.xrayUrl);
status = await this.startWebLogin();
break;
case LoginConnectionType.BasicAuthOrToken:
await this.send.loadPage(this.updatedPageStatus);
status = await this.connectionManager.tryStoreCredentials(
this.platformUrl,
this.artifactoryUrl,
Expand All @@ -82,9 +81,11 @@ export class LoginTask {
);
break;
case LoginConnectionType.Cli:
await this.send.loadPage(this.updatedPageStatus);
status = await this.connectionManager.tryCredentialsFromJfrogCli();
break;
case LoginConnectionType.EnvVars:
await this.send.loadPage(this.updatedPageStatus);
status = await this.connectionManager.tryCredentialsFromEnv();
}
return this.toWebviewLoginStatus(status);
Expand All @@ -94,6 +95,19 @@ export class LoginTask {
}
}

private async startWebLogin(): Promise<LoginStatus> {
const sessionId: string = crypto.randomUUID();

this.updatedPageStatus.ssoVerification = {
code: sessionId.substring(sessionId.length - 4),
codeTimeoutMs: 300000
};
// Update webview page
await this.send.loadPage(this.updatedPageStatus);

return await this.connectionManager.startWebLogin(sessionId, this.platformUrl, this.artifactoryUrl, this.xrayUrl);
}

public toWebviewLoginStatus(ideStatus: LoginStatus) {
switch (ideStatus) {
case LoginStatus.Success:
Expand Down
4 changes: 2 additions & 2 deletions src/test/tests/connectionManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ describe('Connection Manager Tests', () => {
const tryStoreCredentialsStub: any = sinon.stub(mockConnectionManager, 'tryStoreCredentials').resolves(LoginStatus.Success);

// Call the function
const result: LoginStatus = await mockConnectionManager.startWebLogin('mock-url', 'mock-artifactoryUrl', 'mock-xrayUrl');
const result: LoginStatus = await mockConnectionManager.startWebLogin('123456', 'mock-url', 'mock-artifactoryUrl', 'mock-xrayUrl');

// Check the return value and ensure that necessary methods are called
assert.strictEqual(result, LoginStatus.Success);
Expand All @@ -361,7 +361,7 @@ describe('Connection Manager Tests', () => {
// Mock dependencies and setup necessary conditions
const platformUrl: string = 'mock-platform-url';
const sessionId: string = 'mock-session-id';
const expectedEndpoint: string = 'mock-platform-url/ui/login?jfClientSession=mock-session-id&jfClientName=VS-Code';
const expectedEndpoint: string = 'mock-platform-url/ui/login?jfClientSession=mock-session-id&jfClientName=VS-Code&jfClientCode=1';
const logMessageStub: any = sinon.stub(mockLogger, 'logMessage');

// Call the method
Expand Down
1 change: 0 additions & 1 deletion src/test/tests/yarnImpactGraph.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ describe('Yarn impact graph util', async () => {
assert.deepEqual(results.pathsLimit, 1);

RootNode.IMPACT_PATHS_LIMIT = ORIGIN_IMPACT_PATHS_LIMIT;

});
});

Expand Down

0 comments on commit 6b063f7

Please sign in to comment.