multi_auth 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 -%>
|