Authentication at the identity client level.
diff --git a/openstack/identity/v3/client.go b/openstack/identity/v3/client.go
index 8c6e3e4..5f25ee6 100644
--- a/openstack/identity/v3/client.go
+++ b/openstack/identity/v3/client.go
@@ -4,11 +4,14 @@
"time"
"github.com/rackspace/gophercloud"
+ "github.com/rackspace/gophercloud/openstack/identity/v3/tokens"
)
// Client abstracts the connection information necessary to make API calls to Identity v3 resources.
// It exists mainly to adhere to the IdentityService interface.
-type Client gophercloud.ServiceClient
+type Client struct {
+ gophercloud.ServiceClient
+}
// Token models a token acquired from the tokens/ API resource.
type Token struct {
@@ -19,12 +22,34 @@
// NewClient creates a new client associated with the v3 identity service of a provider.
func NewClient(provider *gophercloud.ProviderClient) *Client {
return &Client{
- ProviderClient: *provider,
- Endpoint: provider.IdentityEndpoint + "v3/",
+ ServiceClient: gophercloud.ServiceClient{
+ ProviderClient: *provider,
+ Endpoint: provider.IdentityEndpoint + "v3/",
+ },
}
}
// Authenticate provides the supplied credentials to an identity v3 endpoint and attempts to acquire a token.
func (c *Client) Authenticate(authOptions gophercloud.AuthOptions) (*Token, error) {
- return nil, nil
+ c.ServiceClient.ProviderClient.Options = authOptions
+
+ result, err := tokens.Create(&c.ServiceClient, nil)
+ if err != nil {
+ return nil, err
+ }
+
+ tokenID, err := result.TokenID()
+ if err != nil {
+ return nil, err
+ }
+
+ expiresAt, err := result.ExpiresAt()
+ if err != nil {
+ return nil, err
+ }
+
+ return &Token{
+ ID: tokenID,
+ ExpiresAt: expiresAt,
+ }, nil
}
diff --git a/openstack/identity/v3/client_test.go b/openstack/identity/v3/client_test.go
index 7c57e68..0744e7d 100644
--- a/openstack/identity/v3/client_test.go
+++ b/openstack/identity/v3/client_test.go
@@ -4,17 +4,35 @@
"fmt"
"net/http"
"testing"
+ "time"
"github.com/rackspace/gophercloud"
+ "github.com/rackspace/gophercloud/openstack/identity/v3/tokens"
"github.com/rackspace/gophercloud/testhelper"
)
+func TestNewClient(t *testing.T) {
+ testhelper.SetupHTTP()
+ defer testhelper.TeardownHTTP()
+
+ provider := &gophercloud.ProviderClient{
+ IdentityEndpoint: testhelper.Endpoint(),
+ }
+ client := NewClient(provider)
+
+ expected := testhelper.Endpoint() + "v3/"
+ if client.Endpoint != expected {
+ t.Errorf("Expected endpoint to be %s, but was %s", expected, client.Endpoint)
+ }
+}
+
func TestAuthentication(t *testing.T) {
testhelper.SetupHTTP()
defer testhelper.TeardownHTTP()
+ const ID = "aaaa1111"
testhelper.Mux.HandleFunc("/v3/auth/tokens", func(w http.ResponseWriter, r *http.Request) {
- w.Header().Add("X-Subject-Token", "aaaa1111")
+ w.Header().Add("X-Subject-Token", ID)
w.WriteHeader(http.StatusCreated)
fmt.Fprintf(w, `{ "token": { "expires_at": "2013-02-02T18:30:59.000000Z" } }`)
@@ -25,8 +43,17 @@
}
client := NewClient(provider)
- expected := testhelper.Endpoint() + "v3/"
- if client.Endpoint != expected {
- t.Errorf("Expected endpoint to be %s, but was %s", expected, client.Endpoint)
+ token, err := client.Authenticate(gophercloud.AuthOptions{UserID: "me", Password: "swordfish"})
+ if err != nil {
+ t.Errorf("Unexpected error from authentication: %v", err)
+ }
+
+ if token.ID != ID {
+ t.Errorf("Expected token ID [%s], but got [%s]", ID, token.ID)
+ }
+
+ expectedExpiration, _ := time.Parse(tokens.RFC3339Milli, "2013-02-02T18:30:59.000000Z")
+ if token.ExpiresAt != expectedExpiration {
+ t.Errorf("Expected token expiration [%v], but got [%v]", expectedExpiration, token.ExpiresAt)
}
}