Skip to content
This repository has been archived by the owner on Jan 24, 2019. It is now read-only.

Apply HMAC signatures to upstream requests #147

Closed
wants to merge 20 commits into from

Conversation

mbland
Copy link
Contributor

@mbland mbland commented Sep 29, 2015

Closes #146.

This still a work-in-progress, as I need to add tests to verify that the actual signing of requests by the proxy is implemented properly. I will remove the "[WIP]" from the title and ping when that's done.

However, the signature package itself and the updating of options to include the new signature_key and upstream_keys configuration values is tested and complete.

@mbland mbland force-pushed the hmac-signatures branch 6 times, most recently from 50ab403 to e44dfad Compare September 30, 2015 20:23
@mbland mbland changed the title [WIP] Apply HMAC signatures to upstream requests Apply HMAC signatures to upstream requests Sep 30, 2015
@mbland mbland force-pushed the hmac-signatures branch 3 times, most recently from 16832c7 to 71931f2 Compare October 1, 2015 00:25
@mbland
Copy link
Contributor Author

mbland commented Oct 1, 2015

OK @jehiah, this is ready for a look-see. I haven't squashed down the commits yet, just in case I end up wanting/needing to tweak something. Also, the last commit is a broader change to allow for more algorithms besides sha1; all the commits before that hardcode sha1.

Note that signature.ValidateRequest should be immediately usable by Go programs wishing to validate signed requests (I think go get will do the right thing). Also, all of StringToSign, RequestSignature, and ValidateRequest should be easy to implement in other languages; I plan to write a Ruby gem and an npm if and when this change makes it in.

@mbland
Copy link
Contributor Author

mbland commented Oct 2, 2015

I've gotten the jump on the Ruby and Node implementations; as expected, they were more or less straight ports of signature/signature.go:

https://rubygems.org/gems/oauth2_proxy_authentication
https://www.npmjs.com/package/oauth2-proxy-authentication

I'll get on the Python version soon. Of course, I stand ready to update these and share maintainership based on the outcome of this PR.

@mbland
Copy link
Contributor Author

mbland commented Oct 2, 2015

So I went on a tear, and figured out how generic this HMAC signature logic could be. I've extracted the former signature package into github.com/18F/hmacauth, and also created:

https://rubygems.org/gems/hmac_authentication
https://www.npmjs.com/package/hmac-authentication

So now the headers could even be configurable between instances.

@jehiah
Copy link
Member

jehiah commented Oct 2, 2015

@mbland I'm excited for this PR. It certainly adds a few new configuration options for oauth2proxy.

Some general feedback on a first read:

  • I'm not convinced there is a compelling need to have separate signatures/secrets for each potential upstream. It feels like it would be much simpler (in implementation and usage) to just have --signature-"sha1:s3kr3t" and apply that to all upstream requests. Thoughts?
  • The signature in github.com/a18F/hmacauth is calculated with header.Get() but we need all the headers of a particular header in case they are repeated. I think this also implies we need output the header key as part of the signature to disambiguate where values came from.
  • The signature has the full URL and i'm pretty sure that means it's requires that you must use -pass-host-header=true (the default). I think this is ok, but it's worth documenting as otherwise the upstream wouldn't have enough information to re-construct the signature.
  • Header order. Would it be useful to just define that the headers are signed in sorted order?

@mbland
Copy link
Contributor Author

mbland commented Oct 2, 2015

Hey @jehiah:

  • I've removed the support for per-upstream secret keys. I've saved a patch in case we ever want to add it back.
  • Looking more closely at the documentation for Header.Get(), I see now that it says it will return the "first" value. I'll update the 18F/hmacauth package.
  • Actually, the intent is to pass just the path + query, so pass-host-header shouldn't be necessary. Again, I'll update 18F/hmacauth.
  • So you're saying just sort all the headers by name and hash them all? Interesting approach that wouldn't even require a configuration of which headers to pick. Can't think of a downside offhand.

As a government employee, I can't solicit effort, but I'll copy you on the 18F/hmacauth PR(s). 😉

@jehiah
Copy link
Member

jehiah commented Oct 2, 2015

oops, no i wasn't implying to sort all headers, i was implying we sort the order of the headers we are hashing. english--

@mbland
Copy link
Contributor Author

mbland commented Oct 2, 2015

Ah, got it. I'll keep the header config bit, then.

mbland pushed a commit to 18F/hmacauth that referenced this pull request Oct 2, 2015
Per @jehiah's suggestion in bitly/oauth2_proxy#147.

Also adds a test to ensure that the query string of the URL is factored in.
@mbland
Copy link
Contributor Author

mbland commented Oct 5, 2015

FYI, I managed to get a generic proxy server together based on the 18F/hmacauth package. Check it out: https://github.com/18F/hmacproxy/

However, I don't know why the build is breaking; it somehow can't find 18F/hmacauth, even though it's public and specified in the Godeps file. Any hints, @jehiah?

@mbland
Copy link
Contributor Author

