auther 1.4.0 → 2.0.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
- checksums.yaml.gz.sig +1 -2
- data.tar.gz.sig +0 -0
- data/LICENSE.md +1 -1
- data/README.md +90 -56
- data/app/controllers/auther/base_controller.rb +31 -39
- data/app/controllers/auther/session_controller.rb +1 -1
- data/app/models/auther/account.rb +8 -46
- data/app/presenters/auther/account.rb +19 -0
- data/app/views/auther/session/new.html.slim +5 -5
- data/lib/auther.rb +3 -0
- data/lib/auther/authenticator.rb +56 -0
- data/lib/auther/engine.rb +7 -0
- data/lib/auther/gatekeeper.rb +12 -11
- data/lib/auther/settings.rb +18 -0
- data/lib/auther/version.rb +1 -1
- data/lib/generators/auther/install/install_generator.rb +23 -0
- data/lib/generators/auther/templates/config/initializers/auther.rb +9 -0
- metadata +26 -7
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 18370adb7c20520b5fe1a95290e6d0ebc387e26f
|
4
|
+
data.tar.gz: 83be7320485a4b859bd51ba040145baad8bfd597
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c83a3d37bebb80fe575e2961b4ba54c775cf2f9af45275d8f135417620b0e767255b85233ec542caf16d22f031c8b7491235d13dd6deccba1a47a8b5018ee94a
|
7
|
+
data.tar.gz: 2a0ed3ede21308c3870e038a4bdad28a8a041fe5777114b3f115996a1371b95da7a549f437b2bab9e88a5c984c0d85a25593b8f6c605ca4db1f221cd01a67311
|
checksums.yaml.gz.sig
CHANGED
@@ -1,2 +1 @@
|
|
1
|
-
|
2
|
-
�}��9s
|
1
|
+
+�MsVykGD�1�&UE�\�x5�Nn���63ˋ �X�~\fTD���{PuW�n%3w�dEߕm���Hk�i�*��55_1�jԧ�PD5r���3o �.y���3(�8���W?wKx������C��A
|
data.tar.gz.sig
CHANGED
Binary file
|
data/LICENSE.md
CHANGED
data/README.md
CHANGED
@@ -2,9 +2,10 @@
|
|
2
2
|
|
3
3
|
[](http://badge.fury.io/rb/auther)
|
4
4
|
[](https://codeclimate.com/github/bkuhlmann/auther)
|
5
|
+
[](https://codeclimate.com/github/bkuhlmann/auther)
|
5
6
|
[](https://gemnasium.com/bkuhlmann/auther)
|
6
7
|
[](http://travis-ci.org/bkuhlmann/auther)
|
7
|
-
[](https://www.gittip.com/bkuhlmann)
|
8
9
|
|
9
10
|
Provides simple, form-based authentication for apps that need security but don't want to deal with the clunky UI
|
10
11
|
of HTTP Basic Authentication or something as heavyweight as [Devise](https://github.com/plataformatec/devise). It
|
@@ -22,9 +23,9 @@ making for a pleasent user experience.
|
|
22
23
|
* Multiple account support with account specific blacklisted paths.
|
23
24
|
* Auto-redirection to requested path (once credentials have been verified).
|
24
25
|
* Log filtering for account credentials (login and password).
|
25
|
-
* Customizable logger support.
|
26
26
|
* Customizable view support.
|
27
27
|
* Customizable controller support.
|
28
|
+
* Customizable logger support.
|
28
29
|
|
29
30
|
# Requirements
|
30
31
|
|
@@ -38,7 +39,7 @@ making for a pleasent user experience.
|
|
38
39
|
|
39
40
|
For a secure install, type the following from the command line (recommended):
|
40
41
|
|
41
|
-
gem cert --add <(curl -Ls http://www.
|
42
|
+
gem cert --add <(curl -Ls http://www.alchemists.io/gem-public.pem)
|
42
43
|
gem install auther --trust-policy MediumSecurity
|
43
44
|
|
44
45
|
NOTE: A HighSecurity trust policy would be best but MediumSecurity enables signed gem verification while
|
@@ -52,79 +53,106 @@ Add the following to your Gemfile:
|
|
52
53
|
|
53
54
|
gem "auther"
|
54
55
|
|
55
|
-
|
56
|
+
Run the generator to configure and initialize your application:
|
56
57
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
58
|
+
bin/rails generate auther:install
|
59
|
+
|
60
|
+
# Usage
|
61
|
+
|
62
|
+
Using the setup examples, from above, launch your Rails application and visit either of the following routes:
|
63
|
+
|
64
|
+
http://localhost:3000/login
|
65
|
+
http://localhost:3000/admin/example # Assumes this route exists. Will redirect to /login if not authorized.
|
66
|
+
|
67
|
+
Use the following credentials to login:
|
68
|
+
|
69
|
+
* Login: test@test.com
|
70
|
+
* Password: password
|
71
|
+
|
72
|
+
To encrypt/decrypt account credentials, launch a rails console and type the following:
|
61
73
|
|
62
|
-
|
74
|
+
# Best if more than 150 characters and gibberish to read. Must be the same as defined in auther settings.
|
75
|
+
cipher = Auther::Cipher.new "vuKrwD9XWoYuv@s99?tR(9VqryiL,KV{W7wFnejUa4QcVBP+D{2rD4JfuD(mXgA=$tNK4Pfn#NeGs3o3TZ3CqNc^Qb"
|
76
|
+
|
77
|
+
# Do this to encrypt an unecrypted value.
|
78
|
+
cipher.encrypt "test@test.com"
|
79
|
+
|
80
|
+
# Do this to decrypt an encrypted value.
|
81
|
+
cipher.decrypt "N3JzR213WlBISDZsMjJQNkRXbEVmYVczbVdnMHRYVHRud29lOWRCekp6ST0tLWpFMkROekUvWDBkOHZ4ZngxZHV6clE9PQ==--cd863c39991fa4bb9a35de918aa16da54514e331"
|
82
|
+
|
83
|
+
# Customization
|
84
|
+
|
85
|
+
## Initializer
|
86
|
+
|
87
|
+
The initializer (installed during setup) can be found here:
|
88
|
+
|
89
|
+
config/initializers/auther.rb
|
90
|
+
|
91
|
+
The initializer comes installed with the following settings:
|
63
92
|
|
64
93
|
Rails.application.config.auther_settings = {
|
65
94
|
secret: "vuKrwD9XWoYuv@s99?tR(9VqryiL,KV{W7wFnejUa4QcVBP+D{2rD4JfuD(mXgA=$tNK4Pfn#NeGs3o3TZ3CqNc^Qb",
|
66
95
|
accounts: [
|
67
96
|
name: "admin",
|
68
|
-
|
69
|
-
|
97
|
+
encrypted_login: "N3JzR213WlBISDZsMjJQNkRXbEVmYVczbVdnMHRYVHRud29lOWRCekp6ST0tLWpFMkROekUvWDBkOHZ4ZngxZHV6clE9PQ==--cd863c39991fa4bb9a35de918aa16da54514e331",
|
98
|
+
encrypted_password: "cHhFSStjRm9KbEYwK3ZJVlF2MmpTTWVVZU5acEdlejZsZEhjWFJoQWxKND0tLTE3cmpXZVBQdW5VUW1jK0ZSSDdLUnc9PQ==--f51171174fa77055540420f205e0dd9d499cfeb6",
|
70
99
|
paths: ["/admin"]
|
71
|
-
]
|
72
|
-
auth_url: "/login"
|
100
|
+
]
|
73
101
|
}
|
74
102
|
|
75
|
-
The
|
103
|
+
The initializer can be customized as follows:
|
76
104
|
|
77
105
|
* *title* - Optional. The HTML page title (as rendered within a browser tab). Default: "Authorization".
|
78
106
|
* *label* - Optional. The page label (what would appear above the form). Default: "Authorization".
|
79
107
|
* *secret* - Required. The secret passphrase used to encrypt/decrypt account credentials.
|
80
108
|
* *accounts* - Required. The array of accounts with different or similar access to the application.
|
81
109
|
* *name* - Required. The account name. The name that uniquely identifies each account.
|
82
|
-
* *
|
83
|
-
* *
|
110
|
+
* *encrypted_login* - Required. The encrypted account login. For example, the above decrypts to: *test@test.com*.
|
111
|
+
* *encrypted_password* - Required. The encrypted account password. For example, the above decrypts to: *password*.
|
84
112
|
* *paths* - Required. The array of blacklisted paths for which only this account has access to.
|
85
|
-
* *
|
113
|
+
* *authorized_url* - Optional. The URL to redirect to upon successful authorization. Authorized redirection works
|
86
114
|
as follows (in the order defined):
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
* *
|
115
|
+
0. The blacklisted path (if requested prior to authorization but now authorized).
|
116
|
+
0. The authorized URL (if defined and the blacklisted path wasn't requested).
|
117
|
+
0. The root path (if none of the above).
|
118
|
+
* *deauthorized_url* - Optional. The URL to redirect to upon successful deauthorization (i.e. logout). Deauthorized
|
119
|
+
redirections works as follows (in the order defined):
|
120
|
+
0. The deauthorized URL (if defined).
|
121
|
+
0. The auth URL.
|
122
|
+
* *auth_url* - Optional. The URL to redirect to when enforcing authentication. Default: “/login”.
|
91
123
|
* *logger* - Optional. The logger used to log path/account authorization messages. Default: Auther::NullLogger.
|
92
124
|
|
93
|
-
|
94
|
-
|
95
|
-
Using the setup examples, from above, launch your Rails application and visit either of the following routes:
|
96
|
-
|
97
|
-
http://localhost:3000/login
|
98
|
-
http://localhost:3000/admin # Will redirect to /login if not authorized.
|
125
|
+
## Routes
|
99
126
|
|
100
|
-
|
127
|
+
The routes can be customized as follows (installed, by default, via the install generator):
|
101
128
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
129
|
+
Rails.application.routes.draw do
|
130
|
+
mount Auther::Engine => "/auther"
|
131
|
+
get "/login", to: "auther/session#new", as: "login"
|
132
|
+
delete "/logout", to: "auther/session#destroy", as: "logout"
|
133
|
+
end
|
107
134
|
|
108
|
-
|
109
|
-
cipher.decrypt "N3JzR213WlBISDZsMjJQNkRXbEVmYVczbVdnMHRYVHRud29lOWRCekp6ST0tLWpFMkROekUvWDBkOHZ4ZngxZHV6clE9PQ==--cd863c39991fa4bb9a35de918aa16da54514e331"
|
135
|
+
## Model
|
110
136
|
|
111
|
-
|
137
|
+
The [Auther::Account](app/models/auther/account.rb) is a plain old Ruby object that uses ActiveModel validations to aid
|
138
|
+
in attribute validation. This model could potentially be replaced with a database-backed object (would require
|
139
|
+
controller customization)...but you might want to question if you have outgrown the use of this gem and need a different
|
140
|
+
solution altogether if it comes to that.
|
112
141
|
|
113
|
-
##
|
142
|
+
## Presenter
|
114
143
|
|
115
|
-
The [Auther::Account](app/
|
116
|
-
to aid in form
|
117
|
-
(would require controller customization)...but you might want to question if you have outgrown the use of this
|
118
|
-
gem and need a different solution altogether if it comes to that.
|
144
|
+
The [Auther::Presenter::Account](app/presenters/auther/account.rb) is a plain old Ruby object that uses ActiveModel
|
145
|
+
validations to aid in form validation. This presenter makes it easy to construct form data for input and validation.
|
119
146
|
|
120
|
-
##
|
147
|
+
## View
|
121
148
|
|
122
149
|
The view can be customized by creating the following file within your Rails application (assumes that the
|
123
150
|
default Auther::SessionController implementation is sufficient):
|
124
151
|
|
125
152
|
app/views/auther/session/new.html
|
126
153
|
|
127
|
-
The form
|
154
|
+
The form uses `@account_presenter` instance variable which is an instance of the Auther::Presenter::Account presenter
|
155
|
+
(as mentioned above). The form can be stylized by attaching new styles to the .authorization class (see
|
128
156
|
[auther.scss](app/assets/stylesheets/auther/auther.scss) for details).
|
129
157
|
|
130
158
|
## Controller
|
@@ -141,23 +169,21 @@ you add a controller to your app that inherits from the Auther::BaseController.
|
|
141
169
|
This allows complete customization of session controller behavior to serve any special business needs. See the
|
142
170
|
Auther::BaseController for additional details or the Auther::SessionController for default implementation.
|
143
171
|
|
144
|
-
## Routes
|
145
|
-
|
146
|
-
As mentioned in the setup above, the routes can be customized as follows:
|
147
|
-
|
148
|
-
Rails.application.routes.draw do
|
149
|
-
mount Auther::Engine => "/auther"
|
150
|
-
get "/login", to: "auther/session#new"
|
151
|
-
delete "/logout", to: "auther/session#destroy"
|
152
|
-
end
|
153
|
-
|
154
172
|
## Logging
|
155
173
|
|
156
174
|
As mentioned in the setup above, the logger can be customized as follows:
|
157
175
|
|
158
176
|
Auther::NullLogger.new # This is the default logger (which is no logging at all).
|
159
177
|
ActiveSupport::Logger.new("log/#{Rails.env}.log") # Can be used to log to the environment log.
|
160
|
-
Logger.new(
|
178
|
+
Logger.new(STDOUT) # Can be used to log to standard output.
|
179
|
+
|
180
|
+
When logging is enabled, you'll be able to see the following information in the server logs to help debug custom
|
181
|
+
Auther settings:
|
182
|
+
|
183
|
+
* Requested path and blacklist path detection.
|
184
|
+
* Finding (or not finding) of account.
|
185
|
+
* Account authentication pass/fail.
|
186
|
+
* Account and path authorization pass/fail.
|
161
187
|
|
162
188
|
# Tests
|
163
189
|
|
@@ -167,10 +193,18 @@ To test, do the following:
|
|
167
193
|
0. bundle install
|
168
194
|
0. bundle exec rspec spec
|
169
195
|
|
196
|
+
# Troubleshooting
|
197
|
+
|
198
|
+
* If upgrading Rails, changing the cookie/session settings, generating a new secret base key, etc. this might
|
199
|
+
cause Auther authentication to fail. Make sure to clear your browser cookies in this situation or use Google
|
200
|
+
Chrome (incognito mode) to verify.
|
201
|
+
|
170
202
|
# Resources
|
171
203
|
|
172
204
|
* [Simplest Auth](https://github.com/vigetlabs/simplest_auth) - For situations where you need user and email reset
|
173
205
|
support beyond what this engine can provide.
|
206
|
+
* [Devise](https://github.com/plataformatec/devise) - For complex situations where you need persisted user objects,
|
207
|
+
email support, social media support, and much more.
|
174
208
|
|
175
209
|
# Contributions
|
176
210
|
|
@@ -178,11 +212,11 @@ Read CONTRIBUTING for details.
|
|
178
212
|
|
179
213
|
# Credits
|
180
214
|
|
181
|
-
Developed by [Brooke Kuhlmann](http://www.
|
215
|
+
Developed by [Brooke Kuhlmann](http://www.alchemists.io) at [Alchemists](http://www.alchemists.io).
|
182
216
|
|
183
217
|
# License
|
184
218
|
|
185
|
-
Copyright (c) 2014 [
|
219
|
+
Copyright (c) 2014 [Alchemists](http://www.alchemists.io).
|
186
220
|
Read the LICENSE for details.
|
187
221
|
|
188
222
|
# History
|
@@ -1,57 +1,49 @@
|
|
1
1
|
module Auther
|
2
2
|
class BaseController < ActionController::Base
|
3
3
|
def show
|
4
|
-
redirect_to settings
|
4
|
+
redirect_to settings.auth_url
|
5
5
|
end
|
6
6
|
|
7
7
|
def new
|
8
|
-
@
|
8
|
+
@account_presenter = Auther::Presenter::Account.new
|
9
9
|
end
|
10
10
|
|
11
11
|
def create
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
@account_presenter = Auther::Presenter::Account.new params[:account]
|
13
|
+
account_model = Auther::Account.new settings.find_account(@account_presenter.name)
|
14
|
+
authenticator = Auther::Authenticator.new settings.secret, account_model, @account_presenter
|
15
|
+
|
16
|
+
if authenticator.authenticated?
|
17
|
+
store_credentials account_model
|
18
|
+
redirect_to authorized_url(account_model)
|
15
19
|
else
|
16
|
-
remove_credentials
|
20
|
+
remove_credentials account_model
|
17
21
|
render template: new_template_path
|
18
22
|
end
|
19
23
|
end
|
20
24
|
|
21
25
|
def destroy
|
22
|
-
|
23
|
-
|
26
|
+
account_model = Auther::Account.new settings.find_account(params[:name])
|
27
|
+
remove_credentials account_model
|
28
|
+
redirect_to deauthorized_url(account_model)
|
24
29
|
end
|
25
30
|
|
26
31
|
private
|
27
32
|
|
28
|
-
def load_title
|
29
|
-
@title = settings.fetch :title, "Authorization"
|
30
|
-
end
|
31
|
-
|
32
|
-
def load_label
|
33
|
-
@label = settings.fetch :label, "Authorization"
|
34
|
-
end
|
35
|
-
|
36
33
|
def settings
|
37
|
-
Rails.application.config.auther_settings
|
34
|
+
Auther::Settings.new Rails.application.config.auther_settings
|
38
35
|
end
|
39
36
|
|
40
|
-
def
|
41
|
-
|
42
|
-
|
37
|
+
def load_title
|
38
|
+
@title = settings.title
|
39
|
+
end
|
43
40
|
|
44
|
-
|
45
|
-
|
46
|
-
secure_login: account_settings.fetch(:login),
|
47
|
-
password: account_params.fetch(:password),
|
48
|
-
secure_password: account_settings.fetch(:password),
|
49
|
-
secret: settings.fetch(:secret),
|
50
|
-
success_url: account_settings.fetch(:success_url, nil)
|
41
|
+
def load_label
|
42
|
+
@label = settings.label
|
51
43
|
end
|
52
44
|
|
53
|
-
def
|
54
|
-
@
|
45
|
+
def load_account_options
|
46
|
+
@account_options = settings.accounts.map do |account|
|
55
47
|
name = account.fetch :name
|
56
48
|
[name.capitalize, name]
|
57
49
|
end
|
@@ -61,22 +53,22 @@ module Auther
|
|
61
53
|
raise NotImplementedError, "The method, #new_template_path, is not implemented."
|
62
54
|
end
|
63
55
|
|
64
|
-
def
|
65
|
-
session["auther_redirect_url"] ||
|
56
|
+
def authorized_url account_model
|
57
|
+
session["auther_redirect_url"] || account_model.authorized_url || '/'
|
66
58
|
end
|
67
59
|
|
68
|
-
def
|
69
|
-
|
60
|
+
def deauthorized_url account_model
|
61
|
+
account_model.deauthorized_url || settings.auth_url
|
70
62
|
end
|
71
63
|
|
72
|
-
def store_credentials
|
73
|
-
keymaster = Auther::Keymaster.new
|
74
|
-
session[keymaster.login_key] =
|
75
|
-
session[keymaster.password_key] =
|
64
|
+
def store_credentials account_model
|
65
|
+
keymaster = Auther::Keymaster.new account_model.name
|
66
|
+
session[keymaster.login_key] = account_model.encrypted_login
|
67
|
+
session[keymaster.password_key] = account_model.encrypted_password
|
76
68
|
end
|
77
69
|
|
78
|
-
def remove_credentials
|
79
|
-
keymaster = Auther::Keymaster.new name
|
70
|
+
def remove_credentials account_model
|
71
|
+
keymaster = Auther::Keymaster.new account_model.name
|
80
72
|
session.delete keymaster.login_key
|
81
73
|
session.delete keymaster.password_key
|
82
74
|
end
|
@@ -1,59 +1,21 @@
|
|
1
|
+
require "active_model"
|
2
|
+
|
1
3
|
module Auther
|
2
4
|
class Account
|
3
5
|
include ActiveModel::Validations
|
4
6
|
|
5
|
-
attr_accessor :name, :
|
7
|
+
attr_accessor :name, :encrypted_login, :encrypted_password, :paths, :authorized_url, :deauthorized_url
|
6
8
|
|
7
|
-
validates :name, presence: true
|
9
|
+
validates :name, :encrypted_login, :encrypted_password, presence: true
|
8
10
|
validates :paths, presence: {unless: lambda { |account| account.paths.is_a? Array }, message: "must be an array"}
|
9
11
|
|
10
12
|
def initialize options = {}
|
11
13
|
@name = options.fetch :name, nil
|
12
|
-
@
|
13
|
-
@
|
14
|
-
@password = options.fetch :password, nil
|
15
|
-
@secure_password = options.fetch :secure_password, nil
|
14
|
+
@encrypted_login = options.fetch :encrypted_login, nil
|
15
|
+
@encrypted_password = options.fetch :encrypted_password, nil
|
16
16
|
@paths = options.fetch :paths, []
|
17
|
-
@
|
18
|
-
@
|
19
|
-
end
|
20
|
-
|
21
|
-
def valid?
|
22
|
-
super && authorized_login? && authorized_password?
|
23
|
-
end
|
24
|
-
|
25
|
-
def invalid?
|
26
|
-
!valid?
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
def secret
|
32
|
-
@secret
|
33
|
-
end
|
34
|
-
|
35
|
-
def decrypt attribute
|
36
|
-
if attribute.present? && secret.present?
|
37
|
-
cipher = Auther::Cipher.new secret
|
38
|
-
cipher.decrypt attribute
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def authorized? attribute, secure_attribute, error_name
|
43
|
-
if attribute == decrypt(secure_attribute)
|
44
|
-
true
|
45
|
-
else
|
46
|
-
errors.add error_name, "is invalid"
|
47
|
-
false
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def authorized_login?
|
52
|
-
authorized? login, secure_login, "login"
|
53
|
-
end
|
54
|
-
|
55
|
-
def authorized_password?
|
56
|
-
authorized? password, secure_password, "password"
|
17
|
+
@authorized_url = options.fetch :authorized_url, nil
|
18
|
+
@deauthorized_url = options.fetch :deauthorized_url, nil
|
57
19
|
end
|
58
20
|
end
|
59
21
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "active_model"
|
2
|
+
|
3
|
+
module Auther
|
4
|
+
module Presenter
|
5
|
+
class Account
|
6
|
+
include ActiveModel::Validations
|
7
|
+
|
8
|
+
attr_accessor :name, :login, :password
|
9
|
+
|
10
|
+
validates :name, :login, :password, presence: true
|
11
|
+
|
12
|
+
def initialize options = {}
|
13
|
+
@name = options[:name]
|
14
|
+
@login = options[:login]
|
15
|
+
@password = options[:password]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
- content_for(:title) { @title }
|
2
2
|
|
3
|
-
- error_keys = @
|
3
|
+
- error_keys = @account_presenter.errors.keys
|
4
4
|
- login_error = error_keys.include?(:login)
|
5
5
|
- password_error = error_keys.include?(:password)
|
6
6
|
- name_error = error_keys.include?(:name)
|
7
7
|
|
8
8
|
.authorization
|
9
|
-
= form_for @
|
9
|
+
= form_for @account_presenter, as: :account, url: "/auther/session" do |form|
|
10
10
|
.small-12
|
11
11
|
.row
|
12
12
|
h1.authorization-label = @label
|
@@ -18,7 +18,7 @@
|
|
18
18
|
= form.label :login, "Login:", class: "inline right"
|
19
19
|
= content_tag :div, class: render_foundation_error(login_error, classes: %w(small-6 columns))
|
20
20
|
= form.text_field :login
|
21
|
-
= content_tag(:small, @
|
21
|
+
= content_tag(:small, @account_presenter.errors.full_messages.first, class: "error") if login_error
|
22
22
|
.row
|
23
23
|
.small-8
|
24
24
|
.row
|
@@ -26,7 +26,7 @@
|
|
26
26
|
= form.label :password, "Password:", class: "inline right"
|
27
27
|
= content_tag :div, class: render_foundation_error(password_error, classes: %w(small-6 columns))
|
28
28
|
= form.password_field :password
|
29
|
-
= content_tag(:small, @
|
29
|
+
= content_tag(:small, @account_presenter.errors.full_messages.first, class: "error") if password_error
|
30
30
|
|
31
31
|
.row
|
32
32
|
.small-8
|
@@ -34,7 +34,7 @@
|
|
34
34
|
.small-6.columns
|
35
35
|
= form.label :name, "Account:", class: "inline right"
|
36
36
|
.small-6.columns
|
37
|
-
= form.select :name, @
|
37
|
+
= form.select :name, @account_options
|
38
38
|
|
39
39
|
.row
|
40
40
|
.small-8
|
data/lib/auther.rb
CHANGED
@@ -0,0 +1,56 @@
|
|
1
|
+
module Auther
|
2
|
+
class Authenticator
|
3
|
+
|
4
|
+
attr_reader :logger
|
5
|
+
|
6
|
+
def initialize secret, account_model, account_presenter, logger = Auther::NullLogger.new(STDOUT)
|
7
|
+
@cipher = Auther::Cipher.new secret
|
8
|
+
@account_model = account_model
|
9
|
+
@account_presenter = account_presenter
|
10
|
+
@logger = logger
|
11
|
+
end
|
12
|
+
|
13
|
+
def authenticated?
|
14
|
+
account_model.valid? &&
|
15
|
+
account_presenter.valid? &&
|
16
|
+
authentic_name? &&
|
17
|
+
authentic_login? &&
|
18
|
+
authentic_password?
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
attr_reader :cipher, :account_model, :account_presenter
|
24
|
+
|
25
|
+
def log_info message
|
26
|
+
id = "[#{Auther::Keymaster.namespace}]"
|
27
|
+
logger.info [id, message].join(": ")
|
28
|
+
end
|
29
|
+
|
30
|
+
def authentic? encrypted_value, value, error_name
|
31
|
+
begin
|
32
|
+
if cipher.decrypt(encrypted_value) == value
|
33
|
+
true
|
34
|
+
else
|
35
|
+
account_presenter.errors.add error_name, "is invalid"
|
36
|
+
false
|
37
|
+
end
|
38
|
+
rescue ActiveSupport::MessageVerifier::InvalidSignature => error
|
39
|
+
log_info %(Authentication failed! Invalid credential(s) for "#{account_model.name}" account.)
|
40
|
+
false
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def authentic_name?
|
45
|
+
account_presenter.name == account_model.name
|
46
|
+
end
|
47
|
+
|
48
|
+
def authentic_login?
|
49
|
+
authentic? account_model.encrypted_login, account_presenter.login, "login"
|
50
|
+
end
|
51
|
+
|
52
|
+
def authentic_password?
|
53
|
+
authentic? account_model.encrypted_password, account_presenter.password, "password"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/auther/engine.rb
CHANGED
@@ -5,6 +5,13 @@ module Auther
|
|
5
5
|
# Set defaults. Can be overwritten in app config.
|
6
6
|
config.auther_settings = {}
|
7
7
|
|
8
|
+
# Autoload presenters
|
9
|
+
config.to_prepare do
|
10
|
+
Dir.glob(Engine.root + "app/presenters/**/*.rb").each do |presenter|
|
11
|
+
require_dependency presenter
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
8
15
|
initializer "auther.initialize" do |app|
|
9
16
|
asset_paths = app.config.assets.paths
|
10
17
|
|
data/lib/auther/gatekeeper.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
module Auther
|
2
2
|
class Gatekeeper
|
3
|
-
attr_reader :application, :environment, :settings
|
3
|
+
attr_reader :application, :environment, :settings
|
4
4
|
|
5
|
-
|
5
|
+
delegate :logger, to: :settings
|
6
|
+
|
7
|
+
def initialize application, settings = {}
|
6
8
|
@application = application
|
7
|
-
@settings = settings
|
8
|
-
@logger = @settings.fetch :logger, Auther::NullLogger.new(STDOUT)
|
9
|
+
@settings = Auther::Settings.new settings
|
9
10
|
end
|
10
11
|
|
11
12
|
def call environment
|
@@ -16,7 +17,7 @@ module Auther
|
|
16
17
|
else
|
17
18
|
session[Auther::Keymaster.redirect_url_key] = request.path
|
18
19
|
denied_response = response
|
19
|
-
denied_response.redirect settings
|
20
|
+
denied_response.redirect settings.auth_url
|
20
21
|
denied_response.finish
|
21
22
|
end
|
22
23
|
end
|
@@ -62,7 +63,7 @@ module Auther
|
|
62
63
|
def find_account
|
63
64
|
session["auther_init"] = true # Force session to initialize.
|
64
65
|
account_name = Auther::Keymaster.get_account_name session
|
65
|
-
account = settings.
|
66
|
+
account = settings.find_account account_name
|
66
67
|
|
67
68
|
account ? log_info("Account found.") : log_info("Account unknown.")
|
68
69
|
account
|
@@ -84,13 +85,13 @@ module Auther
|
|
84
85
|
|
85
86
|
def authenticated? account
|
86
87
|
keymaster = Auther::Keymaster.new account.fetch(:name)
|
87
|
-
cipher = Auther::Cipher.new settings.
|
88
|
+
cipher = Auther::Cipher.new settings.secret
|
88
89
|
|
89
90
|
begin
|
90
91
|
session_login = cipher.decrypt session[keymaster.login_key]
|
91
92
|
session_password = cipher.decrypt session[keymaster.password_key]
|
92
|
-
account_login = cipher.decrypt account.fetch(:
|
93
|
-
account_password = cipher.decrypt account.fetch(:
|
93
|
+
account_login = cipher.decrypt account.fetch(:encrypted_login)
|
94
|
+
account_password = cipher.decrypt account.fetch(:encrypted_password)
|
94
95
|
|
95
96
|
authenticated = session_login == account_login && session_password == account_password
|
96
97
|
log_authentication authenticated, account.fetch(:name)
|
@@ -110,8 +111,8 @@ module Auther
|
|
110
111
|
end
|
111
112
|
|
112
113
|
def authorized? path
|
113
|
-
accounts = settings.
|
114
|
-
all_blacklisted_paths = blacklisted_paths settings.
|
114
|
+
accounts = settings.accounts
|
115
|
+
all_blacklisted_paths = blacklisted_paths settings.accounts
|
115
116
|
|
116
117
|
if blacklisted_matched_paths(accounts, path).any?
|
117
118
|
log_info %(Requested path "#{request.path}" found in blacklisted paths: #{all_blacklisted_paths}.)
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Auther
|
2
|
+
class Settings
|
3
|
+
attr_reader :title, :label, :secret, :accounts, :auth_url, :logger
|
4
|
+
|
5
|
+
def initialize options = {}
|
6
|
+
@title = options.fetch :title, "Authorization"
|
7
|
+
@label = options.fetch :title, "Authorization"
|
8
|
+
@secret = options.fetch :secret, nil
|
9
|
+
@accounts = options.fetch :accounts, []
|
10
|
+
@auth_url = options.fetch :auth_url, "/login"
|
11
|
+
@logger = options.fetch :logger, Auther::NullLogger.new(STDOUT)
|
12
|
+
end
|
13
|
+
|
14
|
+
def find_account name
|
15
|
+
accounts.detect { |account| account.fetch(:name) == name }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/auther/version.rb
CHANGED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Auther
|
2
|
+
class InstallGenerator < ::Rails::Generators::Base
|
3
|
+
source_root File.join(File.dirname(__FILE__), "..", "templates")
|
4
|
+
|
5
|
+
desc "Installs Auther settings and routes."
|
6
|
+
def install
|
7
|
+
install_initializer
|
8
|
+
add_routes
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def install_initializer
|
14
|
+
template File.join("config", "initializers", "auther.rb"), File.join("config", "initializers", "auther.rb")
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_routes
|
18
|
+
route %(delete "/logout", to: "auther/session#destroy", as: "logout")
|
19
|
+
route %(get "/login", to: "auther/session#new", as: "login")
|
20
|
+
route %(mount Auther::Engine => "/auther")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
Rails.application.config.auther_settings = {
|
2
|
+
secret: "vuKrwD9XWoYuv@s99?tR(9VqryiL,KV{W7wFnejUa4QcVBP+D{2rD4JfuD(mXgA=$tNK4Pfn#NeGs3o3TZ3CqNc^Qb",
|
3
|
+
accounts: [
|
4
|
+
name: "admin",
|
5
|
+
encrypted_login: "N3JzR213WlBISDZsMjJQNkRXbEVmYVczbVdnMHRYVHRud29lOWRCekp6ST0tLWpFMkROekUvWDBkOHZ4ZngxZHV6clE9PQ==--cd863c39991fa4bb9a35de918aa16da54514e331",
|
6
|
+
encrypted_password: "cHhFSStjRm9KbEYwK3ZJVlF2MmpTTWVVZU5acEdlejZsZEhjWFJoQWxKND0tLTE3cmpXZVBQdW5VUW1jK0ZSSDdLUnc9PQ==--f51171174fa77055540420f205e0dd9d499cfeb6",
|
7
|
+
paths: ["/admin"]
|
8
|
+
]
|
9
|
+
}
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: auther
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brooke Kuhlmann
|
@@ -30,7 +30,7 @@ cert_chain:
|
|
30
30
|
SJpzzzZ8gO6BKn4fhd+ENNQ333Qy3nuNk07TVIaNnlgeHhowUDuD9T7Z8Lka0pt3
|
31
31
|
4PteiTppsf0SSVAM9zSO5IuFngXMRwWgvjOfXE70f43RDuUVTCSyylc=
|
32
32
|
-----END CERTIFICATE-----
|
33
|
-
date: 2014-
|
33
|
+
date: 2014-06-12 00:00:00.000000000 Z
|
34
34
|
dependencies:
|
35
35
|
- !ruby/object:Gem::Dependency
|
36
36
|
name: pry-byebug
|
@@ -160,6 +160,20 @@ dependencies:
|
|
160
160
|
version: '10.0'
|
161
161
|
- !ruby/object:Gem::Dependency
|
162
162
|
name: pry
|
163
|
+
requirement: !ruby/object:Gem::Requirement
|
164
|
+
requirements:
|
165
|
+
- - "~>"
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: 0.9.12
|
168
|
+
type: :development
|
169
|
+
prerelease: false
|
170
|
+
version_requirements: !ruby/object:Gem::Requirement
|
171
|
+
requirements:
|
172
|
+
- - "~>"
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
version: 0.9.12
|
175
|
+
- !ruby/object:Gem::Dependency
|
176
|
+
name: pry-remote
|
163
177
|
requirement: !ruby/object:Gem::Requirement
|
164
178
|
requirements:
|
165
179
|
- - ">="
|
@@ -173,7 +187,7 @@ dependencies:
|
|
173
187
|
- !ruby/object:Gem::Version
|
174
188
|
version: '0'
|
175
189
|
- !ruby/object:Gem::Dependency
|
176
|
-
name: pry-
|
190
|
+
name: pry-rescue
|
177
191
|
requirement: !ruby/object:Gem::Requirement
|
178
192
|
requirements:
|
179
193
|
- - ">="
|
@@ -187,7 +201,7 @@ dependencies:
|
|
187
201
|
- !ruby/object:Gem::Version
|
188
202
|
version: '0'
|
189
203
|
- !ruby/object:Gem::Dependency
|
190
|
-
name:
|
204
|
+
name: rspec-rails
|
191
205
|
requirement: !ruby/object:Gem::Requirement
|
192
206
|
requirements:
|
193
207
|
- - ">="
|
@@ -201,7 +215,7 @@ dependencies:
|
|
201
215
|
- !ruby/object:Gem::Version
|
202
216
|
version: '0'
|
203
217
|
- !ruby/object:Gem::Dependency
|
204
|
-
name:
|
218
|
+
name: ammeter
|
205
219
|
requirement: !ruby/object:Gem::Requirement
|
206
220
|
requirements:
|
207
221
|
- - ">="
|
@@ -243,7 +257,7 @@ dependencies:
|
|
243
257
|
- !ruby/object:Gem::Version
|
244
258
|
version: '0'
|
245
259
|
- !ruby/object:Gem::Dependency
|
246
|
-
name:
|
260
|
+
name: codeclimate-test-reporter
|
247
261
|
requirement: !ruby/object:Gem::Requirement
|
248
262
|
requirements:
|
249
263
|
- - ">="
|
@@ -276,17 +290,22 @@ files:
|
|
276
290
|
- app/controllers/auther/session_controller.rb
|
277
291
|
- app/helpers/auther/foundation_helper.rb
|
278
292
|
- app/models/auther/account.rb
|
293
|
+
- app/presenters/auther/account.rb
|
279
294
|
- app/views/auther/session/new.html.slim
|
280
295
|
- app/views/layouts/auther/auth.html.slim
|
281
296
|
- bin/rails
|
282
297
|
- config/routes.rb
|
283
298
|
- lib/auther.rb
|
299
|
+
- lib/auther/authenticator.rb
|
284
300
|
- lib/auther/cipher.rb
|
285
301
|
- lib/auther/engine.rb
|
286
302
|
- lib/auther/gatekeeper.rb
|
287
303
|
- lib/auther/keymaster.rb
|
288
304
|
- lib/auther/null_logger.rb
|
305
|
+
- lib/auther/settings.rb
|
289
306
|
- lib/auther/version.rb
|
307
|
+
- lib/generators/auther/install/install_generator.rb
|
308
|
+
- lib/generators/auther/templates/config/initializers/auther.rb
|
290
309
|
homepage: https://github.com/bkuhlmann/auther
|
291
310
|
licenses:
|
292
311
|
- MIT
|
@@ -307,7 +326,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
307
326
|
version: '0'
|
308
327
|
requirements: []
|
309
328
|
rubyforge_project:
|
310
|
-
rubygems_version: 2.
|
329
|
+
rubygems_version: 2.3.0
|
311
330
|
signing_key:
|
312
331
|
specification_version: 4
|
313
332
|
summary: Enhances Rails with multi-account, form-based, database-less, application-wide
|
metadata.gz.sig
CHANGED
Binary file
|