~juju-qa/ubuntu/yakkety/juju/2.0-rc3-again

« back to all changes in this revision

Viewing changes to src/launchpad.net/goamz/iam/iamtest/server.go

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2013-04-24 22:34:47 UTC
  • Revision ID: package-import@ubuntu.com-20130424223447-f0qdji7ubnyo0s71
Tags: upstream-1.10.0.1
ImportĀ upstreamĀ versionĀ 1.10.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Package iamtest implements a fake IAM provider with the capability of
 
2
// inducing errors on any given operation, and retrospectively determining what
 
3
// operations have been carried out.
 
4
package iamtest
 
5
 
 
6
import (
 
7
        "encoding/json"
 
8
        "encoding/xml"
 
9
        "fmt"
 
10
        "launchpad.net/goamz/iam"
 
11
        "net"
 
12
        "net/http"
 
13
        "strings"
 
14
        "sync"
 
15
)
 
16
 
 
17
type action struct {
 
18
        srv   *Server
 
19
        w     http.ResponseWriter
 
20
        req   *http.Request
 
21
        reqId string
 
22
}
 
23
 
 
24
// Server implements an IAM simulator for use in tests.
 
25
type Server struct {
 
26
        reqId        int
 
27
        url          string
 
28
        listener     net.Listener
 
29
        users        []iam.User
 
30
        groups       []iam.Group
 
31
        accessKeys   []iam.AccessKey
 
32
        userPolicies []iam.UserPolicy
 
33
        mutex        sync.Mutex
 
34
}
 
35
 
 
36
func NewServer() (*Server, error) {
 
37
        l, err := net.Listen("tcp", "localhost:0")
 
38
        if err != nil {
 
39
                return nil, fmt.Errorf("cannot listen on localhost: %v", err)
 
40
        }
 
41
        srv := &Server{
 
42
                listener: l,
 
43
                url:      "http://" + l.Addr().String(),
 
44
        }
 
45
        go http.Serve(l, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
 
46
                srv.serveHTTP(w, req)
 
47
        }))
 
48
        return srv, nil
 
49
}
 
50
 
 
51
// Quit closes down the server.
 
52
func (srv *Server) Quit() error {
 
53
        return srv.listener.Close()
 
54
}
 
55
 
 
56
// URL returns a URL for the server.
 
57
func (srv *Server) URL() string {
 
58
        return srv.url
 
59
}
 
60
 
 
61
type xmlErrors struct {
 
62
        XMLName string `xml:"ErrorResponse"`
 
63
        Error   iam.Error
 
64
}
 
65
 
 
66
func (srv *Server) error(w http.ResponseWriter, err *iam.Error) {
 
67
        w.WriteHeader(err.StatusCode)
 
68
        xmlErr := xmlErrors{Error: *err}
 
69
        if e := xml.NewEncoder(w).Encode(xmlErr); e != nil {
 
70
                panic(e)
 
71
        }
 
72
}
 
73
 
 
74
func (srv *Server) serveHTTP(w http.ResponseWriter, req *http.Request) {
 
75
        req.ParseForm()
 
76
        srv.mutex.Lock()
 
77
        defer srv.mutex.Unlock()
 
78
        action := req.FormValue("Action")
 
79
        if action == "" {
 
80
                srv.error(w, &iam.Error{
 
81
                        StatusCode: 400,
 
82
                        Code:       "MissingAction",
 
83
                        Message:    "Missing action",
 
84
                })
 
85
        }
 
86
        if a, ok := actions[action]; ok {
 
87
                reqId := fmt.Sprintf("req%0X", srv.reqId)
 
88
                srv.reqId++
 
89
                if resp, err := a(srv, w, req, reqId); err == nil {
 
90
                        if err := xml.NewEncoder(w).Encode(resp); err != nil {
 
91
                                panic(err)
 
92
                        }
 
93
                } else {
 
94
                        switch err.(type) {
 
95
                        case *iam.Error:
 
96
                                srv.error(w, err.(*iam.Error))
 
97
                        default:
 
98
                                panic(err)
 
99
                        }
 
100
                }
 
101
        } else {
 
102
                srv.error(w, &iam.Error{
 
103
                        StatusCode: 400,
 
104
                        Code:       "InvalidAction",
 
105
                        Message:    "Invalid action: " + action,
 
106
                })
 
107
        }
 
108
}
 
