sorcery 0.7.4 → 0.7.5
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.
Potentially problematic release.
This version of sorcery might be problematic. Click here for more details.
- data/Gemfile.lock +2 -2
- data/README.rdoc +1 -1
- data/VERSION +1 -1
- data/lib/generators/sorcery/install_generator.rb +5 -3
- data/lib/generators/sorcery/templates/initializer.rb +25 -4
- data/lib/sorcery.rb +2 -0
- data/lib/sorcery/controller/submodules/external/protocols/oauth2.rb +17 -18
- data/lib/sorcery/controller/submodules/external/providers/github.rb +11 -3
- data/lib/sorcery/controller/submodules/external/providers/google.rb +89 -0
- data/lib/sorcery/controller/submodules/external/providers/liveid.rb +90 -0
- data/lib/sorcery/model.rb +17 -4
- data/lib/sorcery/model/adapters/active_record.rb +6 -1
- data/lib/sorcery/model/adapters/mongo_mapper.rb +6 -1
- data/lib/sorcery/model/adapters/mongoid.rb +6 -1
- data/lib/sorcery/model/submodules/activity_logging.rb +4 -4
- data/lib/sorcery/model/submodules/brute_force_protection.rb +5 -5
- data/lib/sorcery/model/submodules/reset_password.rb +4 -5
- data/lib/sorcery/model/submodules/user_activation.rb +1 -2
- data/sorcery.gemspec +4 -2
- data/spec/Gemfile.lock +3 -3
- data/spec/rails3/Gemfile +1 -2
- data/spec/rails3/Gemfile.lock +13 -14
- data/spec/rails3/app/controllers/application_controller.rb +26 -2
- data/spec/rails3/spec/controller_oauth2_spec.rb +111 -11
- data/spec/rails3/spec/controller_spec.rb +30 -2
- data/spec/rails3_mongo_mapper/Gemfile.lock +11 -11
- data/spec/rails3_mongo_mapper/spec/controller_spec.rb +34 -1
- data/spec/rails3_mongoid/Gemfile.lock +8 -8
- data/spec/rails3_mongoid/spec/controller_activity_logging_spec.rb +3 -3
- data/spec/rails3_mongoid/spec/controller_spec.rb +34 -1
- data/spec/shared_examples/user_reset_password_shared_examples.rb +9 -1
- data/spec/sorcery_crypto_providers_spec.rb +5 -1
- metadata +4 -2
data/Gemfile.lock
CHANGED
@@ -61,7 +61,7 @@ GEM
|
|
61
61
|
oauth2 (0.4.1)
|
62
62
|
faraday (~> 0.6.1)
|
63
63
|
multi_json (>= 0.0.5)
|
64
|
-
polyglot (0.3.
|
64
|
+
polyglot (0.3.3)
|
65
65
|
rack (1.3.5)
|
66
66
|
rack-cache (1.1)
|
67
67
|
rack (>= 0.4)
|
@@ -129,7 +129,7 @@ GEM
|
|
129
129
|
treetop (1.4.10)
|
130
130
|
polyglot
|
131
131
|
polyglot (>= 0.3.1)
|
132
|
-
tzinfo (0.3.
|
132
|
+
tzinfo (0.3.31)
|
133
133
|
yard (0.6.8)
|
134
134
|
|
135
135
|
PLATFORMS
|
data/README.rdoc
CHANGED
@@ -28,7 +28,7 @@ Railscast: http://railscasts.com/episodes/283-authentication-with-sorcery
|
|
28
28
|
|
29
29
|
Example Rails 3 app using sorcery: https://github.com/NoamB/sorcery-example-app
|
30
30
|
|
31
|
-
Documentation: http://rubydoc.info/gems/sorcery/0.7.
|
31
|
+
Documentation: http://rubydoc.info/gems/sorcery/0.7.5/frames
|
32
32
|
|
33
33
|
Check out the tutorials in the github wiki!
|
34
34
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.7.
|
1
|
+
0.7.5
|
@@ -39,6 +39,9 @@ module Sorcery
|
|
39
39
|
|
40
40
|
# Copy the migrations files to db/migrate folder
|
41
41
|
def copy_migration_files
|
42
|
+
# Copy core migration file in all cases except when you pass --migrations.
|
43
|
+
migration_template "migration/core.rb", "db/migrate/sorcery_core.rb" unless options[:migrations]
|
44
|
+
|
42
45
|
if submodules
|
43
46
|
submodules.each do |submodule|
|
44
47
|
unless submodule == "http_basic_auth" || submodule == "session_timeout"
|
@@ -47,8 +50,7 @@ module Sorcery
|
|
47
50
|
end
|
48
51
|
end
|
49
52
|
|
50
|
-
|
51
|
-
migration_template "migration/core.rb", "db/migrate/sorcery_core.rb" unless options[:migrations]
|
53
|
+
|
52
54
|
end
|
53
55
|
|
54
56
|
# Define the next_migration_number method (necessary for the migration_template method to work)
|
@@ -69,4 +71,4 @@ module Sorcery
|
|
69
71
|
end
|
70
72
|
end
|
71
73
|
end
|
72
|
-
end
|
74
|
+
end
|
@@ -29,19 +29,22 @@ Rails.application.config.sorcery.configure do |config|
|
|
29
29
|
# -- http_basic_auth --
|
30
30
|
# config.controller_to_realm_map = {"application" => "Application"} # What realm to display for which controller name.
|
31
31
|
# For example {"My App" => "Application"}
|
32
|
-
|
32
|
+
|
33
33
|
# -- activity logging --
|
34
34
|
# config.register_login_time = true # will register the time of last user login, every login.
|
35
35
|
# config.register_logout_time = true # will register the time of last user logout, every logout.
|
36
36
|
# config.register_last_activity_time = true # will register the time of last user action, every action.
|
37
|
-
|
37
|
+
|
38
38
|
# -- external --
|
39
39
|
# config.external_providers = [] # What providers are supported by this app,
|
40
|
-
# i.e. [:twitter, :facebook, :github] .
|
40
|
+
# i.e. [:twitter, :facebook, :github, :google, :liveid] .
|
41
41
|
# config.ca_file = 'path/to/ca_file' # Path to ca_file. By default use a internal ca-bundle.crt.
|
42
42
|
# You can change it by your local ca_file.
|
43
43
|
# i.e. '/etc/pki/tls/certs/ca-bundle.crt'
|
44
44
|
|
45
|
+
# Twitter wil not accept any requests nor redirect uri containing localhost,
|
46
|
+
# make sure you use 0.0.0.0:3000 to access your app in development
|
47
|
+
#
|
45
48
|
# config.twitter.key = "eYVNBjBDi33aa9GkA3w"
|
46
49
|
# config.twitter.secret = "XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8"
|
47
50
|
# config.twitter.callback_url = "http://0.0.0.0:3000/oauth/callback?provider=twitter"
|
@@ -56,6 +59,20 @@ Rails.application.config.sorcery.configure do |config|
|
|
56
59
|
# config.github.secret = ""
|
57
60
|
# config.github.callback_url = "http://0.0.0.0:3000/oauth/callback?provider=github"
|
58
61
|
# config.github.user_info_mapping = {:email => "name"}
|
62
|
+
#
|
63
|
+
# config.google.key = "491253340633.apps.googleusercontent.com"
|
64
|
+
# config.google.secret = "4oE6kXqbL_LN-VGcGcg7qgdL"
|
65
|
+
# config.google.callback_url = "http://0.0.0.0:3000/oauth/callback?provider=google"
|
66
|
+
# config.google.user_info_mapping = {:email => "email", :username => "name"}
|
67
|
+
#
|
68
|
+
# To use liveid in development mode you have to replace mydomain.com with
|
69
|
+
# a valid domain even in development. To use a valid domain in development
|
70
|
+
# simply add your domain in your /etc/hosts file in front of 127.0.0.1
|
71
|
+
#
|
72
|
+
# config.liveid.key = ""
|
73
|
+
# config.liveid.secret = ""
|
74
|
+
# config.liveid.callback_url = "http://mydomain.com:3000/oauth/callback?provider=liveid"
|
75
|
+
# config.liveid.user_info_mapping = {:username => "name"}
|
59
76
|
|
60
77
|
# --- user config ---
|
61
78
|
config.user_config do |user|
|
@@ -69,6 +86,10 @@ Rails.application.config.sorcery.configure do |config|
|
|
69
86
|
# until an encrypted one is
|
70
87
|
# generated.
|
71
88
|
|
89
|
+
# user.downcase_username_before_authenticating = false # downcase the username before
|
90
|
+
# trying to authenticate, default
|
91
|
+
# is false
|
92
|
+
|
72
93
|
# user.email_attribute_name = :email # change default email attribute.
|
73
94
|
|
74
95
|
# user.crypted_password_attribute_name = :crypted_password # change default crypted_password
|
@@ -88,7 +109,7 @@ Rails.application.config.sorcery.configure do |config|
|
|
88
109
|
#
|
89
110
|
# WARNING:
|
90
111
|
#
|
91
|
-
# If used for users' passwords, changing this key
|
112
|
+
# If used for users' passwords, changing this key
|
92
113
|
# will leave passwords undecryptable!
|
93
114
|
|
94
115
|
# user.custom_encryption_provider = nil # use an external encryption
|
data/lib/sorcery.rb
CHANGED
@@ -34,6 +34,8 @@ module Sorcery
|
|
34
34
|
autoload :Twitter, 'sorcery/controller/submodules/external/providers/twitter'
|
35
35
|
autoload :Facebook, 'sorcery/controller/submodules/external/providers/facebook'
|
36
36
|
autoload :Github, 'sorcery/controller/submodules/external/providers/github'
|
37
|
+
autoload :Google, 'sorcery/controller/submodules/external/providers/google'
|
38
|
+
autoload :Liveid, 'sorcery/controller/submodules/external/providers/liveid'
|
37
39
|
end
|
38
40
|
end
|
39
41
|
end
|
@@ -8,35 +8,34 @@ module Sorcery
|
|
8
8
|
def oauth_version
|
9
9
|
"2.0"
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
def authorize_url(options = {})
|
13
|
-
|
14
|
-
:site => @site,
|
15
|
-
:ssl => { :ca_file => Config.ca_file }
|
16
|
-
}
|
17
|
-
client = ::OAuth2::Client.new(
|
18
|
-
@key,
|
19
|
-
@secret,
|
20
|
-
defaults.merge!(options)
|
21
|
-
)
|
13
|
+
client = build_client(options)
|
22
14
|
client.web_server.authorize_url(
|
23
15
|
:redirect_uri => @callback_url,
|
24
16
|
:scope => @scope
|
25
17
|
)
|
26
18
|
end
|
27
|
-
|
28
|
-
def get_access_token(args)
|
29
|
-
client =
|
30
|
-
@key,
|
31
|
-
@secret,
|
32
|
-
:site => @site,
|
33
|
-
:ssl => { :ca_file => Config.ca_file }
|
34
|
-
)
|
19
|
+
|
20
|
+
def get_access_token(args, options = {})
|
21
|
+
client = build_client(options)
|
35
22
|
client.web_server.get_access_token(
|
36
23
|
args[:code],
|
37
24
|
:redirect_uri => @callback_url
|
38
25
|
)
|
39
26
|
end
|
27
|
+
|
28
|
+
def build_client(options = {})
|
29
|
+
defaults = {
|
30
|
+
:site => @site,
|
31
|
+
:ssl => { :ca_file => Config.ca_file }
|
32
|
+
}
|
33
|
+
::OAuth2::Client.new(
|
34
|
+
@key,
|
35
|
+
@secret,
|
36
|
+
defaults.merge!(options)
|
37
|
+
)
|
38
|
+
end
|
40
39
|
end
|
41
40
|
end
|
42
41
|
end
|
@@ -31,6 +31,8 @@ module Sorcery
|
|
31
31
|
attr_accessor :key,
|
32
32
|
:secret,
|
33
33
|
:callback_url,
|
34
|
+
:auth_path,
|
35
|
+
:token_path,
|
34
36
|
:site,
|
35
37
|
:user_info_path,
|
36
38
|
:user_info_mapping
|
@@ -39,7 +41,9 @@ module Sorcery
|
|
39
41
|
|
40
42
|
def init
|
41
43
|
@site = "https://github.com/"
|
42
|
-
@user_info_path = "
|
44
|
+
@user_info_path = "https://api.github.com/user"
|
45
|
+
@auth_path = "/login/oauth/authorize"
|
46
|
+
@token_path = "/login/oauth/access_token"
|
43
47
|
@user_info_mapping = {}
|
44
48
|
end
|
45
49
|
|
@@ -58,14 +62,18 @@ module Sorcery
|
|
58
62
|
# calculates and returns the url to which the user should be redirected,
|
59
63
|
# to get authenticated at the external provider's site.
|
60
64
|
def login_url(params,session)
|
61
|
-
self.authorize_url({:authorize_path =>
|
65
|
+
self.authorize_url({:authorize_path => @auth_path})
|
62
66
|
end
|
63
67
|
|
64
68
|
# tries to login the user from access token
|
65
69
|
def process_callback(params,session)
|
66
70
|
args = {}
|
67
71
|
args.merge!({:code => params[:code]}) if params[:code]
|
68
|
-
|
72
|
+
options = {
|
73
|
+
:access_token_path => @token_path,
|
74
|
+
:access_token_method => :post
|
75
|
+
}
|
76
|
+
@access_token = self.get_access_token(args, options)
|
69
77
|
end
|
70
78
|
|
71
79
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Sorcery
|
2
|
+
module Controller
|
3
|
+
module Submodules
|
4
|
+
module External
|
5
|
+
module Providers
|
6
|
+
# This module adds support for OAuth with google.com.
|
7
|
+
# When included in the 'config.providers' option, it adds a new option, 'config.google'.
|
8
|
+
# Via this new option you can configure Google specific settings like your app's key and secret.
|
9
|
+
#
|
10
|
+
# config.google.key = <key>
|
11
|
+
# config.google.secret = <secret>
|
12
|
+
# ...
|
13
|
+
#
|
14
|
+
module Google
|
15
|
+
def self.included(base)
|
16
|
+
base.module_eval do
|
17
|
+
class << self
|
18
|
+
attr_reader :google # access to google_client.
|
19
|
+
|
20
|
+
def merge_google_defaults!
|
21
|
+
@defaults.merge!(:@google => GoogleClient)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
merge_google_defaults!
|
25
|
+
update!
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
module GoogleClient
|
30
|
+
class << self
|
31
|
+
attr_accessor :key,
|
32
|
+
:secret,
|
33
|
+
:callback_url,
|
34
|
+
:site,
|
35
|
+
:auth_url,
|
36
|
+
:token_path,
|
37
|
+
:user_info_url,
|
38
|
+
:scope,
|
39
|
+
:user_info_mapping
|
40
|
+
|
41
|
+
include Protocols::Oauth2
|
42
|
+
|
43
|
+
def init
|
44
|
+
@site = "https://accounts.google.com"
|
45
|
+
@auth_url = "/o/oauth2/auth"
|
46
|
+
@token_path = "/o/oauth2/token"
|
47
|
+
@user_info_url = "https://www.googleapis.com/oauth2/v1/userinfo"
|
48
|
+
@scope = "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile"
|
49
|
+
@user_info_mapping = {}
|
50
|
+
end
|
51
|
+
|
52
|
+
def get_user_hash
|
53
|
+
user_hash = {}
|
54
|
+
response = @access_token.get(@user_info_url)
|
55
|
+
user_hash[:user_info] = JSON.parse(response)
|
56
|
+
user_hash[:uid] = user_hash[:user_info]['id']
|
57
|
+
user_hash
|
58
|
+
end
|
59
|
+
|
60
|
+
def has_callback?
|
61
|
+
true
|
62
|
+
end
|
63
|
+
|
64
|
+
# calculates and returns the url to which the user should be redirected,
|
65
|
+
# to get authenticated at the external provider's site.
|
66
|
+
def login_url(params,session)
|
67
|
+
self.authorize_url({:authorize_url => @auth_url})
|
68
|
+
end
|
69
|
+
|
70
|
+
# tries to login the user from access token
|
71
|
+
def process_callback(params,session)
|
72
|
+
args = {}
|
73
|
+
args.merge!({:code => params[:code]}) if params[:code]
|
74
|
+
options = {
|
75
|
+
:access_token_path => @token_path,
|
76
|
+
:access_token_method => :post
|
77
|
+
}
|
78
|
+
@access_token = self.get_access_token(args, options)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
init
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Sorcery
|
2
|
+
module Controller
|
3
|
+
module Submodules
|
4
|
+
module External
|
5
|
+
module Providers
|
6
|
+
# This module adds support for OAuth with microsoft liveid
|
7
|
+
# When included in the 'config.providers' option, it adds a new option, 'config.liveid'.
|
8
|
+
# Via this new option you can configure LiveId specific settings like your app's key and secret.
|
9
|
+
#
|
10
|
+
# config.liveid.key = <key>
|
11
|
+
# config.liveid.secret = <secret>
|
12
|
+
# ...
|
13
|
+
#
|
14
|
+
module Liveid
|
15
|
+
def self.included(base)
|
16
|
+
base.module_eval do
|
17
|
+
class << self
|
18
|
+
attr_reader :liveid # access to liveid_client.
|
19
|
+
|
20
|
+
def merge_liveid_defaults!
|
21
|
+
@defaults.merge!(:@liveid => LiveidClient)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
merge_liveid_defaults!
|
25
|
+
update!
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
module LiveidClient
|
30
|
+
class << self
|
31
|
+
attr_accessor :key,
|
32
|
+
:secret,
|
33
|
+
:callback_url,
|
34
|
+
:site,
|
35
|
+
:auth_url,
|
36
|
+
:token_path,
|
37
|
+
:user_info_url,
|
38
|
+
:scope,
|
39
|
+
:user_info_mapping
|
40
|
+
|
41
|
+
include Protocols::Oauth2
|
42
|
+
|
43
|
+
def init
|
44
|
+
@site = "https://oauth.live.com/"
|
45
|
+
@auth_url = "/authorize"
|
46
|
+
@token_path = "/token"
|
47
|
+
@user_info_url = "https://apis.live.net/v5.0/me"
|
48
|
+
@scope = "wl.basic wl.emails wl.offline_access"
|
49
|
+
@user_info_mapping = {}
|
50
|
+
end
|
51
|
+
|
52
|
+
def get_user_hash
|
53
|
+
user_hash = {}
|
54
|
+
@access_token.token_param = "access_token"
|
55
|
+
response = @access_token.get(@user_info_url)
|
56
|
+
user_hash[:user_info] = JSON.parse(response)
|
57
|
+
user_hash[:uid] = user_hash[:user_info]['id']
|
58
|
+
user_hash
|
59
|
+
end
|
60
|
+
|
61
|
+
def has_callback?
|
62
|
+
true
|
63
|
+
end
|
64
|
+
|
65
|
+
# calculates and returns the url to which the user should be redirected,
|
66
|
+
# to get authenticated at the external provider's site.
|
67
|
+
def login_url(params,session)
|
68
|
+
self.authorize_url({:authorize_url => @auth_url})
|
69
|
+
end
|
70
|
+
|
71
|
+
# tries to login the user from access token
|
72
|
+
def process_callback(params,session)
|
73
|
+
args = {}
|
74
|
+
args.merge!({:code => params[:code]}) if params[:code]
|
75
|
+
options = {
|
76
|
+
:access_token_path => @token_path,
|
77
|
+
:access_token_method => :post
|
78
|
+
}
|
79
|
+
@access_token = self.get_access_token(args, options)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
init
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
data/lib/sorcery/model.rb
CHANGED
@@ -104,7 +104,11 @@ module Sorcery
|
|
104
104
|
# returns the user if success, nil otherwise.
|
105
105
|
def authenticate(*credentials)
|
106
106
|
raise ArgumentError, "at least 2 arguments required" if credentials.size < 2
|
107
|
+
credentials[0].downcase! if @sorcery_config.downcase_username_before_authenticating
|
107
108
|
user = find_by_credentials(credentials)
|
109
|
+
|
110
|
+
set_encryption_attributes()
|
111
|
+
|
108
112
|
_salt = user.send(@sorcery_config.salt_attribute_name) if user && !@sorcery_config.salt_attribute_name.nil? && !@sorcery_config.encryption_provider.nil?
|
109
113
|
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)
|
110
114
|
end
|
@@ -113,14 +117,19 @@ module Sorcery
|
|
113
117
|
def encrypt(*tokens)
|
114
118
|
return tokens.first if @sorcery_config.encryption_provider.nil?
|
115
119
|
|
116
|
-
|
117
|
-
|
120
|
+
set_encryption_attributes()
|
121
|
+
|
118
122
|
CryptoProviders::AES256.key = @sorcery_config.encryption_key
|
119
123
|
@sorcery_config.encryption_provider.encrypt(*tokens)
|
120
124
|
end
|
121
125
|
|
122
126
|
protected
|
123
|
-
|
127
|
+
|
128
|
+
def set_encryption_attributes()
|
129
|
+
@sorcery_config.encryption_provider.stretches = @sorcery_config.stretches if @sorcery_config.encryption_provider.respond_to?(:stretches) && @sorcery_config.stretches
|
130
|
+
@sorcery_config.encryption_provider.join_token = @sorcery_config.salt_join_token if @sorcery_config.encryption_provider.respond_to?(:join_token) && @sorcery_config.salt_join_token
|
131
|
+
end
|
132
|
+
|
124
133
|
# Calls the configured encryption provider to compare the supplied password with the encrypted one.
|
125
134
|
def credentials_match?(crypted, *tokens)
|
126
135
|
return crypted == tokens.join if @sorcery_config.encryption_provider.nil?
|
@@ -193,6 +202,9 @@ module Sorcery
|
|
193
202
|
# until an encrypted one is generated.
|
194
203
|
|
195
204
|
:email_attribute_name, # change default email attribute.
|
205
|
+
|
206
|
+
:downcase_username_before_authenticating, # downcase the username before trying to authenticate, default is false
|
207
|
+
|
196
208
|
:crypted_password_attribute_name, # change default crypted_password attribute.
|
197
209
|
:salt_join_token, # what pattern to use to join the password with the salt
|
198
210
|
:salt_attribute_name, # change default salt attribute.
|
@@ -220,6 +232,7 @@ module Sorcery
|
|
220
232
|
:@submodules => [],
|
221
233
|
:@username_attribute_names => [:username],
|
222
234
|
:@password_attribute_name => :password,
|
235
|
+
:@downcase_username_before_authenticating => false,
|
223
236
|
:@email_attribute_name => :email,
|
224
237
|
:@crypted_password_attribute_name => :crypted_password,
|
225
238
|
:@encryption_algorithm => :bcrypt,
|
@@ -268,4 +281,4 @@ module Sorcery
|
|
268
281
|
end
|
269
282
|
|
270
283
|
end
|
271
|
-
end
|
284
|
+
end
|