Move the auth file creation to GetCredentials

This shares the code, and makes getConfigCredentials
and getAuthCredentials side-effect free and possibly easier to test.

Should not change behavior.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
This commit is contained in:
Miloslav Trmač
2021-09-11 22:52:47 +02:00
parent 9d56ebb611
commit 29f4088713

View File

@ -31,48 +31,59 @@ const XRegistryAuthHeader HeaderAuthName = "X-Registry-Auth"
const XRegistryConfigHeader HeaderAuthName = "X-Registry-Config" const XRegistryConfigHeader HeaderAuthName = "X-Registry-Config"
// GetCredentials queries the http.Request for X-Registry-.* headers and extracts // GetCredentials queries the http.Request for X-Registry-.* headers and extracts
// the necessary authentication information for libpod operations // the necessary authentication information for libpod operations, possibly
// creating a config file. If that is the case, the caller must call RemoveAuthFile.
func GetCredentials(r *http.Request) (*types.DockerAuthConfig, string, error) { func GetCredentials(r *http.Request) (*types.DockerAuthConfig, string, error) {
nonemptyHeaderValue := func(key HeaderAuthName) ([]string, bool) { nonemptyHeaderValue := func(key HeaderAuthName) ([]string, bool) {
hdr := r.Header.Values(key.String()) hdr := r.Header.Values(key.String())
return hdr, len(hdr) > 0 return hdr, len(hdr) > 0
} }
var override *types.DockerAuthConfig var override *types.DockerAuthConfig
var authFile string var fileContents map[string]types.DockerAuthConfig
var headerName HeaderAuthName var headerName HeaderAuthName
var err error var err error
if hdr, ok := nonemptyHeaderValue(XRegistryConfigHeader); ok { if hdr, ok := nonemptyHeaderValue(XRegistryConfigHeader); ok {
headerName = XRegistryConfigHeader headerName = XRegistryConfigHeader
override, authFile, err = getConfigCredentials(r, hdr) override, fileContents, err = getConfigCredentials(r, hdr)
} else if hdr, ok := nonemptyHeaderValue(XRegistryAuthHeader); ok { } else if hdr, ok := nonemptyHeaderValue(XRegistryAuthHeader); ok {
headerName = XRegistryAuthHeader headerName = XRegistryAuthHeader
override, authFile, err = getAuthCredentials(hdr) override, fileContents, err = getAuthCredentials(hdr)
} else { } else {
return nil, "", nil return nil, "", nil
} }
if err != nil { if err != nil {
return nil, "", errors.Wrapf(err, "failed to parse %q header for %s", headerName, r.URL.String()) return nil, "", errors.Wrapf(err, "failed to parse %q header for %s", headerName, r.URL.String())
} }
var authFile string
if fileContents == nil {
authFile = ""
} else {
authFile, err = authConfigsToAuthFile(fileContents)
if err != nil {
return nil, "", errors.Wrapf(err, "failed to parse %q header for %s", headerName, r.URL.String())
}
}
return override, authFile, nil return override, authFile, nil
} }
// getConfigCredentials extracts one or more docker.AuthConfig from a request and its // getConfigCredentials extracts one or more docker.AuthConfig from a request and its
// XRegistryConfigHeader value. An empty key will be used as default while a named registry will be // XRegistryConfigHeader value. An empty key will be used as default while a named registry will be
// returned as types.DockerAuthConfig // returned as types.DockerAuthConfig
func getConfigCredentials(r *http.Request, headers []string) (*types.DockerAuthConfig, string, error) { func getConfigCredentials(r *http.Request, headers []string) (*types.DockerAuthConfig, map[string]types.DockerAuthConfig, error) {
var auth *types.DockerAuthConfig var auth *types.DockerAuthConfig
configs := make(map[string]types.DockerAuthConfig) configs := make(map[string]types.DockerAuthConfig)
for _, h := range headers { for _, h := range headers {
param, err := base64.URLEncoding.DecodeString(h) param, err := base64.URLEncoding.DecodeString(h)
if err != nil { if err != nil {
return nil, "", errors.Wrapf(err, "failed to decode %q", XRegistryConfigHeader) return nil, nil, errors.Wrapf(err, "failed to decode %q", XRegistryConfigHeader)
} }
ac := make(map[string]dockerAPITypes.AuthConfig) ac := make(map[string]dockerAPITypes.AuthConfig)
err = json.Unmarshal(param, &ac) err = json.Unmarshal(param, &ac)
if err != nil { if err != nil {
return nil, "", errors.Wrapf(err, "failed to unmarshal %q", XRegistryConfigHeader) return nil, nil, errors.Wrapf(err, "failed to unmarshal %q", XRegistryConfigHeader)
} }
for k, v := range ac { for k, v := range ac {
@ -108,31 +119,28 @@ func getConfigCredentials(r *http.Request, headers []string) (*types.DockerAuthC
} }
} }
authfile, err := authConfigsToAuthFile(configs) return auth, configs, nil
return auth, authfile, err
} }
// getAuthCredentials extracts one or more DockerAuthConfigs from an XRegistryAuthHeader // getAuthCredentials extracts one or more DockerAuthConfigs from an XRegistryAuthHeader
// value. The header could specify a single-auth config in which case the // value. The header could specify a single-auth config in which case the
// first return value is set. In case of a multi-auth header, the contents are // first return value is set. In case of a multi-auth header, the contents are
// stored in a temporary auth file (2nd return value). Note that the auth file // returned in the second return value.
// should be removed after usage. func getAuthCredentials(headers []string) (*types.DockerAuthConfig, map[string]types.DockerAuthConfig, error) {
func getAuthCredentials(headers []string) (*types.DockerAuthConfig, string, error) {
authHeader := headers[0] authHeader := headers[0]
// First look for a multi-auth header (i.e., a map). // First look for a multi-auth header (i.e., a map).
authConfigs, err := parseMultiAuthHeader(authHeader) authConfigs, err := parseMultiAuthHeader(authHeader)
if err == nil { if err == nil {
authfile, err := authConfigsToAuthFile(authConfigs) return nil, authConfigs, nil
return nil, authfile, err
} }
// Fallback to looking for a single-auth header (i.e., one config). // Fallback to looking for a single-auth header (i.e., one config).
authConfig, err := parseSingleAuthHeader(authHeader) authConfig, err := parseSingleAuthHeader(authHeader)
if err != nil { if err != nil {
return nil, "", err return nil, nil, err
} }
return &authConfig, "", nil return &authConfig, nil, nil
} }
// Header builds the requested Authentication Header // Header builds the requested Authentication Header