New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhancement request: Support for SignedJwtAssertionCredentials-like authentication, as used by Google BigQuery #119

Closed
mchayat opened this Issue Jul 15, 2014 · 18 comments

Comments

Projects
None yet
4 participants
@mchayat

mchayat commented Jul 15, 2014

Handy server side auth type for Google Big Query, as per described below using client ID and a keystore:

https://developers.google.com/bigquery/authorization#service-accounts-server

@hadley

This comment has been minimized.

Member

hadley commented Jul 16, 2014

@craigcitro have you used this auth flow?

@craigcitro

This comment has been minimized.

Contributor

craigcitro commented Jul 16, 2014

yes -- we totally want to support service accounts. i believe @siddarthab already has or nearly has some working code on this front? (last i heard he needed to get a crypto-related patch upstreamed ...)

@craigcitro

This comment has been minimized.

Contributor

craigcitro commented Jul 17, 2014

and of course by @siddarthab i meant @siddharthab. sid, how far along is this?

@siddharthab

This comment has been minimized.

Contributor

siddharthab commented Jul 17, 2014

It's working really smooth. I extended httr::Token2.0 with overridden methods for refresh and init_credentials, and disabled caching. And I have a different class for the app object which holds the private key (PKCS1, 8 or 12). Also working smooth for GCE accounts which get authorised automatically on package load. I am using libssl and libcrypto directly. Just cleaning up the documentation before I send for review but I can demo tomorrow if you want.

@mchayat

This comment has been minimized.

mchayat commented Jul 17, 2014

That's good news. I am happy to give it a spin as well, if there is a
branch to try. Thanks!

On 17 July 2014 17:23, Siddhartha Bagaria notifications@github.com wrote:

It's working really smooth. I extended httr::Token2.0 with overridden
methods for refresh and init_credentials, and disabled caching. And I have
a different class for the app object which holds the private key (PKCS1, 8
or 12). Also working smooth for GCE accounts which get authorised
automatically on package load. I am using libssl and libcrypto directly.
Just cleaning up the documentation before I send for review but I can demo
tomorrow if you want.


Reply to this email directly or view it on GitHub
#119 (comment).

Regards,
Michael

@hadley

This comment has been minimized.

Member

hadley commented Jul 28, 2014

@siddharthab I'd love to see some code, even if it is rough.

@siddharthab

This comment has been minimized.

Contributor

siddharthab commented Jul 28, 2014

Sorry I got busy with my main project and could not give much love to this one last week. Currently, the code is part of the GoogleGenomics package, but I am moving it to a new WIP GoogleAPI package right now. I will respond in the next few hours with a link.

@siddharthab

This comment has been minimized.

Contributor

siddharthab commented Jul 28, 2014

Code is checked in without any documentation at https://github.com/siddharthab/GoogleAPI
Currently builds on Linux and Mac (albeit with warnings).

What you want to do after loading the package is

oAuthParams <- readClientSecrets('<json file downloaded from Google for service account>', scopes='<character vector of scope URIs>')
token <- getOAuthToken(oAuthParams)
@hadley

This comment has been minimized.

Member

hadley commented Oct 6, 2014

Docs at: https://developers.google.com/accounts/docs/OAuth2ServiceAccount

  • JWT = header + claim set + signature
  • Header = list(alg = unbox("RS256"), typ = unbox("JWT"))
  • Claimset = iss (email address), scope, aud (https://accounts.google.com/o/oauth2/token), exp (expiry date = now() + 1 hour), iat = now
  • Signature = sign header + claim with " RSASSA-PKCS1-V1_5-SIGN with the SHA-256 hash function" using the private key from the

@siddharthab, @craigcitro any thoughts on implementing the key signing without using libssl + libcrypto? That's going to be hard for a CRAN package.

@siddharthab

This comment has been minimized.

Contributor

siddharthab commented Oct 6, 2014

I don't think I will trust an arbitrary encryption library. In my opinion, libssl is important. FWIW, I also added necessary support to the PKI package in R - s-u/PKI#1. But we will most likely not depend on PKI and provide our own infra as in https://github.com/siddharthab/GoogleAPI/blob/master/src/rsa.c

@hadley

This comment has been minimized.

Member

hadley commented Oct 6, 2014

@siddharthab Ok, it looks like I'll be able to build on top of PKI (unfortunately OpenSSL provided by the windows cran builder is OpenSSL/1.0.0, published March 2010)

@hadley

This comment has been minimized.

Member

hadley commented Oct 7, 2014

@siddharthab @craigcitro if either of you happen to know the author of "Using OAuth 2.0 for Server to Server Applications", a complete example in "Computing the signature" (e.g. including sample private keys), would be really useful for validating output.

And a pointer to the definition of base64url wouldn't go astray - I think I've managed to reverse engineer it with help from @siddharthab's code (translate + and / and remove padding), but I'm not 100% sure.

@hadley

This comment has been minimized.

Member

hadley commented Oct 7, 2014

First pass at infrastructure in b79ca91

hadley added a commit that referenced this issue Oct 7, 2014

@hadley

This comment has been minimized.

Member

hadley commented Oct 7, 2014

I have all the pieces working, but I'm getting an "invalid_grant" error when I attempt to get a token. Any ideas?

@siddharthab

This comment has been minimized.

Contributor

siddharthab commented Oct 7, 2014

The grant is sensitive to spaces, etc. It will help if you could compare intermediary outputs from my code and yours, and get them to be byte equivalent. If it does not work, I can take a stab at running your code and debugging.

@hadley

This comment has been minimized.

Member

hadley commented Oct 8, 2014

@siddharthab I've checked the jwt_header() and jwt_claimset() against the references in the docs, and they're definitely on. Would you mind taking a quick look at jwt_signature() (https://github.com/hadley/httr/blob/master/R/oauth-server-side.R#L43-L54) to see if my basic approach is correct?

If that fails, I'll do a step-by-step comparison of the output from your code and my code.

@siddharthab

This comment has been minimized.

Contributor

siddharthab commented Oct 8, 2014

Sure, actually I can do the step by step comparison too. I will reply by tonight.

@siddharthab

This comment has been minimized.

Contributor

siddharthab commented Oct 9, 2014

Sent you #158.
With the above fix, at least this will work for your own secrets file:

secrets <- jsonlite::fromJSON("Genomics-47c75176507d.json")
scope <- "https://www.googleapis.com/auth/userinfo.profile"
payload <- httr:::jwt_signature(secrets, scope)
token_uri <- "https://accounts.google.com/o/oauth2/token"
grant_type <- "urn:ietf:params:oauth:grant-type:jwt-bearer"
httr::POST(token_uri, body=list(grant_type=grant_type, assertion=payload))

@hadley hadley closed this in 66566b7 Oct 9, 2014

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment