Skip to content
New issue

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

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

Already on GitHub? # to your account

Simplify service account user code #90

Closed
redgetan opened this issue May 27, 2015 · 15 comments
Closed

Simplify service account user code #90

redgetan opened this issue May 27, 2015 · 15 comments

Comments

@redgetan
Copy link

The code in https://github.com/tpitale/legato/wiki/OAuth2-and-Google#service-accounts can be simplified (no need to initialize Google::APIClient.new)

def service_account_user(scope="https://www.googleapis.com/auth/analytics.readonly")
  key = Google::APIClient::PKCS12.load_key("YOUR_PRIVATE_KEY_FILENAME", "notasecret")
  service_account = Google::APIClient::JWTAsserter.new("YOUR_API_EMAIL_ADDRESS@developer.gserviceaccount.com", scope, key)
  access_token = service_account.authorize.access_token
  oauth_client = OAuth2::Client.new("", "", {
    :authorize_url => 'https://accounts.google.com/o/oauth2/auth',
    :token_url => 'https://accounts.google.com/o/oauth2/token'
  })
  token = OAuth2::AccessToken.new(oauth_client, access_token, expires_in: 1.hour)
  user = Legato::User.new(token)

  # after an hour or so
  user.access_token.expired?
end
@vrodokanakis
Copy link