109
 
 
110
func (srv *Server) createUser(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
 
111
        if err := srv.validate(req, []string{"UserName"}); err != nil {
 
112
                return nil, err
 
113
        }
 
114
        path := req.FormValue("Path")
 
115
        if path == "" {
 
116
                path = "/"
 
117
        }
 
118
        name := req.FormValue("UserName")
 
119
        for _, user := range srv.users {
 
120
                if user.Name == name {
 
121
                        return nil, &iam.Error{
 
122
                                StatusCode: 409,
 
123
                                Code:       "EntityAlreadyExists",
 
124
                                Message:    fmt.Sprintf("User with name %s already exists.", name),
 
125
                        }
 
126
                }
 
127
        }
 
128
        user := iam.User{
 
129
                Id:   "USER" + reqId + "EXAMPLE",
 
130
                Arn:  fmt.Sprintf("arn:aws:iam:::123456789012:user%s%s", path, name),
 
131
                Name: name,
 
132
                Path: path,
 
133
        }
 
134
        srv.users = append(srv.users, user)
 
135
        return iam.CreateUserResp{
 
136
                RequestId: reqId,
 
137
                User:      user,
 
138
        }, nil
 
139
}
 
140
 
 
141
func (srv *Server) getUser(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
 
142
        if err := srv.validate(req, []string{"UserName"}); err != nil {
 
143
                return nil, err
 
144
        }
 
145
        name := req.FormValue("UserName")
 
146
        index, err := srv.findUser(name)
 
147
        if err != nil {
 
148
                return nil, err
 
149
        }
 
150
        return iam.GetUserResp{RequestId: reqId, User: srv.users[index]}, nil
 
151
}
 
152
 
 
153
func (srv *Server) deleteUser(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
 
154
        if err := srv.validate(req, []string{"UserName"}); err != nil {
 
155
                return nil, err
 
156
        }
 
157
        name := req.FormValue("UserName")
 
158
        index, err := srv.findUser(name)
 
159
        if err != nil {
 
160
                return nil, err
 
161
        }
 
162
        copy(srv.users[index:], srv.users[index+1:])
 
163
        srv.users = srv.users[:len(srv.users)-1]
 
164
        return iam.SimpleResp{RequestId: reqId}, nil
 
165
}
 
166
 
 
167
func (srv *Server) createAccessKey(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
 
168
        if err := srv.validate(req, []string{"UserName"}); err != nil {
 
169
                return nil, err
 
170
        }
 
171
        userName := req.FormValue("UserName")
 
172
        if _, err := srv.findUser(userName); err != nil {
 
173
                return nil, err
 
174
        }
 
175
        key := iam.AccessKey{
 
176
                Id:       fmt.Sprintf("%s%d", userName, len(srv.accessKeys)),
 
177
                Secret:   "",
 
178
                UserName: userName,
 
179
                Status:   "Active",
 
180
        }
 
181
        srv.accessKeys = append(srv.accessKeys, key)
 
182
        return iam.CreateAccessKeyResp{RequestId: reqId, AccessKey: key}, nil
 
183
}
 
184
 
 
185
func (srv *Server) deleteAccessKey(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
 
186
        if err := srv.validate(req, []string{"AccessKeyId", "UserName"}); err != nil {
 
187
                return nil, err
 
188
        }
 
189
        key := req.FormValue("AccessKeyId")
 
190
        index := -1
 
191
        for i, ak := range srv.accessKeys {
 
192
                if ak.Id == key {
 
193
                        index = i
 
194
                        break
 
195
                }
 
196
        }
 
197
        if index < 0 {
 
198
                return nil, &iam.Error{
 
199
                        StatusCode: 404,
 
200
                        Code:       "NoSuchEntity",
 
201
                        Message:    "No such key.",
 
202
                }
 
203
        }
 
204
        copy(srv.accessKeys[index:], srv.accessKeys[index+1:])
 
205
        srv.accessKeys = srv.accessKeys[:len(srv.accessKeys)-1]
 
206
        return iam.SimpleResp{RequestId: reqId}, nil
 
207
}
 
208
 
 
209
func (srv *Server) listAccessKeys(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
 
210
        if err := srv.validate(req, []string{"UserName"}); err != nil {
 
211
                return nil, err
 
212
        }
 
213
        userName := req.FormValue("UserName")
 
214
        if _, err := srv.findUser(userName); err != nil {
 
215
                return nil, err
 
216
        }
 
217
        var keys []iam.AccessKey
 
218
        for _, k := range srv.accessKeys {
 
219
                if k.UserName == userName {
 
220
                        keys = append(keys, k)
 
221
                }
 
222
        }
 
223
        return iam.AccessKeysResp{
 
224
                RequestId:  reqId,
 
225
                AccessKeys: keys,
 
226
        }, nil
 
227
}
 
