Skip to content

Commit

Permalink
Update AWS auth backend iam_request_headers to be TypeHeader (#5320)
Browse files Browse the repository at this point in the history
Update AWS Auth backend to use TypeHeader for iam request headers

- Remove parseIamRequestHeaders function and test, no longer needed with new TypeHeader
- Update AWS auth login docs
  • Loading branch information
catsby authored Sep 12, 2018
1 parent 25cb22f commit d070b36
Show file tree
Hide file tree
Showing 4 changed files with 259 additions and 104 deletions.
7 changes: 4 additions & 3 deletions builtin/credential/aws/backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ import (
logicaltest "github.com/hashicorp/vault/logical/testing"
)

const testVaultHeaderValue = "VaultAcceptanceTesting"
const testValidRoleName = "valid-role"
const testInvalidRoleName = "invalid-role"

func TestBackend_CreateParseVerifyRoleTag(t *testing.T) {
// create a backend
config := logical.TestBackendConfig()
Expand Down Expand Up @@ -1510,9 +1514,6 @@ func TestBackendAcc_LoginWithCallerIdentity(t *testing.T) {
// it allows us to login to our role
// 6. Pass in a request that has a validly signed request, asking for
// the other role, ensure it fails
const testVaultHeaderValue = "VaultAcceptanceTesting"
const testValidRoleName = "valid-role"
const testInvalidRoleName = "invalid-role"

clientConfigData := map[string]interface{}{
"iam_server_id_header_value": testVaultHeaderValue,
Expand Down
60 changes: 9 additions & 51 deletions builtin/credential/aws/path_login.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,12 @@ import (
"crypto/subtle"
"crypto/x509"
"encoding/base64"
"encoding/json"
"encoding/pem"
"encoding/xml"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"reflect"
"regexp"
"strings"
"time"
Expand Down Expand Up @@ -89,10 +87,11 @@ when using iam auth_type.`,
This must match the request body included in the signature.`,
},
"iam_request_headers": {
Type: framework.TypeString,
Description: `Base64-encoded JSON representation of the request headers when auth_type is
iam. This must at a minimum include the headers over
which AWS has included a signature.`,
Type: framework.TypeHeader,
Description: `Key/value pairs of headers for use in the
sts:GetCallerIdentity HTTP requests headers when auth_type is iam. Can be either
a Base64-encoded, JSON-serialized string, or a JSON object of key/value pairs.
This must at a minimum include the headers over which AWS has included a signature.`,
},
"identity": {
Type: framework.TypeString,
Expand Down Expand Up @@ -202,7 +201,7 @@ func validateMetadata(clientNonce, pendingTime string, storedIdentity *whitelist
}

// If reauthentication is disabled or if the nonce supplied matches a
// predefied nonce which indicates reauthentication to be disabled,
// predefined nonce which indicates reauthentication to be disabled,
// authentication will not succeed.
if storedIdentity.DisallowReauthentication ||
subtle.ConstantTimeCompare([]byte(reauthenticationDisabledNonce), []byte(clientNonce)) == 1 {
Expand Down Expand Up @@ -1149,17 +1148,10 @@ func (b *backend) pathLoginUpdateIam(ctx context.Context, req *logical.Request,
}
body := string(bodyRaw)

headersB64 := data.Get("iam_request_headers").(string)
if headersB64 == "" {
headers := data.Get("iam_request_headers").(http.Header)
if len(headers) == 0 {
return logical.ErrorResponse("missing iam_request_headers"), nil
}
headers, err := parseIamRequestHeaders(headersB64)
if err != nil {
return logical.ErrorResponse(fmt.Sprintf("Error parsing iam_request_headers: %v", err)), nil
}
if headers == nil {
return logical.ErrorResponse("nil response when parsing iam_request_headers"), nil
}

config, err := b.lockedClientConfigEntry(ctx, req.Storage)
if err != nil {
Expand Down Expand Up @@ -1491,41 +1483,6 @@ func parseGetCallerIdentityResponse(response string) (GetCallerIdentityResponse,
return result, err
}

func parseIamRequestHeaders(headersB64 string) (http.Header, error) {
headersJson, err := base64.StdEncoding.DecodeString(headersB64)
if err != nil {
return nil, fmt.Errorf("failed to base64 decode iam_request_headers")
}
var headersDecoded map[string]interface{}
err = jsonutil.DecodeJSON(headersJson, &headersDecoded)
if err != nil {
return nil, errwrap.Wrapf(fmt.Sprintf("failed to JSON decode iam_request_headers %q: {{err}}", headersJson), err)
}
headers := make(http.Header)
for k, v := range headersDecoded {
switch typedValue := v.(type) {
case string:
headers.Add(k, typedValue)
case json.Number:
headers.Add(k, typedValue.String())
case []interface{}:
for _, individualVal := range typedValue {
switch possibleStrVal := individualVal.(type) {
case string:
headers.Add(k, possibleStrVal)
case json.Number:
headers.Add(k, possibleStrVal.String())
default:
return nil, fmt.Errorf("header %q contains value %q that has type %s, not string", k, individualVal, reflect.TypeOf(individualVal))
}
}
default:
return nil, fmt.Errorf("header %q value %q has type %s, not string or []interface", k, typedValue, reflect.TypeOf(v))
}
}
return headers, nil
}

func submitCallerIdentityRequest(method, endpoint string, parsedUrl *url.URL, body string, headers http.Header) (*GetCallerIdentityResult, error) {
// NOTE: We need to ensure we're calling STS, instead of acting as an unintended network proxy
// The protection against this is that this method will only call the endpoint specified in the
Expand All @@ -1536,6 +1493,7 @@ func submitCallerIdentityRequest(method, endpoint string, parsedUrl *url.URL, bo
client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
}

response, err := client.Do(request)
if err != nil {
return nil, errwrap.Wrapf("error making request: {{err}}", err)
Expand Down
Loading

0 comments on commit d070b36

Please sign in to comment.