Skip to content

Commit

Permalink
feat: add configuration setting for authentication method, default to…
Browse files Browse the repository at this point in the history
… token [IDE-459] (#500)

* feat: add new welcome view text

* feat: add config setting for authentication

* fix: tests for authentication method

* fix: linter

* docs: added changelog entry

* chore: optimize imports

* refactor: remove redundant setter

* fix: add authentication method changed welcome view and delete creds

* chore: update welcome screen copy

* chore: 💄 update text copy for setting
  • Loading branch information
bastiandoetsch authored Jul 26, 2024
1 parent a0d5168 commit 56f6d4a
Show file tree
Hide file tree
Showing 11 changed files with 67 additions and 9 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## [2.16.1]
- updated the language server protocol version to 13 to support delta findings.
- added setting for choosing authentication method

## [2.16.0]
- Reorganize settings page into categorized sections:
Expand Down
27 changes: 23 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,20 @@
"title": "Snyk Account",
"order": 1,
"properties": {
"snyk.advanced.authenticationMethod": {
"type": "string",
"default": "OAuth2 authentication",
"description": "Specifies whether to authenticate with OAuth2 or with an API token. \n\nNote: OAuth2 is currently experimental. Once it is fully supported, using OAuth2 authentication is recommended as it provides enhanced security.",
"enum": [
"OAuth2 authentication",
"Token authentication"
],
"enumDescriptions": [
"Uses the OAuth2 authentication",
"Uses the legacy Snyk Token authentication."
],
"markdownDescription": "Specifies whether to authenticate with OAuth2 or with an API token. \n\nNote: OAuth2 is currently experimental. Once it is fully supported, using OAuth2 authentication is recommended as it provides enhanced security."
},
"snyk.advanced.tokenStorage": {
"type": "string",
"enum": [
Expand Down Expand Up @@ -304,7 +318,7 @@
{
"id": "snyk.views.welcome",
"name": "Snyk",
"when": "!snyk:loggedIn || snyk:error || !snyk:workspaceFound"
"when": "!snyk:loggedIn || snyk:error || !snyk:workspaceFound || snyk:authenticationChanged"
},
{
"id": "snyk.views.analysis.oss",
Expand Down Expand Up @@ -345,13 +359,18 @@
},
{
"view": "snyk.views.welcome",
"contents": "👋 Welcome to Snyk for Visual Studio Code. \n⏱️ Please wait, the extension is loading...",
"contents": "👋 Welcome to Snyk for Visual Studio Code.\n⏱️ Please wait, the extension is loading...",
"when": "!snyk:error && !snyk:initialized"
},
{
"view": "snyk.views.welcome",
"contents": "👋 Welcome to Snyk for Visual Studio Code. \n👉 Connect with Snyk to start your first analysis!\nWhen scanning folder files, Snyk may automatically execute code such as invoking the package manager to get dependency information. You should only scan projects you trust. [More info](https://docs.snyk.io/ide-tools/visual-studio-code-extension/workspace-trust)\n[Trust workspace and connect](command:snyk.initiateLogin 'Connect with Snyk')\nBy connecting your account with Snyk, you agree to the Snyk [Privacy Policy](https://snyk.io/policies/privacy), and the Snyk [Terms of Service](https://snyk.io/policies/terms-of-service).",
"when": "!snyk:error && snyk:initialized && !snyk:loggedIn"
"contents": "👋 Let's secure your code! \nTo scan your project for issues, Snyk needs to:\n 1. Connect to your Snyk account: This allows us to securely analyse your code.\n2. Trust this workspace: This lets Snyk safely gather information about your project (like dependencies).\nYou should only scan projects you trust. [More info](https://docs.snyk.io/ide-tools/visual-studio-code-extension/workspace-trust)\nBy connecting your account with Snyk, you agree to the Snyk [Privacy Policy](https://snyk.io/policies/privacy), and the Snyk [Terms of Service](https://snyk.io/policies/terms-of-service).\n\n[Connect & Trust Workspace](command:snyk.initiateLogin 'Connect with Snyk')",
"when": "!snyk:error && snyk:initialized && !snyk:loggedIn && !snyk:authMethodChanged"
},
{
"view": "snyk.views.welcome",
"contents": "⚠️ Your authentication method has changed.\n\n👉 Please re-authenticate to continue using Snyk\n\nBy connecting your account with Snyk, you agree to the Snyk [Privacy Policy](https://snyk.io/policies/privacy), and the Snyk [Terms of Service](https://snyk.io/policies/terms-of-service).\n\n[Connect & Trust Workspace](command:snyk.initiateLogin 'Re-authenticate')",
"when": "!snyk:error && snyk:initialized && !snyk:loggedIn && snyk:authMethodChanged"
},
{
"view": "snyk.views.welcome",
Expand Down
3 changes: 2 additions & 1 deletion src/snyk/base/services/authenticationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export class AuthenticationService implements IAuthenticationService {

async setToken(): Promise<void> {
const token = await this.window.showInputBox({
placeHolder: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
placeHolder: 'UUID for API Token or OAuth2 Token',
password: true,
validateInput: token => {
const valid = this.validateToken(token);
Expand Down Expand Up @@ -91,6 +91,7 @@ export class AuthenticationService implements IAuthenticationService {
await this.configuration.setToken(token);
await this.contextService.setContext(SNYK_CONTEXT.AUTHENTICATING, false);
await this.contextService.setContext(SNYK_CONTEXT.LOGGEDIN, true);
await this.contextService.setContext(SNYK_CONTEXT.AUTHENTICATION_METHOD_CHANGED, false);

this.baseModule.loadingBadge.setLoadingBadge(false);
await this.commands.executeCommand(SNYK_WORKSPACE_SCAN_COMMAND);
Expand Down
21 changes: 18 additions & 3 deletions src/snyk/common/configuration/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { SNYK_TOKEN_KEY } from '../constants/general';
import {
ADVANCED_ADDITIONAL_PARAMETERS_SETTING,
ADVANCED_ADVANCED_MODE_SETTING,
ADVANCED_AUTHENTICATION_METHOD,
ADVANCED_AUTOMATIC_DEPENDENCY_MANAGEMENT,
ADVANCED_AUTOSCAN_OSS_SETTING,
ADVANCED_CLI_PATH,
Expand All @@ -14,18 +15,18 @@ import {
CODE_QUALITY_ENABLED_SETTING,
CODE_SECURITY_ENABLED_SETTING,
CONFIGURATION_IDENTIFIER,
DELTA_FINDINGS,
FEATURES_PREVIEW_SETTING,
FOLDER_CONFIGS,
IAC_ENABLED_SETTING,
ISSUE_VIEW_OPTIONS_SETTING,
OSS_ENABLED_SETTING,
SCANNING_MODE,
ISSUE_VIEW_OPTIONS_SETTING,
SEVERITY_FILTER_SETTING,
TRUSTED_FOLDERS,
YES_BACKGROUND_OSS_NOTIFICATION_SETTING,
YES_CRASH_REPORT_SETTING,
YES_WELCOME_NOTIFICATION_SETTING,
DELTA_FINDINGS,
FOLDER_CONFIGS,
} from '../constants/settings';
import SecretStorageAdapter from '../vscode/secretStorage';
import { IVSCodeWorkspace } from '../vscode/workspace';
Expand Down Expand Up @@ -77,6 +78,8 @@ export interface IConfiguration {

setToken(token: string | undefined): Promise<void>;

getAuthenticationMethod(): string;

setCliPath(cliPath: string): Promise<void>;

clearToken(): Promise<void>;
Expand Down Expand Up @@ -242,6 +245,18 @@ export class Configuration implements IConfiguration {
);
}

getAuthenticationMethod(): string {
const setting = this.workspace.getConfiguration<string>(
CONFIGURATION_IDENTIFIER,
this.getConfigName(ADVANCED_AUTHENTICATION_METHOD),
);
if (setting?.toLowerCase() != 'token authentication') {
return 'oauth';
} else {
return 'token';
}
}

async getToken(): Promise<string | undefined> {
return new Promise(resolve => {
SecretStorageAdapter.instance
Expand Down
1 change: 1 addition & 0 deletions src/snyk/common/constants/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const ADVANCED_ORGANIZATION = `${CONFIGURATION_IDENTIFIER}.advanced.organ
export const ADVANCED_AUTOMATIC_DEPENDENCY_MANAGEMENT = `${CONFIGURATION_IDENTIFIER}.advanced.automaticDependencyManagement`;
export const ADVANCED_CLI_PATH = `${CONFIGURATION_IDENTIFIER}.advanced.cliPath`;
export const ADVANCED_CUSTOM_LS_PATH = `${CONFIGURATION_IDENTIFIER}.advanced.languageServerPath`;
export const ADVANCED_AUTHENTICATION_METHOD = `${CONFIGURATION_IDENTIFIER}.advanced.authenticationMethod`;

export const ISSUE_VIEW_OPTIONS_SETTING = `${CONFIGURATION_IDENTIFIER}.issueViewOptions`;
export const SEVERITY_FILTER_SETTING = `${CONFIGURATION_IDENTIFIER}.severity`;
Expand Down
3 changes: 3 additions & 0 deletions src/snyk/common/constants/views.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// see https://code.visualstudio.com/api/references/contribution-points#contributes.viewsWelcome

export const SNYK_VIEW_WELCOME = 'snyk.views.welcome';
export const SNYK_VIEW_ANALYSIS_CODE_ENABLEMENT = 'snyk.views.analysis.code.enablement';
export const SNYK_VIEW_ANALYSIS_CODE_SECURITY = 'snyk.views.analysis.code.security';
Expand All @@ -14,6 +16,7 @@ export const SNYK_VIEW_ANALYSIS_IAC = 'snyk.views.analysis.configuration';
export const SNYK_CONTEXT = {
INITIALIZED: 'initialized', // default to loading state (notLoading = false when boolean is initialized)
LOGGEDIN: 'loggedIn',
AUTHENTICATION_METHOD_CHANGED: 'authMethodChanged',
AUTHENTICATING: 'authenticating',
CODE_ENABLED: 'codeEnabled',
CODE_LOCAL_ENGINE_ENABLED: 'codeLocalEngineEnabled',
Expand Down
2 changes: 2 additions & 0 deletions src/snyk/common/languageServer/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export type ServerSettings = {
// Authentication and parameters
token?: string;
automaticAuthentication?: string;
authenticationMethod?: string;
additionalParams?: string;
manageBinariesAutomatically?: string;

Expand Down Expand Up @@ -70,6 +71,7 @@ export class LanguageServerSettings {
organization: configuration.organization,
token: await configuration.getToken(),
automaticAuthentication: 'false',
authenticationMethod: configuration.getAuthenticationMethod(),
additionalParams: configuration.getAdditionalCliParameters(),
manageBinariesAutomatically: `${configuration.isAutomaticDependencyManagementEnabled()}`,
filterSeverity: configuration.severityFilter,
Expand Down
7 changes: 7 additions & 0 deletions src/snyk/common/watchers/configurationWatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ import {
TRUSTED_FOLDERS,
DELTA_FINDINGS,
FOLDER_CONFIGS,
ADVANCED_AUTHENTICATION_METHOD,
} from '../constants/settings';
import { ErrorHandler } from '../error/errorHandler';
import { ILog } from '../logger/interfaces';
import { errorsLogs } from '../messages/errors';
import SecretStorageAdapter from '../vscode/secretStorage';
import { IWatcher } from './interfaces';
import { SNYK_CONTEXT } from '../constants/views';

class ConfigurationWatcher implements IWatcher {
constructor(private readonly logger: ILog) {}
Expand All @@ -45,6 +47,10 @@ class ConfigurationWatcher implements IWatcher {
return extension.viewManagerService.refreshAllViews();
} else if (key === ADVANCED_CUSTOM_ENDPOINT) {
return configuration.clearToken();
} else if (key === ADVANCED_AUTHENTICATION_METHOD) {
await extension.contextService.setContext(SNYK_CONTEXT.LOGGEDIN, false);
await extension.contextService.setContext(SNYK_CONTEXT.AUTHENTICATION_METHOD_CHANGED, true);
return extension.viewManagerService.refreshAllViews();
} else if (key === ADVANCED_CUSTOM_LS_PATH) {
// Language Server client must sync config changes before we can restart
return _.debounce(() => extension.restartLanguageServer(), DEFAULT_LS_DEBOUNCE_INTERVAL)();
Expand Down Expand Up @@ -81,6 +87,7 @@ class ConfigurationWatcher implements IWatcher {
SEVERITY_FILTER_SETTING,
ADVANCED_CUSTOM_ENDPOINT,
ADVANCED_CUSTOM_LS_PATH,
ADVANCED_AUTHENTICATION_METHOD,
TRUSTED_FOLDERS,
ISSUE_VIEW_OPTIONS_SETTING,
DELTA_FINDINGS,
Expand Down
5 changes: 4 additions & 1 deletion src/test/unit/common/languageServer/languageServer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { defaultFeaturesConfigurationStub } from '../../mocks/configuration.mock
import { LoggerMock } from '../../mocks/logger.mock';
import { windowMock } from '../../mocks/window.mock';
import { stubWorkspaceConfiguration } from '../../mocks/workspace.mock';
import { FolderConfigs } from '../../../../snyk/common/configuration/folderConfigs';

suite('Language Server', () => {
const authServiceMock = {} as IAuthenticationService;
Expand All @@ -37,6 +36,9 @@ suite('Language Server', () => {

setup(() => {
configurationMock = {
getAuthenticationMethod(): string {
return 'oauth';
},
getInsecure(): boolean {
return true;
},
Expand Down Expand Up @@ -228,6 +230,7 @@ suite('Language Server', () => {
requiredProtocolVersion: '13',
scanningMode: 'auto',
folderConfigs: [],
authenticationMethod: 'oauth',
};

deepStrictEqual(await languageServer.getInitializationOptions(), expectedInitializationOptions);
Expand Down
3 changes: 3 additions & 0 deletions src/test/unit/common/languageServer/middleware.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ suite('Language Server: Middleware', () => {
setup(() => {
user = { anonymousId: 'anonymous-id' } as User;
configuration = {
getAuthenticationMethod(): string {
return 'oauth';
},
shouldReportErrors: false,
snykApiEndpoint: 'https://dev.snyk.io/api',
getAdditionalCliParameters: () => '',
Expand Down
3 changes: 3 additions & 0 deletions src/test/unit/common/languageServer/settings.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ suite('LanguageServerSettings', () => {
getFolderConfigs(): FolderConfig[] {
return [];
},
getAuthenticationMethod(): string {
return 'oauth';
},
severityFilter: { critical: true, high: true, medium: true, low: false },
scanningMode: 'scan-mode',
} as IConfiguration;
Expand Down

0 comments on commit 56f6d4a

Please sign in to comment.