Skip to content

Commit

Permalink
Additional functionality to normalize/sort policy to match what AWS sets
Browse files Browse the repository at this point in the history
  • Loading branch information
Chris Marchesi committed Dec 12, 2015
1 parent 981add7 commit 30b11d1
Showing 1 changed file with 61 additions and 0 deletions.
61 changes: 61 additions & 0 deletions builtin/providers/aws/resource_aws_s3_bucket.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"log"
"sort"

"github.com/hashicorp/terraform/helper/schema"

Expand Down Expand Up @@ -718,6 +719,8 @@ func normalizeJson(jsonString interface{}) string {
if err != nil {
return fmt.Sprintf("Error parsing JSON: %s", err)
}
normalizePolicyStatements(j)
sortJSONArray(j)
b, _ := json.Marshal(j)
return string(b[:])
}
Expand All @@ -735,3 +738,61 @@ func normalizeRegion(region string) string {
type S3Website struct {
Endpoint, Domain string
}

// S3 bucket policy parsing logic - this is necessary as AWS sorts some
// policy sections (ie: Action lists in policy statements), but Unmarshal/
// Marshal does not.

// multiArray allows us to define a slice of interfaces to sort, versus
// a slice of strings.
type multiArray []interface{}

func (a multiArray) Len() int { return len(a) }
func (a multiArray) Swap(i, j int) { a[i], a[j] = a[j], a[i] }

// multiArray.Less() is implemented to sort only on neighboring string values,
// so if the array contains non-string values, this will give unstable results.
func (a multiArray) Less(i, j int) bool {
switch ival := a[i].(type) {
case string:
if jval, ok := a[j].(string); ok {
log.Printf("[DEBUG] sort: %s < %s", ival, jval)
return ival < jval
}
}
return false
}

// sortJsonArray recursively looks for arrays and sorts them.
func sortJSONArray(d interface{}) {
switch e := d.(type) {
case map[string]interface{}:
for k, v := range e {
log.Printf("[DEBUG] recursing into %s", k)
sortJSONArray(v)
}
case []interface{}:
log.Printf("Found array, length %d", len(e))
sort.Sort(multiArray(e))
for _, v := range e {
log.Printf("[DEBUG] recursing into %s", v)
sortJSONArray(v)
}
}
}

// normalizePolicyStatements performs the following fixups to a policy:
// * Populate policy statement's Sid as empty if it is not present
// * Set action's value to a single string if only one element is present
func normalizePolicyStatements(policy map[string]interface{}) {
for _, v := range policy["Statement"].([]interface{}) {
if _, ok := v.(map[string]interface{})["Sid"]; ok == false {
v.(map[string]interface{})["Sid"] = ""
}
if actions, ok := v.(map[string]interface{})["Action"].([]interface{}); ok {
if len(actions) < 2 {
v.(map[string]interface{})["Action"] = actions[0].(string)
}
}
}
}

0 comments on commit 30b11d1

Please sign in to comment.