mirror of
https://github.com/minio/minio.git
synced 2024-12-25 06:35:56 -05:00
signV4: Move pkg/signature to pkg/s3/signature4
Cleanup and move this to relevant path.
This commit is contained in:
parent
d3966d1dde
commit
653ceee9ee
@ -16,13 +16,88 @@
|
|||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "net/http"
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/minio/minio/pkg/s3/signature4"
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
signV4Algorithm = "AWS4-HMAC-SHA256"
|
signV4Algorithm = "AWS4-HMAC-SHA256"
|
||||||
jwtAlgorithm = "Bearer"
|
jwtAlgorithm = "Bearer"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Verify if request has JWT.
|
||||||
|
func isRequestJWT(r *http.Request) bool {
|
||||||
|
if _, ok := r.Header["Authorization"]; ok {
|
||||||
|
if strings.HasPrefix(r.Header.Get("Authorization"), jwtAlgorithm) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify if request has AWS Signature Version '4'.
|
||||||
|
func isRequestSignatureV4(r *http.Request) bool {
|
||||||
|
if _, ok := r.Header["Authorization"]; ok {
|
||||||
|
if strings.HasPrefix(r.Header.Get("Authorization"), signV4Algorithm) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify if request has AWS Presignature Version '4'.
|
||||||
|
func isRequestPresignedSignatureV4(r *http.Request) bool {
|
||||||
|
if _, ok := r.URL.Query()["X-Amz-Credential"]; ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify if request has AWS Post policy Signature Version '4'.
|
||||||
|
func isRequestPostPolicySignatureV4(r *http.Request) bool {
|
||||||
|
if _, ok := r.Header["Content-Type"]; ok {
|
||||||
|
if strings.Contains(r.Header.Get("Content-Type"), "multipart/form-data") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify if request requires ACL check.
|
||||||
|
func isRequestRequiresACLCheck(r *http.Request) bool {
|
||||||
|
if isRequestSignatureV4(r) || isRequestPresignedSignatureV4(r) || isRequestPostPolicySignatureV4(r) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify if request has valid AWS Signature Version '4'.
|
||||||
|
func isSignV4ReqAuthenticated(sign *signature4.Sign, r *http.Request) bool {
|
||||||
|
auth := sign.SetHTTPRequestToVerify(r)
|
||||||
|
if isRequestSignatureV4(r) {
|
||||||
|
dummyPayload := sha256.Sum256([]byte(""))
|
||||||
|
ok, err := auth.DoesSignatureMatch(hex.EncodeToString(dummyPayload[:]))
|
||||||
|
if err != nil {
|
||||||
|
errorIf(err.Trace(), "Signature verification failed.", nil)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return ok
|
||||||
|
} else if isRequestPresignedSignatureV4(r) {
|
||||||
|
ok, err := auth.DoesPresignedSignatureMatch()
|
||||||
|
if err != nil {
|
||||||
|
errorIf(err.Trace(), "Presigned signature verification failed.", nil)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// authHandler - handles all the incoming authorization headers and
|
// authHandler - handles all the incoming authorization headers and
|
||||||
// validates them if possible.
|
// validates them if possible.
|
||||||
type authHandler struct {
|
type authHandler struct {
|
||||||
|
@ -24,11 +24,11 @@ import (
|
|||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
mux "github.com/gorilla/mux"
|
||||||
"github.com/minio/minio/pkg/crypto/sha256"
|
"github.com/minio/minio/pkg/crypto/sha256"
|
||||||
"github.com/minio/minio/pkg/fs"
|
"github.com/minio/minio/pkg/fs"
|
||||||
"github.com/minio/minio/pkg/probe"
|
"github.com/minio/minio/pkg/probe"
|
||||||
signV4 "github.com/minio/minio/pkg/signature"
|
"github.com/minio/minio/pkg/s3/signature4"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetBucketLocationHandler - GET Bucket location.
|
// GetBucketLocationHandler - GET Bucket location.
|
||||||
@ -368,7 +368,7 @@ func (api storageAPI) PostPolicyBucketHandler(w http.ResponseWriter, r *http.Req
|
|||||||
writeErrorResponse(w, r, SignatureDoesNotMatch, r.URL.Path)
|
writeErrorResponse(w, r, SignatureDoesNotMatch, r.URL.Path)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = signV4.ApplyPolicyCond(formValues); err != nil {
|
if err = signature4.ApplyPolicyCond(formValues); err != nil {
|
||||||
errorIf(err.Trace(), "Invalid request, policy doesn't match with the endpoint.", nil)
|
errorIf(err.Trace(), "Invalid request, policy doesn't match with the endpoint.", nil)
|
||||||
writeErrorResponse(w, r, MalformedPOSTRequest, r.URL.Path)
|
writeErrorResponse(w, r, MalformedPOSTRequest, r.URL.Path)
|
||||||
return
|
return
|
||||||
|
@ -39,7 +39,7 @@ import (
|
|||||||
"github.com/minio/minio/pkg/disk"
|
"github.com/minio/minio/pkg/disk"
|
||||||
"github.com/minio/minio/pkg/mimedb"
|
"github.com/minio/minio/pkg/mimedb"
|
||||||
"github.com/minio/minio/pkg/probe"
|
"github.com/minio/minio/pkg/probe"
|
||||||
signV4 "github.com/minio/minio/pkg/signature"
|
"github.com/minio/minio/pkg/s3/signature4"
|
||||||
)
|
)
|
||||||
|
|
||||||
// isValidUploadID - is upload id.
|
// isValidUploadID - is upload id.
|
||||||
@ -297,7 +297,7 @@ func (a partNumber) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
|||||||
func (a partNumber) Less(i, j int) bool { return a[i].PartNumber < a[j].PartNumber }
|
func (a partNumber) Less(i, j int) bool { return a[i].PartNumber < a[j].PartNumber }
|
||||||
|
|
||||||
// CreateObjectPart - create a part in a multipart session
|
// CreateObjectPart - create a part in a multipart session
|
||||||
func (fs Filesystem) CreateObjectPart(bucket, object, uploadID, expectedMD5Sum string, partID int, size int64, data io.Reader, signature *signV4.Signature) (string, *probe.Error) {
|
func (fs Filesystem) CreateObjectPart(bucket, object, uploadID, expectedMD5Sum string, partID int, size int64, data io.Reader, signature *signature4.Sign) (string, *probe.Error) {
|
||||||
di, err := disk.GetInfo(fs.path)
|
di, err := disk.GetInfo(fs.path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", probe.NewError(err)
|
return "", probe.NewError(err)
|
||||||
@ -431,7 +431,7 @@ func (fs Filesystem) CreateObjectPart(bucket, object, uploadID, expectedMD5Sum s
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CompleteMultipartUpload - complete a multipart upload and persist the data
|
// CompleteMultipartUpload - complete a multipart upload and persist the data
|
||||||
func (fs Filesystem) CompleteMultipartUpload(bucket, object, uploadID string, data io.Reader, signature *signV4.Signature) (ObjectMetadata, *probe.Error) {
|
func (fs Filesystem) CompleteMultipartUpload(bucket, object, uploadID string, data io.Reader, signature *signature4.Sign) (ObjectMetadata, *probe.Error) {
|
||||||
// Check bucket name is valid.
|
// Check bucket name is valid.
|
||||||
if !IsValidBucketName(bucket) {
|
if !IsValidBucketName(bucket) {
|
||||||
return ObjectMetadata{}, probe.NewError(BucketNameInvalid{Bucket: bucket})
|
return ObjectMetadata{}, probe.NewError(BucketNameInvalid{Bucket: bucket})
|
||||||
|
@ -34,7 +34,7 @@ import (
|
|||||||
"github.com/minio/minio/pkg/ioutils"
|
"github.com/minio/minio/pkg/ioutils"
|
||||||
"github.com/minio/minio/pkg/mimedb"
|
"github.com/minio/minio/pkg/mimedb"
|
||||||
"github.com/minio/minio/pkg/probe"
|
"github.com/minio/minio/pkg/probe"
|
||||||
signV4 "github.com/minio/minio/pkg/signature"
|
"github.com/minio/minio/pkg/s3/signature4"
|
||||||
)
|
)
|
||||||
|
|
||||||
/// Object Operations
|
/// Object Operations
|
||||||
@ -199,7 +199,7 @@ func isMD5SumEqual(expectedMD5Sum, actualMD5Sum string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateObject - create an object.
|
// CreateObject - create an object.
|
||||||
func (fs Filesystem) CreateObject(bucket, object, expectedMD5Sum string, size int64, data io.Reader, sig *signV4.Signature) (ObjectMetadata, *probe.Error) {
|
func (fs Filesystem) CreateObject(bucket, object, expectedMD5Sum string, size int64, data io.Reader, sig *signature4.Sign) (ObjectMetadata, *probe.Error) {
|
||||||
di, e := disk.GetInfo(fs.path)
|
di, e := disk.GetInfo(fs.path)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
return ObjectMetadata{}, probe.NewError(e)
|
return ObjectMetadata{}, probe.NewError(e)
|
||||||
@ -294,7 +294,7 @@ func (fs Filesystem) CreateObject(bucket, object, expectedMD5Sum string, size in
|
|||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
file.CloseAndPurge()
|
file.CloseAndPurge()
|
||||||
return ObjectMetadata{}, signV4.ErrSignDoesNotMath("Signature does not match")
|
return ObjectMetadata{}, probe.NewError(SignDoesNotMatch{})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file.Close()
|
file.Close()
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Minio Cloud Storage, (C) 2015 Minio, Inc.
|
* Minio Cloud Storage, (C) 2015, 2016 Minio, Inc.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package signature
|
package signature4
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -24,13 +24,14 @@ import (
|
|||||||
|
|
||||||
type errFunc func(msg string, a ...string) *probe.Error
|
type errFunc func(msg string, a ...string) *probe.Error
|
||||||
|
|
||||||
|
// generic error factory which wraps around probe.NewError()
|
||||||
func errFactory() errFunc {
|
func errFactory() errFunc {
|
||||||
return func(msg string, a ...string) *probe.Error {
|
return func(msg string, a ...string) *probe.Error {
|
||||||
return probe.NewError(fmt.Errorf("%s, Args: %s", msg, a)).Untrace()
|
return probe.NewError(fmt.Errorf("%s, Args: %s", msg, a)).Untrace()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Various errors.
|
// Various signature v4 errors.
|
||||||
var (
|
var (
|
||||||
ErrPolicyAlreadyExpired = errFactory()
|
ErrPolicyAlreadyExpired = errFactory()
|
||||||
ErrInvalidRegion = errFactory()
|
ErrInvalidRegion = errFactory()
|
@ -1,4 +1,20 @@
|
|||||||
package signature
|
/*
|
||||||
|
* Minio Cloud Storage, (C) 2015 Minio, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package signature4
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/url"
|
"net/url"
|
||||||
@ -8,7 +24,9 @@ import (
|
|||||||
"github.com/minio/minio/pkg/probe"
|
"github.com/minio/minio/pkg/probe"
|
||||||
)
|
)
|
||||||
|
|
||||||
type credScope struct {
|
// credential data type represents structured form of Credential
|
||||||
|
// string from authorization header.
|
||||||
|
type credential struct {
|
||||||
accessKeyID string
|
accessKeyID string
|
||||||
scope struct {
|
scope struct {
|
||||||
date time.Time
|
date time.Time
|
||||||
@ -18,45 +36,46 @@ type credScope struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseCredential(credElement string) (credScope, *probe.Error) {
|
// parse credential string into its structured form.
|
||||||
|
func parseCredential(credElement string) (credential, *probe.Error) {
|
||||||
creds := strings.Split(strings.TrimSpace(credElement), "=")
|
creds := strings.Split(strings.TrimSpace(credElement), "=")
|
||||||
if len(creds) != 2 {
|
if len(creds) != 2 {
|
||||||
return credScope{}, ErrMissingFields("Credential tag has missing fields.", credElement).Trace(credElement)
|
return credential{}, ErrMissingFields("Credential tag has missing fields.", credElement).Trace(credElement)
|
||||||
}
|
}
|
||||||
if creds[0] != "Credential" {
|
if creds[0] != "Credential" {
|
||||||
return credScope{}, ErrMissingCredTag("Missing credentials tag.", credElement).Trace(credElement)
|
return credential{}, ErrMissingCredTag("Missing credentials tag.", credElement).Trace(credElement)
|
||||||
}
|
}
|
||||||
credElements := strings.Split(strings.TrimSpace(creds[1]), "/")
|
credElements := strings.Split(strings.TrimSpace(creds[1]), "/")
|
||||||
if len(credElements) != 5 {
|
if len(credElements) != 5 {
|
||||||
return credScope{}, ErrCredMalformed("Credential values malformed.", credElement).Trace(credElement)
|
return credential{}, ErrCredMalformed("Credential values malformed.", credElement).Trace(credElement)
|
||||||
}
|
}
|
||||||
if !isValidAccessKey.MatchString(credElements[0]) {
|
if !isValidAccessKey.MatchString(credElements[0]) {
|
||||||
return credScope{}, ErrInvalidAccessKeyID("Invalid access key id.", credElement).Trace(credElement)
|
return credential{}, ErrInvalidAccessKeyID("Invalid access key id.", credElement).Trace(credElement)
|
||||||
}
|
}
|
||||||
cred := credScope{
|
cred := credential{
|
||||||
accessKeyID: credElements[0],
|
accessKeyID: credElements[0],
|
||||||
}
|
}
|
||||||
var e error
|
var e error
|
||||||
cred.scope.date, e = time.Parse(yyyymmdd, credElements[1])
|
cred.scope.date, e = time.Parse(yyyymmdd, credElements[1])
|
||||||
if e != nil {
|
if e != nil {
|
||||||
return credScope{}, ErrInvalidDateFormat("Invalid date format.", credElement).Trace(credElement)
|
return credential{}, ErrInvalidDateFormat("Invalid date format.", credElement).Trace(credElement)
|
||||||
}
|
}
|
||||||
if credElements[2] == "" {
|
if credElements[2] == "" {
|
||||||
return credScope{}, ErrRegionISEmpty("Region is empty.", credElement).Trace(credElement)
|
return credential{}, ErrRegionISEmpty("Region is empty.", credElement).Trace(credElement)
|
||||||
}
|
}
|
||||||
cred.scope.region = credElements[2]
|
cred.scope.region = credElements[2]
|
||||||
if credElements[3] != "s3" {
|
if credElements[3] != "s3" {
|
||||||
return credScope{}, ErrInvalidService("Invalid service detected.", credElement).Trace(credElement)
|
return credential{}, ErrInvalidService("Invalid service detected.", credElement).Trace(credElement)
|
||||||
}
|
}
|
||||||
cred.scope.service = credElements[3]
|
cred.scope.service = credElements[3]
|
||||||
if credElements[4] != "aws4_request" {
|
if credElements[4] != "aws4_request" {
|
||||||
return credScope{}, ErrInvalidRequestVersion("Invalid request version detected.", credElement).Trace(credElement)
|
return credential{}, ErrInvalidRequestVersion("Invalid request version detected.", credElement).Trace(credElement)
|
||||||
}
|
}
|
||||||
cred.scope.request = credElements[4]
|
cred.scope.request = credElements[4]
|
||||||
return cred, nil
|
return cred, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse signature.
|
// Parse signature string.
|
||||||
func parseSignature(signElement string) (string, *probe.Error) {
|
func parseSignature(signElement string) (string, *probe.Error) {
|
||||||
signFields := strings.Split(strings.TrimSpace(signElement), "=")
|
signFields := strings.Split(strings.TrimSpace(signElement), "=")
|
||||||
if len(signFields) != 2 {
|
if len(signFields) != 2 {
|
||||||
@ -69,7 +88,7 @@ func parseSignature(signElement string) (string, *probe.Error) {
|
|||||||
return signature, nil
|
return signature, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse signed headers.
|
// Parse signed headers string.
|
||||||
func parseSignedHeaders(signedHdrElement string) ([]string, *probe.Error) {
|
func parseSignedHeaders(signedHdrElement string) ([]string, *probe.Error) {
|
||||||
signedHdrFields := strings.Split(strings.TrimSpace(signedHdrElement), "=")
|
signedHdrFields := strings.Split(strings.TrimSpace(signedHdrElement), "=")
|
||||||
if len(signedHdrFields) != 2 {
|
if len(signedHdrFields) != 2 {
|
||||||
@ -82,14 +101,14 @@ func parseSignedHeaders(signedHdrElement string) ([]string, *probe.Error) {
|
|||||||
return signedHeaders, nil
|
return signedHeaders, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// structured version of AWS Signature V4 header.
|
// signValues data type represents structured form of AWS Signature V4 header.
|
||||||
type signValues struct {
|
type signValues struct {
|
||||||
Creds credScope
|
Credential credential
|
||||||
SignedHeaders []string
|
SignedHeaders []string
|
||||||
Signature string
|
Signature string
|
||||||
}
|
}
|
||||||
|
|
||||||
// structued version of AWS Signature V4 query string.
|
// preSignValues data type represents structued form of AWS Signature V4 query string.
|
||||||
type preSignValues struct {
|
type preSignValues struct {
|
||||||
signValues
|
signValues
|
||||||
Date time.Time
|
Date time.Time
|
||||||
@ -115,8 +134,8 @@ func parsePreSignV4(query url.Values) (preSignValues, *probe.Error) {
|
|||||||
preSignV4Values := preSignValues{}
|
preSignV4Values := preSignValues{}
|
||||||
|
|
||||||
var err *probe.Error
|
var err *probe.Error
|
||||||
// Save credentail values.
|
// Save credential.
|
||||||
preSignV4Values.Creds, err = parseCredential("Credential=" + query.Get("X-Amz-Credential"))
|
preSignV4Values.Credential, err = parseCredential("Credential=" + query.Get("X-Amz-Credential"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return preSignValues{}, err.Trace(query.Get("X-Amz-Credential"))
|
return preSignValues{}, err.Trace(query.Get("X-Amz-Credential"))
|
||||||
}
|
}
|
||||||
@ -181,7 +200,7 @@ func parseSignV4(v4Auth string) (signValues, *probe.Error) {
|
|||||||
|
|
||||||
var err *probe.Error
|
var err *probe.Error
|
||||||
// Save credentail values.
|
// Save credentail values.
|
||||||
signV4Values.Creds, err = parseCredential(authFields[0])
|
signV4Values.Credential, err = parseCredential(authFields[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return signValues{}, err.Trace(v4Auth)
|
return signValues{}, err.Trace(v4Auth)
|
||||||
}
|
}
|
@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package signature
|
package signature4
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
@ -14,7 +14,15 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package signature
|
// Package signature4 implements helper functions to validate AWS
|
||||||
|
// Signature Version '4' authorization header.
|
||||||
|
//
|
||||||
|
// This package provides comprehensive helpers for following signature
|
||||||
|
// types.
|
||||||
|
// - Based on Authorization header.
|
||||||
|
// - Based on Query parameters.
|
||||||
|
// - Based on Form POST policy.
|
||||||
|
package signature4
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -30,8 +38,8 @@ import (
|
|||||||
"github.com/minio/minio/pkg/probe"
|
"github.com/minio/minio/pkg/probe"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Signature - local variables
|
// Sign - local variables
|
||||||
type Signature struct {
|
type Sign struct {
|
||||||
accessKeyID string
|
accessKeyID string
|
||||||
secretAccessKey string
|
secretAccessKey string
|
||||||
region string
|
region string
|
||||||
@ -39,6 +47,7 @@ type Signature struct {
|
|||||||
extractedSignedHeaders http.Header
|
extractedSignedHeaders http.Header
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AWS Signature Version '4' constants.
|
||||||
const (
|
const (
|
||||||
signV4Algorithm = "AWS4-HMAC-SHA256"
|
signV4Algorithm = "AWS4-HMAC-SHA256"
|
||||||
iso8601Format = "20060102T150405Z"
|
iso8601Format = "20060102T150405Z"
|
||||||
@ -46,7 +55,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// New - initialize a new authorization checkes.
|
// New - initialize a new authorization checkes.
|
||||||
func New(accessKeyID, secretAccessKey, region string) (*Signature, *probe.Error) {
|
func New(accessKeyID, secretAccessKey, region string) (*Sign, *probe.Error) {
|
||||||
if !isValidAccessKey.MatchString(accessKeyID) {
|
if !isValidAccessKey.MatchString(accessKeyID) {
|
||||||
return nil, ErrInvalidAccessKeyID("Invalid access key id.", accessKeyID).Trace(accessKeyID)
|
return nil, ErrInvalidAccessKeyID("Invalid access key id.", accessKeyID).Trace(accessKeyID)
|
||||||
}
|
}
|
||||||
@ -56,7 +65,7 @@ func New(accessKeyID, secretAccessKey, region string) (*Signature, *probe.Error)
|
|||||||
if region == "" {
|
if region == "" {
|
||||||
return nil, ErrRegionISEmpty("Region is empty.").Trace()
|
return nil, ErrRegionISEmpty("Region is empty.").Trace()
|
||||||
}
|
}
|
||||||
signature := &Signature{
|
signature := &Sign{
|
||||||
accessKeyID: accessKeyID,
|
accessKeyID: accessKeyID,
|
||||||
secretAccessKey: secretAccessKey,
|
secretAccessKey: secretAccessKey,
|
||||||
region: region,
|
region: region,
|
||||||
@ -65,7 +74,7 @@ func New(accessKeyID, secretAccessKey, region string) (*Signature, *probe.Error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetHTTPRequestToVerify - sets the http request which needs to be verified.
|
// SetHTTPRequestToVerify - sets the http request which needs to be verified.
|
||||||
func (s *Signature) SetHTTPRequestToVerify(r *http.Request) *Signature {
|
func (s *Sign) SetHTTPRequestToVerify(r *http.Request) *Sign {
|
||||||
// Do not set http request if its 'nil'.
|
// Do not set http request if its 'nil'.
|
||||||
if r == nil {
|
if r == nil {
|
||||||
return s
|
return s
|
||||||
@ -75,7 +84,7 @@ func (s *Signature) SetHTTPRequestToVerify(r *http.Request) *Signature {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getCanonicalHeaders generate a list of request headers with their values
|
// getCanonicalHeaders generate a list of request headers with their values
|
||||||
func (s Signature) getCanonicalHeaders(signedHeaders http.Header) string {
|
func (s Sign) getCanonicalHeaders(signedHeaders http.Header) string {
|
||||||
var headers []string
|
var headers []string
|
||||||
vals := make(http.Header)
|
vals := make(http.Header)
|
||||||
for k, vv := range signedHeaders {
|
for k, vv := range signedHeaders {
|
||||||
@ -107,7 +116,7 @@ func (s Signature) getCanonicalHeaders(signedHeaders http.Header) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getSignedHeaders generate a string i.e alphabetically sorted, semicolon-separated list of lowercase request header names
|
// getSignedHeaders generate a string i.e alphabetically sorted, semicolon-separated list of lowercase request header names
|
||||||
func (s Signature) getSignedHeaders(signedHeaders http.Header) string {
|
func (s Sign) getSignedHeaders(signedHeaders http.Header) string {
|
||||||
var headers []string
|
var headers []string
|
||||||
for k := range signedHeaders {
|
for k := range signedHeaders {
|
||||||
headers = append(headers, strings.ToLower(k))
|
headers = append(headers, strings.ToLower(k))
|
||||||
@ -127,7 +136,7 @@ func (s Signature) getSignedHeaders(signedHeaders http.Header) string {
|
|||||||
// <SignedHeaders>\n
|
// <SignedHeaders>\n
|
||||||
// <HashedPayload>
|
// <HashedPayload>
|
||||||
//
|
//
|
||||||
func (s *Signature) getCanonicalRequest() string {
|
func (s *Sign) getCanonicalRequest() string {
|
||||||
payload := s.httpRequest.Header.Get(http.CanonicalHeaderKey("x-amz-content-sha256"))
|
payload := s.httpRequest.Header.Get(http.CanonicalHeaderKey("x-amz-content-sha256"))
|
||||||
s.httpRequest.URL.RawQuery = strings.Replace(s.httpRequest.URL.Query().Encode(), "+", "%20", -1)
|
s.httpRequest.URL.RawQuery = strings.Replace(s.httpRequest.URL.Query().Encode(), "+", "%20", -1)
|
||||||
encodedPath := getURLEncodedName(s.httpRequest.URL.Path)
|
encodedPath := getURLEncodedName(s.httpRequest.URL.Path)
|
||||||
@ -154,7 +163,7 @@ func (s *Signature) getCanonicalRequest() string {
|
|||||||
// <SignedHeaders>\n
|
// <SignedHeaders>\n
|
||||||
// <HashedPayload>
|
// <HashedPayload>
|
||||||
//
|
//
|
||||||
func (s Signature) getPresignedCanonicalRequest(presignedQuery string) string {
|
func (s Sign) getPresignedCanonicalRequest(presignedQuery string) string {
|
||||||
rawQuery := strings.Replace(presignedQuery, "+", "%20", -1)
|
rawQuery := strings.Replace(presignedQuery, "+", "%20", -1)
|
||||||
encodedPath := getURLEncodedName(s.httpRequest.URL.Path)
|
encodedPath := getURLEncodedName(s.httpRequest.URL.Path)
|
||||||
// Convert any space strings back to "+".
|
// Convert any space strings back to "+".
|
||||||
@ -171,7 +180,7 @@ func (s Signature) getPresignedCanonicalRequest(presignedQuery string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getScope generate a string of a specific date, an AWS region, and a service.
|
// getScope generate a string of a specific date, an AWS region, and a service.
|
||||||
func (s Signature) getScope(t time.Time) string {
|
func (s Sign) getScope(t time.Time) string {
|
||||||
scope := strings.Join([]string{
|
scope := strings.Join([]string{
|
||||||
t.Format(yyyymmdd),
|
t.Format(yyyymmdd),
|
||||||
s.region,
|
s.region,
|
||||||
@ -182,7 +191,7 @@ func (s Signature) getScope(t time.Time) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getStringToSign a string based on selected query values.
|
// getStringToSign a string based on selected query values.
|
||||||
func (s Signature) getStringToSign(canonicalRequest string, t time.Time) string {
|
func (s Sign) getStringToSign(canonicalRequest string, t time.Time) string {
|
||||||
stringToSign := signV4Algorithm + "\n" + t.Format(iso8601Format) + "\n"
|
stringToSign := signV4Algorithm + "\n" + t.Format(iso8601Format) + "\n"
|
||||||
stringToSign = stringToSign + s.getScope(t) + "\n"
|
stringToSign = stringToSign + s.getScope(t) + "\n"
|
||||||
canonicalRequestBytes := sha256.Sum256([]byte(canonicalRequest))
|
canonicalRequestBytes := sha256.Sum256([]byte(canonicalRequest))
|
||||||
@ -191,7 +200,7 @@ func (s Signature) getStringToSign(canonicalRequest string, t time.Time) string
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getSigningKey hmac seed to calculate final signature.
|
// getSigningKey hmac seed to calculate final signature.
|
||||||
func (s Signature) getSigningKey(t time.Time) []byte {
|
func (s Sign) getSigningKey(t time.Time) []byte {
|
||||||
secret := s.secretAccessKey
|
secret := s.secretAccessKey
|
||||||
date := sumHMAC([]byte("AWS4"+secret), []byte(t.Format(yyyymmdd)))
|
date := sumHMAC([]byte("AWS4"+secret), []byte(t.Format(yyyymmdd)))
|
||||||
region := sumHMAC(date, []byte(s.region))
|
region := sumHMAC(date, []byte(s.region))
|
||||||
@ -201,27 +210,27 @@ func (s Signature) getSigningKey(t time.Time) []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getSignature final signature in hexadecimal form.
|
// getSignature final signature in hexadecimal form.
|
||||||
func (s Signature) getSignature(signingKey []byte, stringToSign string) string {
|
func (s Sign) getSignature(signingKey []byte, stringToSign string) string {
|
||||||
return hex.EncodeToString(sumHMAC(signingKey, []byte(stringToSign)))
|
return hex.EncodeToString(sumHMAC(signingKey, []byte(stringToSign)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// DoesPolicySignatureMatch - Verify query headers with post policy
|
// DoesPolicySignatureMatch - Verify query headers with post policy
|
||||||
// - http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-HTTPPOSTConstructPolicy.html
|
// - http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-HTTPPOSTConstructPolicy.html
|
||||||
// returns true if matches, false otherwise. if error is not nil then it is always false
|
// returns true if matches, false otherwise. if error is not nil then it is always false
|
||||||
func (s *Signature) DoesPolicySignatureMatch(formValues map[string]string) (bool, *probe.Error) {
|
func (s *Sign) DoesPolicySignatureMatch(formValues map[string]string) (bool, *probe.Error) {
|
||||||
// Parse credential tag.
|
// Parse credential tag.
|
||||||
creds, err := parseCredential("Credential=" + formValues["X-Amz-Credential"])
|
credential, err := parseCredential("Credential=" + formValues["X-Amz-Credential"])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err.Trace(formValues["X-Amz-Credential"])
|
return false, err.Trace(formValues["X-Amz-Credential"])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify if the access key id matches.
|
// Verify if the access key id matches.
|
||||||
if creds.accessKeyID != s.accessKeyID {
|
if credential.accessKeyID != s.accessKeyID {
|
||||||
return false, ErrInvalidAccessKeyID("Access key id does not match with our records.", creds.accessKeyID).Trace(creds.accessKeyID)
|
return false, ErrInvalidAccessKeyID("Access key id does not match with our records.", credential.accessKeyID).Trace(credential.accessKeyID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify if the region is valid.
|
// Verify if the region is valid.
|
||||||
reqRegion := creds.scope.region
|
reqRegion := credential.scope.region
|
||||||
if !isValidRegion(reqRegion, s.region) {
|
if !isValidRegion(reqRegion, s.region) {
|
||||||
return false, ErrInvalidRegion("Requested region is not recognized.", reqRegion).Trace(reqRegion)
|
return false, ErrInvalidRegion("Requested region is not recognized.", reqRegion).Trace(reqRegion)
|
||||||
}
|
}
|
||||||
@ -245,20 +254,20 @@ func (s *Signature) DoesPolicySignatureMatch(formValues map[string]string) (bool
|
|||||||
// DoesPresignedSignatureMatch - Verify query headers with presigned signature
|
// DoesPresignedSignatureMatch - Verify query headers with presigned signature
|
||||||
// - http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html
|
// - http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html
|
||||||
// returns true if matches, false otherwise. if error is not nil then it is always false
|
// returns true if matches, false otherwise. if error is not nil then it is always false
|
||||||
func (s *Signature) DoesPresignedSignatureMatch() (bool, *probe.Error) {
|
func (s *Sign) DoesPresignedSignatureMatch() (bool, *probe.Error) {
|
||||||
// Parse request query string.
|
// Parse request query string.
|
||||||
preSignV4Values, err := parsePreSignV4(s.httpRequest.URL.Query())
|
preSignValues, err := parsePreSignV4(s.httpRequest.URL.Query())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err.Trace(s.httpRequest.URL.String())
|
return false, err.Trace(s.httpRequest.URL.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify if the access key id matches.
|
// Verify if the access key id matches.
|
||||||
if preSignV4Values.Creds.accessKeyID != s.accessKeyID {
|
if preSignValues.Credential.accessKeyID != s.accessKeyID {
|
||||||
return false, ErrInvalidAccessKeyID("Access key id does not match with our records.", preSignV4Values.Creds.accessKeyID).Trace(preSignV4Values.Creds.accessKeyID)
|
return false, ErrInvalidAccessKeyID("Access key id does not match with our records.", preSignValues.Credential.accessKeyID).Trace(preSignValues.Credential.accessKeyID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify if region is valid.
|
// Verify if region is valid.
|
||||||
reqRegion := preSignV4Values.Creds.scope.region
|
reqRegion := preSignValues.Credential.scope.region
|
||||||
if !isValidRegion(reqRegion, s.region) {
|
if !isValidRegion(reqRegion, s.region) {
|
||||||
return false, ErrInvalidRegion("Requested region is not recognized.", reqRegion).Trace(reqRegion)
|
return false, ErrInvalidRegion("Requested region is not recognized.", reqRegion).Trace(reqRegion)
|
||||||
}
|
}
|
||||||
@ -267,19 +276,19 @@ func (s *Signature) DoesPresignedSignatureMatch() (bool, *probe.Error) {
|
|||||||
s.region = reqRegion
|
s.region = reqRegion
|
||||||
|
|
||||||
// Extract all the signed headers along with its values.
|
// Extract all the signed headers along with its values.
|
||||||
s.extractedSignedHeaders = extractSignedHeaders(preSignV4Values.SignedHeaders, s.httpRequest.Header)
|
s.extractedSignedHeaders = extractSignedHeaders(preSignValues.SignedHeaders, s.httpRequest.Header)
|
||||||
|
|
||||||
// Construct new query.
|
// Construct new query.
|
||||||
query := make(url.Values)
|
query := make(url.Values)
|
||||||
query.Set("X-Amz-Algorithm", signV4Algorithm)
|
query.Set("X-Amz-Algorithm", signV4Algorithm)
|
||||||
|
|
||||||
if time.Now().UTC().Sub(preSignV4Values.Date) > time.Duration(preSignV4Values.Expires) {
|
if time.Now().UTC().Sub(preSignValues.Date) > time.Duration(preSignValues.Expires) {
|
||||||
return false, ErrExpiredPresignRequest("Presigned request already expired, please initiate a new request.")
|
return false, ErrExpiredPresignRequest("Presigned request already expired, please initiate a new request.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the date and expires.
|
// Save the date and expires.
|
||||||
t := preSignV4Values.Date
|
t := preSignValues.Date
|
||||||
expireSeconds := int(time.Duration(preSignV4Values.Expires) / time.Second)
|
expireSeconds := int(time.Duration(preSignValues.Expires) / time.Second)
|
||||||
|
|
||||||
// Construct the query.
|
// Construct the query.
|
||||||
query.Set("X-Amz-Date", t.Format(iso8601Format))
|
query.Set("X-Amz-Date", t.Format(iso8601Format))
|
||||||
@ -325,7 +334,7 @@ func (s *Signature) DoesPresignedSignatureMatch() (bool, *probe.Error) {
|
|||||||
// DoesSignatureMatch - Verify authorization header with calculated header in accordance with
|
// DoesSignatureMatch - Verify authorization header with calculated header in accordance with
|
||||||
// - http://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html
|
// - http://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html
|
||||||
// returns true if matches, false otherwise. if error is not nil then it is always false
|
// returns true if matches, false otherwise. if error is not nil then it is always false
|
||||||
func (s *Signature) DoesSignatureMatch(hashedPayload string) (bool, *probe.Error) {
|
func (s *Sign) DoesSignatureMatch(hashedPayload string) (bool, *probe.Error) {
|
||||||
// Save authorization header.
|
// Save authorization header.
|
||||||
v4Auth := s.httpRequest.Header.Get("Authorization")
|
v4Auth := s.httpRequest.Header.Get("Authorization")
|
||||||
|
|
||||||
@ -339,12 +348,12 @@ func (s *Signature) DoesSignatureMatch(hashedPayload string) (bool, *probe.Error
|
|||||||
s.extractedSignedHeaders = extractSignedHeaders(signV4Values.SignedHeaders, s.httpRequest.Header)
|
s.extractedSignedHeaders = extractSignedHeaders(signV4Values.SignedHeaders, s.httpRequest.Header)
|
||||||
|
|
||||||
// Verify if the access key id matches.
|
// Verify if the access key id matches.
|
||||||
if signV4Values.Creds.accessKeyID != s.accessKeyID {
|
if signV4Values.Credential.accessKeyID != s.accessKeyID {
|
||||||
return false, ErrInvalidAccessKeyID("Access key id does not match with our records.", signV4Values.Creds.accessKeyID).Trace(signV4Values.Creds.accessKeyID)
|
return false, ErrInvalidAccessKeyID("Access key id does not match with our records.", signV4Values.Credential.accessKeyID).Trace(signV4Values.Credential.accessKeyID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify if region is valid.
|
// Verify if region is valid.
|
||||||
reqRegion := signV4Values.Creds.scope.region
|
reqRegion := signV4Values.Credential.scope.region
|
||||||
if !isValidRegion(reqRegion, s.region) {
|
if !isValidRegion(reqRegion, s.region) {
|
||||||
return false, ErrInvalidRegion("Requested region is not recognized.", reqRegion).Trace(reqRegion)
|
return false, ErrInvalidRegion("Requested region is not recognized.", reqRegion).Trace(reqRegion)
|
||||||
}
|
}
|
@ -1,4 +1,20 @@
|
|||||||
package signature
|
/*
|
||||||
|
* Minio Cloud Storage, (C) 2015, 2016 Minio, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package signature4
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/hmac"
|
"crypto/hmac"
|
||||||
@ -11,12 +27,6 @@ import (
|
|||||||
"github.com/minio/minio/pkg/crypto/sha256"
|
"github.com/minio/minio/pkg/crypto/sha256"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AccessID and SecretID length in bytes
|
|
||||||
const (
|
|
||||||
MinioAccessID = 20
|
|
||||||
MinioSecretID = 40
|
|
||||||
)
|
|
||||||
|
|
||||||
/// helpers
|
/// helpers
|
||||||
|
|
||||||
// isValidSecretKey - validate secret key.
|
// isValidSecretKey - validate secret key.
|
@ -34,7 +34,7 @@ import (
|
|||||||
"github.com/minio/minio/pkg/crypto/sha256"
|
"github.com/minio/minio/pkg/crypto/sha256"
|
||||||
"github.com/minio/minio/pkg/crypto/sha512"
|
"github.com/minio/minio/pkg/crypto/sha512"
|
||||||
"github.com/minio/minio/pkg/probe"
|
"github.com/minio/minio/pkg/probe"
|
||||||
signV4 "github.com/minio/minio/pkg/signature"
|
"github.com/minio/minio/pkg/s3/signature4"
|
||||||
"github.com/minio/minio/pkg/xl/block"
|
"github.com/minio/minio/pkg/xl/block"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -236,7 +236,7 @@ func (b bucket) ReadObject(objectName string) (reader io.ReadCloser, size int64,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WriteObject - write a new object into bucket
|
// WriteObject - write a new object into bucket
|
||||||
func (b bucket) WriteObject(objectName string, objectData io.Reader, size int64, expectedMD5Sum string, metadata map[string]string, signature *signV4.Signature) (ObjectMetadata, *probe.Error) {
|
func (b bucket) WriteObject(objectName string, objectData io.Reader, size int64, expectedMD5Sum string, metadata map[string]string, signature *signature4.Sign) (ObjectMetadata, *probe.Error) {
|
||||||
b.lock.Lock()
|
b.lock.Lock()
|
||||||
defer b.lock.Unlock()
|
defer b.lock.Unlock()
|
||||||
if objectName == "" || objectData == nil {
|
if objectName == "" || objectData == nil {
|
||||||
|
@ -20,7 +20,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/minio/minio/pkg/probe"
|
"github.com/minio/minio/pkg/probe"
|
||||||
signV4 "github.com/minio/minio/pkg/signature"
|
"github.com/minio/minio/pkg/s3/signature4"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Collection of XL specification interfaces
|
// Collection of XL specification interfaces
|
||||||
@ -37,7 +37,7 @@ type CloudStorage interface {
|
|||||||
GetBucketMetadata(bucket string) (BucketMetadata, *probe.Error)
|
GetBucketMetadata(bucket string) (BucketMetadata, *probe.Error)
|
||||||
SetBucketMetadata(bucket string, metadata map[string]string) *probe.Error
|
SetBucketMetadata(bucket string, metadata map[string]string) *probe.Error
|
||||||
ListBuckets() ([]BucketMetadata, *probe.Error)
|
ListBuckets() ([]BucketMetadata, *probe.Error)
|
||||||
MakeBucket(bucket string, ACL string, location io.Reader, signature *signV4.Signature) *probe.Error
|
MakeBucket(bucket string, ACL string, location io.Reader, signature *signature4.Sign) *probe.Error
|
||||||
|
|
||||||
// Bucket operations
|
// Bucket operations
|
||||||
ListObjects(string, BucketResourcesMetadata) ([]ObjectMetadata, BucketResourcesMetadata, *probe.Error)
|
ListObjects(string, BucketResourcesMetadata) ([]ObjectMetadata, BucketResourcesMetadata, *probe.Error)
|
||||||
@ -46,7 +46,7 @@ type CloudStorage interface {
|
|||||||
GetObject(w io.Writer, bucket, object string, start, length int64) (int64, *probe.Error)
|
GetObject(w io.Writer, bucket, object string, start, length int64) (int64, *probe.Error)
|
||||||
GetObjectMetadata(bucket, object string) (ObjectMetadata, *probe.Error)
|
GetObjectMetadata(bucket, object string) (ObjectMetadata, *probe.Error)
|
||||||
// bucket, object, expectedMD5Sum, size, reader, metadata, signature
|
// bucket, object, expectedMD5Sum, size, reader, metadata, signature
|
||||||
CreateObject(string, string, string, int64, io.Reader, map[string]string, *signV4.Signature) (ObjectMetadata, *probe.Error)
|
CreateObject(string, string, string, int64, io.Reader, map[string]string, *signature4.Sign) (ObjectMetadata, *probe.Error)
|
||||||
|
|
||||||
Multipart
|
Multipart
|
||||||
}
|
}
|
||||||
@ -55,8 +55,8 @@ type CloudStorage interface {
|
|||||||
type Multipart interface {
|
type Multipart interface {
|
||||||
NewMultipartUpload(bucket, key, contentType string) (string, *probe.Error)
|
NewMultipartUpload(bucket, key, contentType string) (string, *probe.Error)
|
||||||
AbortMultipartUpload(bucket, key, uploadID string) *probe.Error
|
AbortMultipartUpload(bucket, key, uploadID string) *probe.Error
|
||||||
CreateObjectPart(string, string, string, int, string, string, int64, io.Reader, *signV4.Signature) (string, *probe.Error)
|
CreateObjectPart(string, string, string, int, string, string, int64, io.Reader, *signature4.Sign) (string, *probe.Error)
|
||||||
CompleteMultipartUpload(bucket, key, uploadID string, data io.Reader, signature *signV4.Signature) (ObjectMetadata, *probe.Error)
|
CompleteMultipartUpload(bucket, key, uploadID string, data io.Reader, signature *signature4.Sign) (ObjectMetadata, *probe.Error)
|
||||||
ListMultipartUploads(string, BucketMultipartResourcesMetadata) (BucketMultipartResourcesMetadata, *probe.Error)
|
ListMultipartUploads(string, BucketMultipartResourcesMetadata) (BucketMultipartResourcesMetadata, *probe.Error)
|
||||||
ListObjectParts(string, string, ObjectResourcesMetadata) (ObjectResourcesMetadata, *probe.Error)
|
ListObjectParts(string, string, ObjectResourcesMetadata) (ObjectResourcesMetadata, *probe.Error)
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ import (
|
|||||||
|
|
||||||
"github.com/minio/minio/pkg/crypto/sha256"
|
"github.com/minio/minio/pkg/crypto/sha256"
|
||||||
"github.com/minio/minio/pkg/probe"
|
"github.com/minio/minio/pkg/probe"
|
||||||
signV4 "github.com/minio/minio/pkg/signature"
|
"github.com/minio/minio/pkg/s3/signature4"
|
||||||
"github.com/minio/minio/pkg/xl/cache/data"
|
"github.com/minio/minio/pkg/xl/cache/data"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -109,7 +109,7 @@ func (xl API) AbortMultipartUpload(bucket, key, uploadID string) *probe.Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateObjectPart - create a part in a multipart session
|
// CreateObjectPart - create a part in a multipart session
|
||||||
func (xl API) CreateObjectPart(bucket, key, uploadID string, partID int, contentType, expectedMD5Sum string, size int64, data io.Reader, signature *signV4.Signature) (string, *probe.Error) {
|
func (xl API) CreateObjectPart(bucket, key, uploadID string, partID int, contentType, expectedMD5Sum string, size int64, data io.Reader, signature *signature4.Sign) (string, *probe.Error) {
|
||||||
xl.lock.Lock()
|
xl.lock.Lock()
|
||||||
etag, err := xl.createObjectPart(bucket, key, uploadID, partID, "", expectedMD5Sum, size, data, signature)
|
etag, err := xl.createObjectPart(bucket, key, uploadID, partID, "", expectedMD5Sum, size, data, signature)
|
||||||
xl.lock.Unlock()
|
xl.lock.Unlock()
|
||||||
@ -120,7 +120,7 @@ func (xl API) CreateObjectPart(bucket, key, uploadID string, partID int, content
|
|||||||
}
|
}
|
||||||
|
|
||||||
// createObject - internal wrapper function called by CreateObjectPart
|
// createObject - internal wrapper function called by CreateObjectPart
|
||||||
func (xl API) createObjectPart(bucket, key, uploadID string, partID int, contentType, expectedMD5Sum string, size int64, data io.Reader, signature *signV4.Signature) (string, *probe.Error) {
|
func (xl API) createObjectPart(bucket, key, uploadID string, partID int, contentType, expectedMD5Sum string, size int64, data io.Reader, signature *signature4.Sign) (string, *probe.Error) {
|
||||||
if !IsValidBucket(bucket) {
|
if !IsValidBucket(bucket) {
|
||||||
return "", probe.NewError(BucketNameInvalid{Bucket: bucket})
|
return "", probe.NewError(BucketNameInvalid{Bucket: bucket})
|
||||||
}
|
}
|
||||||
@ -289,7 +289,7 @@ func (xl API) mergeMultipart(parts *CompleteMultipartUpload, uploadID string, fu
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CompleteMultipartUpload - complete a multipart upload and persist the data
|
// CompleteMultipartUpload - complete a multipart upload and persist the data
|
||||||
func (xl API) CompleteMultipartUpload(bucket, key, uploadID string, data io.Reader, signature *signV4.Signature) (ObjectMetadata, *probe.Error) {
|
func (xl API) CompleteMultipartUpload(bucket, key, uploadID string, data io.Reader, signature *signature4.Sign) (ObjectMetadata, *probe.Error) {
|
||||||
xl.lock.Lock()
|
xl.lock.Lock()
|
||||||
defer xl.lock.Unlock()
|
defer xl.lock.Unlock()
|
||||||
size := int64(xl.multiPartObjects[uploadID].Stats().Bytes)
|
size := int64(xl.multiPartObjects[uploadID].Stats().Bytes)
|
||||||
@ -307,7 +307,7 @@ func (xl API) CompleteMultipartUpload(bucket, key, uploadID string, data io.Read
|
|||||||
return objectMetadata, nil
|
return objectMetadata, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (xl API) completeMultipartUploadV2(bucket, key, uploadID string, data io.Reader, signature *signV4.Signature) (io.Reader, *probe.Error) {
|
func (xl API) completeMultipartUploadV2(bucket, key, uploadID string, data io.Reader, signature *signature4.Sign) (io.Reader, *probe.Error) {
|
||||||
if !IsValidBucket(bucket) {
|
if !IsValidBucket(bucket) {
|
||||||
return nil, probe.NewError(BucketNameInvalid{Bucket: bucket})
|
return nil, probe.NewError(BucketNameInvalid{Bucket: bucket})
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ import (
|
|||||||
"github.com/minio/minio/pkg/crypto/sha256"
|
"github.com/minio/minio/pkg/crypto/sha256"
|
||||||
"github.com/minio/minio/pkg/crypto/sha512"
|
"github.com/minio/minio/pkg/crypto/sha512"
|
||||||
"github.com/minio/minio/pkg/probe"
|
"github.com/minio/minio/pkg/probe"
|
||||||
signV4 "github.com/minio/minio/pkg/signature"
|
"github.com/minio/minio/pkg/s3/signature4"
|
||||||
"github.com/minio/minio/pkg/xl/block"
|
"github.com/minio/minio/pkg/xl/block"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -128,7 +128,7 @@ func (xl API) listObjects(bucket, prefix, marker, delimiter string, maxkeys int)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// putObject - put object
|
// putObject - put object
|
||||||
func (xl API) putObject(bucket, object, expectedMD5Sum string, reader io.Reader, size int64, metadata map[string]string, signature *signV4.Signature) (ObjectMetadata, *probe.Error) {
|
func (xl API) putObject(bucket, object, expectedMD5Sum string, reader io.Reader, size int64, metadata map[string]string, signature *signature4.Sign) (ObjectMetadata, *probe.Error) {
|
||||||
if bucket == "" || strings.TrimSpace(bucket) == "" {
|
if bucket == "" || strings.TrimSpace(bucket) == "" {
|
||||||
return ObjectMetadata{}, probe.NewError(InvalidArgument{})
|
return ObjectMetadata{}, probe.NewError(InvalidArgument{})
|
||||||
}
|
}
|
||||||
@ -160,7 +160,7 @@ func (xl API) putObject(bucket, object, expectedMD5Sum string, reader io.Reader,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// putObject - put object
|
// putObject - put object
|
||||||
func (xl API) putObjectPart(bucket, object, expectedMD5Sum, uploadID string, partID int, reader io.Reader, size int64, metadata map[string]string, signature *signV4.Signature) (PartMetadata, *probe.Error) {
|
func (xl API) putObjectPart(bucket, object, expectedMD5Sum, uploadID string, partID int, reader io.Reader, size int64, metadata map[string]string, signature *signature4.Sign) (PartMetadata, *probe.Error) {
|
||||||
if bucket == "" || strings.TrimSpace(bucket) == "" {
|
if bucket == "" || strings.TrimSpace(bucket) == "" {
|
||||||
return PartMetadata{}, probe.NewError(InvalidArgument{})
|
return PartMetadata{}, probe.NewError(InvalidArgument{})
|
||||||
}
|
}
|
||||||
@ -337,7 +337,7 @@ func (xl API) listObjectParts(bucket, object string, resources ObjectResourcesMe
|
|||||||
}
|
}
|
||||||
|
|
||||||
// completeMultipartUpload complete an incomplete multipart upload
|
// completeMultipartUpload complete an incomplete multipart upload
|
||||||
func (xl API) completeMultipartUpload(bucket, object, uploadID string, data io.Reader, signature *signV4.Signature) (ObjectMetadata, *probe.Error) {
|
func (xl API) completeMultipartUpload(bucket, object, uploadID string, data io.Reader, signature *signature4.Sign) (ObjectMetadata, *probe.Error) {
|
||||||
if bucket == "" || strings.TrimSpace(bucket) == "" {
|
if bucket == "" || strings.TrimSpace(bucket) == "" {
|
||||||
return ObjectMetadata{}, probe.NewError(InvalidArgument{})
|
return ObjectMetadata{}, probe.NewError(InvalidArgument{})
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ import (
|
|||||||
"github.com/minio/minio/pkg/crypto/sha256"
|
"github.com/minio/minio/pkg/crypto/sha256"
|
||||||
"github.com/minio/minio/pkg/probe"
|
"github.com/minio/minio/pkg/probe"
|
||||||
"github.com/minio/minio/pkg/quick"
|
"github.com/minio/minio/pkg/quick"
|
||||||
signV4 "github.com/minio/minio/pkg/signature"
|
"github.com/minio/minio/pkg/s3/signature4"
|
||||||
"github.com/minio/minio/pkg/xl/cache/data"
|
"github.com/minio/minio/pkg/xl/cache/data"
|
||||||
"github.com/minio/minio/pkg/xl/cache/metadata"
|
"github.com/minio/minio/pkg/xl/cache/metadata"
|
||||||
)
|
)
|
||||||
@ -267,7 +267,7 @@ func isMD5SumEqual(expectedMD5Sum, actualMD5Sum string) *probe.Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateObject - create an object
|
// CreateObject - create an object
|
||||||
func (xl API) CreateObject(bucket, key, expectedMD5Sum string, size int64, data io.Reader, metadata map[string]string, signature *signV4.Signature) (ObjectMetadata, *probe.Error) {
|
func (xl API) CreateObject(bucket, key, expectedMD5Sum string, size int64, data io.Reader, metadata map[string]string, signature *signature4.Sign) (ObjectMetadata, *probe.Error) {
|
||||||
xl.lock.Lock()
|
xl.lock.Lock()
|
||||||
defer xl.lock.Unlock()
|
defer xl.lock.Unlock()
|
||||||
|
|
||||||
@ -280,7 +280,7 @@ func (xl API) CreateObject(bucket, key, expectedMD5Sum string, size int64, data
|
|||||||
}
|
}
|
||||||
|
|
||||||
// createObject - PUT object to cache buffer
|
// createObject - PUT object to cache buffer
|
||||||
func (xl API) createObject(bucket, key, contentType, expectedMD5Sum string, size int64, data io.Reader, signature *signV4.Signature) (ObjectMetadata, *probe.Error) {
|
func (xl API) createObject(bucket, key, contentType, expectedMD5Sum string, size int64, data io.Reader, signature *signature4.Sign) (ObjectMetadata, *probe.Error) {
|
||||||
if len(xl.config.NodeDiskMap) == 0 {
|
if len(xl.config.NodeDiskMap) == 0 {
|
||||||
if size > int64(xl.config.MaxSize) {
|
if size > int64(xl.config.MaxSize) {
|
||||||
generic := GenericObjectError{Bucket: bucket, Object: key}
|
generic := GenericObjectError{Bucket: bucket, Object: key}
|
||||||
@ -414,7 +414,7 @@ func (xl API) createObject(bucket, key, contentType, expectedMD5Sum string, size
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MakeBucket - create bucket in cache
|
// MakeBucket - create bucket in cache
|
||||||
func (xl API) MakeBucket(bucketName, acl string, location io.Reader, signature *signV4.Signature) *probe.Error {
|
func (xl API) MakeBucket(bucketName, acl string, location io.Reader, signature *signature4.Sign) *probe.Error {
|
||||||
xl.lock.Lock()
|
xl.lock.Lock()
|
||||||
defer xl.lock.Unlock()
|
defer xl.lock.Unlock()
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ import (
|
|||||||
"github.com/minio/minio-go"
|
"github.com/minio/minio-go"
|
||||||
"github.com/minio/minio/pkg/fs"
|
"github.com/minio/minio/pkg/fs"
|
||||||
"github.com/minio/minio/pkg/probe"
|
"github.com/minio/minio/pkg/probe"
|
||||||
signV4 "github.com/minio/minio/pkg/signature"
|
"github.com/minio/minio/pkg/s3/signature4"
|
||||||
)
|
)
|
||||||
|
|
||||||
// storageAPI container for S3 compatible API.
|
// storageAPI container for S3 compatible API.
|
||||||
@ -37,7 +37,7 @@ type storageAPI struct {
|
|||||||
// Filesystem instance.
|
// Filesystem instance.
|
||||||
Filesystem fs.Filesystem
|
Filesystem fs.Filesystem
|
||||||
// Signature instance.
|
// Signature instance.
|
||||||
Signature *signV4.Signature
|
Signature *signature4.Sign
|
||||||
// Region instance.
|
// Region instance.
|
||||||
Region string
|
Region string
|
||||||
}
|
}
|
||||||
@ -141,7 +141,7 @@ func initAPI(conf cloudServerConfig) storageAPI {
|
|||||||
fs, err := fs.New(conf.Path, conf.MinFreeDisk)
|
fs, err := fs.New(conf.Path, conf.MinFreeDisk)
|
||||||
fatalIf(err.Trace(), "Initializing filesystem failed.", nil)
|
fatalIf(err.Trace(), "Initializing filesystem failed.", nil)
|
||||||
|
|
||||||
sign, err := signV4.New(conf.AccessKeyID, conf.SecretAccessKey, conf.Region)
|
sign, err := signature4.New(conf.AccessKeyID, conf.SecretAccessKey, conf.Region)
|
||||||
fatalIf(err.Trace(conf.AccessKeyID, conf.SecretAccessKey, conf.Region), "Initializing signature version '4' failed.", nil)
|
fatalIf(err.Trace(conf.AccessKeyID, conf.SecretAccessKey, conf.Region), "Initializing signature version '4' failed.", nil)
|
||||||
|
|
||||||
return storageAPI{
|
return storageAPI{
|
||||||
|
94
signature.go
94
signature.go
@ -1,94 +0,0 @@
|
|||||||
/*
|
|
||||||
* Minio Cloud Storage, (C) 2015, 2016 Minio, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/hex"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
signV4 "github.com/minio/minio/pkg/signature"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Verify if request has JWT.
|
|
||||||
func isRequestJWT(r *http.Request) bool {
|
|
||||||
if _, ok := r.Header["Authorization"]; ok {
|
|
||||||
if strings.HasPrefix(r.Header.Get("Authorization"), jwtAlgorithm) {
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify if request has AWS Signature Version '4'.
|
|
||||||
func isRequestSignatureV4(r *http.Request) bool {
|
|
||||||
if _, ok := r.Header["Authorization"]; ok {
|
|
||||||
if strings.HasPrefix(r.Header.Get("Authorization"), signV4Algorithm) {
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify if request has AWS Presignature Version '4'.
|
|
||||||
func isRequestPresignedSignatureV4(r *http.Request) bool {
|
|
||||||
if _, ok := r.URL.Query()["X-Amz-Credential"]; ok {
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify if request has AWS Post policy Signature Version '4'.
|
|
||||||
func isRequestPostPolicySignatureV4(r *http.Request) bool {
|
|
||||||
if _, ok := r.Header["Content-Type"]; ok {
|
|
||||||
if strings.Contains(r.Header.Get("Content-Type"), "multipart/form-data") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify if request requires ACL check.
|
|
||||||
func isRequestRequiresACLCheck(r *http.Request) bool {
|
|
||||||
if isRequestSignatureV4(r) || isRequestPresignedSignatureV4(r) || isRequestPostPolicySignatureV4(r) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify if request has valid AWS Signature Version '4'.
|
|
||||||
func isSignV4ReqAuthenticated(sign *signV4.Signature, r *http.Request) bool {
|
|
||||||
auth := sign.SetHTTPRequestToVerify(r)
|
|
||||||
if isRequestSignatureV4(r) {
|
|
||||||
dummyPayload := sha256.Sum256([]byte(""))
|
|
||||||
ok, err := auth.DoesSignatureMatch(hex.EncodeToString(dummyPayload[:]))
|
|
||||||
if err != nil {
|
|
||||||
errorIf(err.Trace(), "Signature verification failed.", nil)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return ok
|
|
||||||
} else if isRequestPresignedSignatureV4(r) {
|
|
||||||
ok, err := auth.DoesPresignedSignatureMatch()
|
|
||||||
if err != nil {
|
|
||||||
errorIf(err.Trace(), "Presigned signature verification failed.", nil)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user