admin_auth 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|