Commit df2f3c3675d596abd61cbb44fdca02afce38f111

Authored by Nathan Broadbent
1 parent 9c3b6ba9
Exists in master and in 1 other branch production

Added an optional username field to User model. Mongo makes this easy without an…

…y need for migrations, and I made my implementation as unintrusive as possible. Some organizations (such as ours) will find the "username" field useful when implementing an alternative authentication strategy. (Default is off, and this is fully backwards compatible.)
@@ -100,11 +100,13 @@ for you. Checkout [Hoptoad](http://hoptoadapp.com) from the guys over at @@ -100,11 +100,13 @@ for you. Checkout [Hoptoad](http://hoptoadapp.com) from the guys over at
100 100
101 **Configuring LDAP authentication:** 101 **Configuring LDAP authentication:**
102 102
103 -Follow the instructions at https://github.com/cschiewek/devise_ldap_authenticatable 103 + 1. In `config/config.yml`, set `user_has_username` to `true`
  104 + 2. Follow the instructions at https://github.com/cschiewek/devise_ldap_authenticatable
  105 + to set up the devise_ldap_authenticatable gem.
104 106
105 -If you want to authenticate via `username`, add the following lines to `app/models/user.rb`: 107 + 3. If you are authenticating by `username`, you will need to set the user's email
  108 + after authentication. You can do this by adding the following lines to `app/models/user.rb`:
106 109
107 - field :username  
108 before_save :set_ldap_email 110 before_save :set_ldap_email
109 def set_ldap_email 111 def set_ldap_email
110 self.email = Devise::LdapAdapter.get_ldap_param(self.username, "mail") 112 self.email = Devise::LdapAdapter.get_ldap_param(self.username, "mail")
app/models/user.rb
@@ -19,6 +19,11 @@ class User @@ -19,6 +19,11 @@ class User
19 19
20 attr_protected :admin 20 attr_protected :admin
21 21
  22 + if Errbit::Config.user_has_username
  23 + field :username
  24 + validates_presence_of :username
  25 + end
  26 +
22 # Mongoid doesn't seem to currently support 27 # Mongoid doesn't seem to currently support
23 # referencing embedded documents 28 # referencing embedded documents
24 def watchers 29 def watchers
app/views/users/_fields.html.haml
@@ -3,7 +3,12 @@ @@ -3,7 +3,12 @@
3 .required 3 .required
4 = f.label :name 4 = f.label :name
5 = f.text_field :name 5 = f.text_field :name
6 - 6 +
  7 +- if Errbit::Config.user_has_username
  8 + .required
  9 + = f.label :username
  10 + = f.text_field :username
  11 +
7 .required 12 .required
8 = f.label :email 13 = f.label :email
9 = f.text_field :email 14 = f.text_field :email
@@ -11,11 +16,11 @@ @@ -11,11 +16,11 @@
11 .required 16 .required
12 = f.label 'Entries per page' 17 = f.label 'Entries per page'
13 = f.select :per_page, [10, 20, 30, 50, 75, 100] 18 = f.select :per_page, [10, 20, 30, 50, 75, 100]
14 - 19 +
15 .required 20 .required
16 = f.label :password 21 = f.label :password
17 = f.password_field :password 22 = f.password_field :password
18 - 23 +
19 .required 24 .required
20 = f.label :password_confirmation 25 = f.label :password_confirmation
21 = f.password_field :password_confirmation 26 = f.password_field :password_confirmation
@@ -23,4 +28,5 @@ @@ -23,4 +28,5 @@
23 - if current_user.admin? 28 - if current_user.admin?
24 .checkbox 29 .checkbox
25 = f.check_box :admin 30 = f.check_box :admin
26 - = f.label :admin, 'Admin?'  
27 \ No newline at end of file 31 \ No newline at end of file
  32 + = f.label :admin, 'Admin?'
  33 +
app/views/users/index.html.haml
@@ -6,13 +6,17 @@ @@ -6,13 +6,17 @@
6 %thead 6 %thead
7 %tr 7 %tr
8 %th Name 8 %th Name
  9 + - if Errbit::Config.user_has_username
  10 + %th Username
9 %th.main Email 11 %th.main Email
10 %th Admin? 12 %th Admin?
11 %tbody 13 %tbody
12 - @users.each do |user| 14 - @users.each do |user|
13 %tr 15 %tr
14 %td.nowrap= link_to user.name, user_path(user) 16 %td.nowrap= link_to user.name, user_path(user)
  17 + - if Errbit::Config.user_has_username
  18 + %td= user.username
15 %td= user.email 19 %td= user.email
16 %td= user.admin? ? 'Y' : 'N' 20 %td= user.admin? ? 'Y' : 'N'
17 = will_paginate @users, :previous_label => '« Previous', :next_label => 'Next »' 21 = will_paginate @users, :previous_label => '« Previous', :next_label => 'Next »'
18 -  
19 \ No newline at end of file 22 \ No newline at end of file
  23 +
app/views/users/show.html.haml
@@ -8,6 +8,10 @@ @@ -8,6 +8,10 @@
8 %tr 8 %tr
9 %th Email 9 %th Email
10 %td.main= @user.email 10 %td.main= @user.email
  11 + - if Errbit::Config.user_has_username
  12 + %tr
  13 + %th Username
  14 + %td.main= @user.username
11 %tr 15 %tr
12 %th Admin? 16 %th Admin?
13 %td= @user.admin? ? 'Y' : 'N' 17 %td= @user.admin? ? 'Y' : 'N'
config/config.example.yml
@@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
6 # be copied to shared/config on the server when 6 # be copied to shared/config on the server when
7 # `cap deploy:setup` is ran the first time. Be sure 7 # `cap deploy:setup` is ran the first time. Be sure
8 # to place production specific settings there 8 # to place production specific settings there
  9 +# You will need to restart the server after changing any settings.
9 10
10 # The host of your errbit server 11 # The host of your errbit server
11 host: errbit.example.com 12 host: errbit.example.com
@@ -26,3 +27,7 @@ email_at_notices: [1, 10, 100] @@ -26,3 +27,7 @@ email_at_notices: [1, 10, 100]
26 # Configure whether or not the user should be prompted before resolving an error. 27 # Configure whether or not the user should be prompted before resolving an error.
27 confirm_resolve_err: true 28 confirm_resolve_err: true
28 29
  30 +# Add an optional 'username' field to Users.
  31 +# Helpful if you want to plug in your own authentication strategy.
  32 +user_has_username: false
  33 +
config/initializers/devise.rb
@@ -20,7 +20,7 @@ Devise.setup do |config| @@ -20,7 +20,7 @@ Devise.setup do |config|
20 # authenticating an user, both parameters are required. Remember that those 20 # authenticating an user, both parameters are required. Remember that those
21 # parameters are used only when authenticating and not when retrieving from 21 # parameters are used only when authenticating and not when retrieving from
22 # session. If you need permissions, you should implement that in a before filter. 22 # session. If you need permissions, you should implement that in a before filter.
23 - # config.authentication_keys = [ :email ] 23 + config.authentication_keys = [ Errbit::Config.user_has_username ? :username : :email ]
24 24
25 # Tell if authentication through request.params is enabled. True by default. 25 # Tell if authentication through request.params is enabled. True by default.
26 # config.params_authenticatable = true 26 # config.params_authenticatable = true
@@ -140,3 +140,4 @@ Devise.setup do |config| @@ -140,3 +140,4 @@ Devise.setup do |config|
140 # manager.default_strategies(:scope => :user).unshift :twitter_oauth 140 # manager.default_strategies(:scope => :user).unshift :twitter_oauth
141 # end 141 # end
142 end 142 end
  143 +
config/initializers/overrides.rb
1 require Rails.root.join('lib/overrides/mongoid/relations/builder.rb') 1 require Rails.root.join('lib/overrides/mongoid/relations/builder.rb')
  2 +require Rails.root.join('lib/overrides/devise/failure_app.rb')
  3 +
config/locales/devise.en.yml
@@ -10,7 +10,10 @@ en: @@ -10,7 +10,10 @@ en:
10 unauthenticated: 'You need to sign in before continuing.' 10 unauthenticated: 'You need to sign in before continuing.'
11 unconfirmed: 'You have to confirm your account before continuing.' 11 unconfirmed: 'You have to confirm your account before continuing.'
12 locked: 'Your account is locked.' 12 locked: 'Your account is locked.'
13 - invalid: 'Invalid email or password.' 13 + invalid: 'Invalid login details.'
  14 + user:
  15 + email_invalid: 'Invalid email or password.'
  16 + username_invalid: 'Invalid username or password.'
14 invalid_token: 'Invalid authentication token.' 17 invalid_token: 'Invalid authentication token.'
15 timeout: 'Your session expired, please sign in again to continue.' 18 timeout: 'Your session expired, please sign in again to continue.'
16 inactive: 'Your account was not activated yet.' 19 inactive: 'Your account was not activated yet.'
@@ -37,3 +40,4 @@ en: @@ -37,3 +40,4 @@ en:
37 subject: 'Reset password instructions' 40 subject: 'Reset password instructions'
38 unlock_instructions: 41 unlock_instructions:
39 subject: 'Unlock Instructions' 42 subject: 'Unlock Instructions'
  43 +
@@ -2,10 +2,12 @@ puts "Seeding database" @@ -2,10 +2,12 @@ puts "Seeding database"
2 puts "-------------------------------" 2 puts "-------------------------------"
3 3
4 # Create an initial Admin User 4 # Create an initial Admin User
  5 +admin_username = "errbit"
5 admin_email = "errbit@#{Errbit::Config.host}" 6 admin_email = "errbit@#{Errbit::Config.host}"
6 admin_pass = 'password' 7 admin_pass = 'password'
7 8
8 puts "Creating an initial admin user:" 9 puts "Creating an initial admin user:"
  10 +puts "-- username: #{admin_username}" if Errbit::Config.user_has_username
9 puts "-- email: #{admin_email}" 11 puts "-- email: #{admin_email}"
10 puts "-- password: #{admin_pass}" 12 puts "-- password: #{admin_pass}"
11 puts "" 13 puts ""
@@ -16,6 +18,8 @@ user = User.where(:email => admin_email).first || User.new({ @@ -16,6 +18,8 @@ user = User.where(:email => admin_email).first || User.new({
16 :password => admin_pass, 18 :password => admin_pass,
17 :password_confirmation => admin_pass 19 :password_confirmation => admin_pass
18 }) 20 })
  21 +user.username = admin_username if Errbit::Config.user_has_username
19 22
20 user.admin = true 23 user.admin = true
21 user.save! 24 user.save!
  25 +
lib/overrides/devise/failure_app.rb 0 → 100644
@@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
  1 +Devise::FailureApp.class_eval do
  2 + protected
  3 + # Handles both 'email_invalid' and 'username_invalid' messages.
  4 + def i18n_message(default = nil)
  5 + message = warden.message || warden_options[:message] || default || :unauthenticated
  6 +
  7 + if message.is_a?(Symbol)
  8 + I18n.t(:"#{scope}.#{Devise.authentication_keys.first}_#{message}", :resource_name => scope,
  9 + :scope => "devise.failure", :default => [message, message.to_s])
  10 + else
  11 + message.to_s
  12 + end
  13 + end
  14 +end
  15 +