google-authenticator-rails 0.0.4 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +4 -6
- data/Appraisals +27 -0
- data/README.md +185 -23
- data/Rakefile +26 -0
- data/gemfiles/rails2.3.gemfile +7 -0
- data/gemfiles/rails2.3.gemfile.lock +45 -0
- data/gemfiles/rails3.0.gemfile +7 -0
- data/gemfiles/rails3.0.gemfile.lock +70 -0
- data/gemfiles/rails3.1.gemfile +7 -0
- data/gemfiles/rails3.1.gemfile.lock +79 -0
- data/gemfiles/rails3.2..gemfile +7 -0
- data/gemfiles/rails3.2..gemfile.lock +78 -0
- data/gemfiles/rails4.0.gemfile +8 -0
- data/gemfiles/rails4.0.gemfile.lock +75 -0
- data/gemfiles/rails4.1.gemfile +8 -0
- data/gemfiles/rails4.1.gemfile.lock +75 -0
- data/google-authenticator.gemspec +11 -4
- data/lib/google-authenticator-rails/action_controller/rails_adapter.rb +3 -1
- data/lib/google-authenticator-rails/active_record/acts_as_google_authenticated.rb +31 -21
- data/lib/google-authenticator-rails/active_record/helpers.rb +10 -14
- data/lib/google-authenticator-rails/session/persistence.rb +13 -7
- data/lib/google-authenticator-rails/version.rb +1 -1
- data/lib/google-authenticator-rails.rb +31 -9
- data/spec/google_authenticator_spec.rb +50 -26
- data/spec/session/persistance_spec.rb +27 -6
- data/spec/spec_helper.rb +26 -4
- metadata +53 -38
@@ -0,0 +1,75 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ../
|
3
|
+
specs:
|
4
|
+
google-authenticator-rails (0.0.11)
|
5
|
+
actionpack
|
6
|
+
activerecord
|
7
|
+
google-qr
|
8
|
+
rotp (= 1.6.1)
|
9
|
+
|
10
|
+
GEM
|
11
|
+
remote: https://rubygems.org/
|
12
|
+
specs:
|
13
|
+
actionpack (4.0.2)
|
14
|
+
activesupport (= 4.0.2)
|
15
|
+
builder (~> 3.1.0)
|
16
|
+
erubis (~> 2.7.0)
|
17
|
+
rack (~> 1.5.2)
|
18
|
+
rack-test (~> 0.6.2)
|
19
|
+
activemodel (4.0.2)
|
20
|
+
activesupport (= 4.0.2)
|
21
|
+
builder (~> 3.1.0)
|
22
|
+
activerecord (4.0.2)
|
23
|
+
activemodel (= 4.0.2)
|
24
|
+
activerecord-deprecated_finders (~> 1.0.2)
|
25
|
+
activesupport (= 4.0.2)
|
26
|
+
arel (~> 4.0.0)
|
27
|
+
activerecord-deprecated_finders (1.0.3)
|
28
|
+
activesupport (4.0.2)
|
29
|
+
i18n (~> 0.6, >= 0.6.4)
|
30
|
+
minitest (~> 4.2)
|
31
|
+
multi_json (~> 1.3)
|
32
|
+
thread_safe (~> 0.1)
|
33
|
+
tzinfo (~> 0.3.37)
|
34
|
+
appraisal (0.5.2)
|
35
|
+
bundler
|
36
|
+
rake
|
37
|
+
arel (4.0.1)
|
38
|
+
atomic (1.1.14)
|
39
|
+
builder (3.1.4)
|
40
|
+
diff-lcs (1.1.3)
|
41
|
+
erubis (2.7.0)
|
42
|
+
google-qr (0.2.2)
|
43
|
+
i18n (0.6.9)
|
44
|
+
minitest (4.7.5)
|
45
|
+
multi_json (1.8.4)
|
46
|
+
protected_attributes (1.0.8)
|
47
|
+
activemodel (>= 4.0.1, < 5.0)
|
48
|
+
rack (1.5.2)
|
49
|
+
rack-test (0.6.2)
|
50
|
+
rack (>= 1.0)
|
51
|
+
rake (10.1.1)
|
52
|
+
rotp (1.6.1)
|
53
|
+
rspec (2.8.0)
|
54
|
+
rspec-core (~> 2.8.0)
|
55
|
+
rspec-expectations (~> 2.8.0)
|
56
|
+
rspec-mocks (~> 2.8.0)
|
57
|
+
rspec-core (2.8.0)
|
58
|
+
rspec-expectations (2.8.0)
|
59
|
+
diff-lcs (~> 1.1.2)
|
60
|
+
rspec-mocks (2.8.0)
|
61
|
+
sqlite3 (1.3.8)
|
62
|
+
thread_safe (0.1.3)
|
63
|
+
atomic
|
64
|
+
tzinfo (0.3.38)
|
65
|
+
|
66
|
+
PLATFORMS
|
67
|
+
ruby
|
68
|
+
|
69
|
+
DEPENDENCIES
|
70
|
+
activerecord (~> 4.0.0)
|
71
|
+
appraisal (~> 0.5.1)
|
72
|
+
google-authenticator-rails!
|
73
|
+
protected_attributes
|
74
|
+
rspec (~> 2.8.0)
|
75
|
+
sqlite3
|
@@ -0,0 +1,75 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ../
|
3
|
+
specs:
|
4
|
+
google-authenticator-rails (0.0.11)
|
5
|
+
actionpack
|
6
|
+
activerecord
|
7
|
+
google-qr
|
8
|
+
rotp (= 1.6.1)
|
9
|
+
|
10
|
+
GEM
|
11
|
+
remote: https://rubygems.org/
|
12
|
+
specs:
|
13
|
+
actionpack (4.1.7)
|
14
|
+
actionview (= 4.1.7)
|
15
|
+
activesupport (= 4.1.7)
|
16
|
+
rack (~> 1.5.2)
|
17
|
+
rack-test (~> 0.6.2)
|
18
|
+
actionview (4.1.7)
|
19
|
+
activesupport (= 4.1.7)
|
20
|
+
builder (~> 3.1)
|
21
|
+
erubis (~> 2.7.0)
|
22
|
+
activemodel (4.1.7)
|
23
|
+
activesupport (= 4.1.7)
|
24
|
+
builder (~> 3.1)
|
25
|
+
activerecord (4.1.7)
|
26
|
+
activemodel (= 4.1.7)
|
27
|
+
activesupport (= 4.1.7)
|
28
|
+
arel (~> 5.0.0)
|
29
|
+
activesupport (4.1.7)
|
30
|
+
i18n (~> 0.6, >= 0.6.9)
|
31
|
+
json (~> 1.7, >= 1.7.7)
|
32
|
+
minitest (~> 5.1)
|
33
|
+
thread_safe (~> 0.1)
|
34
|
+
tzinfo (~> 1.1)
|
35
|
+
appraisal (0.5.2)
|
36
|
+
bundler
|
37
|
+
rake
|
38
|
+
arel (5.0.1.20140414130214)
|
39
|
+
builder (3.2.2)
|
40
|
+
diff-lcs (1.1.3)
|
41
|
+
erubis (2.7.0)
|
42
|
+
google-qr (0.2.2)
|
43
|
+
i18n (0.6.11)
|
44
|
+
json (1.8.1)
|
45
|
+
minitest (5.4.3)
|
46
|
+
protected_attributes (1.0.8)
|
47
|
+
activemodel (>= 4.0.1, < 5.0)
|
48
|
+
rack (1.5.2)
|
49
|
+
rack-test (0.6.2)
|
50
|
+
rack (>= 1.0)
|
51
|
+
rake (10.3.2)
|
52
|
+
rotp (1.6.1)
|
53
|
+
rspec (2.8.0)
|
54
|
+
rspec-core (~> 2.8.0)
|
55
|
+
rspec-expectations (~> 2.8.0)
|
56
|
+
rspec-mocks (~> 2.8.0)
|
57
|
+
rspec-core (2.8.0)
|
58
|
+
rspec-expectations (2.8.0)
|
59
|
+
diff-lcs (~> 1.1.2)
|
60
|
+
rspec-mocks (2.8.0)
|
61
|
+
sqlite3 (1.3.10)
|
62
|
+
thread_safe (0.3.4)
|
63
|
+
tzinfo (1.2.2)
|
64
|
+
thread_safe (~> 0.1)
|
65
|
+
|
66
|
+
PLATFORMS
|
67
|
+
ruby
|
68
|
+
|
69
|
+
DEPENDENCIES
|
70
|
+
activerecord (~> 4.1.0)
|
71
|
+
appraisal (~> 0.5.1)
|
72
|
+
google-authenticator-rails!
|
73
|
+
protected_attributes
|
74
|
+
rspec (~> 2.8.0)
|
75
|
+
sqlite3
|
@@ -1,6 +1,12 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
require File.expand_path('../lib/google-authenticator-rails/version', __FILE__)
|
3
3
|
|
4
|
+
version_info = RUBY_VERSION.split(".")
|
5
|
+
|
6
|
+
major = version_info.first.to_i
|
7
|
+
minor = version_info[1].to_i
|
8
|
+
hotfix = version_info.last.to_i
|
9
|
+
|
4
10
|
Gem::Specification.new do |gem|
|
5
11
|
gem.authors = ["Jared McFarland"]
|
6
12
|
gem.email = ["jared.online@gmail.com"]
|
@@ -14,12 +20,13 @@ Gem::Specification.new do |gem|
|
|
14
20
|
gem.name = "google-authenticator-rails"
|
15
21
|
gem.require_paths = ["lib"]
|
16
22
|
gem.version = Google::Authenticator::Rails::VERSION
|
17
|
-
|
18
|
-
gem.add_dependency "rotp"
|
23
|
+
|
24
|
+
gem.add_dependency "rotp", "= 1.6.1"
|
19
25
|
gem.add_dependency "activerecord"
|
20
26
|
gem.add_dependency "google-qr"
|
21
27
|
gem.add_dependency "actionpack"
|
22
|
-
|
23
|
-
gem.add_development_dependency "rspec",
|
28
|
+
|
29
|
+
gem.add_development_dependency "rspec", "~> 2.8.0"
|
30
|
+
gem.add_development_dependency "appraisal", "~> 0.5.1"
|
24
31
|
gem.add_development_dependency "sqlite3"
|
25
32
|
end
|
@@ -33,4 +33,6 @@ module GoogleAuthenticatorRails
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
ActionController::Base
|
36
|
+
if defined?(ActionController::Base)
|
37
|
+
ActionController::Base.send(:include, GoogleAuthenticatorRails::ActionController::Integration)
|
38
|
+
end
|
@@ -1,88 +1,98 @@
|
|
1
1
|
module GoogleAuthenticatorRails # :nodoc:
|
2
|
-
module ActiveRecord # :nodoc:
|
2
|
+
module ActiveRecord # :nodoc:
|
3
3
|
module ActsAsGoogleAuthenticated # :nodoc:
|
4
4
|
def self.included(base)
|
5
5
|
base.extend ClassMethods
|
6
6
|
end
|
7
7
|
|
8
8
|
# This is the single integration point. Monkey patch ActiveRecord::Base
|
9
|
-
# to include the ActsAsGoogleAuthenticated module, which allows a user
|
9
|
+
# to include the ActsAsGoogleAuthenticated module, which allows a user
|
10
10
|
# to call User.acts_as_google_authenticated.
|
11
|
-
#
|
11
|
+
#
|
12
12
|
# The model being used must have a string column named "google_secret", or an explicitly
|
13
13
|
# named column.
|
14
|
-
#
|
14
|
+
#
|
15
15
|
# Example:
|
16
|
-
#
|
16
|
+
#
|
17
17
|
# class User
|
18
18
|
# acts_as_google_authenticated
|
19
19
|
# end
|
20
|
-
#
|
20
|
+
#
|
21
21
|
# @user = user.new
|
22
22
|
# @user.set_google_secret # => true
|
23
23
|
# @user.google_qr_uri # => http://path.to.google/qr?with=params
|
24
24
|
# @user.google_authentic?(123456) # => true
|
25
|
-
#
|
25
|
+
#
|
26
26
|
# Google Labels
|
27
27
|
# When setting up an account with the GoogleAuthenticator you need to provide
|
28
28
|
# a label for that account (to distinguish it from other accounts).
|
29
|
-
#
|
29
|
+
#
|
30
30
|
# GoogleAuthenticatorRails allows you to customize how the record will create
|
31
31
|
# that label. There are three options:
|
32
32
|
# - The default just uses the column "email" on the model
|
33
33
|
# - You can specify a custom column with the :column_name option
|
34
34
|
# - You can specify a custom method via a symbol or a proc
|
35
|
-
#
|
35
|
+
#
|
36
36
|
# Examples:
|
37
|
-
#
|
37
|
+
#
|
38
38
|
# class User
|
39
39
|
# acts_as_google_authenticated :column => :user_name
|
40
40
|
# end
|
41
|
-
#
|
41
|
+
#
|
42
42
|
# @user = User.new(:user_name => "ted")
|
43
43
|
# @user.google_label # => "ted"
|
44
|
-
#
|
44
|
+
#
|
45
45
|
# class User
|
46
46
|
# acts_as_google_authenticated :method => :user_name_with_label
|
47
|
-
#
|
47
|
+
#
|
48
48
|
# def user_name_with_label
|
49
49
|
# "#{user_name}@example.com"
|
50
50
|
# end
|
51
51
|
# end
|
52
|
-
#
|
52
|
+
#
|
53
53
|
# @user = User.new(:user_name => "ted")
|
54
54
|
# @user.google_label # => "ted@example.com"
|
55
|
-
#
|
55
|
+
#
|
56
56
|
# class User
|
57
57
|
# acts_as_google_authenticated :method => Proc.new { |user| user.user_name_with_label.upcase }
|
58
|
-
#
|
58
|
+
#
|
59
59
|
# def user_name_with_label
|
60
60
|
# "#{user_name}@example.com"
|
61
61
|
# end
|
62
62
|
# end
|
63
|
-
#
|
63
|
+
#
|
64
64
|
# @user = User.new(:user_name => "ted")
|
65
65
|
# @user.google_label # => "TED@EXAMPLE.COM"
|
66
|
-
#
|
66
|
+
#
|
67
67
|
module ClassMethods # :nodoc
|
68
68
|
|
69
|
-
# Initializes the class attributes with the specified options and includes the
|
69
|
+
# Initializes the class attributes with the specified options and includes the
|
70
70
|
# respective ActiveRecord helper methods
|
71
|
-
#
|
71
|
+
#
|
72
72
|
# Options:
|
73
73
|
# [:column_name] the name of the column used to create the google_label
|
74
74
|
# [:method] name of the method to call to create the google_label
|
75
75
|
# it supercedes :column_name
|
76
76
|
# [:google_secret_column] the column the secret will be stored in, defaults
|
77
77
|
# to "google_secret"
|
78
|
+
# [:lookup_token] the column to use to find the record from the DB, defaults
|
79
|
+
# to "persistence_token"
|
80
|
+
# [:drift] drift the number of seconds that the client and server are
|
81
|
+
# allowed to drift apart. Default value is 6.
|
82
|
+
#
|
83
|
+
# [:issuer] the name of the issuer to appear in the app (optional), defaults
|
84
|
+
# to ""
|
78
85
|
def acts_as_google_authenticated(options = {})
|
79
86
|
@google_label_column = options[:column_name] || :email
|
80
87
|
@google_label_method = options[:method] || :default_google_label_method
|
81
88
|
@google_secret_column = options[:google_secret_column] || :google_secret
|
89
|
+
@google_lookup_token = options[:lookup_token] || :persistence_token
|
90
|
+
@google_drift = options[:drift] || GoogleAuthenticatorRails::DRIFT
|
91
|
+
@google_issuer = options[:issuer]
|
82
92
|
|
83
93
|
puts ":skip_attr_accessible is no longer required. Called from #{Kernel.caller[0]}}" if options.has_key?(:skip_attr_accessible)
|
84
94
|
|
85
|
-
[:google_label_column, :google_label_method, :google_secret_column].each do |cattr|
|
95
|
+
[:google_label_column, :google_label_method, :google_secret_column, :google_lookup_token, :google_drift, :google_issuer].each do |cattr|
|
86
96
|
self.singleton_class.class_eval { attr_reader cattr }
|
87
97
|
end
|
88
98
|
|
@@ -6,24 +6,12 @@ module GoogleAuthenticatorRails # :nodoc:
|
|
6
6
|
save
|
7
7
|
end
|
8
8
|
|
9
|
-
# TODO: Remove this method in version 0.0.4
|
10
|
-
def set_google_secret!
|
11
|
-
put "DEPRECATION WARNING: #set_google_secret! is no longer being used, use #set_google_secret instead. #set_google_secret! will be removed in 0.0.4. Called from #{Kernel.caller[0]}"
|
12
|
-
set_google_secret
|
13
|
-
end
|
14
|
-
|
15
9
|
def google_authentic?(code)
|
16
|
-
GoogleAuthenticatorRails.valid?(code, google_secret_value)
|
17
|
-
end
|
18
|
-
|
19
|
-
# TODO: Remove this method in version 0.0.4
|
20
|
-
def google_authenticate(code)
|
21
|
-
put "DEPRECATION WARNING: #google_authenticate is no longer being used, use #google_authentic? instead. #google_authenticate will be removed in 0.0.4. Called from #{Kernel.caller[0]}"
|
22
|
-
google_authentic?(code)
|
10
|
+
GoogleAuthenticatorRails.valid?(code, google_secret_value, self.class.google_drift)
|
23
11
|
end
|
24
12
|
|
25
13
|
def google_qr_uri
|
26
|
-
GoogleQR.new(:data => ROTP::TOTP.new(google_secret_value).provisioning_uri(google_label), :size => "200x200").to_s
|
14
|
+
GoogleQR.new(:data => ROTP::TOTP.new(google_secret_value, :issuer => google_issuer).provisioning_uri(google_label), :size => "200x200").to_s
|
27
15
|
end
|
28
16
|
|
29
17
|
def google_label
|
@@ -38,6 +26,10 @@ module GoogleAuthenticatorRails # :nodoc:
|
|
38
26
|
end
|
39
27
|
end
|
40
28
|
|
29
|
+
def google_token_value
|
30
|
+
self.__send__(self.class.google_lookup_token)
|
31
|
+
end
|
32
|
+
|
41
33
|
private
|
42
34
|
def default_google_label_method
|
43
35
|
self.__send__(self.class.google_label_column)
|
@@ -46,6 +38,10 @@ module GoogleAuthenticatorRails # :nodoc:
|
|
46
38
|
def google_secret_value
|
47
39
|
self.__send__(self.class.google_secret_column)
|
48
40
|
end
|
41
|
+
|
42
|
+
def google_issuer
|
43
|
+
self.class.google_issuer
|
44
|
+
end
|
49
45
|
end
|
50
46
|
end
|
51
47
|
end
|
@@ -16,7 +16,7 @@ module GoogleAuthenticatorRails
|
|
16
16
|
cookie = controller.cookies[cookie_key]
|
17
17
|
if cookie
|
18
18
|
token, user_id = parse_cookie(cookie).values_at(:token, :user_id)
|
19
|
-
conditions = {
|
19
|
+
conditions = { klass.google_lookup_token => token, :id => user_id }
|
20
20
|
record = __send__(finder, conditions).first
|
21
21
|
session = new(record)
|
22
22
|
session.valid? ? session : nil
|
@@ -26,11 +26,15 @@ module GoogleAuthenticatorRails
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def create(user)
|
29
|
-
raise GoogleAuthenticatorRails::Session::Persistence::TokenNotFound if !user.respond_to?(
|
30
|
-
controller.cookies[cookie_key] = create_cookie(user.
|
29
|
+
raise GoogleAuthenticatorRails::Session::Persistence::TokenNotFound if user.nil? || !user.respond_to?(user.class.google_lookup_token) || user.google_token_value.blank?
|
30
|
+
controller.cookies[cookie_key] = create_cookie(user.google_token_value, user.id)
|
31
31
|
new(user)
|
32
32
|
end
|
33
33
|
|
34
|
+
def destroy
|
35
|
+
controller.cookies.delete cookie_key
|
36
|
+
end
|
37
|
+
|
34
38
|
private
|
35
39
|
def finder
|
36
40
|
@_finder ||= klass.public_methods.include?(:where) ? :rails_3_finder : :rails_2_finder
|
@@ -55,14 +59,16 @@ module GoogleAuthenticatorRails
|
|
55
59
|
|
56
60
|
def create_cookie(token, user_id)
|
57
61
|
value = [token, user_id].join('::')
|
58
|
-
{
|
62
|
+
options = GoogleAuthenticatorRails.cookie_options || {}
|
63
|
+
options.merge(
|
59
64
|
:value => value,
|
60
65
|
:expires => GoogleAuthenticatorRails.time_until_expiration.from_now
|
61
|
-
|
66
|
+
)
|
62
67
|
end
|
63
68
|
|
64
69
|
def cookie_key
|
65
|
-
|
70
|
+
suffix = GoogleAuthenticatorRails.cookie_key_suffix || 'mfa_credentials'
|
71
|
+
"#{klass.to_s.downcase}_#{suffix}"
|
66
72
|
end
|
67
73
|
end
|
68
74
|
|
@@ -72,4 +78,4 @@ module GoogleAuthenticatorRails
|
|
72
78
|
end
|
73
79
|
end
|
74
80
|
end
|
75
|
-
end
|
81
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
# Stuff the gem
|
2
|
-
#
|
1
|
+
# Stuff the gem requires
|
2
|
+
#
|
3
3
|
require 'active_support'
|
4
4
|
require 'active_record'
|
5
5
|
require 'openssl'
|
@@ -12,7 +12,7 @@ GOOGLE_AUTHENTICATOR_RAILS_PATH = File.dirname(__FILE__) + "/google-authenticato
|
|
12
12
|
|
13
13
|
[
|
14
14
|
"version",
|
15
|
-
|
15
|
+
|
16
16
|
"action_controller",
|
17
17
|
"active_record",
|
18
18
|
"session"
|
@@ -20,15 +20,21 @@ GOOGLE_AUTHENTICATOR_RAILS_PATH = File.dirname(__FILE__) + "/google-authenticato
|
|
20
20
|
require GOOGLE_AUTHENTICATOR_RAILS_PATH + library
|
21
21
|
end
|
22
22
|
|
23
|
-
|
24
|
-
#
|
23
|
+
# Sets up some basic accessors for use with the ROTP module
|
24
|
+
#
|
25
25
|
module GoogleAuthenticatorRails
|
26
|
-
# Drift is set to 6 because ROTP drift is not inclusive.
|
26
|
+
# Drift is set to 6 because ROTP drift is not inclusive. This allows a drift of 5 seconds.
|
27
27
|
DRIFT = 6
|
28
28
|
|
29
29
|
# How long a Session::Persistence cookie should last.
|
30
30
|
@@time_until_expiration = 24.hours
|
31
31
|
|
32
|
+
# Last part of a Session::Persistence cookie's key
|
33
|
+
@@cookie_key_suffix = nil
|
34
|
+
|
35
|
+
# Additional configuration passed to a Session::Persistence cookie.
|
36
|
+
@@cookie_options = { :httponly => true }
|
37
|
+
|
32
38
|
def self.generate_password(secret, iteration)
|
33
39
|
ROTP::HOTP.new(secret).at(iteration)
|
34
40
|
end
|
@@ -37,8 +43,8 @@ module GoogleAuthenticatorRails
|
|
37
43
|
ROTP::TOTP.new(secret).now
|
38
44
|
end
|
39
45
|
|
40
|
-
def self.valid?(code, secret)
|
41
|
-
ROTP::TOTP.new(secret).verify_with_drift(code,
|
46
|
+
def self.valid?(code, secret, drift = DRIFT)
|
47
|
+
ROTP::TOTP.new(secret).verify_with_drift(code, drift)
|
42
48
|
end
|
43
49
|
|
44
50
|
def self.generate_secret
|
@@ -52,4 +58,20 @@ module GoogleAuthenticatorRails
|
|
52
58
|
def self.time_until_expiration=(time_until_expiration)
|
53
59
|
@@time_until_expiration = time_until_expiration
|
54
60
|
end
|
55
|
-
|
61
|
+
|
62
|
+
def self.cookie_key_suffix
|
63
|
+
@@cookie_key_suffix
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.cookie_key_suffix=(suffix)
|
67
|
+
@@cookie_key_suffix = suffix
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.cookie_options
|
71
|
+
@@cookie_options
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.cookie_options=(options)
|
75
|
+
@@cookie_options = options
|
76
|
+
end
|
77
|
+
end
|
@@ -5,49 +5,65 @@ describe GoogleAuthenticatorRails do
|
|
5
5
|
before do
|
6
6
|
ROTP::Base32.stub!(:random_base32).and_return(random32)
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
describe '#generate_password' do
|
10
10
|
subject { GoogleAuthenticatorRails::generate_password("test", counter) }
|
11
|
-
|
11
|
+
|
12
12
|
context 'counter = 1' do
|
13
13
|
let(:counter) { 1 }
|
14
|
-
it { should ==
|
14
|
+
it { should == 868864 }
|
15
15
|
end
|
16
16
|
|
17
17
|
context 'counter = 2' do
|
18
18
|
let(:counter) { 2 }
|
19
|
-
it { should ==
|
19
|
+
it { should == 304404 }
|
20
20
|
end
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
context 'time-based passwords' do
|
24
24
|
let(:time) { Time.parse("2012-08-07 11:11:11 AM +0700") }
|
25
25
|
let(:secret) { "test" }
|
26
|
-
let(:code) {
|
26
|
+
let(:code) { 922511 }
|
27
27
|
before { Time.stub!(:now).and_return(time) }
|
28
28
|
|
29
29
|
specify { GoogleAuthenticatorRails::time_based_password(secret).should == code }
|
30
|
-
specify { GoogleAuthenticatorRails::valid?(code, secret).should be true }
|
30
|
+
specify { GoogleAuthenticatorRails::valid?(code, secret).should be true }
|
31
31
|
|
32
32
|
specify { GoogleAuthenticatorRails::valid?(code * 2, secret).should be false }
|
33
|
-
specify { GoogleAuthenticatorRails::valid?(code, secret * 2).should be false }
|
33
|
+
specify { GoogleAuthenticatorRails::valid?(code, secret * 2).should be false }
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
it 'can create a secret' do
|
37
37
|
GoogleAuthenticatorRails::generate_secret.should == random32
|
38
38
|
end
|
39
|
-
|
40
|
-
context 'integration with ActiveRecord'
|
39
|
+
|
40
|
+
context 'integration with ActiveRecord' do
|
41
41
|
let(:original_time) { Time.parse("2012-08-07 11:11:00 AM +0700") }
|
42
42
|
let(:time) { original_time }
|
43
|
+
let(:user) { User.create(:email => "test@example.com", :user_name => "test_user") }
|
43
44
|
before do
|
44
45
|
Time.stub!(:now).and_return(time)
|
45
|
-
|
46
|
-
|
46
|
+
user.google_secret = "test"
|
47
|
+
end
|
48
|
+
|
49
|
+
context "custom drift" do
|
50
|
+
# 30 seconds drift
|
51
|
+
let(:user) { DriftUser.create(:email => "test@example.com", :user_name => "test_user") }
|
52
|
+
subject { user.google_authentic?(922511) }
|
53
|
+
|
54
|
+
context '6 seconds of drift' do
|
55
|
+
let(:time) { original_time + 36.seconds }
|
56
|
+
it { should be true }
|
57
|
+
end
|
58
|
+
|
59
|
+
context '30 seconds of drift' do
|
60
|
+
let(:time) { original_time + 61.seconds }
|
61
|
+
it { should be false }
|
62
|
+
end
|
47
63
|
end
|
48
|
-
|
64
|
+
|
49
65
|
context 'code validation' do
|
50
|
-
subject {
|
66
|
+
subject { user.google_authentic?(922511) }
|
51
67
|
|
52
68
|
it { should be true }
|
53
69
|
|
@@ -61,10 +77,10 @@ describe GoogleAuthenticatorRails do
|
|
61
77
|
it { should be false }
|
62
78
|
end
|
63
79
|
end
|
64
|
-
|
80
|
+
|
65
81
|
it 'creates a secret' do
|
66
|
-
|
67
|
-
|
82
|
+
user.set_google_secret
|
83
|
+
user.google_secret.should == random32
|
68
84
|
end
|
69
85
|
|
70
86
|
context 'secret column' do
|
@@ -75,7 +91,7 @@ describe GoogleAuthenticatorRails do
|
|
75
91
|
end
|
76
92
|
|
77
93
|
it 'validates code' do
|
78
|
-
@user.google_authentic?(
|
94
|
+
@user.google_authentic?(922511).should be_true
|
79
95
|
end
|
80
96
|
|
81
97
|
it 'generates a url for a qr code' do
|
@@ -89,6 +105,14 @@ describe GoogleAuthenticatorRails do
|
|
89
105
|
it { should raise_error(NoMethodError) }
|
90
106
|
end
|
91
107
|
|
108
|
+
context "drift value" do
|
109
|
+
it { DriftUser.google_drift.should == 31 }
|
110
|
+
|
111
|
+
context "default value" do
|
112
|
+
it { User.google_drift.should == 6 }
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
92
116
|
context 'qr codes' do
|
93
117
|
let(:options) { { :email => "test@example.com", :user_name => "test_user" } }
|
94
118
|
let(:user) { User.create options }
|
@@ -96,12 +120,12 @@ describe GoogleAuthenticatorRails do
|
|
96
120
|
subject { user.google_qr_uri }
|
97
121
|
|
98
122
|
it { should eq "https://chart.googleapis.com/chart?cht=qr&chl=otpauth%3A%2F%2Ftotp%2Ftest%40example.com%3Fsecret%3D5qlcip7azyjuwm36&chs=200x200" }
|
99
|
-
|
123
|
+
|
100
124
|
context 'custom column name' do
|
101
125
|
let(:user) { ColumnNameUser.create options }
|
102
126
|
it { should eq "https://chart.googleapis.com/chart?cht=qr&chl=otpauth%3A%2F%2Ftotp%2Ftest_user%3Fsecret%3D5qlcip7azyjuwm36&chs=200x200" }
|
103
127
|
end
|
104
|
-
|
128
|
+
|
105
129
|
context 'custom proc' do
|
106
130
|
let(:user) { ProcUser.create options }
|
107
131
|
it { should eq "https://chart.googleapis.com/chart?cht=qr&chl=otpauth%3A%2F%2Ftotp%2Ftest_user%40futureadvisor-admin%3Fsecret%3D5qlcip7azyjuwm36&chs=200x200" }
|
@@ -112,12 +136,12 @@ describe GoogleAuthenticatorRails do
|
|
112
136
|
it { should eq "https://chart.googleapis.com/chart?cht=qr&chl=otpauth%3A%2F%2Ftotp%2Ftest%40example.com%3Fsecret%3D5qlcip7azyjuwm36&chs=200x200" }
|
113
137
|
end
|
114
138
|
|
115
|
-
context 'method defined by string' do
|
139
|
+
context 'method defined by string' do
|
116
140
|
let(:user) { StringUser.create options }
|
117
141
|
it { should eq "https://chart.googleapis.com/chart?cht=qr&chl=otpauth%3A%2F%2Ftotp%2Ftest%40example.com%3Fsecret%3D5qlcip7azyjuwm36&chs=200x200" }
|
118
|
-
end
|
142
|
+
end
|
119
143
|
end
|
120
|
-
|
144
|
+
|
121
145
|
end
|
122
|
-
|
123
|
-
end
|
146
|
+
|
147
|
+
end
|