multi_auth 0.0.1
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 +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 -%>
|