multi_auth 0.1.0 → 0.2.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.
Files changed (34) hide show
  1. data/README +11 -0
  2. data/app/controllers/auth/name_controller.rb +31 -0
  3. data/app/controllers/credentials/email_controller.rb +3 -3
  4. data/app/controllers/credentials/name_controller.rb +93 -0
  5. data/app/controllers/credentials_controller.rb +6 -4
  6. data/app/models/name_credential.rb +63 -0
  7. data/app/models/name_credential_edit_form.rb +40 -0
  8. data/app/models/name_login_form.rb +14 -0
  9. data/app/models/{email_password_edit_form.rb → password_edit_form.rb} +5 -13
  10. data/app/views/auth/name/index.html.erb +89 -0
  11. data/app/views/credentials/index.html.erb +46 -0
  12. data/app/views/credentials/name/delete.html.erb +19 -0
  13. data/app/views/credentials/name/edit_password.html.erb +27 -0
  14. data/app/views/credentials/name/new.html.erb +32 -0
  15. data/config/routes.rb +8 -0
  16. data/db/development.sqlite3 +0 -0
  17. data/db/schema.rb +13 -1
  18. data/db/test.sqlite3 +0 -0
  19. data/generators/multi_auth_migration/templates/migration.rb +13 -0
  20. data/generators/multi_auth_migration/templates/upgrade_migration.rb +19 -0
  21. data/generators/multi_auth_migration/upgrade_multi_auth_tables_generator.rb +11 -0
  22. data/lib/multi_auth.rb +1 -0
  23. data/lib/multi_auth/active_record.rb +1 -0
  24. data/locale/ja/LC_MESSAGES/multi_auth.mo +0 -0
  25. data/po/ja/multi_auth.po +357 -259
  26. data/po/multi_auth.pot +309 -215
  27. data/test/functional/auth/name_controller_test.rb +77 -0
  28. data/test/functional/credentials/email_controller_test.rb +3 -4
  29. data/test/functional/credentials/name_controller_test.rb +292 -0
  30. data/test/unit/name_credential_edit_form_test.rb +151 -0
  31. data/test/unit/name_credential_test.rb +173 -0
  32. data/test/unit/name_login_form_test.rb +68 -0
  33. data/test/unit/{email_password_edit_form_test.rb → password_edit_form_test.rb} +7 -6
  34. metadata +22 -6
data/README CHANGED
@@ -54,6 +54,15 @@ You can use default style sheet and icons.
54
54
 
55
55
  $ ruby script/generate multi_auth_public_assets
56
56
 
57
+ Upgrade
58
+ =======
59
+
60
+ $ ruby script/generate multi_auth_migration upgrade_multi_auth_tables
61
+
62
+ Create migrations for multi_auth. Just add a table for NameCredential.
63
+
64
+ $ rake db:migrate
65
+
57
66
 
58
67
  Settings
59
68
  ========
@@ -67,6 +76,8 @@ Ex.
67
76
  s.from_address = 'yourname@example.com'
68
77
  s.user_model = 'YourUserModel'
69
78
  s.session_times_out_in = 1.hour
79
+ # if false do not display in credentials index
80
+ s.credentials = { :open_id => true, :email => true, :name => true }
70
81
  end
71
82
 
72
83
  You can use OpenID::CustomFetcher to use OpenID provider which uses SSL.
@@ -0,0 +1,31 @@
1
+ class Auth::NameController < ApplicationController
2
+ filter_parameter_logging :password
3
+ verify_method_post :only => [:login]
4
+
5
+ # GET /auth/name
6
+ def index
7
+ session[:user_id] = nil
8
+ @login_form = NameLoginForm.new
9
+ end
10
+
11
+ # POST /auth/name/login
12
+ def login
13
+ session[:user_id] = nil
14
+ @login_form = NameLoginForm.new(params[:login_form])
15
+
16
+ if @login_form.valid?
17
+ @name_credential = @login_form.authenticate
18
+ end
19
+
20
+ if @name_credential
21
+ @name_credential.login!
22
+ @login_user = @name_credential.user
23
+ session[:user_id] = @login_user.id
24
+ redirect_to(:controller => "/auth", :action => "logged_in")
25
+ else
26
+ @login_form.password = nil
27
+ set_error_now(p_("MultiAuth", "The name or the password is wrong."))
28
+ render(:action => "index")
29
+ end
30
+ end
31
+ end
@@ -55,14 +55,14 @@ class Credentials::EmailController < ApplicationController
55
55
 