mbland commented Oct 6, 2015

What d'ya know, it's passing again. :-) @jehiah So long as you're comfortable with the implementation of github.com/18F/hmacauth, this may be ready for another look.

But to pick up two points from before:

  • I've implemented the hashing of multiply-defined headers in the hmacauth package, as well as in the Node.js HMAC auth implementation, but apparently that's a discouraged practice, and Ruby unilaterally selects the value from the last instance of a header (see the notes in the README from the Ruby HMAC auth implementation.
  • I've not sorted the headers for hashing, but I'm really on the fence about that. If you think it's really worth it, I can update hmacauth (and the other implementations) accordingly.

@mbland
Copy link
Contributor Author

mbland commented Oct 10, 2015

I just pushed a commit to simulate a request body buffer consumed by Read(), which is why the test is currently failing.

Using fakeNetConn in the test exposes a bug in 18F/hmacauth when handling POST requests, addressed by 18F/hmacauth#4. The bug was that the strings.Reader does not consume its buffer contents the same way that a net.Conn does. So the test would pass because its request body would still be intact after signing, but during live testing, the request body would be consumed by HmacAuth.requestSignature().

It also happened to expose a subsequent 18F/hmacauth bug addressed in 18F/hmacauth#5. It turns out that checking Request.ContentLength is an unreliable way of detecting that a body is present, and checking body != nil is sufficient.

18F/hmacauth#4 is already merged; when 18F/hmacauth#5 is in, I'll tag 18F/hmacauth v1.0.1 and update the Godeps to use that version, at which point the test should pass.

cc: @dlapiduz @jcscottiii

@mbland
Copy link
Contributor Author

mbland commented Oct 13, 2015

OK, hmacauth bumped to v1.0.1 and the test is passing again.

@jehiah
Copy link
Member

jehiah commented Oct 13, 2015

@mbland 😄 I think this is in good shape now! Sorry i've been silent here over the past week. I should be able to help wrap this up today

@mbland
Copy link
Contributor Author

mbland commented Oct 13, 2015

No worries, and no rush! 😄

@mbland
Copy link
Contributor Author

mbland commented Nov 9, 2015

@jehiah Also rebased this branch after #164.

Mike Bland added 18 commits November 9, 2015 11:13
Using fakeNetConn in the test exposes a bug in 18F/hmacauth when handling POST
requests, addressed by 18F/hmacauth#4. The bug was that the strings.Reader
does not consume its buffer contents the same way that a net.Conn does. So the
test would pass because its request body would still be intact after signing,
but during live testing, the request body would be consumed by
HmacAuth.requestSignature().

It also happened to expose a subsequent 18F/hmacauth bug addressed in
18F/hmacauth#5. It turns out that checking Request.ContentLength is an
unreliable way of detecting that a body is present, and checking body != nil
is sufficient.

18F/hmacauth#4 is already merged; when 18F/hmacauth#5 is in, I'll tag
18F/hmacauth v1.0.1 and update the Godeps to use that version, at which point
the test should pass.
v1.0.1 contains 18F/hmacauth#4 and 18F/hmacauth#5, needed to make
TestRequestSignaturePostRequest pass again.
@mbland
Copy link
Contributor Author

mbland commented Nov 9, 2015

...and after #153. 😄

@jehiah jehiah closed this in e4626c1 Nov 16, 2015
@jehiah
Copy link
Member

jehiah commented Nov 16, 2015

merged with some slight readme changes as e4626c1

@mbland
Copy link
Contributor Author

mbland commented Nov 17, 2015

Ah, thanks, @jehiah!

@mbland mbland deleted the hmac-signatures branch November 17, 2015 13:13
stepanstipl pushed a commit to stepanstipl/oauth2_proxy that referenced this pull request Jan 16, 2016
eelcocramer added a commit to servicelab/oauth2_proxy that referenced this pull request Jan 20, 2016
Updates readme and help

Adds azure to the providers.

Fixes race condition

Sometimes, during tests, a race condition occurs. Using `break` instead
of `return` fixes this for me.

Tries to read mail address

Tries to read mail address from the Graph API. Currently this
has not been tested properly.

Adds resource parameter

Uses to gain access to protected resources when redeeming the token.

Gets the mail address from the graph

*: rename Url to URL everywhere

Go coding style says that acronyms should be all lower or all upper. Fix
Url to URL.

oauthproxy: rename Uri to URI

Be consistent with Go coding style for acroynyms.

*: rename Oauth to OAuth

Be consistent with Go capitalization styling and use a single way of
spelling this across the tree.

Add /auth endpoint to support Nginx's auth_request

Closes bitly#152.

Extract Authenticate for Proxy, AuthenticateOnly

Add nginx auth_request config to README

Sign Upstream requests with HMAC. closes bitly#147

Renames var ending on Url to URL

Simplifies configuration for brevity
ruta-goomba pushed a commit to ruta-goomba/oauth2_proxy that referenced this pull request Jan 21, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants