dsl struct tags; wip
diff --git a/openstack/identity/v3/tokens/requests.go b/openstack/identity/v3/tokens/requests.go
index 4b87311..e7320fd 100644
--- a/openstack/identity/v3/tokens/requests.go
+++ b/openstack/identity/v3/tokens/requests.go
@@ -6,12 +6,11 @@
"github.com/gophercloud/gophercloud"
)
-// Scope allows a created token to be limited to a specific domain or project.
-type Scope struct {
- ProjectID string
- ProjectName string
- DomainID string
- DomainName string
+// AuthOptionsBuilder describes any argument that may be passed to the Create call.
+type AuthOptionsBuilder interface {
+ // ToTokenV3CreateMap assembles the Create request body, returning an error if parameters are
+ // missing or inconsistent.
+ ToTokenV3CreateMap(*gophercloud.ScopeOptsV3) (map[string]interface{}, error)
}
func subjectTokenHeaders(c *gophercloud.ServiceClient, subjectToken string) map[string]string {
@@ -21,241 +20,33 @@
}
// Create authenticates and either generates a new token, or changes the Scope of an existing token.
-func Create(c *gophercloud.ServiceClient, options gophercloud.AuthOptions, scope *Scope) CreateResult {
- type domainReq struct {
- ID *string `json:"id,omitempty"`
- Name *string `json:"name,omitempty"`
+func Create(c *gophercloud.ServiceClient, opts AuthOptionsBuilder, scopeOpts *gophercloud.ScopeOptsV3) CreateResult {
+ var r CreateResult
+ b, err := opts.ToTokenV3CreateMap(scopeOpts)
+ if err != nil {
+ r.Err = err
+ return r
}
-
- type projectReq struct {
- Domain *domainReq `json:"domain,omitempty"`
- Name *string `json:"name,omitempty"`
- ID *string `json:"id,omitempty"`
+ var resp *http.Response
+ resp, r.Err = c.Post(tokenURL(c), b, &r.Body, nil)
+ if resp != nil {
+ r.Header = resp.Header
}
-
- 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 {
- Domain *domainReq `json:"domain,omitempty"`
- Project *projectReq `json:"project,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(ErrAPIKeyProvided)
- }
- if options.TenantID != "" {
- return createErr(ErrTenantIDProvided)
- }
- if options.TenantName != "" {
- return createErr(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(ErrUsernameWithToken)
- }
- if options.UserID != "" {
- return createErr(ErrUserIDWithToken)
- }
- if options.DomainID != "" {
- return createErr(ErrDomainIDWithToken)
- }
- if options.DomainName != "" {
- return createErr(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(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(ErrUsernameOrUserID)
- }
-
- if options.Username != "" {
- // If Username is provided, UserID may not be provided.
- if options.UserID != "" {
- return createErr(ErrUsernameOrUserID)
- }
-
- // Either DomainID or DomainName must also be specified.
- if options.DomainID == "" && options.DomainName == "" {
- return createErr(ErrDomainIDOrDomainName)
- }
-
- if options.DomainID != "" {
- if options.DomainName != "" {
- return createErr(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(ErrDomainIDWithUserID)
- }
- if options.DomainName != "" {
- return createErr(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.ProjectName != "" {
- // ProjectName provided: either DomainID or DomainName must also be supplied.
- // ProjectID may not be supplied.
- if scope.DomainID == "" && scope.DomainName == "" {
- return createErr(ErrScopeDomainIDOrDomainName)
- }
- if scope.ProjectID != "" {
- return createErr(ErrScopeProjectIDOrProjectName)
- }
-
- if scope.DomainID != "" {
- // ProjectName + DomainID
- req.Auth.Scope = &scopeReq{
- Project: &projectReq{
- Name: &scope.ProjectName,
- Domain: &domainReq{ID: &scope.DomainID},
- },
- }
- }
-
- if scope.DomainName != "" {
- // ProjectName + DomainName
- req.Auth.Scope = &scopeReq{
- Project: &projectReq{
- Name: &scope.ProjectName,
- Domain: &domainReq{Name: &scope.DomainName},
- },
- }
- }
- } else if scope.ProjectID != "" {
- // ProjectID provided. ProjectName, DomainID, and DomainName may not be provided.
- if scope.DomainID != "" {
- return createErr(ErrScopeProjectIDAlone)
- }
- if scope.DomainName != "" {
- return createErr(ErrScopeProjectIDAlone)
- }
-
- // ProjectID
- req.Auth.Scope = &scopeReq{
- Project: &projectReq{ID: &scope.ProjectID},
- }
- } else if scope.DomainID != "" {
- // DomainID provided. ProjectID, ProjectName, and DomainName may not be provided.
- if scope.DomainName != "" {
- return createErr(ErrScopeDomainIDOrDomainName)
- }
-
- // DomainID
- req.Auth.Scope = &scopeReq{
- Domain: &domainReq{ID: &scope.DomainID},
- }
- } else if scope.DomainName != "" {
- return createErr(ErrScopeDomainName)
- } else {
- return createErr(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
+ return r
}
// 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{
+ var r GetResult
+ var resp *http.Response
+ resp, r.Err = c.Get(tokenURL(c), &r.Body, &gophercloud.RequestOpts{
MoreHeaders: subjectTokenHeaders(c, token),
OkCodes: []int{200, 203},
})
- if result.Err != nil {
- return result
+ if resp != nil {
+ r.Header = resp.Header
}
- result.Header = response.Header
- return result
+ return r
}
// Validate determines if a specified token is valid or not.
@@ -273,9 +64,9 @@
// 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{
+ var r RevokeResult
+ _, r.Err = c.Delete(tokenURL(c), &gophercloud.RequestOpts{
MoreHeaders: subjectTokenHeaders(c, token),
})
- return res
+ return r
}
diff --git a/openstack/identity/v3/tokens/requests_test.go b/openstack/identity/v3/tokens/requests_test.go
index 89d3b51..a39a6f4 100644
--- a/openstack/identity/v3/tokens/requests_test.go
+++ b/openstack/identity/v3/tokens/requests_test.go
@@ -11,7 +11,7 @@
)
// authTokenPost verifies that providing certain AuthOptions and Scope results in an expected JSON structure.
-func authTokenPost(t *testing.T, options gophercloud.AuthOptions, scope *Scope, requestJSON string) {
+func authTokenPost(t *testing.T, options AuthOptionsBuilder, scope *gophercloud.ScopeOptsV3, requestJSON string) {
testhelper.SetupHTTP()
defer testhelper.TeardownHTTP()
@@ -42,7 +42,7 @@
}
}
-func authTokenPostErr(t *testing.T, options gophercloud.AuthOptions, scope *Scope, includeToken bool, expectedErr error) {
+func authTokenPostErr(t *testing.T, options AuthOptionsBuilder, scope *gophercloud.ScopeOptsV3, includeToken bool, expectedErr error) {
testhelper.SetupHTTP()
defer testhelper.TeardownHTTP()
@@ -64,7 +64,10 @@
}
func TestCreateUserIDAndPassword(t *testing.T) {
- authTokenPost(t, gophercloud.AuthOptions{UserID: "me", Password: "squirrel!"}, nil, `
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "me"
+ ao.Password = "squirrel!"
+ authTokenPost(t, ao, nil, `
{
"auth": {
"identity": {
@@ -79,7 +82,10 @@
}
func TestCreateUsernameDomainIDPassword(t *testing.T) {
- authTokenPost(t, gophercloud.AuthOptions{Username: "fakey", Password: "notpassword", DomainID: "abc123"}, nil, `
+ ao := gophercloud.AuthOptions{DomainID: "abc123"}
+ ao.Username = "fakey"
+ ao.Password = "notpassword"
+ authTokenPost(t, ao, nil, `
{
"auth": {
"identity": {
@@ -100,7 +106,10 @@
}
func TestCreateUsernameDomainNamePassword(t *testing.T) {
- authTokenPost(t, gophercloud.AuthOptions{Username: "frank", Password: "swordfish", DomainName: "spork.net"}, nil, `
+ ao := gophercloud.AuthOptions{DomainName: "spork.net"}
+ ao.Username = "frank"
+ ao.Password = "swordfish"
+ authTokenPost(t, ao, nil, `
{
"auth": {
"identity": {
@@ -121,7 +130,7 @@
}
func TestCreateTokenID(t *testing.T) {
- authTokenPost(t, gophercloud.AuthOptions{}, nil, `
+ authTokenPost(t, gophercloud.AuthOptions{TokenID: "12345abcdef"}, nil, `
{
"auth": {
"identity": {
@@ -136,9 +145,11 @@
}
func TestCreateProjectIDScope(t *testing.T) {
- options := gophercloud.AuthOptions{UserID: "fenris", Password: "g0t0h311"}
- scope := &Scope{ProjectID: "123456"}
- authTokenPost(t, options, scope, `
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "fenris"
+ ao.Password = "g0t0h311"
+ scope := &gophercloud.ScopeOptsV3{ProjectID: "123456"}
+ authTokenPost(t, ao, scope, `
{
"auth": {
"identity": {
@@ -161,9 +172,11 @@
}
func TestCreateDomainIDScope(t *testing.T) {
- options := gophercloud.AuthOptions{UserID: "fenris", Password: "g0t0h311"}
- scope := &Scope{DomainID: "1000"}
- authTokenPost(t, options, scope, `
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "fenris"
+ ao.Password = "g0t0h311"
+ scope := &gophercloud.ScopeOptsV3{DomainID: "1000"}
+ authTokenPost(t, ao, scope, `
{
"auth": {
"identity": {
@@ -186,9 +199,11 @@
}
func TestCreateProjectNameAndDomainIDScope(t *testing.T) {
- options := gophercloud.AuthOptions{UserID: "fenris", Password: "g0t0h311"}
- scope := &Scope{ProjectName: "world-domination", DomainID: "1000"}
- authTokenPost(t, options, scope, `
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "fenris"
+ ao.Password = "g0t0h311"
+ scope := &gophercloud.ScopeOptsV3{ProjectName: "world-domination", DomainID: "1000"}
+ authTokenPost(t, ao, scope, `
{
"auth": {
"identity": {
@@ -214,9 +229,11 @@
}
func TestCreateProjectNameAndDomainNameScope(t *testing.T) {
- options := gophercloud.AuthOptions{UserID: "fenris", Password: "g0t0h311"}
- scope := &Scope{ProjectName: "world-domination", DomainName: "evil-plans"}
- authTokenPost(t, options, scope, `
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "fenris"
+ ao.Password = "g0t0h311"
+ scope := &gophercloud.ScopeOptsV3{ProjectName: "world-domination", DomainName: "evil-plans"}
+ authTokenPost(t, ao, scope, `
{
"auth": {
"identity": {
@@ -261,8 +278,10 @@
}`)
})
- options := gophercloud.AuthOptions{UserID: "me", Password: "shhh"}
- token, err := Create(&client, options, nil).Extract()
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "me"
+ ao.Password = "shhh"
+ token, err := Create(&client, ao, nil).Extract()
if err != nil {
t.Fatalf("Create returned an error: %v", err)
}
@@ -276,20 +295,10 @@
authTokenPostErr(t, gophercloud.AuthOptions{}, nil, false, ErrMissingPassword)
}
-func TestCreateFailureAPIKey(t *testing.T) {
- authTokenPostErr(t, gophercloud.AuthOptions{APIKey: "something"}, nil, false, ErrAPIKeyProvided)
-}
-
-func TestCreateFailureTenantID(t *testing.T) {
- authTokenPostErr(t, gophercloud.AuthOptions{TenantID: "something"}, nil, false, ErrTenantIDProvided)
-}
-
-func TestCreateFailureTenantName(t *testing.T) {
- authTokenPostErr(t, gophercloud.AuthOptions{TenantName: "something"}, nil, false, ErrTenantNameProvided)
-}
-
func TestCreateFailureTokenIDUsername(t *testing.T) {
- authTokenPostErr(t, gophercloud.AuthOptions{Username: "something"}, nil, true, ErrUsernameWithToken)
+ ao := gophercloud.AuthOptions{}
+ ao.Username = "somthing"
+ authTokenPostErr(t, ao, nil, true, ErrUsernameWithToken)
}
func TestCreateFailureTokenIDUserID(t *testing.T) {
@@ -305,95 +314,105 @@
}
func TestCreateFailureMissingUser(t *testing.T) {
- options := gophercloud.AuthOptions{Password: "supersecure"}
- authTokenPostErr(t, options, nil, false, ErrUsernameOrUserID)
+ ao := gophercloud.AuthOptions{}
+ ao.Password = "supersecure"
+ authTokenPostErr(t, ao, nil, false, ErrUsernameOrUserID)
}
func TestCreateFailureBothUser(t *testing.T) {
- options := gophercloud.AuthOptions{
- Password: "supersecure",
- Username: "oops",
- UserID: "redundancy",
- }
- authTokenPostErr(t, options, nil, false, ErrUsernameOrUserID)
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "redundancy"
+ ao.Username = "oops"
+ ao.Password = "supersecure"
+ authTokenPostErr(t, ao, nil, false, ErrUsernameOrUserID)
}
func TestCreateFailureMissingDomain(t *testing.T) {
- options := gophercloud.AuthOptions{
- Password: "supersecure",
- Username: "notuniqueenough",
- }
- authTokenPostErr(t, options, nil, false, ErrDomainIDOrDomainName)
+ ao := gophercloud.AuthOptions{}
+ ao.Username = "notuniqueenough"
+ ao.Password = "supersecure"
+ authTokenPostErr(t, ao, nil, false, ErrDomainIDOrDomainName)
}
func TestCreateFailureBothDomain(t *testing.T) {
- options := gophercloud.AuthOptions{
- Password: "supersecure",
- Username: "someone",
- DomainID: "hurf",
- DomainName: "durf",
- }
- authTokenPostErr(t, options, nil, false, ErrDomainIDOrDomainName)
+ ao := gophercloud.AuthOptions{}
+ ao.Username = "someone"
+ ao.Password = "supersecure"
+ ao.DomainID = "hurf"
+ ao.DomainName = "durf"
+ authTokenPostErr(t, ao, nil, false, ErrDomainIDOrDomainName)
}
func TestCreateFailureUserIDDomainID(t *testing.T) {
- options := gophercloud.AuthOptions{
- UserID: "100",
- Password: "stuff",
- DomainID: "oops",
- }
- authTokenPostErr(t, options, nil, false, ErrDomainIDWithUserID)
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "100"
+ ao.Password = "stuff"
+ ao.DomainID = "oops"
+ authTokenPostErr(t, ao, nil, false, ErrDomainIDWithUserID)
}
func TestCreateFailureUserIDDomainName(t *testing.T) {
- options := gophercloud.AuthOptions{
- UserID: "100",
- Password: "sssh",
- DomainName: "oops",
- }
- authTokenPostErr(t, options, nil, false, ErrDomainNameWithUserID)
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "100"
+ ao.Password = "sssh"
+ ao.DomainName = "oops"
+ authTokenPostErr(t, ao, nil, false, ErrDomainNameWithUserID)
}
func TestCreateFailureScopeProjectNameAlone(t *testing.T) {
- options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
- scope := &Scope{ProjectName: "notenough"}
- authTokenPostErr(t, options, scope, false, ErrScopeDomainIDOrDomainName)
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "myself"
+ ao.Password = "swordfish"
+ scope := &gophercloud.ScopeOptsV3{ProjectName: "notenough"}
+ authTokenPostErr(t, ao, scope, false, ErrScopeDomainIDOrDomainName)
}
func TestCreateFailureScopeProjectNameAndID(t *testing.T) {
- options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
- scope := &Scope{ProjectName: "whoops", ProjectID: "toomuch", DomainID: "1234"}
- authTokenPostErr(t, options, scope, false, ErrScopeProjectIDOrProjectName)
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "myself"
+ ao.Password = "swordfish"
+ scope := &gophercloud.ScopeOptsV3{ProjectName: "whoops", ProjectID: "toomuch", DomainID: "1234"}
+ authTokenPostErr(t, ao, scope, false, ErrScopeProjectIDOrProjectName)
}
func TestCreateFailureScopeProjectIDAndDomainID(t *testing.T) {
- options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
- scope := &Scope{ProjectID: "toomuch", DomainID: "notneeded"}
- authTokenPostErr(t, options, scope, false, ErrScopeProjectIDAlone)
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "myself"
+ ao.Password = "swordfish"
+ scope := &gophercloud.ScopeOptsV3{ProjectID: "toomuch", DomainID: "notneeded"}
+ authTokenPostErr(t, ao, scope, false, ErrScopeProjectIDAlone)
}
func TestCreateFailureScopeProjectIDAndDomainNAme(t *testing.T) {
- options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
- scope := &Scope{ProjectID: "toomuch", DomainName: "notneeded"}
- authTokenPostErr(t, options, scope, false, ErrScopeProjectIDAlone)
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "myself"
+ ao.Password = "swordfish"
+ scope := &gophercloud.ScopeOptsV3{ProjectID: "toomuch", DomainName: "notneeded"}
+ authTokenPostErr(t, ao, scope, false, ErrScopeProjectIDAlone)
}
func TestCreateFailureScopeDomainIDAndDomainName(t *testing.T) {
- options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
- scope := &Scope{DomainID: "toomuch", DomainName: "notneeded"}
- authTokenPostErr(t, options, scope, false, ErrScopeDomainIDOrDomainName)
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "myself"
+ ao.Password = "swordfish"
+ scope := &gophercloud.ScopeOptsV3{DomainID: "toomuch", DomainName: "notneeded"}
+ authTokenPostErr(t, ao, scope, false, ErrScopeDomainIDOrDomainName)
}
func TestCreateFailureScopeDomainNameAlone(t *testing.T) {
- options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
- scope := &Scope{DomainName: "notenough"}
- authTokenPostErr(t, options, scope, false, ErrScopeDomainName)
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "myself"
+ ao.Password = "swordfish"
+ scope := &gophercloud.ScopeOptsV3{DomainName: "notenough"}
+ authTokenPostErr(t, ao, scope, false, ErrScopeDomainName)
}
func TestCreateFailureEmptyScope(t *testing.T) {
- options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
- scope := &Scope{}
- authTokenPostErr(t, options, scope, false, ErrScopeEmpty)
+ ao := gophercloud.AuthOptions{}
+ ao.UserID = "myself"
+ ao.Password = "swordfish"
+ scope := &gophercloud.ScopeOptsV3{}
+ authTokenPostErr(t, ao, scope, false, ErrScopeEmpty)
}
func TestGetRequest(t *testing.T) {