Skip to content

Commit

Permalink
Merge pull request #1 from stevenh/s3-aws4
Browse files Browse the repository at this point in the history
Fully implement AWS4 signing support
  • Loading branch information
stevenh committed Jul 21, 2015
2 parents 50f393d + 3532817 commit 34a4365
Show file tree
Hide file tree
Showing 29 changed files with 536 additions and 421 deletions.
7 changes: 4 additions & 3 deletions autoscaling/autoscaling.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,9 @@ func (as *AutoScaling) query(params map[string]string, resp interface{}) error {
hreq.Header.Set("X-Amz-Security-Token", token)
}

signer := aws.NewV4Signer(as.Auth, "autoscaling", as.Region)
signer.Sign(hreq)
if err = aws.SignV4(hreq, as.Auth, "autoscaling", as.Region.Name); err != nil {
return err
}

if debug {
log.Printf("%v -> {\n", hreq)
Expand All @@ -104,7 +105,7 @@ func (as *AutoScaling) query(params map[string]string, resp interface{}) error {
log.Printf("response:\n")
log.Printf("%v\n}\n", string(dump))
}
if r.StatusCode != 200 {
if r.StatusCode != http.StatusOK {
return buildError(r)
}
err = xml.NewDecoder(r.Body).Decode(resp)
Expand Down
89 changes: 35 additions & 54 deletions aws/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,6 @@ import (
"github.com/vaughan0/go-ini"
)

// Defines the valid signers
const (
V2Signature = iota
V4Signature = iota
Route53Signature = iota
)

// Defines the service endpoint and correct Signer implementation to use
// to sign requests for this endpoint
type ServiceInfo struct {
Endpoint string
Signer uint
}

// Region defines the URLs where AWS services may be accessed.
//
// See http://goo.gl/d8BP1 for more details.
Expand All @@ -54,12 +40,13 @@ type Region struct {
IAMEndpoint string
ELBEndpoint string
DynamoDBEndpoint string
CloudWatchServicepoint ServiceInfo
CloudWatchEndpoint string
AutoScalingEndpoint string
RDSEndpoint ServiceInfo
RDSEndpoint string
STSEndpoint string
CloudFormationEndpoint string
ECSEndpoint string
Sign SignerFunc
}

var Regions = map[string]Region{
Expand All @@ -76,14 +63,6 @@ var Regions = map[string]Region{
CNNorth.Name: CNNorth,
}

// Designates a signer interface suitable for signing AWS requests, params
// should be appropriately encoded for the request before signing.
//
// A signer should be initialized with Auth and the appropriate endpoint.
type Signer interface {
Sign(method, path string, params map[string]string)
}

// An AWS Service interface with the API to query the AWS service
//
// Supplied as an easy way to mock out service calls during testing.
Expand All @@ -99,8 +78,10 @@ type AWSService interface {
// Implements a Server Query/Post API to easily query AWS services and build
// errors when desired
type Service struct {
service ServiceInfo
signer Signer
auth Auth
endpoint string
serviceName string
region Region
}

// Create a base set of params for an action
Expand All @@ -110,41 +91,29 @@ func MakeParams(action string) map[string]string {
return params
}

// Create a new AWS server to handle making requests
func NewService(auth Auth, service ServiceInfo) (s *Service, err error) {
var signer Signer
switch service.Signer {
case V2Signature:
signer, err = NewV2Signer(auth, service)
// case V4Signature:
// signer, err = NewV4Signer(auth, service, Regions["eu-west-1"])
default:
err = fmt.Errorf("Unsupported signer for service")
}
if err != nil {
return
}
s = &Service{service: service, signer: signer}
return
// Create a new AWS service to handle making requests
func NewService(auth Auth, endpoint string, region Region, serviceName string) (*Service, error) {
return &Service{auth: auth, endpoint: endpoint, region: region, serviceName: serviceName}, nil
}

func (s *Service) Query(method, path string, params map[string]string) (resp *http.Response, err error) {
func (s *Service) Query(method, path string, params map[string]string) (*http.Response, error) {
params["Timestamp"] = time.Now().UTC().Format(time.RFC3339)
u, err := url.Parse(s.service.Endpoint)

req, err := NewRequest(method, s.endpoint, path, params)
if err != nil {
return nil, err
}
u.Path = path

s.signer.Sign(method, path, params)
if method == "GET" {
u.RawQuery = multimap(params).Encode()
resp, err = http.Get(u.String())
} else if method == "POST" {
resp, err = http.PostForm(u.String(), multimap(params))
if s.region.Sign == nil {
// Default to V2 signature to maintain compatibility
err = SignV2(req, s.auth, s.serviceName)
} else {
err = s.region.Sign(req, s.auth, s.serviceName)
}
if err != nil {
return nil, err
}

return
return http.DefaultClient.Do(req)
}

func (s *Service) BuildError(r *http.Response) error {
Expand Down Expand Up @@ -259,7 +228,7 @@ func GetMetaData(path string) (contents []byte, err error) {
}
defer resp.Body.Close()

if resp.StatusCode != 200 {
if resp.StatusCode != http.StatusOK {
err = fmt.Errorf("Code %d returned for url %s", resp.StatusCode, url)
return
}
Expand Down Expand Up @@ -429,3 +398,15 @@ func Encode(s string) string {
}
return string(e[:ei])
}

// NewRequest builds a valid request for the given endpoint, method, path and params
func NewRequest(method, endpoint, path string, params map[string]string) (*http.Request, error) {
req, err := http.NewRequest(method, endpoint+path, nil)
if err != nil {
return nil, err
}

req.URL.RawQuery = multimap(params).Encode()

return req, nil
}
2 changes: 1 addition & 1 deletion aws/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ func (s *V4Signer) RequestTime(req *http.Request) time.Time {
return s.requestTime(req)
}

func (s *V4Signer) CanonicalRequest(req *http.Request) string {
func (s *V4Signer) CanonicalRequest(req *http.Request) (string, error) {
return s.canonicalRequest(req)
}

Expand Down
57 changes: 34 additions & 23 deletions aws/regions.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ var USGovWest = Region{
"https://iam.us-gov.amazonaws.com",
"https://elasticloadbalancing.us-gov-west-1.amazonaws.com",
"https://dynamodb.us-gov-west-1.amazonaws.com",
ServiceInfo{"https://monitoring.us-gov-west-1.amazonaws.com", V2Signature},
"https://monitoring.us-gov-west-1.amazonaws.com",
"https://autoscaling.us-gov-west-1.amazonaws.com",
ServiceInfo{"https://rds.us-gov-west-1.amazonaws.com", V2Signature},
"https://rds.us-gov-west-1.amazonaws.com",
"https://sts.amazonaws.com",
"https://cloudformation.us-gov-west-1.amazonaws.com",
"https://ecs.us-gov-west-1.amazonaws.com",
SignV2,
}

var USEast = Region{
Expand All @@ -36,12 +37,13 @@ var USEast = Region{
"https://iam.amazonaws.com",
"https://elasticloadbalancing.us-east-1.amazonaws.com",
"https://dynamodb.us-east-1.amazonaws.com",
ServiceInfo{"https://monitoring.us-east-1.amazonaws.com", V2Signature},
"https://monitoring.us-east-1.amazonaws.com",
"https://autoscaling.us-east-1.amazonaws.com",
ServiceInfo{"https://rds.us-east-1.amazonaws.com", V2Signature},
"https://rds.us-east-1.amazonaws.com",
"https://sts.amazonaws.com",
"https://cloudformation.us-east-1.amazonaws.com",
"https://ecs.us-east-1.amazonaws.com",
SignV2,
}

var USWest = Region{
Expand All @@ -58,12 +60,13 @@ var USWest = Region{
"https://iam.amazonaws.com",
"https://elasticloadbalancing.us-west-1.amazonaws.com",
"https://dynamodb.us-west-1.amazonaws.com",
ServiceInfo{"https://monitoring.us-west-1.amazonaws.com", V2Signature},
"https://monitoring.us-west-1.amazonaws.com",
"https://autoscaling.us-west-1.amazonaws.com",
ServiceInfo{"https://rds.us-west-1.amazonaws.com", V2Signature},
"https://rds.us-west-1.amazonaws.com",
"https://sts.amazonaws.com",
"https://cloudformation.us-west-1.amazonaws.com",
"https://ecs.us-west-1.amazonaws.com",
SignV2,
}

var USWest2 = Region{
Expand All @@ -80,12 +83,13 @@ var USWest2 = Region{
"https://iam.amazonaws.com",
"https://elasticloadbalancing.us-west-2.amazonaws.com",
"https://dynamodb.us-west-2.amazonaws.com",
ServiceInfo{"https://monitoring.us-west-2.amazonaws.com", V2Signature},
"https://monitoring.us-west-2.amazonaws.com",
"https://autoscaling.us-west-2.amazonaws.com",
ServiceInfo{"https://rds.us-west-2.amazonaws.com", V2Signature},
"https://rds.us-west-2.amazonaws.com",
"https://sts.amazonaws.com",
"https://cloudformation.us-west-2.amazonaws.com",
"https://ecs.us-west-2.amazonaws.com",
SignV2,
}

var EUWest = Region{
Expand All @@ -102,18 +106,19 @@ var EUWest = Region{
"https://iam.amazonaws.com",
"https://elasticloadbalancing.eu-west-1.amazonaws.com",
"https://dynamodb.eu-west-1.amazonaws.com",
ServiceInfo{"https://monitoring.eu-west-1.amazonaws.com", V2Signature},
"https://monitoring.eu-west-1.amazonaws.com",
"https://autoscaling.eu-west-1.amazonaws.com",
ServiceInfo{"https://rds.eu-west-1.amazonaws.com", V2Signature},
"https://rds.eu-west-1.amazonaws.com",
"https://sts.amazonaws.com",
"https://cloudformation.eu-west-1.amazonaws.com",
"https://ecs.eu-west-1.amazonaws.com",
SignV2,
}

var EUCentral = Region{
"eu-central-1",
"https://ec2.eu-central-1.amazonaws.com",
"https://s3-eu-central-1.amazonaws.com",
"https://s3.eu-central-1.amazonaws.com", // s3.eu.. not s3-eu.. as thats what the SSL Cert matches
"",
true,
true,
Expand All @@ -124,12 +129,13 @@ var EUCentral = Region{
"https://iam.amazonaws.com",
"https://elasticloadbalancing.eu-central-1.amazonaws.com",
"https://dynamodb.eu-central-1.amazonaws.com",
ServiceInfo{"https://monitoring.eu-central-1.amazonaws.com", V2Signature},
"https://monitoring.eu-central-1.amazonaws.com",
"https://autoscaling.eu-central-1.amazonaws.com",
ServiceInfo{"https://rds.eu-central-1.amazonaws.com", V2Signature},
"https://rds.eu-central-1.amazonaws.com",
"https://sts.amazonaws.com",
"https://cloudformation.eu-central-1.amazonaws.com",
"https://ecs.eu-central-1.amazonaws.com",
SignV4Region("eu-central-1"),
}

var APSoutheast = Region{
Expand All @@ -146,12 +152,13 @@ var APSoutheast = Region{
"https://iam.amazonaws.com",
"https://elasticloadbalancing.ap-southeast-1.amazonaws.com",
"https://dynamodb.ap-southeast-1.amazonaws.com",
ServiceInfo{"https://monitoring.ap-southeast-1.amazonaws.com", V2Signature},
"https://monitoring.ap-southeast-1.amazonaws.com",
"https://autoscaling.ap-southeast-1.amazonaws.com",
ServiceInfo{"https://rds.ap-southeast-1.amazonaws.com", V2Signature},
"https://rds.ap-southeast-1.amazonaws.com",
"https://sts.amazonaws.com",
"https://cloudformation.ap-southeast-1.amazonaws.com",
"https://ecs.ap-southeast-1.amazonaws.com",
SignV2,
}

var APSoutheast2 = Region{
Expand All @@ -168,12 +175,13 @@ var APSoutheast2 = Region{
"https://iam.amazonaws.com",
"https://elasticloadbalancing.ap-southeast-2.amazonaws.com",
"https://dynamodb.ap-southeast-2.amazonaws.com",
ServiceInfo{"https://monitoring.ap-southeast-2.amazonaws.com", V2Signature},
"https://monitoring.ap-southeast-2.amazonaws.com",
"https://autoscaling.ap-southeast-2.amazonaws.com",
ServiceInfo{"https://rds.ap-southeast-2.amazonaws.com", V2Signature},
"https://rds.ap-southeast-2.amazonaws.com",
"https://sts.amazonaws.com",
"https://cloudformation.ap-southeast-2.amazonaws.com",
"https://ecs.ap-southeast-2.amazonaws.com",
SignV2,
}

var APNortheast = Region{
Expand All @@ -190,12 +198,13 @@ var APNortheast = Region{
"https://iam.amazonaws.com",
"https://elasticloadbalancing.ap-northeast-1.amazonaws.com",
"https://dynamodb.ap-northeast-1.amazonaws.com",
ServiceInfo{"https://monitoring.ap-northeast-1.amazonaws.com", V2Signature},
"https://monitoring.ap-northeast-1.amazonaws.com",
"https://autoscaling.ap-northeast-1.amazonaws.com",
ServiceInfo{"https://rds.ap-northeast-1.amazonaws.com", V2Signature},
"https://rds.ap-northeast-1.amazonaws.com",
"https://sts.amazonaws.com",
"https://cloudformation.ap-northeast-1.amazonaws.com",
"https://ecs.ap-northeast-1.amazonaws.com",
SignV2,
}

var SAEast = Region{
Expand All @@ -212,12 +221,13 @@ var SAEast = Region{
"https://iam.amazonaws.com",
"https://elasticloadbalancing.sa-east-1.amazonaws.com",
"https://dynamodb.sa-east-1.amazonaws.com",
ServiceInfo{"https://monitoring.sa-east-1.amazonaws.com", V2Signature},
"https://monitoring.sa-east-1.amazonaws.com",
"https://autoscaling.sa-east-1.amazonaws.com",
ServiceInfo{"https://rds.sa-east-1.amazonaws.com", V2Signature},
"https://rds.sa-east-1.amazonaws.com",
"https://sts.amazonaws.com",
"https://cloudformation.sa-east-1.amazonaws.com",
"https://ecs.sa-east-1.amazonaws.com",
SignV4Region("sa-east-1"),
}

var CNNorth = Region{
Expand All @@ -234,10 +244,11 @@ var CNNorth = Region{
"https://iam.cn-north-1.amazonaws.com.cn",
"https://elasticloadbalancing.cn-north-1.amazonaws.com.cn",
"https://dynamodb.cn-north-1.amazonaws.com.cn",
ServiceInfo{"https://monitoring.cn-north-1.amazonaws.com.cn", V4Signature},
"https://monitoring.cn-north-1.amazonaws.com.cn",
"https://autoscaling.cn-north-1.amazonaws.com.cn",
ServiceInfo{"https://rds.cn-north-1.amazonaws.com.cn", V4Signature},
"https://rds.cn-north-1.amazonaws.com.cn",
"https://sts.cn-north-1.amazonaws.com.cn",
"https://cloudformation.cn-north-1.amazonaws.com.cn",
"https://ecs.cn-north-1.amazonaws.com.cn",
SignV4Region("cn-north-1"),
}
Loading

0 comments on commit 34a4365

Please sign in to comment.