forked from googleapis/google-auth-library-ruby
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
429 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
# Rails generator for configuring the google auth library for Rails. Performs | ||
# the following actions | ||
# | ||
# - Creates a route for "/oauth2callback' in `config/routes.rb` for the 3LO | ||
# callback handler | ||
# - Generates a migration for storing user credentials via ActiveRecord | ||
# - Creates an initializer for further customization | ||
# | ||
class GoogleauthGenerator < Rails::Generators::Base | ||
source_root File.expand_path('../templates', __FILE__) | ||
class_option :generate_route, | ||
type: :boolean, | ||
default: true, | ||
description: 'Don\'t insert routes in config/routes.rb' | ||
class_option :generate_migration, | ||
type: :boolean, | ||
default: true, | ||
description: 'Don\'t generate a migration for token storage' | ||
class_option :generate_initializer, | ||
type: :boolean, | ||
default: true, | ||
description: 'Don\t generate an initializer' | ||
|
||
def generate_config | ||
add_route unless options.skip_route | ||
add_migration unless options.skip_migration | ||
add_initializer unless options.skip_initializer | ||
|
||
say 'Please download your application credentials from ' \ | ||
'http://console.developers.google.com ' \ | ||
'and copy to config/client_secret.json.' unless client_secret_exists? | ||
end | ||
|
||
private | ||
|
||
def add_route | ||
route "match '/oauth2callback', "\ | ||
'to: Google::Auth::WebUserAuthorizer::CallbackApp, '\ | ||
'via: :all' | ||
end | ||
|
||
def add_migration | ||
generate 'migration', 'CreateGoogleAuthTokens user_id:string:index ' \ | ||
'token:string' | ||
end | ||
|
||
def add_initializer | ||
copy_file 'googleauth.rb', 'config/initializers/googleauth.rb' | ||
end | ||
|
||
def client_secret_exists? | ||
path = File.join(Rails.root, 'config', 'client_secret.json') | ||
File.exist?(path) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# Default token store uses ActiveRecord. Use the following to use Redis instead | ||
# | ||
# Rails.application.config.googleauth.token_store = :redis | ||
# Rails.application.config.googleauth.token_store_options = { | ||
# :url => 'redis://localhost:6380' | ||
# } | ||
|
||
# Default client secret location is config/client_secret.json. Alternate | ||
# locations can be specified as: | ||
# Rails.application.config.googleauth.client_secret_path = | ||
# '/etc/googleauth/client_secret.json' | ||
# | ||
# Or configured directly: | ||
# Rails.application.config.googleauth.id = 'myclientsecret' | ||
# Rails.application.config.googleauth.secret = 'mysecret' | ||
|
||
# Default scopes to request | ||
# Rails.application.config.googleauth.scope = %w(email profile) | ||
|
||
# Redirect URI path | ||
# Rails.application.config.googleauth.callback_uri = '/oauth2callback' | ||
|
||
# Uncommment to disable automatic injection of helpers into controllers. | ||
# If disabled, helpers can me added as needed by | ||
# including the module 'Google::Auth::Rails::ControllerHelpers' | ||
# Rails.application.config.googleauth.include_helpers = false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
require 'rails' | ||
require 'googleauth/token_store' | ||
require 'googleauth/web_user_authorizer' | ||
|
||
module Google | ||
module Auth | ||
module Rails | ||
# Helpers for rails controllers to simplify the most common usage | ||
# patterns. | ||
# | ||
# In the most basic form, authorization can be added by declaring a | ||
# before_action filter for a controller: | ||
# | ||
# before_action :require_google_credentials | ||
# | ||
# This assumes that: | ||
# - The authorization scope required is configured via | ||
# `config.googleauth.scope` | ||
# - The unique ID of the user is available at `session[:user_id]` | ||
# | ||
# Upon passing the filter, the user credentials are available in the | ||
# instance variable `@google_user_credentials` and can be used to access | ||
# the corresponding APIs. | ||
# | ||
# The filter can be customized by supplying a block instead. This can be | ||
# used to supply a different user ID or require a different scope | ||
# depending on the controller. The following sample uses the Google API | ||
# client from Google Drive: | ||
# | ||
# class FileController < ApplicationController | ||
# before_action do | ||
# require_google_credentials( | ||
# user_id: current_user.email, | ||
# scope: 'https://www.googleapis.com/auth/drive') | ||
# end | ||
# | ||
# def index | ||
# drive = Google::Apis::DriveV2::DriveService.new | ||
# drive.authorization = @google_user_credentials | ||
# @files = drive.list_files(q: "mimeType = 'application/pdf') | ||
# end | ||
# end | ||
# | ||
module ControllerHelpers | ||
# Ensure that user credentials are available for the request. | ||
# Intended to be used as a filter on controllers, but can be called | ||
# directly within a controller method as well. | ||
# | ||
# After calling, credentials are available via the | ||
# `@google_user_credentials` instance variable on the controller. | ||
# | ||
# If no credentials available, the user will be redirected for | ||
# authorization. | ||
# | ||
# @param [String] user_id | ||
# Unique user ID to load credentials for. Defaults to | ||
# `session[:user_id]` if nil. | ||
# @param [String] login_hint | ||
# Optional email address or google profile ID of the user to request | ||
# authorization for. | ||
# @param [Array<String>,String] scope | ||
# Scope to require authorization for. If specified, credentials will | ||
# only be made available if and only if they are authorized for the | ||
# specified scope. If nil, uses the default scope configured for | ||
# the app. | ||
# @return [Google::Auth::UserRefreshCredentials] | ||
# Credentials, if present | ||
def require_google_credentials(options = {}) | ||
@google_user_credentials = google_user_credentials(options) | ||
redirect_to_google_auth_url(options) if @google_user_credentials.nil? | ||
@google_user_credentials | ||
end | ||
|
||
# Retrieve user credentials. | ||
# | ||
# @param [String] user_id | ||
# Unique user ID to load credentials for. Defaults to | ||
# `session[:user_id]` if nil. | ||
# @param [String] scope | ||
# Scope to require authorization for. If specified, credentials will | ||
# only be made available if and only if they are authorized for the | ||
# specified scope. If nil, no scope check is performed and any | ||
# available credentials are returned as is. | ||
# @return [Google::Auth::UserRefreshCredentials] | ||
# Credentials, if present | ||
def google_user_credentials(options = {}) | ||
user_id = options[:user_id] || session[:user_id] | ||
google_user_authorizer.get_credentials(user_id, | ||
request, | ||
options[:scope]) | ||
end | ||
|
||
# Redirects the user to request authorization. | ||
# | ||
# @param [String] login_hint | ||
# Optional email address or google profile ID of the user to request | ||
# authorization for. | ||
# @param [String] redirect_to | ||
# Optional URL to proceed to after authorization complete. Defaults | ||
# to the current URL. | ||
# @param [String, Array<String>] scope | ||
# Authorization scope to request. Overrides the instance scopes | ||
# if not nil. | ||
# @return [Google::Auth::UserRefreshCredentials] | ||
# Credentials, if present | ||
def redirect_to_google_auth_url(options = {}) | ||
url = google_user_authorizer.get_authorization_url( | ||
login_hint: options[:login_hint], | ||
request: request, | ||
redirect_to: options[:redirect_to], | ||
scope: options[:scope]) | ||
redirect_to url | ||
end | ||
|
||
# Retrieves the default authorizer | ||
# | ||
# @return [Google::Auth::WebUserAuthorizer] | ||
def google_user_authorizer | ||
Google::Auth::WebUserAuthorizer.default | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
require 'rails' | ||
require 'googleauth/token_store' | ||
require 'googleauth/web_user_authorizer' | ||
require 'googleauth/rails/controller_helpers' | ||
|
||
module Google | ||
module Auth | ||
# Rails-specific extensions | ||
module Rails | ||
# Railtie for simplified integration with Rails. Exposes configuration | ||
# via Rails config and performs initialiation on startup. | ||
class Railtie < Rails::Railtie | ||
MISSING_CLIENT_ID_ERROR = | ||
'Unable to configure googleauth library, no client secret available' | ||
MISSING_TOKEN_STORE_ERROR = | ||
'Unable to configure googleauth library, no token store configured' | ||
config.googleauth = ActiveSupport::OrderedOptions.new | ||
config.googleauth.token_store = :active_record | ||
config.googleauth.client_secret_path = nil | ||
config.googleauth.id = nil | ||
config.googleauth.secret = nil | ||
config.googleauth.scope = %w(email profile) | ||
config.googleauth.callback_uri = '/oauth2callback' | ||
config.googleauth.token_store_options = {} | ||
config.googleauth.include_helpers = true | ||
|
||
# Initialize authorizers based on config | ||
config.after_initialize do | ||
opts = config.googleauth | ||
client_id = load_client_id | ||
token_store = load_token_store | ||
if client_id.nil? | ||
Rails.logger.warn(MISSING_CLIENT_ID_ERROR) | ||
elsif token_store.nil? | ||
Rails.logger.warn(MISING_TOKEN_STORE_ERROR) | ||
else | ||
Google::Auth::WebUserAuthorizer.default = | ||
Google::Auth::WebUserAuthorizer.new( | ||
client_id, | ||
opts.scope, | ||
token_store, | ||
opts.callback_uri) | ||
if config.googleauth.include_helpers | ||
ActionController::Base.send( | ||
:include, Google::Auth::Rails::ControllerHelpers) | ||
end | ||
end | ||
end | ||
|
||
# Load the client ID | ||
def load_client_id | ||
opts = config.googleauth | ||
return Google::Auth::ClientId.new(opts.id, opts.secret) if opts.id | ||
client_secret = config.googleauth.client_secret_path || | ||
File.join(Rails.root, 'config', 'client_secret.json') | ||
return nil unless File.exist?(client_secret) | ||
Rails.logger.info("Initializing client ID from #{client_secret}") | ||
Google::Auth::ClientId.from_file(client_secret) | ||
end | ||
|
||
# Initialize the token store | ||
def load_token_store | ||
token_store = config.googleauth.token_store | ||
case token_store | ||
when Google::Auth::TokenStore | ||
token_store | ||
when :active_record | ||
require 'googleauth/stores/active_record_token_store' | ||
Google::Auth::Stores::ActiveRecordTokenStore.new( | ||
config.googleauth.token_store_options) | ||
when :redis | ||
require 'googleauth/stores/redis_token_store' | ||
Google::Auth::Stores::RedisTokenStore.new( | ||
config.googleauth.token_store_options) | ||
when :file | ||
require 'googleauth/stores/file_token_store' | ||
Google::Auth::Stores::FileTokenStore.new( | ||
config.googleauth.token_store_options) | ||
else | ||
fail "Unsupported token store: #{token_store}" | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
# Copyright 2014, Google Inc. | ||
# All rights reserved. | ||
# | ||
# Redistribution and use in source and binary forms, with or without | ||
# modification, are permitted provided that the following conditions are | ||
# met: | ||
# | ||
# * Redistributions of source code must retain the above copyright | ||
# notice, this list of conditions and the following disclaimer. | ||
# * Redistributions in binary form must reproduce the above | ||
# copyright notice, this list of conditions and the following disclaimer | ||
# in the documentation and/or other materials provided with the | ||
# distribution. | ||
# * Neither the name of Google Inc. nor the names of its | ||
# contributors may be used to endorse or promote products derived from | ||
# this software without specific prior written permission. | ||
# | ||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
|
||
require 'active_record' | ||
require 'googleauth/token_store' | ||
|
||
module Google | ||
module Auth | ||
module Stores | ||
# Simple model for storing tokens | ||
class GoogleAuthToken < ActiveRecord::Base | ||
validates :user_id, presence: true | ||
validates :token, presence: true | ||
end | ||
|
||
# Implementation of user token storage using ActiveRecord. | ||
class ActiveRecordTokenStore < Google::Auth::TokenStore | ||
def initialize(*) | ||
end | ||
|
||
# (see Google::Auth::Stores::TokenStore#load) | ||
def load(id) | ||
entry = GoogleAuthToken.find_by(user_id: id) | ||
return nil if entry.nil? | ||
entry.token | ||
end | ||
|
||
# (see Google::Auth::Stores::TokenStore#store) | ||
def store(id, token) | ||
entry = GoogleAuthToken.find_or_initialize_by(user_id: id) | ||
entry.update(token: token) | ||
end | ||
|
||
# (see Google::Auth::Stores::TokenStore#delete) | ||
def delete(id) | ||
entry = GoogleAuthToken.find_by(user_id: id) | ||
entry.destroy unless entry.nil? | ||
end | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.