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.
- data/README +11 -0
- data/app/controllers/auth/name_controller.rb +31 -0
- data/app/controllers/credentials/email_controller.rb +3 -3
- data/app/controllers/credentials/name_controller.rb +93 -0
- data/app/controllers/credentials_controller.rb +6 -4
- data/app/models/name_credential.rb +63 -0
- data/app/models/name_credential_edit_form.rb +40 -0
- data/app/models/name_login_form.rb +14 -0
- data/app/models/{email_password_edit_form.rb → password_edit_form.rb} +5 -13
- data/app/views/auth/name/index.html.erb +89 -0
- data/app/views/credentials/index.html.erb +46 -0
- data/app/views/credentials/name/delete.html.erb +19 -0
- data/app/views/credentials/name/edit_password.html.erb +27 -0
- data/app/views/credentials/name/new.html.erb +32 -0
- data/config/routes.rb +8 -0
- data/db/development.sqlite3 +0 -0
- data/db/schema.rb +13 -1
- data/db/test.sqlite3 +0 -0
- data/generators/multi_auth_migration/templates/migration.rb +13 -0
- data/generators/multi_auth_migration/templates/upgrade_migration.rb +19 -0
- data/generators/multi_auth_migration/upgrade_multi_auth_tables_generator.rb +11 -0
- data/lib/multi_auth.rb +1 -0
- data/lib/multi_auth/active_record.rb +1 -0
- data/locale/ja/LC_MESSAGES/multi_auth.mo +0 -0
- data/po/ja/multi_auth.po +357 -259
- data/po/multi_auth.pot +309 -215
- data/test/functional/auth/name_controller_test.rb +77 -0
- data/test/functional/credentials/email_controller_test.rb +3 -4
- data/test/functional/credentials/name_controller_test.rb +292 -0
- data/test/unit/name_credential_edit_form_test.rb +151 -0
- data/test/unit/name_credential_test.rb +173 -0
- data/test/unit/name_login_form_test.rb +68 -0
- data/test/unit/{email_password_edit_form_test.rb → password_edit_form_test.rb} +7 -6
- 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 =
|
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 =
|
63
|
+
@edit_form = PasswordEditForm.new(params[:edit_form])
|
64
64
|
|
65
|
-
@email_credential.attributes = @edit_form.
|
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 =
|
10
|
-
:order => "open_id_credentials.identity_url ASC")
|
11
|
-
@email_credentials =
|
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
|
-
#
|
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
|
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"> </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 -%>
|