-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Change client initialization to accept an http.Client
This implementation follows the most common best practices around using a RoundTripper for authentication, rather than passing a credential and modifying the Do to apply the credential headers. Definining a RoundTripper is a more flexible, powerful, and elengant approach. This change requires to bump to 1.7 (given we add the dependency to golang/x/oauth2 that uses the context package). Closes GH-15
- Loading branch information
Showing
8 changed files
with
94 additions
and
88 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,6 @@ | ||
language: go | ||
|
||
go: | ||
- "1.2" | ||
- "1.3" | ||
- "1.4" | ||
- "1.5" | ||
- "1.6" | ||
- "1.7" | ||
- "1.8" | ||
- "1.9" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,52 +1,52 @@ | ||
package dnsimple | ||
|
||
import ( | ||
"encoding/base64" | ||
"net/http" | ||
) | ||
|
||
const ( | ||
httpHeaderAuthorization = "Authorization" | ||
) | ||
|
||
// Provides credentials that can be used for authenticating with DNSimple. | ||
// | ||
// See https://developer.dnsimple.com/v2/#authentication | ||
type Credentials interface { | ||
// Returns the HTTP headers that should be set | ||
// to authenticate the HTTP Request. | ||
Headers() map[string]string | ||
} | ||
// BasicAuthTransport is an http.RoundTripper that authenticates all requests | ||
// using HTTP Basic Authentication with the provided username and password. | ||
type BasicAuthTransport struct { | ||
Username string | ||
Password string | ||
|
||
// HTTP basic authentication | ||
type httpBasicCredentials struct { | ||
email string | ||
password string | ||
// Transport is the transport RoundTripper used to make HTTP requests. | ||
// If nil, http.DefaultTransport is used. | ||
Transport http.RoundTripper | ||
} | ||
|
||
// NewHTTPBasicCredentials construct Credentials using HTTP Basic Auth. | ||
func NewHTTPBasicCredentials(email, password string) Credentials { | ||
return &httpBasicCredentials{email, password} | ||
} | ||
|
||
func (c *httpBasicCredentials) Headers() map[string]string { | ||
return map[string]string{httpHeaderAuthorization: "Basic " + c.basicAuth(c.email, c.password)} | ||
} | ||
// RoundTrip implements the RoundTripper interface. We just add the | ||
// basic auth and return the RoundTripper for this transport type. | ||
func (t *BasicAuthTransport) RoundTrip(req *http.Request) (*http.Response, error) { | ||
req2 := cloneRequest(req) // per RoundTripper contract | ||
|
||
func (c *httpBasicCredentials) basicAuth(username, password string) string { | ||
auth := username + ":" + password | ||
return base64.StdEncoding.EncodeToString([]byte(auth)) | ||
req2.SetBasicAuth(t.Username, t.Password) | ||
return t.transport().RoundTrip(req2) | ||
} | ||
|
||
// OAuth token authentication | ||
type oauthTokenCredentials struct { | ||
oauthToken string | ||
// Client returns an *http.Client that uses the BasicAuthTransport transport | ||
// to authenticate the request via HTTP Basic Auth. | ||
func (t *BasicAuthTransport) Client() *http.Client { | ||
return &http.Client{Transport: t} | ||
} | ||
|
||
// NewOauthTokenCredentials construct Credentials using the OAuth access token. | ||
func NewOauthTokenCredentials(oauthToken string) Credentials { | ||
return &oauthTokenCredentials{oauthToken: oauthToken} | ||
func (t *BasicAuthTransport) transport() http.RoundTripper { | ||
if t.Transport != nil { | ||
return t.Transport | ||
} | ||
return http.DefaultTransport | ||
} | ||
|
||
func (c *oauthTokenCredentials) Headers() map[string]string { | ||
return map[string]string{httpHeaderAuthorization: "Bearer " + c.oauthToken} | ||
// cloneRequest returns a clone of the provided *http.Request. | ||
// The clone is a shallow copy of the struct and its Header map. | ||
func cloneRequest(r *http.Request) *http.Request { | ||
// shallow copy of the struct | ||
r2 := new(http.Request) | ||
*r2 = *r | ||
// deep copy of the Header | ||
r2.Header = make(http.Header, len(r.Header)) | ||
for k, s := range r.Header { | ||
r2.Header[k] = append([]string(nil), s...) | ||
} | ||
return r2 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1 @@ | ||
package dnsimple | ||
|
||
import ( | ||
"fmt" | ||
"reflect" | ||
"testing" | ||
) | ||
|
||
func testCredentials(t *testing.T, credentials Credentials, headers map[string]string) { | ||
if want, got := headers, credentials.Headers(); !reflect.DeepEqual(want, got) { | ||
t.Errorf("Header %v, want %v", got, want) | ||
} | ||
} | ||
|
||
func TestHttpBasicCredentialsHttpHeader(t *testing.T) { | ||
email, password := "email", "password" | ||
credentials := NewHTTPBasicCredentials(email, password) | ||
expectedHeaderValue := "Basic ZW1haWw6cGFzc3dvcmQ=" | ||
testCredentials(t, credentials, map[string]string{httpHeaderAuthorization: expectedHeaderValue}) | ||
} | ||
|
||
func TestOauthTokenCredentialsHttpHeader(t *testing.T) { | ||
oauthToken := "oauth-token" | ||
credentials := NewOauthTokenCredentials(oauthToken) | ||
expectedHeaderValue := fmt.Sprintf("Bearer %v", oauthToken) | ||
testCredentials(t, credentials, map[string]string{httpHeaderAuthorization: expectedHeaderValue}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters