github.com/uriddle/docker@v0.0.0-20210926094723-4072e6aeb013/registry/token.go (about)

     1  package registry
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"net/http"
     8  	"net/url"
     9  	"strings"
    10  )
    11  
    12  type tokenResponse struct {
    13  	Token string `json:"token"`
    14  }
    15  
    16  func getToken(username, password string, params map[string]string, registryEndpoint *Endpoint) (string, error) {
    17  	realm, ok := params["realm"]
    18  	if !ok {
    19  		return "", errors.New("no realm specified for token auth challenge")
    20  	}
    21  
    22  	realmURL, err := url.Parse(realm)
    23  	if err != nil {
    24  		return "", fmt.Errorf("invalid token auth challenge realm: %s", err)
    25  	}
    26  
    27  	if realmURL.Scheme == "" {
    28  		if registryEndpoint.IsSecure {
    29  			realmURL.Scheme = "https"
    30  		} else {
    31  			realmURL.Scheme = "http"
    32  		}
    33  	}
    34  
    35  	req, err := http.NewRequest("GET", realmURL.String(), nil)
    36  	if err != nil {
    37  		return "", err
    38  	}
    39  
    40  	reqParams := req.URL.Query()
    41  	service := params["service"]
    42  	scope := params["scope"]
    43  
    44  	if service != "" {
    45  		reqParams.Add("service", service)
    46  	}
    47  
    48  	for _, scopeField := range strings.Fields(scope) {
    49  		reqParams.Add("scope", scopeField)
    50  	}
    51  
    52  	if username != "" {
    53  		reqParams.Add("account", username)
    54  		req.SetBasicAuth(username, password)
    55  	}
    56  
    57  	req.URL.RawQuery = reqParams.Encode()
    58  
    59  	resp, err := registryEndpoint.client.Do(req)
    60  	if err != nil {
    61  		return "", err
    62  	}
    63  	defer resp.Body.Close()
    64  
    65  	if resp.StatusCode != http.StatusOK {
    66  		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))
    67  	}
    68  
    69  	decoder := json.NewDecoder(resp.Body)
    70  
    71  	tr := new(tokenResponse)
    72  	if err = decoder.Decode(tr); err != nil {
    73  		return "", fmt.Errorf("unable to decode token response: %s", err)
    74  	}
    75  
    76  	if tr.Token == "" {
    77  		return "", errors.New("authorization server did not include a token in the response")
    78  	}
    79  
    80  	return tr.Token, nil
    81  }