add extract user method from get token's response include the unit and acceptance tests
diff --git a/acceptance/openstack/identity/v2/token_test.go b/acceptance/openstack/identity/v2/token_test.go
index d903140..e01b3b3 100644
--- a/acceptance/openstack/identity/v2/token_test.go
+++ b/acceptance/openstack/identity/v2/token_test.go
@@ -9,7 +9,8 @@
th "github.com/rackspace/gophercloud/testhelper"
)
-func TestAuthenticate(t *testing.T) {
+func TestAuthenticateAndValidate(t *testing.T) {
+ // 1. TestAuthenticate
ao := v2AuthOptions(t)
service := unauthenticatedClient(t)
@@ -35,4 +36,19 @@
t.Logf(" - region=[%s] publicURL=[%s]", endpoint.Region, endpoint.PublicURL)
}
}
+
+ // 2. TestValidate
+ client := authenticatedClient(t)
+
+ // Validate Token!
+ getResult := tokens2.Get(client, token.ID)
+
+ // Extract and print the user.
+ user, err := getResult.ExtractUser()
+ th.AssertNoErr(t, err)
+
+ t.Logf("Acquired User: [%s]", user.Name)
+ t.Logf("The User id: [%s]", user.ID)
+ t.Logf("The User username: [%s]", user.UserName)
+ t.Logf("The User roles: [%#v]", user.Roles)
}
diff --git a/openstack/identity/v2/tokens/fixtures.go b/openstack/identity/v2/tokens/fixtures.go
index 1cb0d05..6245259 100644
--- a/openstack/identity/v2/tokens/fixtures.go
+++ b/openstack/identity/v2/tokens/fixtures.go
@@ -10,6 +10,7 @@
"github.com/rackspace/gophercloud/openstack/identity/v2/tenants"
th "github.com/rackspace/gophercloud/testhelper"
+ thclient "github.com/rackspace/gophercloud/testhelper/client"
)
// ExpectedToken is the token that should be parsed from TokenCreationResponse.
@@ -54,6 +55,14 @@
},
}
+// ExpectedUser is the token that should be parsed from TokenGetResponse.
+var ExpectedUser = &User{
+ ID: "a530fefc3d594c4ba2693a4ecd6be74e",
+ Name: "apiserver",
+ Roles: []Role{{"member"}, {"service"}},
+ UserName: "apiserver",
+}
+
// TokenCreationResponse is a JSON response that contains ExpectedToken and ExpectedServiceCatalog.
const TokenCreationResponse = `
{
@@ -99,6 +108,39 @@
}
`
+// TokenGetResponse is a JSON response that contains ExpectedToken and ExpectedUser.
+const TokenGetResponse = `
+{
+ "access": {
+ "token": {
+ "issued_at": "2014-01-30T15:30:58.000000Z",
+ "expires": "2014-01-31T15:30:58Z",
+ "id": "aaaabbbbccccdddd",
+ "tenant": {
+ "description": "There are many tenants. This one is yours.",
+ "enabled": true,
+ "id": "fc394f2ab2df4114bde39905f800dc57",
+ "name": "test"
+ }
+ },
+ "serviceCatalog": [],
+ "user": {
+ "id": "a530fefc3d594c4ba2693a4ecd6be74e",
+ "name": "apiserver",
+ "roles": [
+ {
+ "name": "member"
+ },
+ {
+ "name": "service"
+ }
+ ],
+ "roles_links": [],
+ "username": "apiserver"
+ }
+ }
+}`
+
// HandleTokenPost expects a POST against a /tokens handler, ensures that the request body has been
// constructed properly given certain auth options, and returns the result.
func HandleTokenPost(t *testing.T, requestJSON string) {
@@ -115,6 +157,19 @@
})
}
+// HandleTokenGet expects a Get against a /tokens handler, ensures that the request body has been
+// constructed properly given certain auth options, and returns the result.
+func HandleTokenGet(t *testing.T, token string) {
+ th.Mux.HandleFunc("/tokens/"+token, func(w http.ResponseWriter, r *http.Request) {
+ th.TestMethod(t, r, "GET")
+ th.TestHeader(t, r, "Accept", "application/json")
+ th.TestHeader(t, r, "X-Auth-Token", thclient.TokenID)
+
+ w.WriteHeader(http.StatusOK)
+ fmt.Fprintf(w, TokenGetResponse)
+ })
+}
+
// IsSuccessful ensures that a CreateResult was successful and contains the correct token and
// service catalog.
func IsSuccessful(t *testing.T, result CreateResult) {
@@ -126,3 +181,15 @@
th.AssertNoErr(t, err)
th.CheckDeepEquals(t, ExpectedServiceCatalog, serviceCatalog)
}
+
+// GetIsSuccessful ensures that a GetResult was successful and contains the correct token and
+// User Info.
+func GetIsSuccessful(t *testing.T, result GetResult) {
+ token, err := result.ExtractToken()
+ th.AssertNoErr(t, err)
+ th.CheckDeepEquals(t, ExpectedToken, token)
+
+ user, err := result.ExtractUser()
+ th.AssertNoErr(t, err)
+ th.CheckDeepEquals(t, ExpectedUser, user)
+}
diff --git a/openstack/identity/v2/tokens/requests.go b/openstack/identity/v2/tokens/requests.go
index aa8b77f..1f51438 100644
--- a/openstack/identity/v2/tokens/requests.go
+++ b/openstack/identity/v2/tokens/requests.go
@@ -95,8 +95,5 @@
_, result.Err = client.Get(GetURL(client, token), &result.Body, &gophercloud.RequestOpts{
OkCodes: []int{200, 203},
})
- if result.Err != nil {
- return result
- }
return result
}
diff --git a/openstack/identity/v2/tokens/requests_test.go b/openstack/identity/v2/tokens/requests_test.go
index 8b78c85..f1ec339 100644
--- a/openstack/identity/v2/tokens/requests_test.go
+++ b/openstack/identity/v2/tokens/requests_test.go
@@ -139,3 +139,14 @@
tokenPostErr(t, options, ErrPasswordRequired)
}
+
+func tokenGet(t *testing.T, tokenId string) GetResult {
+ th.SetupHTTP()
+ defer th.TeardownHTTP()
+ HandleTokenGet(t, tokenId)
+ return Get(client.ServiceClient(), tokenId)
+}
+
+func TestGetWithToken(t *testing.T) {
+ GetIsSuccessful(t, tokenGet(t, "db22caf43c934e6c829087c41ff8d8d6"))
+}
diff --git a/openstack/identity/v2/tokens/results.go b/openstack/identity/v2/tokens/results.go
index 3903e39..67c577b 100644
--- a/openstack/identity/v2/tokens/results.go
+++ b/openstack/identity/v2/tokens/results.go
@@ -23,10 +23,17 @@
// Tenant provides information about the tenant to which this token grants access.
Tenant tenants.Tenant
+}
- // the owner user of token
- UserName string
- UserID string
+// Authorization need user info which can get from token authentication's response
+type Role struct {
+ Name string `mapstructure:"name"`
+}
+type User struct {
+ ID string `mapstructure:"id"`
+ Name string `mapstructure:"name"`
+ UserName string `mapstructure:"username"`
+ Roles []Role `mapstructure:"roles"`
}
// Endpoint represents a single API endpoint offered by a service.
@@ -78,9 +85,10 @@
gophercloud.Result
}
-// GetResult is the deferred response from a Get call.
+// GetResult is the deferred response from a Get call, which is the same with a Created token.
+// Use ExtractUser() to interpret it as a User.
type GetResult struct {
- gophercloud.Result
+ CreateResult
}
// ExtractToken returns the just-created Token from a CreateResult.
@@ -141,22 +149,15 @@
return CreateResult{gophercloud.Result{Err: err}}
}
-// ExtractToken returns the Token from a GetResult.
-func (result GetResult) ExtractToken() (*Token, error) {
+// ExtractUser returns the User from a GetResult.
+func (result GetResult) ExtractUser() (*User, error) {
if result.Err != nil {
return nil, result.Err
}
var response struct {
Access struct {
- Token struct {
- Expires string `mapstructure:"expires"`
- ID string `mapstructure:"id"`
- } `mapstructure:"token"`
- User struct {
- ID string `mapstructure:"id"`
- Name string `mapstructure:"name"`
- } `mapstructure:"user"`
+ User User `mapstructure:"user"`
} `mapstructure:"access"`
}
@@ -165,15 +166,5 @@
return nil, err
}
- expiresTs, err := time.Parse(gophercloud.RFC3339Milli, response.Access.Token.Expires)
- if err != nil {
- return nil, err
- }
-
- return &Token{
- ID: response.Access.Token.ID,
- ExpiresAt: expiresTs,
- UserID: response.Access.User.ID,
- UserName: response.Access.User.Name,
- }, nil
+ return &response.Access.User, nil
}
diff --git a/provider_client.go b/provider_client.go
index ef028cf..e813e0e 100644
--- a/provider_client.go
+++ b/provider_client.go
@@ -185,21 +185,10 @@
if resp.StatusCode == http.StatusUnauthorized {
if client.ReauthFunc != nil {
- // make sure ReauthFunc only exec one time, or will occur endless recursive loop when admin reauth fail
- execFunc := client.ReauthFunc
- client.ReauthFunc = nil
- err = execFunc()
- client.ReauthFunc = execFunc
+ err = client.ReauthFunc()
if err != nil {
return nil, fmt.Errorf("Error trying to re-authenticate: %s", err)
}
-
- if options.MoreHeaders != nil {
- options.MoreHeaders["X-Auth-Token"] = client.TokenID
- } else {
- options.MoreHeaders = client.AuthenticatedHeaders()
- }
-
if options.RawBody != nil {
options.RawBody.Seek(0, 0)
}