github.com/minio/minio-go/v6@v6.0.57/api-presigned.go (about)

     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  	"errors"
    22  	"net/http"
    23  	"net/url"
    24  	"time"
    25  
    26  	"github.com/minio/minio-go/v6/pkg/s3utils"
    27  	"github.com/minio/minio-go/v6/pkg/signer"
    28  )
    29  
    30  // presignURL - Returns a presigned URL for an input 'method'.
    31  // Expires maximum is 7days - ie. 604800 and minimum is 1.
    32  func (c Client) presignURL(method string, bucketName string, objectName string, expires time.Duration, reqParams url.Values) (u *url.URL, err error) {
    33  	// Input validation.
    34  	if method == "" {
    35  		return nil, ErrInvalidArgument("method cannot be empty.")
    36  	}
    37  	if err = s3utils.CheckValidBucketName(bucketName); err != nil {
    38  		return nil, err
    39  	}
    40  	if err = isValidExpiry(expires); err != nil {
    41  		return nil, err
    42  	}
    43  
    44  	// Convert expires into seconds.
    45  	expireSeconds := int64(expires / time.Second)
    46  	reqMetadata := requestMetadata{
    47  		presignURL:  true,
    48  		bucketName:  bucketName,
    49  		objectName:  objectName,
    50  		expires:     expireSeconds,
    51  		queryValues: reqParams,
    52  	}
    53  
    54  	// Instantiate a new request.
    55  	// Since expires is set newRequest will presign the request.
    56  	var req *http.Request
    57  	if req, err = c.newRequest(method, reqMetadata); err != nil {
    58  		return nil, err
    59  	}
    60  	return req.URL, nil
    61  }
    62  
    63  // PresignedGetObject - Returns a presigned URL to access an object
    64  // data without credentials. URL can have a maximum expiry of
    65  // upto 7days or a minimum of 1sec. Additionally you can override
    66  // a set of response headers using the query parameters.
    67  func (c Client) PresignedGetObject(bucketName string, objectName string, expires time.Duration, reqParams url.Values) (u *url.URL, err error) {
    68  	if err = s3utils.CheckValidObjectName(objectName); err != nil {
    69  		return nil, err
    70  	}
    71  	return c.presignURL("GET", bucketName, objectName, expires, reqParams)
    72  }
    73  
    74  // PresignedHeadObject - Returns a presigned URL to access object
    75  // metadata without credentials. URL can have a maximum expiry of
    76  // upto 7days or a minimum of 1sec. Additionally you can override
    77  // a set of response headers using the query parameters.
    78  func (c Client) PresignedHeadObject(bucketName string, objectName string, expires time.Duration, reqParams url.Values) (u *url.URL, err error) {
    79  	if err = s3utils.CheckValidObjectName(objectName); err != nil {
    80  		return nil, err
    81  	}
    82  	return c.presignURL("HEAD", bucketName, objectName, expires, reqParams)
    83  }
    84  
    85  // PresignedPutObject - Returns a presigned URL to upload an object
    86  // without credentials. URL can have a maximum expiry of upto 7days
    87  // or a minimum of 1sec.
    88  func (c Client) PresignedPutObject(bucketName string, objectName string, expires time.Duration) (u *url.URL, err error) {
    89  	if err = s3utils.CheckValidObjectName(objectName); err != nil {
    90  		return nil, err
    91  	}
    92  	return c.presignURL("PUT", bucketName, objectName, expires, nil)
    93  }
    94  
    95  // Presign - returns a presigned URL for any http method of your choice
    96  // along with custom request params. URL can have a maximum expiry of
    97  // upto 7days or a minimum of 1sec.
    98  func (c Client) Presign(method string, bucketName string, objectName string, expires time.Duration, reqParams url.Values) (u *url.URL, err error) {
    99  	return c.presignURL(method, bucketName, objectName, expires, reqParams)
   100  }
   101  
   102  // PresignedPostPolicy - Returns POST urlString, form data to upload an object.
   103  func (c Client) PresignedPostPolicy(p *PostPolicy) (u *url.URL, formData map[string]string, err error) {
   104  	// Validate input arguments.
   105  	if p.expiration.IsZero() {
   106  		return nil, nil, errors.New("Expiration time must be specified")
   107  	}
   108  	if _, ok := p.formData["key"]; !ok {
   109  		return nil, nil, errors.New("object key must be specified")
   110  	}
   111  	if _, ok := p.formData["bucket"]; !ok {
   112  		return nil, nil, errors.New("bucket name must be specified")
   113  	}
   114  
   115  	bucketName := p.formData["bucket"]
   116  	// Fetch the bucket location.
   117  	location, err := c.getBucketLocation(bucketName)
   118  	if err != nil {
   119  		return nil, nil, err
   120  	}
   121  
   122  	isVirtualHost := c.isVirtualHostStyleRequest(*c.endpointURL, bucketName)
   123  
   124  	u, err = c.makeTargetURL(bucketName, "", location, isVirtualHost, nil)
   125  	if err != nil {
   126  		return nil, nil, err
   127  	}
   128  
   129  	// Get credentials from the configured credentials provider.
   130  	credValues, err := c.credsProvider.Get()
   131  	if err != nil {
   132  		return nil, nil, err
   133  	}
   134  
   135  	var (
   136  		signerType      = credValues.SignerType
   137  		sessionToken    = credValues.SessionToken
   138  		accessKeyID     = credValues.AccessKeyID
   139  		secretAccessKey = credValues.SecretAccessKey
   140  	)
   141  
   142  	if signerType.IsAnonymous() {
   143  		return nil, nil, ErrInvalidArgument("Presigned operations are not supported for anonymous credentials")
   144  	}
   145  
   146  	// Keep time.
   147  	t := time.Now().UTC()
   148  	// For signature version '2' handle here.
   149  	if signerType.IsV2() {
   150  		policyBase64 := p.base64()
   151  		p.formData["policy"] = policyBase64
   152  		// For Google endpoint set this value to be 'GoogleAccessId'.
   153  		if s3utils.IsGoogleEndpoint(*c.endpointURL) {
   154  			p.formData["GoogleAccessId"] = accessKeyID
   155  		} else {
   156  			// For all other endpoints set this value to be 'AWSAccessKeyId'.
   157  			p.formData["AWSAccessKeyId"] = accessKeyID
   158  		}
   159  		// Sign the policy.
   160  		p.formData["signature"] = signer.PostPresignSignatureV2(policyBase64, secretAccessKey)
   161  		return u, p.formData, nil
   162  	}
   163  
   164  	// Add date policy.
   165  	if err = p.addNewPolicy(policyCondition{
   166  		matchType: "eq",
   167  		condition: "$x-amz-date",
   168  		value:     t.Format(iso8601DateFormat),
   169  	}); err != nil {
   170  		return nil, nil, err
   171  	}
   172  
   173  	// Add algorithm policy.
   174  	if err = p.addNewPolicy(policyCondition{
   175  		matchType: "eq",
   176  		condition: "$x-amz-algorithm",
   177  		value:     signV4Algorithm,
   178  	}); err != nil {
   179  		return nil, nil, err
   180  	}
   181  
   182  	// Add a credential policy.
   183  	credential := signer.GetCredential(accessKeyID, location, t, signer.ServiceTypeS3)
   184  	if err = p.addNewPolicy(policyCondition{
   185  		matchType: "eq",
   186  		condition: "$x-amz-credential",
   187  		value:     credential,
   188  	}); err != nil {
   189  		return nil, nil, err
   190  	}
   191  
   192  	if sessionToken != "" {
   193  		if err = p.addNewPolicy(policyCondition{
   194  			matchType: "eq",
   195  			condition: "$x-amz-security-token",
   196  			value:     sessionToken,
   197  		}); err != nil {
   198  			return nil, nil, err
   199  		}
   200  	}
   201  
   202  	// Get base64 encoded policy.
   203  	policyBase64 := p.base64()
   204  
   205  	// Fill in the form data.
   206  	p.formData["policy"] = policyBase64
   207  	p.formData["x-amz-algorithm"] = signV4Algorithm
   208  	p.formData["x-amz-credential"] = credential
   209  	p.formData["x-amz-date"] = t.Format(iso8601DateFormat)
   210  	if sessionToken != "" {
   211  		p.formData["x-amz-security-token"] = sessionToken
   212  	}
   213  	p.formData["x-amz-signature"] = signer.PostPresignSignatureV4(policyBase64, t, secretAccessKey, location)
   214  	return u, p.formData, nil
   215  }