casino-activerecord_authenticator 2.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,18 @@
1
+ # rcov generated
2
+ coverage
3
+ coverage.data
4
+
5
+ # rdoc generated
6
+ rdoc
7
+
8
+ # yard generated
9
+ doc
10
+ .yardoc
11
+
12
+ # bundler
13
+ .bundle
14
+
15
+ # jeweler generated
16
+ pkg
17
+
18
+ /Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color --format Fivemat
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ casino-activerecord_authenticator
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 1.9.3-p194
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 Nils Caspar
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,41 @@
1
+ # casino-activerecord_authenticator [![Build Status](https://travis-ci.org/rbCAS/casino-activerecord_authenticator.png?branch=master)](https://travis-ci.org/rbCAS/casino-activerecord_authenticator) [![Coverage Status](https://coveralls.io/repos/rbCAS/casino-activerecord_authenticator/badge.png?branch=master)](https://coveralls.io/r/rbCAS/casino-activerecord_authenticator)
2
+
3
+ Provides mechanism to use ActiveRecord as an authenticator for [CASinoCore](https://github.com/rbCAS/CASinoCore).
4
+
5
+ ActiveRecord supports many SQL databases such as MySQL, PostgreSQL, SQLite, ...
6
+
7
+ To use the ActiveRecord authenticator, configure it in your cas.yml:
8
+
9
+ authenticators:
10
+ my_company_sql:
11
+ authenticator: "ActiveRecord"
12
+ options:
13
+ connection:
14
+ adapter: "mysql2"
15
+ host: "localhost"
16
+ username: "casino"
17
+ password: "secret"
18
+ database: "users"
19
+ table: "users"
20
+ username_column: "username"
21
+ password_column: "password"
22
+ pepper: "suffix of the password" # optional
23
+ extra_attributes:
24
+ email: "email_database_column"
25
+ fullname: "displayname_database_column"
26
+
27
+ ## Contributing to casino-activerecord_authenticator
28
+
29
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
30
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
31
+ * Fork the project.
32
+ * Start a feature/bugfix branch.
33
+ * Commit and push until you are happy with your contribution.
34
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
35
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
36
+
37
+ ## Copyright
38
+
39
+ Copyright (c) 2013 Nils Caspar. See LICENSE.txt
40
+ for further details.
41
+
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require 'bundler'
2
+ require 'rake'
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ task :default => :spec
7
+
8
+ desc 'Run all specs'
9
+ RSpec::Core::RakeTask.new(:spec) do |spec|
10
+ spec.pattern = FileList['spec/**/*_spec.rb']
11
+ end
@@ -0,0 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+ require 'casino/activerecord_authenticator/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'casino-activerecord_authenticator'
7
+ s.version = CASino::ActiveRecordAuthenticator::VERSION
8
+ s.authors = ['Nils Caspar', 'Raffael Schmid']
9
+ s.email = ['ncaspar@me.com', 'raffael@yux.ch']
10
+ s.homepage = 'http://rbcas.org/'
11
+ s.license = 'MIT'
12
+ s.summary = 'Provides mechanism to use ActiveRecord as an authenticator for CASino.'
13
+ s.description = 'This gem can be used to allow the CASino backend to authenticate against an SQL server using ActiveRecord.'
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_development_dependency 'rake', '~> 10.0'
21
+ s.add_development_dependency 'rspec', '~> 2.12'
22
+ s.add_development_dependency 'simplecov', '~> 0.7'
23
+ s.add_development_dependency 'sqlite3', '~> 1.3.7'
24
+ s.add_development_dependency 'coveralls'
25
+ s.add_development_dependency 'fivemat'
26
+
27
+ s.add_runtime_dependency 'activerecord', '~> 3.2.12'
28
+ s.add_runtime_dependency 'unix-crypt', '~> 1.1'
29
+ s.add_runtime_dependency 'bcrypt-ruby', '~> 3.0'
30
+ s.add_runtime_dependency 'casino', '~> 2.0'
31
+ end
@@ -0,0 +1 @@
1
+ require 'casino-activerecord_authenticator'
@@ -0,0 +1,2 @@
1
+ require 'casino/activerecord_authenticator/version'
2
+ require 'casino/activerecord_authenticator'
@@ -0,0 +1,72 @@
1
+ require 'active_record'
2
+ require 'unix_crypt'
3
+ require 'bcrypt'
4
+
5
+ class CASino::ActiveRecordAuthenticator
6
+
7
+ class AuthDatabase < ::ActiveRecord::Base
8
+ self.abstract_class = true
9
+ end
10
+
11
+ # @param [Hash] options
12
+ def initialize(options)
13
+ @options = options
14
+
15
+ eval <<-END
16
+ class #{self.class.to_s}::#{@options[:table].classify} < AuthDatabase
17
+ set_table_name "#{@options[:table]}"
18
+ end
19
+ END
20
+
21
+ @model = "#{self.class.to_s}::#{@options[:table].classify}".constantize
22
+ @model.establish_connection @options[:connection]
23
+ end
24
+
25
+ def validate(username, password)
26
+ @model.verify_active_connections!
27
+ user = @model.send("find_by_#{@options[:username_column]}!", username)
28
+ password_from_database = user.send(@options[:password_column])
29
+
30
+ if valid_password?(password, password_from_database)
31
+ { username: user.send(@options[:username_column]), extra_attributes: extra_attributes(user) }
32
+ else
33
+ false
34
+ end
35
+
36
+ rescue ActiveRecord::RecordNotFound
37
+ false
38
+ end
39
+
40
+ private
41
+ def valid_password?(password, password_from_database)
42
+ return false if password_from_database.blank?
43
+ magic = password_from_database.split('$')[1]
44
+ case magic
45
+ when /\A2a?\z/
46
+ valid_password_with_bcrypt?(password, password_from_database)
47
+ else
48
+ valid_password_with_unix_crypt?(password, password_from_database)
49
+ end
50
+ end
51
+
52
+ def valid_password_with_bcrypt?(password, password_from_database)
53
+ password_with_pepper = password + @options[:pepper].to_s
54
+ BCrypt::Password.new(password_from_database) == password_with_pepper
55
+ end
56
+
57
+ def valid_password_with_unix_crypt?(password, password_from_database)
58
+ UnixCrypt.valid?(password, password_from_database)
59
+ end
60
+
61
+ def extra_attributes(user)
62
+ attributes = {}
63
+ extra_attributes_option.each do |attribute_name, database_column|
64
+ attributes[attribute_name] = user.send(database_column)
65
+ end
66
+ attributes
67
+ end
68
+
69
+ def extra_attributes_option
70
+ @options[:extra_attributes] || {}
71
+ end
72
+ end
@@ -0,0 +1,5 @@
1
+ module CASino
2
+ class ActiveRecordAuthenticator
3
+ VERSION = '2.0.0'
4
+ end
5
+ end
@@ -0,0 +1,137 @@
1
+ require 'spec_helper'
2
+ require 'casino/activerecord_authenticator'
3
+
4
+ describe CASino::ActiveRecordAuthenticator do
5
+
6
+ let(:pepper) { nil }
7
+ let(:extra_attributes) {{ email: 'mail_address' }}
8
+ let(:options) do
9
+ {
10
+ connection: {
11
+ adapter: 'sqlite3',
12
+ database: '/tmp/casino-test-auth.sqlite'
13
+ },
14
+ table: 'users',
15
+ username_column: 'username',
16
+ password_column: 'password',
17
+ pepper: pepper,
18
+ extra_attributes: extra_attributes
19
+ }
20
+ end
21
+
22
+ subject { described_class.new(options) }
23
+
24
+ before do
25
+ subject # ensure everything is initialized
26
+
27
+ ::ActiveRecord::Base.establish_connection options[:connection]
28
+
29
+ ActiveRecord::Migration.suppress_messages do
30
+ ActiveRecord::Schema.define do
31
+ create_table :users do |t|
32
+ t.string :username
33
+ t.string :password
34
+ t.string :mail_address
35
+ end
36
+ end
37
+ end
38
+
39
+ described_class::User.create!(
40
+ username: 'test',
41
+ password: '$5$cegeasjoos$vPX5AwDqOTGocGjehr7k1IYp6Kt.U4FmMUa.1l6NrzD', # password: testpassword
42
+ mail_address: 'mail@example.org')
43
+ end
44
+
45
+ after do
46
+ ActiveRecord::Migration.suppress_messages do
47
+ ActiveRecord::Schema.define do
48
+ drop_table :users
49
+ end
50
+ end
51
+ end
52
+
53
+ describe '#validate' do
54
+
55
+ context 'valid username' do
56
+ context 'valid password' do
57
+ it 'returns the username' do
58
+ subject.validate('test', 'testpassword')[:username].should eq('test')
59
+ end
60
+
61
+ it 'returns the extra attributes' do
62
+ subject.validate('test', 'testpassword')[:extra_attributes][:email].should eq('mail@example.org')
63
+ end
64
+
65
+ context 'when no extra attributes given' do
66
+ let(:extra_attributes) { nil }
67
+
68
+ it 'returns an empty hash for extra attributes' do
69
+ subject.validate('test', 'testpassword')[:extra_attributes].should eq({})
70
+ end
71
+ end
72
+ end
73
+
74
+ context 'invalid password' do
75
+ it 'returns false' do
76
+ subject.validate('test', 'wrongpassword').should eq(false)
77
+ end
78
+ end
79
+
80
+ context 'NULL password field' do
81
+ it 'returns false' do
82
+ user = described_class::User.first
83
+ user.password = nil
84
+ user.save!
85
+
86
+ subject.validate('test', 'wrongpassword').should eq(false)
87
+ end
88
+ end
89
+
90
+ context 'empty password field' do
91
+ it 'returns false' do
92
+ user = described_class::User.first
93
+ user.password = ''
94
+ user.save!
95
+
96
+ subject.validate('test', 'wrongpassword').should eq(false)
97
+ end
98
+ end
99
+ end
100
+
101
+ context 'invalid username' do
102
+ it 'returns false' do
103
+ subject.validate('does-not-exist', 'testpassword').should eq(false)
104
+ end
105
+ end
106
+
107
+ context 'support for bcrypt' do
108
+ before do
109
+ described_class::User.create!(
110
+ username: 'test2',
111
+ password: '$2a$10$dRFLSkYedQ05sqMs3b265e0nnJSoa9RhbpKXU79FDPVeuS1qBG7Jq', # password: testpassword2
112
+ mail_address: 'mail@example.org')
113
+ end
114
+
115
+ it 'is able to handle bcrypt password hashes' do
116
+ subject.validate('test2', 'testpassword2').should be_instance_of(Hash)
117
+ end
118
+ end
119
+
120
+ context 'support for bcrypt with pepper' do
121
+ let(:pepper) { 'abcdefg' }
122
+
123
+ before do
124
+ described_class::User.create!(
125
+ username: 'test3',
126
+ password: '$2a$10$ndCGPWg5JFMQH/Kl6xKe.OGNaiG7CFIAVsgAOJU75Q6g5/FpY5eX6', # password: testpassword3, pepper: abcdefg
127
+ mail_address: 'mail@example.org')
128
+ end
129
+
130
+ it 'is able to handle bcrypt password hashes' do
131
+ subject.validate('test3', 'testpassword3').should be_instance_of(Hash)
132
+ end
133
+ end
134
+
135
+ end
136
+
137
+ end
@@ -0,0 +1,24 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'simplecov'
5
+ require 'coveralls'
6
+ SimpleCov.formatter = Coveralls::SimpleCov::Formatter
7
+ SimpleCov.start do
8
+ add_filter '/spec'
9
+ end
10
+
11
+ require 'rspec'
12
+ require 'casino-activerecord_authenticator'
13
+
14
+ # Requires supporting files with custom matchers and macros, etc,
15
+ # in ./support/ and its subdirectories.
16
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
17
+
18
+ RSpec.configure do |config|
19
+ # Run specs in random order to surface order dependencies. If you find an
20
+ # order dependency and want to debug it, you can fix the order by providing
21
+ # the seed, which is printed after each run.
22
+ # --seed 1234
23
+ config.order = 'random'
24
+ end
metadata ADDED
@@ -0,0 +1,227 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: casino-activerecord_authenticator
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Nils Caspar
9
+ - Raffael Schmid
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2013-10-29 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rake
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: '10.0'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ version: '10.0'
31
+ - !ruby/object:Gem::Dependency
32
+ name: rspec
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ~>
37
+ - !ruby/object:Gem::Version
38
+ version: '2.12'
39
+ type: :development
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: '2.12'
47
+ - !ruby/object:Gem::Dependency
48
+ name: simplecov
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '0.7'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ version: '0.7'
63
+ - !ruby/object:Gem::Dependency
64
+ name: sqlite3
65
+ requirement: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ~>
69
+ - !ruby/object:Gem::Version
70
+ version: 1.3.7
71
+ type: :development
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ~>
77
+ - !ruby/object:Gem::Version
78
+ version: 1.3.7
79
+ - !ruby/object:Gem::Dependency
80
+ name: coveralls
81
+ requirement: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ type: :development
88
+ prerelease: false
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ - !ruby/object:Gem::Dependency
96
+ name: fivemat
97
+ requirement: !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ! '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: activerecord
113
+ requirement: !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ~>
117
+ - !ruby/object:Gem::Version
118
+ version: 3.2.12
119
+ type: :runtime
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ none: false
123
+ requirements:
124
+ - - ~>
125
+ - !ruby/object:Gem::Version
126
+ version: 3.2.12
127
+ - !ruby/object:Gem::Dependency
128
+ name: unix-crypt
129
+ requirement: !ruby/object:Gem::Requirement
130
+ none: false
131
+ requirements:
132
+ - - ~>
133
+ - !ruby/object:Gem::Version
134
+ version: '1.1'
135
+ type: :runtime
136
+ prerelease: false
137
+ version_requirements: !ruby/object:Gem::Requirement
138
+ none: false
139
+ requirements:
140
+ - - ~>
141
+ - !ruby/object:Gem::Version
142
+ version: '1.1'
143
+ - !ruby/object:Gem::Dependency
144
+ name: bcrypt-ruby
145
+ requirement: !ruby/object:Gem::Requirement
146
+ none: false
147
+ requirements:
148
+ - - ~>
149
+ - !ruby/object:Gem::Version
150
+ version: '3.0'
151
+ type: :runtime
152
+ prerelease: false
153
+ version_requirements: !ruby/object:Gem::Requirement
154
+ none: false
155
+ requirements:
156
+ - - ~>
157
+ - !ruby/object:Gem::Version
158
+ version: '3.0'
159
+ - !ruby/object:Gem::Dependency
160
+ name: casino
161
+ requirement: !ruby/object:Gem::Requirement
162
+ none: false
163
+ requirements:
164
+ - - ~>
165
+ - !ruby/object:Gem::Version
166
+ version: '2.0'
167
+ type: :runtime
168
+ prerelease: false
169
+ version_requirements: !ruby/object:Gem::Requirement
170
+ none: false
171
+ requirements:
172
+ - - ~>
173
+ - !ruby/object:Gem::Version
174
+ version: '2.0'
175
+ description: This gem can be used to allow the CASino backend to authenticate against
176
+ an SQL server using ActiveRecord.
177
+ email:
178
+ - ncaspar@me.com
179
+ - raffael@yux.ch
180
+ executables: []
181
+ extensions: []
182
+ extra_rdoc_files: []
183
+ files:
184
+ - .gitignore
185
+ - .rspec
186
+ - .ruby-gemset
187
+ - .ruby-version
188
+ - .travis.yml
189
+ - Gemfile
190
+ - LICENSE.txt
191
+ - README.md
192
+ - Rakefile
193
+ - casino-activerecord_authenticator.gemspec
194
+ - lib/casino-active_record_authenticator.rb
195
+ - lib/casino-activerecord_authenticator.rb
196
+ - lib/casino/activerecord_authenticator.rb
197
+ - lib/casino/activerecord_authenticator/version.rb
198
+ - spec/casino_core/activerecord_authenticator_spec.rb
199
+ - spec/spec_helper.rb
200
+ homepage: http://rbcas.org/
201
+ licenses:
202
+ - MIT
203
+ post_install_message:
204
+ rdoc_options: []
205
+ require_paths:
206
+ - lib
207
+ required_ruby_version: !ruby/object:Gem::Requirement
208
+ none: false
209
+ requirements:
210
+ - - ! '>='
211
+ - !ruby/object:Gem::Version
212
+ version: '0'
213
+ required_rubygems_version: !ruby/object:Gem::Requirement
214
+ none: false
215
+ requirements:
216
+ - - ! '>='
217
+ - !ruby/object:Gem::Version
218
+ version: '0'
219
+ requirements: []
220
+ rubyforge_project:
221
+ rubygems_version: 1.8.23
222
+ signing_key:
223
+ specification_version: 3
224
+ summary: Provides mechanism to use ActiveRecord as an authenticator for CASino.
225
+ test_files:
226
+ - spec/casino_core/activerecord_authenticator_spec.rb
227
+ - spec/spec_helper.rb