56
56
  # GET /credential/email/:email_credential_id/edit_password
57
57
  def edit_password
58
- @edit_form = EmailPasswordEditForm.new
58
+ @edit_form = PasswordEditForm.new
59
59
  end
60
60
 
61
61
  # POST /credential/email/:email_credential_id/update_password
62
62
  def update_password
63
- @edit_form = EmailPasswordEditForm.new(params[:edit_form])
63
+ @edit_form = PasswordEditForm.new(params[:edit_form])
64
64
 
65
- @email_credential.attributes = @edit_form.to_email_credential_hash
65
+ @email_credential.attributes = @edit_form.to_credential_hash
66
66
 
67
67
  if @edit_form.valid? && @email_credential.save
68
68
  set_notice(p_("MultiAuth", "Password was changed."))
@@ -0,0 +1,93 @@
1
+ # -*- coding: utf-8 -*-
2
+ class Credentials::NameController < ApplicationController
3
+
4
+ verify_method_post :only => [:create, :update_password, :destroy, :activate]
5
+ before_filter :authentication
6
+ before_filter :authentication_required
7
+ before_filter :required_param_name_credential_id, :only => [:edit_password, :update_password, :delete, :destroy]
8
+ before_filter :specified_name_credential_belongs_to_login_user, :only => [:edit_password, :update_password, :delete, :destroy]
9
+
10
+ # GET /credentials/name/new
11
+ def new
12
+ @edit_form = NameCredentialEditForm.new
13
+ end
14
+
15
+ # POST /credentials/name/create
16
+ def create
17
+ @edit_form = NameCredentialEditForm.new(params[:edit_form])
18
+
19
+ @name_credential = @login_user.name_credentials.build
20
+ @name_credential.attributes = @edit_form.to_name_credential_hash
21
+
22
+ if @edit_form.valid? && @name_credential.save
23
+ # メール送信はしない
24
+ set_notice(p_("MultiAuth", "Name authentication credential was successfully added."))
25
+ redirect_to(credentials_path)
26
+ else
27
+ @edit_form.password = nil
28
+ @edit_form.password_confirmation = nil
29
+ set_error_now(p_("MultiAuth", "Please confirm your input."))
30
+ render(:action => "new")
31
+ end
32
+ end
33
+
34
+ # GET /credential/name/:name_credential_id/edit_password
35
+ def edit_password
36
+ @edit_form = PasswordEditForm.new
37
+ end
38
+
39
+ # POST /credential/name/:name_credential_id/update_password
40
+ def update_password
41
+ @edit_form = PasswordEditForm.new(params[:edit_form])
42
+
43
+ @name_credential.attributes = @edit_form.to_credential_hash
44
+
45
+ if @edit_form.valid? && @name_credential.save
46
+ set_notice(p_("MultiAuth", "Password was changed."))
47
+ redirect_to(:controller => "/credentials")
48
+ else
49
+ @edit_form.password = nil
50
+ @edit_form.password_confirmation = nil
51
+ set_error_now(p_("MultiAuth", "Please confirm your input."))
52
+ render(:action => "edit_password")
53
+ end
54
+ end
55
+
56
+ # GET /credential/name/:name_credential_id/delete
57
+ def delete
58
+ # nop
59
+ end
60
+
61
+ # POST /credential/email/:email_credential_id/destroy
62
+ def destroy
63
+ @name_credential.destroy
64
+
65
+ set_notice(p_("MultiAuth", "Name authentication credential was successfully deleted."))
66
+ redirect_to(:controller => "/credentials")
67
+ end
68
+
69
+ private
70
+
71
+ # FIXME: login_userに属することを同時に確認
72
+ def required_param_name_credential_id(name_credential_id = params[:name_credential_id])
73
+ @name_credential = NameCredential.find_by_id(name_credential_id)
74
+ if @name_credential
75
+ return true
76
+ else
77
+ set_error(p_("MultiAuth", "It is invalid name authentication credential."))
78
+ redirect_to(root_path)
79
+ return false
80
+ end
81
+ end
82
+
83
+ def specified_name_credential_belongs_to_login_user
84
+ if @name_credential.user_id == @login_user.id
85
+ return true
86
+ else
87
+ set_error(p_("MultiAuth", "It is invalid name authentication credential."))
88
+ redirect_to(root_path)
89
+ return false
90
+ end
91
+ end
92
+
93
+ end
@@ -1,3 +1,4 @@
1
+ # -*- coding: utf-8 -*-
1
2
 
