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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 65a58c9e0dbe816215f33e5daa86064c83a06185
4
- data.tar.gz: 276515d8c4cf3b4fcc96e6dd548400f362270d03
3
+ metadata.gz: 18370adb7c20520b5fe1a95290e6d0ebc387e26f
4
+ data.tar.gz: 83be7320485a4b859bd51ba040145baad8bfd597
5
5
  SHA512:
6
- metadata.gz: f85b9b1dd51400d5a52aa18f006e9c06bc8a5f5c91e1757bda195c323e6df33e8b9709b6d3fbd0586a94466154b2e1be388960b9741ed765251b76262ace07ef
7
- data.tar.gz: 4e8e0a69cb00fa91133f3c074517643c9affa4c6970edcc65609ec6d4e48e9540ab2055ea208640f8c54f0bfb2c4c4f0616a3e86087c2eb8c3f037301fe47814
6
+ metadata.gz: c83a3d37bebb80fe575e2961b4ba54c775cf2f9af45275d8f135417620b0e767255b85233ec542caf16d22f031c8b7491235d13dd6deccba1a47a8b5018ee94a
7
+ data.tar.gz: 2a0ed3ede21308c3870e038a4bdad28a8a041fe5777114b3f115996a1371b95da7a549f437b2bab9e88a5c984c0d85a25593b8f6c605ca4db1f221cd01a67311
checksums.yaml.gz.sig CHANGED
@@ -1,2 +1 @@
1
- �{k=��&53����Ђǃ��5�q^�<����}XyJ���#�F���:6��}��al���%i A��r�4�Kqs�
2
- �}��9s
1
+ +�MsVykGD�1�&UE�\�x5�N n���63ˋ �X�~\fTD���{PuWn%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
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014 [Red Alchemist](http://www.redalchemist.com).
1
+ Copyright (c) 2014 [Alchemists](http://www.alchemists.io).
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -2,9 +2,10 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/auther.png)](http://badge.fury.io/rb/auther)
4
4
  [![Code Climate GPA](https://codeclimate.com/github/bkuhlmann/auther.png)](https://codeclimate.com/github/bkuhlmann/auther)
5
+ [![Code Climate Coverage](https://codeclimate.com/github/bkuhlmann/auther/coverage.png)](https://codeclimate.com/github/bkuhlmann/auther)
5
6
  [![Gemnasium Status](https://gemnasium.com/bkuhlmann/auther.png)](https://gemnasium.com/bkuhlmann/auther)
6
7
  [![Travis CI Status](https://secure.travis-ci.org/bkuhlmann/auther.png)](http://travis-ci.org/bkuhlmann/auther)
7
- [![Coverage Status](https://coveralls.io/repos/bkuhlmann/auther/badge.png)](https://coveralls.io/r/bkuhlmann/auther)
8
+ [![Gittip](http://img.shields.io/gittip/bkuhlmann.svg)](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.redalchemist.com/gem-public.pem)
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
- Edit your routes.rb as follows:
56
+ Run the generator to configure and initialize your application:
56
57
 
57
- Rails.application.routes.draw do
58
- mount Auther::Engine => "/auther"
59
- get "/login", to: "auther/session#new"
60
- end
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
- Add a config/initializers/auther.rb to your application with the following content:
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
- login: "N3JzR213WlBISDZsMjJQNkRXbEVmYVczbVdnMHRYVHRud29lOWRCekp6ST0tLWpFMkROekUvWDBkOHZ4ZngxZHV6clE9PQ==--cd863c39991fa4bb9a35de918aa16da54514e331",
69
- password: "cHhFSStjRm9KbEYwK3ZJVlF2MmpTTWVVZU5acEdlejZsZEhjWFJoQWxKND0tLTE3cmpXZVBQdW5VUW1jK0ZSSDdLUnc9PQ==--f51171174fa77055540420f205e0dd9d499cfeb6",
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 purpose of each setting is as follows:
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
- * *login* - Required. The encrypted account login. For example, the above decrypts to: *test@test.com*.
83
- * *password* - Required. The encrypted account password. For example, the above decrypts to: *password*.
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
- * *success_url* - Optional. The URL to redirect to upon successful authorization. Success redirection works
113
+ * *authorized_url* - Optional. The URL to redirect to upon successful authorization. Authorized redirection works
86
114
  as follows (in the order defined):
87
- 0. The blacklisted path (if requested prior to authorization but now authorized).
88
- 0. The success URL (if defined and the blacklisted path wasn't requested).
89
- 0. The root path (if none of the above).
90
- * *auth_url* - Required. The URL to redirect to when enforcing authentication to a blacklisted path.
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
- # Usage
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
- To encrypt/decrypt account credentials, launch a rails console and type the following:
127
+ The routes can be customized as follows (installed, by default, via the install generator):
101
128
 
102
- # Best if more than 150 characters and gibberish to read. Must be the same as defined in auther settings.
103
- cipher = Auther::Cipher.new "vuKrwD9XWoYuv@s99?tR(9VqryiL,KV{W7wFnejUa4QcVBP+D{2rD4JfuD(mXgA=$tNK4Pfn#NeGs3o3TZ3CqNc^Qb"
104
-
105
- # Do this to encrypt an unecrypted value.
106
- cipher.encrypt "test@test.com"
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
- # Do this to decrypt an encrypted value.
109
- cipher.decrypt "N3JzR213WlBISDZsMjJQNkRXbEVmYVczbVdnMHRYVHRud29lOWRCekp6ST0tLWpFMkROekUvWDBkOHZ4ZngxZHV6clE9PQ==--cd863c39991fa4bb9a35de918aa16da54514e331"
135
+ ## Model
110
136
 
111
- # Customization
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
- ## Model
142
+ ## Presenter
114
143
 
115
- The [Auther::Account](app/models/auther/account.rb) is a plain old Ruby object that uses ActiveRecord validations
116
- to aid in form/credential validation. This model could potentially be replaced with a database-backed object
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
- ## Views
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 can be stylized by attaching new styles to the .authorization class (see
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($stdout) # Can be used to log to standard output.
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.redalchemist.com) at [Red Alchemist](http://www.redalchemist.com).
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 [Red Alchemist](http://www.redalchemist.com).
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[:auth_url]
4
+ redirect_to settings.auth_url
5
5
  end
6
6
 
7
7
  def new
8
- @account = Auther::Account.new
8
+ @account_presenter = Auther::Presenter::Account.new
9
9
  end
10
10
 
11
11
  def create
12
- if account.valid?
13
- store_credentials
14
- redirect_to redirect_url
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 account.name
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
- remove_credentials params[:name]
23
- redirect_to settings[:auth_url]
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 account
41
- account_params = params.fetch :account
42
- account_settings = find_account account_params.fetch(:name)
37
+ def load_title
38
+ @title = settings.title
39
+ end
43
40
 
44
- @account ||= Auther::Account.new name: account_params.fetch(:name),
45
- login: account_params.fetch(:login),
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 name_options
54
- @name_options = settings.fetch(:accounts).map do |account|
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 redirect_url
65
- session["auther_redirect_url"] || account.success_url || '/'
56
+ def authorized_url account_model
57
+ session["auther_redirect_url"] || account_model.authorized_url || '/'
66
58
  end
67
59
 
68
- def find_account name
69
- settings.fetch(:accounts).select { |account| account.fetch(:name) == name }.first
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 account.name
74
- session[keymaster.login_key] = account.secure_login
75
- session[keymaster.password_key] = account.secure_password
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 name
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,7 +1,7 @@
1
1
  class Auther::SessionController < Auther::BaseController
2
2
  layout "auther/auth"
3
3
  before_filter :load_title, :load_label
4
- before_filter :name_options, only: [:new, :create]
4
+ before_filter :load_account_options, only: [:new, :create]
5
5
 
6
6
  private
7
7
 
@@ -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, :login, :secure_login, :password, :secure_password, :paths, :success_url
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
- @login = options.fetch :login, nil
13
- @secure_login = options.fetch :secure_login, nil
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
- @secret = options.fetch :secret, nil
18
- @success_url = options.fetch :success_url, nil
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 = @account.errors.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 @account, as: :account, url: "/auther/session" do |form|
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, @account.errors.full_messages.first, class: "error") if login_error
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, @account.errors.full_messages.first, class: "error") if password_error
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, @name_options
37
+ = form.select :name, @account_options
38
38
 
39
39
  .row
40
40
  .small-8
data/lib/auther.rb CHANGED
@@ -1,6 +1,9 @@
1
1
  require "slim-rails"
2
+ require "auther/version"
3
+ require "auther/settings"
2
4
  require "auther/null_logger"
3
5
  require "auther/cipher"
6
+ require "auther/authenticator"
4
7
  require "auther/keymaster"
5
8
  require "auther/gatekeeper"
6
9
  require "auther/engine"
@@ -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
 
@@ -1,11 +1,12 @@
1
1
  module Auther
2
2
  class Gatekeeper
3
- attr_reader :application, :environment, :settings, :logger
3
+ attr_reader :application, :environment, :settings
4
4
 
5
- def initialize application, settings = []
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[:auth_url]
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.fetch(:accounts).detect { |account| account.fetch(:name) == account_name }
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.fetch(:secret)
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(:login)
93
- account_password = cipher.decrypt account.fetch(:password)
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.fetch :accounts
114
- all_blacklisted_paths = blacklisted_paths settings.fetch(:accounts)
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
@@ -1,3 +1,3 @@
1
1
  module Auther
2
- VERSION = "1.4.0"
2
+ VERSION = "2.0.0"
3
3
  end
@@ -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: 1.4.0
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-05-29 00:00:00.000000000 Z
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-remote
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: pry-rescue
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: rspec-rails
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: coveralls
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.2.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