diff --git a/client/driver/driver_test.go b/client/driver/driver_test.go index 27e5390..41fa5b5 100644 --- a/client/driver/driver_test.go +++ b/client/driver/driver_test.go @@ -19,6 +19,7 @@ import ( "crypto/tls" "crypto/x509" "fmt" + "io/ioutil" "net" "net/http" "os" @@ -295,25 +296,25 @@ func testTxBasic(t *testing.T, c Driver, mc *mockServer) { } func TestGRPCDriver(t *testing.T) { - client, mockServer, cancel := setupGRPCTests(t, &Config{}) + client, mockServer, cancel := setupGRPCTests(t, &Config{Token: "aaa"}) defer cancel() testDriverBasic(t, client, mockServer) } func TestHTTPDriver(t *testing.T) { - client, mockServer, cancel := setupHTTPTests(t, &Config{}) + client, mockServer, cancel := setupHTTPTests(t, &Config{Token: "aaa"}) defer cancel() testDriverBasic(t, client, mockServer) } func TestTxGRPCDriver(t *testing.T) { - client, mockServer, cancel := setupGRPCTests(t, &Config{}) + client, mockServer, cancel := setupGRPCTests(t, &Config{Token: "aaa"}) defer cancel() testTxBasic(t, client, mockServer) } func TestTxHTTPDriver(t *testing.T) { - client, mockServer, cancel := setupHTTPTests(t, &Config{}) + client, mockServer, cancel := setupHTTPTests(t, &Config{Token: "aaa"}) defer cancel() testTxBasic(t, client, mockServer) } @@ -391,6 +392,13 @@ func setupTests(t *testing.T) (*mockServer, func()) { r.HandleFunc(apiPathPrefix+documentPathPattern, func(w http.ResponseWriter, r *http.Request) { mux.ServeHTTP(w, r) }) + r.HandleFunc("/token", func(w http.ResponseWriter, r *http.Request) { + b, err := ioutil.ReadAll(r.Body) + require.NoError(t, err) + require.Equal(t, []byte(`grant_type=refresh_token&refresh_token=refresh_token_123`), b) + _, err = w.Write([]byte(`access_token=refreshed_token_config_123`)) + require.NoError(t, err) + }) var wg sync.WaitGroup @@ -438,14 +446,14 @@ func testDriverAuth(t *testing.T, d Driver, mc *mockServer, token string) { func TestGRPCDriverAuth(t *testing.T) { t.Run("config", func(t *testing.T) { - client, mockServer, cancel := setupGRPCTests(t, &Config{AuthToken: "token_config_123"}) + client, mockServer, cancel := setupGRPCTests(t, &Config{Token: "token_config_123"}) defer cancel() testDriverAuth(t, client, mockServer, "token_config_123") }) t.Run("env", func(t *testing.T) { - err := os.Setenv(AUTH_TOKEN_ENV, "token_env_567") + err := os.Setenv(TOKEN_ENV, "token_env_567") require.NoError(t, err) client, mockServer, cancel := setupGRPCTests(t, &Config{}) @@ -453,21 +461,21 @@ func TestGRPCDriverAuth(t *testing.T) { testDriverAuth(t, client, mockServer, "token_env_567") - err = os.Unsetenv(AUTH_TOKEN_ENV) + err = os.Unsetenv(TOKEN_ENV) require.NoError(t, err) }) } func TestHTTPDriverAuth(t *testing.T) { t.Run("config", func(t *testing.T) { - client, mockServer, cancel := setupHTTPTests(t, &Config{AuthToken: "token_config_123"}) + client, mockServer, cancel := setupHTTPTests(t, &Config{Token: "token_config_123"}) defer cancel() testDriverAuth(t, client, mockServer, "token_config_123") }) t.Run("env", func(t *testing.T) { - err := os.Setenv(AUTH_TOKEN_ENV, "token_env_567") + err := os.Setenv(TOKEN_ENV, "token_env_567") require.NoError(t, err) client, mockServer, cancel := setupHTTPTests(t, &Config{}) @@ -475,11 +483,29 @@ func TestHTTPDriverAuth(t *testing.T) { testDriverAuth(t, client, mockServer, "token_env_567") - err = os.Unsetenv(AUTH_TOKEN_ENV) + err = os.Unsetenv(TOKEN_ENV) require.NoError(t, err) }) } +func TestGRPCTokenRefresh(t *testing.T) { + TOKEN_REFRESH_URL = TestHTTPURL + "/token" + + client, mockServer, cancel := setupGRPCTests(t, &Config{Token: "token_config_123:refresh_token_123"}) + defer cancel() + + testDriverAuth(t, client, mockServer, "refreshed_token_config_123") +} + +func TestHTTPTokenRefresh(t *testing.T) { + TOKEN_REFRESH_URL = TestHTTPURL + "/token" + + client, mockServer, cancel := setupHTTPTests(t, &Config{Token: "token_config_123:refresh_token_123"}) + defer cancel() + + testDriverAuth(t, client, mockServer, "refreshed_token_config_123") +} + var testServerKey = ` -----BEGIN PRIVATE KEY----- MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALmad2p/jWwu6Wbc diff --git a/client/driver/grpc.go b/client/driver/grpc.go index 25ed526..794e6d5 100644 --- a/client/driver/grpc.go +++ b/client/driver/grpc.go @@ -20,7 +20,6 @@ import ( "unsafe" api "github.com/tigrisdata/tigrisdb-client-go/api/server/v1" - "golang.org/x/oauth2" "google.golang.org/grpc" "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/oauth" @@ -31,11 +30,14 @@ type grpcDriver struct { conn *grpc.ClientConn } -func NewGRPCClient(_ context.Context, url string, config *Config) (Driver, error) { - rpcCreds := oauth.NewOauthAccess(&oauth2.Token{AccessToken: getAuthToken(config)}) +func NewGRPCClient(ctx context.Context, url string, config *Config) (Driver, error) { + token, oCfg, ctxClient := getAuthToken(ctx, config) + + ts := oCfg.TokenSource(ctxClient, token) + conn, err := grpc.Dial(url, grpc.WithTransportCredentials(credentials.NewTLS(config.TLS)), - grpc.WithPerRPCCredentials(rpcCreds), + grpc.WithPerRPCCredentials(oauth.TokenSource{TokenSource: ts}), //grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.FailOnNonTempDialError(true), grpc.WithReturnConnectionError(), diff --git a/client/driver/http.go b/client/driver/http.go index 2f80fef..ceeb671 100644 --- a/client/driver/http.go +++ b/client/driver/http.go @@ -7,7 +7,6 @@ import ( "net/http" "unsafe" - "github.com/deepmap/oapi-codegen/pkg/securityprovider" userHTTP "github.com/tigrisdata/tigrisdb-client-go/api/client/v1/user" ) @@ -30,21 +29,13 @@ type httpDriver struct { *httpCRUD } -func NewHTTPClient(_ context.Context, url string, config *Config) (Driver, error) { - auth, err := securityprovider.NewSecurityProviderBearerToken(getAuthToken(config)) - if err != nil { - return nil, err - } - - t := &http.Transport{ - TLSClientConfig: config.TLS, - } +func NewHTTPClient(ctx context.Context, url string, config *Config) (Driver, error) { + token, oCfg, ctxClient := getAuthToken(ctx, config) - hc := http.Client{Transport: t} + hc := oCfg.Client(ctxClient, token) c, err := userHTTP.NewClientWithResponses(url, - userHTTP.WithRequestEditorFn(auth.Intercept), - userHTTP.WithHTTPClient(&hc), + userHTTP.WithHTTPClient(hc), ) return &driver{driverWithOptions: &httpDriver{httpCRUD: &httpCRUD{api: c}}}, err } diff --git a/client/driver/internal.go b/client/driver/internal.go index 3050841..7850b27 100644 --- a/client/driver/internal.go +++ b/client/driver/internal.go @@ -2,7 +2,12 @@ package driver import ( "context" + "net/http" "os" + "strings" + "time" + + "golang.org/x/oauth2" ) type driverWithOptions interface { @@ -31,10 +36,31 @@ type txWithOptions interface { Rollback(ctx context.Context) error } -func getAuthToken(config *Config) string { - token := config.AuthToken - if os.Getenv(AUTH_TOKEN_ENV) != "" { - token = os.Getenv(AUTH_TOKEN_ENV) +func getAuthToken(ctx context.Context, config *Config) (*oauth2.Token, *oauth2.Config, context.Context) { + token := config.Token + if os.Getenv(TOKEN_ENV) != "" { + token = os.Getenv(TOKEN_ENV) + } + + parts := strings.Split(token, ":") + + t := oauth2.Token{} + + if len(parts) > 0 { + t.AccessToken = parts[0] } - return token + + if len(parts) > 1 { + t.RefreshToken = parts[1] + // So as we have refresh token, just disregard current access token and refresh immediately + t.Expiry = time.Now() + } + + tr := &http.Transport{ + TLSClientConfig: config.TLS, + } + + ocfg := &oauth2.Config{Endpoint: oauth2.Endpoint{TokenURL: TOKEN_REFRESH_URL}} + + return &t, ocfg, context.WithValue(ctx, oauth2.HTTPClient, &http.Client{Transport: tr}) } diff --git a/client/driver/types.go b/client/driver/types.go index efa481f..9f9667f 100644 --- a/client/driver/types.go +++ b/client/driver/types.go @@ -8,11 +8,15 @@ import ( ) const ( - GRPC = iota - HTTP = iota - DefaultProtocol = GRPC + GRPC = iota + HTTP = iota - AUTH_TOKEN_ENV = "TIGRISDB_AUTH_TOKEN" + TOKEN_ENV = "TIGRISDB_TOKEN" +) + +var ( + DefaultProtocol = GRPC + TOKEN_REFRESH_URL = "https://tigrisdata-dev.us.auth0.com/oauth/token" ) type Document json.RawMessage @@ -36,6 +40,6 @@ type UpdateResponse *api.UpdateResponse type DeleteResponse *api.DeleteResponse type Config struct { - AuthToken string `json:"auth_token"` - TLS *tls.Config `json:"tls"` + TLS *tls.Config `json:"tls,omitempty"` + Token string `json:",omitempty"` } diff --git a/go.mod b/go.mod index a4d3eab..0d4afa3 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,6 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e // indirect golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 // indirect golang.org/x/text v0.3.7 // indirect diff --git a/go.sum b/go.sum index 57ea902..ee2e2d0 100644 --- a/go.sum +++ b/go.sum @@ -185,9 +185,7 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/labstack/echo/v4 v4.6.3 h1:VhPuIZYxsbPmo4m9KAkMU/el2442eB7EBFFhNTTT9ac= github.com/labstack/echo/v4 v4.6.3/go.mod h1:Hk5OiHj0kDqmFq7aHe7eDqI7CUhuCrfpupQtLGGLm7A= -github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o= github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= @@ -204,10 +202,8 @@ github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= -github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= @@ -242,9 +238,7 @@ github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVM github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -269,8 +263,6 @@ golang.org/x/crypto v0.0.0-20201217014255-9d1352758620/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e h1:1SzTfNOXwIS2oWiMF+6qu0OUDKb0dauo6MoDUQyu+yU= -golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=