feature/318_add_logs #319
10 changed files with 93 additions and 52 deletions
|
@ -94,12 +94,12 @@ func New(creds tokens.Credentials, prefixes []string) *Center {
|
||||||
func (c *Center) parseAuthHeader(header string) (*AuthHeader, error) {
|
func (c *Center) parseAuthHeader(header string) (*AuthHeader, error) {
|
||||||
submatches := c.reg.GetSubmatches(header)
|
submatches := c.reg.GetSubmatches(header)
|
||||||
if len(submatches) != authHeaderPartsNum {
|
if len(submatches) != authHeaderPartsNum {
|
||||||
return nil, apiErrors.GetAPIError(apiErrors.ErrAuthorizationHeaderMalformed)
|
return nil, fmt.Errorf("%w: %s", apiErrors.GetAPIError(apiErrors.ErrAuthorizationHeaderMalformed), header)
|
||||||
}
|
}
|
||||||
|
|
||||||
accessKey := strings.Split(submatches["access_key_id"], "0")
|
accessKey := strings.Split(submatches["access_key_id"], "0")
|
||||||
if len(accessKey) != accessKeyPartsNum {
|
if len(accessKey) != accessKeyPartsNum {
|
||||||
return nil, apiErrors.GetAPIError(apiErrors.ErrInvalidAccessKeyID)
|
return nil, fmt.Errorf("%w: %s", apiErrors.GetAPIError(apiErrors.ErrInvalidAccessKeyID), accessKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
signedFields := strings.Split(submatches["signed_header_fields"], ";")
|
signedFields := strings.Split(submatches["signed_header_fields"], ";")
|
||||||
|
@ -114,11 +114,12 @@ func (c *Center) parseAuthHeader(header string) (*AuthHeader, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AuthHeader) getAddress() (oid.Address, error) {
|
func getAddress(accessKeyID string) (oid.Address, error) {
|
||||||
var addr oid.Address
|
var addr oid.Address
|
||||||
if err := addr.DecodeString(strings.ReplaceAll(a.AccessKeyID, "0", "/")); err != nil {
|
if err := addr.DecodeString(strings.ReplaceAll(accessKeyID, "0", "/")); err != nil {
|
||||||
return addr, apiErrors.GetAPIError(apiErrors.ErrInvalidAccessKeyID)
|
return addr, fmt.Errorf("%w: %s", apiErrors.GetAPIError(apiErrors.ErrInvalidAccessKeyID), accessKeyID)
|
||||||
}
|
}
|
||||||
|
|
||||||
return addr, nil
|
return addr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +162,7 @@ func (c *Center) Authenticate(r *http.Request) (*middleware.Box, error) {
|
||||||
if strings.HasPrefix(r.Header.Get(ContentTypeHdr), "multipart/form-data") {
|
if strings.HasPrefix(r.Header.Get(ContentTypeHdr), "multipart/form-data") {
|
||||||
return c.checkFormData(r)
|
return c.checkFormData(r)
|
||||||
}
|
}
|
||||||
return nil, middleware.ErrNoAuthorizationHeader
|
return nil, fmt.Errorf("%w: %v", middleware.ErrNoAuthorizationHeader, authHeaderField)
|
||||||
}
|
}
|
||||||
authHdr, err = c.parseAuthHeader(authHeaderField[0])
|
authHdr, err = c.parseAuthHeader(authHeaderField[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -176,18 +177,18 @@ func (c *Center) Authenticate(r *http.Request) (*middleware.Box, error) {
|
||||||
return nil, fmt.Errorf("failed to parse x-amz-date header field: %w", err)
|
return nil, fmt.Errorf("failed to parse x-amz-date header field: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.checkAccessKeyID(authHdr.AccessKeyID); err != nil {
|
if err = c.checkAccessKeyID(authHdr.AccessKeyID); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
addr, err := authHdr.getAddress()
|
addr, err := getAddress(authHdr.AccessKeyID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
box, err := c.cli.GetBox(r.Context(), addr)
|
box, err := c.cli.GetBox(r.Context(), addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("get box: %w", err)
|
return nil, fmt.Errorf("get box '%s': %w", addr, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = checkFormatHashContentSHA256(r.Header.Get(AmzContentSHA256)); err != nil {
|
if err = checkFormatHashContentSHA256(r.Header.Get(AmzContentSHA256)); err != nil {
|
||||||
|
@ -218,10 +219,11 @@ func checkFormatHashContentSHA256(hash string) error {
|
||||||
if !IsStandardContentSHA256(hash) {
|
if !IsStandardContentSHA256(hash) {
|
||||||
hashBinary, err := hex.DecodeString(hash)
|
hashBinary, err := hex.DecodeString(hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return apiErrors.GetAPIError(apiErrors.ErrContentSHA256Mismatch)
|
return fmt.Errorf("%w: decode hash: %s: %s", apiErrors.GetAPIError(apiErrors.ErrContentSHA256Mismatch),
|
||||||
|
hash, err.Error())
|
||||||
}
|
}
|
||||||
if len(hashBinary) != sha256.Size && len(hash) != 0 {
|
if len(hashBinary) != sha256.Size && len(hash) != 0 {
|
||||||
return apiErrors.GetAPIError(apiErrors.ErrContentSHA256Mismatch)
|
return fmt.Errorf("%w: invalid hash size %d", apiErrors.GetAPIError(apiErrors.ErrContentSHA256Mismatch), len(hashBinary))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,12 +241,12 @@ func (c Center) checkAccessKeyID(accessKeyID string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return apiErrors.GetAPIError(apiErrors.ErrAccessDenied)
|
return fmt.Errorf("%w: accesskeyID prefix isn't allowed", apiErrors.GetAPIError(apiErrors.ErrAccessDenied))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Center) checkFormData(r *http.Request) (*middleware.Box, error) {
|
func (c *Center) checkFormData(r *http.Request) (*middleware.Box, error) {
|
||||||
if err := r.ParseMultipartForm(maxFormSizeMemory); err != nil {
|
if err := r.ParseMultipartForm(maxFormSizeMemory); err != nil {
|
||||||
return nil, apiErrors.GetAPIError(apiErrors.ErrInvalidArgument)
|
return nil, fmt.Errorf("%w: parse multipart form with max size %d", apiErrors.GetAPIError(apiErrors.ErrInvalidArgument), maxFormSizeMemory)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := prepareForm(r.MultipartForm); err != nil {
|
if err := prepareForm(r.MultipartForm); err != nil {
|
||||||
|
@ -253,12 +255,13 @@ func (c *Center) checkFormData(r *http.Request) (*middleware.Box, error) {
|
||||||
|
|
||||||
policy := MultipartFormValue(r, "policy")
|
policy := MultipartFormValue(r, "policy")
|
||||||
if policy == "" {
|
if policy == "" {
|
||||||
return nil, middleware.ErrNoAuthorizationHeader
|
return nil, fmt.Errorf("%w: missing policy", middleware.ErrNoAuthorizationHeader)
|
||||||
}
|
}
|
||||||
|
|
||||||
submatches := c.postReg.GetSubmatches(MultipartFormValue(r, "x-amz-credential"))
|
creds := MultipartFormValue(r, "x-amz-credential")
|
||||||
|
submatches := c.postReg.GetSubmatches(creds)
|
||||||
if len(submatches) != 4 {
|
if len(submatches) != 4 {
|
||||||
return nil, apiErrors.GetAPIError(apiErrors.ErrAuthorizationHeaderMalformed)
|
return nil, fmt.Errorf("%w: %s", apiErrors.GetAPIError(apiErrors.ErrAuthorizationHeaderMalformed), creds)
|
||||||
}
|
}
|
||||||
|
|
||||||
signatureDateTime, err := time.Parse("20060102T150405Z", MultipartFormValue(r, "x-amz-date"))
|
signatureDateTime, err := time.Parse("20060102T150405Z", MultipartFormValue(r, "x-amz-date"))
|
||||||
|
@ -266,22 +269,24 @@ func (c *Center) checkFormData(r *http.Request) (*middleware.Box, error) {
|
||||||
return nil, fmt.Errorf("failed to parse x-amz-date field: %w", err)
|
return nil, fmt.Errorf("failed to parse x-amz-date field: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var addr oid.Address
|
addr, err := getAddress(submatches["access_key_id"])
|
||||||
if err = addr.DecodeString(strings.ReplaceAll(submatches["access_key_id"], "0", "/")); err != nil {
|
if err != nil {
|
||||||
return nil, apiErrors.GetAPIError(apiErrors.ErrInvalidAccessKeyID)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
box, err := c.cli.GetBox(r.Context(), addr)
|
box, err := c.cli.GetBox(r.Context(), addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("get box: %w", err)
|
return nil, fmt.Errorf("get box '%s': %w", addr, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
secret := box.Gate.SecretKey
|
secret := box.Gate.SecretKey
|
||||||
service, region := submatches["service"], submatches["region"]
|
service, region := submatches["service"], submatches["region"]
|
||||||
|
|
||||||
signature := signStr(secret, service, region, signatureDateTime, policy)
|
signature := signStr(secret, service, region, signatureDateTime, policy)
|
||||||
if signature != MultipartFormValue(r, "x-amz-signature") {
|
reqSignature := MultipartFormValue(r, "x-amz-signature")
|
||||||
return nil, apiErrors.GetAPIError(apiErrors.ErrSignatureDoesNotMatch)
|
if signature != reqSignature {
|
||||||
|
return nil, fmt.Errorf("%w: %s != %s", apiErrors.GetAPIError(apiErrors.ErrSignatureDoesNotMatch),
|
||||||
|
reqSignature, signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &middleware.Box{AccessBox: box}, nil
|
return &middleware.Box{AccessBox: box}, nil
|
||||||
|
@ -317,10 +322,12 @@ func (c *Center) checkSign(authHeader *AuthHeader, box *accessbox.Box, request *
|
||||||
if authHeader.IsPresigned {
|
if authHeader.IsPresigned {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
if signatureDateTime.Add(authHeader.Expiration).Before(now) {
|
if signatureDateTime.Add(authHeader.Expiration).Before(now) {
|
||||||
return apiErrors.GetAPIError(apiErrors.ErrExpiredPresignRequest)
|
return fmt.Errorf("%w: expired: now %s, signature %s", apiErrors.GetAPIError(apiErrors.ErrExpiredPresignRequest),
|
||||||
|
now.Format(time.RFC3339), signatureDateTime.Format(time.RFC3339))
|
||||||
}
|
}
|
||||||
if now.Before(signatureDateTime) {
|
if now.Before(signatureDateTime) {
|
||||||
return apiErrors.GetAPIError(apiErrors.ErrBadRequest)
|
return fmt.Errorf("%w: signature time from the future: now %s, signature %s", apiErrors.GetAPIError(apiErrors.ErrBadRequest),
|
||||||
|
now.Format(time.RFC3339), signatureDateTime.Format(time.RFC3339))
|
||||||
}
|
}
|
||||||
if _, err := signer.Presign(request, nil, authHeader.Service, authHeader.Region, authHeader.Expiration, signatureDateTime); err != nil {
|
if _, err := signer.Presign(request, nil, authHeader.Service, authHeader.Region, authHeader.Expiration, signatureDateTime); err != nil {
|
||||||
return fmt.Errorf("failed to pre-sign temporary HTTP request: %w", err)
|
return fmt.Errorf("failed to pre-sign temporary HTTP request: %w", err)
|
||||||
|
@ -334,7 +341,8 @@ func (c *Center) checkSign(authHeader *AuthHeader, box *accessbox.Box, request *
|
||||||
}
|
}
|
||||||
|
|
||||||
if authHeader.SignatureV4 != signature {
|
if authHeader.SignatureV4 != signature {
|
||||||
return apiErrors.GetAPIError(apiErrors.ErrSignatureDoesNotMatch)
|
return fmt.Errorf("%w: %s != %s: headers %v", apiErrors.GetAPIError(apiErrors.ErrSignatureDoesNotMatch),
|
||||||
|
authHeader.SignatureV4, signature, authHeader.SignedFields)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -45,7 +45,7 @@ func TestAuthHeaderParse(t *testing.T) {
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
authHeader, err := center.parseAuthHeader(tc.header)
|
authHeader, err := center.parseAuthHeader(tc.header)
|
||||||
require.Equal(t, tc.err, err, tc.header)
|
require.ErrorIs(t, err, tc.err, tc.header)
|
||||||
require.Equal(t, tc.expected, authHeader, tc.header)
|
require.Equal(t, tc.expected, authHeader, tc.header)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,8 +82,8 @@ func TestAuthHeaderGetAddress(t *testing.T) {
|
||||||
err: defaulErr,
|
err: defaulErr,
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
_, err := tc.authHeader.getAddress()
|
_, err := getAddress(tc.authHeader.AccessKeyID)
|
||||||
require.Equal(t, tc.err, err, tc.authHeader.AccessKeyID)
|
require.ErrorIs(t, err, tc.err, tc.authHeader.AccessKeyID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,7 +141,7 @@ func TestCheckFormatContentSHA256(t *testing.T) {
|
||||||
} {
|
} {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
err := checkFormatHashContentSHA256(tc.hash)
|
err := checkFormatHashContentSHA256(tc.hash)
|
||||||
require.Equal(t, tc.error, err)
|
require.ErrorIs(t, err, tc.error)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
|
stderrors "errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
@ -628,11 +629,21 @@ func checkPostPolicy(r *http.Request, reqInfo *middleware.ReqInfo, metadata map[
|
||||||
policy.empty = false
|
policy.empty = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if r.MultipartForm == nil {
|
||||||
|
return nil, stderrors.New("empty multipart form")
|
||||||
|
}
|
||||||
|
|
||||||
for key, v := range r.MultipartForm.Value {
|
for key, v := range r.MultipartForm.Value {
|
||||||
value := v[0]
|
|
||||||
if key == "file" || key == "policy" || key == "x-amz-signature" || strings.HasPrefix(key, "x-ignore-") {
|
if key == "file" || key == "policy" || key == "x-amz-signature" || strings.HasPrefix(key, "x-ignore-") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(v) != 1 {
|
||||||
|
return nil, fmt.Errorf("empty multipart value for key '%s'", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
value := v[0]
|
||||||
|
|
||||||
if err := policy.CheckField(key, value); err != nil {
|
if err := policy.CheckField(key, value); err != nil {
|
||||||
return nil, fmt.Errorf("'%s' form field doesn't match the policy: %w", key, err)
|
return nil, fmt.Errorf("'%s' form field doesn't match the policy: %w", key, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,14 +2,15 @@ package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
stderrors "errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
|
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apiErrors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
|
||||||
|
frostfsErrors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/errors"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
@ -40,7 +41,7 @@ type (
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrNoAuthorizationHeader is returned for unauthenticated requests.
|
// ErrNoAuthorizationHeader is returned for unauthenticated requests.
|
||||||
var ErrNoAuthorizationHeader = stderrors.New("no authorization header")
|
var ErrNoAuthorizationHeader = errors.New("no authorization header")
|
||||||
|
|
||||||
func Auth(center Center, log *zap.Logger) Func {
|
func Auth(center Center, log *zap.Logger) Func {
|
||||||
return func(h http.Handler) http.Handler {
|
return func(h http.Handler) http.Handler {
|
||||||
|
@ -50,12 +51,13 @@ func Auth(center Center, log *zap.Logger) Func {
|
||||||
reqInfo.User = "anon"
|
reqInfo.User = "anon"
|
||||||
box, err := center.Authenticate(r)
|
box, err := center.Authenticate(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == ErrNoAuthorizationHeader {
|
if errors.Is(err, ErrNoAuthorizationHeader) {
|
||||||
reqLogOrDefault(ctx, log).Debug(logs.CouldntReceiveAccessBoxForGateKeyRandomKeyWillBeUsed)
|
reqLogOrDefault(ctx, log).Debug(logs.CouldntReceiveAccessBoxForGateKeyRandomKeyWillBeUsed, zap.Error(err))
|
||||||
} else {
|
} else {
|
||||||
reqLogOrDefault(ctx, log).Error(logs.FailedToPassAuthentication, zap.Error(err))
|
reqLogOrDefault(ctx, log).Error(logs.FailedToPassAuthentication, zap.Error(err))
|
||||||
if _, ok := err.(errors.Error); !ok {
|
err = frostfsErrors.UnwrapErr(err)
|
||||||
err = errors.GetAPIError(errors.ErrAccessDenied)
|
if _, ok := err.(apiErrors.Error); !ok {
|
||||||
|
err = apiErrors.GetAPIError(apiErrors.ErrAccessDenied)
|
||||||
}
|
}
|
||||||
WriteErrorResponse(w, GetReqInfo(r.Context()), err)
|
WriteErrorResponse(w, GetReqInfo(r.Context()), err)
|
||||||
return
|
return
|
||||||
|
@ -70,6 +72,7 @@ func Auth(center Center, log *zap.Logger) Func {
|
||||||
if box.AccessBox.Gate.BearerToken != nil {
|
if box.AccessBox.Gate.BearerToken != nil {
|
||||||
reqInfo.User = bearer.ResolveIssuer(*box.AccessBox.Gate.BearerToken).String()
|
reqInfo.User = bearer.ResolveIssuer(*box.AccessBox.Gate.BearerToken).String()
|
||||||
}
|
}
|
||||||
|
reqLogOrDefault(ctx, log).Debug(logs.SuccessfulAuth, zap.String("accessKeyID", box.AuthHeaders.AccessKeyID))
|
||||||
}
|
}
|
||||||
|
|
||||||
h.ServeHTTP(w, r.WithContext(ctx))
|
h.ServeHTTP(w, r.WithContext(ctx))
|
||||||
|
|
|
@ -54,7 +54,7 @@ func PolicyCheck(cfg PolicyConfig) Func {
|
||||||
|
|
||||||
func policyCheck(r *http.Request, cfg PolicyConfig) error {
|
func policyCheck(r *http.Request, cfg PolicyConfig) error {
|
||||||
reqType, bktName, objName := getBucketObject(r, cfg.Domains)
|
reqType, bktName, objName := getBucketObject(r, cfg.Domains)
|
||||||
req, err := getPolicyRequest(r, cfg.FrostfsID, reqType, bktName, objName)
|
req, err := getPolicyRequest(r, cfg.FrostfsID, reqType, bktName, objName, cfg.Log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,7 @@ func isAPEBehavior(ctx context.Context, req *testutil.Request, cfg PolicyConfig,
|
||||||
return bktInfo.APEEnabled, nil
|
return bktInfo.APEEnabled, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPolicyRequest(r *http.Request, frostfsid FrostFSIDInformer, reqType ReqType, bktName string, objName string) (*testutil.Request, error) {
|
func getPolicyRequest(r *http.Request, frostfsid FrostFSIDInformer, reqType ReqType, bktName string, objName string, log *zap.Logger) (*testutil.Request, error) {
|
||||||
var (
|
var (
|
||||||
owner string
|
owner string
|
||||||
groups []string
|
groups []string
|
||||||
|
@ -133,6 +133,9 @@ func getPolicyRequest(r *http.Request, frostfsid FrostFSIDInformer, reqType ReqT
|
||||||
res = fmt.Sprintf(s3.ResourceFormatS3Bucket, bktName)
|
res = fmt.Sprintf(s3.ResourceFormatS3Bucket, bktName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reqLogOrDefault(r.Context(), log).Debug(logs.PolicyRequest, zap.String("action", op),
|
||||||
|
zap.String("resource", res), zap.String("owner", owner))
|
||||||
|
|
||||||
return testutil.NewRequest(op, testutil.NewResource(res, nil),
|
return testutil.NewRequest(op, testutil.NewResource(res, nil),
|
||||||
map[string]string{
|
map[string]string{
|
||||||
s3.PropertyKeyOwner: owner,
|
s3.PropertyKeyOwner: owner,
|
||||||
|
@ -290,7 +293,7 @@ func determineBucketOperation(r *http.Request) string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ""
|
return "UnmatchedBucketOperation"
|
||||||
}
|
}
|
||||||
|
|
||||||
func determineObjectOperation(r *http.Request) string {
|
func determineObjectOperation(r *http.Request) string {
|
||||||
|
@ -354,12 +357,12 @@ func determineObjectOperation(r *http.Request) string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ""
|
return "UnmatchedObjectOperation"
|
||||||
}
|
}
|
||||||
|
|
||||||
func determineGeneralOperation(r *http.Request) string {
|
func determineGeneralOperation(r *http.Request) string {
|
||||||
if r.Method == http.MethodGet {
|
if r.Method == http.MethodGet {
|
||||||
return ListBucketsOperation
|
return ListBucketsOperation
|
||||||
}
|
}
|
||||||
return ""
|
return "UnmatchedOperation"
|
||||||
}
|
}
|
||||||
|
|
|
@ -222,7 +222,7 @@ func Request(log *zap.Logger, settings RequestSettings) Func {
|
||||||
r = r.WithContext(SetReqLogger(r.Context(), reqLogger))
|
r = r.WithContext(SetReqLogger(r.Context(), reqLogger))
|
||||||
|
|
||||||
reqLogger.Info(logs.RequestStart, zap.String("host", r.Host),
|
reqLogger.Info(logs.RequestStart, zap.String("host", r.Host),
|
||||||
zap.String("remote_host", reqInfo.RemoteHost))
|
zap.String("remote_host", reqInfo.RemoteHost), zap.String("namespace", reqInfo.Namespace))
|
||||||
|
|
||||||
// continue execution
|
// continue execution
|
||||||
h.ServeHTTP(w, r)
|
h.ServeHTTP(w, r)
|
||||||
|
@ -239,8 +239,10 @@ func AddBucketName(l *zap.Logger) Func {
|
||||||
reqInfo := GetReqInfo(ctx)
|
reqInfo := GetReqInfo(ctx)
|
||||||
reqInfo.BucketName = chi.URLParam(r, BucketURLPrm)
|
reqInfo.BucketName = chi.URLParam(r, BucketURLPrm)
|
||||||
|
|
||||||
|
if reqInfo.BucketName != "" {
|
||||||
reqLogger := reqLogOrDefault(ctx, l)
|
reqLogger := reqLogOrDefault(ctx, l)
|
||||||
r = r.WithContext(SetReqLogger(ctx, reqLogger.With(zap.String("bucket", reqInfo.BucketName))))
|
r = r.WithContext(SetReqLogger(ctx, reqLogger.With(zap.String("bucket", reqInfo.BucketName))))
|
||||||
|
}
|
||||||
|
|
||||||
h.ServeHTTP(w, r)
|
h.ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
|
@ -270,7 +272,9 @@ func AddObjectName(l *zap.Logger) Func {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if reqInfo.ObjectName != "" {
|
||||||
r = r.WithContext(SetReqLogger(ctx, reqLogger.With(zap.String("object", reqInfo.ObjectName))))
|
r = r.WithContext(SetReqLogger(ctx, reqLogger.With(zap.String("object", reqInfo.ObjectName))))
|
||||||
|
}
|
||||||
|
|
||||||
h.ServeHTTP(w, r)
|
h.ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
|
|
|
@ -312,12 +312,20 @@ func LogSuccessResponse(l *zap.Logger) Func {
|
||||||
reqLogger := reqLogOrDefault(ctx, l)
|
reqLogger := reqLogOrDefault(ctx, l)
|
||||||
reqInfo := GetReqInfo(ctx)
|
reqInfo := GetReqInfo(ctx)
|
||||||
|
|
||||||
fields := []zap.Field{
|
fields := make([]zap.Field, 0, 6)
|
||||||
zap.String("method", reqInfo.API),
|
fields = append(fields,
|
||||||
zap.String("bucket", reqInfo.BucketName),
|
|
||||||
zap.String("object", reqInfo.ObjectName),
|
|
||||||
zap.Int("status", lw.statusCode),
|
zap.Int("status", lw.statusCode),
|
||||||
zap.String("description", http.StatusText(lw.statusCode))}
|
zap.String("description", http.StatusText(lw.statusCode)),
|
||||||
|
zap.String("method", reqInfo.API),
|
||||||
|
)
|
||||||
|
|
||||||
|
if reqInfo.BucketName != "" {
|
||||||
|
fields = append(fields, zap.String("bucket", reqInfo.BucketName))
|
||||||
|
}
|
||||||
|
if reqInfo.ObjectName != "" {
|
||||||
|
fields = append(fields, zap.String("object", reqInfo.ObjectName))
|
||||||
|
}
|
||||||
|
|
||||||
if traceID, err := trace.TraceIDFromHex(reqInfo.TraceID); err == nil && traceID.IsValid() {
|
if traceID, err := trace.TraceIDFromHex(reqInfo.TraceID); err == nil && traceID.IsValid() {
|
||||||
fields = append(fields, zap.String("trace_id", reqInfo.TraceID))
|
fields = append(fields, zap.String("trace_id", reqInfo.TraceID))
|
||||||
}
|
}
|
||||||
|
|
|
@ -148,6 +148,7 @@ func NewRouter(cfg Config) *chi.Mux {
|
||||||
defaultRouter := chi.NewRouter()
|
defaultRouter := chi.NewRouter()
|
||||||
defaultRouter.Mount(fmt.Sprintf("/{%s}", s3middleware.BucketURLPrm), bucketRouter(cfg.Handler, cfg.Log))
|
defaultRouter.Mount(fmt.Sprintf("/{%s}", s3middleware.BucketURLPrm), bucketRouter(cfg.Handler, cfg.Log))
|
||||||
defaultRouter.Get("/", named("ListBuckets", cfg.Handler.ListBucketsHandler))
|
defaultRouter.Get("/", named("ListBuckets", cfg.Handler.ListBucketsHandler))
|
||||||
|
attachErrorHandler(defaultRouter)
|
||||||
|
|
||||||
hr := NewHostBucketRouter("bucket")
|
hr := NewHostBucketRouter("bucket")
|
||||||
hr.Default(defaultRouter)
|
hr.Default(defaultRouter)
|
||||||
|
@ -182,7 +183,7 @@ func errorResponseHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
})
|
})
|
||||||
|
|
||||||
if log := s3middleware.GetReqLog(ctx); log != nil {
|
if log := s3middleware.GetReqLog(ctx); log != nil {
|
||||||
log.Error(logs.RequestUnmatched, zap.String("method", reqInfo.API))
|
log.Error(logs.RequestUnmatched, zap.String("method", reqInfo.API), zap.String("http method", r.Method), zap.String("url", r.RequestURI))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ func (c *centerMock) Authenticate(*http.Request) (*middleware.Box, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return &middleware.Box{
|
return &middleware.Box{
|
||||||
|
AuthHeaders: &middleware.AuthHeader{},
|
||||||
AccessBox: &accessbox.Box{
|
AccessBox: &accessbox.Box{
|
||||||
Gate: &accessbox.GateData{
|
Gate: &accessbox.GateData{
|
||||||
BearerToken: token,
|
BearerToken: token,
|
||||||
|
|
|
@ -146,4 +146,6 @@ const (
|
||||||
BucketOwnerKeyIsMissing = "bucket owner key is missing"
|
BucketOwnerKeyIsMissing = "bucket owner key is missing"
|
||||||
SettingsNodeInvalidOwnerKey = "settings node: invalid owner key"
|
SettingsNodeInvalidOwnerKey = "settings node: invalid owner key"
|
||||||
FailedToSendTransaction = "failed to send transaction"
|
FailedToSendTransaction = "failed to send transaction"
|
||||||
|
SuccessfulAuth = "successful auth"
|
||||||
|
PolicyRequest = "policy request"
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue