sorcery 0.2.1 → 0.4.2
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/Gemfile +3 -2
- data/Gemfile.lock +13 -11
- data/README.rdoc +157 -61
- data/Rakefile +4 -4
- 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/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/{oauth.rb → external.rb} +18 -27
- data/lib/sorcery/controller/submodules/http_basic_auth.rb +11 -7
- data/lib/sorcery/controller.rb +21 -21
- data/lib/sorcery/crypto_providers/bcrypt.rb +3 -5
- data/lib/sorcery/crypto_providers/common.rb +35 -0
- data/lib/sorcery/crypto_providers/md5.rb +3 -23
- data/lib/sorcery/crypto_providers/sha1.rb +4 -16
- data/lib/sorcery/crypto_providers/sha256.rb +3 -23
- data/lib/sorcery/crypto_providers/sha512.rb +3 -23
- data/lib/sorcery/engine.rb +4 -0
- data/lib/sorcery/initializers/initializer.rb +86 -0
- data/lib/sorcery/model/submodules/activity_logging.rb +2 -2
- data/lib/sorcery/model/submodules/brute_force_protection.rb +1 -5
- data/lib/sorcery/model/submodules/{oauth.rb → external.rb} +3 -3
- data/lib/sorcery/model/submodules/reset_password.rb +1 -1
- data/lib/sorcery/model.rb +34 -9
- data/lib/sorcery/railties/tasks.rake +10 -0
- data/lib/sorcery/sinatra.rb +5 -0
- data/lib/sorcery/test_helpers/internal/rails.rb +52 -0
- data/lib/sorcery/test_helpers/internal/sinatra.rb +122 -0
- data/lib/sorcery/test_helpers/internal.rb +55 -0
- data/lib/sorcery/test_helpers/rails.rb +16 -0
- data/lib/sorcery/test_helpers/sinatra.rb +85 -0
- data/lib/sorcery/test_helpers.rb +0 -79
- data/lib/sorcery.rb +25 -7
- data/sorcery.gemspec +207 -137
- data/spec/Gemfile +2 -2
- data/spec/Gemfile.lock +20 -12
- data/spec/Rakefile +1 -0
- data/spec/rails3/.rspec +1 -1
- data/spec/rails3/{app_root/Gemfile → Gemfile} +5 -7
- data/spec/rails3/{app_root/Gemfile.lock → Gemfile.lock} +20 -23
- data/spec/rails3/{app_root/Rakefile → Rakefile} +1 -0
- data/spec/rails3/{app_root/app → app}/controllers/application_controller.rb +11 -11
- data/spec/rails3/config/database.yml +27 -0
- data/spec/rails3/{app_root/spec → spec}/controller_activity_logging_spec.rb +2 -4
- data/spec/rails3/{app_root/spec → spec}/controller_brute_force_protection_spec.rb +3 -2
- data/spec/rails3/{app_root/spec → spec}/controller_oauth2_spec.rb +25 -22
- data/spec/rails3/{app_root/spec → spec}/controller_oauth_spec.rb +24 -19
- data/spec/rails3/spec/controller_session_timeout_spec.rb +55 -0
- data/spec/rails3/{app_root/spec → spec}/controller_spec.rb +6 -16
- data/spec/rails3/spec/spec.opts +2 -0
- data/spec/rails3/spec/spec_helper.rb +70 -0
- data/spec/rails3/{app_root/spec → spec}/user_activation_spec.rb +7 -13
- data/spec/rails3/{app_root/spec → spec}/user_brute_force_protection_spec.rb +2 -30
- data/spec/rails3/{app_root/spec → spec}/user_oauth_spec.rb +7 -7
- data/spec/rails3/{app_root/spec → spec}/user_remember_me_spec.rb +3 -11
- data/spec/rails3/{app_root/spec → spec}/user_reset_password_spec.rb +20 -17
- data/spec/rails3/{app_root/spec → spec}/user_spec.rb +21 -11
- data/spec/sinatra/Gemfile +12 -0
- data/spec/sinatra/Gemfile.lock +134 -0
- data/spec/sinatra/Rakefile +11 -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 +70 -0
- data/spec/sinatra/spec/controller_http_basic_auth_spec.rb +53 -0
- data/spec/sinatra/spec/controller_oauth2_spec.rb +120 -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 +57 -0
- data/spec/sinatra/spec/controller_spec.rb +120 -0
- data/spec/sinatra/spec/spec.opts +2 -0
- data/spec/sinatra/spec/spec_helper.rb +46 -0
- data/spec/sinatra/user.rb +6 -0
- data/spec/sinatra/views/test_login.erb +4 -0
- data/spec/sorcery_crypto_providers_spec.rb +5 -4
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +3 -4
- data/spec/untitled folder +18 -0
- metadata +217 -139
- 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/.rspec +0 -1
- data/spec/rails3/app_root/config/database.yml +0 -27
- data/spec/rails3/app_root/spec/controller_session_timeout_spec.rb +0 -50
- data/spec/rails3/app_root/spec/spec_helper.rb +0 -61
- /data/spec/rails3/{app_root/.gitignore → .gitignore} +0 -0
- /data/spec/rails3/{app_root/README → README} +0 -0
- /data/spec/rails3/{app_root/Rakefile.unused → Rakefile.unused} +0 -0
- /data/spec/rails3/{app_root/app → app}/helpers/application_helper.rb +0 -0
- /data/spec/rails3/{app_root/app → app}/mailers/sorcery_mailer.rb +0 -0
- /data/spec/rails3/{app_root/app → app}/models/authentication.rb +0 -0
- /data/spec/rails3/{app_root/app → app}/models/user.rb +0 -0
- /data/spec/rails3/{app_root/app → app}/views/layouts/application.html.erb +0 -0
- /data/spec/rails3/{app_root/app → app}/views/sorcery_mailer/activation_email.html.erb +0 -0
- /data/spec/rails3/{app_root/app → app}/views/sorcery_mailer/activation_email.text.erb +0 -0
- /data/spec/rails3/{app_root/app → app}/views/sorcery_mailer/activation_success_email.html.erb +0 -0
- /data/spec/rails3/{app_root/app → app}/views/sorcery_mailer/activation_success_email.text.erb +0 -0
- /data/spec/rails3/{app_root/app → app}/views/sorcery_mailer/reset_password_email.html.erb +0 -0
- /data/spec/rails3/{app_root/app → app}/views/sorcery_mailer/reset_password_email.text.erb +0 -0
- /data/spec/rails3/{app_root/config → config}/application.rb +0 -0
- /data/spec/rails3/{app_root/config → config}/boot.rb +0 -0
- /data/spec/rails3/{app_root/config → config}/environment.rb +0 -0
- /data/spec/rails3/{app_root/config → config}/environments/development.rb +0 -0
- /data/spec/rails3/{app_root/config → config}/environments/in_memory.rb +0 -0
- /data/spec/rails3/{app_root/config → config}/environments/production.rb +0 -0
- /data/spec/rails3/{app_root/config → config}/environments/test.rb +0 -0
- /data/spec/rails3/{app_root/config → config}/initializers/backtrace_silencers.rb +0 -0
- /data/spec/rails3/{app_root/config → config}/initializers/inflections.rb +0 -0
- /data/spec/rails3/{app_root/config → config}/initializers/mime_types.rb +0 -0
- /data/spec/rails3/{app_root/config → config}/initializers/secret_token.rb +0 -0
- /data/spec/rails3/{app_root/config → config}/initializers/session_store.rb +0 -0
- /data/spec/rails3/{app_root/config → config}/locales/en.yml +0 -0
- /data/spec/rails3/{app_root/config → config}/routes.rb +0 -0
- /data/spec/rails3/{app_root/config.ru → config.ru} +0 -0
- /data/spec/rails3/{app_root/db → db}/migrate/activation/20101224223622_add_activation_to_users.rb +0 -0
- /data/spec/rails3/{app_root/db → db}/migrate/activity_logging/20101224223624_add_activity_logging_to_users.rb +0 -0
- /data/spec/rails3/{app_root/db → db}/migrate/brute_force_protection/20101224223626_add_brute_force_protection_to_users.rb +0 -0
- /data/spec/rails3/{app_root/db → db}/migrate/core/20101224223620_create_users.rb +0 -0
- /data/spec/rails3/{app_root/db/migrate/oauth → db/migrate/external}/20101224223628_create_authentications.rb +0 -0
- /data/spec/rails3/{app_root/db → db}/migrate/remember_me/20101224223623_add_remember_me_token_to_users.rb +0 -0
- /data/spec/rails3/{app_root/db → db}/migrate/reset_password/20101224223622_add_reset_password_to_users.rb +0 -0
- /data/spec/rails3/{app_root/db → db}/schema.rb +0 -0
- /data/spec/rails3/{app_root/db → db}/seeds.rb +0 -0
- /data/spec/rails3/{app_root/lib → lib}/tasks/.gitkeep +0 -0
- /data/spec/rails3/{app_root/public → public}/404.html +0 -0
- /data/spec/rails3/{app_root/public → public}/422.html +0 -0
- /data/spec/rails3/{app_root/public → public}/500.html +0 -0
- /data/spec/rails3/{app_root/public → public}/favicon.ico +0 -0
- /data/spec/rails3/{app_root/public → public}/images/rails.png +0 -0
- /data/spec/rails3/{app_root/public → public}/index.html +0 -0
- /data/spec/rails3/{app_root/public → public}/javascripts/application.js +0 -0
- /data/spec/rails3/{app_root/public → public}/javascripts/controls.js +0 -0
- /data/spec/rails3/{app_root/public → public}/javascripts/dragdrop.js +0 -0
- /data/spec/rails3/{app_root/public → public}/javascripts/effects.js +0 -0
- /data/spec/rails3/{app_root/public → public}/javascripts/prototype.js +0 -0
- /data/spec/rails3/{app_root/public → public}/javascripts/rails.js +0 -0
- /data/spec/rails3/{app_root/public → public}/robots.txt +0 -0
- /data/spec/rails3/{app_root/public → public}/stylesheets/.gitkeep +0 -0
- /data/spec/rails3/{app_root/script → script}/rails +0 -0
- /data/spec/rails3/{app_root/spec → spec}/controller_http_basic_auth_spec.rb +0 -0
- /data/spec/rails3/{app_root/spec → spec}/controller_remember_me_spec.rb +0 -0
- /data/spec/rails3/{app_root/spec → spec}/spec_helper.orig.rb +0 -0
- /data/spec/rails3/{app_root/spec → spec}/user_activity_logging_spec.rb +0 -0
- /data/spec/rails3/{app_root/vendor → vendor}/plugins/.gitkeep +0 -0
data/Gemfile
CHANGED
|
@@ -9,12 +9,13 @@ gem 'oauth2', ">= 0.1.1"
|
|
|
9
9
|
# Add dependencies to develop your gem here.
|
|
10
10
|
# Include everything needed to run rake, tests, features, etc.
|
|
11
11
|
group :development do
|
|
12
|
-
gem "rspec", "~> 2.
|
|
13
|
-
gem 'rspec-rails'
|
|
12
|
+
gem "rspec", "~> 2.5.0"
|
|
13
|
+
gem 'rspec-rails', "~> 2.5.0"
|
|
14
14
|
gem 'ruby-debug19'
|
|
15
15
|
gem 'sqlite3-ruby', :require => 'sqlite3'
|
|
16
16
|
gem "yard", "~> 0.6.0"
|
|
17
17
|
gem "bundler", "~> 1.0.0"
|
|
18
18
|
gem "jeweler", "~> 1.5.2"
|
|
19
19
|
gem 'simplecov', '>= 0.3.8', :require => false # Will install simplecov-html as a dependency
|
|
20
|
+
gem 'timecop'
|
|
20
21
|
end
|
data/Gemfile.lock
CHANGED
|
@@ -81,19 +81,19 @@ GEM
|
|
|
81
81
|
rake (>= 0.8.7)
|
|
82
82
|
thor (~> 0.14.4)
|
|
83
83
|
rake (0.8.7)
|
|
84
|
-
rspec (2.
|
|
85
|
-
rspec-core (~> 2.
|
|
86
|
-
rspec-expectations (~> 2.
|
|
87
|
-
rspec-mocks (~> 2.
|
|
88
|
-
rspec-core (2.
|
|
89
|
-
rspec-expectations (2.
|
|
84
|
+
rspec (2.5.0)
|
|
85
|
+
rspec-core (~> 2.5.0)
|
|
86
|
+
rspec-expectations (~> 2.5.0)
|
|
87
|
+
rspec-mocks (~> 2.5.0)
|
|
88
|
+
rspec-core (2.5.1)
|
|
89
|
+
rspec-expectations (2.5.0)
|
|
90
90
|
diff-lcs (~> 1.1.2)
|
|
91
|
-
rspec-mocks (2.
|
|
92
|
-
rspec-rails (2.
|
|
91
|
+
rspec-mocks (2.5.0)
|
|
92
|
+
rspec-rails (2.5.0)
|
|
93
93
|
actionpack (~> 3.0)
|
|
94
94
|
activesupport (~> 3.0)
|
|
95
95
|
railties (~> 3.0)
|
|
96
|
-
rspec (~> 2.
|
|
96
|
+
rspec (~> 2.5.0)
|
|
97
97
|
ruby-debug-base19 (0.11.24)
|
|
98
98
|
columnize (>= 0.3.1)
|
|
99
99
|
linecache19 (>= 0.5.11)
|
|
@@ -109,6 +109,7 @@ GEM
|
|
|
109
109
|
simplecov-html (0.3.9)
|
|
110
110
|
sqlite3-ruby (1.3.2)
|
|
111
111
|
thor (0.14.6)
|
|
112
|
+
timecop (0.3.5)
|
|
112
113
|
treetop (1.4.9)
|
|
113
114
|
polyglot (>= 0.3.1)
|
|
114
115
|
tzinfo (0.3.23)
|
|
@@ -124,9 +125,10 @@ DEPENDENCIES
|
|
|
124
125
|
oauth (>= 0.4.4)
|
|
125
126
|
oauth2 (>= 0.1.1)
|
|
126
127
|
rails (>= 3.0.0)
|
|
127
|
-
rspec (~> 2.
|
|
128
|
-
rspec-rails
|
|
128
|
+
rspec (~> 2.5.0)
|
|
129
|
+
rspec-rails (~> 2.5.0)
|
|
129
130
|
ruby-debug19
|
|
130
131
|
simplecov (>= 0.3.8)
|
|
131
132
|
sqlite3-ruby
|
|
133
|
+
timecop
|
|
132
134
|
yard (~> 0.6.0)
|
data/README.rdoc
CHANGED
|
@@ -1,34 +1,151 @@
|
|
|
1
1
|
= sorcery
|
|
2
|
-
Magical Authentication for Rails 3.
|
|
2
|
+
Magical Authentication for Rails 3 and Sinatra.
|
|
3
3
|
|
|
4
4
|
Inspired by restful_authentication, Authlogic and Devise.
|
|
5
5
|
Crypto code taken almost unchanged from Authlogic.
|
|
6
|
-
OAuth code inspired by OmniAuth.
|
|
6
|
+
OAuth code inspired by OmniAuth and Ryan Bates's railscasts about it.
|
|
7
7
|
|
|
8
|
-
== Summary
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
It does this with a few goals in mind:
|
|
9
|
+
== Philosophy
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
|
|
12
|
+
Sorcery is a stripped-down, bare-bones authentication library, with which you can write your own authentication flow.
|
|
13
|
+
It was built with a few goals in mind:
|
|
14
|
+
|
|
15
|
+
* Less is more - less than 20 public methods to remember for the entire feature-set make the lib easy to 'get'.
|
|
16
|
+
* No built-in or generated code - use the library's methods inside *your own* MVC structures, and don't fight to fix someone else's.
|
|
15
17
|
* Magic yes, Voodoo no - the lib should be easy to hack for most developers.
|
|
16
18
|
* Configuration over Confusion - Simple & short configuration as possible, not drowning in syntactic sugar.
|
|
17
19
|
* Keep MVC cleanly separated - DB is for models, sessions are for controllers. Models stay unaware of sessions.
|
|
18
20
|
|
|
19
21
|
Hopefully, I've achieved this. If not, let me know.
|
|
20
22
|
|
|
23
|
+
|
|
21
24
|
== Useful Links:
|
|
22
25
|
|
|
23
|
-
Example app using sorcery: https://github.com/NoamB/sorcery-example-app
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
Example Rails 3 app using sorcery: https://github.com/NoamB/sorcery-example-app
|
|
28
|
+
|
|
29
|
+
Example Sinatra app using sorcery: https://github.com/NoamB/sorcery-example-app-sinatra
|
|
30
|
+
|
|
31
|
+
Documentation: http://rubydoc.info/gems/sorcery/0.4.2/frames
|
|
26
32
|
|
|
27
33
|
Check out the tutorials in the github wiki!
|
|
28
34
|
|
|
35
|
+
|
|
36
|
+
== API Summary
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
Below is a summary of the library methods. Most method names are self explaining and the rest are commented:
|
|
40
|
+
|
|
41
|
+
# core
|
|
42
|
+
require_login # this is a before filter
|
|
43
|
+
login(username,password,remember_me = false)
|
|
44
|
+
logout
|
|
45
|
+
logged_in?
|
|
46
|
+
current_user
|
|
47
|
+
redirect_back_or_to # 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.
|
|
48
|
+
@user.external? # external users, such as facebook/twitter etc.
|
|
49
|
+
User.authenticates_with_sorcery!
|
|
50
|
+
|
|
51
|
+
# activity logging
|
|
52
|
+
current_users
|
|
53
|
+
|
|
54
|
+
# http basic auth
|
|
55
|
+
require_login_from_http_basic # this is a before filter
|
|
56
|
+
|
|
57
|
+
# external
|
|
58
|
+
login_at(provider) # sends the user to an external service (twitter etc.) to authenticate.
|
|
59
|
+
login_from(provider) # tries to login from the external provider's callback.
|
|
60
|
+
create_from(provider) # create the user in the local app db.
|
|
61
|
+
|
|
62
|
+
# remember me
|
|
63
|
+
remember_me!
|
|
64
|
+
forget_me!
|
|
65
|
+
|
|
66
|
+
# reset password
|
|
67
|
+
User.load_from_reset_password_token(token)
|
|
68
|
+
@user.deliver_reset_password_instructions!
|
|
69
|
+
@user.reset_password!(params)
|
|
70
|
+
|
|
71
|
+
# user activation
|
|
72
|
+
User.load_from_activation_token(token)
|
|
73
|
+
@user.activate!
|
|
74
|
+
|
|
75
|
+
Please see the tutorials in the github wiki for detailed usage information.
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
== Installation:
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
If using bundler, first add 'sorcery' to your Gemfile:
|
|
82
|
+
|
|
83
|
+
gem "sorcery"
|
|
84
|
+
|
|
85
|
+
And run
|
|
86
|
+
|
|
87
|
+
bundle install
|
|
88
|
+
|
|
89
|
+
Otherwise simply
|
|
90
|
+
|
|
91
|
+
gem install sorcery
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
== Rails 3 Configuration:
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
For Rails 3 create an initializer file using:
|
|
98
|
+
|
|
99
|
+
rake sorcery:bootstrap
|
|
100
|
+
|
|
101
|
+
This will create the file as config/initializers/sorcery.rb .
|
|
102
|
+
Inside it the comments will tell you everything you need to know.
|
|
103
|
+
|
|
104
|
+
For your convenience, Sorcery includes a migrations generator for Rails, which can be used like so:
|
|
105
|
+
|
|
106
|
+
rails g sorcery_migration [list of submodules]
|
|
107
|
+
|
|
108
|
+
For example, for only the core functionality use:
|
|
109
|
+
|
|
110
|
+
rails g sorcery_migration core
|
|
111
|
+
|
|
112
|
+
To generate migrations for both the core AND 'remember_me' submodule:
|
|
113
|
+
|
|
114
|
+
rails g sorcery_migration core remember_me
|
|
115
|
+
|
|
116
|
+
These migrations use the default fields. You can choose to use these migrations or make your own tables and fields. Sorcery tries not to impose a database structure and naming scheme on your application.
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
== Sinatra Configuration:
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
For Sinatra you'll need to create the initializer manually. You can do it in the main app file or in a separate file you require (see example in example app). The code looks as follows:
|
|
123
|
+
|
|
124
|
+
Sorcery::Controller::Config.submodules = [] # specify here the submodules you want to include
|
|
125
|
+
|
|
126
|
+
Sorcery::Controller::Config.configure do |config|
|
|
127
|
+
config.session_timeout = 10.minutes
|
|
128
|
+
...
|
|
129
|
+
...
|
|
130
|
+
|
|
131
|
+
config.user_config do |user|
|
|
132
|
+
user.username_attribute_name = :email
|
|
133
|
+
...
|
|
134
|
+
...
|
|
135
|
+
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
Finally, to make all the code above take effect, we'll need to re-include the sorcery controller module:
|
|
140
|
+
|
|
141
|
+
include Sorcery::Controller::Adapters::Sinatra
|
|
142
|
+
include Sorcery::Controller
|
|
143
|
+
|
|
144
|
+
|
|
29
145
|
== Full Features List by module:
|
|
30
146
|
|
|
31
|
-
|
|
147
|
+
|
|
148
|
+
Core (see lib/sorcery/model.rb and lib/sorcery/controller.rb):
|
|
32
149
|
* login/logout, optional return user to requested url on login, configurable redirect for non-logged-in users.
|
|
33
150
|
* password encryption, algorithms: bcrypt(default), md5, sha1, sha256, sha512, aes256, custom(yours!), none. Configurable stretches and salt.
|
|
34
151
|
* configurable attribute names for username, password and email.
|
|
@@ -68,88 +185,67 @@ Activity Logging (see lib/sorcery/model/submodules/activity_logging.rb):
|
|
|
68
185
|
* an easy method of collecting the list of currently logged in users.
|
|
69
186
|
* configurable timeout by which to decide whether to include a user in the list of logged in users.
|
|
70
187
|
|
|
71
|
-
|
|
188
|
+
External (see lib/sorcery/controller/submodules/external.rb):
|
|
72
189
|
* OAuth1 and OAuth2 support (currently twitter & facebook)
|
|
73
190
|
* configurable db field names and authentications table.
|
|
74
191
|
|
|
192
|
+
|
|
75
193
|
== Next Planned Features:
|
|
76
194
|
|
|
195
|
+
|
|
77
196
|
I've got many plans which include (by priority):
|
|
78
|
-
*
|
|
197
|
+
* Forgot username, maybe as part of the reset_password module
|
|
198
|
+
* Scoping logins (to a subdomain or another arbitrary field)
|
|
79
199
|
* Mongoid support
|
|
80
|
-
* Configurable Auto login on registration/activation
|
|
81
200
|
* Other reset password strategies (security questions?)
|
|
82
201
|
* Other brute force protection strategies (captcha)
|
|
83
202
|
* Have an idea? Let me know, and it might get into the gem!
|
|
84
203
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
gem install sorcery
|
|
92
|
-
|
|
93
|
-
== Configuration:
|
|
204
|
+
Other stuff:
|
|
205
|
+
* Improve specs speed
|
|
206
|
+
* Provide an easy way to run specs after install
|
|
207
|
+
* Improve documentation
|
|
208
|
+
* Tty to reduce the number of library methods, and find better names to some
|
|
94
209
|
|
|
95
|
-
First add 'sorcery' to your Gemfile:
|
|
96
|
-
|
|
97
|
-
gem "sorcery"
|
|
98
|
-
|
|
99
|
-
And run
|
|
100
|
-
|
|
101
|
-
bundle install
|
|
102
|
-
|
|
103
|
-
There are 2 required places to configure the plugin, and an optional one:
|
|
104
|
-
1. config/application.rb
|
|
105
|
-
|
|
106
|
-
config.sorcery.submodules = [:user_activation, :remember_me] # add the modules you want to use
|
|
107
|
-
|
|
108
|
-
You can also configure here any controller and any controller-submodule option here.
|
|
109
|
-
For example:
|
|
110
|
-
|
|
111
|
-
config.sorcery.session_timeout = 10.minutes
|
|
112
210
|
|
|
211
|
+
== Backward compatibility
|
|
113
212
|
|
|
114
|
-
2. app/models/user.rb (or another model of your choice)
|
|
115
213
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
214
|
+
While the lib is young and evolving fast I'm breaking backward compatibility quite often.
|
|
215
|
+
I'm constantly finding better ways to do things and throwing away old ways.
|
|
216
|
+
To let you know when things are changing in a non-compatible way, I'm bumping the minor version of the gem.
|
|
217
|
+
The patch version changes are backward compatible.
|
|
120
218
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
activate_sorcery! do |config|
|
|
124
|
-
config.session_timeout = 10.minutes
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
Also check the migrations in the example app to see what database fields are expected.
|
|
128
|
-
|
|
129
|
-
The configuration options vary with the modules you've chosen to use.
|
|
219
|
+
In short, an app that works with x.3.1 should be able to upgrade to x.3.2 with no code changes.
|
|
220
|
+
The same cannot be said about upgrading to x.4.0 and above, however.
|
|
130
221
|
|
|
131
222
|
|
|
132
223
|
== Contributing to sorcery
|
|
133
224
|
|
|
225
|
+
|
|
134
226
|
Your feedback is very welcome and will make this gem much much better for you, me and everyone else.
|
|
135
227
|
Besides feedback on code, features, suggestions and bug reports, you may want to actually make an impact on the code.
|
|
136
228
|
For this:
|
|
137
229
|
|
|
138
|
-
* Fork
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
* Commit
|
|
142
|
-
* Send me a pull request
|
|
230
|
+
* Fork it.
|
|
231
|
+
* Fix it.
|
|
232
|
+
* Test it.
|
|
233
|
+
* Commit it.
|
|
234
|
+
* Send me a pull request so I'll... Pull it.
|
|
235
|
+
|
|
236
|
+
If you feel sorcery has made your life easier, and you would like to express your thanks via a donation, my paypal email is in the contact details.
|
|
143
237
|
|
|
144
|
-
If you feel my work has made your life easier, and you would like to thank me through a donation, my paypal email is in the contact details.
|
|
145
238
|
|
|
146
239
|
== Contact
|
|
147
240
|
|
|
241
|
+
|
|
242
|
+
Feel free to ask questions using these contact details:
|
|
243
|
+
|
|
148
244
|
email: nbenari@gmail.com ( also for paypal )
|
|
149
245
|
twitter: @nbenari
|
|
150
246
|
|
|
247
|
+
|
|
151
248
|
== Copyright
|
|
152
249
|
|
|
153
|
-
Copyright (c) 2010 Noam Ben Ari (nbenari@gmail.com). See LICENSE.txt for further details.
|
|
154
|
-
Released with permission from Kontera (http://www.kontera.com), where I work.
|
|
155
250
|
|
|
251
|
+
Copyright (c) 2010 Noam Ben Ari (nbenari@gmail.com). See LICENSE.txt for further details.
|
data/Rakefile
CHANGED
|
@@ -41,11 +41,11 @@ end
|
|
|
41
41
|
require 'yard'
|
|
42
42
|
YARD::Rake::YardocTask.new
|
|
43
43
|
|
|
44
|
-
desc 'Default: Run all specs.'
|
|
45
|
-
task :default => :
|
|
44
|
+
desc 'Default: Run all sorcery specs.'
|
|
45
|
+
task :default => :all_sorcery_specs
|
|
46
46
|
|
|
47
|
-
desc "Run all specs"
|
|
48
|
-
task :
|
|
47
|
+
desc "Run all sorcery specs"
|
|
48
|
+
task :all_sorcery_specs do
|
|
49
49
|
Dir['spec/**/Rakefile'].each do |rakefile|
|
|
50
50
|
directory_name = File.dirname(rakefile)
|
|
51
51
|
sh <<-CMD
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.2
|
|
1
|
+
0.4.2
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require 'rails/generators'
|
|
2
|
+
require 'rails/generators/migration'
|
|
3
|
+
|
|
4
|
+
class SorceryMigrationGenerator < Rails::Generators::Base
|
|
5
|
+
include Rails::Generators::Migration
|
|
6
|
+
|
|
7
|
+
source_root File.join(File.dirname(__FILE__), 'templates')
|
|
8
|
+
argument :submodules, :type => :array, :required => true
|
|
9
|
+
|
|
10
|
+
def self.next_migration_number(dirname)
|
|
11
|
+
if ActiveRecord::Base.timestamped_migrations
|
|
12
|
+
Time.new.utc.strftime("%Y%m%d%H%M%S")
|
|
13
|
+
else
|
|
14
|
+
"%.3d" % (current_migration_number(dirname) + 1)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def create_migration_file
|
|
19
|
+
self.submodules.each do |submodule|
|
|
20
|
+
migration_template "#{submodule}.rb", "db/migrate/sorcery_#{submodule}.rb"
|
|
21
|
+
sleep 1 # for the timestamp to change
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
class SorceryActivityLogging < ActiveRecord::Migration
|
|
2
|
+
def self.up
|
|
3
|
+
add_column :users, :last_login_at, :datetime, :default => nil
|
|
4
|
+
add_column :users, :last_logout_at, :datetime, :default => nil
|
|
5
|
+
add_column :users, :last_activity_at, :datetime, :default => nil
|
|
6
|
+
|
|
7
|
+
add_index :users, [:last_logout_at, :last_activity_at]
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def self.down
|
|
11
|
+
remove_index :users, [:last_logout_at, :last_activity_at]
|
|
12
|
+
|
|
13
|
+
remove_column :users, :last_activity_at
|
|
14
|
+
remove_column :users, :last_logout_at
|
|
15
|
+
remove_column :users, :last_login_at
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
class SorceryBruteForceProtection < ActiveRecord::Migration
|
|
2
|
+
def self.up
|
|
3
|
+
add_column :users, :failed_logins_count, :integer, :default => 0
|
|
4
|
+
add_column :users, :lock_expires_at, :datetime, :default => nil
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def self.down
|
|
8
|
+
remove_column :users, :lock_expires_at
|
|
9
|
+
remove_column :users, :failed_logins_count
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
class SorceryCore < ActiveRecord::Migration
|
|
2
|
+
def self.up
|
|
3
|
+
create_table :users do |t|
|
|
4
|
+
t.string :username, :null => false # if you use another filed as a username, for example email, you can safely remove this field.
|
|
5
|
+
t.string :email, :default => nil # if you use this field as a username, you might want to make it :null => false.
|
|
6
|
+
t.string :crypted_password, :default => nil
|
|
7
|
+
t.string :salt, :default => nil
|
|
8
|
+
|
|
9
|
+
t.timestamps
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.down
|
|
14
|
+
drop_table :users
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
class SorceryExternal < ActiveRecord::Migration
|
|
2
|
+
def self.up
|
|
3
|
+
create_table :authentications do |t|
|
|
4
|
+
t.integer :user_id, :null => false
|
|
5
|
+
t.string :provider, :uid, :null => false
|
|
6
|
+
|
|
7
|
+
t.timestamps
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.down
|
|
12
|
+
drop_table :authentications
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
class SorceryRememberMe < ActiveRecord::Migration
|
|
2
|
+
def self.up
|
|
3
|
+
add_column :users, :remember_me_token, :string, :default => nil
|
|
4
|
+
add_column :users, :remember_me_token_expires_at, :datetime, :default => nil
|
|
5
|
+
|
|
6
|
+
add_index :users, :remember_me_token
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def self.down
|
|
10
|
+
remove_index :users, :remember_me_token
|
|
11
|
+
|
|
12
|
+
remove_column :users, :remember_me_token_expires_at
|
|
13
|
+
remove_column :users, :remember_me_token
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
class SorceryResetPassword < ActiveRecord::Migration
|
|
2
|
+
def self.up
|
|
3
|
+
add_column :users, :reset_password_token, :string, :default => nil
|
|
4
|
+
add_column :users, :reset_password_token_expires_at, :datetime, :default => nil
|
|
5
|
+
add_column :users, :reset_password_email_sent_at, :datetime, :default => nil
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def self.down
|
|
9
|
+
remove_column :users, :reset_password_email_sent_at
|
|
10
|
+
remove_column :users, :reset_password_token_expires_at
|
|
11
|
+
remove_column :users, :reset_password_token
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
class SorceryUserActivation < ActiveRecord::Migration
|
|
2
|
+
def self.up
|
|
3
|
+
add_column :users, :activation_state, :string, :default => nil
|
|
4
|
+
add_column :users, :activation_token, :string, :default => nil
|
|
5
|
+
add_column :users, :activation_token_expires_at, :datetime, :default => nil
|
|
6
|
+
|
|
7
|
+
add_index :users, :activation_token
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def self.down
|
|
11
|
+
remove_index :users, :activation_token
|
|
12
|
+
|
|
13
|
+
remove_column :users, :activation_token_expires_at
|
|
14
|
+
remove_column :users, :activation_token
|
|
15
|
+
remove_column :users, :activation_state
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
module Sorcery
|
|
2
|
+
module Controller
|
|
3
|
+
module Adapters
|
|
4
|
+
# This module does the magic of translating Rails commands to Sinatra.
|
|
5
|
+
# This way the Rails code doesn't change, but it actually now calls Sinatra calls.
|
|
6
|
+
module Sinatra
|
|
7
|
+
def self.included(base)
|
|
8
|
+
base.class_eval do
|
|
9
|
+
class << self
|
|
10
|
+
# prepend a filter
|
|
11
|
+
def prepend_filter(type, path = nil, options = {}, &block)
|
|
12
|
+
return filters[type].unshift block unless path
|
|
13
|
+
path, options = //, path if path.respond_to?(:each_pair)
|
|
14
|
+
block, *arguments = compile!(type, path, block, options)
|
|
15
|
+
prepend_filter(type) do
|
|
16
|
+
process_route(*arguments) { instance_eval(&block) }
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def after_filter(filter)
|
|
21
|
+
after do
|
|
22
|
+
send(filter)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
::Sinatra::Request.class_eval do
|
|
29
|
+
def authorization
|
|
30
|
+
env['HTTP_AUTHORIZATION'] ||
|
|
31
|
+
env['X-HTTP_AUTHORIZATION'] ||
|
|
32
|
+
env['X_HTTP_AUTHORIZATION'] ||
|
|
33
|
+
env['REDIRECT_X_HTTP_AUTHORIZATION'] || nil
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
base.send(:include, InstanceMethods)
|
|
38
|
+
base.extend(ClassMethods)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
module InstanceMethods
|
|
42
|
+
def reset_session
|
|
43
|
+
session.clear
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def redirect_to(*args)
|
|
47
|
+
args.pop if args.last.is_a?(Hash)
|
|
48
|
+
redirect(*args)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def root_path
|
|
52
|
+
'/'
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
helpers do
|
|
56
|
+
def request_http_basic_authentication(realm)
|
|
57
|
+
response.header['WWW-Authenticate'] = %(Basic realm="#{realm}")
|
|
58
|
+
response.status = 401
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def authenticate_with_http_basic(&blk)
|
|
62
|
+
@auth ||= Rack::Auth::Basic::Request.new(request.env)
|
|
63
|
+
yield @auth.credentials if ( @auth.provided? && @auth.basic? && @auth.credentials )
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def cookies
|
|
68
|
+
@cookie_proxy ||= CookieProxy.new(request,response)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
class CookieProxy
|
|
73
|
+
def initialize(request,response)
|
|
74
|
+
@request = request
|
|
75
|
+
@response = response
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def [](key)
|
|
79
|
+
@request.cookies[key.to_s]
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def []=(key, value)
|
|
83
|
+
@response.set_cookie(key, value)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
module ClassMethods
|
|
88
|
+
def prepend_before_filter(filter)
|
|
89
|
+
prepend_filter(:before) do
|
|
90
|
+
send(filter)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require 'oauth'
|
|
2
|
+
module Sorcery
|
|
3
|
+
module Controller
|
|
4
|
+
module Submodules
|
|
5
|
+
module External
|
|
6
|
+
module Protocols
|
|
7
|
+
module Oauth1
|
|
8
|
+
def oauth_version
|
|
9
|
+
"1.0"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def get_request_token(token=nil,secret=nil)
|
|
13
|
+
return ::OAuth::RequestToken.new(get_consumer,token,secret) if token && secret
|
|
14
|
+
get_consumer.get_request_token(:oauth_callback => @callback_url)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def authorize_url(args)
|
|
18
|
+
get_request_token(args[:request_token],args[:request_token_secret]).authorize_url(:oauth_callback => @callback_url)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def get_access_token(args)
|
|
22
|
+
get_request_token(args[:request_token],args[:request_token_secret]).get_access_token(:oauth_verifier => args[:oauth_verifier])
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
protected
|
|
26
|
+
|
|
27
|
+
def get_consumer
|
|
28
|
+
::OAuth::Consumer.new(@key, @secret, :site => @site)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'oauth2'
|
|
2
|
+
module Sorcery
|
|
3
|
+
module Controller
|
|
4
|
+
module Submodules
|
|
5
|
+
module External
|
|
6
|
+
module Protocols
|
|
7
|
+
module Oauth2
|
|
8
|
+
def oauth_version
|
|
9
|
+
"2.0"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def authorize_url(*args)
|
|
13
|
+
client = ::OAuth2::Client.new(@key, @secret, :site => @site)
|
|
14
|
+
client.web_server.authorize_url(:redirect_uri => @callback_url, :scope => @scope)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def get_access_token(args)
|
|
18
|
+
client = ::OAuth2::Client.new(@key, @secret, :site => @site)
|
|
19
|
+
client.web_server.get_access_token(args[:code], :redirect_uri => @callback_url)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|