Skip to content

Commit

Permalink
Add basic auth client
Browse files Browse the repository at this point in the history
  • Loading branch information
Piszmog committed Feb 18, 2024
1 parent 3a2bf02 commit 20daf21
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 12 deletions.
18 changes: 14 additions & 4 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cloudconfigclient

import (
"context"
"encoding/base64"
"errors"
"fmt"
"net/http"
Expand Down Expand Up @@ -64,21 +65,30 @@ func newLocalClientFromEnv(client *http.Client) ([]*HTTPClient, error) {
if len(localUrls) == 0 {
return nil, fmt.Errorf("no local Config Server URLs provided in environment variable %s", EnvironmentLocalConfigServerUrls)
}
return newLocalClient(client, strings.Split(localUrls, ",")), nil
return newSimpleClient(client, "", strings.Split(localUrls, ",")), nil
}

// Local creates a clients for a locally running Config Servers.
func Local(client *http.Client, urls ...string) Option {
return func(clients *[]*HTTPClient) error {
*clients = append(*clients, newLocalClient(client, urls)...)
*clients = append(*clients, newSimpleClient(client, "", urls)...)
return nil
}
}

func newLocalClient(client *http.Client, urls []string) []*HTTPClient {
// Basic creates a clients for a Config Server based on the provided basic authentication information.
func Basic(client *http.Client, username, password string, urls ...string) Option {
return func(clients *[]*HTTPClient) error {
auth := "Basic " + base64.StdEncoding.EncodeToString([]byte(username+":"+password))
*clients = append(*clients, newSimpleClient(client, auth, urls)...)
return nil
}
}

func newSimpleClient(client *http.Client, auth string, urls []string) []*HTTPClient {
clients := make([]*HTTPClient, len(urls), len(urls))
for index, baseUrl := range urls {
clients[index] = &HTTPClient{BaseURL: baseUrl, Client: client}
clients[index] = &HTTPClient{BaseURL: baseUrl, Client: client, Authorization: auth}
}
return clients
}
Expand Down
6 changes: 6 additions & 0 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ func TestOption(t *testing.T) {
{BaseURL: "http://localhost:8888", Client: &http.Client{}},
},
},
{

name: "Basic",
option: cloudconfigclient.Basic(&http.Client{}, "username", "password", "http://localhost:8880"),
expected: []*cloudconfigclient.HTTPClient{{BaseURL: "http://localhost:8880", Client: &http.Client{}, Authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ="}},
},
{
name: "DefaultCFService",
setup: func() {
Expand Down
2 changes: 1 addition & 1 deletion configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,8 @@ func toJson(propertySources []PropertySource) (map[string]interface{}, error) {
//
// A property source is either a YAML or a PROPERTIES file located in the repository that a Config Server is pointed at.
type PropertySource struct {
Name string `json:"name"`
Source map[string]interface{} `json:"source"`
Name string `json:"name"`
}

// Configuration interface for retrieving an application's configuration files from the Config Server.
Expand Down
19 changes: 15 additions & 4 deletions http.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"encoding/xml"
"errors"
"fmt"
"io/ioutil"
"io"
"net/http"
"net/url"
"path"
Expand All @@ -17,7 +17,11 @@ import (
// HTTPClient is a wrapper for http.Client.
type HTTPClient struct {
*http.Client
// BaseURL is the base URL for the Config Server.
BaseURL string
// Authorization is the authorization header value for the Config Server. If not provided, no authorization header is not explicitly set.
// If the client is using OAuth2, the authorization header is set automatically.
Authorization string
}

// ErrResourceNotFound is a special error that is used to propagate 404s.
Expand Down Expand Up @@ -45,7 +49,7 @@ func (h *HTTPClient) GetResource(paths []string, params map[string]string, dest
}
if resp.StatusCode != http.StatusOK {
var b []byte
b, err = ioutil.ReadAll(resp.Body)
b, err = io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("failed to read body with status code '%d': %w", resp.StatusCode, err)
}
Expand Down Expand Up @@ -89,7 +93,7 @@ func (h *HTTPClient) GetResourceRaw(paths []string, params map[string]string) ([
return nil, ErrResourceNotFound
}
var b []byte
b, err = ioutil.ReadAll(resp.Body)
b, err = io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read body with status code '%d': %w", resp.StatusCode, err)
}
Expand All @@ -105,7 +109,14 @@ func (h *HTTPClient) Get(paths []string, params map[string]string) (*http.Respon
if err != nil {
return nil, fmt.Errorf("failed to create url: %w", err)
}
response, err := h.Client.Get(fullUrl)
req, err := http.NewRequest(http.MethodGet, fullUrl, nil)
if err != nil {
return nil, fmt.Errorf("failed to create request for %s: %w", fullUrl, err)
}
if h.Authorization != "" {
req.Header.Set("Authorization", h.Authorization)
}
response, err := h.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to retrieve from %s: %w", fullUrl, err)
}
Expand Down
17 changes: 14 additions & 3 deletions http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package cloudconfigclient_test
import (
"bytes"
"errors"
"io/ioutil"
"io"
"net/http"
"testing"

Expand All @@ -29,7 +29,7 @@ func NewMockHttpResponse(code int, body string) *http.Response {
return &http.Response{
StatusCode: code,
// Send response to be tested
Body: ioutil.NopCloser(bytes.NewBufferString(body)),
Body: io.NopCloser(bytes.NewBufferString(body)),
// Must be set to non-nil value or it panics
Header: make(http.Header),
}
Expand All @@ -39,6 +39,7 @@ func TestHTTPClient_Get(t *testing.T) {
tests := []struct {
name string
baseURL string
auth string
paths []string
params map[string]string
response *http.Response
Expand All @@ -61,6 +62,7 @@ func TestHTTPClient_Get(t *testing.T) {
response: NewMockHttpResponse(200, ""),
checker: func(t *testing.T, request *http.Request) {
require.Equal(t, "/", request.URL.RequestURI())
require.Empty(t, request.Header.Get("Authorization"))
},
},
{
Expand Down Expand Up @@ -91,6 +93,15 @@ func TestHTTPClient_Get(t *testing.T) {
require.Equal(t, "/foo/bar?field=value", request.URL.RequestURI())
},
},
{
name: "Correct Request URI With Auth",
baseURL: "http://something",
auth: "Basic dXNlcjpwYXNz",
response: NewMockHttpResponse(200, ""),
checker: func(t *testing.T, request *http.Request) {
require.Equal(t, "Basic dXNlcjpwYXNz", request.Header.Get("Authorization"))
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
Expand All @@ -100,7 +111,7 @@ func TestHTTPClient_Get(t *testing.T) {
}
return test.response
})
httpClient := cloudconfigclient.HTTPClient{BaseURL: test.baseURL, Client: client}
httpClient := cloudconfigclient.HTTPClient{BaseURL: test.baseURL, Client: client, Authorization: test.auth}
_, err := httpClient.Get(test.paths, test.params)
if err != nil {
require.Error(t, err)
Expand Down

0 comments on commit 20daf21

Please sign in to comment.