228
 
 
229
func (srv *Server) createGroup(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
 
230
        if err := srv.validate(req, []string{"GroupName"}); err != nil {
 
231
                return nil, err
 
232
        }
 
233
        name := req.FormValue("GroupName")
 
234
        path := req.FormValue("Path")
 
235
        for _, group := range srv.groups {
 
236
                if group.Name == name {
 
237
                        return nil, &iam.Error{
 
238
                                StatusCode: 409,
 
239
                                Code:       "EntityAlreadyExists",
 
240
                                Message:    fmt.Sprintf("Group with name %s already exists.", name),
 
241
                        }
 
242
                }
 
243
        }
 
244
        group := iam.Group{
 
245
                Id:   "GROUP " + reqId + "EXAMPLE",
 
246
                Arn:  fmt.Sprintf("arn:aws:iam:::123456789012:group%s%s", path, name),
 
247
                Name: name,
 
248
                Path: path,
 
249
        }
 
250
        srv.groups = append(srv.groups, group)
 
251
        return iam.CreateGroupResp{
 
252
                RequestId: reqId,
 
253
                Group:     group,
 
254
        }, nil
 
255
}
 
256
 
 
257
func (srv *Server) listGroups(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
 
258
        pathPrefix := req.FormValue("PathPrefix")
 
259
        if pathPrefix == "" {
 
260
                return iam.GroupsResp{
 
261
                        RequestId: reqId,
 
262
                        Groups:    srv.groups,
 
263
                }, nil
 
264
        }
 
265
        var groups []iam.Group
 
266
        for _, group := range srv.groups {
 
267
                if strings.HasPrefix(group.Path, pathPrefix) {
 
268
                        groups = append(groups, group)
 
269
                }
 
270
        }
 
271
        return iam.GroupsResp{
 
272
                RequestId: reqId,
 
273
                Groups:    groups,
 
274
        }, nil
 
275
}
 
276
 
 
277
func (srv *Server) deleteGroup(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
 
278
        if err := srv.validate(req, []string{"GroupName"}); err != nil {
 
279
                return nil, err
 
280
        }
 
281
        name := req.FormValue("GroupName")
 
282
        index := -1
 
283
        for i, group := range srv.groups {
 
284
                if group.Name == name {
 
285
                        index = i
 
286
                        break
 
287
                }
 
288
        }
 
289
        if index == -1 {
 
290
                return nil, &iam.Error{
 
291
                        StatusCode: 404,
 
292
                        Code:       "NoSuchEntity",
 
293
                        Message:    fmt.Sprintf("The group with name %s cannot be found.", name),
 
294
                }
 
295
        }
 
296
        copy(srv.groups[index:], srv.groups[index+1:])
 
297
        srv.groups = srv.groups[:len(srv.groups)-1]
 
298
        return iam.SimpleResp{RequestId: reqId}, nil
 
299
}
 
300
 
 
301
func (srv *Server) putUserPolicy(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
 
302
        if err := srv.validate(req, []string{"UserName", "PolicyDocument", "PolicyName"}); err != nil {
 
303
                return nil, err
 
304
        }
 
305
        var exists bool
 
306
        policyName := req.FormValue("PolicyName")
 
307
        userName := req.FormValue("UserName")
 
308
        for _, policy := range srv.userPolicies {
 
309
                if policyName == policy.Name && userName == policy.UserName {
 
310
                        exists = true
 
311
                        break
 
312
                }
 
313
        }
 
314
        if !exists {
 
315
                policy := iam.UserPolicy{
 
316
                        Name:     policyName,
 
317
                        UserName: userName,
 
318
                        Document: req.FormValue("PolicyDocument"),
 
319
                }
 
320
                var dumb interface{}
 
321
                if err := json.Unmarshal([]byte(policy.Document), &dumb); err != nil {
 
322
                        return nil, &iam.Error{
 
323
                                StatusCode: 400,
 
324
                                Code:       "MalformedPolicyDocument",
 
325
                                Message:    "Malformed policy document",
 
326
                        }
 
327
                }
 
328
                srv.userPolicies = append(srv.userPolicies, policy)
 
329
        }
 
330
        return iam.SimpleResp{RequestId: reqId}, nil
 
331
}
 