2
3
  # 認証情報コントローラ
3
4
  class CredentialsController < ApplicationController
@@ -6,9 +7,10 @@ class CredentialsController < ApplicationController
6
7
 
7
8
  # GET /credentials
8
9
  def index
9
- @open_id_credentials = @login_user.open_id_credentials.all(
10
- :order => "open_id_credentials.identity_url ASC")
11
- @email_credentials = @login_user.email_credentials.all(
12
- :order => "email_credentials.email ASC")
10
+ @open_id_credentials =
11
+ @login_user.open_id_credentials.all(:order => "open_id_credentials.identity_url ASC")
12
+ @email_credentials =
13
+ @login_user.email_credentials.all(:order => "email_credentials.email ASC")
14
+ @name_credentials = @login_user.name_credentials.all(:order => "name_credentials.name ASC")
13
15
  end
14
16
  end
@@ -0,0 +1,63 @@
1
+ # -*- coding: utf-8 -*-
2
+ class NameCredential < ActiveRecord::Base
3
+
4
+ untranslate :created_at, :user_id, :hashed_password
5
+
6
+ NameMaximumLength = 200
7
+ HashedPasswordPattern = /\A([0-9a-f]{8}):([0-9a-f]{64})\z/
8
+ MaximumRecordsPerUser = 10
9
+
10
+ belongs_to :user, :class_name => MultiAuth.user_model, :foreign_key => 'user_id'
11
+
12
+ validates_presence_of :name
13
+ validates_presence_of :hashed_password
14
+ validates_length_of :name, :maximum => NameMaximumLength, :allow_nil => true
15
+ validates_format_of :hashed_password, :with => HashedPasswordPattern, :allow_nil => true
16
+ validates_uniqueness_of :name
17
+ validates_each(:user_id, :on => :create) { |record, attr, value|
18
+ if record.user && record.user.name_credentials(true).size >= MaximumRecordsPerUser
19
+ record.errors.add(attr, "これ以上%{fn}に#{_(record.class.to_s.downcase)}を追加できません。")
20
+ end
21
+ }
22
+
23
+ def self.create_hashed_password(password)
24
+ salt = 8.times.map { rand(16).to_s(16) }.join
25
+ return salt + ":" + Digest::SHA256.hexdigest(salt + ":" + password)
26
+ end
27
+
28
+ def self.compare_hashed_password(password, hashed_password)
29
+ return false unless HashedPasswordPattern =~ hashed_password
30
+ salt, digest = $1, $2
31
+ return (Digest::SHA256.hexdigest(salt + ":" + password) == digest)
32
+ end
33
+
34
+ def self.authenticate(name, password)
35
+ credential = self.find_by_name(name)
36
+ return nil unless credential
37
+ return nil unless credential.authenticated?(password)
38
+ return credential
39
+ end
40
+
41
+ def authenticated?(password)
42
+ return false unless self.class.compare_hashed_password(password, self.hashed_password)
43
+ return false unless self.activated?
44
+ return true
45
+ end
46
+
47
+ def activated?
48
+ true
49
+ end
50
+
51
+ def activate!
52
+ true
53
+ end
54
+
55
+ def login!
56
+ self.update_attributes!(:loggedin_at => Time.now)
57
+ end
58
+
59
+ def to_label
60
+ name
61
+ end
62
+
63
+ end
@@ -0,0 +1,40 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ class NameCredentialEditForm < ActiveForm
4
+ PasswordLengthRange = 4..20
5
+ PasswordPattern = /\A[\x21-\x7E]+\z/
6
+
7
+ column :name, :type => :text
8
+ column :password, :type => :text
9
+ column :password_confirmation, :type => :text
10
+
11
+ N_("NameCredentialEditForm|Name")
12
+ N_("NameCredentialEditForm|Password")
13
+ N_("NameCredentialEditForm|Password confirmation")
14
+
15
+ validates_presence_of :name
16
+ validates_presence_of :password
17
+ validates_presence_of :password_confirmation
18
+ validates_length_of :name, :maximum => ::NameCredential::NameMaximumLength, :allow_nil => true
19
+ validates_length_of :password, :in => PasswordLengthRange, :allow_nil => true
20
+ validates_format_of :password, :with => PasswordPattern, :allow_nil => true
21
+ validates_each(:password) { |record, attr, value|
22
+ # MEMO: validates_confirmation_of は password_confirmation 属性を上書きしてしまうため、
23
+ # ここでは使用できない。そのため、validates_confirmation_of を参考に独自に実装。
24
+ confirmation = record.__send__("#{attr}_confirmation")
25
+ if confirmation.blank? || value != confirmation
26
+ record.errors.add(attr, :confirmation)
27
+ end
28
+ }
29
+
30
+ def masked_password
31
+ return self.password.to_s.gsub(/./, "*")
32
+ end
33
+
34
+ def to_name_credential_hash
35
+ return {
36
+ :name => self.name,
37
+ :hashed_password => NameCredential.create_hashed_password(self.password.to_s),
38
+ }
39
+ end
40
+ end
@@ -0,0 +1,14 @@
1
+ class NameLoginForm < ActiveForm
2
+ column :name, :type => :text
3
+ column :password, :type => :text
4
+
5
+ N_("NameLoginForm|Name")
6
+ N_("NameLoginForm|Password")
7
+
8
+ validates_presence_of :name
9
+ validates_presence_of :password
10
+
11
+ def authenticate
12
+ NameCredential.authenticate(self.name, self.password)
13
+ end
14
+ end
@@ -1,14 +1,6 @@
1
- # == Schema Information
2
- # Schema version: 20090529051529
3
- #
4
- # Table name: active_forms
5
- #
6
- # password :text
7
- # password_confirmation :text
8
- #
1
+ # -*- coding: utf-8 -*-
9
2
 
