|
Packit |
63bb0d |
package gophercloud
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
/*
|
|
Packit |
63bb0d |
AuthOptions stores information needed to authenticate to an OpenStack Cloud.
|
|
Packit |
63bb0d |
You can populate one manually, or use a provider's AuthOptionsFromEnv() function
|
|
Packit |
63bb0d |
to read relevant information from the standard environment variables. Pass one
|
|
Packit |
63bb0d |
to a provider's AuthenticatedClient function to authenticate and obtain a
|
|
Packit |
63bb0d |
ProviderClient representing an active session on that provider.
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
Its fields are the union of those recognized by each identity implementation and
|
|
Packit |
63bb0d |
provider.
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
An example of manually providing authentication information:
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
opts := gophercloud.AuthOptions{
|
|
Packit |
63bb0d |
IdentityEndpoint: "https://openstack.example.com:5000/v2.0",
|
|
Packit |
63bb0d |
Username: "{username}",
|
|
Packit |
63bb0d |
Password: "{password}",
|
|
Packit |
63bb0d |
TenantID: "{tenant_id}",
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
provider, err := openstack.AuthenticatedClient(opts)
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
An example of using AuthOptionsFromEnv(), where the environment variables can
|
|
Packit |
63bb0d |
be read from a file, such as a standard openrc file:
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
opts, err := openstack.AuthOptionsFromEnv()
|
|
Packit |
63bb0d |
provider, err := openstack.AuthenticatedClient(opts)
|
|
Packit |
63bb0d |
*/
|
|
Packit |
63bb0d |
type AuthOptions struct {
|
|
Packit |
63bb0d |
// IdentityEndpoint specifies the HTTP endpoint that is required to work with
|
|
Packit |
63bb0d |
// the Identity API of the appropriate version. While it's ultimately needed by
|
|
Packit |
63bb0d |
// all of the identity services, it will often be populated by a provider-level
|
|
Packit |
63bb0d |
// function.
|
|
Packit |
63bb0d |
//
|
|
Packit |
63bb0d |
// The IdentityEndpoint is typically referred to as the "auth_url" or
|
|
Packit |
63bb0d |
// "OS_AUTH_URL" in the information provided by the cloud operator.
|
|
Packit |
63bb0d |
IdentityEndpoint string `json:"-"`
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// Username is required if using Identity V2 API. Consult with your provider's
|
|
Packit |
63bb0d |
// control panel to discover your account's username. In Identity V3, either
|
|
Packit |
63bb0d |
// UserID or a combination of Username and DomainID or DomainName are needed.
|
|
Packit |
63bb0d |
Username string `json:"username,omitempty"`
|
|
Packit |
63bb0d |
UserID string `json:"-"`
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
Password string `json:"password,omitempty"`
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// Passcode is used in TOTP authentication method
|
|
Packit |
63bb0d |
Passcode string `json:"passcode,omitempty"`
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// At most one of DomainID and DomainName must be provided if using Username
|
|
Packit |
63bb0d |
// with Identity V3. Otherwise, either are optional.
|
|
Packit |
63bb0d |
DomainID string `json:"-"`
|
|
Packit |
63bb0d |
DomainName string `json:"name,omitempty"`
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// The TenantID and TenantName fields are optional for the Identity V2 API.
|
|
Packit |
63bb0d |
// The same fields are known as project_id and project_name in the Identity
|
|
Packit |
63bb0d |
// V3 API, but are collected as TenantID and TenantName here in both cases.
|
|
Packit |
63bb0d |
// Some providers allow you to specify a TenantName instead of the TenantId.
|
|
Packit |
63bb0d |
// Some require both. Your provider's authentication policies will determine
|
|
Packit |
63bb0d |
// how these fields influence authentication.
|
|
Packit |
63bb0d |
// If DomainID or DomainName are provided, they will also apply to TenantName.
|
|
Packit |
63bb0d |
// It is not currently possible to authenticate with Username and a Domain
|
|
Packit |
63bb0d |
// and scope to a Project in a different Domain by using TenantName. To
|
|
Packit |
63bb0d |
// accomplish that, the ProjectID will need to be provided as the TenantID
|
|
Packit |
63bb0d |
// option.
|
|
Packit |
63bb0d |
TenantID string `json:"tenantId,omitempty"`
|
|
Packit |
63bb0d |
TenantName string `json:"tenantName,omitempty"`
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// AllowReauth should be set to true if you grant permission for Gophercloud to
|
|
Packit |
63bb0d |
// cache your credentials in memory, and to allow Gophercloud to attempt to
|
|
Packit |
63bb0d |
// re-authenticate automatically if/when your token expires. If you set it to
|
|
Packit |
63bb0d |
// false, it will not cache these settings, but re-authentication will not be
|
|
Packit |
63bb0d |
// possible. This setting defaults to false.
|
|
Packit |
63bb0d |
//
|
|
Packit |
63bb0d |
// NOTE: The reauth function will try to re-authenticate endlessly if left
|
|
Packit |
63bb0d |
// unchecked. The way to limit the number of attempts is to provide a custom
|
|
Packit |
63bb0d |
// HTTP client to the provider client and provide a transport that implements
|
|
Packit |
63bb0d |
// the RoundTripper interface and stores the number of failed retries. For an
|
|
Packit |
63bb0d |
// example of this, see here:
|
|
Packit |
63bb0d |
// https://github.com/rackspace/rack/blob/1.0.0/auth/clients.go#L311
|
|
Packit |
63bb0d |
AllowReauth bool `json:"-"`
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// TokenID allows users to authenticate (possibly as another user) with an
|
|
Packit |
63bb0d |
// authentication token ID.
|
|
Packit |
63bb0d |
TokenID string `json:"-"`
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// Scope determines the scoping of the authentication request.
|
|
Packit |
63bb0d |
Scope *AuthScope `json:"-"`
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// Authentication through Application Credentials requires supplying name, project and secret
|
|
Packit |
63bb0d |
// For project we can use TenantID
|
|
Packit |
63bb0d |
ApplicationCredentialID string `json:"-"`
|
|
Packit |
63bb0d |
ApplicationCredentialName string `json:"-"`
|
|
Packit |
63bb0d |
ApplicationCredentialSecret string `json:"-"`
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// AuthScope allows a created token to be limited to a specific domain or project.
|
|
Packit |
63bb0d |
type AuthScope struct {
|
|
Packit |
63bb0d |
ProjectID string
|
|
Packit |
63bb0d |
ProjectName string
|
|
Packit |
63bb0d |
DomainID string
|
|
Packit |
63bb0d |
DomainName string
|
|
Packit |
63bb0d |
System bool
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// ToTokenV2CreateMap allows AuthOptions to satisfy the AuthOptionsBuilder
|
|
Packit |
63bb0d |
// interface in the v2 tokens package
|
|
Packit |
63bb0d |
func (opts AuthOptions) ToTokenV2CreateMap() (map[string]interface{}, error) {
|
|
Packit |
63bb0d |
// Populate the request map.
|
|
Packit |
63bb0d |
authMap := make(map[string]interface{})
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
if opts.Username != "" {
|
|
Packit |
63bb0d |
if opts.Password != "" {
|
|
Packit |
63bb0d |
authMap["passwordCredentials"] = map[string]interface{}{
|
|
Packit |
63bb0d |
"username": opts.Username,
|
|
Packit |
63bb0d |
"password": opts.Password,
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
} else {
|
|
Packit |
63bb0d |
return nil, ErrMissingInput{Argument: "Password"}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
} else if opts.TokenID != "" {
|
|
Packit |
63bb0d |
authMap["token"] = map[string]interface{}{
|
|
Packit |
63bb0d |
"id": opts.TokenID,
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
} else {
|
|
Packit |
63bb0d |
return nil, ErrMissingInput{Argument: "Username"}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
if opts.TenantID != "" {
|
|
Packit |
63bb0d |
authMap["tenantId"] = opts.TenantID
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
if opts.TenantName != "" {
|
|
Packit |
63bb0d |
authMap["tenantName"] = opts.TenantName
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
return map[string]interface{}{"auth": authMap}, nil
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// ToTokenV3CreateMap allows AuthOptions to satisfy the AuthOptionsBuilder
|
|
Packit |
63bb0d |
// interface in the v3 tokens package
|
|
Packit |
63bb0d |
func (opts *AuthOptions) ToTokenV3CreateMap(scope map[string]interface{}) (map[string]interface{}, error) {
|
|
Packit |
63bb0d |
type domainReq struct {
|
|
Packit |
63bb0d |
ID *string `json:"id,omitempty"`
|
|
Packit |
63bb0d |
Name *string `json:"name,omitempty"`
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
type projectReq struct {
|
|
Packit |
63bb0d |
Domain *domainReq `json:"domain,omitempty"`
|
|
Packit |
63bb0d |
Name *string `json:"name,omitempty"`
|
|
Packit |
63bb0d |
ID *string `json:"id,omitempty"`
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
type userReq struct {
|
|
Packit |
63bb0d |
ID *string `json:"id,omitempty"`
|
|
Packit |
63bb0d |
Name *string `json:"name,omitempty"`
|
|
Packit |
63bb0d |
Password *string `json:"password,omitempty"`
|
|
Packit |
63bb0d |
Passcode *string `json:"passcode,omitempty"`
|
|
Packit |
63bb0d |
Domain *domainReq `json:"domain,omitempty"`
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
type passwordReq struct {
|
|
Packit |
63bb0d |
User userReq `json:"user"`
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
type tokenReq struct {
|
|
Packit |
63bb0d |
ID string `json:"id"`
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
type applicationCredentialReq struct {
|
|
Packit |
63bb0d |
ID *string `json:"id,omitempty"`
|
|
Packit |
63bb0d |
Name *string `json:"name,omitempty"`
|
|
Packit |
63bb0d |
User *userReq `json:"user,omitempty"`
|
|
Packit |
63bb0d |
Secret *string `json:"secret,omitempty"`
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
type totpReq struct {
|
|
Packit |
63bb0d |
User *userReq `json:"user,omitempty"`
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
type identityReq struct {
|
|
Packit |
63bb0d |
Methods []string `json:"methods"`
|
|
Packit |
63bb0d |
Password *passwordReq `json:"password,omitempty"`
|
|
Packit |
63bb0d |
Token *tokenReq `json:"token,omitempty"`
|
|
Packit |
63bb0d |
ApplicationCredential *applicationCredentialReq `json:"application_credential,omitempty"`
|
|
Packit |
63bb0d |
TOTP *totpReq `json:"totp,omitempty"`
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
type authReq struct {
|
|
Packit |
63bb0d |
Identity identityReq `json:"identity"`
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
type request struct {
|
|
Packit |
63bb0d |
Auth authReq `json:"auth"`
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// Populate the request structure based on the provided arguments. Create and return an error
|
|
Packit |
63bb0d |
// if insufficient or incompatible information is present.
|
|
Packit |
63bb0d |
var req request
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
if opts.Password == "" && opts.Passcode == "" {
|
|
Packit |
63bb0d |
if opts.TokenID != "" {
|
|
Packit |
63bb0d |
// Because we aren't using password authentication, it's an error to also provide any of the user-based authentication
|
|
Packit |
63bb0d |
// parameters.
|
|
Packit |
63bb0d |
if opts.Username != "" {
|
|
Packit |
63bb0d |
return nil, ErrUsernameWithToken{}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
if opts.UserID != "" {
|
|
Packit |
63bb0d |
return nil, ErrUserIDWithToken{}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
if opts.DomainID != "" {
|
|
Packit |
63bb0d |
return nil, ErrDomainIDWithToken{}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
if opts.DomainName != "" {
|
|
Packit |
63bb0d |
return nil, ErrDomainNameWithToken{}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// Configure the request for Token authentication.
|
|
Packit |
63bb0d |
req.Auth.Identity.Methods = []string{"token"}
|
|
Packit |
63bb0d |
req.Auth.Identity.Token = &tokenReq{
|
|
Packit |
63bb0d |
ID: opts.TokenID,
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
} else if opts.ApplicationCredentialID != "" {
|
|
Packit |
63bb0d |
// Configure the request for ApplicationCredentialID authentication.
|
|
Packit |
63bb0d |
// https://github.com/openstack/keystoneauth/blob/stable/rocky/keystoneauth1/identity/v3/application_credential.py#L48-L67
|
|
Packit |
63bb0d |
// There are three kinds of possible application_credential requests
|
|
Packit |
63bb0d |
// 1. application_credential id + secret
|
|
Packit |
63bb0d |
// 2. application_credential name + secret + user_id
|
|
Packit |
63bb0d |
// 3. application_credential name + secret + username + domain_id / domain_name
|
|
Packit |
63bb0d |
if opts.ApplicationCredentialSecret == "" {
|
|
Packit |
63bb0d |
return nil, ErrAppCredMissingSecret{}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
req.Auth.Identity.Methods = []string{"application_credential"}
|
|
Packit |
63bb0d |
req.Auth.Identity.ApplicationCredential = &applicationCredentialReq{
|
|
Packit |
63bb0d |
ID: &opts.ApplicationCredentialID,
|
|
Packit |
63bb0d |
Secret: &opts.ApplicationCredentialSecret,
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
} else if opts.ApplicationCredentialName != "" {
|
|
Packit |
63bb0d |
if opts.ApplicationCredentialSecret == "" {
|
|
Packit |
63bb0d |
return nil, ErrAppCredMissingSecret{}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
var userRequest *userReq
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
if opts.UserID != "" {
|
|
Packit |
63bb0d |
// UserID could be used without the domain information
|
|
Packit |
63bb0d |
userRequest = &userReq{
|
|
Packit |
63bb0d |
ID: &opts.UserID,
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
if userRequest == nil && opts.Username == "" {
|
|
Packit |
63bb0d |
// Make sure that Username or UserID are provided
|
|
Packit |
63bb0d |
return nil, ErrUsernameOrUserID{}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
if userRequest == nil && opts.DomainID != "" {
|
|
Packit |
63bb0d |
userRequest = &userReq{
|
|
Packit |
63bb0d |
Name: &opts.Username,
|
|
Packit |
63bb0d |
Domain: &domainReq{ID: &opts.DomainID},
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
if userRequest == nil && opts.DomainName != "" {
|
|
Packit |
63bb0d |
userRequest = &userReq{
|
|
Packit |
63bb0d |
Name: &opts.Username,
|
|
Packit |
63bb0d |
Domain: &domainReq{Name: &opts.DomainName},
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// Make sure that DomainID or DomainName are provided among Username
|
|
Packit |
63bb0d |
if userRequest == nil {
|
|
Packit |
63bb0d |
return nil, ErrDomainIDOrDomainName{}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
req.Auth.Identity.Methods = []string{"application_credential"}
|
|
Packit |
63bb0d |
req.Auth.Identity.ApplicationCredential = &applicationCredentialReq{
|
|
Packit |
63bb0d |
Name: &opts.ApplicationCredentialName,
|
|
Packit |
63bb0d |
User: userRequest,
|
|
Packit |
63bb0d |
Secret: &opts.ApplicationCredentialSecret,
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
} else {
|
|
Packit |
63bb0d |
// If no password or token ID or ApplicationCredential are available, authentication can't continue.
|
|
Packit |
63bb0d |
return nil, ErrMissingPassword{}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
} else {
|
|
Packit |
63bb0d |
// Password authentication.
|
|
Packit |
63bb0d |
if opts.Password != "" {
|
|
Packit |
63bb0d |
req.Auth.Identity.Methods = append(req.Auth.Identity.Methods, "password")
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// TOTP authentication.
|
|
Packit |
63bb0d |
if opts.Passcode != "" {
|
|
Packit |
63bb0d |
req.Auth.Identity.Methods = append(req.Auth.Identity.Methods, "totp")
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// At least one of Username and UserID must be specified.
|
|
Packit |
63bb0d |
if opts.Username == "" && opts.UserID == "" {
|
|
Packit |
63bb0d |
return nil, ErrUsernameOrUserID{}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
if opts.Username != "" {
|
|
Packit |
63bb0d |
// If Username is provided, UserID may not be provided.
|
|
Packit |
63bb0d |
if opts.UserID != "" {
|
|
Packit |
63bb0d |
return nil, ErrUsernameOrUserID{}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// Either DomainID or DomainName must also be specified.
|
|
Packit |
63bb0d |
if opts.DomainID == "" && opts.DomainName == "" {
|
|
Packit |
63bb0d |
return nil, ErrDomainIDOrDomainName{}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
if opts.DomainID != "" {
|
|
Packit |
63bb0d |
if opts.DomainName != "" {
|
|
Packit |
63bb0d |
return nil, ErrDomainIDOrDomainName{}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// Configure the request for Username and Password authentication with a DomainID.
|
|
Packit |
63bb0d |
if opts.Password != "" {
|
|
Packit |
63bb0d |
req.Auth.Identity.Password = &passwordReq{
|
|
Packit |
63bb0d |
User: userReq{
|
|
Packit |
63bb0d |
Name: &opts.Username,
|
|
Packit |
63bb0d |
Password: &opts.Password,
|
|
Packit |
63bb0d |
Domain: &domainReq{ID: &opts.DomainID},
|
|
Packit |
63bb0d |
},
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
if opts.Passcode != "" {
|
|
Packit |
63bb0d |
req.Auth.Identity.TOTP = &totpReq{
|
|
Packit |
63bb0d |
User: &userReq{
|
|
Packit |
63bb0d |
Name: &opts.Username,
|
|
Packit |
63bb0d |
Passcode: &opts.Passcode,
|
|
Packit |
63bb0d |
Domain: &domainReq{ID: &opts.DomainID},
|
|
Packit |
63bb0d |
},
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
if opts.DomainName != "" {
|
|
Packit |
63bb0d |
// Configure the request for Username and Password authentication with a DomainName.
|
|
Packit |
63bb0d |
if opts.Password != "" {
|
|
Packit |
63bb0d |
req.Auth.Identity.Password = &passwordReq{
|
|
Packit |
63bb0d |
User: userReq{
|
|
Packit |
63bb0d |
Name: &opts.Username,
|
|
Packit |
63bb0d |
Password: &opts.Password,
|
|
Packit |
63bb0d |
Domain: &domainReq{Name: &opts.DomainName},
|
|
Packit |
63bb0d |
},
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
if opts.Passcode != "" {
|
|
Packit |
63bb0d |
req.Auth.Identity.TOTP = &totpReq{
|
|
Packit |
63bb0d |
User: &userReq{
|
|
Packit |
63bb0d |
Name: &opts.Username,
|
|
Packit |
63bb0d |
Passcode: &opts.Passcode,
|
|
Packit |
63bb0d |
Domain: &domainReq{Name: &opts.DomainName},
|
|
Packit |
63bb0d |
},
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
if opts.UserID != "" {
|
|
Packit |
63bb0d |
// If UserID is specified, neither DomainID nor DomainName may be.
|
|
Packit |
63bb0d |
if opts.DomainID != "" {
|
|
Packit |
63bb0d |
return nil, ErrDomainIDWithUserID{}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
if opts.DomainName != "" {
|
|
Packit |
63bb0d |
return nil, ErrDomainNameWithUserID{}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// Configure the request for UserID and Password authentication.
|
|
Packit |
63bb0d |
if opts.Password != "" {
|
|
Packit |
63bb0d |
req.Auth.Identity.Password = &passwordReq{
|
|
Packit |
63bb0d |
User: userReq{
|
|
Packit |
63bb0d |
ID: &opts.UserID,
|
|
Packit |
63bb0d |
Password: &opts.Password,
|
|
Packit |
63bb0d |
},
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
if opts.Passcode != "" {
|
|
Packit |
63bb0d |
req.Auth.Identity.TOTP = &totpReq{
|
|
Packit |
63bb0d |
User: &userReq{
|
|
Packit |
63bb0d |
ID: &opts.UserID,
|
|
Packit |
63bb0d |
Passcode: &opts.Passcode,
|
|
Packit |
63bb0d |
},
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
b, err := BuildRequestBody(req, "")
|
|
Packit |
63bb0d |
if err != nil {
|
|
Packit |
63bb0d |
return nil, err
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
if len(scope) != 0 {
|
|
Packit |
63bb0d |
b["auth"].(map[string]interface{})["scope"] = scope
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
return b, nil
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// ToTokenV3ScopeMap builds a scope from AuthOptions and satisfies interface in
|
|
Packit |
63bb0d |
// the v3 tokens package.
|
|
Packit |
63bb0d |
func (opts *AuthOptions) ToTokenV3ScopeMap() (map[string]interface{}, error) {
|
|
Packit |
63bb0d |
// For backwards compatibility.
|
|
Packit |
63bb0d |
// If AuthOptions.Scope was not set, try to determine it.
|
|
Packit |
63bb0d |
// This works well for common scenarios.
|
|
Packit |
63bb0d |
if opts.Scope == nil {
|
|
Packit |
63bb0d |
opts.Scope = new(AuthScope)
|
|
Packit |
63bb0d |
if opts.TenantID != "" {
|
|
Packit |
63bb0d |
opts.Scope.ProjectID = opts.TenantID
|
|
Packit |
63bb0d |
} else {
|
|
Packit |
63bb0d |
if opts.TenantName != "" {
|
|
Packit |
63bb0d |
opts.Scope.ProjectName = opts.TenantName
|
|
Packit |
63bb0d |
opts.Scope.DomainID = opts.DomainID
|
|
Packit |
63bb0d |
opts.Scope.DomainName = opts.DomainName
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
if opts.Scope.System {
|
|
Packit |
63bb0d |
return map[string]interface{}{
|
|
Packit |
63bb0d |
"system": map[string]interface{}{
|
|
Packit |
63bb0d |
"all": true,
|
|
Packit |
63bb0d |
},
|
|
Packit |
63bb0d |
}, nil
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
if opts.Scope.ProjectName != "" {
|
|
Packit |
63bb0d |
// ProjectName provided: either DomainID or DomainName must also be supplied.
|
|
Packit |
63bb0d |
// ProjectID may not be supplied.
|
|
Packit |
63bb0d |
if opts.Scope.DomainID == "" && opts.Scope.DomainName == "" {
|
|
Packit |
63bb0d |
return nil, ErrScopeDomainIDOrDomainName{}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
if opts.Scope.ProjectID != "" {
|
|
Packit |
63bb0d |
return nil, ErrScopeProjectIDOrProjectName{}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
if opts.Scope.DomainID != "" {
|
|
Packit |
63bb0d |
// ProjectName + DomainID
|
|
Packit |
63bb0d |
return map[string]interface{}{
|
|
Packit |
63bb0d |
"project": map[string]interface{}{
|
|
Packit |
63bb0d |
"name": &opts.Scope.ProjectName,
|
|
Packit |
63bb0d |
"domain": map[string]interface{}{"id": &opts.Scope.DomainID},
|
|
Packit |
63bb0d |
},
|
|
Packit |
63bb0d |
}, nil
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
if opts.Scope.DomainName != "" {
|
|
Packit |
63bb0d |
// ProjectName + DomainName
|
|
Packit |
63bb0d |
return map[string]interface{}{
|
|
Packit |
63bb0d |
"project": map[string]interface{}{
|
|
Packit |
63bb0d |
"name": &opts.Scope.ProjectName,
|
|
Packit |
63bb0d |
"domain": map[string]interface{}{"name": &opts.Scope.DomainName},
|
|
Packit |
63bb0d |
},
|
|
Packit |
63bb0d |
}, nil
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
} else if opts.Scope.ProjectID != "" {
|
|
Packit |
63bb0d |
// ProjectID provided. ProjectName, DomainID, and DomainName may not be provided.
|
|
Packit |
63bb0d |
if opts.Scope.DomainID != "" {
|
|
Packit |
63bb0d |
return nil, ErrScopeProjectIDAlone{}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
if opts.Scope.DomainName != "" {
|
|
Packit |
63bb0d |
return nil, ErrScopeProjectIDAlone{}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// ProjectID
|
|
Packit |
63bb0d |
return map[string]interface{}{
|
|
Packit |
63bb0d |
"project": map[string]interface{}{
|
|
Packit |
63bb0d |
"id": &opts.Scope.ProjectID,
|
|
Packit |
63bb0d |
},
|
|
Packit |
63bb0d |
}, nil
|
|
Packit |
63bb0d |
} else if opts.Scope.DomainID != "" {
|
|
Packit |
63bb0d |
// DomainID provided. ProjectID, ProjectName, and DomainName may not be provided.
|
|
Packit |
63bb0d |
if opts.Scope.DomainName != "" {
|
|
Packit |
63bb0d |
return nil, ErrScopeDomainIDOrDomainName{}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// DomainID
|
|
Packit |
63bb0d |
return map[string]interface{}{
|
|
Packit |
63bb0d |
"domain": map[string]interface{}{
|
|
Packit |
63bb0d |
"id": &opts.Scope.DomainID,
|
|
Packit |
63bb0d |
},
|
|
Packit |
63bb0d |
}, nil
|
|
Packit |
63bb0d |
} else if opts.Scope.DomainName != "" {
|
|
Packit |
63bb0d |
// DomainName
|
|
Packit |
63bb0d |
return map[string]interface{}{
|
|
Packit |
63bb0d |
"domain": map[string]interface{}{
|
|
Packit |
63bb0d |
"name": &opts.Scope.DomainName,
|
|
Packit |
63bb0d |
},
|
|
Packit |
63bb0d |
}, nil
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
return nil, nil
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
func (opts AuthOptions) CanReauth() bool {
|
|
Packit |
63bb0d |
if opts.Passcode != "" {
|
|
Packit |
63bb0d |
// cannot reauth using TOTP passcode
|
|
Packit |
63bb0d |
return false
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
return opts.AllowReauth
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// ToTokenV3HeadersMap allows AuthOptions to satisfy the AuthOptionsBuilder
|
|
Packit |
63bb0d |
// interface in the v3 tokens package.
|
|
Packit |
63bb0d |
func (opts *AuthOptions) ToTokenV3HeadersMap(map[string]interface{}) (map[string]string, error) {
|
|
Packit |
63bb0d |
return nil, nil
|
|
Packit |
63bb0d |
}
|