Skip to content

Commit

Permalink
Added support for the field "token" during Docker registry authorizat…
Browse files Browse the repository at this point in the history
…ion, closes #174 (#175)
  • Loading branch information
Simon Jahreiß authored and Erik Nelson committed Jan 21, 2019
1 parent dcb2c74 commit 212e283
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 5 deletions.
37 changes: 32 additions & 5 deletions registries/adapters/oauth/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,16 @@ import (
log "github.com/sirupsen/logrus"
)

// authResponse - holds the response data from an oauth2 token request
type authResponse struct {
// oauth2Response - holds the response data from an oauth2 token request
type oauth2Response struct {
Token string `json:"access_token"`
}

// dockerResponse - holds the response data from a docker token request
type dockerResponse struct {
Token string `json:"token"`
}

// NewClient - creates and returns a *Client ready to use. If skipVerify is
// true, it will skip verification of the remote TLS certificate.
func NewClient(user, pass string, skipVerify bool, url *url.URL) *Client {
Expand Down Expand Up @@ -187,12 +192,11 @@ func (c *Client) getToken(wwwauth string) error {
return err
}

authResp := authResponse{}
err = json.Unmarshal(body, &authResp)
c.token, err = parseAuthToken(body)
if err != nil {
return err
}
c.token = authResp.Token

log.Debugf("new token: %s", c.token)
return nil
}
Expand Down Expand Up @@ -234,3 +238,26 @@ func parseAuthHeader(value string) (*url.URL, error) {

return u, nil
}

// parseAuthToken - parses a token from a http response body in json format.
// The token can be located in the fields "access_token" or "token" of the json
// response. This method returns the value of one of those fields (favouring
// "access_token" if both are set) or an empty string if non of the fields is set.
func parseAuthToken(body []byte) (string, error) {
oauth2Resp := oauth2Response{}
err := json.Unmarshal(body, &oauth2Resp)
if err != nil {
return "", err
}

if oauth2Resp.Token != "" {
return oauth2Resp.Token, nil
}

dockerResp := dockerResponse{}
err = json.Unmarshal(body, &dockerResp)
if err != nil {
return "", err
}
return dockerResp.Token, nil
}
37 changes: 37 additions & 0 deletions registries/adapters/oauth/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,20 @@ var headerErrorCases = map[string]string{
"Bearer realm=\"\"": "",
}

var tokenCases = map[string]string{
"{\"access_token\": \"abc123\"}": "abc123",
"{\"token\": \"abc123\"}": "abc123",
"{\"access_token\": \"abc123\", \"token\": \"def456\"}": "abc123",
"{}": "",
}

var tokenErrorCases = map[string]string{
"{\"token\": {}": "unexpected end of JSON input",
"{\"access_token\": {}": "unexpected end of JSON input",
"{\"token\": null": "unexpected end of JSON input",
"{\"access_token\": null": "unexpected end of JSON input",
}

func TestParseAuthHeader(t *testing.T) {
for in, out := range headerCases {
result, err := parseAuthHeader(in)
Expand All @@ -58,6 +72,29 @@ func TestParseAuthHeaderErrors(t *testing.T) {
}
}

func TestParseAuthToken(t *testing.T) {
for in, out := range tokenCases {
result, err := parseAuthToken([]byte(in))
if err != nil {
t.Error(err.Error())
}
if result != out {
t.Errorf("Expected %s, got %s", out, result)
}
}
}

func TestParseAuthTokenErrors(t *testing.T) {
for in, out := range tokenErrorCases {
_, err := parseAuthToken([]byte(in))
if err == nil {
t.Errorf("Expected an error parsing %s", in)
} else if strings.HasPrefix(err.Error(), out) == false {
t.Errorf("Expected prefix %s, got %s", out, err.Error())
}
}
}

func TestNewRequest(t *testing.T) {
u, _ := url.Parse("http://automationbroker.io")
c := NewClient("foo", "bar", false, u)
Expand Down

0 comments on commit 212e283

Please sign in to comment.