89bd48481c
This patch removes the need for requestFactories and decorators by implementing http.RoundTripper transports instead. It refactors some challenging-to-read code. NewSession now takes an *http.Client that can already have a custom Transport, it will add its own auth transport by wrapping it. The idea is that callers of http.Client should not bother setting custom headers for every handler but instead it should be transparent to the callers of a same context. This patch is needed for future refactorings of registry, namely refactoring of the v1 client code. Signed-off-by: Tibor Vass <tibor@docker.com>
81 lines
1.7 KiB
Go
81 lines
1.7 KiB
Go
package registry
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
)
|
|
|
|
type tokenResponse struct {
|
|
Token string `json:"token"`
|
|
}
|
|
|
|
func getToken(username, password string, params map[string]string, registryEndpoint *Endpoint, client *http.Client) (token string, err error) {
|
|
realm, ok := params["realm"]
|
|
if !ok {
|
|
return "", errors.New("no realm specified for token auth challenge")
|
|
}
|
|
|
|
realmURL, err := url.Parse(realm)
|
|
if err != nil {
|
|
return "", fmt.Errorf("invalid token auth challenge realm: %s", err)
|
|
}
|
|
|
|
if realmURL.Scheme == "" {
|
|
if registryEndpoint.IsSecure {
|
|
realmURL.Scheme = "https"
|
|
} else {
|
|
realmURL.Scheme = "http"
|
|
}
|
|
}
|
|
|
|
req, err := http.NewRequest("GET", realmURL.String(), nil)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
reqParams := req.URL.Query()
|
|
service := params["service"]
|
|
scope := params["scope"]
|
|
|
|
if service != "" {
|
|
reqParams.Add("service", service)
|
|
}
|
|
|
|
for _, scopeField := range strings.Fields(scope) {
|
|
reqParams.Add("scope", scopeField)
|
|
}
|
|
|
|
if username != "" {
|
|
reqParams.Add("account", username)
|
|
req.SetBasicAuth(username, password)
|
|
}
|
|
|
|
req.URL.RawQuery = reqParams.Encode()
|
|
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
return "", fmt.Errorf("token auth attempt for registry %s: %s request failed with status: %d %s", registryEndpoint, req.URL, resp.StatusCode, http.StatusText(resp.StatusCode))
|
|
}
|
|
|
|
decoder := json.NewDecoder(resp.Body)
|
|
|
|
tr := new(tokenResponse)
|
|
if err = decoder.Decode(tr); err != nil {
|
|
return "", fmt.Errorf("unable to decode token response: %s", err)
|
|
}
|
|
|
|
if tr.Token == "" {
|
|
return "", errors.New("authorization server did not include a token in the response")
|
|
}
|
|
|
|
return tr.Token, nil
|
|
}
|