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