simple_google_auth 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +33 -1
- data/lib/simple_google_auth.rb +8 -1
- data/lib/simple_google_auth/controller.rb +29 -0
- data/lib/simple_google_auth/http_client.rb +30 -0
- data/lib/simple_google_auth/oauth.rb +51 -0
- data/lib/simple_google_auth/receiver.rb +5 -41
- data/lib/simple_google_auth/version.rb +1 -1
- metadata +13 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b07e9d444f3a69575224aae7742706c4e857fd6b
|
4
|
+
data.tar.gz: 03baf12262054337668111cd951ea4b8e259faa1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2fa8cf9287ed2bff1db2be4b8f347b65bc5ca6031f0b754758d886a8a9439c9ed0e6aa776d3c19f400982134a1b11d761ba97a2ec574386f0331b62125e6617f
|
7
|
+
data.tar.gz: e8f0d7c17256ec5ac1b7dca2a75adb48e9a4a767702044cc2b283ea11a58b9295abbb7d222b2510965b7adfd7af3a0eec2cdbdf4c5b4239d4f926e3c8e68075c
|
data/README.md
CHANGED
@@ -60,7 +60,6 @@ a different redirect URI. Just pop them on the end of the file.
|
|
60
60
|
config.redirect_uri = "https://mysite.com/google-callback"
|
61
61
|
end
|
62
62
|
|
63
|
-
|
64
63
|
## How do I tell who is logged in?
|
65
64
|
|
66
65
|
Call `#google_auth_data` from your controller or view and you'll get the identification hash that Google sends back.
|
@@ -69,6 +68,39 @@ Call `#google_auth_data` from your controller or view and you'll get the identif
|
|
69
68
|
|
70
69
|
Take a look at https://developers.google.com/accounts/docs/OAuth2Login#obtainuserinfo to find out more about the fields in the hash.
|
71
70
|
|
71
|
+
## Refreshing tokens and offline mode
|
72
|
+
|
73
|
+
By default simple_google_auth doesn't check the expiry time
|
74
|
+
on the credentials after they've been loaded from google the first time.
|
75
|
+
This is less hassle if all you want is simple authentication for your site,
|
76
|
+
but prevents you from using the credentials for other uses (eg. GCal integration)
|
77
|
+
because the oauth tokens will expire and google won't accept them anymore.
|
78
|
+
|
79
|
+
If you want the tokens to be refreshed when they expire then you need to
|
80
|
+
add an extra line to your config. Doing so will ensure that your
|
81
|
+
google auth tokens never get stale and allow you to use offline mode.
|
82
|
+
|
83
|
+
SimpleGoogleAuth.configure do |config|
|
84
|
+
config.refresh_stale_tokens = true
|
85
|
+
end
|
86
|
+
|
87
|
+
Whenever the google_auth_data is requested in a controller it will first
|
88
|
+
be checked to make sure it's not stale. If it is stale the tokens will be
|
89
|
+
refreshed before being returned.
|
90
|
+
|
91
|
+
If your users have already allowed your site access to a certain set of scopes
|
92
|
+
google won't re-issue you a refresh_token automatically. You'll need to set an
|
93
|
+
extra param in the request_parameters configuration hash to force google to
|
94
|
+
send you the refresh token every time your users authenticate.
|
95
|
+
|
96
|
+
SimpleGoogleAuth.configure do |config|
|
97
|
+
config.refresh_stale_tokens = true
|
98
|
+
config.request_parameters.merge!({ approval_prompt: "force" })
|
99
|
+
end
|
100
|
+
|
101
|
+
For more details on offline mode and approval_prompt refer to the google OAuth docs, as of
|
102
|
+
writing you can find them #[here](https://developers.google.com/accounts/docs/OAuth2WebServer).
|
103
|
+
|
72
104
|
## Configuring
|
73
105
|
|
74
106
|
There are a few configuration options that can be set using `SimpleGoogleAuth.configure` as in the example above.
|
data/lib/simple_google_auth.rb
CHANGED
@@ -13,7 +13,8 @@ module SimpleGoogleAuth
|
|
13
13
|
:google_token_url,
|
14
14
|
:state_session_key_name,
|
15
15
|
:data_session_key_name,
|
16
|
-
:request_parameters
|
16
|
+
:request_parameters,
|
17
|
+
:refresh_stale_tokens
|
17
18
|
) do
|
18
19
|
def get_or_call(attribute)
|
19
20
|
value = send(attribute)
|
@@ -26,6 +27,10 @@ module SimpleGoogleAuth
|
|
26
27
|
|
27
28
|
def self.configure
|
28
29
|
yield config
|
30
|
+
|
31
|
+
if config.refresh_stale_tokens
|
32
|
+
config.request_parameters.merge!({ access_type: "offline" })
|
33
|
+
end
|
29
34
|
end
|
30
35
|
|
31
36
|
def self.uri(state)
|
@@ -51,6 +56,8 @@ SimpleGoogleAuth.configure do |config|
|
|
51
56
|
config.authenticate = lambda { raise "You must define an authenticate lambda that sets the session" }
|
52
57
|
end
|
53
58
|
|
59
|
+
require 'simple_google_auth/http_client'
|
60
|
+
require 'simple_google_auth/oauth'
|
54
61
|
require 'simple_google_auth/engine'
|
55
62
|
require 'simple_google_auth/controller'
|
56
63
|
require 'simple_google_auth/receiver'
|
@@ -11,7 +11,36 @@ module SimpleGoogleAuth
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def google_auth_data
|
14
|
+
return unless google_auth_data_from_session
|
15
|
+
|
16
|
+
if should_refresh_google_auth_data?
|
17
|
+
refresh_google_auth_data
|
18
|
+
end
|
19
|
+
google_auth_data_from_session
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def refresh_google_auth_data
|
25
|
+
api = SimpleGoogleAuth::OAuth.new(SimpleGoogleAuth.config)
|
26
|
+
|
27
|
+
auth_data = api.refresh_auth_token!(google_auth_data_from_session["refresh_token"])
|
28
|
+
|
29
|
+
session[SimpleGoogleAuth.config.data_session_key_name] = auth_data
|
30
|
+
end
|
31
|
+
|
32
|
+
def google_auth_data_from_session
|
14
33
|
session[SimpleGoogleAuth.config.data_session_key_name]
|
15
34
|
end
|
35
|
+
|
36
|
+
def should_refresh_google_auth_data?
|
37
|
+
SimpleGoogleAuth.config.refresh_stale_tokens && google_auth_data_stale?
|
38
|
+
end
|
39
|
+
|
40
|
+
def google_auth_data_stale?
|
41
|
+
expiry_time = google_auth_data_from_session["expires_at"]
|
42
|
+
|
43
|
+
expiry_time.nil? || Time.parse(expiry_time).past?
|
44
|
+
end
|
16
45
|
end
|
17
46
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module SimpleGoogleAuth
|
2
|
+
class HttpClient
|
3
|
+
def initialize(url, ca_path)
|
4
|
+
@uri = URI(url)
|
5
|
+
@http = Net::HTTP.new(@uri.host, @uri.port)
|
6
|
+
setup_https(ca_path)
|
7
|
+
end
|
8
|
+
|
9
|
+
def request(params)
|
10
|
+
request = Net::HTTP::Post.new(@uri.request_uri)
|
11
|
+
request.set_form_data(params)
|
12
|
+
response = @http.request(request)
|
13
|
+
response.body
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
def setup_https(ca_path)
|
18
|
+
if @uri.scheme == "https"
|
19
|
+
@http.use_ssl = true
|
20
|
+
if ca_path
|
21
|
+
@http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
22
|
+
@http.ca_path = ca_path
|
23
|
+
else
|
24
|
+
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
25
|
+
Rails.logger.warn "SimpleGoogleAuth does not have a ca_path configured; SSL with Google is not protected"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module SimpleGoogleAuth
|
2
|
+
class OAuth
|
3
|
+
def initialize(config)
|
4
|
+
@config = config
|
5
|
+
@client = HttpClient.new(@config.google_token_url, @config.ca_path)
|
6
|
+
end
|
7
|
+
|
8
|
+
def exchange_code_for_auth_token!(code)
|
9
|
+
response = @client.request(
|
10
|
+
code: code,
|
11
|
+
grant_type: "authorization_code",
|
12
|
+
client_id: @config.client_id,
|
13
|
+
client_secret: @config.client_secret,
|
14
|
+
redirect_uri: @config.redirect_uri)
|
15
|
+
|
16
|
+
parse_auth_response(response)
|
17
|
+
end
|
18
|
+
|
19
|
+
def refresh_auth_token!(refresh_token)
|
20
|
+
return if refresh_token.blank?
|
21
|
+
|
22
|
+
response = @client.request(
|
23
|
+
refresh_token: refresh_token,
|
24
|
+
client_id: @config.client_id,
|
25
|
+
client_secret: @config.client_secret,
|
26
|
+
grant_type: "refresh_token")
|
27
|
+
|
28
|
+
parse_auth_response(response).merge("refresh_token" => refresh_token)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
def parse_auth_response(response)
|
33
|
+
auth_data = JSON.parse(response)
|
34
|
+
|
35
|
+
auth_data["expires_at"] = calculate_expiry(auth_data).to_s
|
36
|
+
|
37
|
+
id_data = decode_id_data(auth_data.delete("id_token"))
|
38
|
+
auth_data.merge!(id_data)
|
39
|
+
end
|
40
|
+
|
41
|
+
def calculate_expiry(auth_data)
|
42
|
+
Time.now + auth_data["expires_in"] - 5.seconds
|
43
|
+
end
|
44
|
+
|
45
|
+
def decode_id_data(id_data)
|
46
|
+
id_data_64 = id_data.split(".")[1]
|
47
|
+
id_data_64 << "=" until id_data_64.length % 4 == 0
|
48
|
+
JSON.parse(Base64.decode64(id_data_64))
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -5,14 +5,14 @@ module SimpleGoogleAuth
|
|
5
5
|
def call(env)
|
6
6
|
request = Rack::Request.new(env)
|
7
7
|
config = SimpleGoogleAuth.config
|
8
|
-
|
9
8
|
ensure_params_are_correct(request, config)
|
10
|
-
auth_data = obtain_authentication_data(request.params["code"], config)
|
11
|
-
id_data = decode_id_data(auth_data.delete("id_token"))
|
12
9
|
|
13
|
-
|
10
|
+
api = SimpleGoogleAuth::OAuth.new(config)
|
11
|
+
auth_data = api.exchange_code_for_auth_token!(request.params["code"])
|
12
|
+
|
13
|
+
raise Error, "Authentication failed" unless config.authenticate.call(auth_data)
|
14
14
|
|
15
|
-
request.session[config.data_session_key_name] =
|
15
|
+
request.session[config.data_session_key_name] = auth_data
|
16
16
|
|
17
17
|
path = request.session[config.state_session_key_name][32..-1]
|
18
18
|
path = "/" if path.blank?
|
@@ -35,41 +35,5 @@ module SimpleGoogleAuth
|
|
35
35
|
raise Error, "No authentication code returned"
|
36
36
|
end
|
37
37
|
end
|
38
|
-
|
39
|
-
def obtain_authentication_data(code, config)
|
40
|
-
uri = URI(config.google_token_url)
|
41
|
-
|
42
|
-
http = Net::HTTP.new(uri.host, uri.port)
|
43
|
-
if uri.scheme == "https"
|
44
|
-
http.use_ssl = true
|
45
|
-
if config.ca_path
|
46
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
47
|
-
http.ca_path = config.ca_path
|
48
|
-
else
|
49
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
50
|
-
Rails.logger.warn "SimpleGoogleAuth does not have a ca_path configured; SSL with Google is not protected"
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
request = Net::HTTP::Post.new(uri.request_uri)
|
55
|
-
request.set_form_data(
|
56
|
-
code: code,
|
57
|
-
client_id: config.get_or_call(:client_id),
|
58
|
-
client_secret: config.get_or_call(:client_secret),
|
59
|
-
redirect_uri: config.redirect_uri,
|
60
|
-
grant_type: "authorization_code"
|
61
|
-
)
|
62
|
-
|
63
|
-
response = http.request(request)
|
64
|
-
raise Error, "Failed to get an access token" unless response.is_a?(Net::HTTPSuccess)
|
65
|
-
|
66
|
-
JSON.parse(response.body)
|
67
|
-
end
|
68
|
-
|
69
|
-
def decode_id_data(id_data)
|
70
|
-
id_data_64 = id_data.split(".")[1]
|
71
|
-
id_data_64 << "=" until id_data_64.length % 4 == 0
|
72
|
-
JSON.parse(Base64.decode64(id_data_64))
|
73
|
-
end
|
74
38
|
end
|
75
39
|
end
|
metadata
CHANGED
@@ -1,27 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simple_google_auth
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Roger Nesbitt
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-01-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 3.2.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 3.2.0
|
27
27
|
description: An extremely easy way to protect your site by requiring Google logins
|
@@ -32,15 +32,17 @@ executables: []
|
|
32
32
|
extensions: []
|
33
33
|
extra_rdoc_files: []
|
34
34
|
files:
|
35
|
+
- MIT-LICENSE
|
36
|
+
- README.md
|
37
|
+
- Rakefile
|
35
38
|
- config/routes.rb
|
39
|
+
- lib/simple_google_auth.rb
|
36
40
|
- lib/simple_google_auth/controller.rb
|
37
41
|
- lib/simple_google_auth/engine.rb
|
42
|
+
- lib/simple_google_auth/http_client.rb
|
43
|
+
- lib/simple_google_auth/oauth.rb
|
38
44
|
- lib/simple_google_auth/receiver.rb
|
39
45
|
- lib/simple_google_auth/version.rb
|
40
|
-
- lib/simple_google_auth.rb
|
41
|
-
- MIT-LICENSE
|
42
|
-
- Rakefile
|
43
|
-
- README.md
|
44
46
|
homepage: https://github.com/mogest/simple_google_auth
|
45
47
|
licenses:
|
46
48
|
- MIT
|
@@ -51,17 +53,17 @@ require_paths:
|
|
51
53
|
- lib
|
52
54
|
required_ruby_version: !ruby/object:Gem::Requirement
|
53
55
|
requirements:
|
54
|
-
- -
|
56
|
+
- - ">="
|
55
57
|
- !ruby/object:Gem::Version
|
56
58
|
version: '0'
|
57
59
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
60
|
requirements:
|
59
|
-
- -
|
61
|
+
- - ">="
|
60
62
|
- !ruby/object:Gem::Version
|
61
63
|
version: '0'
|
62
64
|
requirements: []
|
63
65
|
rubyforge_project:
|
64
|
-
rubygems_version: 2.
|
66
|
+
rubygems_version: 2.2.2
|
65
67
|
signing_key:
|
66
68
|
specification_version: 4
|
67
69
|
summary: Super simple Google authentication for your Rails site
|