summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/goamz/goamz/iam/iamtest/server.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/goamz/goamz/iam/iamtest/server.go')
-rw-r--r--vendor/github.com/goamz/goamz/iam/iamtest/server.go432
1 files changed, 432 insertions, 0 deletions
diff --git a/vendor/github.com/goamz/goamz/iam/iamtest/server.go b/vendor/github.com/goamz/goamz/iam/iamtest/server.go
new file mode 100644
index 000000000..08991d2f8
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/iam/iamtest/server.go
@@ -0,0 +1,432 @@
+// Package iamtest implements a fake IAM provider with the capability of
+// inducing errors on any given operation, and retrospectively determining what
+// operations have been carried out.
+package iamtest
+
+import (
+ "encoding/json"
+ "encoding/xml"
+ "fmt"
+ "github.com/goamz/goamz/iam"
+ "net"
+ "net/http"
+ "strings"
+ "sync"
+)
+
+type action struct {
+ srv *Server
+ w http.ResponseWriter
+ req *http.Request
+ reqId string
+}
+
+// Server implements an IAM simulator for use in tests.
+type Server struct {
+ reqId int
+ url string
+ listener net.Listener
+ users []iam.User
+ groups []iam.Group
+ accessKeys []iam.AccessKey
+ userPolicies []iam.UserPolicy
+ mutex sync.Mutex
+}
+
+func NewServer() (*Server, error) {
+ l, err := net.Listen("tcp", "localhost:0")
+ if err != nil {
+ return nil, fmt.Errorf("cannot listen on localhost: %v", err)
+ }
+ srv := &Server{
+ listener: l,
+ url: "http://" + l.Addr().String(),
+ }
+ go http.Serve(l, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ srv.serveHTTP(w, req)
+ }))
+ return srv, nil
+}
+
+// Quit closes down the server.
+func (srv *Server) Quit() error {
+ return srv.listener.Close()
+}
+
+// URL returns a URL for the server.
+func (srv *Server) URL() string {
+ return srv.url
+}
+
+type xmlErrors struct {
+ XMLName string `xml:"ErrorResponse"`
+ Error iam.Error
+}
+
+func (srv *Server) error(w http.ResponseWriter, err *iam.Error) {
+ w.WriteHeader(err.StatusCode)
+ xmlErr := xmlErrors{Error: *err}
+ if e := xml.NewEncoder(w).Encode(xmlErr); e != nil {
+ panic(e)
+ }
+}
+
+func (srv *Server) serveHTTP(w http.ResponseWriter, req *http.Request) {
+ req.ParseForm()
+ srv.mutex.Lock()
+ defer srv.mutex.Unlock()
+ action := req.FormValue("Action")
+ if action == "" {
+ srv.error(w, &iam.Error{
+ StatusCode: 400,
+ Code: "MissingAction",
+ Message: "Missing action",
+ })
+ }
+ if a, ok := actions[action]; ok {
+ reqId := fmt.Sprintf("req%0X", srv.reqId)
+ srv.reqId++
+ if resp, err := a(srv, w, req, reqId); err == nil {
+ if err := xml.NewEncoder(w).Encode(resp); err != nil {
+ panic(err)
+ }
+ } else {
+ switch err.(type) {
+ case *iam.Error:
+ srv.error(w, err.(*iam.Error))
+ default:
+ panic(err)
+ }
+ }
+ } else {
+ srv.error(w, &iam.Error{
+ StatusCode: 400,
+ Code: "InvalidAction",
+ Message: "Invalid action: " + action,
+ })
+ }
+}
+
+func (srv *Server) createUser(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ if err := srv.validate(req, []string{"UserName"}); err != nil {
+ return nil, err
+ }
+ path := req.FormValue("Path")
+ if path == "" {
+ path = "/"
+ }
+ name := req.FormValue("UserName")
+ for _, user := range srv.users {
+ if user.Name == name {
+ return nil, &iam.Error{
+ StatusCode: 409,
+ Code: "EntityAlreadyExists",
+ Message: fmt.Sprintf("User with name %s already exists.", name),
+ }
+ }
+ }
+ user := iam.User{
+ Id: "USER" + reqId + "EXAMPLE",
+ Arn: fmt.Sprintf("arn:aws:iam:::123456789012:user%s%s", path, name),
+ Name: name,
+ Path: path,
+ }
+ srv.users = append(srv.users, user)
+ return iam.CreateUserResp{
+ RequestId: reqId,
+ User: user,
+ }, nil
+}
+
+func (srv *Server) getUser(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ if err := srv.validate(req, []string{"UserName"}); err != nil {
+ return nil, err
+ }
+ name := req.FormValue("UserName")
+ index, err := srv.findUser(name)
+ if err != nil {
+ return nil, err
+ }
+ return iam.GetUserResp{RequestId: reqId, User: srv.users[index]}, nil
+}
+
+func (srv *Server) deleteUser(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ if err := srv.validate(req, []string{"UserName"}); err != nil {
+ return nil, err
+ }
+ name := req.FormValue("UserName")
+ index, err := srv.findUser(name)
+ if err != nil {
+ return nil, err
+ }
+ copy(srv.users[index:], srv.users[index+1:])
+ srv.users = srv.users[:len(srv.users)-1]
+ return iam.SimpleResp{RequestId: reqId}, nil
+}
+
+func (srv *Server) createAccessKey(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ if err := srv.validate(req, []string{"UserName"}); err != nil {
+ return nil, err
+ }
+ userName := req.FormValue("UserName")
+ if _, err := srv.findUser(userName); err != nil {
+ return nil, err
+ }
+ key := iam.AccessKey{
+ Id: fmt.Sprintf("%s%d", userName, len(srv.accessKeys)),
+ Secret: "",
+ UserName: userName,
+ Status: "Active",
+ }
+ srv.accessKeys = append(srv.accessKeys, key)
+ return iam.CreateAccessKeyResp{RequestId: reqId, AccessKey: key}, nil
+}
+
+func (srv *Server) deleteAccessKey(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ if err := srv.validate(req, []string{"AccessKeyId", "UserName"}); err != nil {
+ return nil, err
+ }
+ key := req.FormValue("AccessKeyId")
+ index := -1
+ for i, ak := range srv.accessKeys {
+ if ak.Id == key {
+ index = i
+ break
+ }
+ }
+ if index < 0 {
+ return nil, &iam.Error{
+ StatusCode: 404,
+ Code: "NoSuchEntity",
+ Message: "No such key.",
+ }
+ }
+ copy(srv.accessKeys[index:], srv.accessKeys[index+1:])
+ srv.accessKeys = srv.accessKeys[:len(srv.accessKeys)-1]
+ return iam.SimpleResp{RequestId: reqId}, nil
+}
+
+func (srv *Server) listAccessKeys(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ if err := srv.validate(req, []string{"UserName"}); err != nil {
+ return nil, err
+ }
+ userName := req.FormValue("UserName")
+ if _, err := srv.findUser(userName); err != nil {
+ return nil, err
+ }
+ var keys []iam.AccessKey
+ for _, k := range srv.accessKeys {
+ if k.UserName == userName {
+ keys = append(keys, k)
+ }
+ }
+ return iam.AccessKeysResp{
+ RequestId: reqId,
+ AccessKeys: keys,
+ }, nil
+}
+
+func (srv *Server) createGroup(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ if err := srv.validate(req, []string{"GroupName"}); err != nil {
+ return nil, err
+ }
+ name := req.FormValue("GroupName")
+ path := req.FormValue("Path")
+ for _, group := range srv.groups {
+ if group.Name == name {
+ return nil, &iam.Error{
+ StatusCode: 409,
+ Code: "EntityAlreadyExists",
+ Message: fmt.Sprintf("Group with name %s already exists.", name),
+ }
+ }
+ }
+ group := iam.Group{
+ Id: "GROUP " + reqId + "EXAMPLE",
+ Arn: fmt.Sprintf("arn:aws:iam:::123456789012:group%s%s", path, name),
+ Name: name,
+ Path: path,
+ }
+ srv.groups = append(srv.groups, group)
+ return iam.CreateGroupResp{
+ RequestId: reqId,
+ Group: group,
+ }, nil
+}
+
+func (srv *Server) listGroups(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ pathPrefix := req.FormValue("PathPrefix")
+ if pathPrefix == "" {
+ return iam.GroupsResp{
+ RequestId: reqId,
+ Groups: srv.groups,
+ }, nil
+ }
+ var groups []iam.Group
+ for _, group := range srv.groups {
+ if strings.HasPrefix(group.Path, pathPrefix) {
+ groups = append(groups, group)
+ }
+ }
+ return iam.GroupsResp{
+ RequestId: reqId,
+ Groups: groups,
+ }, nil
+}
+
+func (srv *Server) deleteGroup(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ if err := srv.validate(req, []string{"GroupName"}); err != nil {
+ return nil, err
+ }
+ name := req.FormValue("GroupName")
+ index := -1
+ for i, group := range srv.groups {
+ if group.Name == name {
+ index = i
+ break
+ }
+ }
+ if index == -1 {
+ return nil, &iam.Error{
+ StatusCode: 404,
+ Code: "NoSuchEntity",
+ Message: fmt.Sprintf("The group with name %s cannot be found.", name),
+ }
+ }
+ copy(srv.groups[index:], srv.groups[index+1:])
+ srv.groups = srv.groups[:len(srv.groups)-1]
+ return iam.SimpleResp{RequestId: reqId}, nil
+}
+
+func (srv *Server) putUserPolicy(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ if err := srv.validate(req, []string{"UserName", "PolicyDocument", "PolicyName"}); err != nil {
+ return nil, err
+ }
+ var exists bool
+ policyName := req.FormValue("PolicyName")
+ userName := req.FormValue("UserName")
+ for _, policy := range srv.userPolicies {
+ if policyName == policy.Name && userName == policy.UserName {
+ exists = true
+ break
+ }
+ }
+ if !exists {
+ policy := iam.UserPolicy{
+ Name: policyName,
+ UserName: userName,
+ Document: req.FormValue("PolicyDocument"),
+ }
+ var dumb interface{}
+ if err := json.Unmarshal([]byte(policy.Document), &dumb); err != nil {
+ return nil, &iam.Error{
+ StatusCode: 400,
+ Code: "MalformedPolicyDocument",
+ Message: "Malformed policy document",
+ }
+ }
+ srv.userPolicies = append(srv.userPolicies, policy)
+ }
+ return iam.SimpleResp{RequestId: reqId}, nil
+}
+
+func (srv *Server) deleteUserPolicy(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ if err := srv.validate(req, []string{"UserName", "PolicyName"}); err != nil {
+ return nil, err
+ }
+ policyName := req.FormValue("PolicyName")
+ userName := req.FormValue("UserName")
+ index := -1
+ for i, policy := range srv.userPolicies {
+ if policyName == policy.Name && userName == policy.UserName {
+ index = i
+ break
+ }
+ }
+ if index < 0 {
+ return nil, &iam.Error{
+ StatusCode: 404,
+ Code: "NoSuchEntity",
+ Message: "No such user policy",
+ }
+ }
+ copy(srv.userPolicies[index:], srv.userPolicies[index+1:])
+ srv.userPolicies = srv.userPolicies[:len(srv.userPolicies)-1]
+ return iam.SimpleResp{RequestId: reqId}, nil
+}
+
+func (srv *Server) getUserPolicy(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ if err := srv.validate(req, []string{"UserName", "PolicyName"}); err != nil {
+ return nil, err
+ }
+ policyName := req.FormValue("PolicyName")
+ userName := req.FormValue("UserName")
+ index := -1
+ for i, policy := range srv.userPolicies {
+ if policyName == policy.Name && userName == policy.UserName {
+ index = i
+ break
+ }
+ }
+ if index < 0 {
+ return nil, &iam.Error{
+ StatusCode: 404,
+ Code: "NoSuchEntity",
+ Message: "No such user policy",
+ }
+ }
+ return iam.GetUserPolicyResp{
+ Policy: srv.userPolicies[index],
+ RequestId: reqId,
+ }, nil
+}
+
+func (srv *Server) findUser(userName string) (int, error) {
+ var (
+ err error
+ index = -1
+ )
+ for i, user := range srv.users {
+ if user.Name == userName {
+ index = i
+ break
+ }
+ }
+ if index < 0 {
+ err = &iam.Error{
+ StatusCode: 404,
+ Code: "NoSuchEntity",
+ Message: fmt.Sprintf("The user with name %s cannot be found.", userName),
+ }
+ }
+ return index, err
+}
+
+// Validates the presence of required request parameters.
+func (srv *Server) validate(req *http.Request, required []string) error {
+ for _, r := range required {
+ if req.FormValue(r) == "" {
+ return &iam.Error{
+ StatusCode: 400,
+ Code: "InvalidParameterCombination",
+ Message: fmt.Sprintf("%s is required.", r),
+ }
+ }
+ }
+ return nil
+}
+
+var actions = map[string]func(*Server, http.ResponseWriter, *http.Request, string) (interface{}, error){
+ "CreateUser": (*Server).createUser,
+ "DeleteUser": (*Server).deleteUser,
+ "GetUser": (*Server).getUser,
+ "CreateAccessKey": (*Server).createAccessKey,
+ "DeleteAccessKey": (*Server).deleteAccessKey,
+ "ListAccessKeys": (*Server).listAccessKeys,
+ "PutUserPolicy": (*Server).putUserPolicy,
+ "DeleteUserPolicy": (*Server).deleteUserPolicy,
+ "GetUserPolicy": (*Server).getUserPolicy,
+ "CreateGroup": (*Server).createGroup,
+ "DeleteGroup": (*Server).deleteGroup,
+ "ListGroups": (*Server).listGroups,
+}