Override request body generation for API keys.
diff --git a/openstack/identity/v2/tokens/requests.go b/openstack/identity/v2/tokens/requests.go
index 96c28cf..c25a72b 100644
--- a/openstack/identity/v2/tokens/requests.go
+++ b/openstack/identity/v2/tokens/requests.go
@@ -19,6 +19,11 @@
gophercloud.AuthOptions
}
+// WrapOptions embeds a root AuthOptions struct in a package-specific one.
+func WrapOptions(original gophercloud.AuthOptions) AuthOptions {
+ return AuthOptions{AuthOptions: original}
+}
+
// ToTokenCreateMap converts AuthOptions into nested maps that can be serialized into a JSON
// request.
func (auth AuthOptions) ToTokenCreateMap() (map[string]interface{}, error) {
diff --git a/rackspace/identity/v2/tokens/delegate.go b/rackspace/identity/v2/tokens/delegate.go
index 6a5c1b3..4f9885a 100644
--- a/rackspace/identity/v2/tokens/delegate.go
+++ b/rackspace/identity/v2/tokens/delegate.go
@@ -1,50 +1,60 @@
package tokens
import (
- "github.com/racker/perigee"
+ "errors"
+
"github.com/rackspace/gophercloud"
os "github.com/rackspace/gophercloud/openstack/identity/v2/tokens"
)
+var (
+ // ErrPasswordProvided is returned if both a password and an API key are provided to Create.
+ ErrPasswordProvided = errors.New("Please provide either a password or an API key.")
+)
+
+// AuthOptions wraps the OpenStack AuthOptions struct to be able to customize the request body
+// when API key authentication is used.
+type AuthOptions struct {
+ os.AuthOptions
+}
+
+// WrapOptions embeds a root AuthOptions struct in a package-specific one.
+func WrapOptions(original gophercloud.AuthOptions) AuthOptions {
+ return AuthOptions{AuthOptions: os.WrapOptions(original)}
+}
+
+// ToTokenCreateMap serializes an AuthOptions into a request body. If an API key is provided, it
+// will be used, otherwise
+func (auth AuthOptions) ToTokenCreateMap() (map[string]interface{}, error) {
+ if auth.APIKey == "" {
+ return auth.AuthOptions.ToTokenCreateMap()
+ }
+
+ // Verify that other required attributes are present.
+ if auth.Username == "" {
+ return nil, os.ErrUsernameRequired
+ }
+
+ authMap := make(map[string]interface{})
+
+ authMap["RAX-KSKEY:apiKeyCredentials"] = map[string]interface{}{
+ "username": auth.Username,
+ "apiKey": auth.APIKey,
+ }
+
+ if auth.TenantID != "" {
+ authMap["tenantId"] = auth.TenantID
+ }
+ if auth.TenantName != "" {
+ authMap["tenantName"] = auth.TenantName
+ }
+
+ return map[string]interface{}{"auth": authMap}, nil
+}
+
// Create authenticates to Rackspace's identity service and attempts to acquire a Token. Rather
// than interact with this service directly, users should generally call
// rackspace.AuthenticatedClient().
-func Create(client *gophercloud.ServiceClient, auth gophercloud.AuthOptions) os.CreateResult {
- if auth.APIKey != "" {
- // Authenticate with the provided API key.
-
- if auth.Username == "" {
- return createErr(os.ErrUsernameRequired)
- }
-
- var request struct {
- Auth struct {
- APIKeyCredentials struct {
- Username string `json:"username"`
- APIKey string `json:"apiKey"`
- } `json:"RAX-KSKEY:apiKeyCredentials"`
- TenantID string `json:"tenantId,omitempty"`
- TenantName string `json:"tenantName,omitempty"`
- } `json:"auth"`
- }
-
- request.Auth.APIKeyCredentials.Username = auth.Username
- request.Auth.APIKeyCredentials.APIKey = auth.APIKey
- request.Auth.TenantID = auth.TenantID
- request.Auth.TenantName = auth.TenantName
-
- var result os.CreateResult
- _, result.Err = perigee.Request("POST", os.CreateURL(client), perigee.Options{
- ReqBody: &request,
- Results: &result.Resp,
- OkCodes: []int{200, 203},
- })
- return result
- }
-
+func Create(client *gophercloud.ServiceClient, auth AuthOptions) os.CreateResult {
return os.Create(client, auth)
}
-
-func createErr(err error) os.CreateResult {
- return os.CreateResult{CommonResult: gophercloud.CommonResult{Err: err}}
-}
diff --git a/rackspace/identity/v2/tokens/delegate_test.go b/rackspace/identity/v2/tokens/delegate_test.go
index c289947..9f9b321 100644
--- a/rackspace/identity/v2/tokens/delegate_test.go
+++ b/rackspace/identity/v2/tokens/delegate_test.go
@@ -110,7 +110,7 @@
`)
})
- return Create(&client, options)
+ return Create(&client, WrapOptions(options))
}
func tokenPostErr(t *testing.T, options gophercloud.AuthOptions, expectedErr error) {
@@ -128,7 +128,7 @@
fmt.Fprintf(w, `{}`)
})
- actualErr := Create(&client, options).Err
+ actualErr := Create(&client, WrapOptions(options)).Err
th.CheckEquals(t, expectedErr, actualErr)
}