From 9e3fce441e22ccd044bef1c1dec1d175e6d8ef19 Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Wed, 21 Nov 2018 20:03:24 -0800 Subject: [PATCH] Audit log claims from token (#6847) --- cmd/acl-handlers.go | 4 +- cmd/auth-handler.go | 86 ++++++++++++++++++----------- cmd/bucket-handlers-listobjects.go | 4 +- cmd/bucket-handlers.go | 16 +++--- cmd/bucket-notification-handlers.go | 6 +- cmd/bucket-policy-handlers.go | 6 +- cmd/logger/audit.go | 4 +- cmd/logger/message/audit/entry.go | 16 +++--- cmd/object-handlers.go | 24 ++++---- cmd/sts-handlers.go | 2 + cmd/web-handlers.go | 6 +- docs/logging/README.md | 40 ++++++++++---- 12 files changed, 128 insertions(+), 86 deletions(-) diff --git a/cmd/acl-handlers.go b/cmd/acl-handlers.go index da67f3676..2fad04ad0 100644 --- a/cmd/acl-handlers.go +++ b/cmd/acl-handlers.go @@ -57,7 +57,7 @@ type accessControlPolicy struct { func (api objectAPIHandlers) GetBucketACLHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "GetBucketACL") - defer logger.AuditLog(w, r, "GetBucketACL") + defer logger.AuditLog(w, r, "GetBucketACL", mustGetClaimsFromToken(r)) vars := mux.Vars(r) bucket := vars["bucket"] @@ -106,7 +106,7 @@ func (api objectAPIHandlers) GetBucketACLHandler(w http.ResponseWriter, r *http. func (api objectAPIHandlers) GetObjectACLHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "GetObjectACL") - defer logger.AuditLog(w, r, "GetObjectACL") + defer logger.AuditLog(w, r, "GetObjectACL", mustGetClaimsFromToken(r)) vars := mux.Vars(r) bucket := vars["bucket"] diff --git a/cmd/auth-handler.go b/cmd/auth-handler.go index 138b5471d..f9ccf2776 100644 --- a/cmd/auth-handler.go +++ b/cmd/auth-handler.go @@ -19,10 +19,10 @@ package cmd import ( "bytes" "context" + "crypto/subtle" "encoding/base64" "encoding/hex" "errors" - "fmt" "io" "io/ioutil" "net/http" @@ -155,32 +155,56 @@ func getSessionToken(r *http.Request) (token string) { return r.URL.Query().Get("X-Amz-Security-Token") } -// Fetch claims in the security token returned by the client and validate the token. -func getClaimsFromToken(r *http.Request, cred auth.Credentials) (map[string]interface{}, APIErrorCode) { +// Fetch claims in the security token returned by the client, doesn't return +// errors - upon errors the returned claims map will be empty. +func mustGetClaimsFromToken(r *http.Request) map[string]interface{} { + claims, _ := getClaimsFromToken(r) + return claims +} + +// Fetch claims in the security token returned by the client. +func getClaimsFromToken(r *http.Request) (map[string]interface{}, error) { + claims := make(map[string]interface{}) + token := getSessionToken(r) + if token == "" { + return claims, nil + } stsTokenCallback := func(jwtToken *jwtgo.Token) (interface{}, error) { - if _, ok := jwtToken.Method.(*jwtgo.SigningMethodHMAC); !ok { - return nil, fmt.Errorf("Unexpected signing method: %v", jwtToken.Header["alg"]) - } - if err := jwtToken.Claims.Valid(); err != nil { - return nil, errAuthentication - } - if claims, ok := jwtToken.Claims.(jwtgo.MapClaims); ok { - if _, ok = claims["accessKey"].(string); !ok { - return nil, errInvalidAccessKeyID - } - // JWT token for x-amz-security-token is signed with admin - // secret key, temporary credentials become invalid if - // server admin credentials change. This is done to ensure - // that clients cannot decode the token using the temp - // secret keys and generate an entirely new claim by essentially - // hijacking the policies. We need to make sure that this is - // based an admin credential such that token cannot be decoded - // on the client side and is treated like an opaque value. - return []byte(globalServerConfig.GetCredential().SecretKey), nil - } + // JWT token for x-amz-security-token is signed with admin + // secret key, temporary credentials become invalid if + // server admin credentials change. This is done to ensure + // that clients cannot decode the token using the temp + // secret keys and generate an entirely new claim by essentially + // hijacking the policies. We need to make sure that this is + // based an admin credential such that token cannot be decoded + // on the client side and is treated like an opaque value. + return []byte(globalServerConfig.GetCredential().SecretKey), nil + } + p := &jwtgo.Parser{ + ValidMethods: []string{ + jwtgo.SigningMethodHS256.Alg(), + jwtgo.SigningMethodHS512.Alg(), + }, + } + jtoken, err := p.ParseWithClaims(token, jwtgo.MapClaims(claims), stsTokenCallback) + if err != nil { + return nil, err + } + if !jtoken.Valid { return nil, errAuthentication } - claims := make(map[string]interface{}) + v, ok := claims["accessKey"] + if !ok { + return nil, errInvalidAccessKeyID + } + if _, ok = v.(string); !ok { + return nil, errInvalidAccessKeyID + } + return claims, nil +} + +// Fetch claims in the security token returned by the client and validate the token. +func checkClaimsFromToken(r *http.Request, cred auth.Credentials) (map[string]interface{}, APIErrorCode) { token := getSessionToken(r) if token == "" { return nil, ErrNone @@ -188,16 +212,12 @@ func getClaimsFromToken(r *http.Request, cred auth.Credentials) (map[string]inte if token != "" && cred.AccessKey == "" { return nil, ErrNoAccessKey } - if token != cred.SessionToken { + if subtle.ConstantTimeCompare([]byte(token), []byte(cred.SessionToken)) != 1 { return nil, ErrInvalidToken } - p := &jwtgo.Parser{} - jtoken, err := p.ParseWithClaims(token, jwtgo.MapClaims(claims), stsTokenCallback) + claims, err := getClaimsFromToken(r) if err != nil { - return nil, toAPIErrorCode(context.Background(), errAuthentication) - } - if !jtoken.Valid { - return nil, toAPIErrorCode(context.Background(), errAuthentication) + return nil, toAPIErrorCode(context.Background(), err) } return claims, ErrNone } @@ -256,7 +276,7 @@ func checkRequestAuthType(ctx context.Context, r *http.Request, action policy.Ac r.Body = ioutil.NopCloser(bytes.NewReader(payload)) } - claims, s3Err := getClaimsFromToken(r, cred) + claims, s3Err := checkClaimsFromToken(r, cred) if s3Err != ErrNone { return s3Err } @@ -421,7 +441,7 @@ func isPutAllowed(atype authType, bucketName, objectName string, r *http.Request return s3Err } - claims, s3Err := getClaimsFromToken(r, cred) + claims, s3Err := checkClaimsFromToken(r, cred) if s3Err != ErrNone { return s3Err } diff --git a/cmd/bucket-handlers-listobjects.go b/cmd/bucket-handlers-listobjects.go index 2edad2f58..2bf798ede 100644 --- a/cmd/bucket-handlers-listobjects.go +++ b/cmd/bucket-handlers-listobjects.go @@ -59,7 +59,7 @@ func validateListObjectsArgs(prefix, marker, delimiter string, maxKeys int) APIE func (api objectAPIHandlers) ListObjectsV2Handler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "ListObjectsV2") - defer logger.AuditLog(w, r, "ListObjectsV2") + defer logger.AuditLog(w, r, "ListObjectsV2", mustGetClaimsFromToken(r)) vars := mux.Vars(r) bucket := vars["bucket"] @@ -141,7 +141,7 @@ func (api objectAPIHandlers) ListObjectsV2Handler(w http.ResponseWriter, r *http func (api objectAPIHandlers) ListObjectsV1Handler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "ListObjectsV1") - defer logger.AuditLog(w, r, "ListObjectsV1") + defer logger.AuditLog(w, r, "ListObjectsV1", mustGetClaimsFromToken(r)) vars := mux.Vars(r) bucket := vars["bucket"] diff --git a/cmd/bucket-handlers.go b/cmd/bucket-handlers.go index 1abc0e58b..f4c67b3ec 100644 --- a/cmd/bucket-handlers.go +++ b/cmd/bucket-handlers.go @@ -89,7 +89,7 @@ func initFederatorBackend(objLayer ObjectLayer) { func (api objectAPIHandlers) GetBucketLocationHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "GetBucketLocation") - defer logger.AuditLog(w, r, "GetBucketLocation") + defer logger.AuditLog(w, r, "GetBucketLocation", mustGetClaimsFromToken(r)) vars := mux.Vars(r) bucket := vars["bucket"] @@ -139,7 +139,7 @@ func (api objectAPIHandlers) GetBucketLocationHandler(w http.ResponseWriter, r * func (api objectAPIHandlers) ListMultipartUploadsHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "ListMultipartUploads") - defer logger.AuditLog(w, r, "ListMultipartUploads") + defer logger.AuditLog(w, r, "ListMultipartUploads", mustGetClaimsFromToken(r)) vars := mux.Vars(r) bucket := vars["bucket"] @@ -192,7 +192,7 @@ func (api objectAPIHandlers) ListMultipartUploadsHandler(w http.ResponseWriter, func (api objectAPIHandlers) ListBucketsHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "ListBuckets") - defer logger.AuditLog(w, r, "ListBuckets") + defer logger.AuditLog(w, r, "ListBuckets", mustGetClaimsFromToken(r)) objectAPI := api.ObjectAPI() if objectAPI == nil { @@ -250,7 +250,7 @@ func (api objectAPIHandlers) ListBucketsHandler(w http.ResponseWriter, r *http.R func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "DeleteMultipleObjects") - defer logger.AuditLog(w, r, "DeleteMultipleObjects") + defer logger.AuditLog(w, r, "DeleteMultipleObjects", mustGetClaimsFromToken(r)) vars := mux.Vars(r) bucket := vars["bucket"] @@ -397,7 +397,7 @@ func (api objectAPIHandlers) DeleteMultipleObjectsHandler(w http.ResponseWriter, func (api objectAPIHandlers) PutBucketHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "PutBucket") - defer logger.AuditLog(w, r, "PutBucket") + defer logger.AuditLog(w, r, "PutBucket", mustGetClaimsFromToken(r)) objectAPI := api.ObjectAPI() if objectAPI == nil { @@ -475,7 +475,7 @@ func (api objectAPIHandlers) PutBucketHandler(w http.ResponseWriter, r *http.Req func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "PostPolicyBucket") - defer logger.AuditLog(w, r, "PostPolicyBucket") + defer logger.AuditLog(w, r, "PostPolicyBucket", mustGetClaimsFromToken(r)) objectAPI := api.ObjectAPI() if objectAPI == nil { @@ -703,7 +703,7 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h func (api objectAPIHandlers) HeadBucketHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "HeadBucket") - defer logger.AuditLog(w, r, "HeadBucket") + defer logger.AuditLog(w, r, "HeadBucket", mustGetClaimsFromToken(r)) vars := mux.Vars(r) bucket := vars["bucket"] @@ -735,7 +735,7 @@ func (api objectAPIHandlers) HeadBucketHandler(w http.ResponseWriter, r *http.Re func (api objectAPIHandlers) DeleteBucketHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "DeleteBucket") - defer logger.AuditLog(w, r, "DeleteBucket") + defer logger.AuditLog(w, r, "DeleteBucket", mustGetClaimsFromToken(r)) vars := mux.Vars(r) bucket := vars["bucket"] diff --git a/cmd/bucket-notification-handlers.go b/cmd/bucket-notification-handlers.go index eefd804ee..4e88146b8 100644 --- a/cmd/bucket-notification-handlers.go +++ b/cmd/bucket-notification-handlers.go @@ -44,7 +44,7 @@ var errNoSuchNotifications = errors.New("The specified bucket does not have buck func (api objectAPIHandlers) GetBucketNotificationHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "GetBucketNotification") - defer logger.AuditLog(w, r, "GetBucketNotification") + defer logger.AuditLog(w, r, "GetBucketNotification", mustGetClaimsFromToken(r)) vars := mux.Vars(r) bucketName := vars["bucket"] @@ -102,7 +102,7 @@ func (api objectAPIHandlers) GetBucketNotificationHandler(w http.ResponseWriter, func (api objectAPIHandlers) PutBucketNotificationHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "PutBucketNotification") - defer logger.AuditLog(w, r, "PutBucketNotification") + defer logger.AuditLog(w, r, "PutBucketNotification", mustGetClaimsFromToken(r)) objectAPI := api.ObjectAPI() if objectAPI == nil { @@ -164,7 +164,7 @@ func (api objectAPIHandlers) PutBucketNotificationHandler(w http.ResponseWriter, func (api objectAPIHandlers) ListenBucketNotificationHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "ListenBucketNotification") - defer logger.AuditLog(w, r, "ListenBucketNotification") + defer logger.AuditLog(w, r, "ListenBucketNotification", mustGetClaimsFromToken(r)) // Validate if bucket exists. objAPI := api.ObjectAPI() diff --git a/cmd/bucket-policy-handlers.go b/cmd/bucket-policy-handlers.go index 7bf1c605b..4a6c1af97 100644 --- a/cmd/bucket-policy-handlers.go +++ b/cmd/bucket-policy-handlers.go @@ -40,7 +40,7 @@ const ( func (api objectAPIHandlers) PutBucketPolicyHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "PutBucketPolicy") - defer logger.AuditLog(w, r, "PutBucketPolicy") + defer logger.AuditLog(w, r, "PutBucketPolicy", mustGetClaimsFromToken(r)) objAPI := api.ObjectAPI() if objAPI == nil { @@ -103,7 +103,7 @@ func (api objectAPIHandlers) PutBucketPolicyHandler(w http.ResponseWriter, r *ht func (api objectAPIHandlers) DeleteBucketPolicyHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "DeleteBucketPolicy") - defer logger.AuditLog(w, r, "DeleteBucketPolicy") + defer logger.AuditLog(w, r, "DeleteBucketPolicy", mustGetClaimsFromToken(r)) objAPI := api.ObjectAPI() if objAPI == nil { @@ -141,7 +141,7 @@ func (api objectAPIHandlers) DeleteBucketPolicyHandler(w http.ResponseWriter, r func (api objectAPIHandlers) GetBucketPolicyHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "GetBucketPolicy") - defer logger.AuditLog(w, r, "GetBucketPolicy") + defer logger.AuditLog(w, r, "GetBucketPolicy", mustGetClaimsFromToken(r)) objAPI := api.ObjectAPI() if objAPI == nil { diff --git a/cmd/logger/audit.go b/cmd/logger/audit.go index b74ee8c85..d8bd49208 100644 --- a/cmd/logger/audit.go +++ b/cmd/logger/audit.go @@ -55,7 +55,7 @@ func AddAuditTarget(t Target) { } // AuditLog - logs audit logs to all audit targets. -func AuditLog(w http.ResponseWriter, r *http.Request, api string) { +func AuditLog(w http.ResponseWriter, r *http.Request, api string, reqClaims map[string]interface{}) { var statusCode int lrw, ok := w.(*ResponseWriter) if ok { @@ -63,6 +63,6 @@ func AuditLog(w http.ResponseWriter, r *http.Request, api string) { } // Send audit logs only to http targets. for _, t := range AuditTargets { - t.Send(audit.ToEntry(w, r, api, statusCode)) + _ = t.Send(audit.ToEntry(w, r, api, statusCode, reqClaims)) } } diff --git a/cmd/logger/message/audit/entry.go b/cmd/logger/message/audit/entry.go index d3d57e80c..d3f2aa64f 100644 --- a/cmd/logger/message/audit/entry.go +++ b/cmd/logger/message/audit/entry.go @@ -40,16 +40,17 @@ type Entry struct { Status string `json:"status,omitempty"` StatusCode int `json:"statusCode,omitempty"` } `json:"api"` - RemoteHost string `json:"remotehost,omitempty"` - RequestID string `json:"requestID,omitempty"` - UserAgent string `json:"userAgent,omitempty"` - ReqQuery map[string]string `json:"requestQuery,omitempty"` - ReqHeader map[string]string `json:"requestHeader,omitempty"` - RespHeader map[string]string `json:"responseHeader,omitempty"` + RemoteHost string `json:"remotehost,omitempty"` + RequestID string `json:"requestID,omitempty"` + UserAgent string `json:"userAgent,omitempty"` + ReqClaims map[string]interface{} `json:"requestClaims,omitempty"` + ReqQuery map[string]string `json:"requestQuery,omitempty"` + ReqHeader map[string]string `json:"requestHeader,omitempty"` + RespHeader map[string]string `json:"responseHeader,omitempty"` } // ToEntry - constructs an audit entry object. -func ToEntry(w http.ResponseWriter, r *http.Request, api string, statusCode int) Entry { +func ToEntry(w http.ResponseWriter, r *http.Request, api string, statusCode int, reqClaims map[string]interface{}) Entry { vars := mux.Vars(r) bucket := vars["bucket"] object := vars["object"] @@ -77,6 +78,7 @@ func ToEntry(w http.ResponseWriter, r *http.Request, api string, statusCode int) Time: time.Now().UTC().Format(time.RFC3339Nano), ReqQuery: reqQuery, ReqHeader: reqHeader, + ReqClaims: reqClaims, RespHeader: respHeader, } diff --git a/cmd/object-handlers.go b/cmd/object-handlers.go index eba163d2c..54b7eb9c8 100644 --- a/cmd/object-handlers.go +++ b/cmd/object-handlers.go @@ -79,7 +79,7 @@ func setHeadGetRespHeaders(w http.ResponseWriter, reqParams url.Values) { func (api objectAPIHandlers) SelectObjectContentHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "SelectObject") - defer logger.AuditLog(w, r, "SelectObject") + defer logger.AuditLog(w, r, "SelectObject", mustGetClaimsFromToken(r)) // Fetch object stat info. objectAPI := api.ObjectAPI() @@ -305,7 +305,7 @@ func (api objectAPIHandlers) SelectObjectContentHandler(w http.ResponseWriter, r func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "GetObject") - defer logger.AuditLog(w, r, "GetObject") + defer logger.AuditLog(w, r, "GetObject", mustGetClaimsFromToken(r)) objectAPI := api.ObjectAPI() if objectAPI == nil { @@ -473,7 +473,7 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req func (api objectAPIHandlers) HeadObjectHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "HeadObject") - defer logger.AuditLog(w, r, "HeadObject") + defer logger.AuditLog(w, r, "HeadObject", mustGetClaimsFromToken(r)) objectAPI := api.ObjectAPI() if objectAPI == nil { @@ -656,7 +656,7 @@ func getCpObjMetadataFromHeader(ctx context.Context, r *http.Request, userMeta m func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "CopyObject") - defer logger.AuditLog(w, r, "CopyObject") + defer logger.AuditLog(w, r, "CopyObject", mustGetClaimsFromToken(r)) objectAPI := api.ObjectAPI() if objectAPI == nil { @@ -1028,7 +1028,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "PutObject") - defer logger.AuditLog(w, r, "PutObject") + defer logger.AuditLog(w, r, "PutObject", mustGetClaimsFromToken(r)) objectAPI := api.ObjectAPI() if objectAPI == nil { @@ -1291,7 +1291,7 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "NewMultipartUpload") - defer logger.AuditLog(w, r, "NewMultipartUpload") + defer logger.AuditLog(w, r, "NewMultipartUpload", mustGetClaimsFromToken(r)) objectAPI := api.ObjectAPI() if objectAPI == nil { @@ -1388,7 +1388,7 @@ func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "CopyObjectPart") - defer logger.AuditLog(w, r, "CopyObjectPart") + defer logger.AuditLog(w, r, "CopyObjectPart", mustGetClaimsFromToken(r)) objectAPI := api.ObjectAPI() if objectAPI == nil { @@ -1632,7 +1632,7 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "PutObjectPart") - defer logger.AuditLog(w, r, "PutObjectPart") + defer logger.AuditLog(w, r, "PutObjectPart", mustGetClaimsFromToken(r)) objectAPI := api.ObjectAPI() if objectAPI == nil { @@ -1883,7 +1883,7 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http func (api objectAPIHandlers) AbortMultipartUploadHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "AbortMultipartUpload") - defer logger.AuditLog(w, r, "AbortMultipartUpload") + defer logger.AuditLog(w, r, "AbortMultipartUpload", mustGetClaimsFromToken(r)) vars := mux.Vars(r) bucket := vars["bucket"] @@ -1929,7 +1929,7 @@ func (api objectAPIHandlers) AbortMultipartUploadHandler(w http.ResponseWriter, func (api objectAPIHandlers) ListObjectPartsHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "ListObjectParts") - defer logger.AuditLog(w, r, "ListObjectParts") + defer logger.AuditLog(w, r, "ListObjectParts", mustGetClaimsFromToken(r)) vars := mux.Vars(r) bucket := vars["bucket"] @@ -2008,7 +2008,7 @@ func (api objectAPIHandlers) ListObjectPartsHandler(w http.ResponseWriter, r *ht func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "CompleteMultipartUpload") - defer logger.AuditLog(w, r, "CompleteMultipartUpload") + defer logger.AuditLog(w, r, "CompleteMultipartUpload", mustGetClaimsFromToken(r)) vars := mux.Vars(r) bucket := vars["bucket"] @@ -2187,7 +2187,7 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite func (api objectAPIHandlers) DeleteObjectHandler(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "DeleteObject") - defer logger.AuditLog(w, r, "DeleteObject") + defer logger.AuditLog(w, r, "DeleteObject", mustGetClaimsFromToken(r)) vars := mux.Vars(r) bucket := vars["bucket"] diff --git a/cmd/sts-handlers.go b/cmd/sts-handlers.go index d6d1eb3e8..393a804b7 100644 --- a/cmd/sts-handlers.go +++ b/cmd/sts-handlers.go @@ -127,6 +127,8 @@ type ClientGrantsResult struct { func (sts *stsAPIHandlers) AssumeRoleWithClientGrants(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "AssumeRoleWithClientGrants") + defer logger.AuditLog(w, r, "AssumeRoleWithClientGrants", nil) + if globalIAMValidators == nil { writeSTSErrorResponse(w, ErrSTSNotInitialized) return diff --git a/cmd/web-handlers.go b/cmd/web-handlers.go index 8b0fc5381..0aec44ef2 100644 --- a/cmd/web-handlers.go +++ b/cmd/web-handlers.go @@ -707,7 +707,7 @@ func (web *webAPIHandlers) CreateURLToken(r *http.Request, args *WebGenericArgs, func (web *webAPIHandlers) Upload(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "WebUpload") - defer logger.AuditLog(w, r, "WebUpload") + defer logger.AuditLog(w, r, "WebUpload", mustGetClaimsFromToken(r)) objectAPI := web.ObjectAPI() if objectAPI == nil { @@ -845,7 +845,7 @@ func (web *webAPIHandlers) Upload(w http.ResponseWriter, r *http.Request) { func (web *webAPIHandlers) Download(w http.ResponseWriter, r *http.Request) { ctx := newContext(r, w, "WebDownload") - defer logger.AuditLog(w, r, "WebDownload") + defer logger.AuditLog(w, r, "WebDownload", mustGetClaimsFromToken(r)) var wg sync.WaitGroup objectAPI := web.ObjectAPI() @@ -1027,7 +1027,7 @@ func (web *webAPIHandlers) DownloadZip(w http.ResponseWriter, r *http.Request) { } ctx := newContext(r, w, "WebDownloadZip") - defer logger.AuditLog(w, r, "WebDownloadZip") + defer logger.AuditLog(w, r, "WebDownloadZip", mustGetClaimsFromToken(r)) var wg sync.WaitGroup objectAPI := web.ObjectAPI() diff --git a/docs/logging/README.md b/docs/logging/README.md index 05c91027d..3b8858fe8 100644 --- a/docs/logging/README.md +++ b/docs/logging/README.md @@ -77,27 +77,45 @@ Setting this environment variable automatically enables audit logging to the HTT { "version": "1", "deploymentid": "1b3002bf-5005-4d9b-853e-64a05008ebb2", - "time": "2018-11-02T21:57:58.231480177Z", + "time": "2018-11-21T23:16:06.828154172Z", "api": { - "name": "ListBuckets", - "args": {} + "name": "PutObject", + "bucket": "my-bucketname", + "object": "my-objectname", + "status": "OK", + "statusCode": 200 }, "remotehost": "127.0.0.1", - "requestID": "15636D7C53428FD4", - "userAgent": "Minio (linux; amd64) minio-go/v6.0.8 mc/2018-11-02T21:13:30Z", + "requestID": "156946C6C1E7842C", + "userAgent": "Minio (linux; amd64) minio-go/v6.0.6", + "requestClaims": { + "accessKey": "A1YABB5YPX3ZPL4227XJ", + "aud": "PoEgXP6uVO45IsENRngDXj5Au5Ya", + "azp": "PoEgXP6uVO45IsENRngDXj5Au5Ya", + "exp": 1542845766, + "iat": 1542842166, + "iss": "https://localhost:9443/oauth2/token", + "jti": "33527fcc-254f-43d2-a558-4942554b8ff8" + }, "requestHeader": { - "Authorization": "AWS4-HMAC-SHA256 Credential=minio/20181102/us-east-1/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=6db486b42a85b23bffba66d654ce60242a7e92fb27cd4a1756e68082c02cc204", - "User-Agent": "Minio (linux; amd64) minio-go/v6.0.8 mc/2018-11-02T21:13:30Z", - "X-Amz-Content-Sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - "X-Amz-Date": "20181102T215758Z" + "Authorization": "AWS4-HMAC-SHA256 Credential=A1YABB5YPX3ZPL4227XJ/20181121/us-east-1/s3/aws4_request,SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-decoded-content-length;x-amz-security-token,Signature=689d9b8f67b5625ea2f0b8cbb3f777d8839a91d50aa81e6a5555f5a6360c1714", + "Content-Length": "184", + "Content-Type": "application/octet-stream", + "User-Agent": "Minio (linux; amd64) minio-go/v6.0.6", + "X-Amz-Content-Sha256": "STREAMING-AWS4-HMAC-SHA256-PAYLOAD", + "X-Amz-Date": "20181121T231606Z", + "X-Amz-Decoded-Content-Length": "12", + "X-Amz-Security-Token": "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3NLZXkiOiJBMVlBQkI1WVBYM1pQTDQyMjdYSiIsImF1ZCI6IlBvRWdYUDZ1Vk80NUlzRU5SbmdEWGo1QXU1WWEiLCJhenAiOiJQb0VnWFA2dVZPNDVJc0VOUm5nRFhqNUF1NVlhIiwiZXhwIjoxNTQyODQ1NzY2LCJpYXQiOjE1NDI4NDIxNjYsImlzcyI6Imh0dHBzOi8vbG9jYWxob3N0Ojk0NDMvb2F1dGgyL3Rva2VuIiwianRpIjoiMzM1MjdmY2MtMjU0Zi00M2QyLWE1NTgtNDk0MjU1NGI4ZmY4In0.KEuAq2cQ3H7dfIB5DVuvcgBXT38mr0gthrIbVRSZcA2OWo8QiH1-DWXj9xYbndgr1p2tiEUsQ49cuszQGEVGMQ" }, "responseHeader": { "Accept-Ranges": "bytes", "Content-Security-Policy": "block-all-mixed-content", "Content-Type": "application/xml", - "Server": "Minio/DEVELOPMENT.2018-11-02T21-57-15Z (linux; amd64)", + "Etag": "", + "Server": "Minio/DEVELOPMENT.2018-11-21T23-15-06Z (linux; amd64)", "Vary": "Origin", - "X-Amz-Request-Id": "15636D7C53428FD4", + "X-Amz-Request-Id": "156946C6C1E7842C", + "X-Minio-Deployment-Id": "1b3002bf-5005-4d9b-853e-64a05008ebb2", "X-Xss-Protection": "1; mode=block" } }