10
- # メール認証情報パスワード編集フォーム
11
- class EmailPasswordEditForm < ActiveForm
3
+ class PasswordEditForm < ActiveForm
12
4
  column :password, :type => :text
13
5
  column :password_confirmation, :type => :text
14
6
 
@@ -17,8 +9,8 @@ class EmailPasswordEditForm < ActiveForm
17
9
 
18
10
  validates_presence_of :password
19
11
  validates_presence_of :password_confirmation
20
- validates_length_of :password, :in => EmailCredentialEditForm::PasswordLengthRange, :allow_nil => true
21
- validates_format_of :password, :with => EmailCredentialEditForm::PasswordPattern, :allow_nil => true
12
+ validates_length_of :password, :in => ::EmailCredentialEditForm::PasswordLengthRange, :allow_nil => true
13
+ validates_format_of :password, :with => ::EmailCredentialEditForm::PasswordPattern, :allow_nil => true
22
14
  validates_each(:password) { |record, attr, value|
23
15
  # MEMO: validates_confirmation_ofはpassword_confirmation属性を上書きしてしまうため、
24
16
  # ここでは使用できない。そのため、validates_confirmation_ofを参考に独自に実装。
@@ -28,7 +20,7 @@ class EmailPasswordEditForm < ActiveForm
28
20
  end
29
21
  }
30
22
 
31
- def to_email_credential_hash
23
+ def to_credential_hash
32
24
  return {
33
25
  :hashed_password => EmailCredential.create_hashed_password(self.password.to_s),
34
26
  }
@@ -0,0 +1,89 @@
1
+ <%- @title = p_("MultiAuth", "Login") -%>
2
+ <%- @enable_side_column = false -%>
3
+
4
+ <%- additional_head { -%>
5
+ <style type="text/css">
6
+ #dialog
7
+ {
8
+ margin: 100px auto;
9
+ padding: 15px;
10
+ width: 400px;
11
+ border-width: 1px;
12
+ border-style: solid;
13
+ border-color: #CCCCCC;
14
+ }
15
+ #dialog h1
16
+ {
17
+ margin: 0 0 0.4em 0;
18
+ color: #666666;
19
+ font-size: 130%;
20
+ font-weight: bold;
21
+ }
22
+
23
+ table#name-login
24
+ {
25
+ margin: 0 auto;
26
+ border-collapse: collapse;
27
+ border-width: 0px;
28
+ }
29
+
30
+ table#name-login th,
31
+ table#name-login td
32
+ {
33
+ padding: 5px;
34
+ border-width: 0px;
35
+ }
36
+
37
+ table#name-login th
38
+ {
39
+ text-align: right;
40
+ font-size: 95%;
41
+ font-weight: bold;
42
+ vertical-align: top;
43
+ color: #666666;
44
+ }
45
+ table#name-login td
46
+ {
47
+ color: #333333;
48
+ }
49
+
50
+ div.fieldWithErrors label
51
+ {
52
+ color: #990000;
53
+ }
54
+ div.formError
55
+ {
56
+ font-size: 80%;
57
+ color: #990000;
58
+ }
59
+ </style>
60
+ <%- } -%>
61
+
62
+ <div id="dialog">
63
+ <h1><%=h p_("MultiAuth", "Login") %></h1>
64
+ <%- form_for(:login_form, @login_form, :url => {:action => "login"}) do |f| -%>
65
+ <table id="name-login">
66
+ <tr>
67
+ <th><%= f.label(:name) %></th>
68
+ <td>
69
+ <%= f.text_field(:name, :size => 30) %>
70
+ <%= error_message_on(:login_form, :name) %>
71
+ </td>
72
+ </tr>
73
+ <tr>
74
+ <th><%= f.label(:password) %></th>
75
+ <td>
76
+ <%= f.password_field(:password, :size => 30) %>
77
+ <%= error_message_on(:login_form, :password) %>
78
+ </td>
79
+ </tr>
80
+ </table>
81
+ <%= submit_tag(p_("MultiAuth", "Login")) %>
82
+ <%- end -%>
83
+ </div>
84
+
85
+ <%- unless production? -%>
86
+ <div class="debug">
87
+ <%= error_messages_for(:login_form) %>
88
+ </div>
89
+ <%- end -%>
@@ -1,6 +1,7 @@
1
1
 