332
 
 
333
func (srv *Server) deleteUserPolicy(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
 
334
        if err := srv.validate(req, []string{"UserName", "PolicyName"}); err != nil {
 
335
                return nil, err
 
336
        }
 
337
        policyName := req.FormValue("PolicyName")
 
338
        userName := req.FormValue("UserName")
 
339
        index := -1
 
340
        for i, policy := range srv.userPolicies {
 
341
                if policyName == policy.Name && userName == policy.UserName {
 
342
                        index = i
 
343
                        break
 
344
                }
 
345
        }
 
346
        if index < 0 {
 
347
                return nil, &iam.Error{
 
348
                        StatusCode: 404,
 
349
                        Code:       "NoSuchEntity",
 
350
                        Message:    "No such user policy",
 
351
                }
 
352
        }
 
353
        copy(srv.userPolicies[index:], srv.userPolicies[index+1:])
 
354
        srv.userPolicies = srv.userPolicies[:len(srv.userPolicies)-1]
 
355
        return iam.SimpleResp{RequestId: reqId}, nil
 
356
}
 
357
 
 
358
func (srv *Server) getUserPolicy(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
 
359
        if err := srv.validate(req, []string{"UserName", "PolicyName"}); err != nil {
 
360
                return nil, err
 
361
        }
 
362
        policyName := req.FormValue("PolicyName")
 
363
        userName := req.FormValue("UserName")
 
364
        index := -1
 
365
        for i, policy := range srv.userPolicies {
 
366
                if policyName == policy.Name && userName == policy.UserName {
 
367
                        index = i
 
368
                        break
 
369
                }
 
370
        }
 
371
        if index < 0 {
 
372
                return nil, &iam.Error{
 
373
                        StatusCode: 404,
 
374
                        Code:       "NoSuchEntity",
 
375
                        Message:    "No such user policy",
 
376
                }
 
377
        }
 
378
        return iam.GetUserPolicyResp{
 
379
                Policy:    srv.userPolicies[index],
 
380
                RequestId: reqId,
 
381
        }, nil
 
382
}
 
383
 
 
384
func (srv *Server) findUser(userName string) (int, error) {
 
385
        var (
 
386
                err   error
 
387
                index = -1
 
388
        )
 
389
        for i, user := range srv.users {
 
390
                if user.Name == userName {
 
391
                        index = i
 
392
                        break
 
393
                }
 
394
        }
 
395
        if index < 0 {
 
396
                err = &iam.Error{
 
397
                        StatusCode: 404,
 
398
                        Code:       "NoSuchEntity",
 
399
                        Message:    fmt.Sprintf("The user with name %s cannot be found.", userName),
 
400
                }
 
401
        }
 
402
        return index, err
 
403
}
 
404
 
 
405
// Validates the presence of required request parameters.
 
406
func (srv *Server) validate(req *http.Request, required []string) error {
 
407
        for _, r := range required {
 
408
                if req.FormValue(r) == "" {
 
409
                        return &iam.Error{
 
410
                                StatusCode: 400,
 
411
                                Code:       "InvalidParameterCombination",
 
412
                                Message:    fmt.Sprintf("%s is required.", r),
 
413
                        }
 
414
                }
 
415
        }
 
416
        return nil
 
417
}
 
418
 
 
419
var actions = map[string]func(*Server, http.ResponseWriter, *http.Request, string) (interface{}, error){
 
420
        "CreateUser":       (*Server).createUser,
 
421
        "DeleteUser":       (*Server).deleteUser,
 
422
        "GetUser":          (*Server).getUser,
 
423
        "CreateAccessKey":  (*Server).createAccessKey,
 
424
        "DeleteAccessKey":  (*Server).deleteAccessKey,
 
425
        "ListAccessKeys":   (*Server).listAccessKeys,
 
426
        "PutUserPolicy":    (*Server).putUserPolicy,
 
427
        "DeleteUserPolicy": (*Server).deleteUserPolicy,
 
428
        "GetUserPolicy":    (*Server).getUserPolicy,
 
429
        "CreateGroup":      (*Server).createGroup,
 
430
        "DeleteGroup":      (*Server).deleteGroup,
 
431
        "ListGroups":       (*Server).listGroups,
 
432
}