multi_auth 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +36 -0
- data/app/controllers/application_controller.rb +11 -0
- data/app/controllers/auth/email_controller.rb +34 -0
- data/app/controllers/auth/open_id_controller.rb +43 -0
- data/app/controllers/auth_controller.rb +24 -0
- data/app/controllers/credentials/email_controller.rb +156 -0
- data/app/controllers/credentials/open_id_controller.rb +85 -0
- data/app/controllers/credentials_controller.rb +14 -0
- data/app/controllers/signup/email_controller.rb +132 -0
- data/app/controllers/signup/open_id_controller.rb +62 -0
- data/app/controllers/signup_controller.rb +8 -0
- data/app/helpers/application_helper.rb +5 -0
- data/app/models/activation_mailer.rb +114 -0
- data/app/models/email_credential.rb +89 -0
- data/app/models/email_credential_edit_form.rb +52 -0
- data/app/models/email_login_form.rb +24 -0
- data/app/models/email_password_edit_form.rb +36 -0
- data/app/models/open_id_credential.rb +33 -0
- data/app/models/open_id_login_form.rb +17 -0
- data/app/models/session.rb +19 -0
- data/app/models/user.rb +37 -0
- data/app/views/activation_mailer/complete_for_credential.erb +4 -0
- data/app/views/activation_mailer/complete_for_notice.erb +4 -0
- data/app/views/activation_mailer/complete_for_signup.erb +4 -0
- data/app/views/activation_mailer/request_for_credential.erb +11 -0
- data/app/views/activation_mailer/request_for_notice.erb +11 -0
- data/app/views/activation_mailer/request_for_signup.erb +11 -0
- data/app/views/auth/email/index.html.erb +90 -0
- data/app/views/auth/logged_in.html.erb +21 -0
- data/app/views/auth/logged_out.html.erb +21 -0
- data/app/views/auth/open_id/index.html.erb +16 -0
- data/app/views/credentials/email/activated.html.erb +4 -0
- data/app/views/credentials/email/activation.html.erb +15 -0
- data/app/views/credentials/email/created.html.erb +15 -0
- data/app/views/credentials/email/delete.html.erb +20 -0
- data/app/views/credentials/email/edit_password.html.erb +31 -0
- data/app/views/credentials/email/new.html.erb +36 -0
- data/app/views/credentials/index.html.erb +88 -0
- data/app/views/credentials/open_id/delete.html.erb +20 -0
- data/app/views/credentials/open_id/new.html.erb +26 -0
- data/app/views/signup/email/_progress.html.erb +14 -0
- data/app/views/signup/email/activated.html.erb +9 -0
- data/app/views/signup/email/activation.html.erb +27 -0
- data/app/views/signup/email/created.html.erb +14 -0
- data/app/views/signup/email/index.html.erb +34 -0
- data/app/views/signup/email/validated.html.erb +21 -0
- data/app/views/signup/index.html.erb +51 -0
- data/app/views/signup/open_id/authenticated.html.erb +15 -0
- data/app/views/signup/open_id/created.html.erb +6 -0
- data/app/views/signup/open_id/index.html.erb +16 -0
- data/config/boot.rb +110 -0
- data/config/database.yml +22 -0
- data/config/database.yml.sqlite3 +22 -0
- data/config/environment.rb +62 -0
- data/config/routes.rb +51 -0
- data/config/smtp.yml.example +8 -0
- data/db/development.sqlite3 +0 -0
- data/db/schema.rb +88 -0
- data/db/test.sqlite3 +0 -0
- data/lib/action_mailer_util.rb +15 -0
- data/lib/multi_auth.rb +64 -0
- data/lib/multi_auth_helper.rb +98 -0
- data/lib/notice_formatter.rb +106 -0
- data/lib/open_id_authentication/result.rb +12 -0
- data/lib/token_util.rb +18 -0
- data/public/404.html +92 -0
- data/public/422.html +91 -0
- data/public/500.html +92 -0
- data/public/503.html +92 -0
- data/public/favicon.ico +0 -0
- data/public/images/battery/cell.png +0 -0
- data/public/images/battery/level-green.png +0 -0
- data/public/images/battery/level-orange.png +0 -0
- data/public/images/battery/level-red.png +0 -0
- data/public/images/battery/level-yellow.png +0 -0
- data/public/images/battery/style.html +82 -0
- data/public/images/favicons/livedoor.png +0 -0
- data/public/images/favicons/mixi.png +0 -0
- data/public/images/favicons/yahoo.png +0 -0
- data/public/images/h1-back.png +0 -0
- data/public/images/icons/fam/add.png +0 -0
- data/public/images/icons/fam/bin.png +0 -0
- data/public/images/icons/fam/bomb.png +0 -0
- data/public/images/icons/fam/cog.png +0 -0
- data/public/images/icons/fam/delete.png +0 -0
- data/public/images/icons/fam/email-with-desc.png +0 -0
- data/public/images/icons/fam/email.png +0 -0
- data/public/images/icons/fam/feed.png +0 -0
- data/public/images/icons/fam/help.png +0 -0
- data/public/images/icons/fam/key-with-desc.png +0 -0
- data/public/images/icons/fam/key.png +0 -0
- data/public/images/icons/fam/lightning.png +0 -0
- data/public/images/icons/fam/plugin.png +0 -0
- data/public/images/icons/fam/stop.png +0 -0
- data/public/images/icons/fam/table_save.png +0 -0
- data/public/images/icons/fam/tick.png +0 -0
- data/public/images/icons/fam/user.png +0 -0
- data/public/images/icons/fam/vcard.png +0 -0
- data/public/images/icons/openid-with-desc.png +0 -0
- data/public/images/icons/openid.png +0 -0
- data/public/images/logo-back.png +0 -0
- data/public/images/logo.png +0 -0
- data/public/images/side-column-back.png +0 -0
- data/public/javascripts/application.js +2 -0
- data/public/javascripts/controls.js +963 -0
- data/public/javascripts/dragdrop.js +973 -0
- data/public/javascripts/effects.js +1128 -0
- data/public/javascripts/prototype.js +4320 -0
- data/public/robots.txt +5 -0
- data/public/stylesheets/application.css +365 -0
- data/public/stylesheets/auth.css +22 -0
- data/public/stylesheets/home.css +114 -0
- data/rails/init.rb +24 -0
- data/test/functional/auth/email_controller_test.rb +102 -0
- data/test/functional/auth/open_id_controller_test.rb +76 -0
- data/test/functional/auth_controller_test.rb +74 -0
- data/test/functional/credentials/email_controller_test.rb +488 -0
- data/test/functional/credentials/open_id_controller_test.rb +308 -0
- data/test/functional/credentials_controller_test.rb +49 -0
- data/test/functional/signup/email_controller_test.rb +369 -0
- data/test/functional/signup/open_id_controller_test.rb +44 -0
- data/test/functional/signup_controller_test.rb +17 -0
- data/test/performance/browsing_test.rb +9 -0
- data/test/test_helper.rb +82 -0
- data/test/unit/action_mailer_util_test.rb +63 -0
- data/test/unit/activation_mailer_test.rb +181 -0
- data/test/unit/email_credential_edit_form_test.rb +173 -0
- data/test/unit/email_credential_test.rb +324 -0
- data/test/unit/email_login_form_test.rb +76 -0
- data/test/unit/email_password_edit_form_test.rb +117 -0
- data/test/unit/helpers/auth_helper_test.rb +4 -0
- data/test/unit/helpers/credentials/email_helper_test.rb +4 -0
- data/test/unit/helpers/credentials/open_id_helper_test.rb +4 -0
- data/test/unit/helpers/credentials_helper_test.rb +4 -0
- data/test/unit/helpers/email_auth_helper_test.rb +4 -0
- data/test/unit/helpers/email_signup_helper_test.rb +4 -0
- data/test/unit/helpers/open_id_auth_helper_test.rb +4 -0
- data/test/unit/helpers/open_id_signup_helper_test.rb +4 -0
- data/test/unit/helpers/password_auth_helper_test.rb +4 -0
- data/test/unit/helpers/password_signup_helper_test.rb +4 -0
- data/test/unit/helpers/signup_helper_test.rb +4 -0
- data/test/unit/notice_formatter_test.rb +153 -0
- data/test/unit/open_id_credential_test.rb +108 -0
- data/test/unit/open_id_login_form_test.rb +57 -0
- data/test/unit/session_test.rb +53 -0
- data/test/unit/token_util_test.rb +51 -0
- data/test/unit/user_test.rb +177 -0
- metadata +220 -0
@@ -0,0 +1,114 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
# アクティベーションメーラ
|
4
|
+
class ActivationMailer < ActionMailer::Base
|
5
|
+
include ActionMailerUtil
|
6
|
+
|
7
|
+
SubjectPrefix = "[#{MultiAuth.application_name}] "
|
8
|
+
FromAddress = MultiAuth.from_address
|
9
|
+
|
10
|
+
def self.create_request_for_signup_params(options)
|
11
|
+
options = options.dup
|
12
|
+
recipients = options.delete(:recipients) || raise(ArgumentError)
|
13
|
+
activation_url = options.delete(:activation_url) || raise(ArgumentError)
|
14
|
+
raise(ArgumentError) unless options.empty?
|
15
|
+
|
16
|
+
return {
|
17
|
+
:subject => SubjectPrefix + "ユーザ登録",
|
18
|
+
:from => FromAddress,
|
19
|
+
:recipients => recipients,
|
20
|
+
:body => {:activation_url => activation_url},
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.create_complete_for_signup_params(options)
|
25
|
+
options = options.dup
|
26
|
+
recipients = options.delete(:recipients) || raise(ArgumentError)
|
27
|
+
raise(ArgumentError) unless options.empty?
|
28
|
+
|
29
|
+
return {
|
30
|
+
:subject => SubjectPrefix + "ユーザ登録完了",
|
31
|
+
:from => FromAddress,
|
32
|
+
:recipients => recipients,
|
33
|
+
:body => {},
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.create_request_for_credential_params(options)
|
38
|
+
options = options.dup
|
39
|
+
recipients = options.delete(:recipients) || raise(ArgumentError)
|
40
|
+
activation_url = options.delete(:activation_url) || raise(ArgumentError)
|
41
|
+
raise(ArgumentError) unless options.empty?
|
42
|
+
|
43
|
+
return {
|
44
|
+
:subject => SubjectPrefix + "メールアドレス認証登録",
|
45
|
+
:from => FromAddress,
|
46
|
+
:recipients => recipients,
|
47
|
+
:body => {:activation_url => activation_url},
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.create_complete_for_credential_params(options)
|
52
|
+
options = options.dup
|
53
|
+
recipients = options.delete(:recipients) || raise(ArgumentError)
|
54
|
+
raise(ArgumentError) unless options.empty?
|
55
|
+
|
56
|
+
return {
|
57
|
+
:subject => SubjectPrefix + "メールアドレス認証登録完了",
|
58
|
+
:from => FromAddress,
|
59
|
+
:recipients => recipients,
|
60
|
+
:body => {},
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.create_request_for_notice_params(options)
|
65
|
+
options = options.dup
|
66
|
+
recipients = options.delete(:recipients) || raise(ArgumentError)
|
67
|
+
activation_url = options.delete(:activation_url) || raise(ArgumentError)
|
68
|
+
raise(ArgumentError) unless options.empty?
|
69
|
+
|
70
|
+
return {
|
71
|
+
:subject => SubjectPrefix + "通知先メールアドレス登録",
|
72
|
+
:from => FromAddress,
|
73
|
+
:recipients => recipients,
|
74
|
+
:body => {:activation_url => activation_url},
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.create_complete_for_notice_params(options)
|
79
|
+
options = options.dup
|
80
|
+
recipients = options.delete(:recipients) || raise(ArgumentError)
|
81
|
+
raise(ArgumentError) unless options.empty?
|
82
|
+
|
83
|
+
return {
|
84
|
+
:subject => SubjectPrefix + "通知先メールアドレス登録完了",
|
85
|
+
:from => FromAddress,
|
86
|
+
:recipients => recipients,
|
87
|
+
:body => {},
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
def request_for_signup(options)
|
92
|
+
build_message(self.class.create_request_for_signup_params(options))
|
93
|
+
end
|
94
|
+
|
95
|
+
def complete_for_signup(options)
|
96
|
+
build_message(self.class.create_complete_for_signup_params(options))
|
97
|
+
end
|
98
|
+
|
99
|
+
def request_for_credential(options)
|
100
|
+
build_message(self.class.create_request_for_credential_params(options))
|
101
|
+
end
|
102
|
+
|
103
|
+
def complete_for_credential(options)
|
104
|
+
build_message(self.class.create_complete_for_credential_params(options))
|
105
|
+
end
|
106
|
+
|
107
|
+
def request_for_notice(options)
|
108
|
+
build_message(self.class.create_request_for_notice_params(options))
|
109
|
+
end
|
110
|
+
|
111
|
+
def complete_for_notice(options)
|
112
|
+
build_message(self.class.create_complete_for_notice_params(options))
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# == Schema Information
|
3
|
+
# Schema version: 20090529051529
|
4
|
+
#
|
5
|
+
# Table name: email_credentials
|
6
|
+
#
|
7
|
+
# id :integer not null, primary key
|
8
|
+
# created_at :datetime not null, index_email_credentials_on_created_at
|
9
|
+
# activation_token :string(40) not null, index_email_credentials_on_activation_token(unique)
|
10
|
+
# user_id :integer not null, index_email_credentials_on_user_id
|
11
|
+
# email :string(200) not null, index_email_credentials_on_email(unique)
|
12
|
+
# hashed_password :string(73) not null
|
13
|
+
# activated_at :datetime index_email_credentials_on_activated_at
|
14
|
+
# loggedin_at :datetime
|
15
|
+
#
|
16
|
+
|
17
|
+
# メール認証情報
|
18
|
+
class EmailCredential < ActiveRecord::Base
|
19
|
+
EmailMaximumLength = 200
|
20
|
+
TokenLength = 20
|
21
|
+
TokenPattern = TokenUtil.create_token_regexp(TokenLength)
|
22
|
+
HashedPasswordPattern = /\A([0-9a-f]{8}):([0-9a-f]{64})\z/
|
23
|
+
MaximumRecordsPerUser = 10
|
24
|
+
|
25
|
+
belongs_to :user
|
26
|
+
|
27
|
+
validates_presence_of :email
|
28
|
+
validates_presence_of :activation_token
|
29
|
+
validates_presence_of :hashed_password
|
30
|
+
validates_length_of :email, :maximum => EmailMaximumLength, :allow_nil => true
|
31
|
+
validates_format_of :activation_token, :with => TokenPattern, :allow_nil => true
|
32
|
+
validates_format_of :hashed_password, :with => HashedPasswordPattern, :allow_nil => true
|
33
|
+
validates_email_format_of :email,
|
34
|
+
:message => "%{fn}は有効なメールアドレスではありません。"
|
35
|
+
validates_uniqueness_of :email
|
36
|
+
validates_each(:user_id, :on => :create) { |record, attr, value|
|
37
|
+
if record.user && record.user.email_credentials(true).size >= MaximumRecordsPerUser
|
38
|
+
record.errors.add(attr, "これ以上%{fn}に#{_(record.class.to_s.downcase)}を追加できません。")
|
39
|
+
end
|
40
|
+
}
|
41
|
+
|
42
|
+
before_validation_on_create { |record|
|
43
|
+
if record.activation_token.blank?
|
44
|
+
record.activation_token = record.class.create_unique_activation_token
|
45
|
+
end
|
46
|
+
}
|
47
|
+
|
48
|
+
def self.create_unique_activation_token
|
49
|
+
return TokenUtil.create_unique_token(self, :activation_token, TokenLength)
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.create_hashed_password(password)
|
53
|
+
salt = 8.times.map { rand(16).to_s(16) }.join
|
54
|
+
return salt + ":" + Digest::SHA256.hexdigest(salt + ":" + password)
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.compare_hashed_password(password, hashed_password)
|
58
|
+
return false unless HashedPasswordPattern =~ hashed_password
|
59
|
+
salt, digest = $1, $2
|
60
|
+
return (Digest::SHA256.hexdigest(salt + ":" + password) == digest)
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.authenticate(email, password)
|
64
|
+
credential = self.find_by_email(email)
|
65
|
+
return nil unless credential
|
66
|
+
return nil unless credential.authenticated?(password)
|
67
|
+
return credential
|
68
|
+
end
|
69
|
+
|
70
|
+
def authenticated?(password)
|
71
|
+
return false unless self.class.compare_hashed_password(password, self.hashed_password)
|
72
|
+
return false unless self.activated?
|
73
|
+
return true
|
74
|
+
end
|
75
|
+
|
76
|
+
def activated?
|
77
|
+
return !self.activated_at.nil?
|
78
|
+
end
|
79
|
+
|
80
|
+
def activate!
|
81
|
+
return false if self.activated?
|
82
|
+
self.update_attributes!(:activated_at => Time.now)
|
83
|
+
return true
|
84
|
+
end
|
85
|
+
|
86
|
+
def login!
|
87
|
+
self.update_attributes!(:loggedin_at => Time.now)
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# == Schema Information
|
3
|
+
# Schema version: 20090529051529
|
4
|
+
#
|
5
|
+
# Table name: active_forms
|
6
|
+
#
|
7
|
+
# email :text
|
8
|
+
# password :text
|
9
|
+
# password_confirmation :text
|
10
|
+
#
|
11
|
+
|
12
|
+
# メール認証情報編集フォーム
|
13
|
+
class EmailCredentialEditForm < ActiveForm
|
14
|
+
PasswordLengthRange = 4..20
|
15
|
+
PasswordPattern = /\A[\x21-\x7E]+\z/
|
16
|
+
|
17
|
+
column :email, :type => :text
|
18
|
+
column :password, :type => :text
|
19
|
+
column :password_confirmation, :type => :text
|
20
|
+
|
21
|
+
N_("EmailCredentialEditForm|Email")
|
22
|
+
N_("EmailCredentialEditForm|Password")
|
23
|
+
N_("EmailCredentialEditForm|Password confirmation")
|
24
|
+
|
25
|
+
validates_presence_of :email
|
26
|
+
validates_presence_of :password
|
27
|
+
validates_presence_of :password_confirmation
|
28
|
+
validates_length_of :email, :maximum => EmailCredential::EmailMaximumLength, :allow_nil => true
|
29
|
+
validates_length_of :password, :in => PasswordLengthRange, :allow_nil => true
|
30
|
+
validates_format_of :password, :with => PasswordPattern, :allow_nil => true
|
31
|
+
validates_email_format_of :email,
|
32
|
+
:message => "%{fn}は有効なメールアドレスではありません。"
|
33
|
+
validates_each(:password) { |record, attr, value|
|
34
|
+
# MEMO: validates_confirmation_ofはpassword_confirmation属性を上書きしてしまうため、
|
35
|
+
# ここでは使用できない。そのため、validates_confirmation_ofを参考に独自に実装。
|
36
|
+
confirmation = record.__send__("#{attr}_confirmation")
|
37
|
+
if confirmation.blank? || value != confirmation
|
38
|
+
record.errors.add(attr, :confirmation)
|
39
|
+
end
|
40
|
+
}
|
41
|
+
|
42
|
+
def masked_password
|
43
|
+
return self.password.to_s.gsub(/./, "*")
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_email_credential_hash
|
47
|
+
return {
|
48
|
+
:email => self.email,
|
49
|
+
:hashed_password => EmailCredential.create_hashed_password(self.password.to_s),
|
50
|
+
}
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# == Schema Information
|
2
|
+
# Schema version: 20090529051529
|
3
|
+
#
|
4
|
+
# Table name: active_forms
|
5
|
+
#
|
6
|
+
# email :text
|
7
|
+
# password :text
|
8
|
+
#
|
9
|
+
|
10
|
+
# メールログインフォーム
|
11
|
+
class EmailLoginForm < ActiveForm
|
12
|
+
column :email, :type => :text
|
13
|
+
column :password, :type => :text
|
14
|
+
|
15
|
+
N_("EmailLoginForm|Email")
|
16
|
+
N_("EmailLoginForm|Password")
|
17
|
+
|
18
|
+
validates_presence_of :email
|
19
|
+
validates_presence_of :password
|
20
|
+
|
21
|
+
def authenticate
|
22
|
+
return EmailCredential.authenticate(self.email, self.password)
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# == Schema Information
|
2
|
+
# Schema version: 20090529051529
|
3
|
+
#
|
4
|
+
# Table name: active_forms
|
5
|
+
#
|
6
|
+
# password :text
|
7
|
+
# password_confirmation :text
|
8
|
+
#
|
9
|
+
|
10
|
+
# メール認証情報パスワード編集フォーム
|
11
|
+
class EmailPasswordEditForm < ActiveForm
|
12
|
+
column :password, :type => :text
|
13
|
+
column :password_confirmation, :type => :text
|
14
|
+
|
15
|
+
N_("EmailPasswordEditForm|Password")
|
16
|
+
N_("EmailPasswordEditForm|Password confirmation")
|
17
|
+
|
18
|
+
validates_presence_of :password
|
19
|
+
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
|
22
|
+
validates_each(:password) { |record, attr, value|
|
23
|
+
# MEMO: validates_confirmation_ofはpassword_confirmation属性を上書きしてしまうため、
|
24
|
+
# ここでは使用できない。そのため、validates_confirmation_ofを参考に独自に実装。
|
25
|
+
confirmation = record.__send__("#{attr}_confirmation")
|
26
|
+
if confirmation.blank? || value != confirmation
|
27
|
+
record.errors.add(attr, :confirmation)
|
28
|
+
end
|
29
|
+
}
|
30
|
+
|
31
|
+
def to_email_credential_hash
|
32
|
+
return {
|
33
|
+
:hashed_password => EmailCredential.create_hashed_password(self.password.to_s),
|
34
|
+
}
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# == Schema Information
|
3
|
+
# Schema version: 20090529051529
|
4
|
+
#
|
5
|
+
# Table name: open_id_credentials
|
6
|
+
#
|
7
|
+
# id :integer not null, primary key
|
8
|
+
# created_at :datetime not null
|
9
|
+
# user_id :integer not null, index_open_id_credentials_on_user_id
|
10
|
+
# identity_url :string(200) not null, index_open_id_credentials_on_identity_url(unique)
|
11
|
+
# loggedin_at :datetime
|
12
|
+
#
|
13
|
+
|
14
|
+
# OpenID認証情報
|
15
|
+
class OpenIdCredential < ActiveRecord::Base
|
16
|
+
MaximumRecordsPerUser = 10
|
17
|
+
|
18
|
+
belongs_to :user
|
19
|
+
|
20
|
+
validates_presence_of :identity_url
|
21
|
+
validates_length_of :identity_url, :maximum => 200, :allow_nil => true
|
22
|
+
validates_format_of :identity_url, :with => URI.regexp(%w[http https]), :allow_nil => true
|
23
|
+
validates_uniqueness_of :identity_url
|
24
|
+
validates_each(:user_id, :on => :create) { |record, attr, value|
|
25
|
+
if record.user && record.user.open_id_credentials(true).size >= MaximumRecordsPerUser
|
26
|
+
record.errors.add(attr, "これ以上%{fn}に#{_(record.class.to_s.downcase)}を追加できません。")
|
27
|
+
end
|
28
|
+
}
|
29
|
+
|
30
|
+
def login!
|
31
|
+
self.update_attributes!(:loggedin_at => Time.now)
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# == Schema Information
|
2
|
+
# Schema version: 20090529051529
|
3
|
+
#
|
4
|
+
# Table name: active_forms
|
5
|
+
#
|
6
|
+
# openid_url :text
|
7
|
+
#
|
8
|
+
|
9
|
+
# OpenIDログインフォーム
|
10
|
+
class OpenIdLoginForm < ActiveForm
|
11
|
+
column :openid_url, :type => :text
|
12
|
+
|
13
|
+
N_("OpenIdLoginForm|Openid url")
|
14
|
+
|
15
|
+
validates_presence_of :openid_url
|
16
|
+
validates_length_of :openid_url, :maximum => 200, :allow_nil => true
|
17
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# == Schema Information
|
2
|
+
# Schema version: 20090529051529
|
3
|
+
#
|
4
|
+
# Table name: sessions
|
5
|
+
#
|
6
|
+
# id :integer not null, primary key
|
7
|
+
# created_at :datetime not null
|
8
|
+
# updated_at :datetime not null, index_sessions_on_updated_at
|
9
|
+
# session_id :string(64) not null, index_sessions_on_session_id(unique)
|
10
|
+
# data :text
|
11
|
+
#
|
12
|
+
|
13
|
+
# セッション
|
14
|
+
class Session < ActiveRecord::Base
|
15
|
+
def self.cleanup(seconds)
|
16
|
+
self.delete_all(["(sessions.updated_at < ?)", Time.now - seconds])
|
17
|
+
return nil
|
18
|
+
end
|
19
|
+
end
|
data/app/models/user.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# == Schema Information
|
3
|
+
# Schema version: 20090529051529
|
4
|
+
#
|
5
|
+
# Table name: users
|
6
|
+
#
|
7
|
+
# id :integer not null, primary key
|
8
|
+
# created_at :datetime not null
|
9
|
+
# updated_at :datetime not null
|
10
|
+
# user_token :string(40) not null, index_users_on_user_token(unique)
|
11
|
+
# nickname :string(40)
|
12
|
+
#
|
13
|
+
|
14
|
+
# ユーザ
|
15
|
+
class User < ActiveRecord::Base
|
16
|
+
NicknameMaximumLength = 40
|
17
|
+
TokenLength = 20
|
18
|
+
TokenPattern = TokenUtil.create_token_regexp(TokenLength)
|
19
|
+
|
20
|
+
has_many :open_id_credentials
|
21
|
+
has_many :email_credentials
|
22
|
+
|
23
|
+
validates_presence_of :user_token
|
24
|
+
validates_length_of :nickname, :maximum => NicknameMaximumLength, :allow_nil => true
|
25
|
+
validates_format_of :user_token, :with => TokenPattern, :allow_nil => true
|
26
|
+
validates_uniqueness_of :user_token
|
27
|
+
|
28
|
+
before_validation_on_create { |record|
|
29
|
+
if record.user_token.blank?
|
30
|
+
record.user_token = record.class.create_unique_user_token
|
31
|
+
end
|
32
|
+
}
|
33
|
+
|
34
|
+
def self.create_unique_user_token
|
35
|
+
return TokenUtil.create_unique_token(self, :user_token, TokenLength)
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<%= MultiAuth.application_name %>へのユーザ登録、ありがとうございます。
|
2
|
+
下記のURLへアクセスすることにより、登録が完了します。
|
3
|
+
|
4
|
+
<%= @activation_url %>
|
5
|
+
|
6
|
+
※ 携帯電話等でのアクセスに関して
|
7
|
+
現時点では、Cookieに対応していない携帯電話等からは登録を行うことができません。
|
8
|
+
お手数ではございますが、本メールをPC等に転送した上で、登録をお願いいたします。
|
9
|
+
|
10
|
+
--
|
11
|
+
<%= MultiAuth.application_name %>
|
@@ -0,0 +1,90 @@
|
|
1
|
+
|
2
|
+
<%- @title = "ログイン" -%>
|
3
|
+
<%- @enable_side_column = false -%>
|
4
|
+
|
5
|
+
<%- additional_head { -%>
|
6
|
+
<style type="text/css">
|
7
|
+
#dialog
|
8
|
+
{
|
9
|
+
margin: 100px auto;
|
10
|
+
padding: 15px;
|
11
|
+
width: 400px;
|
12
|
+
border-width: 1px;
|
13
|
+
border-style: solid;
|
14
|
+
border-color: #CCCCCC;
|
15
|
+
}
|
16
|
+
#dialog h1
|
17
|
+
{
|
18
|
+
margin: 0 0 0.4em 0;
|
19
|
+
color: #666666;
|
20
|
+
font-size: 130%;
|
21
|
+
font-weight: bold;
|
22
|
+
}
|
23
|
+
|
24
|
+
table#email-login
|
25
|
+
{
|
26
|
+
margin: 0 auto;
|
27
|
+
border-collapse: collapse;
|
28
|
+
border-width: 0px;
|
29
|
+
}
|
30
|
+
|
31
|
+
table#email-login th,
|
32
|
+
table#email-login td
|
33
|
+
{
|
34
|
+
padding: 5px;
|
35
|
+
border-width: 0px;
|
36
|
+
}
|
37
|
+
|
38
|
+
table#email-login th
|
39
|
+
{
|
40
|
+
text-align: right;
|
41
|
+
font-size: 95%;
|
42
|
+
font-weight: bold;
|
43
|
+
vertical-align: top;
|
44
|
+
color: #666666;
|
45
|
+
}
|
46
|
+
table#email-login td
|
47
|
+
{
|
48
|
+
color: #333333;
|
49
|
+
}
|
50
|
+
|
51
|
+
div.fieldWithErrors label
|
52
|
+
{
|
53
|
+
color: #990000;
|
54
|
+
}
|
55
|
+
div.formError
|
56
|
+
{
|
57
|
+
font-size: 80%;
|
58
|
+
color: #990000;
|
59
|
+
}
|
60
|
+
</style>
|
61
|
+
<%- } -%>
|
62
|
+
|
63
|
+
<div id="dialog">
|
64
|
+
<h1>ログイン</h1>
|
65
|
+
<%- form_for(:login_form, @login_form, :url => {:action => "login"}) { |f| -%>
|
66
|
+
<table id="email-login">
|
67
|
+
<tr>
|
68
|
+
<th><%= f.label(:email) %></th>
|
69
|
+
<td>
|
70
|
+
<%= f.text_field(:email, :size => 30) %>
|
71
|
+
<%= error_message_on(:login_form, :email) %>
|
72
|
+
</td>
|
73
|
+
</tr>
|
74
|
+
<tr>
|
75
|
+
<th><%= f.label(:password) %></th>
|
76
|
+
<td>
|
77
|
+
<%= f.password_field(:password, :size => 30) %>
|
78
|
+
<%= error_message_on(:login_form, :password) %>
|
79
|
+
</td>
|
80
|
+
</tr>
|
81
|
+
</table>
|
82
|
+
<div style="text-align: center;"><%= submit_tag("ログイン") %></div>
|
83
|
+
<%- } -%>
|
84
|
+
</div>
|
85
|
+
|
86
|
+
<%- unless production? -%>
|
87
|
+
<div class="debug">
|
88
|
+
<%= error_messages_for(:login_form) %>
|
89
|
+
</div>
|
90
|
+
<%- end -%>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
<%- @title = "ログインしました" -%>
|
3
|
+
<%- @enable_side_column = false -%>
|
4
|
+
<%- @stylesheets = %[auth] -%>
|
5
|
+
|
6
|
+
<%- additional_head { -%>
|
7
|
+
<%# MEMO: meta要素による自動遷移は無効化されている可能性があるため、JavaScriptによる遷移を併用する %>
|
8
|
+
<meta http-equiv="refresh" content="1; URL=<%= URI.escape(@return_path) %>" />
|
9
|
+
<script type="text/javascript">
|
10
|
+
// <![CDATA[
|
11
|
+
setTimeout(function() {
|
12
|
+
window.location = "<%= URI.escape(@return_path) %>";
|
13
|
+
}, 2000);
|
14
|
+
// ]]>
|
15
|
+
</script>
|
16
|
+
<%- } -%>
|
17
|
+
|
18
|
+
<div id="dialog">
|
19
|
+
<h1>ログインしました</h1>
|
20
|
+
<div class="message">ページが切り替わらない場合は <%= link_to(h(@return_path), @return_path) %> をクリックしてください。</div>
|
21
|
+
</div>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
<%- @title = "ログアウトしました" -%>
|
3
|
+
<%- @enable_side_column = false -%>
|
4
|
+
<%- @stylesheets = %[auth] -%>
|
5
|
+
|
6
|
+
<%- additional_head { -%>
|
7
|
+
<%# MEMO: meta要素による自動遷移は無効化されている可能性があるため、JavaScriptによる遷移を併用する %>
|
8
|
+
<meta http-equiv="refresh" content="1; URL=<%= URI.escape(@return_path) %>" />
|
9
|
+
<script type="text/javascript">
|
10
|
+
// <![CDATA[
|
11
|
+
setTimeout(function() {
|
12
|
+
window.location = "<%= URI.escape(@return_path) %>";
|
13
|
+
}, 2000);
|
14
|
+
// ]]>
|
15
|
+
</script>
|
16
|
+
<%- } -%>
|
17
|
+
|
18
|
+
<div id="dialog">
|
19
|
+
<h1>ログアウトしました</h1>
|
20
|
+
<div class="message">ページが切り替わらない場合は <%= link_to(h(@return_path), @return_path) %> をクリックしてください。</div>
|
21
|
+
</div>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
<%- @title = "ログイン" -%>
|
3
|
+
|
4
|
+
<h1>OpenID によるログイン</h1>
|
5
|
+
|
6
|
+
<%- form_tag(:action => "login") { -%>
|
7
|
+
<table border="1">
|
8
|
+
<tr>
|
9
|
+
<th><%= label_tag(:openid_url, "OpenID") %></th>
|
10
|
+
<td>
|
11
|
+
<%= text_field_tag(:openid_url, "", :size => 30) %>
|
12
|
+
</td>
|
13
|
+
</tr>
|
14
|
+
</table>
|
15
|
+
<div><%= submit_tag("ログイン") %></div>
|
16
|
+
<%- } -%>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
|
2
|
+
<%- @title = "アクティベーション" -%>
|
3
|
+
|
4
|
+
<h1><%=h @title %></h1>
|
5
|
+
|
6
|
+
<table border="1">
|
7
|
+
<tr>
|
8
|
+
<th>メールアドレス</th>
|
9
|
+
<td><%=h @email_credential.email %></td>
|
10
|
+
</tr>
|
11
|
+
</table>
|
12
|
+
|
13
|
+
<%- form_tag(:action => "activate") { -%>
|
14
|
+
<div><%= submit_tag("登録") %></div>
|
15
|
+
<%- } -%>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
|
2
|
+
<%- @title = "仮登録完了" -%>
|
3
|
+
<%- @topic_path << ["トップ", root_path] -%>
|
4
|
+
<%- @topic_path << ["ログイン設定", url_for(:controller => "/credentials")] -%>
|
5
|
+
<%- @topic_path << [@title] -%>
|
6
|
+
|
7
|
+
<h1><%=h @title %></h1>
|
8
|
+
|
9
|
+
<div>指定されたメールアドレスにメールを送信しました。メールに記載されたURLにアクセスして、登録を完了してください。</div>
|
10
|
+
<div><%= link_to(h("ログイン設定に戻る"), :controller => "/credentials", :action => "index") %></div>
|
11
|
+
|
12
|
+
<%- unless production? -%>
|
13
|
+
<hr />
|
14
|
+
<%= link_to(h("アクティベーション"), :controller => "credentials/email", :action => "activation", :activation_token => @email_credential.activation_token) %>
|
15
|
+
<%- end -%>
|