Skip to content

Commit

Permalink
feat: allow oauth2 authentication (#544)
Browse files Browse the repository at this point in the history
  • Loading branch information
bastiandoetsch authored Jul 9, 2024
1 parent cad968c commit 87d492b
Show file tree
Hide file tree
Showing 143 changed files with 1,230 additions and 1,125 deletions.
3 changes: 2 additions & 1 deletion .github/create-cli-pr.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ BODY=$(printf "## Changes since last integration of Language Server\n\n\`\`\`\n%
BRANCH=feat/automatic-upgrade-of-ls

pushd $CLI_DIR
git checkout $BRANCH || git checkout -b $BRANCH
git checkout -B $BRANCH
git rebase --ignore-whitespace main

UPGRADE=$(go run scripts/upgrade-snyk-go-dependencies.go --name=snyk-ls)
LS_VERSION=$(echo $UPGRADE | sed 's/.*Sha: \(.*\) URL.*/\1/')
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ within `initializationOptions?: LSPAny;` we support the following settings:
"cliPath": "/a/patch/snyk-cli",
// The path where the CLI can be found, or where it should be downloaded to
"token": "secret-token",
// The Snyk token, e.g.: snyk config get api or a token from oauth flow
// The Snyk token, e.g.: snyk config get api or a token from authentication flow
"automaticAuthentication": "true",
// Whether LS will automatically authenticate on scan start (default: true)
"enableTrustedFoldersFeature": "true",
Expand Down Expand Up @@ -369,7 +369,7 @@ within `initializationOptions?: LSPAny;` we support the following settings:
"scanningMode": "auto",
// Specifies the mode for scans: "auto" for background scans or "manual" for scans on command
"authenticationMethod": "token",
// Specifies the authentication method to use: "token" for Snyk API token or "oauth" for Snyk OAuth flow. Default is token.
// Specifies the authentication method to use: "token" for Snyk API token or "authentication" for Snyk OAuth flow. Default is token.
"snykCodeApi": "https://deeproxy.snyk.io",
// Specifies the Snyk Code API endpoint to use. Default is https://deeproxy.snyk.io
"requiredProtocolVersion": "11"
Expand Down
5 changes: 3 additions & 2 deletions application/codeaction/codeaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ import (
"github.com/snyk/snyk-ls/application/config"
"github.com/snyk/snyk-ls/domain/ide/command"
"github.com/snyk/snyk-ls/domain/ide/converter"
noti "github.com/snyk/snyk-ls/domain/ide/notification"
"github.com/snyk/snyk-ls/domain/snyk"
"github.com/snyk/snyk-ls/infrastructure/code"
"github.com/snyk/snyk-ls/internal/lsp"
noti "github.com/snyk/snyk-ls/internal/notification"
"github.com/snyk/snyk-ls/internal/types"
"github.com/snyk/snyk-ls/internal/uri"
)

Expand Down Expand Up @@ -116,7 +117,7 @@ func (c *CodeActionsService) ResolveCodeAction(action lsp.CodeAction, server lsp

func (c *CodeActionsService) handleCommand(action lsp.CodeAction, server lsp.Server) (lsp.CodeAction, error) {
c.logger.Info().Str("method", "codeaction.handleCommand").Msgf("handling command %s", action.Command.Command)
cmd := snyk.CommandData{
cmd := types.CommandData{
Title: action.Command.Title,
CommandId: action.Command.Command,
Arguments: action.Command.Arguments,
Expand Down
9 changes: 5 additions & 4 deletions application/codeaction/codeaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"github.com/snyk/snyk-ls/internal/lsp"
"github.com/snyk/snyk-ls/internal/notification"
"github.com/snyk/snyk-ls/internal/testutil"
"github.com/snyk/snyk-ls/internal/types"
"github.com/snyk/snyk-ls/internal/uri"
)

Expand Down Expand Up @@ -246,11 +247,11 @@ func Test_ResolveCodeAction_CommandIsExecuted(t *testing.T) {
service := setupService()

id := lsp.CodeActionData(uuid.New())
command.SetService(snyk.NewCommandServiceMock())
command.SetService(types.NewCommandServiceMock())

c := &sglsp.Command{
Title: snyk.LoginCommand,
Command: snyk.LoginCommand,
Title: types.LoginCommand,
Command: types.LoginCommand,
}
ca := lsp.CodeAction{
Title: "Made up CA",
Expand All @@ -262,7 +263,7 @@ func Test_ResolveCodeAction_CommandIsExecuted(t *testing.T) {
_, err := service.ResolveCodeAction(ca, nil)
assert.NoError(t, err, "command should be called without error")

serviceMock := command.Service().(*snyk.CommandServiceMock)
serviceMock := command.Service().(*types.CommandServiceMock)
assert.Len(t, serviceMock.ExecutedCommands(), 1)
assert.Equal(t, serviceMock.ExecutedCommands()[0].CommandId, c.Command)
}
Expand Down
29 changes: 15 additions & 14 deletions application/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/snyk/go-application-framework/pkg/runtimeinfo"
"github.com/snyk/snyk-ls/infrastructure/cli/cli_constants"
"github.com/snyk/snyk-ls/internal/logging"
storage2 "github.com/snyk/snyk-ls/internal/storage"

"github.com/adrg/xdg"
"github.com/denisbrodbeck/machineid"
Expand Down Expand Up @@ -190,7 +191,7 @@ type Config struct {
enableSnykLearnCodeActions bool
enableSnykOSSQuickFixCodeActions bool
logger *zerolog.Logger
storage StorageWithCallbacks
storage storage2.StorageWithCallbacks
m sync.Mutex
clientProtocolVersion string
}
Expand Down Expand Up @@ -250,7 +251,7 @@ func New() *Config {
func initWorkFlowEngine(c *Config) {
conf := configuration.NewInMemory()
c.engine = app.CreateAppEngineWithOptions(app.WithConfiguration(conf), app.WithZeroLogger(c.logger))
c.storage = NewStorage()
c.storage = storage2.NewStorage()
conf.SetStorage(c.storage)
conf.Set(configuration.FF_OAUTH_AUTH_FLOW_ENABLED, true)
conf.Set(cli_constants.EXECUTION_MODE_KEY, cli_constants.EXECUTION_MODE_VALUE_STANDALONE)
Expand Down Expand Up @@ -486,7 +487,7 @@ func (c *Config) SetToken(token string) {
}

if isOauthToken && conf.GetString(auth.CONFIG_KEY_OAUTH_TOKEN) != token {
c.Logger().Info().Err(err).Msg("setting oauth authentication in GAF")
c.Logger().Info().Err(err).Msg("setting oauth2 authentication in GAF")
conf.Set(auth.CONFIG_KEY_OAUTH_TOKEN, token)
}

Expand Down Expand Up @@ -850,14 +851,6 @@ func (c *Config) IsAutoScanEnabled() bool {
return c.automaticScanning
}

func (c *Config) SetAuthenticationMethod(method lsp.AuthenticationMethod) {
c.authenticationMethod = method
}

func (c *Config) AuthenticationMethod() lsp.AuthenticationMethod {
return c.authenticationMethod
}

func (c *Config) Engine() workflow.Engine {
return c.engine
}
Expand Down Expand Up @@ -906,19 +899,19 @@ func (c *Config) Logger() *zerolog.Logger {
func (c *Config) TokenAsOAuthToken() (oauth2.Token, error) {
var oauthToken oauth2.Token
if _, err := uuid.Parse(c.Token()); err == nil {
msg := "creds are legacy, not oauth"
msg := "creds are legacy, not oauth2"
c.Logger().Trace().Msgf(msg)
return oauthToken, fmt.Errorf(msg)
}
err := json.Unmarshal([]byte(c.Token()), &oauthToken)
if err != nil {
c.Logger().Trace().Err(err).Msg("unable to unmarshal oauth creds")
c.Logger().Trace().Err(err).Msg("unable to unmarshal creds to oauth2 token")
return oauthToken, err
}
return oauthToken, nil
}

func (c *Config) Storage() StorageWithCallbacks {
func (c *Config) Storage() storage2.StorageWithCallbacks {
return c.storage
}

Expand Down Expand Up @@ -951,3 +944,11 @@ func (c *Config) IsAnalyticsPermitted() bool {
func (c *Config) SetClientProtocolVersion(requiredProtocolVersion string) {
c.clientProtocolVersion = requiredProtocolVersion
}

func (c *Config) AuthenticationMethod() lsp.AuthenticationMethod {
return c.authenticationMethod
}

func (c *Config) SetAuthenticationMethod(authMethod lsp.AuthenticationMethod) {
c.authenticationMethod = authMethod
}
37 changes: 21 additions & 16 deletions application/di/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,18 @@ import (
codeClient "github.com/snyk/code-client-go"
codeClientHTTP "github.com/snyk/code-client-go/http"
codeClientObservability "github.com/snyk/code-client-go/observability"

"github.com/snyk/snyk-ls/application/codeaction"
"github.com/snyk/snyk-ls/application/config"
appNotification "github.com/snyk/snyk-ls/application/server/notification"
"github.com/snyk/snyk-ls/application/watcher"
"github.com/snyk/snyk-ls/domain/ide/command"
"github.com/snyk/snyk-ls/domain/ide/hover"
"github.com/snyk/snyk-ls/domain/ide/initialize"
"github.com/snyk/snyk-ls/domain/ide/notification"
"github.com/snyk/snyk-ls/domain/ide/workspace"
er "github.com/snyk/snyk-ls/domain/observability/error_reporting"
"github.com/snyk/snyk-ls/domain/observability/performance"
"github.com/snyk/snyk-ls/domain/observability/ux"
"github.com/snyk/snyk-ls/domain/snyk"
"github.com/snyk/snyk-ls/infrastructure/amplitude"
"github.com/snyk/snyk-ls/infrastructure/authentication"
"github.com/snyk/snyk-ls/infrastructure/cli"
cliauth "github.com/snyk/snyk-ls/infrastructure/cli/auth"
"github.com/snyk/snyk-ls/infrastructure/cli/cli_constants"
"github.com/snyk/snyk-ls/infrastructure/cli/install"
"github.com/snyk/snyk-ls/infrastructure/code"
Expand All @@ -51,7 +46,11 @@ import (
"github.com/snyk/snyk-ls/infrastructure/oss"
"github.com/snyk/snyk-ls/infrastructure/sentry"
"github.com/snyk/snyk-ls/infrastructure/snyk_api"
"github.com/snyk/snyk-ls/internal/notification"
domainNotify "github.com/snyk/snyk-ls/internal/notification"
er "github.com/snyk/snyk-ls/internal/observability/error_reporting"
performance2 "github.com/snyk/snyk-ls/internal/observability/performance"
"github.com/snyk/snyk-ls/internal/observability/ux"
)

var snykApiClient snyk_api.SnykApiClient
Expand All @@ -61,9 +60,9 @@ var snykCodeScanner *code.Scanner
var infrastructureAsCodeScanner *iac.Scanner
var openSourceScanner snyk.ProductScanner
var scanInitializer initialize.Initializer
var authenticationService snyk.AuthenticationService
var authenticationService authentication.AuthenticationService
var learnService learn.Service
var instrumentor performance.Instrumentor
var instrumentor performance2.Instrumentor
var errorReporter er.ErrorReporter
var installer install.Installer
var analytics ux.Analytics
Expand Down Expand Up @@ -132,14 +131,20 @@ func initInfrastructure(c *config.Config) {
errorReporter = sentry.NewSentryErrorReporter(c, notifier)
installer = install.NewInstaller(errorReporter, networkAccess.GetUnauthorizedHttpClient)
learnService = learn.New(c, networkAccess.GetUnauthorizedHttpClient, errorReporter)
instrumentor = performance.NewInstrumentor()
instrumentor = performance2.NewInstrumentor()
snykApiClient = snyk_api.NewSnykApiClient(c, networkAccess.GetHttpClient)
analytics = amplitude.NewAmplitudeClient(c, snyk.AuthenticationCheck, errorReporter)
authProvider := cliauth.NewCliAuthenticationProvider(c, errorReporter)
authenticationService = snyk.NewAuthenticationService(c, authProvider, analytics, errorReporter, notifier)
snykCli := cli.NewExecutor(c, authenticationService, errorReporter, analytics, notifier)
analytics = amplitude.NewAmplitudeClient(c, authentication.AuthenticationCheck, errorReporter)
gafConfiguration := c.Engine().GetConfiguration()

// we initialize the service without providers
authenticationService = authentication.NewAuthenticationService(c, nil, analytics, errorReporter, notifier)
// after having an instance, we pass it into the default configuration method
// so that the oauth2 provider can use it for its callback
authenticationService.ConfigureProviders(c)

snykCli := cli.NewExecutor(c, errorReporter, analytics, notifier)

if c.Engine().GetConfiguration().GetString(cli_constants.EXECUTION_MODE_KEY) == cli_constants.EXECUTION_MODE_VALUE_EXTENSION {
if gafConfiguration.GetString(cli_constants.EXECUTION_MODE_KEY) == cli_constants.EXECUTION_MODE_VALUE_EXTENSION {
snykCli = cli.NewExtensionExecutor(c)
}

Expand Down Expand Up @@ -171,7 +176,7 @@ func initInfrastructure(c *config.Config) {
snykCodeScanner = code.New(snykCodeBundleUploader, snykApiClient, codeErrorReporter, analytics, learnService, notifier,
codeClientScanner)
cliInitializer = cli.NewInitializer(errorReporter, installer, notifier, snykCli)
authInitializer := cliauth.NewInitializer(c, authenticationService, errorReporter, analytics, notifier)
authInitializer := authentication.NewInitializer(c, authenticationService, errorReporter, analytics, notifier)
scanInitializer = initialize.NewDelegatingInitializer(
cliInitializer,
authInitializer,
Expand Down Expand Up @@ -210,7 +215,7 @@ func ErrorReporter() er.ErrorReporter {
return errorReporter
}

func AuthenticationService() snyk.AuthenticationService {
func AuthenticationService() authentication.AuthenticationService {
initMutex.Lock()
defer initMutex.Unlock()
return authenticationService
Expand Down
21 changes: 11 additions & 10 deletions application/di/test_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,9 @@ import (
"github.com/snyk/snyk-ls/domain/ide/hover"
"github.com/snyk/snyk-ls/domain/ide/initialize"
"github.com/snyk/snyk-ls/domain/ide/workspace"
er "github.com/snyk/snyk-ls/domain/observability/error_reporting"
"github.com/snyk/snyk-ls/domain/observability/performance"
"github.com/snyk/snyk-ls/domain/observability/ux"
"github.com/snyk/snyk-ls/domain/snyk"
"github.com/snyk/snyk-ls/infrastructure/authentication"
"github.com/snyk/snyk-ls/infrastructure/cli"
cliauth "github.com/snyk/snyk-ls/infrastructure/cli/auth"
"github.com/snyk/snyk-ls/infrastructure/cli/install"
"github.com/snyk/snyk-ls/infrastructure/code"
"github.com/snyk/snyk-ls/infrastructure/iac"
Expand All @@ -43,6 +40,10 @@ import (
"github.com/snyk/snyk-ls/infrastructure/oss"
"github.com/snyk/snyk-ls/infrastructure/snyk_api"
domainNotify "github.com/snyk/snyk-ls/internal/notification"
er "github.com/snyk/snyk-ls/internal/observability/error_reporting"
"github.com/snyk/snyk-ls/internal/observability/performance"
"github.com/snyk/snyk-ls/internal/observability/ux"
"github.com/snyk/snyk-ls/internal/types"
)

// TODO this is becoming a hot mess we need to unify integ. test strategies
Expand All @@ -52,18 +53,18 @@ func TestInit(t *testing.T) {
t.Helper()
c := config.CurrentConfig()
// we don't want to open browsers when testing
snyk.DefaultOpenBrowserFunc = func(url string) {}
types.DefaultOpenBrowserFunc = func(url string) {}
notifier = domainNotify.NewNotifier()
analytics = ux.NewTestAnalytics(c)
instrumentor = performance.NewInstrumentor()
errorReporter = er.NewTestErrorReporter()
installer = install.NewFakeInstaller()
authProvider := snyk.NewFakeCliAuthenticationProvider(c)
authProvider := authentication.NewFakeCliAuthenticationProvider(c)
snykApiClient = &snyk_api.FakeApiClient{CodeEnabled: true}
authenticationService = snyk.NewAuthenticationService(c, authProvider, analytics, errorReporter, notifier)
snykCli := cli.NewExecutor(c, authenticationService, errorReporter, analytics, notifier)
authenticationService = authentication.NewAuthenticationService(c, []authentication.AuthenticationProvider{authProvider}, analytics, errorReporter, notifier)
snykCli := cli.NewExecutor(c, errorReporter, analytics, notifier)
cliInitializer = cli.NewInitializer(errorReporter, installer, notifier, snykCli)
authInitializer := cliauth.NewInitializer(c, authenticationService, errorReporter, analytics, notifier)
authInitializer := authentication.NewInitializer(c, authenticationService, errorReporter, analytics, notifier)
scanInitializer = initialize.NewDelegatingInitializer(
cliInitializer,
authInitializer,
Expand Down Expand Up @@ -100,7 +101,7 @@ func TestInit(t *testing.T) {
openSourceScanner,
)
hoverService = hover.NewDefaultService(c, analytics)
command.SetService(&snyk.CommandServiceMock{})
command.SetService(&types.CommandServiceMock{})
// don't use getters or it'll deadlock
w := workspace.New(c, instrumentor, scanner, hoverService, scanNotifier, notifier)
workspace.Set(w)
Expand Down
Loading

0 comments on commit 87d492b

Please sign in to comment.