authem 2.0.1 → 2.1.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 +4 -4
- data/CHANGELOG.md +12 -0
- data/{README.markdown → README.md} +1 -1
- data/lib/authem.rb +9 -1
- data/lib/authem/controller.rb +1 -3
- data/lib/authem/railtie.rb +0 -1
- data/lib/authem/role.rb +1 -3
- data/lib/authem/session.rb +0 -1
- data/lib/authem/support.rb +3 -9
- data/lib/authem/user.rb +0 -2
- data/lib/authem/version.rb +1 -1
- metadata +6 -25
- data/.gitignore +0 -3
- data/.rspec +0 -2
- data/.ruby-gemset +0 -1
- data/.ruby-version +0 -1
- data/.travis.yml +0 -8
- data/Appraisals +0 -12
- data/Gemfile +0 -11
- data/Rakefile +0 -12
- data/authem.gemspec +0 -25
- data/gemfiles/rails_4.0.gemfile +0 -17
- data/gemfiles/rails_4.1.gemfile +0 -16
- data/spec/controller_spec.rb +0 -413
- data/spec/session_spec.rb +0 -52
- data/spec/spec_helper.rb +0 -4
- data/spec/support/active_record.rb +0 -45
- data/spec/support/i18n.rb +0 -1
- data/spec/support/time.rb +0 -1
- data/spec/token_spec.rb +0 -10
- data/spec/user_spec.rb +0 -116
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7d89fb3efe1897f6405ff311cc4041995c47b87c
|
4
|
+
data.tar.gz: 55af0e6279f7222c79453826a938844d06fdff59
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1edf72a5c758c9feb280ac87a6edff176d9aebcd49951a72d7f25c7aa26dbfdf3ca516a382ffec2c5d071587780c2943823b7c5a3ee239d84826b4806f3143a0
|
7
|
+
data.tar.gz: 9892818aec6d3b5cd73e06cc2bb3648240a1ec418ae5545e52ddc37434fa242dee28b574db96c294775f028e20b905d927240b3ccda815a3afb5e30e1c5fd810
|
data/CHANGELOG.md
CHANGED
@@ -6,7 +6,7 @@ Authem is an email-based authentication library for ruby web apps.
|
|
6
6
|
|
7
7
|
## Compatibility
|
8
8
|
|
9
|
-
Authem requires Ruby
|
9
|
+
Authem requires Ruby 1.9.3 or newer
|
10
10
|
|
11
11
|
[](http://travis-ci.org/paulelliott/authem)
|
12
12
|
[](https://codeclimate.com/github/paulelliott/authem)
|
data/lib/authem.rb
CHANGED
@@ -1,6 +1,14 @@
|
|
1
|
+
require "active_support/all"
|
1
2
|
require "authem/railtie"
|
2
|
-
require "authem/user"
|
3
3
|
require "authem/version"
|
4
4
|
|
5
5
|
module Authem
|
6
|
+
autoload :Controller, "authem/controller"
|
7
|
+
autoload :Role, "authem/role"
|
8
|
+
autoload :Session, "authem/session"
|
9
|
+
autoload :Support, "authem/support"
|
10
|
+
autoload :Token, "authem/token"
|
11
|
+
autoload :User, "authem/user"
|
12
|
+
autoload :AmbigousRoleError, "authem/errors/ambigous_role"
|
13
|
+
autoload :UnknownRoleError, "authem/errors/unknown_role"
|
6
14
|
end
|
data/lib/authem/controller.rb
CHANGED
@@ -1,6 +1,3 @@
|
|
1
|
-
require "active_support/concern"
|
2
|
-
require "authem/role"
|
3
|
-
|
4
1
|
module Authem
|
5
2
|
module Controller
|
6
3
|
extend ActiveSupport::Concern
|
@@ -10,6 +7,7 @@ module Authem
|
|
10
7
|
module SessionManagementMethods
|
11
8
|
def sign_in(model, options={})
|
12
9
|
role = options.fetch(:as){ self.class.authem_role_for(model) }
|
10
|
+
session.delete :_csrf_token if session.respond_to?(:delete)
|
13
11
|
public_send "sign_in_#{role}", model, options
|
14
12
|
end
|
15
13
|
|
data/lib/authem/railtie.rb
CHANGED
data/lib/authem/role.rb
CHANGED
@@ -1,10 +1,8 @@
|
|
1
|
-
require "authem/support"
|
2
|
-
|
3
1
|
module Authem
|
4
2
|
class Role
|
5
3
|
attr_reader :controller, :name, :options
|
6
4
|
|
7
|
-
METHODS = %w[current sign_in signed_in?
|
5
|
+
METHODS = %w[current sign_in signed_in? require_role sign_out clear_for deny_access].map(&:to_sym)
|
8
6
|
|
9
7
|
METHODS.each do |method_name|
|
10
8
|
define_method method_name do |controller, *args|
|
data/lib/authem/session.rb
CHANGED
data/lib/authem/support.rb
CHANGED
@@ -1,8 +1,3 @@
|
|
1
|
-
require "active_support/core_ext/module/delegation"
|
2
|
-
require "authem/session"
|
3
|
-
require "authem/errors/ambigous_role"
|
4
|
-
require "authem/errors/unknown_role"
|
5
|
-
|
6
1
|
module Authem
|
7
2
|
class Support
|
8
3
|
attr_reader :role, :controller
|
@@ -15,7 +10,7 @@ module Authem
|
|
15
10
|
if ivar_defined?
|
16
11
|
ivar_get
|
17
12
|
else
|
18
|
-
ivar_set
|
13
|
+
ivar_set(fetch_subject_by_token)
|
19
14
|
end
|
20
15
|
end
|
21
16
|
|
@@ -45,7 +40,7 @@ module Authem
|
|
45
40
|
Authem::Session.by_subject(record).where(role: role_name).delete_all
|
46
41
|
end
|
47
42
|
|
48
|
-
def
|
43
|
+
def require_role
|
49
44
|
unless signed_in?
|
50
45
|
session[:return_to_url] = request.url unless request.xhr?
|
51
46
|
controller.send "deny_#{role_name}_access"
|
@@ -87,12 +82,11 @@ module Authem
|
|
87
82
|
end
|
88
83
|
|
89
84
|
def save_cookie(auth_session)
|
90
|
-
|
85
|
+
cookies.signed[key] = {
|
91
86
|
value: auth_session.token,
|
92
87
|
expires: auth_session.expires_at,
|
93
88
|
domain: :all
|
94
89
|
}
|
95
|
-
cookies.signed[key] = cookie_value
|
96
90
|
end
|
97
91
|
|
98
92
|
def get_auth_session_by_token(token)
|
data/lib/authem/user.rb
CHANGED
data/lib/authem/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: authem
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paul Elliott
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2016-03-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -29,14 +29,14 @@ dependencies:
|
|
29
29
|
name: railties
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
|
-
- - "
|
32
|
+
- - ">="
|
33
33
|
- !ruby/object:Gem::Version
|
34
34
|
version: '4.0'
|
35
35
|
type: :runtime
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
|
-
- - "
|
39
|
+
- - ">="
|
40
40
|
- !ruby/object:Gem::Version
|
41
41
|
version: '4.0'
|
42
42
|
- !ruby/object:Gem::Dependency
|
@@ -61,20 +61,9 @@ executables: []
|
|
61
61
|
extensions: []
|
62
62
|
extra_rdoc_files: []
|
63
63
|
files:
|
64
|
-
- ".gitignore"
|
65
|
-
- ".rspec"
|
66
|
-
- ".ruby-gemset"
|
67
|
-
- ".ruby-version"
|
68
|
-
- ".travis.yml"
|
69
|
-
- Appraisals
|
70
64
|
- CHANGELOG.md
|
71
|
-
- Gemfile
|
72
65
|
- LICENSE
|
73
|
-
- README.
|
74
|
-
- Rakefile
|
75
|
-
- authem.gemspec
|
76
|
-
- gemfiles/rails_4.0.gemfile
|
77
|
-
- gemfiles/rails_4.1.gemfile
|
66
|
+
- README.md
|
78
67
|
- lib/authem.rb
|
79
68
|
- lib/authem/controller.rb
|
80
69
|
- lib/authem/errors/ambigous_role.rb
|
@@ -91,14 +80,6 @@ files:
|
|
91
80
|
- lib/generators/authem/user/templates/create_table_migration.rb
|
92
81
|
- lib/generators/authem/user/templates/model.rb
|
93
82
|
- lib/generators/authem/user/user_generator.rb
|
94
|
-
- spec/controller_spec.rb
|
95
|
-
- spec/session_spec.rb
|
96
|
-
- spec/spec_helper.rb
|
97
|
-
- spec/support/active_record.rb
|
98
|
-
- spec/support/i18n.rb
|
99
|
-
- spec/support/time.rb
|
100
|
-
- spec/token_spec.rb
|
101
|
-
- spec/user_spec.rb
|
102
83
|
homepage: https://github.com/paulelliott/authem
|
103
84
|
licenses:
|
104
85
|
- MIT
|
@@ -119,7 +100,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
119
100
|
version: '0'
|
120
101
|
requirements: []
|
121
102
|
rubyforge_project:
|
122
|
-
rubygems_version: 2.
|
103
|
+
rubygems_version: 2.5.1
|
123
104
|
signing_key:
|
124
105
|
specification_version: 4
|
125
106
|
summary: Authem authenticates them by email
|
data/.gitignore
DELETED
data/.rspec
DELETED
data/.ruby-gemset
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
authem
|
data/.ruby-version
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
ruby-2.1.3
|
data/.travis.yml
DELETED
data/Appraisals
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
appraise "rails-4.1" do
|
2
|
-
gem "activerecord", "~> 4.1.0", require: "active_record"
|
3
|
-
gem "bcrypt", "~> 3.1"
|
4
|
-
gem "railties", "~> 4.0"
|
5
|
-
end
|
6
|
-
|
7
|
-
appraise "rails-4.0" do
|
8
|
-
gem "activerecord", "~> 4.0.0", require: "active_record"
|
9
|
-
gem "bcrypt", "~> 3.1"
|
10
|
-
gem "railties", "~> 4.0"
|
11
|
-
gem "protected_attributes"
|
12
|
-
end
|
data/Gemfile
DELETED
data/Rakefile
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
require "bundler/setup"
|
2
|
-
require "bundler/gem_tasks"
|
3
|
-
|
4
|
-
if !ENV["APPRAISAL_INITIALIZED"] && !ENV["TRAVIS"]
|
5
|
-
require "appraisal/task"
|
6
|
-
Appraisal::Task.new
|
7
|
-
task default: :appraisal
|
8
|
-
else
|
9
|
-
require "rspec/core/rake_task"
|
10
|
-
RSpec::Core::RakeTask.new
|
11
|
-
task default: :spec
|
12
|
-
end
|
data/authem.gemspec
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
lib = File.expand_path("../lib", __FILE__)
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require 'authem/version'
|
5
|
-
|
6
|
-
Gem::Specification.new do |spec|
|
7
|
-
spec.name = "authem"
|
8
|
-
spec.version = Authem::VERSION
|
9
|
-
spec.authors = ["Paul Elliott", "Pavel Pravosud"]
|
10
|
-
spec.email = ["paul@codingfrontier.com", "pavel@pravosud.com"]
|
11
|
-
spec.summary = "Authem authenticates them by email"
|
12
|
-
spec.description = "Authem provides a simple solution for email-based authentication"
|
13
|
-
spec.homepage = "https://github.com/paulelliott/authem"
|
14
|
-
spec.license = "MIT"
|
15
|
-
|
16
|
-
spec.required_ruby_version = ">= 1.9.3"
|
17
|
-
|
18
|
-
spec.files = `git ls-files`.split($/)
|
19
|
-
spec.test_files = spec.files.grep("spec")
|
20
|
-
spec.require_path = "lib"
|
21
|
-
|
22
|
-
spec.add_dependency "activesupport", ">= 4.0.4"
|
23
|
-
spec.add_dependency "railties", "~> 4.0"
|
24
|
-
spec.add_dependency "bcrypt", "~> 3.1"
|
25
|
-
end
|
data/gemfiles/rails_4.0.gemfile
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
# This file was generated by Appraisal
|
2
|
-
|
3
|
-
source "https://rubygems.org"
|
4
|
-
|
5
|
-
gem "appraisal"
|
6
|
-
gem "activerecord", "~> 4.0.0", :require => "active_record"
|
7
|
-
gem "bcrypt", "~> 3.1"
|
8
|
-
gem "railties", "~> 4.0"
|
9
|
-
gem "protected_attributes"
|
10
|
-
|
11
|
-
group :test do
|
12
|
-
gem "rspec", "~> 3.0"
|
13
|
-
gem "rake", "~> 10.3"
|
14
|
-
gem "sqlite3", :platform => :ruby
|
15
|
-
gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby
|
16
|
-
gem "pry"
|
17
|
-
end
|
data/gemfiles/rails_4.1.gemfile
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
# This file was generated by Appraisal
|
2
|
-
|
3
|
-
source "https://rubygems.org"
|
4
|
-
|
5
|
-
gem "appraisal"
|
6
|
-
gem "activerecord", "~> 4.1.0", :require => "active_record"
|
7
|
-
gem "bcrypt", "~> 3.1"
|
8
|
-
gem "railties", "~> 4.0"
|
9
|
-
|
10
|
-
group :test do
|
11
|
-
gem "rspec", "~> 3.0"
|
12
|
-
gem "rake", "~> 10.3"
|
13
|
-
gem "sqlite3", :platform => :ruby
|
14
|
-
gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby
|
15
|
-
gem "pry"
|
16
|
-
end
|
data/spec/controller_spec.rb
DELETED
@@ -1,413 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe Authem::Controller do
|
4
|
-
class User < ActiveRecord::Base
|
5
|
-
self.table_name = :users
|
6
|
-
end
|
7
|
-
|
8
|
-
module MyNamespace
|
9
|
-
class SuperUser < ActiveRecord::Base
|
10
|
-
self.table_name = :users
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
class BaseController
|
15
|
-
include Authem::Controller
|
16
|
-
|
17
|
-
class << self
|
18
|
-
def helper_methods_list
|
19
|
-
@helper_methods_list ||= []
|
20
|
-
end
|
21
|
-
|
22
|
-
def helper_method(*methods)
|
23
|
-
helper_methods_list.concat methods
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def clear_session!
|
28
|
-
session.clear
|
29
|
-
end
|
30
|
-
|
31
|
-
def reloaded
|
32
|
-
original_session, original_cookies = session, cookies
|
33
|
-
|
34
|
-
self.class.new.tap do |controller|
|
35
|
-
controller.class_eval do
|
36
|
-
define_method(:session){ original_session }
|
37
|
-
define_method(:cookies){ original_cookies }
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
def session
|
45
|
-
@_session ||= HashWithIndifferentAccess.new
|
46
|
-
end
|
47
|
-
|
48
|
-
def cookies
|
49
|
-
@_cookies ||= Cookies.new
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
class Cookies < HashWithIndifferentAccess
|
54
|
-
attr_reader :expires_at
|
55
|
-
|
56
|
-
def permanent
|
57
|
-
self
|
58
|
-
end
|
59
|
-
|
60
|
-
alias_method :signed, :permanent
|
61
|
-
|
62
|
-
def []=(key, value)
|
63
|
-
if value.kind_of?(Hash) && value.key?(:expires)
|
64
|
-
@expires_at = value[:expires]
|
65
|
-
super key, value.fetch(:value)
|
66
|
-
else
|
67
|
-
super
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def delete(key, *)
|
72
|
-
super key
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def build_controller
|
77
|
-
controller_klass.new
|
78
|
-
end
|
79
|
-
|
80
|
-
let(:controller){ build_controller.tap{ |c| allow(c).to receive(:request){ request }}}
|
81
|
-
let(:view_helpers){ controller_klass.helper_methods_list }
|
82
|
-
let(:cookies){ controller.send(:cookies) }
|
83
|
-
let(:session){ controller.send(:session) }
|
84
|
-
let(:reloaded_controller){ controller.reloaded }
|
85
|
-
let(:request_url){ "http://example.com/foo" }
|
86
|
-
let(:request){ double("Request", url: request_url, xhr?: false) }
|
87
|
-
|
88
|
-
context "with one role" do
|
89
|
-
let(:user){ User.create(email: "joe@example.com") }
|
90
|
-
let(:controller_klass){ Class.new(BaseController){ authem_for :user }}
|
91
|
-
|
92
|
-
it "has current_user method" do
|
93
|
-
expect(controller).to respond_to(:current_user)
|
94
|
-
end
|
95
|
-
|
96
|
-
it "has sign_in_user method" do
|
97
|
-
expect(controller).to respond_to(:sign_in_user)
|
98
|
-
end
|
99
|
-
|
100
|
-
it "has clear_all_user_sessions_for method" do
|
101
|
-
expect(controller).to respond_to(:clear_all_user_sessions_for)
|
102
|
-
end
|
103
|
-
|
104
|
-
it "has require_user method" do
|
105
|
-
expect(controller).to respond_to(:require_user)
|
106
|
-
end
|
107
|
-
|
108
|
-
it "has user_signed_in? method" do
|
109
|
-
expect(controller).to respond_to(:user_signed_in?)
|
110
|
-
end
|
111
|
-
|
112
|
-
it "has redirect_back_or_to method" do
|
113
|
-
expect(controller).to respond_to(:redirect_back_or_to)
|
114
|
-
end
|
115
|
-
|
116
|
-
it "can clear all sessions using clear_all_sessions method" do
|
117
|
-
expect(controller).to receive(:clear_all_user_sessions_for).with(user)
|
118
|
-
controller.clear_all_sessions_for user
|
119
|
-
end
|
120
|
-
|
121
|
-
it "defines view helpers" do
|
122
|
-
expect(view_helpers).to include(:current_user)
|
123
|
-
expect(view_helpers).to include(:user_signed_in?)
|
124
|
-
end
|
125
|
-
|
126
|
-
it "raises error when calling clear_all_sessions_for with nil" do
|
127
|
-
expect{ controller.clear_all_sessions_for nil }.to raise_error(ArgumentError)
|
128
|
-
expect{ controller.clear_all_user_sessions_for nil }.to raise_error(ArgumentError)
|
129
|
-
end
|
130
|
-
|
131
|
-
it "can sign in user using sign_in_user method" do
|
132
|
-
controller.sign_in_user user
|
133
|
-
expect(controller.current_user).to eq(user)
|
134
|
-
expect(reloaded_controller.current_user).to eq(user)
|
135
|
-
end
|
136
|
-
|
137
|
-
it "can show status of current session with user_signed_in? method" do
|
138
|
-
expect{ controller.sign_in user }.to change(controller, :user_signed_in?).from(false).to(true)
|
139
|
-
expect{ controller.sign_out user }.to change(controller, :user_signed_in?).from(true).to(false)
|
140
|
-
end
|
141
|
-
|
142
|
-
it "can store session token in a cookie when :remember option is used" do
|
143
|
-
expect{ controller.sign_in user, remember: true }.to change(cookies, :size).by(1)
|
144
|
-
end
|
145
|
-
|
146
|
-
it "throws NotImplementedError when require strategy is not defined" do
|
147
|
-
message = "No strategy for require_user defined. Please define `deny_user_access` method in your controller"
|
148
|
-
expect{ controller.require_user }.to raise_error(NotImplementedError, message)
|
149
|
-
end
|
150
|
-
|
151
|
-
it "can require authenticated user with require_user method" do
|
152
|
-
def controller.deny_user_access; redirect_to :custom_path; end
|
153
|
-
expect(controller).to receive(:redirect_to).with(:custom_path)
|
154
|
-
expect{ controller.require_user }.to change{ session[:return_to_url] }.from(nil).to(request_url)
|
155
|
-
end
|
156
|
-
|
157
|
-
it "sets cookie expiration date when :remember options is used" do
|
158
|
-
controller.sign_in user, remember: true, ttl: 1.week
|
159
|
-
expect(cookies.expires_at).to be_within(1.second).of(1.week.from_now)
|
160
|
-
end
|
161
|
-
|
162
|
-
it "can restore user from cookie when session is lost" do
|
163
|
-
controller.sign_in user, remember: true
|
164
|
-
controller.clear_session!
|
165
|
-
expect(controller.reloaded.current_user).to eq(user)
|
166
|
-
end
|
167
|
-
|
168
|
-
it "does not use cookies by default" do
|
169
|
-
expect{ controller.sign_in user }.not_to change(cookies, :size)
|
170
|
-
end
|
171
|
-
|
172
|
-
it "returns session object on sign in" do
|
173
|
-
result = controller.sign_in_user(user)
|
174
|
-
expect(result).to be_kind_of(::Authem::Session)
|
175
|
-
end
|
176
|
-
|
177
|
-
it "allows to specify ttl using sign_in_user with ttl option" do
|
178
|
-
session = controller.sign_in_user(user, ttl: 40.minutes)
|
179
|
-
expect(session.ttl).to eq(40.minutes)
|
180
|
-
end
|
181
|
-
|
182
|
-
it "forgets user after session has expired" do
|
183
|
-
session = controller.sign_in(user)
|
184
|
-
session.update_column :expires_at, 1.minute.ago
|
185
|
-
expect(reloaded_controller.current_user).to be_nil
|
186
|
-
end
|
187
|
-
|
188
|
-
it "renews session ttl each time it is used" do
|
189
|
-
session = controller.sign_in(user, ttl: 1.day)
|
190
|
-
session.update_column :expires_at, 1.minute.from_now
|
191
|
-
reloaded_controller.current_user
|
192
|
-
expect(session.reload.expires_at).to be_within(1.second).of(1.day.from_now)
|
193
|
-
end
|
194
|
-
|
195
|
-
it "renews cookie expiration date each time it is used" do
|
196
|
-
session = controller.sign_in(user, ttl: 1.day, remember: true)
|
197
|
-
session.update_column :ttl, 30.days
|
198
|
-
reloaded_controller.current_user
|
199
|
-
expect(cookies.expires_at).to be_within(1.second).of(30.days.from_now)
|
200
|
-
end
|
201
|
-
|
202
|
-
it "can sign in using sign_in method" do
|
203
|
-
expect(controller).to receive(:sign_in_user).with(user, {})
|
204
|
-
controller.sign_in user
|
205
|
-
end
|
206
|
-
|
207
|
-
it "allows to specify ttl using sign_in method with ttl option" do
|
208
|
-
session = controller.sign_in(user, ttl: 40.minutes)
|
209
|
-
expect(session.ttl).to eq(40.minutes)
|
210
|
-
end
|
211
|
-
|
212
|
-
it "raises an error when trying to sign in unknown model" do
|
213
|
-
model = MyNamespace::SuperUser.create(email: "admin@example.com")
|
214
|
-
message = "Unknown authem role: #{model.inspect}"
|
215
|
-
expect{ controller.sign_in model }.to raise_error(Authem::UnknownRoleError, message)
|
216
|
-
end
|
217
|
-
|
218
|
-
it "raises an error when trying to sign in nil" do
|
219
|
-
expect{ controller.sign_in nil }.to raise_error(ArgumentError)
|
220
|
-
expect{ controller.sign_in_user nil }.to raise_error(ArgumentError)
|
221
|
-
end
|
222
|
-
|
223
|
-
it "has sign_out_user method" do
|
224
|
-
expect(controller).to respond_to(:sign_out_user)
|
225
|
-
end
|
226
|
-
|
227
|
-
context "when user is signed in" do
|
228
|
-
let(:sign_in_options){ Hash.new }
|
229
|
-
|
230
|
-
before do
|
231
|
-
controller.sign_in user, sign_in_options
|
232
|
-
expect(controller.current_user).to eq(user)
|
233
|
-
end
|
234
|
-
|
235
|
-
after do
|
236
|
-
expect(controller.current_user).to be_nil
|
237
|
-
expect(reloaded_controller.current_user).to be_nil
|
238
|
-
end
|
239
|
-
|
240
|
-
it "can sign out using sign_out_user method" do
|
241
|
-
controller.sign_out_user
|
242
|
-
end
|
243
|
-
|
244
|
-
it "can sign out using sign_out method" do
|
245
|
-
controller.sign_out user
|
246
|
-
end
|
247
|
-
|
248
|
-
context "with cookies" do
|
249
|
-
let(:sign_in_options){{ remember: true }}
|
250
|
-
|
251
|
-
after{ expect(cookies).to be_empty }
|
252
|
-
|
253
|
-
it "removes session token from cookies on sign out" do
|
254
|
-
controller.sign_out_user
|
255
|
-
end
|
256
|
-
end
|
257
|
-
end
|
258
|
-
|
259
|
-
context "with multiple sessions across devices" do
|
260
|
-
let(:first_device){ controller }
|
261
|
-
let(:second_device){ build_controller }
|
262
|
-
|
263
|
-
before do
|
264
|
-
first_device.sign_in user
|
265
|
-
second_device.sign_in user
|
266
|
-
end
|
267
|
-
|
268
|
-
it "signs out all currently active sessions on all devices" do
|
269
|
-
expect{ first_device.clear_all_user_sessions_for user }.to change(Authem::Session, :count).by(-2)
|
270
|
-
expect(second_device.reloaded.current_user).to be_nil
|
271
|
-
end
|
272
|
-
end
|
273
|
-
|
274
|
-
it "raises an error when calling sign_out with nil" do
|
275
|
-
expect{ controller.sign_out nil }.to raise_error(ArgumentError)
|
276
|
-
end
|
277
|
-
|
278
|
-
it "persists session in database" do
|
279
|
-
expect{ controller.sign_in user }.to change(Authem::Session, :count).by(1)
|
280
|
-
end
|
281
|
-
|
282
|
-
it "removes database session on sign out" do
|
283
|
-
controller.sign_in user
|
284
|
-
expect{ controller.sign_out user }.to change(Authem::Session, :count).by(-1)
|
285
|
-
end
|
286
|
-
end
|
287
|
-
|
288
|
-
context "with multiple roles" do
|
289
|
-
let(:admin){ MyNamespace::SuperUser.create(email: "admin@example.com") }
|
290
|
-
let(:controller_klass) do
|
291
|
-
Class.new(BaseController) do
|
292
|
-
authem_for :user
|
293
|
-
authem_for :admin, model: MyNamespace::SuperUser
|
294
|
-
end
|
295
|
-
end
|
296
|
-
|
297
|
-
it "has current_admin method" do
|
298
|
-
expect(controller).to respond_to(:current_admin)
|
299
|
-
end
|
300
|
-
|
301
|
-
it "has sign_in_admin method" do
|
302
|
-
expect(controller).to respond_to(:sign_in_admin)
|
303
|
-
end
|
304
|
-
|
305
|
-
it "can sign in admin using sign_in_admin method" do
|
306
|
-
controller.sign_in_admin admin
|
307
|
-
expect(controller.current_admin).to eq(admin)
|
308
|
-
expect(reloaded_controller.current_admin).to eq(admin)
|
309
|
-
end
|
310
|
-
|
311
|
-
it "can sign in using sign_in method" do
|
312
|
-
expect(controller).to receive(:sign_in_admin).with(admin, {})
|
313
|
-
controller.sign_in admin
|
314
|
-
end
|
315
|
-
|
316
|
-
context "with signed in user and admin" do
|
317
|
-
let(:user){ User.create(email: "joe@example.com") }
|
318
|
-
|
319
|
-
before do
|
320
|
-
controller.sign_in_user user
|
321
|
-
controller.sign_in_admin admin
|
322
|
-
end
|
323
|
-
|
324
|
-
after do
|
325
|
-
expect(controller.current_admin).to eq(admin)
|
326
|
-
expect(reloaded_controller.current_admin).to eq(admin)
|
327
|
-
end
|
328
|
-
|
329
|
-
it "can sign out user separately from admin using sign_out_user" do
|
330
|
-
controller.sign_out_user
|
331
|
-
end
|
332
|
-
|
333
|
-
it "can sign out user separately from admin using sign_out" do
|
334
|
-
controller.sign_out user
|
335
|
-
end
|
336
|
-
end
|
337
|
-
end
|
338
|
-
|
339
|
-
context "multiple roles with same model class" do
|
340
|
-
let(:user){ User.create(email: "joe@example.com") }
|
341
|
-
let(:customer){ User.create(email: "shmoe@example.com") }
|
342
|
-
let(:controller_klass) do
|
343
|
-
Class.new(BaseController) do
|
344
|
-
authem_for :user
|
345
|
-
authem_for :customer, model: User
|
346
|
-
end
|
347
|
-
end
|
348
|
-
|
349
|
-
it "can sign in user separately from customer" do
|
350
|
-
controller.sign_in_user user
|
351
|
-
expect(controller.current_user).to eq(user)
|
352
|
-
expect(controller.current_customer).to be_nil
|
353
|
-
expect(reloaded_controller.current_user).to eq(user)
|
354
|
-
expect(reloaded_controller.current_customer).to be_nil
|
355
|
-
end
|
356
|
-
|
357
|
-
it "can sign in customer and user separately" do
|
358
|
-
controller.sign_in_user user
|
359
|
-
controller.sign_in_customer customer
|
360
|
-
expect(controller.current_user).to eq(user)
|
361
|
-
expect(controller.current_customer).to eq(customer)
|
362
|
-
expect(reloaded_controller.current_user).to eq(user)
|
363
|
-
expect(reloaded_controller.current_customer).to eq(customer)
|
364
|
-
end
|
365
|
-
|
366
|
-
it "raises the error when sign in can't guess the model properly" do
|
367
|
-
message = "Ambigous match for #{user.inspect}: user, customer"
|
368
|
-
expect{ controller.sign_in user }.to raise_error(Authem::AmbigousRoleError, message)
|
369
|
-
end
|
370
|
-
|
371
|
-
it "allows to specify role with special :as option" do
|
372
|
-
expect(controller).to receive(:sign_in_customer).with(user, as: :customer)
|
373
|
-
controller.sign_in user, as: :customer
|
374
|
-
end
|
375
|
-
|
376
|
-
it "raises the error when sign out can't guess the model properly" do
|
377
|
-
message = "Ambigous match for #{user.inspect}: user, customer"
|
378
|
-
expect{ controller.sign_out user }.to raise_error(Authem::AmbigousRoleError, message)
|
379
|
-
end
|
380
|
-
end
|
381
|
-
|
382
|
-
context "redirect after authentication" do
|
383
|
-
let(:controller_klass){ Class.new(BaseController){ authem_for :user }}
|
384
|
-
|
385
|
-
context "with saved url" do
|
386
|
-
before{ session[:return_to_url] = :my_url }
|
387
|
-
|
388
|
-
it "redirects back to saved url if it's available" do
|
389
|
-
expect(controller).to receive(:redirect_to).with(:my_url, notice: "foo")
|
390
|
-
controller.redirect_back_or_to :root, notice: "foo"
|
391
|
-
end
|
392
|
-
|
393
|
-
it "removes values from session after successful redirect" do
|
394
|
-
expect(controller).to receive(:redirect_to).with(:my_url, {})
|
395
|
-
expect{ controller.redirect_back_or_to :root }.to change{ session[:return_to_url] }.from(:my_url).to(nil)
|
396
|
-
end
|
397
|
-
end
|
398
|
-
|
399
|
-
it "redirects to specified url if there is no saved value" do
|
400
|
-
expect(controller).to receive(:redirect_to).with(:root, notice: "foo")
|
401
|
-
controller.redirect_back_or_to :root, notice: "foo"
|
402
|
-
end
|
403
|
-
end
|
404
|
-
|
405
|
-
context "when defining authem" do
|
406
|
-
it "settings do not propagate to parent controller" do
|
407
|
-
parent_klass = Class.new(BaseController){ authem_for :user }
|
408
|
-
child_klass = Class.new(parent_klass){ authem_for :member }
|
409
|
-
expect(child_klass.authem_roles.size).to eq(2)
|
410
|
-
expect(parent_klass.authem_roles.size).to eq(1)
|
411
|
-
end
|
412
|
-
end
|
413
|
-
end
|
data/spec/session_spec.rb
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe Authem::Session do
|
4
|
-
class User < ActiveRecord::Base
|
5
|
-
self.table_name = :users
|
6
|
-
end
|
7
|
-
|
8
|
-
let(:user){ User.create(email: "joe@example.com") }
|
9
|
-
let(:role){ :user }
|
10
|
-
|
11
|
-
it "generates secure token on creation" do
|
12
|
-
expect(Authem::Token).to receive(:generate).and_return("a secure token")
|
13
|
-
model = described_class.create(role: role, subject: user)
|
14
|
-
expect(model.token).to eq("a secure token")
|
15
|
-
end
|
16
|
-
|
17
|
-
it "set expires_at attribute according to ttl" do
|
18
|
-
model = described_class.create(role: role, subject: user, ttl: 30.minutes)
|
19
|
-
expect(model.expires_at).to be_within(1.second).of(30.minutes.from_now)
|
20
|
-
end
|
21
|
-
|
22
|
-
it "uses default ttl if value is not provided" do
|
23
|
-
model = described_class.create(role: role, subject: user)
|
24
|
-
expect(model.expires_at).to be_within(1.second).of(30.days.from_now)
|
25
|
-
end
|
26
|
-
|
27
|
-
context "scopes" do
|
28
|
-
def create_session_with_expiration(expires_at)
|
29
|
-
described_class.create(
|
30
|
-
role: role,
|
31
|
-
subject: user,
|
32
|
-
expires_at: expires_at
|
33
|
-
)
|
34
|
-
end
|
35
|
-
|
36
|
-
let!(:expired_session){ create_session_with_expiration(1.day.ago) }
|
37
|
-
let!(:active_session){ create_session_with_expiration(1.week.from_now) }
|
38
|
-
let(:active_scope){ described_class.active }
|
39
|
-
let(:expired_scope){ described_class.expired }
|
40
|
-
|
41
|
-
specify ".active filters out expired sessions" do
|
42
|
-
expect(active_scope).to include(active_session)
|
43
|
-
expect(active_scope).not_to include(expired_session)
|
44
|
-
end
|
45
|
-
|
46
|
-
specify ".expired filters out active sessions" do
|
47
|
-
expect(expired_scope).to include(expired_session)
|
48
|
-
expect(expired_scope).not_to include(active_session)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
end
|
data/spec/spec_helper.rb
DELETED
@@ -1,45 +0,0 @@
|
|
1
|
-
require "active_record"
|
2
|
-
|
3
|
-
ActiveRecord::Migration.verbose = false
|
4
|
-
|
5
|
-
ActiveRecord::Base.establish_connection(
|
6
|
-
adapter: "sqlite3",
|
7
|
-
database: ":memory:"
|
8
|
-
)
|
9
|
-
|
10
|
-
class CreateUsersMigration < ActiveRecord::Migration
|
11
|
-
def up
|
12
|
-
create_table :users do |t|
|
13
|
-
t.string :email
|
14
|
-
t.string :password_digest
|
15
|
-
t.string :password_reset_token
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
class CreateSessionsMigration < ActiveRecord::Migration
|
21
|
-
def up
|
22
|
-
create_table :authem_sessions do |t|
|
23
|
-
t.string :role, null: false
|
24
|
-
t.references :subject, null: false, polymorphic: true
|
25
|
-
t.string :token, null: false
|
26
|
-
t.datetime :expires_at, null: false
|
27
|
-
t.integer :ttl, null: false
|
28
|
-
t.timestamps
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
RSpec.configure do |config|
|
34
|
-
config.before :suite do
|
35
|
-
CreateUsersMigration.new.up
|
36
|
-
CreateSessionsMigration.new.up
|
37
|
-
end
|
38
|
-
|
39
|
-
config.around do |example|
|
40
|
-
ActiveRecord::Base.transaction do
|
41
|
-
example.run
|
42
|
-
raise ActiveRecord::Rollback
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
data/spec/support/i18n.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
I18n.enforce_available_locales = false
|
data/spec/support/time.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
Time.zone_default = ActiveSupport::TimeZone["UTC"]
|
data/spec/token_spec.rb
DELETED
data/spec/user_spec.rb
DELETED
@@ -1,116 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe Authem::User do
|
4
|
-
|
5
|
-
class TestUser < ActiveRecord::Base
|
6
|
-
self.table_name = :users
|
7
|
-
include Authem::User
|
8
|
-
|
9
|
-
|
10
|
-
def self.create(opts={})
|
11
|
-
opts = {email: "joe@example.com", password: "password"}.merge(opts)
|
12
|
-
super(
|
13
|
-
email: opts[:email],
|
14
|
-
password: opts[:password],
|
15
|
-
password_confirmation: opts[:password]
|
16
|
-
)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
it "downcases email" do
|
21
|
-
record = TestUser.new
|
22
|
-
record.email = "JOE@EXAMPLE.COM"
|
23
|
-
expect(record.email).to eq("joe@example.com")
|
24
|
-
end
|
25
|
-
|
26
|
-
subject(:user){ TestUser.create }
|
27
|
-
|
28
|
-
context "#authenticate" do
|
29
|
-
it "returns record if password is correct" do
|
30
|
-
expect(user.authenticate("password")).to eq(user)
|
31
|
-
end
|
32
|
-
|
33
|
-
it "returns false if password is incorrect" do
|
34
|
-
expect(user.authenticate("notright")).to be_falsy
|
35
|
-
end
|
36
|
-
|
37
|
-
it "returns false if password is nil" do
|
38
|
-
expect(user.authenticate(nil)).to be_falsy
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
context "#password_reset_token" do
|
43
|
-
it "generates token on record creation" do
|
44
|
-
expect(user.password_reset_token).to be_present
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
context "#reset_password" do
|
49
|
-
it "changes the password if on successful update" do
|
50
|
-
expect{ user.reset_password "123", "123" }.to change{ user.reload.password_digest }
|
51
|
-
end
|
52
|
-
|
53
|
-
it "regenerates password reset token on successful update" do
|
54
|
-
expect{ user.reset_password "123", "123" }.to change{ user.reload.password_reset_token }
|
55
|
-
end
|
56
|
-
|
57
|
-
it "does not change password on error" do
|
58
|
-
expect{ user.reset_password "123", "321" }.not_to change{ user.reload.password_digest }
|
59
|
-
expect{ user.reset_password "123", "" }.not_to change{ user.reload.password_digest }
|
60
|
-
expect{ user.reset_password nil, "321" }.not_to change{ user.reload.password_digest }
|
61
|
-
expect{ user.reset_password nil, nil }.not_to change{ user.reload.password_digest }
|
62
|
-
end
|
63
|
-
|
64
|
-
it "does not change password reset token on error" do
|
65
|
-
expect{ user.reset_password "123", "321" }.not_to change{ user.reload.password_reset_token }
|
66
|
-
expect{ user.reset_password "123", "" }.not_to change{ user.reload.password_reset_token }
|
67
|
-
expect{ user.reset_password nil, "321" }.not_to change{ user.reload.password_reset_token }
|
68
|
-
expect{ user.reset_password nil, nil }.not_to change{ user.reload.password_reset_token }
|
69
|
-
end
|
70
|
-
|
71
|
-
it "returns true if when password change is successful" do
|
72
|
-
expect(user.reset_password("123", "123")).to be_truthy
|
73
|
-
end
|
74
|
-
|
75
|
-
it "returns false when confirmation does not match" do
|
76
|
-
expect(user.reset_password("123", "321")).to be_falsy
|
77
|
-
end
|
78
|
-
|
79
|
-
it "adds an error when confirmation does not match" do
|
80
|
-
user.reset_password("123", "321")
|
81
|
-
expect(user.errors).to include(:password_confirmation)
|
82
|
-
end
|
83
|
-
|
84
|
-
it "adds and error when password is blank" do
|
85
|
-
user.reset_password(nil, "")
|
86
|
-
expect(user.errors).to include(:password)
|
87
|
-
end
|
88
|
-
|
89
|
-
it "returns false when password is blank" do
|
90
|
-
expect(user.reset_password("", "")).to be_falsy
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
context "validations" do
|
95
|
-
it "allows properly formatted emails" do
|
96
|
-
record = TestUser.create(email: "joe@example.com")
|
97
|
-
expect(record.errors).not_to include(:email)
|
98
|
-
end
|
99
|
-
|
100
|
-
it "validates email presence" do
|
101
|
-
record = TestUser.create(email: nil)
|
102
|
-
expect(record.errors).to include(:email)
|
103
|
-
end
|
104
|
-
|
105
|
-
it "validates email format" do
|
106
|
-
record = TestUser.create(email: "joe-at-example-com")
|
107
|
-
expect(record.errors).to include(:email)
|
108
|
-
end
|
109
|
-
|
110
|
-
it "validates email uniqueness" do
|
111
|
-
TestUser.create email: "joe@example.com"
|
112
|
-
record = TestUser.create(email: "JOE@EXAMPLE.COM")
|
113
|
-
expect(record.errors).to include(:email)
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|