diff --git a/cmd/auth-clientCredentials.go b/cmd/auth-clientCredentials.go index c401c070..eece7ff0 100644 --- a/cmd/auth-clientCredentials.go +++ b/cmd/auth-clientCredentials.go @@ -22,8 +22,11 @@ func auth_clientCredentials(cmd *cobra.Command, args []string) { flagHelper := cli.NewFlagHelper(cmd) clientID := flagHelper.GetOptionalString("client-id") clientSecret := flagHelper.GetOptionalString("client-secret") + var err error + insecure, _ := cmd.Flags().GetBool("insecure") + if clientCredsFile != "" { creds, err := handlers.GetClientCredsFromFile(clientCredsFile) if err != nil { @@ -53,7 +56,7 @@ func auth_clientCredentials(cmd *cobra.Command, args []string) { } } - tok, err := handlers.GetTokenWithClientCreds(cmd.Context(), clientID, clientSecret, handlers.TOKEN_URL, noCacheCreds) + tok, err := handlers.GetTokenWithClientCreds(cmd.Context(), clientID, clientSecret, handlers.TOKEN_URL, noCacheCreds, insecure) if err != nil { cli.ExitWithError("An error occurred during login. Please check your credentials and try again", err) } diff --git a/cmd/dev.go b/cmd/dev.go index ff332683..4431aac9 100644 --- a/cmd/dev.go +++ b/cmd/dev.go @@ -158,13 +158,16 @@ func readBytesFromFile(filePath string) []byte { // instantiates a new handler with authentication via client credentials func NewHandler(cmd *cobra.Command) handlers.Handler { platformEndpoint := cmd.Flag("host").Value.String() - + insecure, err := cmd.Flags().GetBool("insecure") + if err != nil { + cli.ExitWithError("Failed to get insecure flag", err) + } // load client credentials from file, JSON, or OS keyring creds, err := handlers.GetClientCreds(clientCredsFile, []byte(clientCredsJSON)) if err != nil { cli.ExitWithError("Failed to get client credentials", err) } - h, err := handlers.New(platformEndpoint, creds.ClientID, creds.ClientSecret) + h, err := handlers.New(platformEndpoint, creds.ClientID, creds.ClientSecret, insecure) if err != nil { if errors.Is(err, handlers.ErrUnauthenticated) { cli.ExitWithError(fmt.Sprintf("Not logged in. Please authenticate via CLI auth flow(s) before using command (%s %s)", cmd.Parent().Use, cmd.Use), err) diff --git a/cmd/root.go b/cmd/root.go index 0306ac42..8446a958 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -34,6 +34,11 @@ func init() { doc.GetDocFlag("host").Default, doc.GetDocFlag("host").Description, ) + RootCmd.PersistentFlags().Bool( + doc.GetDocFlag("insecure").Name, + doc.GetDocFlag("insecure").DefaultAsBool(), + doc.GetDocFlag("insecure").Description, + ) RootCmd.PersistentFlags().String( doc.GetDocFlag("log-level").Name, doc.GetDocFlag("log-level").Default, diff --git a/docs/man/_index.md b/docs/man/_index.md index d55409ed..8d0c972a 100644 --- a/docs/man/_index.md +++ b/docs/man/_index.md @@ -8,6 +8,9 @@ command: - name: host description: host:port of the OpenTDF Platform gRPC server default: localhost:8080 + - name: insecure + description: use insecure connection + default: false - name: log-level description: log level enum: diff --git a/go.mod b/go.mod index ef1b6ffc..f634f670 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/opentdf/otdfctl -go 1.22.2 +go 1.22.3 require ( github.com/adrg/frontmatter v0.2.0 @@ -14,7 +14,7 @@ require ( github.com/golang-jwt/jwt/v4 v4.5.0 github.com/itchyny/gojq v0.12.15 github.com/opentdf/platform/protocol/go v0.2.0 - github.com/opentdf/platform/sdk v0.2.0 + github.com/opentdf/platform/sdk v0.2.1 github.com/spf13/cobra v1.8.0 github.com/spf13/viper v1.18.2 github.com/zalando/go-keyring v0.2.4 diff --git a/go.sum b/go.sum index 0fb70947..13bfb646 100644 --- a/go.sum +++ b/go.sum @@ -85,8 +85,8 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY= -github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I= +github.com/go-resty/resty/v2 v2.12.0 h1:rsVL8P90LFvkUYq/V5BTVe203WfRIU4gvcf+yfzJzGA= +github.com/go-resty/resty/v2 v2.12.0/go.mod h1:o0yGPrkS3lOe1+eFajk6kBW8ScXzwU3hD69/gt2yB/0= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= @@ -97,8 +97,8 @@ github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keL github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= -github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= +github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= @@ -181,14 +181,14 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= -github.com/opentdf/platform/lib/fixtures v0.1.0 h1:xq0U+8C8tBqRCPGOvlATgeUVtU4qHrNWUdu1HSm3cGU= -github.com/opentdf/platform/lib/fixtures v0.1.0/go.mod h1:+d2iXFUZrI8MrWvh3tA3RK3ZgsnpD3JUtV74RwFJihQ= +github.com/opentdf/platform/lib/fixtures v0.2.0 h1:MIjJbl7bRV+NtQjJvsTIn3YyYZ/BckdTGJCLLRnUHCs= +github.com/opentdf/platform/lib/fixtures v0.2.0/go.mod h1:+d2iXFUZrI8MrWvh3tA3RK3ZgsnpD3JUtV74RwFJihQ= github.com/opentdf/platform/lib/ocrypto v0.1.0 h1:y1UlBZirbiFMzM+bVu6y4pjsX4Xhp2M50Tcjkubd/tI= github.com/opentdf/platform/lib/ocrypto v0.1.0/go.mod h1:eJgEy1WFzdShIwRIzyQ/PotbTpXOq4eApCgchtvSDLg= github.com/opentdf/platform/protocol/go v0.2.0 h1:V92LVoeXJsI7khBDnP/f22XtGZZJKqmcZMz4Pkn7jvM= github.com/opentdf/platform/protocol/go v0.2.0/go.mod h1:qOBx0d9F2dGeTc703tp+HCGhW6nLYXKZ+vmZ2H9xcPI= -github.com/opentdf/platform/sdk v0.2.0 h1:/t0TD6sJ9ERGFlrkBBJMZOfS3eyIPTOOvtEkoJe6PEU= -github.com/opentdf/platform/sdk v0.2.0/go.mod h1:4S/G31fK8SbSMv82xFbFaUyNOm/MGIi1uHeCi9gQdMg= +github.com/opentdf/platform/sdk v0.2.1 h1:iODPDMCvxnCgGV4a+J95OzbhLIO4I0EG0FfSulu/Q4U= +github.com/opentdf/platform/sdk v0.2.1/go.mod h1:j0aEN/6K3u5EREhbvy5rrHLX73bEQ5K79C+Yjz0iPlI= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= diff --git a/pkg/handlers/auth.go b/pkg/handlers/auth.go index aec8a64d..e1518c39 100644 --- a/pkg/handlers/auth.go +++ b/pkg/handlers/auth.go @@ -2,9 +2,11 @@ package handlers import ( "context" + "crypto/tls" "encoding/json" "errors" "fmt" + "net/http" "os" "time" @@ -20,7 +22,14 @@ const ( ) // TODO: get this dynamically from the platform via SDK or dialing directly: [https://github.com/opentdf/platform/issues/147] -const TOKEN_URL = "http://localhost:8888/auth/realms/opentdf/protocol/openid-connect/token" +var TOKEN_URL = "http://localhost:8888/auth/realms/opentdf/protocol/openid-connect/token" + +func init() { + tokenURL := os.Getenv("OTDFCTL_TOKEN_URL") + if tokenURL != "" { + TOKEN_URL = tokenURL + } +} // CheckTokenExpiration checks if an OIDC token has expired. // Returns true if the token is still valid, false otherwise. @@ -119,13 +128,22 @@ func GetClientCreds(file string, credsJSON []byte) (ClientCreds, error) { } // Uses the OAuth2 client credentials flow to obtain a token. -func GetTokenWithClientCreds(ctx context.Context, clientID, clientSecret, tokenURL string, noCache bool) (*oauth2.Token, error) { +func GetTokenWithClientCreds(ctx context.Context, clientID, clientSecret, tokenURL string, noCache bool, insecure bool) (*oauth2.Token, error) { // did the user pass a custom tokenURL? if tokenURL == "" { // use the default hardcoded constant tokenURL = TOKEN_URL } + // Only need to set the insecure client if the user passed the insecure flag + if insecure { + tr := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + insecureClient := &http.Client{Transport: tr} + ctx = context.WithValue(ctx, oauth2.HTTPClient, insecureClient) + } + config := clientcredentials.Config{ ClientID: clientID, ClientSecret: clientSecret, diff --git a/pkg/handlers/sdk.go b/pkg/handlers/sdk.go index 7c40c993..16f2caff 100644 --- a/pkg/handlers/sdk.go +++ b/pkg/handlers/sdk.go @@ -3,6 +3,7 @@ package handlers import ( "context" "errors" + "net/url" "github.com/opentdf/platform/protocol/go/common" "github.com/opentdf/platform/sdk" @@ -22,10 +23,40 @@ type Handler struct { } // Creates a new handler wrapping the SDK, which is authenticated through the cached client-credentials flow tokens -func New(platformEndpoint, clientID, clientSecret string) (Handler, error) { +func New(platformEndpoint, clientID, clientSecret string, insecure bool) (Handler, error) { scopes := []string{"email"} - sdk, err := sdk.New(platformEndpoint, sdk.WithClientCredentials(clientID, clientSecret, scopes), sdk.WithTokenEndpoint(TOKEN_URL), sdk.WithInsecureConn()) + opts := []sdk.Option{ + sdk.WithClientCredentials(clientID, clientSecret, scopes), + sdk.WithTokenEndpoint(TOKEN_URL), + } + + // Try an parse scheme out of platformEndpoint + // If it fails, use the default scheme of https + // There has to be a better way to do this + platformURL, err := url.Parse(platformEndpoint) + if err != nil { + return Handler{}, err + } + + switch platformURL.Scheme { + case "http": + opts = append(opts, sdk.WithInsecurePlaintextConn()) + if platformURL.Port() == "" { + platformURL.Host += ":80" + } + case "https": + if platformURL.Port() == "" { + platformURL.Host += ":443" + } + default: + return Handler{}, errors.New("invalid scheme") + } + if insecure { + opts = append(opts, sdk.WithInsecureSkipVerifyConn()) + } + + sdk, err := sdk.New(platformURL.Host, opts...) if err != nil { return Handler{}, err }