gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

api-presigned.go (8141B)


      1 /*
      2  * MinIO Go Library for Amazon S3 Compatible Cloud Storage
      3  * Copyright 2015-2017 MinIO, Inc.
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 package minio
     19 
     20 import (
     21 	"context"
     22 	"errors"
     23 	"net/http"
     24 	"net/url"
     25 	"time"
     26 
     27 	"github.com/minio/minio-go/v7/pkg/s3utils"
     28 	"github.com/minio/minio-go/v7/pkg/signer"
     29 )
     30 
     31 // presignURL - Returns a presigned URL for an input 'method'.
     32 // Expires maximum is 7days - ie. 604800 and minimum is 1.
     33 func (c *Client) presignURL(ctx context.Context, method string, bucketName string, objectName string, expires time.Duration, reqParams url.Values, extraHeaders http.Header) (u *url.URL, err error) {
     34 	// Input validation.
     35 	if method == "" {
     36 		return nil, errInvalidArgument("method cannot be empty.")
     37 	}
     38 	if err = s3utils.CheckValidBucketName(bucketName); err != nil {
     39 		return nil, err
     40 	}
     41 	if err = isValidExpiry(expires); err != nil {
     42 		return nil, err
     43 	}
     44 
     45 	// Convert expires into seconds.
     46 	expireSeconds := int64(expires / time.Second)
     47 	reqMetadata := requestMetadata{
     48 		presignURL:         true,
     49 		bucketName:         bucketName,
     50 		objectName:         objectName,
     51 		expires:            expireSeconds,
     52 		queryValues:        reqParams,
     53 		extraPresignHeader: extraHeaders,
     54 	}
     55 
     56 	// Instantiate a new request.
     57 	// Since expires is set newRequest will presign the request.
     58 	var req *http.Request
     59 	if req, err = c.newRequest(ctx, method, reqMetadata); err != nil {
     60 		return nil, err
     61 	}
     62 	return req.URL, nil
     63 }
     64 
     65 // PresignedGetObject - Returns a presigned URL to access an object
     66 // data without credentials. URL can have a maximum expiry of
     67 // upto 7days or a minimum of 1sec. Additionally you can override
     68 // a set of response headers using the query parameters.
     69 func (c *Client) PresignedGetObject(ctx context.Context, bucketName string, objectName string, expires time.Duration, reqParams url.Values) (u *url.URL, err error) {
     70 	if err = s3utils.CheckValidObjectName(objectName); err != nil {
     71 		return nil, err
     72 	}
     73 	return c.presignURL(ctx, http.MethodGet, bucketName, objectName, expires, reqParams, nil)
     74 }
     75 
     76 // PresignedHeadObject - Returns a presigned URL to access
     77 // object metadata without credentials. URL can have a maximum expiry
     78 // of upto 7days or a minimum of 1sec. Additionally you can override
     79 // a set of response headers using the query parameters.
     80 func (c *Client) PresignedHeadObject(ctx context.Context, bucketName string, objectName string, expires time.Duration, reqParams url.Values) (u *url.URL, err error) {
     81 	if err = s3utils.CheckValidObjectName(objectName); err != nil {
     82 		return nil, err
     83 	}
     84 	return c.presignURL(ctx, http.MethodHead, bucketName, objectName, expires, reqParams, nil)
     85 }
     86 
     87 // PresignedPutObject - Returns a presigned URL to upload an object
     88 // without credentials. URL can have a maximum expiry of upto 7days
     89 // or a minimum of 1sec.
     90 func (c *Client) PresignedPutObject(ctx context.Context, bucketName string, objectName string, expires time.Duration) (u *url.URL, err error) {
     91 	if err = s3utils.CheckValidObjectName(objectName); err != nil {
     92 		return nil, err
     93 	}
     94 	return c.presignURL(ctx, http.MethodPut, bucketName, objectName, expires, nil, nil)
     95 }
     96 
     97 // PresignHeader - similar to Presign() but allows including HTTP headers that
     98 // will be used to build the signature. The request using the resulting URL will
     99 // need to have the exact same headers to be added for signature validation to
    100 // pass.
    101 //
    102 // FIXME: The extra header parameter should be included in Presign() in the next
    103 // major version bump, and this function should then be deprecated.
    104 func (c *Client) PresignHeader(ctx context.Context, method string, bucketName string, objectName string, expires time.Duration, reqParams url.Values, extraHeaders http.Header) (u *url.URL, err error) {
    105 	return c.presignURL(ctx, method, bucketName, objectName, expires, reqParams, extraHeaders)
    106 }
    107 
    108 // Presign - returns a presigned URL for any http method of your choice along
    109 // with custom request params and extra signed headers. URL can have a maximum
    110 // expiry of upto 7days or a minimum of 1sec.
    111 func (c *Client) Presign(ctx context.Context, method string, bucketName string, objectName string, expires time.Duration, reqParams url.Values) (u *url.URL, err error) {
    112 	return c.presignURL(ctx, method, bucketName, objectName, expires, reqParams, nil)
    113 }
    114 
    115 // PresignedPostPolicy - Returns POST urlString, form data to upload an object.
    116 func (c *Client) PresignedPostPolicy(ctx context.Context, p *PostPolicy) (u *url.URL, formData map[string]string, err error) {
    117 	// Validate input arguments.
    118 	if p.expiration.IsZero() {
    119 		return nil, nil, errors.New("Expiration time must be specified")
    120 	}
    121 	if _, ok := p.formData["key"]; !ok {
    122 		return nil, nil, errors.New("object key must be specified")
    123 	}
    124 	if _, ok := p.formData["bucket"]; !ok {
    125 		return nil, nil, errors.New("bucket name must be specified")
    126 	}
    127 
    128 	bucketName := p.formData["bucket"]
    129 	// Fetch the bucket location.
    130 	location, err := c.getBucketLocation(ctx, bucketName)
    131 	if err != nil {
    132 		return nil, nil, err
    133 	}
    134 
    135 	isVirtualHost := c.isVirtualHostStyleRequest(*c.endpointURL, bucketName)
    136 
    137 	u, err = c.makeTargetURL(bucketName, "", location, isVirtualHost, nil)
    138 	if err != nil {
    139 		return nil, nil, err
    140 	}
    141 
    142 	// Get credentials from the configured credentials provider.
    143 	credValues, err := c.credsProvider.Get()
    144 	if err != nil {
    145 		return nil, nil, err
    146 	}
    147 
    148 	var (
    149 		signerType      = credValues.SignerType
    150 		sessionToken    = credValues.SessionToken
    151 		accessKeyID     = credValues.AccessKeyID
    152 		secretAccessKey = credValues.SecretAccessKey
    153 	)
    154 
    155 	if signerType.IsAnonymous() {
    156 		return nil, nil, errInvalidArgument("Presigned operations are not supported for anonymous credentials")
    157 	}
    158 
    159 	// Keep time.
    160 	t := time.Now().UTC()
    161 	// For signature version '2' handle here.
    162 	if signerType.IsV2() {
    163 		policyBase64 := p.base64()
    164 		p.formData["policy"] = policyBase64
    165 		// For Google endpoint set this value to be 'GoogleAccessId'.
    166 		if s3utils.IsGoogleEndpoint(*c.endpointURL) {
    167 			p.formData["GoogleAccessId"] = accessKeyID
    168 		} else {
    169 			// For all other endpoints set this value to be 'AWSAccessKeyId'.
    170 			p.formData["AWSAccessKeyId"] = accessKeyID
    171 		}
    172 		// Sign the policy.
    173 		p.formData["signature"] = signer.PostPresignSignatureV2(policyBase64, secretAccessKey)
    174 		return u, p.formData, nil
    175 	}
    176 
    177 	// Add date policy.
    178 	if err = p.addNewPolicy(policyCondition{
    179 		matchType: "eq",
    180 		condition: "$x-amz-date",
    181 		value:     t.Format(iso8601DateFormat),
    182 	}); err != nil {
    183 		return nil, nil, err
    184 	}
    185 
    186 	// Add algorithm policy.
    187 	if err = p.addNewPolicy(policyCondition{
    188 		matchType: "eq",
    189 		condition: "$x-amz-algorithm",
    190 		value:     signV4Algorithm,
    191 	}); err != nil {
    192 		return nil, nil, err
    193 	}
    194 
    195 	// Add a credential policy.
    196 	credential := signer.GetCredential(accessKeyID, location, t, signer.ServiceTypeS3)
    197 	if err = p.addNewPolicy(policyCondition{
    198 		matchType: "eq",
    199 		condition: "$x-amz-credential",
    200 		value:     credential,
    201 	}); err != nil {
    202 		return nil, nil, err
    203 	}
    204 
    205 	if sessionToken != "" {
    206 		if err = p.addNewPolicy(policyCondition{
    207 			matchType: "eq",
    208 			condition: "$x-amz-security-token",
    209 			value:     sessionToken,
    210 		}); err != nil {
    211 			return nil, nil, err
    212 		}
    213 	}
    214 
    215 	// Get base64 encoded policy.
    216 	policyBase64 := p.base64()
    217 
    218 	// Fill in the form data.
    219 	p.formData["policy"] = policyBase64
    220 	p.formData["x-amz-algorithm"] = signV4Algorithm
    221 	p.formData["x-amz-credential"] = credential
    222 	p.formData["x-amz-date"] = t.Format(iso8601DateFormat)
    223 	if sessionToken != "" {
    224 		p.formData["x-amz-security-token"] = sessionToken
    225 	}
    226 	p.formData["x-amz-signature"] = signer.PostPresignSignatureV4(policyBase64, t, secretAccessKey, location)
    227 	return u, p.formData, nil
    228 }