Skip to content

Commit

Permalink
refactor client
Browse files Browse the repository at this point in the history
  • Loading branch information
stepansergeevitch committed Feb 27, 2025
1 parent 9bc5532 commit 5838347
Show file tree
Hide file tree
Showing 39 changed files with 1,028 additions and 892 deletions.
43 changes: 15 additions & 28 deletions auth.go → client/auth.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
package fireboltgosdk
package client

import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/url"
"strings"
"time"

"github.com/astaxie/beego/cache"
"github.com/firebolt-db/firebolt-go-sdk/errors"
"github.com/firebolt-db/firebolt-go-sdk/logging"

"github.com/astaxie/beego/cache"
)

const AuthAudienceValue = "https://api.firebolt.io"
Expand All @@ -34,25 +34,12 @@ func init() {
}
}

// Authenticate sends an authentication request, and returns a newly constructed client object
func Authenticate(settings *fireboltSettings, apiEndpoint string) (Client, error) {
userAgent := ConstructUserAgentString()

if settings.newVersion {
_, err := getAccessTokenServiceAccount(settings.clientID, settings.clientSecret, apiEndpoint, userAgent)
if err != nil {
return nil, errors.ConstructNestedError("error while getting access token", err)
} else {
return MakeClient(settings, apiEndpoint)
}
} else {
_, err := getAccessTokenUsernamePassword(settings.clientID, settings.clientSecret, apiEndpoint, userAgent)
if err != nil {
return nil, errors.ConstructNestedError("error while getting access token", err)
} else {
return MakeClientV0(settings, apiEndpoint)
}
}
// jsonStrictUnmarshall unmarshalls json into object, and returns an error
// if some fields are missing, or extra fields are present
func jsonStrictUnmarshall(data []byte, v interface{}) error {
decoder := json.NewDecoder(bytes.NewReader(data))
decoder.DisallowUnknownFields()
return decoder.Decode(v)
}

// getAccessTokenUsernamePassword gets an access token from the cache when it is available in the cache or from the server when it is not available in the cache
Expand All @@ -70,14 +57,14 @@ func getAccessTokenUsernamePassword(username string, password string, apiEndpoin
return "", err
}
logging.Infolog.Printf("Start authentication into '%s' using '%s'", apiEndpoint, loginUrl)
resp := request(requestParameters{context.TODO(), "", "POST", apiEndpoint + loginUrl, userAgent, nil, body, contentType})
resp := DoHttpRequest(requestParameters{context.TODO(), "", "POST", apiEndpoint + loginUrl, userAgent, nil, body, contentType})
if resp.err != nil {
return "", errors.ConstructNestedError("authentication request failed", resp.err)
return "", errors.ConstructNestedError("authentication DoHttpRequest failed", resp.err)
}

var authResp AuthenticationResponse
if err = jsonStrictUnmarshall(resp.data, &authResp); err != nil {
return "", errors.ConstructNestedError("failed to unmarshal authentication response with error", err)
return "", errors.ConstructNestedError("failed to unmarshal authentication Response with error", err)
}
logging.Infolog.Printf("Authentication was successful")
if tokenCache != nil {
Expand Down Expand Up @@ -119,14 +106,14 @@ func getAccessTokenServiceAccount(clientId string, clientSecret string, apiEndpo
return "", errors.ConstructNestedError("error building auth endpoint", err)
}
logging.Infolog.Printf("Start authentication into '%s' using '%s'", authEndpoint, loginUrl)
resp := request(requestParameters{context.TODO(), "", "POST", authEndpoint + loginUrl, userAgent, nil, body, contentType})
resp := DoHttpRequest(requestParameters{context.TODO(), "", "POST", authEndpoint + loginUrl, userAgent, nil, body, contentType})
if resp.err != nil {
return "", errors.ConstructNestedError("authentication request failed", resp.err)
return "", errors.ConstructNestedError("authentication DoHttpRequest failed", resp.err)
}

var authResp AuthenticationResponse
if err = jsonStrictUnmarshall(resp.data, &authResp); err != nil {
return "", errors.ConstructNestedError("failed to unmarshal authentication response with error", err)
return "", errors.ConstructNestedError("failed to unmarshal authentication Response with error", err)
}
logging.Infolog.Printf("Authentication was successful")
if tokenCache != nil {
Expand Down
36 changes: 19 additions & 17 deletions auth_integration_test.go → client/auth_integration_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
//go:build integration || integration_v0
// +build integration integration_v0

package fireboltgosdk
package client

import (
"testing"

"github.com/firebolt-db/firebolt-go-sdk/types"
)

// TestAuthHappyPath tests normal authentication, and that the access token is actually set
Expand All @@ -16,37 +18,37 @@ func TestAuthHappyPath(t *testing.T) {

// TestAuthWrongCredential checks that authentication with wrong credentials returns an error
func TestAuthWrongCredential(t *testing.T) {
if _, err := Authenticate(&fireboltSettings{
clientID: "TestAuthWrongCredential",
clientSecret: "wrong_secret",
newVersion: true,
if _, err := ClientFactory(&types.FireboltSettings{
ClientID: "TestAuthWrongCredential",
ClientSecret: "wrong_secret",
NewVersion: true,
}, GetHostNameURL()); err == nil {
t.Errorf("Authentication with wrong credentials didn't return an error for service account authentication")
}

if _, err := Authenticate(&fireboltSettings{
clientID: "TestAuthWrongCredential",
clientSecret: "wrong_password",
newVersion: false,
if _, err := ClientFactory(&types.FireboltSettings{
ClientID: "TestAuthWrongCredential",
ClientSecret: "wrong_password",
NewVersion: false,
}, GetHostNameURL()); err == nil {
t.Errorf("Authentication with wrong credentials didn't return an error for username/password authentication")
}
}

// TestAuthEmptyCredential checks that authentication with empty password returns an error
func TestAuthEmptyCredential(t *testing.T) {
if _, err := Authenticate(&fireboltSettings{
clientID: "TestAuthEmptyCredential",
clientSecret: "",
newVersion: true,
if _, err := ClientFactory(&types.FireboltSettings{
ClientID: "TestAuthEmptyCredential",
ClientSecret: "",
NewVersion: true,
}, GetHostNameURL()); err == nil {
t.Errorf("Authentication with empty password didn't return an error for service account authentication")
}

if _, err := Authenticate(&fireboltSettings{
clientID: "TestAuthEmptyCredential",
clientSecret: "",
newVersion: false,
if _, err := ClientFactory(&types.FireboltSettings{
ClientID: "TestAuthEmptyCredential",
ClientSecret: "",
NewVersion: false,
}, GetHostNameURL()); err == nil {
t.Errorf("Authentication with empty password didn't return an error for username/password authentication")
}
Expand Down
32 changes: 17 additions & 15 deletions client.go → client/client.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package fireboltgosdk
package client

import (
"context"
"encoding/json"
"errors"
"fmt"

"github.com/firebolt-db/firebolt-go-sdk/types"

errors2 "github.com/firebolt-db/firebolt-go-sdk/errors"
"github.com/firebolt-db/firebolt-go-sdk/logging"

Expand Down Expand Up @@ -41,18 +43,18 @@ func initialiseCaches() error {
return nil
}

func MakeClient(settings *fireboltSettings, apiEndpoint string) (*ClientImpl, error) {
func MakeClient(settings *types.FireboltSettings, apiEndpoint string) (*ClientImpl, error) {
client := &ClientImpl{
BaseClient: BaseClient{
ClientID: settings.clientID,
ClientSecret: settings.clientSecret,
ClientID: settings.ClientID,
ClientSecret: settings.ClientSecret,
ApiEndpoint: apiEndpoint,
UserAgent: ConstructUserAgentString(),
},
AccountName: settings.accountName,
AccountName: settings.AccountName,
}
client.parameterGetter = client.getQueryParams
client.accessTokenGetter = client.getAccessToken
client.ParameterGetter = client.GetQueryParams
client.AccessTokenGetter = client.getAccessToken

if err := initialiseCaches(); err != nil {
logging.Infolog.Printf("Error during cache initialisation: %v", err)
Expand Down Expand Up @@ -96,17 +98,17 @@ func (c *ClientImpl) getSystemEngineURLAndParameters(ctx context.Context, accoun
}
}

resp := c.request(ctx, "GET", url, make(map[string]string), "")
resp := c.requestWithAuthRetry(ctx, "GET", url, make(map[string]string), "")
if resp.statusCode == 404 {
return "", nil, fmt.Errorf(accountError, accountName)
}
if resp.err != nil {
return "", nil, errors2.ConstructNestedError("error during system engine url http request", resp.err)
return "", nil, errors2.ConstructNestedError("error during system engine url http DoHttpRequest", resp.err)
}

var systemEngineURLResponse SystemEngineURLResponse
if err := json.Unmarshal(resp.data, &systemEngineURLResponse); err != nil {
return "", nil, errors2.ConstructNestedError("error during unmarshalling system engine URL response", errors.New(string(resp.data)))
return "", nil, errors2.ConstructNestedError("error during unmarshalling system engine URL Response", errors.New(string(resp.data)))
}
if URLCache != nil {
URLCache.Put(url, systemEngineURLResponse, 0) //nolint:errcheck
Expand All @@ -121,7 +123,7 @@ func (c *ClientImpl) getSystemEngineURLAndParameters(ctx context.Context, accoun
return engineUrl, parameters, nil
}

func (c *ClientImpl) getQueryParams(setStatements map[string]string) (map[string]string, error) {
func (c *ClientImpl) GetQueryParams(setStatements map[string]string) (map[string]string, error) {
params := map[string]string{"output_format": outputFormat}
for setKey, setValue := range setStatements {
params[setKey] = setValue
Expand All @@ -143,14 +145,14 @@ func (c *ClientImpl) GetConnectionParameters(ctx context.Context, engineName, da
}
c.ConnectedToSystemEngine = true

control := connectionControl{
updateParameters: func(key, value string) {
control := ConnectionControl{
UpdateParameters: func(key, value string) {
parameters[key] = value
},
setEngineURL: func(s string) {
SetEngineURL: func(s string) {
engineURL = s
},
resetParameters: func() {},
ResetParameters: func() {},
}
if databaseName != "" {
sql := fmt.Sprintf("USE DATABASE \"%s\"", databaseName)
Expand Down
Loading

0 comments on commit 5838347

Please sign in to comment.