From 732d3b511950360eea19267fe2c1b0a6305a49f6 Mon Sep 17 00:00:00 2001 From: Calvin Leung Huang Date: Wed, 3 Jul 2019 17:21:02 -0700 Subject: [PATCH] move ValidateWrappingToken back to wrappingVerificationFunc --- http/handler.go | 19 ++++++++++++++++ http/logical.go | 7 ++++++ vault/request_handling.go | 30 ------------------------- vault/wrapping.go | 46 ++++++++++++++++++++++++--------------- 4 files changed, 54 insertions(+), 48 deletions(-) diff --git a/http/handler.go b/http/handler.go index 92661ed1637d..7a8d2023e871 100644 --- a/http/handler.go +++ b/http/handler.go @@ -295,6 +295,25 @@ func WrapForwardedForHandler(h http.Handler, authorizedAddrs []*sockaddr.SockAdd }) } +// A lookup on a token that is about to expire returns nil, which means by the +// time we can validate a wrapping token lookup will return nil since it will +// be revoked after the call. So we have to do the validation here. +func wrappingVerificationFunc(ctx context.Context, core *vault.Core, req *logical.Request) error { + if req == nil { + return fmt.Errorf("invalid request") + } + + valid, err := core.ValidateWrappingToken(ctx, req) + if err != nil { + return errwrap.Wrapf("error validating wrapping token: {{err}}", err) + } + if !valid { + return fmt.Errorf("wrapping token is not valid or does not exist") + } + + return nil +} + // stripPrefix is a helper to strip a prefix from the path. It will // return false from the second return value if it the prefix doesn't exist. func stripPrefix(prefix, path string) (string, bool) { diff --git a/http/logical.go b/http/logical.go index 50529f945866..6b2d6c8ddc1c 100644 --- a/http/logical.go +++ b/http/logical.go @@ -211,6 +211,13 @@ func handleLogicalInternal(core *vault.Core, injectDataIntoTopLevel bool) http.H // Route the token wrapping request to its respective sys NS case "sys/wrapping/lookup", "sys/wrapping/rewrap", "sys/wrapping/unwrap": r = r.WithContext(newCtx) + if err := wrappingVerificationFunc(r.Context(), core, req); err != nil { + if errwrap.Contains(err, logical.ErrPermissionDenied.Error()) { + respondError(w, http.StatusForbidden, err) + } else { + respondError(w, http.StatusBadRequest, err) + } + } // The -self paths have no meaning outside of the token NS, so // requests for these paths always go to the token NS diff --git a/vault/request_handling.go b/vault/request_handling.go index 7dcfa00fde92..0e3f6d54b934 100644 --- a/vault/request_handling.go +++ b/vault/request_handling.go @@ -584,21 +584,6 @@ func (c *Core) handleRequest(ctx context.Context, req *logical.Request) (retResp return } - // If this is a wrapping request that contains a wrapping token, check for - // token validity. We perform this before c.checkToken since wrapping token - // validation performs a token store lookup, and can potentially modify - // logical.Request's token-related fields. - switch req.Path { - case "sys/wrapping/rewrap", "sys/wrapping/unwrap": - valid, wtAuth, err := c.validateWrappingToken(ctx, req, nonHMACReqDataKeys) - if err != nil { - return nil, wtAuth, errwrap.Wrapf("error validating wrapping token: {{err}}", err) - } - if !valid { - return logical.ErrorResponse(consts.ErrInvalidWrappingToken.Error()), wtAuth, logical.ErrInvalidRequest - } - } - // Validate the token auth, te, ctErr := c.checkToken(ctx, req, false) if ctErr == logical.ErrPerfStandbyPleaseForward { @@ -931,21 +916,6 @@ func (c *Core) handleLoginRequest(ctx context.Context, req *logical.Request) (re } } - // If this is a wrapping token lookup, validate the token and produce an - // audit log. We perform this before c.checkToken since wrapping token - // validation performs a token store lookup, and can potentially modify - // logical.Request's token-related fields. - switch req.Path { - case "sys/wrapping/lookup": - valid, wtAuth, err := c.validateWrappingToken(ctx, req, nonHMACReqDataKeys) - if err != nil { - return nil, wtAuth, errwrap.Wrapf("error validating wrapping token: {{err}}", err) - } - if !valid { - return logical.ErrorResponse(consts.ErrInvalidWrappingToken.Error()), wtAuth, logical.ErrInvalidRequest - } - } - req.Unauthenticated = true // Do an unauth check. This will cause EGP policies to be checked diff --git a/vault/wrapping.go b/vault/wrapping.go index 4f7582553926..d635ac4a0b9d 100644 --- a/vault/wrapping.go +++ b/vault/wrapping.go @@ -312,14 +312,24 @@ DONELISTHANDLING: // validateWrappingToken checks whether a token is a wrapping token. The passed // in logical request will be updated if the wrapping token was provided within // a JWT token. -func (c *Core) validateWrappingToken(ctx context.Context, req *logical.Request, nonHMACReqDataKeys []string) (valid bool, auth *logical.Auth, err error) { +func (c *Core) ValidateWrappingToken(ctx context.Context, req *logical.Request) (valid bool, err error) { defer func() { // Perform audit logging before returning if there's an issue with checking // the wrapping token if err != nil || !valid { + // Get non-HMAC'ed request data keys + var nonHMACReqDataKeys []string + entry := c.router.MatchingMountEntry(ctx, req.Path) + if entry != nil { + // Get and set ignored HMAC'd value. + if rawVals, ok := entry.synthesizedConfigCache.Load("audit_non_hmac_request_keys"); ok { + nonHMACReqDataKeys = rawVals.([]string) + } + } + // We log the Auth object like so here since the wrapping token can // come from the header, which gets set as the ClientToken - auth = &logical.Auth{ + auth := &logical.Auth{ ClientToken: req.ClientToken, Accessor: req.ClientTokenAccessor, } @@ -336,7 +346,7 @@ func (c *Core) validateWrappingToken(ctx context.Context, req *logical.Request, }() if req == nil { - return false, nil, fmt.Errorf("invalid request") + return false, fmt.Errorf("invalid request") } var token string @@ -347,9 +357,9 @@ func (c *Core) validateWrappingToken(ctx context.Context, req *logical.Request, if req.Data != nil && req.Data["token"] != nil { thirdParty = true if tokenStr, ok := req.Data["token"].(string); !ok { - return false, nil, fmt.Errorf("could not decode token in request body") + return false, fmt.Errorf("could not decode token in request body") } else if tokenStr == "" { - return false, nil, fmt.Errorf("empty token in request body") + return false, fmt.Errorf("empty token in request body") } else { token = tokenStr } @@ -367,23 +377,23 @@ func (c *Core) validateWrappingToken(ctx context.Context, req *logical.Request, // Implement the jose library way parsedJWT, err := squarejwt.ParseSigned(token) if err != nil { - return false, nil, errwrap.Wrapf("wrapping token could not be parsed: {{err}}", err) + return false, errwrap.Wrapf("wrapping token could not be parsed: {{err}}", err) } var claims squarejwt.Claims var allClaims = make(map[string]interface{}) if err = parsedJWT.Claims(&c.wrappingJWTKey.PublicKey, &claims, &allClaims); err != nil { - return false, nil, errwrap.Wrapf("wrapping token signature could not be validated: {{err}}", err) + return false, errwrap.Wrapf("wrapping token signature could not be validated: {{err}}", err) } typeClaimRaw, ok := allClaims["type"] if !ok { - return false, nil, errors.New("could not validate type claim") + return false, errors.New("could not validate type claim") } typeClaim, ok := typeClaimRaw.(string) if !ok { - return false, nil, errors.New("could not parse type claim") + return false, errors.New("could not parse type claim") } if typeClaim != "wrapping" { - return false, nil, errors.New("unexpected type claim") + return false, errors.New("unexpected type claim") } if !thirdParty { req.ClientToken = claims.ID @@ -395,33 +405,33 @@ func (c *Core) validateWrappingToken(ctx context.Context, req *logical.Request, } if token == "" { - return false, nil, fmt.Errorf("token is empty") + return false, fmt.Errorf("token is empty") } if c.Sealed() { - return false, nil, consts.ErrSealed + return false, consts.ErrSealed } c.stateLock.RLock() defer c.stateLock.RUnlock() if c.standby && !c.perfStandby { - return false, nil, consts.ErrStandby + return false, consts.ErrStandby } te, err := c.tokenStore.Lookup(ctx, token) if err != nil { - return false, nil, err + return false, err } if te == nil { - return false, nil, nil + return false, nil } if len(te.Policies) != 1 { - return false, nil, nil + return false, nil } if te.Policies[0] != responseWrappingPolicyName && te.Policies[0] != controlGroupPolicyName { - return false, nil, nil + return false, nil } if !thirdParty { @@ -430,5 +440,5 @@ func (c *Core) validateWrappingToken(ctx context.Context, req *logical.Request, req.SetTokenEntry(te) } - return true, nil, nil + return true, nil }