Google::APIClient::JWTAsserter is deprecated (http://www.rubydoc.info/github/google/google-api-ruby-client/Google/APIClient/JWTAsserter) and service accounts are now supported directly in Signet.

The above code can be written as:

def service_account_user(scope = "https://www.googleapis.com/auth/analytics.readonly")
  key         = Google::APIClient::KeyUtils.load_from_pkcs12("YOUR_PRIVATE_KEY_FILENAME", "notasecret")
  auth_client = Signet::OAuth2::Client.new(
                  token_credential_uri: 'https://accounts.google.com/o/oauth2/token',
                  audience: 'https://accounts.google.com/o/oauth2/token',
                  scope: scope,
                  issuer: 'YOUR_API_EMAIL_ADDRESS@developer.gserviceaccount.com',
                  signing_key: key,
                  sub: 'YOUR_ANALYTICS_EMAIL@example.com')

  access_token = auth_client.fetch_access_token!

  oauth_client = OAuth2::Client.new("", "", {
    authorize_url: 'https://accounts.google.com/o/oauth2/auth',
    token_url: 'https://accounts.google.com/o/oauth2/token'
  })

  token = OAuth2::AccessToken.new(oauth_client, access_token["access_token"], expires_in: 1.hour)
  user  = Legato::User.new(token)

  # after an hour or so
  user.access_token.expired?
end

The benefit of this way is that the key sub can passed which addresses the issue of having to add YOUR_API_EMAIL_ADDRESS@developer.gserviceaccount.com email address to every analytics account.

If sub is not passed then the response is the following:

`request': {"errors"=>[{"domain"=>"global", "reason"=>"insufficientPermissions", "message"=>"User does not have any Google Analytics account."}], "code"=>403, "message"=>"User does not have any Google Analytics account."}:  (OAuth2::Error)
{"error":{"errors":[{"domain":"global","reason":"insufficientPermissions","message":"User does not have any Google Analytics account."}],"code":403,"message":"User does not have any Google Analytics account."}}

I think the docs should be updated, it will save many hours searching.

@tpitale
Copy link
Owner

tpitale commented Jun 1, 2015

What is Signet? Is that a Google gem, or some other library?

@tpitale
Copy link
Owner

tpitale commented Jun 1, 2015

https://developers.google.com/identity/protocols/OAuth2ServiceAccount, that whole section of the Wiki may just need a rewrite.

@vrodokanakis
Copy link

Yes, signet is a google gem (https://github.com/google/signet).

Its a dependency of google-api-client gem (https://rubygems.org/gems/google-api-client) and it is used to handle authorization.

The google-api-client docs suggests to use the new way. See https://github.com/google/google-api-ruby-client#authorization

@basex
Copy link

basex commented May 25, 2016

google-api-client or googleauth (a dependency of google-api-client) are not needed. The code can be simplified by just using the signet gem that is a dependency of googleauth.

require 'signet/oauth_2/client'

def service_account_user(scope = 'https://www.googleapis.com/auth/analytics.readonly')
  key         = OpenSSL::PKCS12.new(File.read('YOUR_PRIVATE_KEY_FILENAME'), 'notasecret').key
  auth_client = Signet::OAuth2::Client.new(
                  token_credential_uri: 'https://accounts.google.com/o/oauth2/token',
                  audience: 'https://accounts.google.com/o/oauth2/token',
                  scope: scope,
                  issuer: 'YOUR_API_EMAIL_ADDRESS@developer.gserviceaccount.com',
                  signing_key: key,
                  sub: 'YOUR_API_EMAIL_ADDRESS@developer.gserviceaccount.com')

  access_token = auth_client.fetch_access_token!

  oauth_client = OAuth2::Client.new('', '', {
    authorize_url: 'https://accounts.google.com/o/oauth2/auth',
    token_url: 'https://accounts.google.com/o/oauth2/token'
  })

  token = OAuth2::AccessToken.new(oauth_client, access_token['access_token'], expires_in: access_token['expires_in'])

  user  = Legato::User.new(token)

  # after an hour or so
  user.access_token.expired?
end

@tpitale
Copy link
Owner

tpitale commented Jun 11, 2016

@tpitale tpitale closed this as completed Jun 11, 2016
@nicooga
Copy link

nicooga commented Nov 3, 2016

Hi there, I'm getting PKCS12_parse: invalid null pkcs12 pointer when doing this:

key = OpenSSL::PKCS12.new(config.fetch('private_key'), 'notasecret').key

where config is the parsed json file that I've downloaded from Google Console, that looks like this:

{
  "type": "service_account",
  "project_id": "xxx",
  "private_key_id": "xxx",
  "private_key": "-----BEGIN PRIVATE KEY-----
xxxxxxxxxxxxxxxxxxxx
-----END PRIVATE KEY-----\n",
  "client_email": "xxxxx@appspot.gserviceaccount.com",
  "client_id": "xxxxx",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://accounts.google.com/o/oauth2/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "xxxx"
}

Do you recognize the error?

@tpitale
Copy link
Owner

tpitale commented Nov 3, 2016

I just tried to create a new service account and there is a new setting for JSON vs. P12. I'm guessing it needs to be P12 to work with OpenSSL::PKCS12. I'm not sure what to do with the JSON file.

@tpitale
Copy link
Owner

tpitale commented Nov 3, 2016

I'm looking at https://github.com/google/google-auth-library-ruby now to see what they're doing with JSON.

@tpitale
Copy link
Owner

tpitale commented Nov 3, 2016

To use JSON you're going to have to follow these instructions https://developers.google.com/identity/protocols/application-default-credentials and use the googleauth gem, it seems.

@tpitale
Copy link
Owner

tpitale commented Nov 3, 2016

It's essentially looking for the path to the JSON file to be in the env variable GOOGLE_APPLICATION_CREDENTIALS

@tpitale
Copy link
Owner

tpitale commented Nov 3, 2016

@tpitale
Copy link
Owner

tpitale commented Nov 3, 2016

Ah! Here is the secret: https://github.com/google/google-auth-library-ruby/blob/37ed189b2e5165243918fcde127ebe323e9a06b5/lib/googleauth/service_account.rb#L56-L70

The JSON file has an RSA key, not a P12 key. So use OpenSSL::PKey::RSA.new(private_key) instead of OpenSSL::PKCS12.

@tpitale
Copy link
Owner

tpitale commented Nov 3, 2016

I've updated the wiki with this new information.

@nicooga
Copy link

nicooga commented Nov 3, 2016

Thank's @tpitale, you rock!

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants