This repository has been archived by the owner on Aug 1, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 181
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
641 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,8 @@ | ||
package apiversions | ||
|
||
import ( | ||
"strings" | ||
"net/url" | ||
"strings" | ||
|
||
"github.com/rackspace/gophercloud" | ||
) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package extensions | ||
|
||
import ( | ||
"github.com/rackspace/gophercloud" | ||
) | ||
|
||
/* | ||
AuthOptions stores information needed to authenticate to an OpenStack cluster. | ||
Pass one to a provider's AuthenticatedClient function to authenticate and obtain a | ||
ProviderClient representing an active session on that provider. | ||
Its fields are the union of those recognized by each identity implementation and | ||
provider. | ||
*/ | ||
type AuthOptions struct { | ||
//Populate fields in gophercloud AuthOptions also. | ||
*gophercloud.AuthOptions | ||
|
||
// Trust allows users to authenticate with Trust ID, | ||
// The TrustID field is to be used with Identity V3 API only. | ||
// ID of the Trust. | ||
TrustID string | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
// Package extensions provides information and interaction with the | ||
// different extensions available for the OpenStack Identity v3 service. | ||
package extensions |
47 changes: 47 additions & 0 deletions
47
openstack/identity/v3/extensions/tokens/endpoint_location.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package tokens | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/rackspace/gophercloud" | ||
) | ||
|
||
// TrustV3EndpointURL discovers the endpoint URL for a specific service from a Catalog acquired | ||
// during the v3 identity service. The specified EndpointOpts are used to identify a unique, | ||
// unambiguous endpoint to return. It's an error both when multiple endpoints match the provided | ||
// criteria and when none do. The minimum that can be specified is a Type, but you will also often | ||
// need to specify a Name and/or a Region depending on what's available on your OpenStack | ||
// deployment. | ||
func TrustV3EndpointURL(catalog *ServiceCatalog, opts gophercloud.EndpointOpts) (string, error) { | ||
// Extract Endpoints from the catalog entries that match the requested Type, Interface, | ||
// Name if provided, and Region if provided. | ||
var endpoints = make([]Endpoint, 0, 1) | ||
for _, entry := range catalog.Entries { | ||
if (entry.Type == opts.Type) && (opts.Name == "" || entry.Name == opts.Name) { | ||
for _, endpoint := range entry.Endpoints { | ||
if opts.Availability != gophercloud.AvailabilityAdmin && | ||
opts.Availability != gophercloud.AvailabilityPublic && | ||
opts.Availability != gophercloud.AvailabilityInternal { | ||
return "", fmt.Errorf("Unexpected availability in endpoint query: %s", opts.Availability) | ||
} | ||
if (opts.Availability == gophercloud.Availability(endpoint.Interface)) && | ||
(opts.Region == "" || endpoint.Region == opts.Region) { | ||
endpoints = append(endpoints, endpoint) | ||
} | ||
} | ||
} | ||
} | ||
|
||
// Report an error if the options were ambiguous. | ||
if len(endpoints) > 1 { | ||
return "", fmt.Errorf("Discovered %d matching endpoints: %#v", len(endpoints), endpoints) | ||
} | ||
|
||
// Extract the URL from the matching Endpoint. | ||
for _, endpoint := range endpoints { | ||
return gophercloud.NormalizeURL(endpoint.URL), nil | ||
} | ||
|
||
// Report an error if there were no matching endpoints. | ||
return "", gophercloud.ErrEndpointNotFound | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,229 @@ | ||
package tokens | ||
|
||
import ( | ||
"net/http" | ||
|
||
"github.com/rackspace/gophercloud" | ||
"github.com/rackspace/gophercloud/openstack/identity/v3/tokens" | ||
"github.com/rackspace/gophercloud/openstack/identity/v3/extensions" | ||
) | ||
|
||
// Scope allows a created token to be limited to a specific domain or project. | ||
type Scope struct { | ||
TrustID string | ||
} | ||
|
||
func subjectTokenHeaders(c *gophercloud.ServiceClient, subjectToken string) map[string]string { | ||
return map[string]string{ | ||
"X-Subject-Token": subjectToken, | ||
} | ||
} | ||
|
||
// Create authenticates and either generates a new token, or changes the Scope of an existing token. | ||
func Create(c *gophercloud.ServiceClient, options extensions.AuthOptions, scope *Scope) CreateResult { | ||
type domainReq struct { | ||
ID *string `json:"id,omitempty"` | ||
Name *string `json:"name,omitempty"` | ||
} | ||
|
||
type v3TrustReq struct { | ||
ID *string `json:"id,omitempty"` | ||
} | ||
|
||
type userReq struct { | ||
ID *string `json:"id,omitempty"` | ||
Name *string `json:"name,omitempty"` | ||
Password string `json:"password"` | ||
Domain *domainReq `json:"domain,omitempty"` | ||
} | ||
|
||
type passwordReq struct { | ||
User userReq `json:"user"` | ||
} | ||
|
||
type tokenReq struct { | ||
ID string `json:"id"` | ||
} | ||
|
||
type identityReq struct { | ||
Methods []string `json:"methods"` | ||
Password *passwordReq `json:"password,omitempty"` | ||
Token *tokenReq `json:"token,omitempty"` | ||
} | ||
|
||
type scopeReq struct { | ||
Trust *v3TrustReq `json:"OS-TRUST:trust,omitempty"` | ||
} | ||
|
||
type authReq struct { | ||
Identity identityReq `json:"identity"` | ||
Scope *scopeReq `json:"scope,omitempty"` | ||
} | ||
|
||
type request struct { | ||
Auth authReq `json:"auth"` | ||
} | ||
|
||
// Populate the request structure based on the provided arguments. Create and return an error | ||
// if insufficient or incompatible information is present. | ||
var req request | ||
|
||
// Test first for unrecognized arguments. | ||
if options.APIKey != "" { | ||
return createErr(tokens.ErrAPIKeyProvided) | ||
} | ||
if options.TenantID != "" { | ||
return createErr(tokens.ErrTenantIDProvided) | ||
} | ||
if options.TenantName != "" { | ||
return createErr(tokens.ErrTenantNameProvided) | ||
} | ||
|
||
if options.Password == "" { | ||
if c.TokenID != "" { | ||
// Because we aren't using password authentication, it's an error to also provide any of the user-based authentication | ||
// parameters. | ||
if options.Username != "" { | ||
return createErr(tokens.ErrUsernameWithToken) | ||
} | ||
if options.UserID != "" { | ||
return createErr(tokens.ErrUserIDWithToken) | ||
} | ||
if options.DomainID != "" { | ||
return createErr(tokens.ErrDomainIDWithToken) | ||
} | ||
if options.DomainName != "" { | ||
return createErr(tokens.ErrDomainNameWithToken) | ||
} | ||
|
||
// Configure the request for Token authentication. | ||
req.Auth.Identity.Methods = []string{"token"} | ||
req.Auth.Identity.Token = &tokenReq{ | ||
ID: c.TokenID, | ||
} | ||
} else { | ||
// If no password or token ID are available, authentication can't continue. | ||
return createErr(tokens.ErrMissingPassword) | ||
} | ||
} else { | ||
// Password authentication. | ||
req.Auth.Identity.Methods = []string{"password"} | ||
|
||
// At least one of Username and UserID must be specified. | ||
if options.Username == "" && options.UserID == "" { | ||
return createErr(tokens.ErrUsernameOrUserID) | ||
} | ||
|
||
if options.Username != "" { | ||
// If Username is provided, UserID may not be provided. | ||
if options.UserID != "" { | ||
return createErr(tokens.ErrUsernameOrUserID) | ||
} | ||
|
||
// Either DomainID or DomainName must also be specified. | ||
if options.DomainID == "" && options.DomainName == "" { | ||
return createErr(tokens.ErrDomainIDOrDomainName) | ||
} | ||
|
||
if options.DomainID != "" { | ||
if options.DomainName != "" { | ||
return createErr(tokens.ErrDomainIDOrDomainName) | ||
} | ||
|
||
// Configure the request for Username and Password authentication with a DomainID. | ||
req.Auth.Identity.Password = &passwordReq{ | ||
User: userReq{ | ||
Name: &options.Username, | ||
Password: options.Password, | ||
Domain: &domainReq{ID: &options.DomainID}, | ||
}, | ||
} | ||
} | ||
|
||
if options.DomainName != "" { | ||
// Configure the request for Username and Password authentication with a DomainName. | ||
req.Auth.Identity.Password = &passwordReq{ | ||
User: userReq{ | ||
Name: &options.Username, | ||
Password: options.Password, | ||
Domain: &domainReq{Name: &options.DomainName}, | ||
}, | ||
} | ||
} | ||
} | ||
|
||
if options.UserID != "" { | ||
// If UserID is specified, neither DomainID nor DomainName may be. | ||
if options.DomainID != "" { | ||
return createErr(tokens.ErrDomainIDWithUserID) | ||
} | ||
if options.DomainName != "" { | ||
return createErr(tokens.ErrDomainNameWithUserID) | ||
} | ||
|
||
// Configure the request for UserID and Password authentication. | ||
req.Auth.Identity.Password = &passwordReq{ | ||
User: userReq{ID: &options.UserID, Password: options.Password}, | ||
} | ||
} | ||
|
||
} | ||
|
||
// Add a "scope" element if a Scope has been provided. | ||
if scope != nil { | ||
if scope.TrustID != "" { | ||
// TrustID provided. | ||
req.Auth.Scope = &scopeReq{ | ||
Trust: &v3TrustReq{ID: &scope.TrustID}, | ||
} | ||
} else { | ||
return createErr(tokens.ErrScopeEmpty) | ||
} | ||
} | ||
|
||
var result CreateResult | ||
var response *http.Response | ||
response, result.Err = c.Post(tokenURL(c), req, &result.Body, nil) | ||
if result.Err != nil { | ||
return result | ||
} | ||
result.Header = response.Header | ||
return result | ||
} | ||
|
||
// Get validates and retrieves information about another token. | ||
func Get(c *gophercloud.ServiceClient, token string) GetResult { | ||
var result GetResult | ||
var response *http.Response | ||
response, result.Err = c.Get(tokenURL(c), &result.Body, &gophercloud.RequestOpts{ | ||
MoreHeaders: subjectTokenHeaders(c, token), | ||
OkCodes: []int{200, 203}, | ||
}) | ||
if result.Err != nil { | ||
return result | ||
} | ||
result.Header = response.Header | ||
return result | ||
} | ||
|
||
// Validate determines if a specified token is valid or not. | ||
func Validate(c *gophercloud.ServiceClient, token string) (bool, error) { | ||
response, err := c.Request("HEAD", tokenURL(c), gophercloud.RequestOpts{ | ||
MoreHeaders: subjectTokenHeaders(c, token), | ||
OkCodes: []int{204, 404}, | ||
}) | ||
if err != nil { | ||
return false, err | ||
} | ||
|
||
return response.StatusCode == 204, nil | ||
} | ||
|
||
// Revoke immediately makes specified token invalid. | ||
func Revoke(c *gophercloud.ServiceClient, token string) RevokeResult { | ||
var res RevokeResult | ||
_, res.Err = c.Delete(tokenURL(c), &gophercloud.RequestOpts{ | ||
MoreHeaders: subjectTokenHeaders(c, token), | ||
}) | ||
return res | ||
} |
Oops, something went wrong.