sorcery 0.2.1 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +129 -61
- data/VERSION +1 -1
- data/lib/generators/sorcery_migration/sorcery_migration_generator.rb +24 -0
- data/lib/generators/sorcery_migration/templates/activity_logging.rb +17 -0
- data/lib/generators/sorcery_migration/templates/brute_force_protection.rb +11 -0
- data/lib/generators/sorcery_migration/templates/core.rb +16 -0
- data/lib/generators/sorcery_migration/templates/external.rb +14 -0
- data/lib/generators/sorcery_migration/templates/remember_me.rb +15 -0
- data/lib/generators/sorcery_migration/templates/reset_password.rb +13 -0
- data/lib/generators/sorcery_migration/templates/user_activation.rb +17 -0
- data/lib/sorcery/controller/adapters/sinatra.rb +97 -0
- data/lib/sorcery/controller/submodules/email.rb +44 -0
- data/lib/sorcery/controller/submodules/external/protocols/oauth1.rb +35 -0
- data/lib/sorcery/controller/submodules/external/protocols/oauth2.rb +26 -0
- data/lib/sorcery/controller/submodules/{oauth → external}/providers/facebook.rb +24 -6
- data/lib/sorcery/controller/submodules/{oauth → external}/providers/twitter.rb +31 -6
- data/lib/sorcery/controller/submodules/external.rb +83 -0
- data/lib/sorcery/controller/submodules/http_basic_auth.rb +10 -6
- data/lib/sorcery/controller/submodules/oauth.rb +6 -3
- data/lib/sorcery/controller.rb +5 -3
- data/lib/sorcery/model/submodules/activity_logging.rb +1 -1
- data/lib/sorcery/model/submodules/brute_force_protection.rb +0 -4
- data/lib/sorcery/model/submodules/{oauth.rb → external.rb} +3 -3
- data/lib/sorcery/model.rb +9 -6
- data/lib/sorcery/sinatra.rb +14 -0
- data/lib/sorcery/test_helpers/rails.rb +57 -0
- data/lib/sorcery/test_helpers/sinatra.rb +131 -0
- data/lib/sorcery/test_helpers.rb +8 -52
- data/lib/sorcery.rb +17 -7
- data/sorcery.gemspec +86 -10
- data/spec/Gemfile +1 -1
- data/spec/Gemfile.lock +2 -2
- data/spec/rails3/app_root/Gemfile +2 -4
- data/spec/rails3/app_root/Gemfile.lock +2 -5
- data/spec/rails3/app_root/app/controllers/application_controller.rb +11 -11
- data/spec/rails3/app_root/spec/controller_oauth2_spec.rb +15 -13
- data/spec/rails3/app_root/spec/controller_oauth_spec.rb +18 -13
- data/spec/rails3/app_root/spec/controller_session_timeout_spec.rb +2 -2
- data/spec/rails3/app_root/spec/spec_helper.rb +1 -0
- data/spec/rails3/app_root/spec/user_oauth_spec.rb +4 -4
- data/spec/rails3/app_root/spec/user_spec.rb +2 -2
- data/spec/sinatra/Gemfile +12 -0
- data/spec/sinatra/Gemfile.lock +134 -0
- data/spec/sinatra/Rakefile +10 -0
- data/spec/sinatra/authentication.rb +3 -0
- data/spec/sinatra/db/migrate/activation/20101224223622_add_activation_to_users.rb +17 -0
- data/spec/sinatra/db/migrate/activity_logging/20101224223624_add_activity_logging_to_users.rb +17 -0
- data/spec/sinatra/db/migrate/brute_force_protection/20101224223626_add_brute_force_protection_to_users.rb +11 -0
- data/spec/sinatra/db/migrate/core/20101224223620_create_users.rb +16 -0
- data/spec/sinatra/db/migrate/external/20101224223628_create_authentications.rb +14 -0
- data/spec/sinatra/db/migrate/remember_me/20101224223623_add_remember_me_token_to_users.rb +15 -0
- data/spec/sinatra/db/migrate/reset_password/20101224223622_add_reset_password_to_users.rb +13 -0
- data/spec/sinatra/filters.rb +21 -0
- data/spec/sinatra/myapp.rb +133 -0
- data/spec/sinatra/sorcery_mailer.rb +25 -0
- data/spec/sinatra/spec/controller_activity_logging_spec.rb +85 -0
- data/spec/sinatra/spec/controller_brute_force_protection_spec.rb +69 -0
- data/spec/sinatra/spec/controller_http_basic_auth_spec.rb +53 -0
- data/spec/sinatra/spec/controller_oauth2_spec.rb +119 -0
- data/spec/sinatra/spec/controller_oauth_spec.rb +121 -0
- data/spec/sinatra/spec/controller_remember_me_spec.rb +64 -0
- data/spec/sinatra/spec/controller_session_timeout_spec.rb +52 -0
- data/spec/sinatra/spec/controller_spec.rb +120 -0
- data/spec/sinatra/spec/spec.opts +4 -0
- data/spec/sinatra/spec/spec_helper.rb +44 -0
- data/spec/sinatra/spec/user_activation_spec.rb +188 -0
- data/spec/sinatra/spec/user_activity_logging_spec.rb +36 -0
- data/spec/sinatra/spec/user_brute_force_protection_spec.rb +76 -0
- data/spec/sinatra/spec/user_oauth_spec.rb +39 -0
- data/spec/sinatra/spec/user_remember_me_spec.rb +66 -0
- data/spec/sinatra/spec/user_reset_password_spec.rb +178 -0
- data/spec/sinatra/spec/user_spec.rb +317 -0
- data/spec/sinatra/user.rb +6 -0
- data/spec/sinatra/views/test_login.erb +4 -0
- data/spec/untitled folder +18 -0
- metadata +85 -9
- data/lib/sorcery/controller/submodules/oauth/oauth1.rb +0 -26
- data/lib/sorcery/controller/submodules/oauth/oauth2.rb +0 -24
- /data/spec/rails3/app_root/db/migrate/{oauth → external}/20101224223628_create_authentications.rb +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module Sorcery
|
|
2
2
|
module Controller
|
|
3
3
|
module Submodules
|
|
4
|
-
module
|
|
4
|
+
module External
|
|
5
5
|
module Providers
|
|
6
6
|
# This module adds support for OAuth with Twitter.com.
|
|
7
7
|
# When included in the 'config.providers' option, it adds a new option, 'config.twitter'.
|
|
@@ -15,7 +15,10 @@ module Sorcery
|
|
|
15
15
|
def self.included(base)
|
|
16
16
|
base.module_eval do
|
|
17
17
|
class << self
|
|
18
|
-
attr_reader :twitter
|
|
18
|
+
attr_reader :twitter
|
|
19
|
+
# def twitter(&blk) # allows block syntax.
|
|
20
|
+
# yield @twitter
|
|
21
|
+
# end
|
|
19
22
|
|
|
20
23
|
def merge_twitter_defaults!
|
|
21
24
|
@defaults.merge!(:@twitter => TwitterClient)
|
|
@@ -25,7 +28,7 @@ module Sorcery
|
|
|
25
28
|
update!
|
|
26
29
|
end
|
|
27
30
|
end
|
|
28
|
-
|
|
31
|
+
|
|
29
32
|
module TwitterClient
|
|
30
33
|
class << self
|
|
31
34
|
attr_accessor :key,
|
|
@@ -35,7 +38,7 @@ module Sorcery
|
|
|
35
38
|
:user_info_path,
|
|
36
39
|
:user_info_mapping
|
|
37
40
|
|
|
38
|
-
include Oauth1
|
|
41
|
+
include Protocols::Oauth1
|
|
39
42
|
|
|
40
43
|
def init
|
|
41
44
|
@site = "https://api.twitter.com"
|
|
@@ -43,13 +46,35 @@ module Sorcery
|
|
|
43
46
|
@user_info_mapping = {}
|
|
44
47
|
end
|
|
45
48
|
|
|
46
|
-
def get_user_hash
|
|
49
|
+
def get_user_hash
|
|
47
50
|
user_hash = {}
|
|
48
|
-
response = access_token.get(@user_info_path)
|
|
51
|
+
response = @access_token.get(@user_info_path)
|
|
49
52
|
user_hash[:user_info] = JSON.parse(response.body)
|
|
50
53
|
user_hash[:uid] = user_hash[:user_info]['id']
|
|
51
54
|
user_hash
|
|
52
55
|
end
|
|
56
|
+
|
|
57
|
+
def has_callback?
|
|
58
|
+
true
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# calculates and returns the url to which the user should be redirected,
|
|
62
|
+
# to get authenticated at the external provider's site.
|
|
63
|
+
def login_url(params,session)
|
|
64
|
+
req_token = self.get_request_token
|
|
65
|
+
session[:request_token] = req_token.token
|
|
66
|
+
session[:request_token_secret] = req_token.secret
|
|
67
|
+
self.authorize_url({:request_token => req_token.token, :request_token_secret => req_token.secret})
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# tries to login the user from access token
|
|
71
|
+
def process_callback(params,session)
|
|
72
|
+
args = {}
|
|
73
|
+
args.merge!({:oauth_verifier => params[:oauth_verifier], :request_token => session[:request_token], :request_token_secret => session[:request_token_secret]})
|
|
74
|
+
args.merge!({:code => params[:code]}) if params[:code]
|
|
75
|
+
@access_token = self.get_access_token(args)
|
|
76
|
+
end
|
|
77
|
+
|
|
53
78
|
end
|
|
54
79
|
init
|
|
55
80
|
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
module Sorcery
|
|
2
|
+
module Controller
|
|
3
|
+
module Submodules
|
|
4
|
+
# This submodule helps you login users from external auth providers such as Twitter.
|
|
5
|
+
# This is the controller part which handles the http requests and tokens passed between the app and the provider.
|
|
6
|
+
module External
|
|
7
|
+
def self.included(base)
|
|
8
|
+
base.send(:include, InstanceMethods)
|
|
9
|
+
Config.module_eval do
|
|
10
|
+
class << self
|
|
11
|
+
attr_reader :external_providers # external providers like twitter.
|
|
12
|
+
|
|
13
|
+
def merge_external_defaults!
|
|
14
|
+
@defaults.merge!(:@external_providers => [])
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def external_providers=(providers)
|
|
18
|
+
providers.each do |provider|
|
|
19
|
+
include Providers.const_get(provider.to_s.split("_").map {|p| p.capitalize}.join(""))
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
merge_external_defaults!
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
module InstanceMethods
|
|
28
|
+
protected
|
|
29
|
+
|
|
30
|
+
# sends user to authenticate at the provider's website.
|
|
31
|
+
# after authentication the user is redirected to the callback defined in the provider config
|
|
32
|
+
def login_at(provider, args = {})
|
|
33
|
+
@provider = Config.send(provider)
|
|
34
|
+
if @provider.has_callback?
|
|
35
|
+
redirect_to @provider.login_url(params,session)
|
|
36
|
+
else
|
|
37
|
+
#@provider.login(args)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# tries to login the user from provider's callback
|
|
42
|
+
def login_from(provider)
|
|
43
|
+
@provider = Config.send(provider)
|
|
44
|
+
@provider.process_callback(params,session)
|
|
45
|
+
@user_hash = @provider.get_user_hash
|
|
46
|
+
if user = Config.user_class.load_from_provider(provider,@user_hash[:uid])
|
|
47
|
+
reset_session
|
|
48
|
+
login_user(user)
|
|
49
|
+
user
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# this method automatically creates a new user from the data in the external user hash.
|
|
54
|
+
# The mappings from user hash fields to user db fields are set at controller config.
|
|
55
|
+
# If the hash field you would like to map is nested, use slashes. For example, Given a hash like:
|
|
56
|
+
#
|
|
57
|
+
# "user" => {"name"=>"moishe"}
|
|
58
|
+
#
|
|
59
|
+
# You will set the mapping:
|
|
60
|
+
#
|
|
61
|
+
# {:username => "user/name"}
|
|
62
|
+
#
|
|
63
|
+
# And this will cause 'moishe' to be set as the value of :username field.
|
|
64
|
+
def create_from(provider)
|
|
65
|
+
provider = provider.to_sym
|
|
66
|
+
@provider = Config.send(provider)
|
|
67
|
+
@user_hash = @provider.get_user_hash
|
|
68
|
+
config = Config.user_class.sorcery_config
|
|
69
|
+
attrs = {}
|
|
70
|
+
@provider.user_info_mapping.each do |k,v|
|
|
71
|
+
(varr = v.split("/")).size > 1 ? attrs.merge!(k => varr.inject(@user_hash[:user_info]) {|hsh,v| hsh[v] }) : attrs.merge!(k => @user_hash[:user_info][v])
|
|
72
|
+
end
|
|
73
|
+
Config.user_class.transaction do
|
|
74
|
+
@user = Config.user_class.create!(attrs)
|
|
75
|
+
Config.user_class.sorcery_config.authentications_class.create!({config.authentications_user_id_attribute_name => @user.id, config.provider_attribute_name => provider, config.provider_uid_attribute_name => @user_hash[:uid]})
|
|
76
|
+
end
|
|
77
|
+
@user
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -48,13 +48,17 @@ module Sorcery
|
|
|
48
48
|
|
|
49
49
|
# Sets the realm name by searching the controller name in the hash given at configuration time.
|
|
50
50
|
def realm_name_by_controller
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
if defined?(ActionController::Base)
|
|
52
|
+
current_controller = self.class
|
|
53
|
+
while current_controller != ActionController::Base
|
|
54
|
+
result = Config.controller_to_realm_map[current_controller.controller_name]
|
|
55
|
+
return result if result
|
|
56
|
+
current_controller = self.class.superclass
|
|
57
|
+
end
|
|
58
|
+
nil
|
|
59
|
+
else
|
|
60
|
+
Config.controller_to_realm_map["application"]
|
|
56
61
|
end
|
|
57
|
-
nil
|
|
58
62
|
end
|
|
59
63
|
|
|
60
64
|
end
|
|
@@ -32,9 +32,12 @@ module Sorcery
|
|
|
32
32
|
# after authentication the user is redirected to the callback defined in the provider config
|
|
33
33
|
def auth_at_provider(provider)
|
|
34
34
|
@provider = Config.send(provider)
|
|
35
|
+
args = {}
|
|
35
36
|
if @provider.respond_to?(:get_request_token)
|
|
36
|
-
|
|
37
|
-
session[:request_token]
|
|
37
|
+
req_token = @provider.get_request_token
|
|
38
|
+
session[:request_token] = req_token.token
|
|
39
|
+
session[:request_token_secret] = req_token.secret
|
|
40
|
+
args.merge!({:request_token => req_token.token, :request_token_secret => req_token.secret})
|
|
38
41
|
end
|
|
39
42
|
redirect_to @provider.authorize_url(args)
|
|
40
43
|
end
|
|
@@ -43,7 +46,7 @@ module Sorcery
|
|
|
43
46
|
def login_from_access_token(provider)
|
|
44
47
|
@provider = Config.send(provider)
|
|
45
48
|
args = {}
|
|
46
|
-
args.merge!({:oauth_verifier => params[:oauth_verifier], :request_token => session[:request_token]}) if @provider.respond_to?(:get_request_token)
|
|
49
|
+
args.merge!({:oauth_verifier => params[:oauth_verifier], :request_token => session[:request_token], :request_token_secret => session[:request_token_secret]}) if @provider.respond_to?(:get_request_token)
|
|
47
50
|
args.merge!({:code => params[:code]}) if params[:code]
|
|
48
51
|
@access_token = @provider.get_access_token(args)
|
|
49
52
|
@user_hash = @provider.get_user_hash(@access_token)
|
data/lib/sorcery/controller.rb
CHANGED
|
@@ -5,7 +5,7 @@ module Sorcery
|
|
|
5
5
|
extend ClassMethods
|
|
6
6
|
include InstanceMethods
|
|
7
7
|
Config.submodules.each do |mod|
|
|
8
|
-
begin
|
|
8
|
+
begin
|
|
9
9
|
include Submodules.const_get(mod.to_s.split("_").map {|p| p.capitalize}.join(""))
|
|
10
10
|
rescue NameError
|
|
11
11
|
# don't stop on a missing submodule.
|
|
@@ -73,12 +73,14 @@ module Sorcery
|
|
|
73
73
|
@current_user ||= login_from_session || login_from_other_sources unless @current_user == false
|
|
74
74
|
end
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
# used when a user tries to access a page while logged out, is asked to login, and we want to return him back to the page he originally wanted.
|
|
77
|
+
def redirect_back_or_to(url, flash_hash = {})
|
|
77
78
|
redirect_to(session[:return_to_url] || url, :flash => flash_hash)
|
|
78
79
|
end
|
|
79
80
|
|
|
80
81
|
# The default action for denying non-authenticated users.
|
|
81
|
-
# You can override this method in your controllers
|
|
82
|
+
# You can override this method in your controllers,
|
|
83
|
+
# or provide a different method in the configuration.
|
|
82
84
|
def not_authenticated
|
|
83
85
|
redirect_to root_path
|
|
84
86
|
end
|
|
@@ -31,7 +31,7 @@ module Sorcery
|
|
|
31
31
|
config = sorcery_config
|
|
32
32
|
where("#{config.last_activity_at_attribute_name} IS NOT NULL") \
|
|
33
33
|
.where("#{config.last_logout_at_attribute_name} IS NULL OR #{config.last_activity_at_attribute_name} > #{config.last_logout_at_attribute_name}") \
|
|
34
|
-
.where("#{config.last_activity_at_attribute_name} > ? ", config.activity_timeout.seconds.ago)
|
|
34
|
+
.where("#{config.last_activity_at_attribute_name} > ? ", config.activity_timeout.seconds.ago.utc.to_s(:db))
|
|
35
35
|
end
|
|
36
36
|
end
|
|
37
37
|
end
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
module Sorcery
|
|
2
2
|
module Model
|
|
3
3
|
module Submodules
|
|
4
|
-
# This submodule helps you login users from
|
|
4
|
+
# This submodule helps you login users from external providers such as Twitter.
|
|
5
5
|
# This is the model part which handles finding the user using access tokens.
|
|
6
|
-
# For the controller options see Sorcery::Controller::
|
|
6
|
+
# For the controller options see Sorcery::Controller::External.
|
|
7
7
|
#
|
|
8
8
|
# Socery assumes (read: requires) you will create external users in the same table where you keep your regular users,
|
|
9
9
|
# but that you will have a separate table for keeping their external authentication data,
|
|
@@ -11,7 +11,7 @@ module Sorcery
|
|
|
11
11
|
#
|
|
12
12
|
# External users will have a null crypted_password field, since we do not hold their password.
|
|
13
13
|
# They will not be sent activation emails on creation.
|
|
14
|
-
module
|
|
14
|
+
module External
|
|
15
15
|
def self.included(base)
|
|
16
16
|
base.sorcery_config.class_eval do
|
|
17
17
|
attr_accessor :authentications_class,
|
data/lib/sorcery/model.rb
CHANGED
|
@@ -56,12 +56,6 @@ module Sorcery
|
|
|
56
56
|
user if user && @sorcery_config.before_authenticate.all? {|c| user.send(c)} && credentials_match?(user.send(@sorcery_config.crypted_password_attribute_name),credentials[1],_salt)
|
|
57
57
|
end
|
|
58
58
|
|
|
59
|
-
# Calls the configured encryption provider to compare the supplied password with the encrypted one.
|
|
60
|
-
def credentials_match?(crypted, *tokens)
|
|
61
|
-
return crypted == tokens.join if @sorcery_config.encryption_provider.nil?
|
|
62
|
-
@sorcery_config.encryption_provider.matches?(crypted, *tokens)
|
|
63
|
-
end
|
|
64
|
-
|
|
65
59
|
# encrypt tokens using current encryption_provider.
|
|
66
60
|
def encrypt(*tokens)
|
|
67
61
|
return tokens.first if @sorcery_config.encryption_provider.nil?
|
|
@@ -71,6 +65,15 @@ module Sorcery
|
|
|
71
65
|
CryptoProviders::AES256.key = @sorcery_config.encryption_key if @sorcery_config.encryption_algorithm == :aes256
|
|
72
66
|
@sorcery_config.encryption_provider.encrypt(*tokens)
|
|
73
67
|
end
|
|
68
|
+
|
|
69
|
+
protected
|
|
70
|
+
|
|
71
|
+
# Calls the configured encryption provider to compare the supplied password with the encrypted one.
|
|
72
|
+
def credentials_match?(crypted, *tokens)
|
|
73
|
+
return crypted == tokens.join if @sorcery_config.encryption_provider.nil?
|
|
74
|
+
@sorcery_config.encryption_provider.matches?(crypted, *tokens)
|
|
75
|
+
end
|
|
76
|
+
|
|
74
77
|
end
|
|
75
78
|
|
|
76
79
|
module InstanceMethods
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
ActiveRecord::Base.send(:include, Sorcery::Model) if defined?(ActiveRecord)
|
|
2
|
+
if defined?(Sinatra::Base)
|
|
3
|
+
Sinatra::Base.send(:include, Sorcery::Controller::Adapters::Sinatra)
|
|
4
|
+
Sinatra::Base.send(:include, Sorcery::Controller)
|
|
5
|
+
# Sorcery::Controller::Config.class_eval do
|
|
6
|
+
# class << self
|
|
7
|
+
# def submodules=(mods)
|
|
8
|
+
# @submodules = mods
|
|
9
|
+
# Sinatra::Base.send(:include, Sorcery::Controller::Adapters::Sinatra)
|
|
10
|
+
# Sinatra::Base.send(:include, Sorcery::Controller)
|
|
11
|
+
# end
|
|
12
|
+
# end
|
|
13
|
+
# end
|
|
14
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
module Sorcery
|
|
2
|
+
module TestHelpers
|
|
3
|
+
module Rails
|
|
4
|
+
SUBMODUELS_AUTO_ADDED_CONTROLLER_FILTERS = [:register_last_activity_time_to_db, :deny_banned_user, :validate_session]
|
|
5
|
+
|
|
6
|
+
def sorcery_reload!(submodules = [], options = {})
|
|
7
|
+
reload_user_class
|
|
8
|
+
|
|
9
|
+
# return to no-module configuration
|
|
10
|
+
::Sorcery::Controller::Config.init!
|
|
11
|
+
::Sorcery::Controller::Config.reset!
|
|
12
|
+
|
|
13
|
+
# remove all plugin before_filters so they won't fail other tests.
|
|
14
|
+
# I don't like this way, but I didn't find another.
|
|
15
|
+
# hopefully it won't break until Rails 4.
|
|
16
|
+
ApplicationController._process_action_callbacks.delete_if {|c| SUBMODUELS_AUTO_ADDED_CONTROLLER_FILTERS.include?(c.filter) }
|
|
17
|
+
|
|
18
|
+
# configure
|
|
19
|
+
::Sorcery::Controller::Config.submodules = submodules
|
|
20
|
+
::Sorcery::Controller::Config.user_class = nil
|
|
21
|
+
ActionController::Base.send(:include,::Sorcery::Controller)
|
|
22
|
+
|
|
23
|
+
User.activate_sorcery! do |config|
|
|
24
|
+
options.each do |property,value|
|
|
25
|
+
config.send(:"#{property}=", value)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def sorcery_controller_property_set(property, value)
|
|
31
|
+
ApplicationController.activate_sorcery! do |config|
|
|
32
|
+
config.send(:"#{property}=", value)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def sorcery_controller_oauth_property_set(provider, property, value)
|
|
37
|
+
ApplicationController.activate_sorcery! do |config|
|
|
38
|
+
config.send(provider).send(:"#{property}=", value)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def login_user(user = nil)
|
|
43
|
+
user ||= @user
|
|
44
|
+
subject.send(:login_user,user)
|
|
45
|
+
subject.send(:after_login!,user,[user.username,'secret'])
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def logout_user
|
|
49
|
+
subject.send(:logout)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def clear_user_without_logout
|
|
53
|
+
subject.instance_variable_set(:@current_user,nil)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
module Sorcery
|
|
2
|
+
module TestHelpers
|
|
3
|
+
module Sinatra
|
|
4
|
+
|
|
5
|
+
class MyApp
|
|
6
|
+
class << self
|
|
7
|
+
def new
|
|
8
|
+
return this
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
class ::Sinatra::Application
|
|
14
|
+
class << self
|
|
15
|
+
attr_accessor :sorcery_vars
|
|
16
|
+
end
|
|
17
|
+
@sorcery_vars = {}
|
|
18
|
+
|
|
19
|
+
# NOTE: see before and after test filters in filters.rb
|
|
20
|
+
|
|
21
|
+
def save_instance_vars
|
|
22
|
+
instance_variables.each do |var|
|
|
23
|
+
self.class.sorcery_vars[:"#{var.to_s.delete("@")}"] = instance_variable_get(var)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
::RSpec::Matchers.define :redirect_to do |expected|
|
|
29
|
+
match do |actual|
|
|
30
|
+
actual.status == 302 && actual.location == expected
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def get_sinatra_app(app)
|
|
35
|
+
while app.class != ::Sinatra::Application do
|
|
36
|
+
app = app.instance_variable_get(:@app)
|
|
37
|
+
end
|
|
38
|
+
app
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def login_user(user=nil)
|
|
42
|
+
user ||= @user
|
|
43
|
+
get_sinatra_app(subject).send(:login_user,user)
|
|
44
|
+
get_sinatra_app(subject).send(:after_login!,user,[user.username,'secret'])
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def logout_user
|
|
48
|
+
get_sinatra_app(subject).send(:logout)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def clear_user_without_logout
|
|
52
|
+
get_sinatra_app(subject).instance_variable_set(:@current_user,nil)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def assigns
|
|
56
|
+
::Sinatra::Application.sorcery_vars
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
class SessionData
|
|
60
|
+
def initialize(cookies)
|
|
61
|
+
@cookies = cookies
|
|
62
|
+
@data = cookies['rack.session']
|
|
63
|
+
if @data
|
|
64
|
+
@data = @data.unpack("m*").first
|
|
65
|
+
@data = Marshal.load(@data)
|
|
66
|
+
else
|
|
67
|
+
@data = {}
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def [](key)
|
|
72
|
+
@data[key]
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def []=(key, value)
|
|
76
|
+
@data[key] = value
|
|
77
|
+
session_data = Marshal.dump(@data)
|
|
78
|
+
session_data = [session_data].pack("m*")
|
|
79
|
+
@cookies.merge("rack.session=#{Rack::Utils.escape(session_data)}", URI.parse("//example.org//"))
|
|
80
|
+
raise "session variable not set" unless @cookies['rack.session'] == session_data
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def session
|
|
85
|
+
SessionData.new(rack_test_session.instance_variable_get(:@rack_mock_session).cookie_jar)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def cookies
|
|
89
|
+
rack_test_session.instance_variable_get(:@rack_mock_session).cookie_jar
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def sorcery_reload!(submodules = [], options = {})
|
|
93
|
+
reload_user_class
|
|
94
|
+
|
|
95
|
+
# return to no-module configuration
|
|
96
|
+
::Sorcery::Controller::Config.init!
|
|
97
|
+
::Sorcery::Controller::Config.reset!
|
|
98
|
+
|
|
99
|
+
# clear all filters
|
|
100
|
+
::Sinatra::Application.instance_variable_set(:@filters,{:before => [],:after => []})
|
|
101
|
+
::Sinatra::Application.class_eval do
|
|
102
|
+
load File.join(File.dirname(__FILE__),'..','..','..','spec','sinatra','filters.rb')
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# configure
|
|
106
|
+
::Sorcery::Controller::Config.submodules = submodules
|
|
107
|
+
::Sorcery::Controller::Config.user_class = nil
|
|
108
|
+
::Sinatra::Application.send(:include, Sorcery::Controller::Adapters::Sinatra)
|
|
109
|
+
::Sinatra::Application.send(:include, Sorcery::Controller)
|
|
110
|
+
|
|
111
|
+
User.activate_sorcery! do |config|
|
|
112
|
+
options.each do |property,value|
|
|
113
|
+
config.send(:"#{property}=", value)
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def sorcery_controller_property_set(property, value)
|
|
119
|
+
::Sinatra::Application.activate_sorcery! do |config|
|
|
120
|
+
config.send(:"#{property}=", value)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def sorcery_controller_oauth_property_set(provider, property, value)
|
|
125
|
+
::Sinatra::Application.activate_sorcery! do |config|
|
|
126
|
+
config.send(provider).send(:"#{property}=", value)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
data/lib/sorcery/test_helpers.rb
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
module Sorcery
|
|
2
2
|
module TestHelpers
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
# a patch to fix a bug in testing that happens when you 'destroy' a session twice.
|
|
4
|
+
# After the first destroy, the session is an ordinary hash, and then when destroy is called again there's an exception.
|
|
5
|
+
class ::Hash
|
|
6
|
+
def destroy
|
|
7
|
+
clear
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
5
11
|
def create_new_user(attributes_hash = nil)
|
|
6
12
|
user_attributes_hash = attributes_hash || {:username => 'gizmo', :email => "bla@bla.com", :password => 'secret'}
|
|
7
13
|
@user = User.new(user_attributes_hash)
|
|
@@ -16,62 +22,12 @@ module Sorcery
|
|
|
16
22
|
@user
|
|
17
23
|
end
|
|
18
24
|
|
|
19
|
-
def login_user(user = nil)
|
|
20
|
-
user ||= @user
|
|
21
|
-
subject.send(:login_user,user)
|
|
22
|
-
subject.send(:after_login!,user,[user.username,'secret'])
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def logout_user
|
|
26
|
-
subject.send(:logout)
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def clear_user_without_logout
|
|
30
|
-
subject.instance_variable_set(:@current_user,nil)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def sorcery_reload!(submodules = [], options = {})
|
|
34
|
-
reload_user_class
|
|
35
|
-
|
|
36
|
-
# return to no-module configuration
|
|
37
|
-
::Sorcery::Controller::Config.init!
|
|
38
|
-
::Sorcery::Controller::Config.reset!
|
|
39
|
-
|
|
40
|
-
# remove all plugin before_filters so they won't fail other tests.
|
|
41
|
-
# I don't like this way, but I didn't find another.
|
|
42
|
-
# hopefully it won't break until Rails 4.
|
|
43
|
-
ApplicationController._process_action_callbacks.delete_if {|c| SUBMODUELS_AUTO_ADDED_CONTROLLER_FILTERS.include?(c.filter) }
|
|
44
|
-
|
|
45
|
-
# configure
|
|
46
|
-
::Sorcery::Controller::Config.submodules = submodules
|
|
47
|
-
::Sorcery::Controller::Config.user_class = nil
|
|
48
|
-
ActionController::Base.send(:include,::Sorcery::Controller)
|
|
49
|
-
|
|
50
|
-
User.activate_sorcery! do |config|
|
|
51
|
-
options.each do |property,value|
|
|
52
|
-
config.send(:"#{property}=", value)
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
|
|
57
25
|
def sorcery_model_property_set(property, *values)
|
|
58
26
|
User.class_eval do
|
|
59
27
|
sorcery_config.send(:"#{property}=", *values)
|
|
60
28
|
end
|
|
61
29
|
end
|
|
62
|
-
|
|
63
|
-
def sorcery_controller_property_set(property, value)
|
|
64
|
-
ApplicationController.activate_sorcery! do |config|
|
|
65
|
-
config.send(:"#{property}=", value)
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
30
|
|
|
69
|
-
def sorcery_controller_oauth_property_set(provider, property, value)
|
|
70
|
-
ApplicationController.activate_sorcery! do |config|
|
|
71
|
-
config.send(provider).send(:"#{property}=", value)
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
|
|
75
31
|
private
|
|
76
32
|
|
|
77
33
|
# reload user class between specs
|
data/lib/sorcery.rb
CHANGED
|
@@ -8,7 +8,7 @@ module Sorcery
|
|
|
8
8
|
autoload :RememberMe, 'sorcery/model/submodules/remember_me'
|
|
9
9
|
autoload :ActivityLogging, 'sorcery/model/submodules/activity_logging'
|
|
10
10
|
autoload :BruteForceProtection, 'sorcery/model/submodules/brute_force_protection'
|
|
11
|
-
autoload :
|
|
11
|
+
autoload :External, 'sorcery/model/submodules/external'
|
|
12
12
|
end
|
|
13
13
|
end
|
|
14
14
|
autoload :Controller, 'sorcery/controller'
|
|
@@ -19,16 +19,21 @@ module Sorcery
|
|
|
19
19
|
autoload :BruteForceProtection, 'sorcery/controller/submodules/brute_force_protection'
|
|
20
20
|
autoload :HttpBasicAuth, 'sorcery/controller/submodules/http_basic_auth'
|
|
21
21
|
autoload :ActivityLogging, 'sorcery/controller/submodules/activity_logging'
|
|
22
|
-
autoload :
|
|
23
|
-
module
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
autoload :External, 'sorcery/controller/submodules/external'
|
|
23
|
+
module External
|
|
24
|
+
module Protocols
|
|
25
|
+
autoload :Oauth1, 'sorcery/controller/submodules/external/protocols/oauth1'
|
|
26
|
+
autoload :Oauth2, 'sorcery/controller/submodules/external/protocols/oauth2'
|
|
27
|
+
end
|
|
26
28
|
module Providers
|
|
27
|
-
autoload :Twitter, 'sorcery/controller/submodules/
|
|
28
|
-
autoload :Facebook, 'sorcery/controller/submodules/
|
|
29
|
+
autoload :Twitter, 'sorcery/controller/submodules/external/providers/twitter'
|
|
30
|
+
autoload :Facebook, 'sorcery/controller/submodules/external/providers/facebook'
|
|
29
31
|
end
|
|
30
32
|
end
|
|
31
33
|
end
|
|
34
|
+
module Adapters
|
|
35
|
+
autoload :Sinatra, 'sorcery/controller/adapters/sinatra'
|
|
36
|
+
end
|
|
32
37
|
end
|
|
33
38
|
module CryptoProviders
|
|
34
39
|
autoload :AES256, 'sorcery/crypto_providers/aes256'
|
|
@@ -39,6 +44,11 @@ module Sorcery
|
|
|
39
44
|
autoload :SHA512, 'sorcery/crypto_providers/sha512'
|
|
40
45
|
end
|
|
41
46
|
autoload :TestHelpers, 'sorcery/test_helpers'
|
|
47
|
+
module TestHelpers
|
|
48
|
+
autoload :Rails, 'sorcery/test_helpers/rails'
|
|
49
|
+
autoload :Sinatra, 'sorcery/test_helpers/sinatra'
|
|
50
|
+
end
|
|
42
51
|
|
|
43
52
|
require 'sorcery/engine' if defined?(Rails) && Rails::VERSION::MAJOR == 3
|
|
53
|
+
require 'sorcery/sinatra' if defined?(Sinatra)
|
|
44
54
|
end
|