Skip to content

Commit

Permalink
add basic auth tests
Browse files Browse the repository at this point in the history
  • Loading branch information
hgiasac committed Nov 15, 2024
1 parent 04d9f6e commit a5c05d7
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 25 deletions.
2 changes: 0 additions & 2 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ linters:
- err113
- lll
- gocognit
- execinquery
- exportloopref
- gomnd
- funlen
- godot
- gofumpt
Expand Down
5 changes: 3 additions & 2 deletions connector/connector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -654,8 +654,9 @@ func createMockServer(t *testing.T, apiKey string, bearerToken string) *httptest
mux.HandleFunc("/model", func(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodPost:
if r.Header.Get("api_key") != apiKey {
t.Errorf("invalid api key, expected %s, got %s", apiKey, r.Header.Get("api_key"))
user, password, ok := r.BasicAuth()
if !ok || user != "user" || password != "password" {
t.Errorf("invalid basic auth, expected user:password, got %s:%s", user, password)
t.FailNow()
return
}
Expand Down
8 changes: 7 additions & 1 deletion connector/internal/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package internal
import (
"bytes"
"context"
"encoding/base64"
"fmt"
"io"
"math/rand/v2"
Expand Down Expand Up @@ -203,7 +204,12 @@ func (req *RetryableRequest) applySecurityScheme(securityScheme rest.SecuritySch
case *rest.BasicAuthConfig:
username := config.GetUsername()
password := config.GetPassword()
req.URL.User = url.UserPassword(username, password)
if config.Header != "" {
b64Value := base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
req.Headers.Set(rest.AuthorizationHeader, "Basic "+b64Value)
} else {
req.URL.User = url.UserPassword(username, password)
}

return true, nil
case *rest.HTTPAuthConfig:
Expand Down
10 changes: 10 additions & 0 deletions connector/testdata/auth/schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ settings:
value:
env: PET_STORE_BEARER_TOKEN
scheme: bearer
basic:
type: basic
header: Authorization
username:
value: user
password:
value: password
scheme: bearer
petstore_auth:
type: oauth2
flows:
Expand Down Expand Up @@ -113,6 +121,8 @@ procedures:
request:
url: /model
method: post
security:
- basic: []
requestBody:
contentType: application/json
response:
Expand Down
14 changes: 11 additions & 3 deletions ndc-http-schema/jsonschema/ndc-http-schema.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@
"basic"
]
},
"user": {
"username": {
"$ref": "#/$defs/EnvString"
},
"password": {
Expand All @@ -577,7 +577,7 @@
"type": "object",
"required": [
"type",
"user",
"username",
"password"
]
},
Expand All @@ -593,7 +593,15 @@
"$ref": "#/$defs/EnvString"
},
"header": {
"type": "string"
"oneOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Request contains a header field in the form of Authorization: Basic \u003ccredentials\u003e"
},
"scheme": {
"type": "string"
Expand Down
41 changes: 25 additions & 16 deletions ndc-http-schema/schema/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,15 @@ func (j SecurityScheme) JSONSchema() *jsonschema.Schema {
Type: "string",
Enum: []any{BasicAuthScheme},
})
basicAuthSchema.Set("user", envStringRef)
basicAuthSchema.Set("username", envStringRef)
basicAuthSchema.Set("password", envStringRef)
httpAuthSchema.Set("header", &jsonschema.Schema{
Description: "Request contains a header field in the form of Authorization: Basic <credentials>",
OneOf: []*jsonschema.Schema{
{Type: "string"},
{Type: "null"},
},
})

oauth2Schema := orderedmap.New[string, *jsonschema.Schema]()
oauth2Schema.Set("type", &jsonschema.Schema{
Expand Down Expand Up @@ -212,7 +219,7 @@ func (j SecurityScheme) JSONSchema() *jsonschema.Schema {
{
Type: "object",
Properties: basicAuthSchema,
Required: []string{"type", "user", "password"},
Required: []string{"type", "username", "password"},
},
{
Type: "object",
Expand Down Expand Up @@ -399,7 +406,7 @@ func (ss APIKeyAuthConfig) GetValue() string {
//
// [bearer]: https://swagger.io/docs/specification/authentication/bearer-authentication
type HTTPAuthConfig struct {
Type SecuritySchemeType `json:"type" mapstructure:"type" yaml:"type"`
Type SecuritySchemeType `json:"type" mapstructure:"type" yaml:"type"`
Header string `json:"header" mapstructure:"header" yaml:"header"`
Scheme string `json:"scheme" mapstructure:"scheme" yaml:"scheme"`
Value utils.EnvString `json:"value" mapstructure:"value" yaml:"value"`
Expand Down Expand Up @@ -457,33 +464,34 @@ func (ss HTTPAuthConfig) GetValue() string {
//
// [basic]: https://swagger.io/docs/specification/authentication/basic-authentication
type BasicAuthConfig struct {
Type SecuritySchemeType `json:"type" mapstructure:"type" yaml:"type"`
User utils.EnvString `json:"user" mapstructure:"user" yaml:"user"`
Type SecuritySchemeType `json:"type" mapstructure:"type" yaml:"type"`
Header string `json:"header" mapstructure:"header" yaml:"header"`
Username utils.EnvString `json:"username" mapstructure:"username" yaml:"username"`
Password utils.EnvString `json:"password" mapstructure:"password" yaml:"password"`

// cached values
user *string
username *string
password *string
}

// NewBasicAuthConfig creates a new BasicAuthConfig instance.
func NewBasicAuthConfig(user, password utils.EnvString) *BasicAuthConfig {
func NewBasicAuthConfig(username, password utils.EnvString) *BasicAuthConfig {
return &BasicAuthConfig{
Type: BasicAuthScheme,
User: user,
Username: username,
Password: password,
}
}

// Validate if the current instance is valid
func (ss *BasicAuthConfig) Validate() error {
user, err := ss.User.Get()
user, err := ss.Username.Get()
if err != nil {
return fmt.Errorf("BasicAuthConfig.User: %w", err)
}

// user and password can be empty.
ss.user = &user
ss.username = &user

password, err := ss.Password.Get()
if err != nil {
Expand All @@ -501,11 +509,11 @@ func (ss BasicAuthConfig) GetType() SecuritySchemeType {

// GetUsername get the username value
func (ss BasicAuthConfig) GetUsername() string {
if ss.user != nil {
return *ss.user
if ss.username != nil {
return *ss.username
}

value, _ := ss.User.Get()
value, _ := ss.Username.Get()

return value
}
Expand Down Expand Up @@ -632,14 +640,15 @@ func (ss OAuth2Config) Validate() error {
return fmt.Errorf("%s: %w", key, err)
}
}

return nil
}

// OpenIDConnectConfig contains configurations for [OpenID Connect] API specification
//
// [OpenID Connect]: https://swagger.io/docs/specification/authentication/openid-connect-discovery
type OpenIDConnectConfig struct {
Type SecuritySchemeType `json:"type" mapstructure:"type" yaml:"type"`
Type SecuritySchemeType `json:"type" mapstructure:"type" yaml:"type"`
OpenIDConnectURL string `json:"openIdConnectUrl" mapstructure:"openIdConnectUrl" yaml:"openIdConnectUrl"`
}

Expand Down Expand Up @@ -672,7 +681,7 @@ func (ss OpenIDConnectConfig) Validate() error {

// CookieAuthConfig represents a cookie authentication configuration.
type CookieAuthConfig struct {
Type SecuritySchemeType `json:"type" mapstructure:"type" yaml:"type"`
Type SecuritySchemeType `json:"type" mapstructure:"type" yaml:"type"`
}

var _ SecuritySchemer = &CookieAuthConfig{}
Expand All @@ -696,7 +705,7 @@ func (ss CookieAuthConfig) Validate() error {

// MutualTLSAuthConfig represents a mutualTLS authentication configuration.
type MutualTLSAuthConfig struct {
Type SecuritySchemeType `json:"type" mapstructure:"type" yaml:"type"`
Type SecuritySchemeType `json:"type" mapstructure:"type" yaml:"type"`
}

var _ SecuritySchemer = &MutualTLSAuthConfig{}
Expand Down
49 changes: 48 additions & 1 deletion ndc-http-schema/schema/setting_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,33 @@ func TestNDCHttpSettings(t *testing.T) {
"in": "header",
"name": "api_key"
},
"http": {
"type": "http",
"value": {
"env": "PET_STORE_API_KEY"
},
"scheme": "bearer",
"header": "Authorization"
},
"basic": {
"type": "basic",
"username": {
"value": "user"
},
"password": {
"value": "password"
}
},
"cookie": {
"type": "cookie"
},
"mutualTLS": {
"type": "mutualTLS"
},
"oidc": {
"type": "openIdConnect",
"openIdConnectUrl": "http://localhost:8080/oauth/token"
},
"petstore_auth": {
"type": "oauth2",
"flows": {
Expand Down Expand Up @@ -88,12 +109,33 @@ func TestNDCHttpSettings(t *testing.T) {
value: utils.ToPtr("api_key"),
},
},
"basic": {
SecuritySchemer: &BasicAuthConfig{
Type: BasicAuthScheme,
Username: utils.NewEnvStringValue("user"),
Password: utils.NewEnvStringValue("password"),
username: utils.ToPtr("user"),
password: utils.ToPtr("password"),
},
},
"http": {
SecuritySchemer: &HTTPAuthConfig{
Type: HTTPAuthScheme,
Header: "Authorization",
Scheme: "bearer",
Value: utils.NewEnvStringVariable("PET_STORE_API_KEY"),
value: utils.ToPtr("api_key"),
},
},
"cookie": {
SecuritySchemer: NewCookieAuthConfig(),
},
"mutualTLS": {
SecuritySchemer: NewMutualTLSAuthConfig(),
},
"oidc": {
SecuritySchemer: NewOpenIDConnectConfig("http://localhost:8080/oauth/token"),
},
"petstore_auth": {
SecuritySchemer: &OAuth2Config{
Type: OAuth2Scheme,
Expand Down Expand Up @@ -131,7 +173,12 @@ func TestNDCHttpSettings(t *testing.T) {
}
assert.DeepEqual(t, tc.expected.Headers, result.Headers)
assert.DeepEqual(t, tc.expected.Security, result.Security)
assert.DeepEqual(t, tc.expected.SecuritySchemes, result.SecuritySchemes, cmp.Exporter(func(t reflect.Type) bool { return true }))
for key, expectedSS := range tc.expected.SecuritySchemes {
ss := result.SecuritySchemes[key]
ss.JSONSchema()
assert.Equal(t, expectedSS.GetType(), ss.GetType())
assert.DeepEqual(t, expectedSS.SecuritySchemer, ss.SecuritySchemer, cmp.Exporter(func(t reflect.Type) bool { return true }))
}
assert.DeepEqual(t, tc.expected.Version, result.Version)

_, err := json.Marshal(tc.expected)
Expand Down

0 comments on commit a5c05d7

Please sign in to comment.