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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 17bdbddcd052da79050cd43d146b6ba3070a808d
4
- data.tar.gz: 565fffa60eaef47bb69710a1830ee4315e73bf59
3
+ metadata.gz: b07e9d444f3a69575224aae7742706c4e857fd6b
4
+ data.tar.gz: 03baf12262054337668111cd951ea4b8e259faa1
5
5
  SHA512:
6
- metadata.gz: a83902d120549033da2bd08cd155e4f419dd9e512ef9a3a9240a654c3238119b36d9818feacdcdc8fcdd85ed8d2cb22a08e5df4a2fa0d7102c493e2360c85730
7
- data.tar.gz: 08e7e440d0c2c27142c7229e1cc88d9a26df65d4ce3ff7d45f3e2195e495a4cef5136c81b08d42cd2acf4517b8cda8b02d73e749c3f04dbf30ff8a3606ae7b23
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.
@@ -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
- raise Error, "Authentication failed" unless config.authenticate.call(id_data)
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] = id_data.merge(auth_data)
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
@@ -1,3 +1,3 @@
1
1
  module SimpleGoogleAuth
2
- VERSION = "0.0.5"
2
+ VERSION = "0.0.6"
3
3
  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.5
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: 2014-11-05 00:00:00.000000000 Z
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.0.14
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