yubikey_database_authenticatable 0.3.0
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.
- data/MIT-LICENSE +20 -0
- data/README.md +48 -0
- data/Rakefile +39 -0
- data/lib/devise_yubikey_database_authenticatable/model.rb +100 -0
- data/lib/devise_yubikey_database_authenticatable/routes.rb +4 -0
- data/lib/devise_yubikey_database_authenticatable/strategy.rb +32 -0
- data/lib/devise_yubikey_database_authenticatable/version.rb +3 -0
- data/lib/yubikey_database_authenticatable.rb +11 -0
- data/rails/init.rb +7 -0
- data/test/test_helper.rb +3 -0
- data/test/yubikey_database_authenticatable_test.rb +8 -0
- data/yubikey_database_authenticatable.gemspec +22 -0
- metadata +110 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Stephen Kapp
|
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/README.md
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# Devise - Yubikey Database Authentication
|
2
|
+
|
3
|
+
This extension to Devise adds a modified Database Authentication strategy to allow the authentication of a user with Two Factor Authentication provided by the Yubikey OTP token
|
4
|
+
|
5
|
+
This extension requires the used to already have a valid account and password and verifies that the user exists along with the password provided by verifying that the user presented a valid Yubikey OTP.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
This plugin requires Rails 3.0.x+ and Devise 1.3.4+. Additionally the Yubikey Ruby library found here is required.
|
10
|
+
|
11
|
+
<https://github.com/titanous/yubikey>
|
12
|
+
|
13
|
+
The gem for the Yubikey library will need to be added to your Gemfile. Currently this can only be installed as a plugin.
|
14
|
+
|
15
|
+
`rails plugin install git://github.com/mort666/yubikey_database_authenticatable.git`
|
16
|
+
|
17
|
+
Is compatible with Rails 3.1.
|
18
|
+
|
19
|
+
## Setup
|
20
|
+
|
21
|
+
Once the plugin is installed, all you need to do is setup the user model which includes a small addition to the model itself and to the schema.
|
22
|
+
|
23
|
+
The following needs to be added to the User module.
|
24
|
+
|
25
|
+
add_column :users, :useyubikey, :boolean
|
26
|
+
add_column :users, :registeredyubikey, :string
|
27
|
+
|
28
|
+
then finally add to the model:
|
29
|
+
|
30
|
+
class User < ActiveRecord::Base
|
31
|
+
|
32
|
+
devise :yubikey_database_authenticatable, :trackable, :timeoutable
|
33
|
+
|
34
|
+
# Setup accessible (or protected) attributes for your model
|
35
|
+
attr_accessible :useyubikey, :registeredyubikey, :yubiotp
|
36
|
+
|
37
|
+
attr_accessor :yubiotp
|
38
|
+
|
39
|
+
def registeredyubikey=(yubiotp)
|
40
|
+
write_attribute(:registeredyubikey, yubiotp[0..11])
|
41
|
+
end
|
42
|
+
|
43
|
+
...
|
44
|
+
end
|
45
|
+
|
46
|
+
## Copyright
|
47
|
+
|
48
|
+
Copyright (c) 2011 Stephen Kapp, Released under MIT License
|
data/Rakefile
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'jeweler'
|
7
|
+
Jeweler::Tasks.new do |gem|
|
8
|
+
gem.name = "yubiket_database_authenticatable"
|
9
|
+
gem.summary = %Q{YubiKey OTP Authentication Plugin for Devise}
|
10
|
+
gem.description = %Q{Extended version of the Devise Database Authentication module to implement YubiKey OTP two factor authentication for registered users}
|
11
|
+
gem.email = "mort666@virus.org"
|
12
|
+
gem.homepage = "https://github.com/mort666/yubikey_database_authenticatable"
|
13
|
+
gem.authors = ["Stephen Kapp"]
|
14
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
|
+
end
|
16
|
+
Jeweler::GemcutterTasks.new
|
17
|
+
rescue LoadError
|
18
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
19
|
+
end
|
20
|
+
|
21
|
+
desc 'Default: run unit tests.'
|
22
|
+
task :default => :test
|
23
|
+
|
24
|
+
desc 'Test the yubikey_database_authenticatable plugin.'
|
25
|
+
Rake::TestTask.new(:test) do |t|
|
26
|
+
t.libs << 'lib'
|
27
|
+
t.libs << 'test'
|
28
|
+
t.pattern = 'test/**/*_test.rb'
|
29
|
+
t.verbose = true
|
30
|
+
end
|
31
|
+
|
32
|
+
desc 'Generate documentation for the yubikey_database_authenticatable plugin.'
|
33
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
34
|
+
rdoc.rdoc_dir = 'rdoc'
|
35
|
+
rdoc.title = 'YubikeyDatabaseAuthenticatable'
|
36
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
37
|
+
rdoc.rdoc_files.include('README')
|
38
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
39
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'yubikey'
|
2
|
+
require 'bcrypt'
|
3
|
+
|
4
|
+
module Devise
|
5
|
+
module Models
|
6
|
+
module YubikeyDatabaseAuthenticatable
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
attr_reader :yubiotp, :password, :current_password
|
11
|
+
attr_accessor :password_confirmation
|
12
|
+
end
|
13
|
+
|
14
|
+
def validate_yubikey(yubiotp)
|
15
|
+
begin
|
16
|
+
otp = Yubikey::OTP::Verify.new(yubiotp)
|
17
|
+
|
18
|
+
if otp.valid?
|
19
|
+
return true
|
20
|
+
else
|
21
|
+
return false
|
22
|
+
end
|
23
|
+
rescue Yubikey::OTP::InvalidOTPError
|
24
|
+
return false
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Generates password encryption based on the given value.
|
29
|
+
def password=(new_password)
|
30
|
+
@password = new_password
|
31
|
+
self.encrypted_password = password_digest(@password) if @password.present?
|
32
|
+
end
|
33
|
+
|
34
|
+
# Verifies whether an password (ie from sign in) is the user password.
|
35
|
+
def valid_password?(password)
|
36
|
+
return false if encrypted_password.blank?
|
37
|
+
bcrypt = ::BCrypt::Password.new(self.encrypted_password)
|
38
|
+
password = ::BCrypt::Engine.hash_secret("#{password}#{self.class.pepper}", bcrypt.salt)
|
39
|
+
Devise.secure_compare(password, self.encrypted_password)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Set password and password confirmation to nil
|
43
|
+
def clean_up_passwords
|
44
|
+
self.password = self.password_confirmation = ""
|
45
|
+
end
|
46
|
+
|
47
|
+
# Update record attributes when :current_password matches, otherwise returns
|
48
|
+
# error on :current_password. It also automatically rejects :password and
|
49
|
+
# :password_confirmation if they are blank.
|
50
|
+
def update_with_password(params={})
|
51
|
+
current_password = params.delete(:current_password)
|
52
|
+
|
53
|
+
if params[:password].blank?
|
54
|
+
params.delete(:password)
|
55
|
+
params.delete(:password_confirmation) if params[:password_confirmation].blank?
|
56
|
+
end
|
57
|
+
|
58
|
+
result = if valid_password?(current_password)
|
59
|
+
update_attributes(params)
|
60
|
+
else
|
61
|
+
self.errors.add(:current_password, current_password.blank? ? :blank : :invalid)
|
62
|
+
self.attributes = params
|
63
|
+
false
|
64
|
+
end
|
65
|
+
|
66
|
+
clean_up_passwords
|
67
|
+
result
|
68
|
+
end
|
69
|
+
|
70
|
+
def after_database_authentication
|
71
|
+
end
|
72
|
+
|
73
|
+
# A reliable way to expose the salt regardless of the implementation.
|
74
|
+
def authenticatable_salt
|
75
|
+
self.encrypted_password[0,29] if self.encrypted_password
|
76
|
+
end
|
77
|
+
|
78
|
+
protected
|
79
|
+
|
80
|
+
# Downcase case-insensitive keys
|
81
|
+
def downcase_keys
|
82
|
+
(self.class.case_insensitive_keys || []).each { |k| self[k].try(:downcase!) }
|
83
|
+
end
|
84
|
+
|
85
|
+
# Digests the password using bcrypt.
|
86
|
+
def password_digest(password)
|
87
|
+
::BCrypt::Password.create("#{password}#{self.class.pepper}", :cost => self.class.stretches).to_s
|
88
|
+
end
|
89
|
+
|
90
|
+
module ClassMethods
|
91
|
+
def find_for_yubikey_database_authentication(conditions)
|
92
|
+
find_for_authentication(conditions)
|
93
|
+
end
|
94
|
+
|
95
|
+
Devise::Models.config(self, :pepper, :stretches)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'devise/strategies/authenticatable'
|
2
|
+
|
3
|
+
module Devise
|
4
|
+
module Strategies
|
5
|
+
class YubikeyDatabaseAuthenticatable < Authenticatable
|
6
|
+
def authenticate!
|
7
|
+
resource = valid_password? && mapping.to.find_for_yubikey_database_authentication(authentication_hash)
|
8
|
+
|
9
|
+
if validate(resource) {resource.valid_password?(password)}
|
10
|
+
if resource.useyubikey == true
|
11
|
+
if params[:user][:yubiotp].blank?
|
12
|
+
fail('Yubikey OTP Required for this user.')
|
13
|
+
else
|
14
|
+
if resource.validate_yubikey(params[:user][:yubiotp]) && (resource.registeredyubikey == params[:user][:yubiotp][0..11])
|
15
|
+
resource.after_database_authentication
|
16
|
+
success!(resource)
|
17
|
+
else
|
18
|
+
fail('Invalid Yubikey OTP.')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
else
|
22
|
+
success!(resource)
|
23
|
+
end
|
24
|
+
else
|
25
|
+
fail(:invalid)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
Warden::Strategies.add(:yubikey_database_authenticatable, Devise::Strategies::YubikeyDatabaseAuthenticatable)
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# YubikeyDatabaseAuthenticatable
|
2
|
+
|
3
|
+
require 'devise'
|
4
|
+
|
5
|
+
$: << File.expand_path("..", __FILE__)
|
6
|
+
|
7
|
+
require 'devise_yubikey_database_authenticatable/model'
|
8
|
+
require 'devise_yubikey_database_authenticatable/strategy'
|
9
|
+
require 'devise_yubikey_database_authenticatable/routes'
|
10
|
+
|
11
|
+
Devise.add_module(:yubikey_database_authenticatable, :strategy => true, :model => "devise_yubikey_database_authenticatable/model", :route => :session, :controller => :sessions)
|
data/rails/init.rb
ADDED
data/test/test_helper.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "devise_yubikey_database_authenticatable/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'yubikey_database_authenticatable'
|
7
|
+
s.version = YubikeyDatabaseAuthenticatable::VERSION.dup
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.summary = 'YubiKey OTP Authentication Plugin for Devise'
|
10
|
+
s.email = 'mort666@virus.org'
|
11
|
+
s.homepage = 'https://github.com/mort666/yubikey_database_authenticatable'
|
12
|
+
s.description = s.summary
|
13
|
+
s.authors = ['Stephen Kapp']
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
|
20
|
+
s.add_dependency('devise', '~> 1.5.0')
|
21
|
+
s.add_dependency('yubikey', '~> 1.2.1')
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: yubikey_database_authenticatable
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 19
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 3
|
9
|
+
- 0
|
10
|
+
version: 0.3.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Stephen Kapp
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-12-04 00:00:00 +00:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: devise
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 1
|
32
|
+
- 5
|
33
|
+
- 0
|
34
|
+
version: 1.5.0
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: yubikey
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 29
|
46
|
+
segments:
|
47
|
+
- 1
|
48
|
+
- 2
|
49
|
+
- 1
|
50
|
+
version: 1.2.1
|
51
|
+
type: :runtime
|
52
|
+
version_requirements: *id002
|
53
|
+
description: YubiKey OTP Authentication Plugin for Devise
|
54
|
+
email: mort666@virus.org
|
55
|
+
executables: []
|
56
|
+
|
57
|
+
extensions: []
|
58
|
+
|
59
|
+
extra_rdoc_files: []
|
60
|
+
|
61
|
+
files:
|
62
|
+
- MIT-LICENSE
|
63
|
+
- README.md
|
64
|
+
- Rakefile
|
65
|
+
- lib/devise_yubikey_database_authenticatable/model.rb
|
66
|
+
- lib/devise_yubikey_database_authenticatable/routes.rb
|
67
|
+
- lib/devise_yubikey_database_authenticatable/strategy.rb
|
68
|
+
- lib/devise_yubikey_database_authenticatable/version.rb
|
69
|
+
- lib/yubikey_database_authenticatable.rb
|
70
|
+
- rails/init.rb
|
71
|
+
- test/test_helper.rb
|
72
|
+
- test/yubikey_database_authenticatable_test.rb
|
73
|
+
- yubikey_database_authenticatable.gemspec
|
74
|
+
has_rdoc: true
|
75
|
+
homepage: https://github.com/mort666/yubikey_database_authenticatable
|
76
|
+
licenses: []
|
77
|
+
|
78
|
+
post_install_message:
|
79
|
+
rdoc_options: []
|
80
|
+
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
hash: 3
|
89
|
+
segments:
|
90
|
+
- 0
|
91
|
+
version: "0"
|
92
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
93
|
+
none: false
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
hash: 3
|
98
|
+
segments:
|
99
|
+
- 0
|
100
|
+
version: "0"
|
101
|
+
requirements: []
|
102
|
+
|
103
|
+
rubyforge_project:
|
104
|
+
rubygems_version: 1.6.2
|
105
|
+
signing_key:
|
106
|
+
specification_version: 3
|
107
|
+
summary: YubiKey OTP Authentication Plugin for Devise
|
108
|
+
test_files:
|
109
|
+
- test/test_helper.rb
|
110
|
+
- test/yubikey_database_authenticatable_test.rb
|