init Iam Api Server

This commit is contained in:
Konstantin Lebedev
2020-12-09 17:11:49 +05:00
parent c276117fef
commit 03c7953254
5 changed files with 320 additions and 0 deletions

View File

@@ -0,0 +1,81 @@
package iamapi
import (
"bytes"
"encoding/xml"
"fmt"
"strconv"
"net/http"
"net/url"
"time"
"github.com/chrislusf/seaweedfs/weed/glog"
"github.com/chrislusf/seaweedfs/weed/s3api/s3err"
)
type mimeType string
const (
mimeNone mimeType = ""
mimeXML mimeType = "application/xml"
)
func setCommonHeaders(w http.ResponseWriter) {
w.Header().Set("x-amz-request-id", fmt.Sprintf("%d", time.Now().UnixNano()))
w.Header().Set("Accept-Ranges", "bytes")
}
// Encodes the response headers into XML format.
func encodeResponse(response interface{}) []byte {
var bytesBuffer bytes.Buffer
bytesBuffer.WriteString(xml.Header)
e := xml.NewEncoder(&bytesBuffer)
e.Encode(response)
return bytesBuffer.Bytes()
}
// If none of the http routes match respond with MethodNotAllowed
func notFoundHandler(w http.ResponseWriter, r *http.Request) {
glog.V(0).Infof("unsupported %s %s", r.Method, r.RequestURI)
writeErrorResponse(w, s3err.ErrMethodNotAllowed, r.URL)
}
func writeErrorResponse(w http.ResponseWriter, errorCode s3err.ErrorCode, reqURL *url.URL) {
apiError := s3err.GetAPIError(errorCode)
errorResponse := getRESTErrorResponse(apiError, reqURL.Path)
encodedErrorResponse := encodeResponse(errorResponse)
writeResponse(w, apiError.HTTPStatusCode, encodedErrorResponse, mimeXML)
}
func getRESTErrorResponse(err s3err.APIError, resource string) s3err.RESTErrorResponse {
return s3err.RESTErrorResponse{
Code: err.Code,
Message: err.Description,
Resource: resource,
RequestID: fmt.Sprintf("%d", time.Now().UnixNano()),
}
}
func writeResponse(w http.ResponseWriter, statusCode int, response []byte, mType mimeType) {
setCommonHeaders(w)
if response != nil {
w.Header().Set("Content-Length", strconv.Itoa(len(response)))
}
if mType != mimeNone {
w.Header().Set("Content-Type", string(mType))
}
w.WriteHeader(statusCode)
if response != nil {
glog.V(4).Infof("status %d %s: %s", statusCode, mType, string(response))
_, err := w.Write(response)
if err != nil {
glog.V(0).Infof("write err: %v", err)
}
w.(http.Flusher).Flush()
}
}
func writeSuccessResponseXML(w http.ResponseWriter, response []byte) {
writeResponse(w, http.StatusOK, response, mimeXML)
}

View File

@@ -0,0 +1,69 @@
package iamapi
import (
"encoding/xml"
"github.com/chrislusf/seaweedfs/weed/glog"
"github.com/chrislusf/seaweedfs/weed/pb/iam_pb"
"github.com/chrislusf/seaweedfs/weed/s3api/s3err"
"net/http"
"net/url"
// "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/iam"
)
const (
version = "2010-05-08"
)
type ListUsersResponse struct {
XMLName xml.Name `xml:"https://iam.amazonaws.com/doc/2010-05-08/ ListUsersResponse"`
ListUsersResult struct {
Users []*iam.User `xml:"Users>member"`
IsTruncated bool `xml:"IsTruncated"`
} `xml:"ListUsersResult"`
ResponseMetadata struct {
RequestId string `xml:"RequestId"`
} `xml:"ResponseMetadata"`
}
// {'Action': 'CreateUser', 'Version': '2010-05-08', 'UserName': 'Bob'}
// {'Action': 'ListUsers', 'Version': '2010-05-08'}
func (iama *IamApiServer) ListUsers(s3cfg *iam_pb.S3ApiConfiguration, values url.Values) ListUsersResponse {
glog.Info("Do ListUsers")
resp := ListUsersResponse{}
for _, ident := range s3cfg.Identities {
resp.ListUsersResult.Users = append(resp.ListUsersResult.Users, &iam.User{UserName: &ident.Name})
}
return resp
}
func (iama *IamApiServer) ListAccessKeys(values url.Values) ListUsersResponse {
return ListUsersResponse{}
}
func (iama *IamApiServer) DoActions(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
writeErrorResponse(w, s3err.ErrInvalidRequest, r.URL)
return
}
values := r.PostForm
s3cfg := &iam_pb.S3ApiConfiguration{}
if err := iama.GetS3ApiConfiguration(s3cfg); err != nil {
writeErrorResponse(w, s3err.ErrInternalError, r.URL)
return
}
glog.Info("values ", values)
var response interface{}
switch r.Form.Get("Action") {
case "ListUsers":
response = iama.ListUsers(s3cfg, values)
case "ListAccessKeys":
response = iama.ListAccessKeys(values)
default:
writeErrorResponse(w, s3err.ErrNotImplemented, r.URL)
return
}
writeSuccessResponseXML(w, encodeResponse(response))
}

View File

@@ -0,0 +1,72 @@
package iamapi
// https://docs.aws.amazon.com/cli/latest/reference/iam/list-roles.html
// https://docs.aws.amazon.com/IAM/latest/APIReference/API_CreateRole.html
import (
"bytes"
"github.com/chrislusf/seaweedfs/weed/filer"
"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/wdclient"
"github.com/gorilla/mux"
"google.golang.org/grpc"
"net/http"
"strings"
)
type IamServerOption struct {
Masters string
Filer string
Port int
FilerGrpcAddress string
GrpcDialOption grpc.DialOption
}
type IamApiServer struct {
option *IamServerOption
masterClient *wdclient.MasterClient
filerclient *filer_pb.SeaweedFilerClient
}
func NewIamApiServer(router *mux.Router, option *IamServerOption) (iamApiServer *IamApiServer, err error) {
iamApiServer = &IamApiServer{
option: option,
masterClient: wdclient.NewMasterClient(option.GrpcDialOption, pb.AdminShellClient, "", 0, "", strings.Split(option.Masters, ",")),
}
iamApiServer.registerRouter(router)
return iamApiServer, nil
}
func (iama *IamApiServer) registerRouter(router *mux.Router) {
// API Router
apiRouter := router.PathPrefix("/").Subrouter()
// ListBuckets
// apiRouter.Methods("GET").Path("/").HandlerFunc(track(s3a.iam.Auth(s3a.ListBucketsHandler, ACTION_ADMIN), "LIST"))
apiRouter.Path("/").Methods("POST").HandlerFunc(iama.DoActions)
// NotFound
apiRouter.NotFoundHandler = http.HandlerFunc(notFoundHandler)
}
func (iama *IamApiServer) GetS3ApiConfiguration(s3cfg *iam_pb.S3ApiConfiguration) (err error) {
var buf bytes.Buffer
err = pb.WithGrpcFilerClient(iama.option.FilerGrpcAddress, iama.option.GrpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
if err = filer.ReadEntry(iama.masterClient, client, filer.IamConfigDirecotry, filer.IamIdentityFile, &buf); err != nil {
return err
}
return nil
})
if err != nil {
return err
}
if buf.Len() > 0 {
if err = filer.ParseS3ConfigurationFromBytes(buf.Bytes(), s3cfg); err != nil {
return err
}
}
return nil
}