blob: 1790df522bb5107cdc2ed07d9eeebc568c35fc7b [file] [log] [blame]
Ash Wilson85d82652014-08-28 13:57:46 -04001package tokens
2
3import (
Ash Wilson85d82652014-08-28 13:57:46 -04004 "github.com/racker/perigee"
5 "github.com/rackspace/gophercloud"
Ash Wilson85d82652014-08-28 13:57:46 -04006)
7
Ash Wilson85d82652014-08-28 13:57:46 -04008// Scope allows a created token to be limited to a specific domain or project.
9type Scope struct {
10 ProjectID string
11 ProjectName string
12 DomainID string
13 DomainName string
14}
15
Ash Wilsone5550862014-08-28 15:37:09 -040016// Create authenticates and either generates a new token, or changes the Scope of an existing token.
17func Create(c *gophercloud.ServiceClient, scope *Scope) (gophercloud.AuthResults, error) {
Ash Wilson85d82652014-08-28 13:57:46 -040018 type domainReq struct {
19 ID *string `json:"id,omitempty"`
20 Name *string `json:"id,omitempty"`
21 }
22
23 type projectReq struct {
24 Domain *domainReq `json:"domain,omitempty"`
25 Name *string `json:"name,omitempty"`
26 ID *string `json:"id,omitempty"`
27 }
28
29 type userReq struct {
30 ID *string `json:"id,omitempty"`
31 Name *string `json:"name,omitempty"`
32 Password string `json:"password"`
Ash Wilsoncde68122014-08-28 16:15:43 -040033 Domain *domainReq `json:"domain,omitempty"`
Ash Wilson85d82652014-08-28 13:57:46 -040034 }
35
36 type passwordReq struct {
37 User userReq `json:"user"`
38 }
39
40 type tokenReq struct {
41 ID string `json:"id"`
42 }
43
44 type identityReq struct {
45 Methods []string `json:"methods"`
Ash Wilsoncde68122014-08-28 16:15:43 -040046 Password *passwordReq `json:"password,omitempty"`
Ash Wilson85d82652014-08-28 13:57:46 -040047 Token *tokenReq `json:"token,omitempty"`
48 }
49
50 type scopeReq struct {
51 Domain *domainReq `json:"domain,omitempty"`
52 Project *projectReq `json:"project,omitempty"`
53 }
54
55 type authReq struct {
56 Identity identityReq `json:"identity"`
Ash Wilsoncde68122014-08-28 16:15:43 -040057 Scope *scopeReq `json:"scope,omitempty"`
Ash Wilson85d82652014-08-28 13:57:46 -040058 }
59
60 type request struct {
61 Auth authReq `json:"auth"`
62 }
63
Ash Wilsone5550862014-08-28 15:37:09 -040064 ao := c.Options
65
Ash Wilson85d82652014-08-28 13:57:46 -040066 // Populate the request structure based on the provided arguments. Create and return an error
67 // if insufficient or incompatible information is present.
68 var req request
69
70 // Test first for unrecognized arguments.
71 if ao.APIKey != "" {
72 return nil, ErrAPIKeyProvided
73 }
74 if ao.TenantID != "" {
75 return nil, ErrTenantIDProvided
76 }
77 if ao.TenantName != "" {
78 return nil, ErrTenantNameProvided
79 }
80
81 if ao.Password == "" {
82 if c.TokenID != "" {
83 // Because we aren't using password authentication, it's an error to also provide any of the user-based authentication
84 // parameters.
85 if ao.Username != "" {
86 return nil, ErrUsernameWithToken
87 }
88 if ao.UserID != "" {
89 return nil, ErrUserIDWithToken
90 }
91 if ao.DomainID != "" {
92 return nil, ErrDomainIDWithToken
93 }
94 if ao.DomainName != "" {
95 return nil, ErrDomainNameWithToken
96 }
97
98 // Configure the request for Token authentication.
99 req.Auth.Identity.Methods = []string{"token"}
100 req.Auth.Identity.Token = &tokenReq{
101 ID: c.TokenID,
102 }
103 } else {
104 // If no password or token ID are available, authentication can't continue.
105 return nil, ErrMissingPassword
106 }
107 } else {
108 // Password authentication.
109 req.Auth.Identity.Methods = []string{"password"}
110
111 // At least one of Username and UserID must be specified.
112 if ao.Username == "" && ao.UserID == "" {
113 return nil, ErrUsernameOrUserID
114 }
115
116 if ao.Username != "" {
117 // If Username is provided, UserID may not be provided.
118 if ao.UserID != "" {
119 return nil, ErrUsernameOrUserID
120 }
121
122 // Either DomainID or DomainName must also be specified.
123 if ao.DomainID == "" && ao.DomainName == "" {
124 return nil, ErrDomainIDOrDomainName
125 }
126
127 if ao.DomainID != "" {
128 if ao.DomainName != "" {
129 return nil, ErrDomainIDOrDomainName
130 }
131
132 // Configure the request for Username and Password authentication with a DomainID.
133 req.Auth.Identity.Password = &passwordReq{
134 User: userReq{
135 Name: &ao.Username,
136 Password: ao.Password,
137 Domain: &domainReq{ID: &ao.DomainID},
138 },
139 }
140 }
141
142 if ao.DomainName != "" {
143 // Configure the request for Username and Password authentication with a DomainName.
144 req.Auth.Identity.Password = &passwordReq{
145 User: userReq{
146 Name: &ao.Username,
147 Password: ao.Password,
148 Domain: &domainReq{Name: &ao.DomainName},
149 },
150 }
151 }
152 }
153
154 if ao.UserID != "" {
155 // If UserID is specified, neither DomainID nor DomainName may be.
156 if ao.DomainID != "" {
157 return nil, ErrDomainIDWithUserID
158 }
159 if ao.DomainName != "" {
160 return nil, ErrDomainNameWithUserID
161 }
162
163 // Configure the request for UserID and Password authentication.
164 req.Auth.Identity.Password = &passwordReq{
Ash Wilsoncde68122014-08-28 16:15:43 -0400165 User: userReq{ID: &ao.UserID, Password: ao.Password},
Ash Wilson85d82652014-08-28 13:57:46 -0400166 }
167 }
168 }
169
170 // Add a "scope" element if a Scope has been provided.
171 if scope != nil {
172 if scope.ProjectName != "" {
173 // ProjectName provided: either DomainID or DomainName must also be supplied.
174 // ProjectID may not be supplied.
175 if scope.DomainID == "" && scope.DomainName == "" {
176 return nil, ErrScopeDomainIDOrDomainName
177 }
178 if scope.ProjectID != "" {
179 return nil, ErrScopeProjectIDOrProjectName
180 }
181
182 if scope.DomainID != "" {
183 // ProjectName + DomainID
184 req.Auth.Scope = &scopeReq{
185 Project: &projectReq{
186 Name: &scope.ProjectName,
187 Domain: &domainReq{ID: &scope.DomainID},
188 },
189 }
190 }
191
192 if scope.DomainName != "" {
193 // ProjectName + DomainName
194 req.Auth.Scope = &scopeReq{
195 Project: &projectReq{
196 Name: &scope.ProjectName,
197 Domain: &domainReq{Name: &scope.DomainName},
198 },
199 }
200 }
201 } else if scope.ProjectID != "" {
202 // ProjectID provided. ProjectName, DomainID, and DomainName may not be provided.
203 if scope.ProjectName != "" {
204 return nil, ErrScopeProjectIDOrProjectName
205 }
206 if scope.DomainID != "" {
207 return nil, ErrScopeProjectIDAlone
208 }
209 if scope.DomainName != "" {
210 return nil, ErrScopeProjectIDAlone
211 }
212
213 // ProjectID
214 req.Auth.Scope = &scopeReq{
215 Project: &projectReq{ID: &scope.ProjectID},
216 }
217 } else if scope.DomainID != "" {
218 // DomainID provided. ProjectID, ProjectName, and DomainName may not be provided.
219 if scope.DomainName != "" {
220 return nil, ErrScopeDomainIDOrDomainName
221 }
222
223 // DomainID
224 req.Auth.Scope = &scopeReq{
225 Domain: &domainReq{ID: &scope.DomainID},
226 }
227 } else if scope.DomainName != "" {
228 return nil, ErrScopeDomainName
229 } else {
230 return nil, ErrScopeEmpty
231 }
232 }
233
234 var resp TokenCreateResult
235 perigee.Post(getTokenURL(c), perigee.Options{
236 ReqBody: &req,
237 Results: &resp,
238 OkCodes: []int{201},
239 })
240 return &resp, nil
241}