authlogic_motp 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/CHANGELOG.rdoc ADDED
@@ -0,0 +1,3 @@
1
+ == 1.0.0 released 2011-12-6
2
+
3
+ * Initial release
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in authlogic_motp.gemspec
4
+ gemspec
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 [name of plugin creator]
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Manifest.txt ADDED
@@ -0,0 +1,12 @@
1
+ CHANGELOG.rdoc
2
+ MIT-LICENSE
3
+ Manifest.txt
4
+ README.rdoc
5
+ Rakefile
6
+ init.rb
7
+ lib/authlogic_motp.rb
8
+ lib/authlogic_motp/acts_as_authentic.rb
9
+ lib/authlogic_motp/session.rb
10
+ lib/authlogic_motp/version.rb
11
+ rails/init.rb
12
+ test/test_authlogic_motp.rb
data/README.rdoc ADDED
@@ -0,0 +1,67 @@
1
+ = Authlogic MOTP
2
+
3
+ Authlogic MOTP is an extension of the Authlogic library to add Mobile-OTP support.
4
+
5
+ == Helpful links
6
+
7
+ * <b>Mobile-OTP:</b> http://motp.sourceforge.net
8
+ * <b>Authlogic:</b> http://github.com/binarylogic/authlogic
9
+
10
+ == Requirements
11
+
12
+ authlogic_motp requires, of course, that authlogic is installed on your server.
13
+ It also assumes that registration of users (issuing/syncing secrets and PIN codes) will be handled by you.
14
+
15
+ == Install and use
16
+
17
+ === 1. Install the Authlogic MOTP gem
18
+
19
+ $ sudo gem install authlogic_motp
20
+
21
+ Now add the gem dependency in your config:
22
+
23
+ Gemfile (Rails 3):
24
+ gem 'authlogic_motp'
25
+
26
+ config (Rails <3)
27
+ config.gem "authlogic_motp"
28
+
29
+ === 2. Make some simple changes to your database:
30
+
31
+ class AddUsersMotpFields < ActiveRecord::Migration
32
+ def self.up
33
+ add_column :users, :motp_secret, :string
34
+ add_column :users, :motp_pin, :string
35
+ add_column :users, :motp_cache, :string
36
+
37
+ change_column :users, :crypted_password, :string, :default => nil, :null => true
38
+ change_column :users, :password_salt, :string, :default => nil, :null => true
39
+ end
40
+
41
+ def self.down
42
+ remove_column :users, :motp_secret
43
+ remove_column :users, :motp_pin
44
+ remove_column :users, :motp_cache
45
+
46
+ [:crypted_password, :password_salt].each do |field|
47
+ User.all(:conditions => "#{field} is NULL").each { |user| user.update_attribute(field, "") if user.send(field).nil? }
48
+ change_column :users, field, :string, :default => "", :null => false
49
+ end
50
+ end
51
+ end
52
+
53
+ === 2. Setup your views
54
+
55
+ authlogic-motp expects the login and password fields in your login form to be named "otp-login" and "otp-password".
56
+ The user should enter their usual login value, and then the OTP generated on their device for the password.
57
+
58
+ === 3. Issue credentials
59
+
60
+ Each user will have to be issued a secret (in general a 16 character long HEX string), which they will use to initialize their account on the OTP device, and also a PIN (in general a 4 digit number) used to generate passwords. Some client programs allow the secret to be generated on the device. In this case the user will have to communicate both secret and pin to the administrator for registration.
61
+
62
+ These should be stored in :motp_secret and :motp_pin respectively.
63
+
64
+
65
+
66
+ Copyright (c) 2011 Martin Chandler, released under the MIT license
67
+
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "authlogic_motp/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "authlogic_motp"
7
+ s.version = AuthlogicMotp::VERSION
8
+ s.authors = ["Martin Chandler"]
9
+ s.email = ["browntigerz.lair@gmail.com"]
10
+ s.homepage = "http://github.com/browntiger/authlogic_motp"
11
+ s.summary = %q{Extension of the Authlogic library to add Mobile-OTP support.}
12
+ s.description = %q{Extension of the Authlogic library to add Mobile-OTP support.}
13
+ s.rdoc_options = ["--charset=UTF-8"]
14
+ s.extra_rdoc_files = ["README.rdoc"]
15
+
16
+ # s.rubyforge_project = "authlogic_motp"
17
+
18
+ s.files = `git ls-files`.split("\n")
19
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20
+ # s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
+ s.require_paths = ["lib"]
22
+
23
+ # specify any dependencies here; for example:
24
+ # s.add_development_dependency "rspec"
25
+ # s.add_runtime_dependency "rest-client"
26
+ s.add_runtime_dependency "authlogic"
27
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.dirname(__FILE__) + "/rails/init.rb"
@@ -0,0 +1,6 @@
1
+ require "authlogic_motp/version"
2
+ require 'authlogic_motp/acts_as_authentic'
3
+ require 'authlogic_motp/session'
4
+
5
+ ActiveRecord::Base.send(:include, AuthlogicMotp::ActsAsAuthentic)
6
+ Authlogic::Session::Base.send(:include, AuthlogicMotp::Session)
@@ -0,0 +1,18 @@
1
+ module AuthlogicMotp
2
+ module ActsAsAuthentic
3
+ def self.included(klass)
4
+ klass.class_eval do
5
+ extend Config
6
+ add_acts_as_authentic_module(Methods, :prepend)
7
+ end
8
+ end
9
+
10
+ module Config
11
+
12
+ end
13
+
14
+ module Methods
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,138 @@
1
+ require 'digest/md5'
2
+ module AuthlogicMotp
3
+ module Session
4
+ def self.included(klass)
5
+ klass.class_eval do
6
+ extend Config
7
+ include Methods
8
+ end
9
+ end
10
+
11
+ module Config
12
+ def motp_maxperiod(value = nil)
13
+ rw_config(:motp_maxperiod_method, value, :motp_maxperiod)
14
+ end
15
+ alias_method :motp_maxperiod=, :motp_maxperiod
16
+ end
17
+
18
+ module Methods
19
+ def self.included(klass)
20
+ klass.class_eval do
21
+ attr_accessor :otp_login
22
+ attr_accessor :otp_password
23
+
24
+ validate :validate_by_otp, :if => :authenticating_with_otp?
25
+ end
26
+ end
27
+
28
+ def credentials
29
+ if authenticating_with_otp?
30
+ details = {}
31
+ details[:otp_login] = send(login_field)
32
+ details[:otp_password] = '<protected>'
33
+ details
34
+ else
35
+ super
36
+ end
37
+ end
38
+
39
+ def credentials=(value)
40
+ super
41
+ values = value.is_a?(Array) ? value : [value]
42
+ hash = values.first.is_a?(Hash) ? values.first.with_indifferent_access : nil
43
+ if !hash.nil?
44
+ self.otp_login = hash[:otp_login] if hash.key?(:otp_login)
45
+ self.otp_password = hash[:otp_password] if hash.key?(:otp_password)
46
+ end
47
+ end
48
+
49
+ private
50
+ def authenticating_with_otp?
51
+ !otp_login.blank? || !otp_password.blank?
52
+ end
53
+
54
+ def motp_maxperiod
55
+ self.class.motp_maxperiod
56
+ end
57
+
58
+ def find_by_otp_login_method
59
+ self.class.find_by_login_method
60
+ end
61
+
62
+ def generalize_credentials_error_messages?
63
+ self.class.generalize_credentials_error_messages
64
+ end
65
+
66
+ def add_general_credentials_error
67
+ error_message =
68
+ if self.class.generalize_credentials_error_messages.is_a? String
69
+ self.class.generalize_credentials_error_messages
70
+ else
71
+ "Login credentials are not valid"
72
+ end
73
+ errors.add(:base, I18n.t('error_messages.general_credentials_error', :default => error_message))
74
+ end
75
+
76
+ def validate_by_otp
77
+ errors.add(:login, I18n.t('error_messages.login_blank', :default => 'cannot be blank')) if otp_login.blank?
78
+ errors.add(:password, I18n.t('error_messages.password_blank', :default => 'cannot be blank')) if otp_password.blank?
79
+ return if errors.count > 0
80
+
81
+ self.attempted_record = klass.send(find_by_otp_login_method, otp_login)
82
+ if attempted_record.blank?
83
+ generalize_credentials_error_messages? ?
84
+ add_general_credentials_error :
85
+ errors.add(:login, I18n.t('error_messages.login_not_found', :default => "does not exist"))
86
+ return
87
+ else
88
+ # don't allow otp that have been successfully used recently in the past
89
+ # even if it is within the legal time frame (otp does mean _one_ time password!)
90
+ old_otp = attempted_record.otp_cache.split(',') unless attempted_record.otp_cache.blank?
91
+ old_otp ||= []
92
+ otp_hash = Digest::MD5.hexdigest(otp_password)
93
+ if old_otp.include?(otp_hash)
94
+ generalize_credentials_error_messages? ?
95
+ add_general_credentials_error :
96
+ errors.add(:password, I18n.t('error_messages.password_invalid', :default => "is invalid"))
97
+ return
98
+ end
99
+
100
+ if CheckMOTP.validate(attempted_record.otp_secret, attempted_record.otp_pin, otp_password, motp_maxperiod)
101
+ # cache the otp so we can check against it next time
102
+ old_otp.pop if old_otp.length == 5
103
+ old_otp << otp_hash
104
+ attempted_record.update_attribute(:otp_cache, old_otp.join(","))
105
+ else
106
+ generalize_credentials_error_messages? ?
107
+ add_general_credentials_error :
108
+ errors.add(:password, I18n.t('error_messages.password_invalid', :default => "is invalid"))
109
+ return
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
115
+
116
+ class CheckMOTP
117
+ def initialize
118
+ @tmp_md5 = ''
119
+ end
120
+
121
+ def self.validate(secret,pin,otp,period=3)
122
+ maxperiod = period * 60 # in seconds
123
+ time = Time.now.utc.to_i
124
+ ((time - maxperiod)..(time + maxperiod)).each do |n|
125
+ md5 = generate_otp(n,secret,pin)
126
+ next if md5 == @tmp_md5
127
+ @tmp_md5 = md5
128
+
129
+ return true if md5.downcase == otp.chomp.downcase
130
+ end
131
+ false
132
+ end
133
+
134
+ def self.generate_otp(time,secret,pin)
135
+ Digest::MD5.hexdigest(time.to_s.chop << secret << pin.to_s)[0,6]
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,3 @@
1
+ module AuthlogicMotp
2
+ VERSION = "1.0.0"
3
+ end
data/rails/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'authlogic_motp'
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: authlogic_motp
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Martin Chandler
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-12-05 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: authlogic
16
+ requirement: &12154840 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *12154840
25
+ description: Extension of the Authlogic library to add Mobile-OTP support.
26
+ email:
27
+ - browntigerz.lair@gmail.com
28
+ executables: []
29
+ extensions: []
30
+ extra_rdoc_files:
31
+ - README.rdoc
32
+ files:
33
+ - .gitignore
34
+ - CHANGELOG.rdoc
35
+ - Gemfile
36
+ - MIT-LICENSE
37
+ - Manifest.txt
38
+ - README.rdoc
39
+ - Rakefile
40
+ - authlogic_motp.gemspec
41
+ - init.rb
42
+ - lib/authlogic_motp.rb
43
+ - lib/authlogic_motp/acts_as_authentic.rb
44
+ - lib/authlogic_motp/session.rb
45
+ - lib/authlogic_motp/version.rb
46
+ - rails/init.rb
47
+ homepage: http://github.com/browntiger/authlogic_motp
48
+ licenses: []
49
+ post_install_message:
50
+ rdoc_options:
51
+ - --charset=UTF-8
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ! '>='
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubyforge_project:
68
+ rubygems_version: 1.8.12
69
+ signing_key:
70
+ specification_version: 3
71
+ summary: Extension of the Authlogic library to add Mobile-OTP support.
72
+ test_files: []