Repository: hamba/avro
Pull request #27 (2019-09-11 17:09:38)

Add Basic Auth support for Schema Registry

nrwiersma: Hey,

Thanks very much for contributing.

What about adding the auth creds as an optional input to the constructor instead? So it would look like `client, _ := registry.NewClient(s.URL, registry.WithBasicAuth("user", "pass"))`. Might be a little cleaner.
kingtong: Thanks for the feedback and the suggestion, it's much cleaner this way.
I'm not sold on the naming of the type/member `auth` although.
nrwiersma: In general i like it. 

If you prefer, you can rename `auth` to `credentials`. There is also no real need to compose the object. So perhaps `creds credentials` would be a better member of the struct?

Patch:
diff --git a/registry/client.go b/registry/client.go
index 7fe6e73..70e2644 100644
--- a/registry/client.go
+++ b/registry/client.go
@@ -57,6 +57,11 @@ type idPayload struct {
 	ID int `json:"id"`
 }
 
+type credentials struct {
+	username string
+	password string
+}
+
 var defaultClient = &http.Client{
 	Transport: &http.Transport{
 		Proxy: http.ProxyFromEnvironment,
@@ -78,11 +83,20 @@ func WithHTTPClient(client *http.Client) ClientFunc {
 	}
 }
 
+// WithBasicAuth sets the credentials to perform http basic auth.
+func WithBasicAuth(username string, password string) ClientFunc {
+	return func(c *Client) {
+		c.creds = credentials{username: username, password: password}
+	}
+}
+
 // Client is an HTTP registry client
 type Client struct {
 	client *http.Client
 	base   string
 
+	creds credentials
+
 	cache *concurrent.Map // map[int]avro.Schema
 }
 
@@ -210,6 +224,10 @@ func (c *Client) request(method, uri string, in, out interface{}) error {
 	req, _ := http.NewRequest(method, c.base+uri, body) // This error is not possible as we already parsed the url
 	req.Header.Set("Content-Type", contentType)
 
+	if len(c.creds.username) > 0 || len(c.creds.password) > 0 {
+		req.SetBasicAuth(c.creds.username, c.creds.password)
+	}
+
 	resp, err := c.client.Do(req)
 	if err != nil {
 		return err


Test patch:
diff --git a/registry/client_internal_test.go b/registry/client_internal_test.go
index cdc4c9e..bbd0256 100644
--- a/registry/client_internal_test.go
+++ b/registry/client_internal_test.go
@@ -14,3 +14,11 @@ func TestNewClient_WithHTTPClient(t *testing.T) {
 
 	assert.Equal(t, client.client, httpClient)
 }
+
+func TestNewClient_WithBasicAuth(t *testing.T) {
+	creds := credentials{username:"username", password:"password"}
+
+	client, _ := NewClient("http://example.com", WithBasicAuth("username", "password"))
+
+	assert.Equal(t, client.creds, creds)
+}
\ No newline at end of file
diff --git a/registry/client_test.go b/registry/client_test.go
index f509b70..862d053 100644
--- a/registry/client_test.go
+++ b/registry/client_test.go
@@ -42,6 +42,23 @@ func TestClient_PopulatesError(t *testing.T) {
 	assert.Equal(t, "schema may not be empty", regError.Message)
 }
 
+func TestNewClient_BasicAuth(t *testing.T) {
+	s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		username, password, ok := r.BasicAuth()
+		assert.True(t, ok)
+		assert.Equal(t, "username", username)
+		assert.Equal(t, "password", password)
+
+		_, _ = w.Write([]byte(`[]`))
+	}))
+	defer s.Close()
+	client, _ := registry.NewClient(s.URL, registry.WithBasicAuth("username", "password"))
+
+	_, err := client.GetSubjects()
+
+	assert.NoError(t, err)
+}
+
 func TestClient_GetSchema(t *testing.T) {
 	s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		assert.Equal(t, "GET", r.Method)