mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2024-01-19 02:48:24 +00:00
add tests
This commit is contained in:
parent
8a95f9c10c
commit
ed79baa30f
|
@ -55,6 +55,7 @@ func writeIamErrorResponse(w http.ResponseWriter, err error, object string, valu
|
||||||
errorResp := ErrorResponse{}
|
errorResp := ErrorResponse{}
|
||||||
errorResp.Error.Type = "Sender"
|
errorResp.Error.Type = "Sender"
|
||||||
errorResp.Error.Code = &errCode
|
errorResp.Error.Code = &errCode
|
||||||
|
glog.Errorf("Response %+v", err)
|
||||||
switch errCode {
|
switch errCode {
|
||||||
case iam.ErrCodeNoSuchEntityException:
|
case iam.ErrCodeNoSuchEntityException:
|
||||||
msg := fmt.Sprintf("The %s with name %s cannot be found.", object, value)
|
msg := fmt.Sprintf("The %s with name %s cannot be found.", object, value)
|
||||||
|
|
|
@ -1,14 +1,10 @@
|
||||||
package iamapi
|
package iamapi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/chrislusf/seaweedfs/weed/filer"
|
|
||||||
"github.com/chrislusf/seaweedfs/weed/glog"
|
"github.com/chrislusf/seaweedfs/weed/glog"
|
||||||
"github.com/chrislusf/seaweedfs/weed/pb"
|
|
||||||
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
|
|
||||||
"github.com/chrislusf/seaweedfs/weed/pb/iam_pb"
|
"github.com/chrislusf/seaweedfs/weed/pb/iam_pb"
|
||||||
"github.com/chrislusf/seaweedfs/weed/s3api/s3_constants"
|
"github.com/chrislusf/seaweedfs/weed/s3api/s3_constants"
|
||||||
"github.com/chrislusf/seaweedfs/weed/s3api/s3err"
|
"github.com/chrislusf/seaweedfs/weed/s3api/s3err"
|
||||||
|
@ -16,6 +12,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/service/iam"
|
"github.com/aws/aws-sdk-go/service/iam"
|
||||||
|
@ -32,13 +29,15 @@ var (
|
||||||
policyDocuments = map[string]*PolicyDocument{}
|
policyDocuments = map[string]*PolicyDocument{}
|
||||||
)
|
)
|
||||||
|
|
||||||
type PolicyDocument struct {
|
type Statement struct {
|
||||||
Version string `json:"Version"`
|
|
||||||
Statement []struct {
|
|
||||||
Effect string `json:"Effect"`
|
Effect string `json:"Effect"`
|
||||||
Action []string `json:"Action"`
|
Action []string `json:"Action"`
|
||||||
Resource []string `json:"Resource"`
|
Resource []string `json:"Resource"`
|
||||||
} `json:"Statement"`
|
}
|
||||||
|
|
||||||
|
type PolicyDocument struct {
|
||||||
|
Version string `json:"Version"`
|
||||||
|
Statement []*Statement `json:"Statement"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func Hash(s *string) string {
|
func Hash(s *string) string {
|
||||||
|
@ -252,13 +251,16 @@ func (iama *IamApiServer) DoActions(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
values := r.PostForm
|
values := r.PostForm
|
||||||
|
var s3cfgLock sync.RWMutex
|
||||||
|
s3cfgLock.RLock()
|
||||||
s3cfg := &iam_pb.S3ApiConfiguration{}
|
s3cfg := &iam_pb.S3ApiConfiguration{}
|
||||||
if err := iama.GetS3ApiConfiguration(s3cfg); err != nil {
|
if err := iama.s3ApiConfig.GetS3ApiConfiguration(s3cfg); err != nil {
|
||||||
writeErrorResponse(w, s3err.ErrInternalError, r.URL)
|
writeErrorResponse(w, s3err.ErrInternalError, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
s3cfgLock.RUnlock()
|
||||||
|
|
||||||
glog.Info("values ", values)
|
glog.V(4).Infof("DoActions: %+v", values)
|
||||||
var response interface{}
|
var response interface{}
|
||||||
var err error
|
var err error
|
||||||
changed := true
|
changed := true
|
||||||
|
@ -292,12 +294,14 @@ func (iama *IamApiServer) DoActions(w http.ResponseWriter, r *http.Request) {
|
||||||
case "CreatePolicy":
|
case "CreatePolicy":
|
||||||
response, err = iama.CreatePolicy(s3cfg, values)
|
response, err = iama.CreatePolicy(s3cfg, values)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
glog.Errorf("CreatePolicy: %+v", err)
|
||||||
writeErrorResponse(w, s3err.ErrInvalidRequest, r.URL)
|
writeErrorResponse(w, s3err.ErrInvalidRequest, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case "PutUserPolicy":
|
case "PutUserPolicy":
|
||||||
response, err = iama.PutUserPolicy(s3cfg, values)
|
response, err = iama.PutUserPolicy(s3cfg, values)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
glog.Errorf("PutUserPolicy: %+v", err)
|
||||||
writeErrorResponse(w, s3err.ErrInvalidRequest, r.URL)
|
writeErrorResponse(w, s3err.ErrInvalidRequest, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -306,22 +310,9 @@ func (iama *IamApiServer) DoActions(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if changed {
|
if changed {
|
||||||
buf := bytes.Buffer{}
|
s3cfgLock.Lock()
|
||||||
if err := filer.S3ConfigurationToText(&buf, s3cfg); err != nil {
|
err := iama.s3ApiConfig.PutS3ApiConfiguration(s3cfg)
|
||||||
glog.Error("S3ConfigurationToText: ", err)
|
s3cfgLock.Unlock()
|
||||||
writeErrorResponse(w, s3err.ErrInternalError, r.URL)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err := pb.WithGrpcFilerClient(
|
|
||||||
iama.option.FilerGrpcAddress,
|
|
||||||
iama.option.GrpcDialOption,
|
|
||||||
func(client filer_pb.SeaweedFilerClient) error {
|
|
||||||
if err := filer.SaveInsideFiler(client, filer.IamConfigDirecotry, filer.IamIdentityFile, buf.Bytes()); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeErrorResponse(w, s3err.ErrInternalError, r.URL)
|
writeErrorResponse(w, s3err.ErrInternalError, r.URL)
|
||||||
return
|
return
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package iamapi
|
package iamapi
|
||||||
|
|
||||||
// https://docs.aws.amazon.com/cli/latest/reference/iam/list-roles.html
|
// https://docs.aws.amazon.com/cli/latest/reference/iam/list-roles.html
|
||||||
// https://docs.aws.amazon.com/IAM/latest/APIReference/API_CreateRole.html
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"github.com/chrislusf/seaweedfs/weed/filer"
|
"github.com/chrislusf/seaweedfs/weed/filer"
|
||||||
"github.com/chrislusf/seaweedfs/weed/pb"
|
"github.com/chrislusf/seaweedfs/weed/pb"
|
||||||
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
|
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
|
||||||
|
@ -16,6 +16,16 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type IamS3ApiConfig interface {
|
||||||
|
GetS3ApiConfiguration(s3cfg *iam_pb.S3ApiConfiguration) (err error)
|
||||||
|
PutS3ApiConfiguration(s3cfg *iam_pb.S3ApiConfiguration) (err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type IamS3ApiConfigure struct {
|
||||||
|
option *IamServerOption
|
||||||
|
masterClient *wdclient.MasterClient
|
||||||
|
}
|
||||||
|
|
||||||
type IamServerOption struct {
|
type IamServerOption struct {
|
||||||
Masters string
|
Masters string
|
||||||
Filer string
|
Filer string
|
||||||
|
@ -25,17 +35,22 @@ type IamServerOption struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type IamApiServer struct {
|
type IamApiServer struct {
|
||||||
option *IamServerOption
|
s3ApiConfig IamS3ApiConfig
|
||||||
masterClient *wdclient.MasterClient
|
|
||||||
filerclient *filer_pb.SeaweedFilerClient
|
filerclient *filer_pb.SeaweedFilerClient
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var s3ApiConfigure IamS3ApiConfig
|
||||||
|
|
||||||
func NewIamApiServer(router *mux.Router, option *IamServerOption) (iamApiServer *IamApiServer, err error) {
|
func NewIamApiServer(router *mux.Router, option *IamServerOption) (iamApiServer *IamApiServer, err error) {
|
||||||
iamApiServer = &IamApiServer{
|
s3ApiConfigure = IamS3ApiConfigure{
|
||||||
option: option,
|
option: option,
|
||||||
masterClient: wdclient.NewMasterClient(option.GrpcDialOption, pb.AdminShellClient, "", 0, "", strings.Split(option.Masters, ",")),
|
masterClient: wdclient.NewMasterClient(option.GrpcDialOption, pb.AdminShellClient, "", 0, "", strings.Split(option.Masters, ",")),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iamApiServer = &IamApiServer{
|
||||||
|
s3ApiConfig: s3ApiConfigure,
|
||||||
|
}
|
||||||
|
|
||||||
iamApiServer.registerRouter(router)
|
iamApiServer.registerRouter(router)
|
||||||
|
|
||||||
return iamApiServer, nil
|
return iamApiServer, nil
|
||||||
|
@ -52,10 +67,10 @@ func (iama *IamApiServer) registerRouter(router *mux.Router) {
|
||||||
apiRouter.NotFoundHandler = http.HandlerFunc(notFoundHandler)
|
apiRouter.NotFoundHandler = http.HandlerFunc(notFoundHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iama *IamApiServer) GetS3ApiConfiguration(s3cfg *iam_pb.S3ApiConfiguration) (err error) {
|
func (iam IamS3ApiConfigure) GetS3ApiConfiguration(s3cfg *iam_pb.S3ApiConfiguration) (err error) {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
err = pb.WithGrpcFilerClient(iama.option.FilerGrpcAddress, iama.option.GrpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
|
err = pb.WithGrpcFilerClient(iam.option.FilerGrpcAddress, iam.option.GrpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
|
||||||
if err = filer.ReadEntry(iama.masterClient, client, filer.IamConfigDirecotry, filer.IamIdentityFile, &buf); err != nil {
|
if err = filer.ReadEntry(iam.masterClient, client, filer.IamConfigDirecotry, filer.IamIdentityFile, &buf); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -70,3 +85,20 @@ func (iama *IamApiServer) GetS3ApiConfiguration(s3cfg *iam_pb.S3ApiConfiguration
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (iam IamS3ApiConfigure) PutS3ApiConfiguration(s3cfg *iam_pb.S3ApiConfiguration) (err error) {
|
||||||
|
buf := bytes.Buffer{}
|
||||||
|
if err := filer.S3ConfigurationToText(&buf, s3cfg); err != nil {
|
||||||
|
return fmt.Errorf("S3ConfigurationToText: %s", err)
|
||||||
|
}
|
||||||
|
return pb.WithGrpcFilerClient(
|
||||||
|
iam.option.FilerGrpcAddress,
|
||||||
|
iam.option.GrpcDialOption,
|
||||||
|
func(client filer_pb.SeaweedFilerClient) error {
|
||||||
|
if err := filer.SaveInsideFiler(client, filer.IamConfigDirecotry, filer.IamIdentityFile, buf.Bytes()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
157
weed/iamapi/iamapi_test.go
Normal file
157
weed/iamapi/iamapi_test.go
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
package iamapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/xml"
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/session"
|
||||||
|
"github.com/aws/aws-sdk-go/service/iam"
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/pb/iam_pb"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var S3config iam_pb.S3ApiConfiguration
|
||||||
|
var GetS3ApiConfiguration func(s3cfg *iam_pb.S3ApiConfiguration) (err error)
|
||||||
|
var PutS3ApiConfiguration func(s3cfg *iam_pb.S3ApiConfiguration) (err error)
|
||||||
|
|
||||||
|
type iamS3ApiConfigureMock struct{}
|
||||||
|
|
||||||
|
func (iam iamS3ApiConfigureMock) GetS3ApiConfiguration(s3cfg *iam_pb.S3ApiConfiguration) (err error) {
|
||||||
|
s3cfg = &S3config
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iam iamS3ApiConfigureMock) PutS3ApiConfiguration(s3cfg *iam_pb.S3ApiConfiguration) (err error) {
|
||||||
|
S3config = *s3cfg
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var a = IamApiServer{}
|
||||||
|
|
||||||
|
func TestCreateUser(t *testing.T) {
|
||||||
|
userName := aws.String("Test")
|
||||||
|
params := &iam.CreateUserInput{UserName: userName}
|
||||||
|
req, _ := iam.New(session.New()).CreateUserRequest(params)
|
||||||
|
_ = req.Build()
|
||||||
|
out := CreateUserResponse{}
|
||||||
|
response, err := executeRequest(req.HTTPRequest, out)
|
||||||
|
assert.Equal(t, nil, err)
|
||||||
|
assert.Equal(t, http.StatusOK, response.Code)
|
||||||
|
//assert.Equal(t, out.XMLName, "lol")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListUsers(t *testing.T) {
|
||||||
|
params := &iam.ListUsersInput{}
|
||||||
|
req, _ := iam.New(session.New()).ListUsersRequest(params)
|
||||||
|
_ = req.Build()
|
||||||
|
out := ListUsersResponse{}
|
||||||
|
response, err := executeRequest(req.HTTPRequest, out)
|
||||||
|
assert.Equal(t, nil, err)
|
||||||
|
assert.Equal(t, http.StatusOK, response.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListAccessKeys(t *testing.T) {
|
||||||
|
svc := iam.New(session.New())
|
||||||
|
params := &iam.ListAccessKeysInput{}
|
||||||
|
req, _ := svc.ListAccessKeysRequest(params)
|
||||||
|
_ = req.Build()
|
||||||
|
out := ListAccessKeysResponse{}
|
||||||
|
response, err := executeRequest(req.HTTPRequest, out)
|
||||||
|
assert.Equal(t, nil, err)
|
||||||
|
assert.Equal(t, http.StatusOK, response.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteUser(t *testing.T) {
|
||||||
|
userName := aws.String("Test")
|
||||||
|
params := &iam.DeleteUserInput{UserName: userName}
|
||||||
|
req, _ := iam.New(session.New()).DeleteUserRequest(params)
|
||||||
|
_ = req.Build()
|
||||||
|
out := DeleteUserResponse{}
|
||||||
|
response, err := executeRequest(req.HTTPRequest, out)
|
||||||
|
assert.Equal(t, nil, err)
|
||||||
|
assert.Equal(t, http.StatusNotFound, response.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetUser(t *testing.T) {
|
||||||
|
userName := aws.String("Test")
|
||||||
|
params := &iam.GetUserInput{UserName: userName}
|
||||||
|
req, _ := iam.New(session.New()).GetUserRequest(params)
|
||||||
|
_ = req.Build()
|
||||||
|
out := GetUserResponse{}
|
||||||
|
response, err := executeRequest(req.HTTPRequest, out)
|
||||||
|
assert.Equal(t, nil, err)
|
||||||
|
assert.Equal(t, http.StatusNotFound, response.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Todo flat statement
|
||||||
|
func TestCreatePolicy(t *testing.T) {
|
||||||
|
params := &iam.CreatePolicyInput{
|
||||||
|
PolicyName: aws.String("S3-read-only-example-bucket"),
|
||||||
|
PolicyDocument: aws.String(`
|
||||||
|
{
|
||||||
|
"Version": "2012-10-17",
|
||||||
|
"Statement": [
|
||||||
|
{
|
||||||
|
"Effect": "Allow",
|
||||||
|
"Action": [
|
||||||
|
"s3:Get*",
|
||||||
|
"s3:List*"
|
||||||
|
],
|
||||||
|
"Resource": [
|
||||||
|
"arn:aws:s3:::EXAMPLE-BUCKET",
|
||||||
|
"arn:aws:s3:::EXAMPLE-BUCKET/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`),
|
||||||
|
}
|
||||||
|
req, _ := iam.New(session.New()).CreatePolicyRequest(params)
|
||||||
|
_ = req.Build()
|
||||||
|
out := CreatePolicyResponse{}
|
||||||
|
response, err := executeRequest(req.HTTPRequest, out)
|
||||||
|
assert.Equal(t, nil, err)
|
||||||
|
assert.Equal(t, http.StatusOK, response.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPutUserPolicy(t *testing.T) {
|
||||||
|
userName := aws.String("Test")
|
||||||
|
params := &iam.PutUserPolicyInput{
|
||||||
|
UserName: userName,
|
||||||
|
PolicyName: aws.String("S3-read-only-example-bucket"),
|
||||||
|
PolicyDocument: aws.String(
|
||||||
|
`{
|
||||||
|
"Version": "2012-10-17",
|
||||||
|
"Statement": [
|
||||||
|
{
|
||||||
|
"Effect": "Allow",
|
||||||
|
"Action": [
|
||||||
|
"s3:Get*",
|
||||||
|
"s3:List*"
|
||||||
|
],
|
||||||
|
"Resource": [
|
||||||
|
"arn:aws:s3:::EXAMPLE-BUCKET",
|
||||||
|
"arn:aws:s3:::EXAMPLE-BUCKET/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`),
|
||||||
|
}
|
||||||
|
req, _ := iam.New(session.New()).PutUserPolicyRequest(params)
|
||||||
|
_ = req.Build()
|
||||||
|
out := PutUserPolicyResponse{}
|
||||||
|
response, err := executeRequest(req.HTTPRequest, out)
|
||||||
|
assert.Equal(t, nil, err)
|
||||||
|
assert.Equal(t, http.StatusOK, response.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func executeRequest(req *http.Request, v interface{}) (*httptest.ResponseRecorder, error) {
|
||||||
|
rr := httptest.NewRecorder()
|
||||||
|
apiRouter := mux.NewRouter().SkipClean(true)
|
||||||
|
a.s3ApiConfig = iamS3ApiConfigureMock{}
|
||||||
|
apiRouter.Path("/").Methods("POST").HandlerFunc(a.DoActions)
|
||||||
|
apiRouter.ServeHTTP(rr, req)
|
||||||
|
return rr, xml.Unmarshal(rr.Body.Bytes(), &v)
|
||||||
|
}
|
Loading…
Reference in a new issue