admin_auth 0.2.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.
- checksums.yaml +15 -0
- data/.gitignore +16 -0
- data/.rspec +1 -0
- data/.travis.yml +12 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +45 -0
- data/Rakefile +2 -0
- data/admin_auth.gemspec +30 -0
- data/app/controllers/admin/admins_controller.rb +45 -0
- data/app/controllers/admin/sessions_controller.rb +41 -0
- data/app/views/admin/admins/edit.haml +6 -0
- data/app/views/admin/admins/index.haml +21 -0
- data/app/views/admin/admins/new.haml +7 -0
- data/app/views/admin/sessions/new.haml +6 -0
- data/lib/admin_auth.rb +19 -0
- data/lib/admin_auth/controller.rb +34 -0
- data/lib/admin_auth/encryptor.rb +34 -0
- data/lib/admin_auth/model.rb +53 -0
- data/lib/admin_auth/repository.rb +36 -0
- data/lib/admin_auth/routes.rb +17 -0
- data/lib/admin_auth/version.rb +3 -0
- data/spec/lib/admin_auth/controller_spec.rb +101 -0
- data/spec/lib/admin_auth/encryptor_spec.rb +28 -0
- data/spec/lib/admin_auth/model_spec.rb +129 -0
- data/spec/lib/admin_auth/repository_spec.rb +55 -0
- data/spec/lib/admin_auth/routes_spec.rb +10 -0
- data/spec/spec_helper.rb +9 -0
- metadata +175 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NzcwYmZlNTJmZjU4MmQ5OGY4YTI5ZTk0NjVhYzFkMjNhOGQ2NGFiZg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
OGE1OTdkZWVkMTRjMzQ1MGFiOTBjYmM0N2NhOWRlNjI1OTRiOTUxYg==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MTk2ZmYyMDdiMjg5YzU0NTc4NzA1N2VhNTcxZjZhNGFlOTJiYzQyM2I1ZWNl
|
10
|
+
N2VhNjE2N2IyMWQzZjIxMzFhNzI3M2JkMDgwYzVlNTBmNTBhMDRmNjBiMzgw
|
11
|
+
NzhlNTNiNGMzMzMxZTBlOTYxMDljYzNmYmMxMGM5NDMzNjc0NmE=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZjVkODExYjBmNTU0YWQzMWI3YWRhOWUwYjY4NTllNDQ2YjZiNjdiNTdhOWNl
|
14
|
+
ZjUwMDEyNWI5OGNhMjg5N2I0ZTM0MDRhYWYxNzc2NDA4ZDVjMGJkMjc2NmY4
|
15
|
+
NWQ1ZWQ4YzQxMmQ2ZjUyZDBkNzE4ZmJjNGNkOTI0YTgzN2RlOTk=
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.travis.yml
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 2.0
|
4
|
+
- 2.1
|
5
|
+
- 2.2
|
6
|
+
script: bundle exec rspec spec
|
7
|
+
deploy:
|
8
|
+
provider: rubygems
|
9
|
+
api_key:
|
10
|
+
secure: 2CoI5hs+BpM23Q7WrZuYoG7FRzcoRVXzfsQugOQrc2qQkQV5OaIZEL1fbO1+5kdWMxd7odKeL6CUpEpkaIw1WBVlJdMBhy4EoA3UchJ1VOA6CH0y1TkaD1vDzC8AWMDNCGxlnzfRQhCiEtcS0rN6IrJj8YBwEmj2fCk47TJ0o1o=
|
11
|
+
notifications:
|
12
|
+
email: false
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Phillip Boksz
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# AdminAuth
|
2
|
+
|
3
|
+
This a small gem that extracts simple admin database authentication functionality.
|
4
|
+
|
5
|
+
It is written in a way that will work with both `ActiveRecord` and `Mongoid` and any other ORM that has the methods `all`, `new`, `create`, `where`, `update_attributes`, `destroy` (And they work in the same fashion).
|
6
|
+
|
7
|
+
It requires adding a few things to your code, but handles all the things related to authentication on this basic level, including controllers, views, routing, password encryption (with BCrypt).
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
gem 'admin_auth'
|
15
|
+
```
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
$ bundle
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
$ gem install admin_auth
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
To use this gem you need to do few things:
|
28
|
+
|
29
|
+
1. Create an `Admin` model that has two fields:
|
30
|
+
- email (string)
|
31
|
+
- encrypted_password (string)
|
32
|
+
2. Add the line `admin_auth_routes` to your `routes.rb` file.
|
33
|
+
3. Now if you add `before_action authenticate_admin!` to any controller it will send the user to the admin login page.
|
34
|
+
4. To create an admin you will need to do it in the rails console: `Admin.create(email: 'email@email.com', password: 'password', password_confirmation: 'password')`
|
35
|
+
5. Optionally, add an `after_login_path` method to your `ApplicationController` that returns the path you want to redirect to when logged in.
|
36
|
+
6. Optionally, add an `after_logout_path` method to your `ApplicationController` that returns the path you want to redirect to after logout.
|
37
|
+
7. Optionally, you can copy the views in the gem to `app/views/admin` and modify then how you see fit.
|
38
|
+
|
39
|
+
## Contributing
|
40
|
+
|
41
|
+
1. Fork it ( https://github.com/[my-github-username]/admin_auth/fork )
|
42
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
43
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
44
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
45
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/admin_auth.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'admin_auth/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "admin_auth"
|
8
|
+
spec.version = AdminAuth::VERSION
|
9
|
+
spec.authors = ["Phillip Boksz"]
|
10
|
+
spec.email = ["pboksz@gmail.com"]
|
11
|
+
spec.summary = "A gem that helps with basic database authentication."
|
12
|
+
spec.description = spec.summary
|
13
|
+
spec.license = "MIT"
|
14
|
+
spec.homepage = "https://github.com/pboksz/admin_auth"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
spec.required_ruby_version = ">= 1.9"
|
21
|
+
|
22
|
+
spec.add_dependency "bcrypt", "~> 3"
|
23
|
+
spec.add_dependency "haml", "~> 4"
|
24
|
+
spec.add_dependency "rails", "~> 4"
|
25
|
+
|
26
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
27
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
28
|
+
spec.add_development_dependency "pry", "~> 0"
|
29
|
+
spec.add_development_dependency "rspec", "~> 3"
|
30
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
class Admin::AdminsController < ::ApplicationController
|
2
|
+
before_action :authenticate_admin!
|
3
|
+
|
4
|
+
def index
|
5
|
+
render :index, locals: { admins: admins_repository.all }
|
6
|
+
end
|
7
|
+
|
8
|
+
def new
|
9
|
+
render :new, locals: { admin: admins_repository.new }
|
10
|
+
end
|
11
|
+
|
12
|
+
def create
|
13
|
+
admin = admins_repository.create(create_params)
|
14
|
+
|
15
|
+
if admin.persisted?
|
16
|
+
redirect_to admin_admins_path(locale)
|
17
|
+
else
|
18
|
+
render :new, locals: { admin: admin }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def edit
|
23
|
+
render :edit, locals: { admin: admins_repository.find(params[:id]) }
|
24
|
+
end
|
25
|
+
|
26
|
+
def update
|
27
|
+
admins_repository.update(params[:id], update_params)
|
28
|
+
redirect_to admin_admins_path(locale)
|
29
|
+
end
|
30
|
+
|
31
|
+
def destroy
|
32
|
+
admins_repository.destroy(params[:id])
|
33
|
+
redirect_to admin_admins_path(locale)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def create_params
|
39
|
+
params.require(:admin).permit(:email, :password, :password_confirmation)
|
40
|
+
end
|
41
|
+
|
42
|
+
def update_params
|
43
|
+
params.require(:admin).permit(:password, :password_confirmation)
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class Admin::SessionsController < ::ApplicationController
|
2
|
+
def new
|
3
|
+
if current_admin
|
4
|
+
redirect_to after_login_path(locale)
|
5
|
+
else
|
6
|
+
render :new, locals: { admin: admins_repository.new }
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def create
|
11
|
+
admin = admins_repository.find(email: create_params[:email])
|
12
|
+
|
13
|
+
if admin && admin.correct_password?(create_params[:password])
|
14
|
+
create_admin_session(admin)
|
15
|
+
redirect_to after_login_path(locale)
|
16
|
+
else
|
17
|
+
render :new, locals: { admin: admins_repository.new }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def destroy
|
22
|
+
destroy_admin_session
|
23
|
+
redirect_to after_logout_path(locale)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def create_admin_session(admin)
|
29
|
+
@current_admin = admin
|
30
|
+
session[:admin_id] = admin.id.to_s
|
31
|
+
end
|
32
|
+
|
33
|
+
def destroy_admin_session
|
34
|
+
@current_admin = nil
|
35
|
+
session[:admin_id] = nil
|
36
|
+
end
|
37
|
+
|
38
|
+
def create_params
|
39
|
+
params.require(:admin).permit(:email, :password)
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
.admin-auth.index
|
2
|
+
%h2= 'Admins'
|
3
|
+
.action
|
4
|
+
= link_to 'Add an Admin', new_admin_admin_path(locale), class: 'button'
|
5
|
+
= link_to 'Change your password', edit_admin_admin_path(locale, current_admin), class: 'button'
|
6
|
+
|
7
|
+
%table
|
8
|
+
%thead
|
9
|
+
%tr
|
10
|
+
%td= 'Email'
|
11
|
+
%td= 'Sign in count'
|
12
|
+
%td= 'Last signed in at'
|
13
|
+
%td= 'Actions'
|
14
|
+
%tbody
|
15
|
+
- admins.each do |admin|
|
16
|
+
%tr
|
17
|
+
%td= admin.email
|
18
|
+
%td= admin.sign_in_count
|
19
|
+
%td= admin.last_sign_in_at
|
20
|
+
%td.action= link_to 'Delete', admin_admin_path(locale, admin), method: :delete,
|
21
|
+
data: { confirm: 'Are you sure?' }, class: 'button'
|
@@ -0,0 +1,7 @@
|
|
1
|
+
.admin-auth.new
|
2
|
+
%h2= 'New admin'
|
3
|
+
= form_for admin, url: admin_admins_path(locale), method: :post do |f|
|
4
|
+
= f.text_field :email, placeholder: 'email@email.com'
|
5
|
+
= f.password_field :password, placeholder: '********'
|
6
|
+
= f.password_field :password_confirmation, placeholder: '********'
|
7
|
+
= f.submit 'Save'
|
data/lib/admin_auth.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'admin_auth/controller'
|
2
|
+
require 'admin_auth/encryptor'
|
3
|
+
require 'admin_auth/model'
|
4
|
+
require 'admin_auth/repository'
|
5
|
+
require 'admin_auth/routes'
|
6
|
+
require 'admin_auth/version'
|
7
|
+
|
8
|
+
module AdminAuth
|
9
|
+
class Engine < ::Rails::Engine
|
10
|
+
config.autoload_paths += Dir["#{config.root}/app/**/*.rb"]
|
11
|
+
end
|
12
|
+
|
13
|
+
class Railtie < ::Rails::Railtie
|
14
|
+
initializer :admin_auth do
|
15
|
+
Admin.include(AdminAuth::Model)
|
16
|
+
ApplicationController.include(AdminAuth::Controller)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module AdminAuth
|
2
|
+
module Controller
|
3
|
+
def self.included(controller)
|
4
|
+
controller.helper_method :current_admin
|
5
|
+
controller.helper_method :locale
|
6
|
+
end
|
7
|
+
|
8
|
+
def authenticate_admin!
|
9
|
+
redirect_to admin_login_path(locale) unless current_admin
|
10
|
+
end
|
11
|
+
|
12
|
+
def current_admin
|
13
|
+
@current_admin ||= admins_repository.find(id: session[:admin_id]) if session[:admin_id]
|
14
|
+
end
|
15
|
+
|
16
|
+
def locale
|
17
|
+
params[:locale]
|
18
|
+
end
|
19
|
+
|
20
|
+
def after_login_path(new_locale = locale)
|
21
|
+
admin_admins_path(new_locale)
|
22
|
+
end
|
23
|
+
|
24
|
+
def after_logout_path(new_locale = locale)
|
25
|
+
admin_root_path(new_locale)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def admins_repository
|
31
|
+
@admins_repository ||= Repository.new
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module AdminAuth
|
2
|
+
class Encryptor
|
3
|
+
require 'bcrypt'
|
4
|
+
|
5
|
+
def encrypt_password(password)
|
6
|
+
create_encrypted_password(password)
|
7
|
+
end
|
8
|
+
|
9
|
+
def compare_passwords?(password, encrypted_password)
|
10
|
+
salt = encrypted_salt(encrypted_password)
|
11
|
+
hashed_password = encrypted_password(password, salt)
|
12
|
+
|
13
|
+
compare_passwords(hashed_password, encrypted_password)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def create_encrypted_password(password)
|
19
|
+
BCrypt::Password.create(password, cost: 10)
|
20
|
+
end
|
21
|
+
|
22
|
+
def encrypted_salt(encrypted_password)
|
23
|
+
BCrypt::Password.new(encrypted_password).salt
|
24
|
+
end
|
25
|
+
|
26
|
+
def encrypted_password(password, salt)
|
27
|
+
BCrypt::Engine.hash_secret(password, salt)
|
28
|
+
end
|
29
|
+
|
30
|
+
def compare_passwords(hashed_password, encrypted_password)
|
31
|
+
Rack::Utils.secure_compare(hashed_password, encrypted_password)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module AdminAuth
|
2
|
+
module Model
|
3
|
+
EMAIL_REGEX = /\A[^@\s]+@([^@\s]+\.)+[^@\s]+\z/
|
4
|
+
PASSWORD_MINIMUM = 8
|
5
|
+
|
6
|
+
def self.included(model)
|
7
|
+
model.validates :email, format: { with: EMAIL_REGEX }
|
8
|
+
model.validates :password, :password_confirmation, length: { minimum: PASSWORD_MINIMUM }
|
9
|
+
model.validate :passwords_must_match
|
10
|
+
end
|
11
|
+
|
12
|
+
def password
|
13
|
+
@password
|
14
|
+
end
|
15
|
+
|
16
|
+
def password=(password)
|
17
|
+
@password = password
|
18
|
+
self.encrypted_password = password_encryptor.encrypt_password(password)
|
19
|
+
end
|
20
|
+
|
21
|
+
def password_confirmation
|
22
|
+
@password_confirmation
|
23
|
+
end
|
24
|
+
|
25
|
+
def password_confirmation=(password)
|
26
|
+
@password_confirmation = password
|
27
|
+
end
|
28
|
+
|
29
|
+
def correct_password?(password)
|
30
|
+
password_encryptor.compare_passwords?(password, encrypted_password)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def passwords_must_match
|
36
|
+
unless @password == @password_confirmation
|
37
|
+
error = 'must match'
|
38
|
+
errors[:password] << error
|
39
|
+
errors[:password_confirmation] << error
|
40
|
+
end
|
41
|
+
|
42
|
+
clear_passwords
|
43
|
+
end
|
44
|
+
|
45
|
+
def clear_passwords
|
46
|
+
@password = @password_confirmation = nil
|
47
|
+
end
|
48
|
+
|
49
|
+
def password_encryptor
|
50
|
+
@password_encryptor ||= Encryptor.new
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module AdminAuth
|
2
|
+
class Repository
|
3
|
+
attr_reader :klass
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@klass = Admin
|
7
|
+
end
|
8
|
+
|
9
|
+
def all
|
10
|
+
klass.all
|
11
|
+
end
|
12
|
+
|
13
|
+
def new(attributes = {})
|
14
|
+
klass.new(attributes)
|
15
|
+
end
|
16
|
+
|
17
|
+
def create(attributes)
|
18
|
+
klass.create(attributes)
|
19
|
+
end
|
20
|
+
|
21
|
+
def find(attributes)
|
22
|
+
klass.where(attributes).first
|
23
|
+
end
|
24
|
+
|
25
|
+
def update(id, attributes)
|
26
|
+
model = find(id: id)
|
27
|
+
model.update_attributes(attributes)
|
28
|
+
|
29
|
+
model
|
30
|
+
end
|
31
|
+
|
32
|
+
def destroy(id)
|
33
|
+
find(id: id).destroy
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ActionDispatch::Routing
|
2
|
+
class Mapper
|
3
|
+
def admin_auth_routes
|
4
|
+
scope '(:locale)' do
|
5
|
+
namespace :admin do
|
6
|
+
get '/login', to: 'sessions#new'
|
7
|
+
post '/login', to: 'sessions#create'
|
8
|
+
get '/logout', to: 'sessions#destroy'
|
9
|
+
|
10
|
+
resources :admins
|
11
|
+
|
12
|
+
root 'sessions#new'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe AdminAuth::Controller do
|
4
|
+
class Controller < ActionController::Base
|
5
|
+
include AdminAuth::Controller
|
6
|
+
end
|
7
|
+
|
8
|
+
subject { Controller.new }
|
9
|
+
|
10
|
+
let(:params) { {} }
|
11
|
+
before do
|
12
|
+
subject.params = params
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#authenticate_admin!' do
|
16
|
+
describe 'current admin present' do
|
17
|
+
before do
|
18
|
+
expect(subject).to receive(:current_admin).and_return(double)
|
19
|
+
expect(subject).to receive(:redirect_to).never
|
20
|
+
end
|
21
|
+
|
22
|
+
it { expect(subject.authenticate_admin!) }
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'current admin nil' do
|
26
|
+
let(:admin_login_path) { 'admin/login' }
|
27
|
+
before do
|
28
|
+
expect(subject).to receive(:current_admin).and_return(nil)
|
29
|
+
expect(subject).to receive(:admin_login_path).and_return(admin_login_path)
|
30
|
+
expect(subject).to receive(:redirect_to).with(admin_login_path)
|
31
|
+
end
|
32
|
+
|
33
|
+
it { expect(subject.authenticate_admin!) }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '#current_admin' do
|
38
|
+
describe 'session has admin id' do
|
39
|
+
let(:admin) { double(id: 1) }
|
40
|
+
let(:admins_repository) { double }
|
41
|
+
before do
|
42
|
+
allow(subject).to receive(:session).and_return({ admin_id: admin.id })
|
43
|
+
expect(subject).to receive(:admins_repository).and_return(admins_repository)
|
44
|
+
expect(admins_repository).to receive(:find).with(id: admin.id).and_return(admin)
|
45
|
+
end
|
46
|
+
|
47
|
+
it { expect(subject.current_admin).to eq admin }
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'session does not have admin id' do
|
51
|
+
before { allow(subject).to receive(:session).and_return({}) }
|
52
|
+
it { expect(subject.current_admin).to be_nil }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#locale' do
|
57
|
+
describe 'no locale in params' do
|
58
|
+
it { expect(subject.locale).to be_nil }
|
59
|
+
end
|
60
|
+
|
61
|
+
describe 'locale in params' do
|
62
|
+
let(:params) { { locale: :en } }
|
63
|
+
it { expect(subject.locale).to eq :en }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe '#after_login_path' do
|
68
|
+
describe 'no locale in params' do
|
69
|
+
before { expect(subject).to receive(:admin_admins_path).with(nil) }
|
70
|
+
it { subject.after_login_path }
|
71
|
+
end
|
72
|
+
|
73
|
+
describe 'locale in params' do
|
74
|
+
let(:params) { { locale: :en } }
|
75
|
+
|
76
|
+
describe 'no locale passed' do
|
77
|
+
before { expect(subject).to receive(:admin_admins_path).with(:en) }
|
78
|
+
it { subject.after_login_path }
|
79
|
+
end
|
80
|
+
|
81
|
+
describe 'locale passed' do
|
82
|
+
before { expect(subject).to receive(:admin_admins_path).with(:pl) }
|
83
|
+
it { subject.after_login_path(:pl) }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe '#after_logout_path' do
|
89
|
+
before { subject.params = { locale: :en } }
|
90
|
+
|
91
|
+
describe 'no locale passed' do
|
92
|
+
before { expect(subject).to receive(:admin_root_path).with(:en) }
|
93
|
+
it { subject.after_logout_path }
|
94
|
+
end
|
95
|
+
|
96
|
+
describe 'locale passed' do
|
97
|
+
before { expect(subject).to receive(:admin_root_path).with(:pl) }
|
98
|
+
it { subject.after_logout_path(:pl) }
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe AdminAuth::Encryptor do
|
4
|
+
subject { AdminAuth::Encryptor.new }
|
5
|
+
|
6
|
+
describe '#encrypt_password' do
|
7
|
+
let(:password) { double }
|
8
|
+
let(:encrypted_password) { double }
|
9
|
+
before { expect(BCrypt::Password).to receive(:create).with(password, cost: 10).and_return(encrypted_password) }
|
10
|
+
|
11
|
+
it { expect(subject.encrypt_password(password)).to eq encrypted_password }
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#compare_passwords?' do
|
15
|
+
let(:password) { double }
|
16
|
+
let(:encrypted_password) { double }
|
17
|
+
let(:salt) { double }
|
18
|
+
let(:bcrypt) { double(salt: salt) }
|
19
|
+
let(:hashed_password) { double }
|
20
|
+
before do
|
21
|
+
expect(BCrypt::Password).to receive(:new).with(encrypted_password).and_return(bcrypt)
|
22
|
+
expect(BCrypt::Engine).to receive(:hash_secret).with(password, salt).and_return(hashed_password)
|
23
|
+
expect(Rack::Utils).to receive(:secure_compare).with(hashed_password, encrypted_password).and_return(true)
|
24
|
+
end
|
25
|
+
|
26
|
+
it { expect(subject.compare_passwords?(password, encrypted_password)).to eq true }
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe AdminAuth::Model do
|
4
|
+
class Admin
|
5
|
+
include ActiveModel::Model
|
6
|
+
include AdminAuth::Model
|
7
|
+
|
8
|
+
attr_accessor :email, :encrypted_password
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:email) { 'email@email.com' }
|
12
|
+
let(:password) { '12345678' }
|
13
|
+
let(:password_confirmation) { password }
|
14
|
+
let(:attributes) { { email: email, password: password, password_confirmation: password_confirmation } }
|
15
|
+
subject { Admin.new(attributes) }
|
16
|
+
|
17
|
+
describe 'validations' do
|
18
|
+
describe 'email format' do
|
19
|
+
describe 'blank' do
|
20
|
+
let(:email) { '' }
|
21
|
+
it { expect(subject).not_to be_valid }
|
22
|
+
end
|
23
|
+
|
24
|
+
describe 'just a string' do
|
25
|
+
let(:email) { 'email' }
|
26
|
+
it { expect(subject).not_to be_valid }
|
27
|
+
end
|
28
|
+
|
29
|
+
describe 'missing domain' do
|
30
|
+
let(:email) { 'email@email' }
|
31
|
+
it { expect(subject).not_to be_valid }
|
32
|
+
end
|
33
|
+
|
34
|
+
describe 'full email' do
|
35
|
+
let(:email) { 'email@email.com' }
|
36
|
+
it { expect(subject).to be_valid }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe 'password length' do
|
41
|
+
describe 'blank' do
|
42
|
+
let(:password) { '' }
|
43
|
+
it { expect(subject).not_to be_valid }
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'too short' do
|
47
|
+
let(:password) { '1234' }
|
48
|
+
it { expect(subject).not_to be_valid }
|
49
|
+
end
|
50
|
+
|
51
|
+
describe 'a least 8 characters' do
|
52
|
+
let(:password) { '12345678' }
|
53
|
+
it { expect(subject).to be_valid }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe 'password confirmation length' do
|
58
|
+
describe 'blank' do
|
59
|
+
let(:password_confirmation) { '' }
|
60
|
+
it { expect(subject).not_to be_valid }
|
61
|
+
end
|
62
|
+
|
63
|
+
describe 'too short' do
|
64
|
+
let(:password_confirmation) { '1234' }
|
65
|
+
it { expect(subject).not_to be_valid }
|
66
|
+
end
|
67
|
+
|
68
|
+
describe 'a least 8 characters' do
|
69
|
+
let(:password_confirmation) { '12345678' }
|
70
|
+
it { expect(subject).to be_valid }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe 'passwords must match' do
|
75
|
+
describe 'they match' do
|
76
|
+
it { expect(subject).to be_valid }
|
77
|
+
end
|
78
|
+
|
79
|
+
describe 'they do not match' do
|
80
|
+
let(:password_confirmation) { 'invalid' }
|
81
|
+
it { expect(subject).not_to be_valid }
|
82
|
+
end
|
83
|
+
|
84
|
+
describe 'clears passwords after check' do
|
85
|
+
before { subject.valid? }
|
86
|
+
it { expect(subject.password).to be_nil }
|
87
|
+
it { expect(subject.password_confirmation).to be_nil }
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe 'instance methods' do
|
93
|
+
let(:password_encryptor) { double }
|
94
|
+
let(:encrypted_password) { double }
|
95
|
+
|
96
|
+
describe '#password' do
|
97
|
+
it { expect(subject.password).to eq password }
|
98
|
+
end
|
99
|
+
|
100
|
+
describe '#password=' do
|
101
|
+
before do
|
102
|
+
allow(AdminAuth::Encryptor).to receive(:new).and_return(password_encryptor)
|
103
|
+
expect(password_encryptor).to receive(:encrypt_password).with(password).and_return(encrypted_password)
|
104
|
+
end
|
105
|
+
|
106
|
+
it { expect(subject.password).to eq password }
|
107
|
+
it { expect(subject.encrypted_password).to eq encrypted_password }
|
108
|
+
end
|
109
|
+
|
110
|
+
describe '#password_confirmation' do
|
111
|
+
it { expect(subject.password_confirmation).to eq password }
|
112
|
+
end
|
113
|
+
|
114
|
+
describe '#password_confirmation=' do
|
115
|
+
before { subject.password_confirmation = password }
|
116
|
+
it { expect(subject.password_confirmation).to eq password }
|
117
|
+
end
|
118
|
+
|
119
|
+
describe '#correct_password?' do
|
120
|
+
before do
|
121
|
+
allow(AdminAuth::Encryptor).to receive(:new).and_return(password_encryptor)
|
122
|
+
expect(password_encryptor).to receive(:encrypt_password).with(password).and_return(encrypted_password)
|
123
|
+
expect(password_encryptor).to receive(:compare_passwords?).with(password, encrypted_password).and_return(true)
|
124
|
+
end
|
125
|
+
|
126
|
+
it { expect(subject.correct_password?(password)).to eq true }
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe AdminAuth::Repository do
|
4
|
+
class Admin; end
|
5
|
+
|
6
|
+
let(:admin) { double(id: 1) }
|
7
|
+
let(:admins) { [admin] }
|
8
|
+
let(:attributes) { { id: admin.id } }
|
9
|
+
subject { AdminAuth::Repository.new }
|
10
|
+
|
11
|
+
describe '#all' do
|
12
|
+
before { expect(Admin).to receive(:all).and_return(admins) }
|
13
|
+
it { expect(subject.all).to eq admins }
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#new' do
|
17
|
+
describe 'no attributes' do
|
18
|
+
before { expect(Admin).to receive(:new).with({}).and_return(admin) }
|
19
|
+
it { expect(subject.new).to eq admin }
|
20
|
+
end
|
21
|
+
|
22
|
+
describe 'with attributes' do
|
23
|
+
before { expect(Admin).to receive(:new).with(attributes).and_return(admin) }
|
24
|
+
it { expect(subject.new(attributes)).to eq admin }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#create' do
|
29
|
+
before { expect(Admin).to receive(:create).with(attributes).and_return(admin) }
|
30
|
+
it { expect(subject.create(attributes)).to eq admin }
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#find' do
|
34
|
+
before { expect(Admin).to receive(:where).with(attributes).and_return([admin]) }
|
35
|
+
it { expect(subject.find(attributes)).to eq admin }
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '#update' do
|
39
|
+
before do
|
40
|
+
expect(subject).to receive(:find).with(id: admin.id).and_return(admin)
|
41
|
+
expect(admin).to receive(:update_attributes).with(attributes)
|
42
|
+
end
|
43
|
+
|
44
|
+
it { expect(subject.update(admin.id, attributes)).to eq admin }
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '#destroy' do
|
48
|
+
before do
|
49
|
+
expect(subject).to receive(:find).with(id: admin.id).and_return(admin)
|
50
|
+
expect(admin).to receive(:destroy).and_return(admin)
|
51
|
+
end
|
52
|
+
|
53
|
+
it { expect(subject.destroy(admin.id)).to eq admin }
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActionDispatch::Routing::Mapper do
|
4
|
+
let(:set) { double(resources_path_names: []) }
|
5
|
+
subject { ActionDispatch::Routing::Mapper.new(set) }
|
6
|
+
|
7
|
+
describe '#admin_auth_routes' do
|
8
|
+
it { expect(subject.respond_to?(:admin_auth_routes)).to eq true }
|
9
|
+
end
|
10
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: admin_auth
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Phillip Boksz
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-02-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bcrypt
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: haml
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '4'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '4'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rails
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '4'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '4'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.7'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.7'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '10.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '10.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: pry
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ~>
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ~>
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ~>
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '3'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ~>
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '3'
|
111
|
+
description: A gem that helps with basic database authentication.
|
112
|
+
email:
|
113
|
+
- pboksz@gmail.com
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- .gitignore
|
119
|
+
- .rspec
|
120
|
+
- .travis.yml
|
121
|
+
- Gemfile
|
122
|
+
- LICENSE.txt
|
123
|
+
- README.md
|
124
|
+
- Rakefile
|
125
|
+
- admin_auth.gemspec
|
126
|
+
- app/controllers/admin/admins_controller.rb
|
127
|
+
- app/controllers/admin/sessions_controller.rb
|
128
|
+
- app/views/admin/admins/edit.haml
|
129
|
+
- app/views/admin/admins/index.haml
|
130
|
+
- app/views/admin/admins/new.haml
|
131
|
+
- app/views/admin/sessions/new.haml
|
132
|
+
- lib/admin_auth.rb
|
133
|
+
- lib/admin_auth/controller.rb
|
134
|
+
- lib/admin_auth/encryptor.rb
|
135
|
+
- lib/admin_auth/model.rb
|
136
|
+
- lib/admin_auth/repository.rb
|
137
|
+
- lib/admin_auth/routes.rb
|
138
|
+
- lib/admin_auth/version.rb
|
139
|
+
- spec/lib/admin_auth/controller_spec.rb
|
140
|
+
- spec/lib/admin_auth/encryptor_spec.rb
|
141
|
+
- spec/lib/admin_auth/model_spec.rb
|
142
|
+
- spec/lib/admin_auth/repository_spec.rb
|
143
|
+
- spec/lib/admin_auth/routes_spec.rb
|
144
|
+
- spec/spec_helper.rb
|
145
|
+
homepage: https://github.com/pboksz/admin_auth
|
146
|
+
licenses:
|
147
|
+
- MIT
|
148
|
+
metadata: {}
|
149
|
+
post_install_message:
|
150
|
+
rdoc_options: []
|
151
|
+
require_paths:
|
152
|
+
- lib
|
153
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
154
|
+
requirements:
|
155
|
+
- - ! '>='
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '1.9'
|
158
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
159
|
+
requirements:
|
160
|
+
- - ! '>='
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
version: '0'
|
163
|
+
requirements: []
|
164
|
+
rubyforge_project:
|
165
|
+
rubygems_version: 2.4.5
|
166
|
+
signing_key:
|
167
|
+
specification_version: 4
|
168
|
+
summary: A gem that helps with basic database authentication.
|
169
|
+
test_files:
|
170
|
+
- spec/lib/admin_auth/controller_spec.rb
|
171
|
+
- spec/lib/admin_auth/encryptor_spec.rb
|
172
|
+
- spec/lib/admin_auth/model_spec.rb
|
173
|
+
- spec/lib/admin_auth/repository_spec.rb
|
174
|
+
- spec/lib/admin_auth/routes_spec.rb
|
175
|
+
- spec/spec_helper.rb
|