2
2
  <%- @title = p_("MultiAuth", "Login setting") -%>
3
3
 
4
+ <%- if MultiAuth.credentials[:open_id] -%>
4
5
  <h2><%=h p_("MultiAuth", "OpenID authentication") %></h2>
5
6
 
6
7
  <table class="list">
@@ -39,7 +40,9 @@
39
40
  <%- end -%>
40
41
  </tbody>
41
42
  </table>
43
+ <%- end -%>
42
44
 
45
+ <%- if MultiAuth.credentials[:email] -%>
43
46
  <h2><%=h p_("MultiAuth", "Email address authentication") %></h2>
44
47
 
45
48
  <table class="list">
@@ -84,3 +87,46 @@
84
87
  <%- end -%>
85
88
  </tbody>
86
89
  </table>
90
+ <%- end -%>
91
+
92
+ <%- if MultiAuth.credentials[:name] -%>
93
+ <h2><%=h p_("MultiAuth", "Name authentication") %></h2>
94
+
95
+ <table class="list">
96
+ <thead>
97
+ <tr>
98
+ <th><%=h s_("NameCredential|Loggedin at") %></th>
99
+ <th><%=h s_("NameCredential|Name") %></th>
100
+ <th colspan="2">&nbsp;</th>
101
+ </tr>
102
+ </thead>
103
+ <tfoot>
104
+ <tr>
105
+ <td colspan="4">
106
+ <%- can_add_name_credential = (@name_credentials.size < NameCredential::MaximumRecordsPerUser) -%>
107
+ <%= link_to_if(can_add_name_credential, add_icon + h(" " + p_("MultiAuth", "Add name authentication")), :controller => "credentials/name", :action => "new") %>
108
+ </td>
109
+ </tr>
110
+ </tfoot>
111
+ <tbody>
112
+ <%- if @name_credentials.empty? -%>
113
+ <tr>
114
+ <td colspan="4" style="padding: 1em;">
115
+ <%=h p_("MultiAuth", "There are no name authentication.") %>
116
+ </td>
117
+ </tr>
118
+ <%- else -%>
119
+ <%- @name_credentials.each_with_index do |name_credential, index| -%>
120
+ <tr class="<%= even_or_odd(index) %>">
121
+ <td><%=h yyyymmdd_hhmm(name_credential.loggedin_at) %></td>
122
+ <td>
123
+ <div style="font-family: monospace;"><%= name_credential.name %></div>
124
+ </td>
125
+ <td><%= link_to(icon16("icons/fam/key.png", p_("MultiAuth", "Update password")) + h(" " + p_("MultiAuth", "Update password")), :controller => "credentials/name", :action => "edit_password", :name_credential_id => name_credential.id) %></td>
126
+ <td><%= link_to(delete_icon + h(" " + p_("MultiAuth", "Delete")), :controller => "credentials/name", :action => "delete", :name_credential_id => name_credential.id) %></td>
127
+ </tr>
128
+ <%- end -%>
129
+ <% end -%>
130
+ </tbody>
131
+ </table>
132
+ <%- end -%>