forked from toolshed/abra
chore: vendor
This commit is contained in:
344
vendor/github.com/containers/image/pkg/docker/config/config.go
generated
vendored
Normal file
344
vendor/github.com/containers/image/pkg/docker/config/config.go
generated
vendored
Normal file
@ -0,0 +1,344 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/image/types"
|
||||
helperclient "github.com/docker/docker-credential-helpers/client"
|
||||
"github.com/docker/docker-credential-helpers/credentials"
|
||||
"github.com/docker/docker/pkg/homedir"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type dockerAuthConfig struct {
|
||||
Auth string `json:"auth,omitempty"`
|
||||
}
|
||||
|
||||
type dockerConfigFile struct {
|
||||
AuthConfigs map[string]dockerAuthConfig `json:"auths"`
|
||||
CredHelpers map[string]string `json:"credHelpers,omitempty"`
|
||||
}
|
||||
|
||||
var (
|
||||
defaultPerUIDPathFormat = filepath.FromSlash("/run/containers/%d/auth.json")
|
||||
xdgRuntimeDirPath = filepath.FromSlash("containers/auth.json")
|
||||
dockerHomePath = filepath.FromSlash(".docker/config.json")
|
||||
dockerLegacyHomePath = ".dockercfg"
|
||||
|
||||
enableKeyring = false
|
||||
|
||||
// ErrNotLoggedIn is returned for users not logged into a registry
|
||||
// that they are trying to logout of
|
||||
ErrNotLoggedIn = errors.New("not logged in")
|
||||
// ErrNotSupported is returned for unsupported methods
|
||||
ErrNotSupported = errors.New("not supported")
|
||||
)
|
||||
|
||||
// SetAuthentication stores the username and password in the auth.json file
|
||||
func SetAuthentication(sys *types.SystemContext, registry, username, password string) error {
|
||||
return modifyJSON(sys, func(auths *dockerConfigFile) (bool, error) {
|
||||
if ch, exists := auths.CredHelpers[registry]; exists {
|
||||
return false, setAuthToCredHelper(ch, registry, username, password)
|
||||
}
|
||||
|
||||
// Set the credentials to kernel keyring if enableKeyring is true.
|
||||
// The keyring might not work in all environments (e.g., missing capability) and isn't supported on all platforms.
|
||||
// Hence, we want to fall-back to using the authfile in case the keyring failed.
|
||||
// However, if the enableKeyring is false, we want adhere to the user specification and not use the keyring.
|
||||
if enableKeyring {
|
||||
err := setAuthToKernelKeyring(registry, username, password)
|
||||
if err == nil {
|
||||
logrus.Debugf("credentials for (%s, %s) were stored in the kernel keyring\n", registry, username)
|
||||
return false, nil
|
||||
}
|
||||
logrus.Debugf("failed to authenticate with the kernel keyring, falling back to authfiles. %v", err)
|
||||
}
|
||||
creds := base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
|
||||
newCreds := dockerAuthConfig{Auth: creds}
|
||||
auths.AuthConfigs[registry] = newCreds
|
||||
return true, nil
|
||||
})
|
||||
}
|
||||
|
||||
// GetAuthentication returns the registry credentials stored in
|
||||
// either auth.json file or .docker/config.json
|
||||
// If an entry is not found empty strings are returned for the username and password
|
||||
func GetAuthentication(sys *types.SystemContext, registry string) (string, string, error) {
|
||||
if sys != nil && sys.DockerAuthConfig != nil {
|
||||
logrus.Debug("Returning credentials from DockerAuthConfig")
|
||||
return sys.DockerAuthConfig.Username, sys.DockerAuthConfig.Password, nil
|
||||
}
|
||||
|
||||
if enableKeyring {
|
||||
username, password, err := getAuthFromKernelKeyring(registry)
|
||||
if err == nil {
|
||||
logrus.Debug("returning credentials from kernel keyring")
|
||||
return username, password, nil
|
||||
}
|
||||
}
|
||||
|
||||
dockerLegacyPath := filepath.Join(homedir.Get(), dockerLegacyHomePath)
|
||||
var paths []string
|
||||
pathToAuth, err := getPathToAuth(sys)
|
||||
if err == nil {
|
||||
paths = append(paths, pathToAuth)
|
||||
} else {
|
||||
// Error means that the path set for XDG_RUNTIME_DIR does not exist
|
||||
// but we don't want to completely fail in the case that the user is pulling a public image
|
||||
// Logging the error as a warning instead and moving on to pulling the image
|
||||
logrus.Warnf("%v: Trying to pull image in the event that it is a public image.", err)
|
||||
}
|
||||
paths = append(paths, filepath.Join(homedir.Get(), dockerHomePath), dockerLegacyPath)
|
||||
|
||||
for _, path := range paths {
|
||||
legacyFormat := path == dockerLegacyPath
|
||||
username, password, err := findAuthentication(registry, path, legacyFormat)
|
||||
if err != nil {
|
||||
logrus.Debugf("Credentials not found")
|
||||
return "", "", err
|
||||
}
|
||||
if username != "" && password != "" {
|
||||
logrus.Debugf("Returning credentials from %s", path)
|
||||
return username, password, nil
|
||||
}
|
||||
}
|
||||
logrus.Debugf("Credentials not found")
|
||||
return "", "", nil
|
||||
}
|
||||
|
||||
// RemoveAuthentication deletes the credentials stored in auth.json
|
||||
func RemoveAuthentication(sys *types.SystemContext, registry string) error {
|
||||
return modifyJSON(sys, func(auths *dockerConfigFile) (bool, error) {
|
||||
// First try cred helpers.
|
||||
if ch, exists := auths.CredHelpers[registry]; exists {
|
||||
return false, deleteAuthFromCredHelper(ch, registry)
|
||||
}
|
||||
|
||||
// Next if keyring is enabled try kernel keyring
|
||||
if enableKeyring {
|
||||
err := deleteAuthFromKernelKeyring(registry)
|
||||
if err == nil {
|
||||
logrus.Debugf("credentials for %s were deleted from the kernel keyring", registry)
|
||||
return false, nil
|
||||
}
|
||||
logrus.Debugf("failed to delete credentials from the kernel keyring, falling back to authfiles")
|
||||
}
|
||||
|
||||
if _, ok := auths.AuthConfigs[registry]; ok {
|
||||
delete(auths.AuthConfigs, registry)
|
||||
} else if _, ok := auths.AuthConfigs[normalizeRegistry(registry)]; ok {
|
||||
delete(auths.AuthConfigs, normalizeRegistry(registry))
|
||||
} else {
|
||||
return false, ErrNotLoggedIn
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
}
|
||||
|
||||
// RemoveAllAuthentication deletes all the credentials stored in auth.json
|
||||
func RemoveAllAuthentication(sys *types.SystemContext) error {
|
||||
return modifyJSON(sys, func(auths *dockerConfigFile) (bool, error) {
|
||||
auths.CredHelpers = make(map[string]string)
|
||||
auths.AuthConfigs = make(map[string]dockerAuthConfig)
|
||||
return true, nil
|
||||
})
|
||||
}
|
||||
|
||||
// getPath gets the path of the auth.json file
|
||||
// The path can be overriden by the user if the overwrite-path flag is set
|
||||
// If the flag is not set and XDG_RUNTIME_DIR is set, the auth.json file is saved in XDG_RUNTIME_DIR/containers
|
||||
// Otherwise, the auth.json file is stored in /run/containers/UID
|
||||
func getPathToAuth(sys *types.SystemContext) (string, error) {
|
||||
if sys != nil {
|
||||
if sys.AuthFilePath != "" {
|
||||
return sys.AuthFilePath, nil
|
||||
}
|
||||
if sys.RootForImplicitAbsolutePaths != "" {
|
||||
return filepath.Join(sys.RootForImplicitAbsolutePaths, fmt.Sprintf(defaultPerUIDPathFormat, os.Getuid())), nil
|
||||
}
|
||||
}
|
||||
|
||||
runtimeDir := os.Getenv("XDG_RUNTIME_DIR")
|
||||
if runtimeDir != "" {
|
||||
// This function does not in general need to separately check that the returned path exists; that’s racy, and callers will fail accessing the file anyway.
|
||||
// We are checking for os.IsNotExist here only to give the user better guidance what to do in this special case.
|
||||
_, err := os.Stat(runtimeDir)
|
||||
if os.IsNotExist(err) {
|
||||
// This means the user set the XDG_RUNTIME_DIR variable and either forgot to create the directory
|
||||
// or made a typo while setting the environment variable,
|
||||
// so return an error referring to $XDG_RUNTIME_DIR instead of xdgRuntimeDirPath inside.
|
||||
return "", errors.Wrapf(err, "%q directory set by $XDG_RUNTIME_DIR does not exist. Either create the directory or unset $XDG_RUNTIME_DIR.", runtimeDir)
|
||||
} // else ignore err and let the caller fail accessing xdgRuntimeDirPath.
|
||||
return filepath.Join(runtimeDir, xdgRuntimeDirPath), nil
|
||||
}
|
||||
return fmt.Sprintf(defaultPerUIDPathFormat, os.Getuid()), nil
|
||||
}
|
||||
|
||||
// readJSONFile unmarshals the authentications stored in the auth.json file and returns it
|
||||
// or returns an empty dockerConfigFile data structure if auth.json does not exist
|
||||
// if the file exists and is empty, readJSONFile returns an error
|
||||
func readJSONFile(path string, legacyFormat bool) (dockerConfigFile, error) {
|
||||
var auths dockerConfigFile
|
||||
|
||||
raw, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
auths.AuthConfigs = map[string]dockerAuthConfig{}
|
||||
return auths, nil
|
||||
}
|
||||
return dockerConfigFile{}, err
|
||||
}
|
||||
|
||||
if legacyFormat {
|
||||
if err = json.Unmarshal(raw, &auths.AuthConfigs); err != nil {
|
||||
return dockerConfigFile{}, errors.Wrapf(err, "error unmarshaling JSON at %q", path)
|
||||
}
|
||||
return auths, nil
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(raw, &auths); err != nil {
|
||||
return dockerConfigFile{}, errors.Wrapf(err, "error unmarshaling JSON at %q", path)
|
||||
}
|
||||
|
||||
return auths, nil
|
||||
}
|
||||
|
||||
// modifyJSON writes to auth.json if the dockerConfigFile has been updated
|
||||
func modifyJSON(sys *types.SystemContext, editor func(auths *dockerConfigFile) (bool, error)) error {
|
||||
path, err := getPathToAuth(sys)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dir := filepath.Dir(path)
|
||||
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(dir, 0700); err != nil {
|
||||
return errors.Wrapf(err, "error creating directory %q", dir)
|
||||
}
|
||||
}
|
||||
|
||||
auths, err := readJSONFile(path, false)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error reading JSON file %q", path)
|
||||
}
|
||||
|
||||
updated, err := editor(&auths)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error updating %q", path)
|
||||
}
|
||||
if updated {
|
||||
newData, err := json.MarshalIndent(auths, "", "\t")
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error marshaling JSON %q", path)
|
||||
}
|
||||
|
||||
if err = ioutil.WriteFile(path, newData, 0755); err != nil {
|
||||
return errors.Wrapf(err, "error writing to file %q", path)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getAuthFromCredHelper(credHelper, registry string) (string, string, error) {
|
||||
helperName := fmt.Sprintf("docker-credential-%s", credHelper)
|
||||
p := helperclient.NewShellProgramFunc(helperName)
|
||||
creds, err := helperclient.Get(p, registry)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
return creds.Username, creds.Secret, nil
|
||||
}
|
||||
|
||||
func setAuthToCredHelper(credHelper, registry, username, password string) error {
|
||||
helperName := fmt.Sprintf("docker-credential-%s", credHelper)
|
||||
p := helperclient.NewShellProgramFunc(helperName)
|
||||
creds := &credentials.Credentials{
|
||||
ServerURL: registry,
|
||||
Username: username,
|
||||
Secret: password,
|
||||
}
|
||||
return helperclient.Store(p, creds)
|
||||
}
|
||||
|
||||
func deleteAuthFromCredHelper(credHelper, registry string) error {
|
||||
helperName := fmt.Sprintf("docker-credential-%s", credHelper)
|
||||
p := helperclient.NewShellProgramFunc(helperName)
|
||||
return helperclient.Erase(p, registry)
|
||||
}
|
||||
|
||||
// findAuthentication looks for auth of registry in path
|
||||
func findAuthentication(registry, path string, legacyFormat bool) (string, string, error) {
|
||||
auths, err := readJSONFile(path, legacyFormat)
|
||||
if err != nil {
|
||||
return "", "", errors.Wrapf(err, "error reading JSON file %q", path)
|
||||
}
|
||||
|
||||
// First try cred helpers. They should always be normalized.
|
||||
if ch, exists := auths.CredHelpers[registry]; exists {
|
||||
return getAuthFromCredHelper(ch, registry)
|
||||
}
|
||||
|
||||
// I'm feeling lucky
|
||||
if val, exists := auths.AuthConfigs[registry]; exists {
|
||||
return decodeDockerAuth(val.Auth)
|
||||
}
|
||||
|
||||
// bad luck; let's normalize the entries first
|
||||
registry = normalizeRegistry(registry)
|
||||
normalizedAuths := map[string]dockerAuthConfig{}
|
||||
for k, v := range auths.AuthConfigs {
|
||||
normalizedAuths[normalizeRegistry(k)] = v
|
||||
}
|
||||
if val, exists := normalizedAuths[registry]; exists {
|
||||
return decodeDockerAuth(val.Auth)
|
||||
}
|
||||
return "", "", nil
|
||||
}
|
||||
|
||||
func decodeDockerAuth(s string) (string, string, error) {
|
||||
decoded, err := base64.StdEncoding.DecodeString(s)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
parts := strings.SplitN(string(decoded), ":", 2)
|
||||
if len(parts) != 2 {
|
||||
// if it's invalid just skip, as docker does
|
||||
return "", "", nil
|
||||
}
|
||||
user := parts[0]
|
||||
password := strings.Trim(parts[1], "\x00")
|
||||
return user, password, nil
|
||||
}
|
||||
|
||||
// convertToHostname converts a registry url which has http|https prepended
|
||||
// to just an hostname.
|
||||
// Copied from github.com/docker/docker/registry/auth.go
|
||||
func convertToHostname(url string) string {
|
||||
stripped := url
|
||||
if strings.HasPrefix(url, "http://") {
|
||||
stripped = strings.TrimPrefix(url, "http://")
|
||||
} else if strings.HasPrefix(url, "https://") {
|
||||
stripped = strings.TrimPrefix(url, "https://")
|
||||
}
|
||||
|
||||
nameParts := strings.SplitN(stripped, "/", 2)
|
||||
|
||||
return nameParts[0]
|
||||
}
|
||||
|
||||
func normalizeRegistry(registry string) string {
|
||||
normalized := convertToHostname(registry)
|
||||
switch normalized {
|
||||
case "registry-1.docker.io", "docker.io":
|
||||
return "index.docker.io"
|
||||
}
|
||||
return normalized
|
||||
}
|
79
vendor/github.com/containers/image/pkg/docker/config/config_linux.go
generated
vendored
Normal file
79
vendor/github.com/containers/image/pkg/docker/config/config_linux.go
generated
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/image/pkg/keyctl"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func getAuthFromKernelKeyring(registry string) (string, string, error) {
|
||||
userkeyring, err := keyctl.UserKeyring()
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
key, err := userkeyring.Search(genDescription(registry))
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
authData, err := key.Get()
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
parts := strings.SplitN(string(authData), "\x00", 2)
|
||||
if len(parts) != 2 {
|
||||
return "", "", nil
|
||||
}
|
||||
return parts[0], parts[1], nil
|
||||
}
|
||||
|
||||
func deleteAuthFromKernelKeyring(registry string) error {
|
||||
userkeyring, err := keyctl.UserKeyring()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
key, err := userkeyring.Search(genDescription(registry))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return key.Unlink()
|
||||
}
|
||||
|
||||
func setAuthToKernelKeyring(registry, username, password string) error {
|
||||
keyring, err := keyctl.SessionKeyring()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
id, err := keyring.Add(genDescription(registry), []byte(fmt.Sprintf("%s\x00%s", username, password)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// sets all permission(view,read,write,search,link,set attribute) for current user
|
||||
// it enables the user to search the key after it linked to user keyring and unlinked from session keyring
|
||||
err = keyctl.SetPerm(id, keyctl.PermUserAll)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// link the key to userKeyring
|
||||
userKeyring, err := keyctl.UserKeyring()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error getting user keyring")
|
||||
}
|
||||
err = keyctl.Link(userKeyring, id)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error linking the key to user keyring")
|
||||
}
|
||||
// unlink the key from session keyring
|
||||
err = keyctl.Unlink(keyring, id)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error unlinking the key from session keyring")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func genDescription(registry string) string {
|
||||
return fmt.Sprintf("container-registry-login:%s", registry)
|
||||
}
|
17
vendor/github.com/containers/image/pkg/docker/config/config_unsupported.go
generated
vendored
Normal file
17
vendor/github.com/containers/image/pkg/docker/config/config_unsupported.go
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
//go:build !linux && (!386 || !amd64)
|
||||
// +build !linux
|
||||
// +build !386 !amd64
|
||||
|
||||
package config
|
||||
|
||||
func getAuthFromKernelKeyring(registry string) (string, string, error) {
|
||||
return "", "", ErrNotSupported
|
||||
}
|
||||
|
||||
func deleteAuthFromKernelKeyring(registry string) error {
|
||||
return ErrNotSupported
|
||||
}
|
||||
|
||||
func setAuthToKernelKeyring(registry, username, password string) error {
|
||||
return ErrNotSupported
|
||||
}
|
Reference in New Issue
Block a user