func (s *credentialsSuite) TestFinalizeCredentialFilePath(c *gc.C) { dir := c.MkDir() filename := filepath.Join(dir, "filename") err := ioutil.WriteFile(filename, []byte{}, 0600) c.Assert(err, jc.ErrorIsNil) cred := cloud.NewCredential( cloud.JSONFileAuthType, map[string]string{ "file": filename, }, ) schema := cloud.CredentialSchema{{ "file", cloud.CredentialAttr{FilePath: true}, }} readFile := func(path string) ([]byte, error) { c.Assert(path, gc.Equals, filename) return []byte("file-contents"), nil } newCred, err := cloud.FinalizeCredential(cred, map[cloud.AuthType]cloud.CredentialSchema{ cloud.JSONFileAuthType: schema, }, readFile) c.Assert(err, jc.ErrorIsNil) c.Assert(newCred.Attributes(), jc.DeepEquals, map[string]string{ "file": "file-contents", }) }
func (s *credentialsSuite) TestFinalizeCredentialMandatoryFieldFromFile(c *gc.C) { cred := cloud.NewCredential( cloud.UserPassAuthType, map[string]string{ "key-file": "path", }, ) schema := cloud.CredentialSchema{{ "key", cloud.CredentialAttr{ Description: "key credential", Optional: false, FileAttr: "key-file", }, }} readFile := func(s string) ([]byte, error) { c.Assert(s, gc.Equals, "path") return []byte("file-value"), nil } newCred, err := cloud.FinalizeCredential(cred, map[cloud.AuthType]cloud.CredentialSchema{ cloud.UserPassAuthType: schema, }, readFile) c.Assert(err, jc.ErrorIsNil) c.Assert(newCred.Attributes(), jc.DeepEquals, map[string]string{ "key": "file-value", }) }
func (s *credentialsSuite) TestFinalizeCredentialNotSupported(c *gc.C) { cred := cloud.NewCredential( cloud.OAuth2AuthType, map[string]string{}, ) _, err := cloud.FinalizeCredential( cred, map[cloud.AuthType]cloud.CredentialSchema{}, readFileNotSupported, ) c.Assert(err, jc.Satisfies, errors.IsNotSupported) c.Assert(err, gc.ErrorMatches, `auth-type "oauth2" not supported`) }
func (s *credentialsSuite) TestFinalizeCredentialRelativeFilePath(c *gc.C) { cred := cloud.NewCredential( cloud.JSONFileAuthType, map[string]string{ "file": "file", }, ) schema := cloud.CredentialSchema{{ "file", cloud.CredentialAttr{FilePath: true}, }} _, err := cloud.FinalizeCredential(cred, map[cloud.AuthType]cloud.CredentialSchema{ cloud.JSONFileAuthType: schema, }, nil) c.Assert(err, gc.ErrorMatches, "file path must be an absolute path: file") }
func (s *credentialsSuite) TestFinalizeCredentialInvalidFilePath(c *gc.C) { cred := cloud.NewCredential( cloud.JSONFileAuthType, map[string]string{ "file": filepath.Join(c.MkDir(), "somefile"), }, ) schema := cloud.CredentialSchema{{ "file", cloud.CredentialAttr{FilePath: true}, }} _, err := cloud.FinalizeCredential(cred, map[cloud.AuthType]cloud.CredentialSchema{ cloud.JSONFileAuthType: schema, }, nil) c.Assert(err, gc.ErrorMatches, "invalid file path: .*") }
func (s *credentialsSuite) TestFinalizeCredentialInvalid(c *gc.C) { cred := cloud.NewCredential( cloud.UserPassAuthType, map[string]string{}, ) schema := cloud.CredentialSchema{{ "key", cloud.CredentialAttr{ Description: "key credential", Hidden: true, }, }} _, err := cloud.FinalizeCredential(cred, map[cloud.AuthType]cloud.CredentialSchema{ cloud.UserPassAuthType: schema, }, readFileNotSupported) c.Assert(err, gc.ErrorMatches, "key: expected string, got nothing") }
func (s *credentialsSuite) TestFinalizeCredentialMandatoryFieldMissing(c *gc.C) { cred := cloud.NewCredential( cloud.UserPassAuthType, map[string]string{ "password": "******", "domain": "domain", }, ) schema := cloud.CredentialSchema{ {"username", cloud.CredentialAttr{Optional: false}}, {"password", cloud.CredentialAttr{Hidden: true}}, {"domain", cloud.CredentialAttr{}}, } _, err := cloud.FinalizeCredential(cred, map[cloud.AuthType]cloud.CredentialSchema{ cloud.UserPassAuthType: schema, }, nil) c.Assert(err, gc.ErrorMatches, "username: expected string, got nothing") }
func (s *credentialsSuite) TestFinalizeCredentialFileAttrNeither(c *gc.C) { cred := cloud.NewCredential( cloud.UserPassAuthType, map[string]string{}, ) schema := cloud.CredentialSchema{{ "key", cloud.CredentialAttr{ Description: "key credential", Hidden: true, FileAttr: "key-file", }, }} _, err := cloud.FinalizeCredential(cred, map[cloud.AuthType]cloud.CredentialSchema{ cloud.UserPassAuthType: schema, }, readFileNotSupported) c.Assert(err, gc.ErrorMatches, `either "key" or "key-file" must be specified`) }
func (s *credentialsSuite) TestFinalizeCredentialInvalidChoice(c *gc.C) { cred := cloud.NewCredential( cloud.UserPassAuthType, map[string]string{ "username": "******", "password": "******", "algorithm": "foo", }, ) schema := cloud.CredentialSchema{ {"username", cloud.CredentialAttr{Optional: false}}, {"password", cloud.CredentialAttr{Hidden: true}}, {"algorithm", cloud.CredentialAttr{Options: []interface{}{"bar", "foobar"}}}, } _, err := cloud.FinalizeCredential(cred, map[cloud.AuthType]cloud.CredentialSchema{ cloud.UserPassAuthType: schema, }, nil) c.Assert(err, gc.ErrorMatches, regexp.QuoteMeta(`algorithm: expected one of [bar foobar], got "foo"`)) }
func (s *credentialsSuite) TestFinalizeCredential(c *gc.C) { cred := cloud.NewCredential( cloud.UserPassAuthType, map[string]string{ "key": "value", }, ) schema := cloud.CredentialSchema{{ "key", cloud.CredentialAttr{ Description: "key credential", Hidden: true, }, }} _, err := cloud.FinalizeCredential(cred, map[cloud.AuthType]cloud.CredentialSchema{ cloud.UserPassAuthType: schema, }, readFileNotSupported) c.Assert(err, jc.ErrorIsNil) }
func (s *credentialsSuite) TestFinalizeCredentialExtraField(c *gc.C) { cred := cloud.NewCredential( cloud.UserPassAuthType, map[string]string{ "username": "******", "password": "******", "domain": "domain", "access-key": "access-key", }, ) schema := cloud.CredentialSchema{ {"username", cloud.CredentialAttr{Optional: false}}, {"password", cloud.CredentialAttr{Hidden: true}}, {"domain", cloud.CredentialAttr{}}, } _, err := cloud.FinalizeCredential(cred, map[cloud.AuthType]cloud.CredentialSchema{ cloud.UserPassAuthType: schema, }, nil) c.Assert(err, gc.ErrorMatches, regexp.QuoteMeta(`unknown key "access-key" (value "access-key")`)) }
// GetCredentials returns a curated set of credential values for a given cloud. // The credential key values are read from the credentials store and the provider // finalises the values to resolve things like json files. // If region is not specified, the default credential region is used. func GetCredentials( store jujuclient.CredentialGetter, region, credentialName, cloudName, cloudType string, ) (_ *cloud.Credential, chosenCredentialName, regionName string, _ error) { credential, credentialName, defaultRegion, err := credentialByName( store, cloudName, credentialName, ) if err != nil { return nil, "", "", errors.Trace(err) } regionName = region if regionName == "" { regionName = defaultRegion } readFile := func(f string) ([]byte, error) { f, err := utils.NormalizePath(f) if err != nil { return nil, errors.Trace(err) } return ioutil.ReadFile(f) } // Finalize credential against schemas supported by the provider. provider, err := environs.Provider(cloudType) if err != nil { return nil, "", "", errors.Trace(err) } credential, err = cloud.FinalizeCredential( *credential, provider.CredentialSchemas(), readFile, ) if err != nil { return nil, "", "", errors.Annotatef( err, "validating %q credential for cloud %q", credentialName, cloudName, ) } return credential, credentialName, regionName, nil }
func (s *credentialsSuite) TestFinalizeCredentialFileAttrBoth(c *gc.C) { cred := cloud.NewCredential( cloud.UserPassAuthType, map[string]string{ "key": "value", "key-file": "path", }, ) schema := cloud.CredentialSchema{{ "key", cloud.CredentialAttr{ Description: "key credential", Hidden: true, FileAttr: "key-file", }, }} _, err := cloud.FinalizeCredential(cred, map[cloud.AuthType]cloud.CredentialSchema{ cloud.UserPassAuthType: schema, }, readFileNotSupported) c.Assert(err, gc.ErrorMatches, `specifying both "key" and "key-file" not valid`) }
func (s *credentialsSuite) TestFinalizeCredentialFileEmpty(c *gc.C) { cred := cloud.NewCredential( cloud.UserPassAuthType, map[string]string{ "key-file": "path", }, ) schema := cloud.CredentialSchema{{ "key", cloud.CredentialAttr{ Description: "key credential", Hidden: true, FileAttr: "key-file", }, }} readFile := func(string) ([]byte, error) { return nil, nil } _, err := cloud.FinalizeCredential(cred, map[cloud.AuthType]cloud.CredentialSchema{ cloud.UserPassAuthType: schema, }, readFile) c.Assert(err, gc.ErrorMatches, `empty file for "key" not valid`) }
// GetCredentials returns a curated set of credential values for a given cloud. // The credential key values are read from the credentials store and the provider // finalises the values to resolve things like json files. // If region is not specified, the default credential region is used. func GetCredentials( ctx *cmd.Context, store jujuclient.CredentialGetter, args GetCredentialsParams, ) (_ *cloud.Credential, chosenCredentialName, regionName string, _ error) { credential, credentialName, defaultRegion, err := credentialByName( store, args.CloudName, args.CredentialName, ) if err != nil { return nil, "", "", errors.Trace(err) } regionName = args.CloudRegion if regionName == "" { regionName = defaultRegion if regionName == "" && len(args.Cloud.Regions) > 0 { // No region was specified, use the first region // in the list. regionName = args.Cloud.Regions[0].Name } } cloudEndpoint := args.Cloud.Endpoint cloudIdentityEndpoint := args.Cloud.IdentityEndpoint if regionName != "" { region, err := cloud.RegionByName(args.Cloud.Regions, regionName) if err != nil { return nil, "", "", errors.Trace(err) } cloudEndpoint = region.Endpoint cloudIdentityEndpoint = region.IdentityEndpoint } readFile := func(f string) ([]byte, error) { f, err := utils.NormalizePath(f) if err != nil { return nil, errors.Trace(err) } return ioutil.ReadFile(f) } // Finalize credential against schemas supported by the provider. provider, err := environs.Provider(args.Cloud.Type) if err != nil { return nil, "", "", errors.Trace(err) } credential, err = cloud.FinalizeCredential( *credential, provider.CredentialSchemas(), readFile, ) if err != nil { return nil, "", "", errors.Annotatef( err, "finalizing %q credential for cloud %q", credentialName, args.CloudName, ) } credential, err = provider.FinalizeCredential( ctx, environs.FinalizeCredentialParams{ Credential: *credential, CloudEndpoint: cloudEndpoint, CloudIdentityEndpoint: cloudIdentityEndpoint, }, ) if err != nil { return nil, "", "", errors.Annotatef( err, "finalizing %q credential for cloud %q", credentialName, args.CloudName, ) } return credential, credentialName, regionName, nil }