Skip to content

Commit 20daf21

Browse files
committed
Add basic auth client
1 parent 3a2bf02 commit 20daf21

File tree

5 files changed

+50
-12
lines changed

5 files changed

+50
-12
lines changed

client.go

+14-4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package cloudconfigclient
22

33
import (
44
"context"
5+
"encoding/base64"
56
"errors"
67
"fmt"
78
"net/http"
@@ -64,21 +65,30 @@ func newLocalClientFromEnv(client *http.Client) ([]*HTTPClient, error) {
6465
if len(localUrls) == 0 {
6566
return nil, fmt.Errorf("no local Config Server URLs provided in environment variable %s", EnvironmentLocalConfigServerUrls)
6667
}
67-
return newLocalClient(client, strings.Split(localUrls, ",")), nil
68+
return newSimpleClient(client, "", strings.Split(localUrls, ",")), nil
6869
}
6970

7071
// Local creates a clients for a locally running Config Servers.
7172
func Local(client *http.Client, urls ...string) Option {
7273
return func(clients *[]*HTTPClient) error {
73-
*clients = append(*clients, newLocalClient(client, urls)...)
74+
*clients = append(*clients, newSimpleClient(client, "", urls)...)
7475
return nil
7576
}
7677
}
7778

78-
func newLocalClient(client *http.Client, urls []string) []*HTTPClient {
79+
// Basic creates a clients for a Config Server based on the provided basic authentication information.
80+
func Basic(client *http.Client, username, password string, urls ...string) Option {
81+
return func(clients *[]*HTTPClient) error {
82+
auth := "Basic " + base64.StdEncoding.EncodeToString([]byte(username+":"+password))
83+
*clients = append(*clients, newSimpleClient(client, auth, urls)...)
84+
return nil
85+
}
86+
}
87+
88+
func newSimpleClient(client *http.Client, auth string, urls []string) []*HTTPClient {
7989
clients := make([]*HTTPClient, len(urls), len(urls))
8090
for index, baseUrl := range urls {
81-
clients[index] = &HTTPClient{BaseURL: baseUrl, Client: client}
91+
clients[index] = &HTTPClient{BaseURL: baseUrl, Client: client, Authorization: auth}
8292
}
8393
return clients
8494
}

client_test.go

+6
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ func TestOption(t *testing.T) {
102102
{BaseURL: "http://localhost:8888", Client: &http.Client{}},
103103
},
104104
},
105+
{
106+
107+
name: "Basic",
108+
option: cloudconfigclient.Basic(&http.Client{}, "username", "password", "http://localhost:8880"),
109+
expected: []*cloudconfigclient.HTTPClient{{BaseURL: "http://localhost:8880", Client: &http.Client{}, Authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ="}},
110+
},
105111
{
106112
name: "DefaultCFService",
107113
setup: func() {

configuration.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,8 @@ func toJson(propertySources []PropertySource) (map[string]interface{}, error) {
143143
//
144144
// A property source is either a YAML or a PROPERTIES file located in the repository that a Config Server is pointed at.
145145
type PropertySource struct {
146-
Name string `json:"name"`
147146
Source map[string]interface{} `json:"source"`
147+
Name string `json:"name"`
148148
}
149149

150150
// Configuration interface for retrieving an application's configuration files from the Config Server.

http.go

+15-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"encoding/xml"
66
"errors"
77
"fmt"
8-
"io/ioutil"
8+
"io"
99
"net/http"
1010
"net/url"
1111
"path"
@@ -17,7 +17,11 @@ import (
1717
// HTTPClient is a wrapper for http.Client.
1818
type HTTPClient struct {
1919
*http.Client
20+
// BaseURL is the base URL for the Config Server.
2021
BaseURL string
22+
// Authorization is the authorization header value for the Config Server. If not provided, no authorization header is not explicitly set.
23+
// If the client is using OAuth2, the authorization header is set automatically.
24+
Authorization string
2125
}
2226

2327
// ErrResourceNotFound is a special error that is used to propagate 404s.
@@ -45,7 +49,7 @@ func (h *HTTPClient) GetResource(paths []string, params map[string]string, dest
4549
}
4650
if resp.StatusCode != http.StatusOK {
4751
var b []byte
48-
b, err = ioutil.ReadAll(resp.Body)
52+
b, err = io.ReadAll(resp.Body)
4953
if err != nil {
5054
return fmt.Errorf("failed to read body with status code '%d': %w", resp.StatusCode, err)
5155
}
@@ -89,7 +93,7 @@ func (h *HTTPClient) GetResourceRaw(paths []string, params map[string]string) ([
8993
return nil, ErrResourceNotFound
9094
}
9195
var b []byte
92-
b, err = ioutil.ReadAll(resp.Body)
96+
b, err = io.ReadAll(resp.Body)
9397
if err != nil {
9498
return nil, fmt.Errorf("failed to read body with status code '%d': %w", resp.StatusCode, err)
9599
}
@@ -105,7 +109,14 @@ func (h *HTTPClient) Get(paths []string, params map[string]string) (*http.Respon
105109
if err != nil {
106110
return nil, fmt.Errorf("failed to create url: %w", err)
107111
}
108-
response, err := h.Client.Get(fullUrl)
112+
req, err := http.NewRequest(http.MethodGet, fullUrl, nil)
113+
if err != nil {
114+
return nil, fmt.Errorf("failed to create request for %s: %w", fullUrl, err)
115+
}
116+
if h.Authorization != "" {
117+
req.Header.Set("Authorization", h.Authorization)
118+
}
119+
response, err := h.Do(req)
109120
if err != nil {
110121
return nil, fmt.Errorf("failed to retrieve from %s: %w", fullUrl, err)
111122
}

http_test.go

+14-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package cloudconfigclient_test
33
import (
44
"bytes"
55
"errors"
6-
"io/ioutil"
6+
"io"
77
"net/http"
88
"testing"
99

@@ -29,7 +29,7 @@ func NewMockHttpResponse(code int, body string) *http.Response {
2929
return &http.Response{
3030
StatusCode: code,
3131
// Send response to be tested
32-
Body: ioutil.NopCloser(bytes.NewBufferString(body)),
32+
Body: io.NopCloser(bytes.NewBufferString(body)),
3333
// Must be set to non-nil value or it panics
3434
Header: make(http.Header),
3535
}
@@ -39,6 +39,7 @@ func TestHTTPClient_Get(t *testing.T) {
3939
tests := []struct {
4040
name string
4141
baseURL string
42+
auth string
4243
paths []string
4344
params map[string]string
4445
response *http.Response
@@ -61,6 +62,7 @@ func TestHTTPClient_Get(t *testing.T) {
6162
response: NewMockHttpResponse(200, ""),
6263
checker: func(t *testing.T, request *http.Request) {
6364
require.Equal(t, "/", request.URL.RequestURI())
65+
require.Empty(t, request.Header.Get("Authorization"))
6466
},
6567
},
6668
{
@@ -91,6 +93,15 @@ func TestHTTPClient_Get(t *testing.T) {
9193
require.Equal(t, "/foo/bar?field=value", request.URL.RequestURI())
9294
},
9395
},
96+
{
97+
name: "Correct Request URI With Auth",
98+
baseURL: "http://something",
99+
auth: "Basic dXNlcjpwYXNz",
100+
response: NewMockHttpResponse(200, ""),
101+
checker: func(t *testing.T, request *http.Request) {
102+
require.Equal(t, "Basic dXNlcjpwYXNz", request.Header.Get("Authorization"))
103+
},
104+
},
94105
}
95106
for _, test := range tests {
96107
t.Run(test.name, func(t *testing.T) {
@@ -100,7 +111,7 @@ func TestHTTPClient_Get(t *testing.T) {
100111
}
101112
return test.response
102113
})
103-
httpClient := cloudconfigclient.HTTPClient{BaseURL: test.baseURL, Client: client}
114+
httpClient := cloudconfigclient.HTTPClient{BaseURL: test.baseURL, Client: client, Authorization: test.auth}
104115
_, err := httpClient.Get(test.paths, test.params)
105116
if err != nil {
106117
require.Error(t, err)

0 commit comments

Comments
 (0)