...

Source file src/github.com/docker/docker-credential-helpers/wincred/wincred.go

Documentation: github.com/docker/docker-credential-helpers/wincred

     1  //go:build windows
     2  
     3  package wincred
     4  
     5  import (
     6  	"bytes"
     7  	"net/url"
     8  	"strings"
     9  
    10  	winc "github.com/danieljoos/wincred"
    11  	"github.com/docker/docker-credential-helpers/credentials"
    12  	"github.com/docker/docker-credential-helpers/registryurl"
    13  )
    14  
    15  // Wincred handles secrets using the Windows credential service.
    16  type Wincred struct{}
    17  
    18  // Add adds new credentials to the windows credentials manager.
    19  func (h Wincred) Add(creds *credentials.Credentials) error {
    20  	credsLabels := []byte(credentials.CredsLabel)
    21  	g := winc.NewGenericCredential(creds.ServerURL)
    22  	g.UserName = creds.Username
    23  	g.CredentialBlob = []byte(creds.Secret)
    24  	g.Persist = winc.PersistLocalMachine
    25  	g.Attributes = []winc.CredentialAttribute{{Keyword: "label", Value: credsLabels}}
    26  
    27  	return g.Write()
    28  }
    29  
    30  // Delete removes credentials from the windows credentials manager.
    31  func (h Wincred) Delete(serverURL string) error {
    32  	g, err := winc.GetGenericCredential(serverURL)
    33  	if g == nil {
    34  		return nil
    35  	}
    36  	if err != nil {
    37  		return err
    38  	}
    39  	return g.Delete()
    40  }
    41  
    42  // Get retrieves credentials from the windows credentials manager.
    43  func (h Wincred) Get(serverURL string) (string, string, error) {
    44  	target, err := getTarget(serverURL)
    45  	if err != nil {
    46  		return "", "", err
    47  	} else if target == "" {
    48  		return "", "", credentials.NewErrCredentialsNotFound()
    49  	}
    50  
    51  	g, _ := winc.GetGenericCredential(target)
    52  	if g == nil {
    53  		return "", "", credentials.NewErrCredentialsNotFound()
    54  	}
    55  
    56  	for _, attr := range g.Attributes {
    57  		if strings.Compare(attr.Keyword, "label") == 0 &&
    58  			bytes.Compare(attr.Value, []byte(credentials.CredsLabel)) == 0 {
    59  
    60  			return g.UserName, string(g.CredentialBlob), nil
    61  		}
    62  	}
    63  	return "", "", credentials.NewErrCredentialsNotFound()
    64  }
    65  
    66  func getTarget(serverURL string) (string, error) {
    67  	s, err := registryurl.Parse(serverURL)
    68  	if err != nil {
    69  		return serverURL, nil
    70  	}
    71  
    72  	creds, err := winc.List()
    73  	if err != nil {
    74  		return "", err
    75  	}
    76  
    77  	var targets []string
    78  	for i := range creds {
    79  		attrs := creds[i].Attributes
    80  		for _, attr := range attrs {
    81  			if attr.Keyword == "label" && bytes.Equal(attr.Value, []byte(credentials.CredsLabel)) {
    82  				targets = append(targets, creds[i].TargetName)
    83  			}
    84  		}
    85  	}
    86  
    87  	if target, found := findMatch(s, targets, exactMatch); found {
    88  		return target, nil
    89  	}
    90  
    91  	if target, found := findMatch(s, targets, approximateMatch); found {
    92  		return target, nil
    93  	}
    94  
    95  	return "", nil
    96  }
    97  
    98  func findMatch(serverUrl *url.URL, targets []string, matches func(url.URL, url.URL) bool) (string, bool) {
    99  	for _, target := range targets {
   100  		tURL, err := registryurl.Parse(target)
   101  		if err != nil {
   102  			continue
   103  		}
   104  		if matches(*serverUrl, *tURL) {
   105  			return target, true
   106  		}
   107  	}
   108  	return "", false
   109  }
   110  
   111  func exactMatch(serverURL, target url.URL) bool {
   112  	return serverURL.String() == target.String()
   113  }
   114  
   115  func approximateMatch(serverURL, target url.URL) bool {
   116  	// if scheme is missing assume it is the same as target
   117  	if serverURL.Scheme == "" {
   118  		serverURL.Scheme = target.Scheme
   119  	}
   120  	// if port is missing assume it is the same as target
   121  	if serverURL.Port() == "" && target.Port() != "" {
   122  		serverURL.Host = serverURL.Host + ":" + target.Port()
   123  	}
   124  	// if path is missing assume it is the same as target
   125  	if serverURL.Path == "" {
   126  		serverURL.Path = target.Path
   127  	}
   128  	return serverURL.String() == target.String()
   129  }
   130  
   131  // List returns the stored URLs and corresponding usernames for a given credentials label.
   132  func (h Wincred) List() (map[string]string, error) {
   133  	creds, err := winc.List()
   134  	if err != nil {
   135  		return nil, err
   136  	}
   137  
   138  	resp := make(map[string]string)
   139  	for i := range creds {
   140  		attrs := creds[i].Attributes
   141  		for _, attr := range attrs {
   142  			if strings.Compare(attr.Keyword, "label") == 0 &&
   143  				bytes.Compare(attr.Value, []byte(credentials.CredsLabel)) == 0 {
   144  
   145  				resp[creds[i].TargetName] = creds[i].UserName
   146  			}
   147  		}
   148  
   149  	}
   150  
   151  	return resp, nil
   152  }
   153  

View as plain text