Skip to content

Commit 1cf5af1

Browse files
loresusoalacuku
authored andcommitted
new: create a library to store and retrieve credentials on files.
Signed-off-by: Lorenzo Susini <[email protected]> Co-authored-by: Aldo Lacuku <[email protected]>
1 parent b22e244 commit 1cf5af1

File tree

1 file changed

+136
-0
lines changed

1 file changed

+136
-0
lines changed

pkg/oci/authn/credentialstore.go

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
// Copyright 2022 The ORAS Authors.
2+
// Copyright 2022 The Falco Authors
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
package authn
17+
18+
import (
19+
"context"
20+
"fmt"
21+
"os"
22+
"path/filepath"
23+
24+
"github.com/docker/cli/cli/config"
25+
"github.com/docker/cli/cli/config/configfile"
26+
"github.com/docker/cli/cli/config/credentials"
27+
"github.com/docker/cli/cli/config/types"
28+
logger "github.com/sirupsen/logrus"
29+
"oras.land/oras-go/v2/registry/remote/auth"
30+
)
31+
32+
// Store provides credential CRUD operations.
33+
type Store struct {
34+
configs []*configfile.ConfigFile
35+
}
36+
37+
// NewStore generates a store based on the passed in config file path.
38+
func NewStore(configPaths ...string) (*Store, error) {
39+
if len(configPaths) == 0 {
40+
// No config path passed, load default docker config file.
41+
cfg, err := config.Load(config.Dir())
42+
if err != nil {
43+
return nil, err
44+
}
45+
if !cfg.ContainsAuth() {
46+
cfg.CredentialsStore = credentials.DetectDefaultStore(cfg.CredentialsStore)
47+
}
48+
49+
return &Store{
50+
configs: []*configfile.ConfigFile{cfg},
51+
}, nil
52+
}
53+
54+
var configs []*configfile.ConfigFile
55+
for _, path := range configPaths {
56+
cfg, err := loadConfigFile(path)
57+
if err != nil {
58+
return nil, fmt.Errorf("%s: %w", path, err)
59+
}
60+
configs = append(configs, cfg)
61+
}
62+
63+
return &Store{
64+
configs: configs,
65+
}, nil
66+
}
67+
68+
// loadConfigFile reads the credential-related configurationfrom the given path.
69+
func loadConfigFile(path string) (*configfile.ConfigFile, error) {
70+
var cfg *configfile.ConfigFile
71+
if _, err := os.Stat(path); err != nil {
72+
if os.IsNotExist(err) {
73+
cfg = configfile.New(path)
74+
} else {
75+
return nil, err
76+
}
77+
} else {
78+
file, err := os.Open(filepath.Clean(path))
79+
if err != nil {
80+
return nil, err
81+
}
82+
defer func() {
83+
if err := file.Close(); err != nil {
84+
logger.Printf("Error closing file: %s\n", err)
85+
}
86+
}()
87+
cfg = configfile.New(path)
88+
if err := cfg.LoadFromReader(file); err != nil {
89+
return nil, err
90+
}
91+
}
92+
93+
if !cfg.ContainsAuth() {
94+
cfg.CredentialsStore = credentials.DetectDefaultStore(cfg.CredentialsStore)
95+
}
96+
return cfg, nil
97+
}
98+
99+
// Store stores a credential for a given registry.
100+
func (s *Store) Store(registry string, cred auth.Credential) error {
101+
authConf := types.AuthConfig{
102+
Username: cred.Username,
103+
Password: cred.Password,
104+
ServerAddress: registry,
105+
IdentityToken: cred.RefreshToken,
106+
RegistryToken: cred.AccessToken,
107+
}
108+
109+
return s.configs[0].GetCredentialsStore(registry).Store(authConf)
110+
}
111+
112+
// Erase erases a credential for a given registry.
113+
func (s *Store) Erase(registry string) error {
114+
return s.configs[0].GetCredentialsStore(registry).Erase(registry)
115+
}
116+
117+
// Credential iterates all the config files, returns the first non-empty
118+
// credential in a best-effort way.
119+
func (s *Store) Credential(ctx context.Context, registry string) (auth.Credential, error) {
120+
for _, c := range s.configs {
121+
authConf, err := c.GetCredentialsStore(registry).Get(registry)
122+
if err != nil {
123+
return auth.EmptyCredential, err
124+
}
125+
cred := auth.Credential{
126+
Username: authConf.Username,
127+
Password: authConf.Password,
128+
AccessToken: authConf.RegistryToken,
129+
RefreshToken: authConf.IdentityToken,
130+
}
131+
if cred != auth.EmptyCredential {
132+
return cred, nil
133+
}
134+
}
135+
return auth.EmptyCredential, nil
136+
}

0 commit comments

Comments
 (0)