| package tokens |
| |
| import ( |
| "net/http" |
| |
| "github.com/rackspace/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 |
| } |
| |
| func subjectTokenHeaders(c *gophercloud.ServiceClient, subjectToken string) map[string]string { |
| h := c.AuthenticatedHeaders() |
| h["X-Subject-Token"] = subjectToken |
| return h |
| } |
| |
| // 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"` |
| } |
| |
| type projectReq struct { |
| Domain *domainReq `json:"domain,omitempty"` |
| Name *string `json:"name,omitempty"` |
| 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 { |
| 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.Request("POST", tokenURL(c), gophercloud.RequestOpts{ |
| JSONBody: &req, |
| JSONResponse: &result.Body, |
| }) |
| 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.Request("GET", tokenURL(c), gophercloud.RequestOpts{ |
| MoreHeaders: subjectTokenHeaders(c, token), |
| JSONResponse: &result.Body, |
| 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.Request("DELETE", tokenURL(c), gophercloud.RequestOpts{ |
| MoreHeaders: subjectTokenHeaders(c, token), |
| }) |
| return res |
| } |