Skip to content

Commit 1c6dca9

Browse files
authored
Refactor User model, extract PamAuthenticable, LdapAuthenticable (mastodon#10217)
1 parent 689122e commit 1c6dca9

5 files changed

Lines changed: 155 additions & 120 deletions

File tree

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# frozen_string_literal: true
2+
3+
module LdapAuthenticable
4+
extend ActiveSupport::Concern
5+
6+
def ldap_setup(_attributes)
7+
self.confirmed_at = Time.now.utc
8+
self.admin = false
9+
10+
save!
11+
end
12+
13+
class_methods do
14+
def ldap_get_user(attributes = {})
15+
resource = joins(:account).find_by(accounts: { username: attributes[Devise.ldap_uid.to_sym].first })
16+
17+
if resource.blank?
18+
resource = new(email: attributes[:mail].first, agreement: true, account_attributes: { username: attributes[Devise.ldap_uid.to_sym].first })
19+
resource.ldap_setup(attributes)
20+
end
21+
22+
resource
23+
end
24+
end
25+
end

app/models/concerns/omniauthable.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ module Omniauthable
77
TEMP_EMAIL_REGEX = /\Achange@me/
88

99
included do
10+
devise :omniauthable
11+
1012
def omniauth_providers
1113
Devise.omniauth_configs.keys
1214
end
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# frozen_string_literal: true
2+
3+
module PamAuthenticable
4+
extend ActiveSupport::Concern
5+
6+
included do
7+
devise :pam_authenticatable if ENV['PAM_ENABLED'] == 'true'
8+
9+
def pam_conflict(_attributes)
10+
# Block pam login tries on traditional account
11+
end
12+
13+
def pam_conflict?
14+
if Devise.pam_authentication
15+
encrypted_password.present? && pam_managed_user?
16+
else
17+
false
18+
end
19+
end
20+
21+
def pam_get_name
22+
if account.present?
23+
account.username
24+
else
25+
super
26+
end
27+
end
28+
29+
def pam_setup(_attributes)
30+
account = Account.new(username: pam_get_name)
31+
account.save!(validate: false)
32+
33+
self.email = "#{account.username}@#{find_pam_suffix}" if email.nil? && find_pam_suffix
34+
self.confirmed_at = Time.now.utc
35+
self.admin = false
36+
self.account = account
37+
38+
account.destroy! unless save
39+
end
40+
41+
def self.pam_get_user(attributes = {})
42+
return nil unless attributes[:email]
43+
44+
resource = begin
45+
if Devise.check_at_sign && !attributes[:email].index('@')
46+
joins(:account).find_by(accounts: { username: attributes[:email] })
47+
else
48+
find_by(email: attributes[:email])
49+
end
50+
end
51+
52+
if resource.nil?
53+
resource = new(email: attributes[:email], agreement: true)
54+
55+
if Devise.check_at_sign && !resource[:email].index('@')
56+
resource[:email] = Rpam2.getenv(resource.find_pam_service, attributes[:email], attributes[:password], 'email', false)
57+
resource[:email] = "#{attributes[:email]}@#{resource.find_pam_suffix}" unless resource[:email]
58+
end
59+
end
60+
61+
resource
62+
end
63+
64+
def self.authenticate_with_pam(attributes = {})
65+
super if Devise.pam_authentication
66+
end
67+
end
68+
end

app/models/concerns/user_roles.rb

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# frozen_string_literal: true
2+
3+
module UserRoles
4+
extend ActiveSupport::Concern
5+
6+
included do
7+
scope :admins, -> { where(admin: true) }
8+
scope :moderators, -> { where(moderator: true) }
9+
scope :staff, -> { admins.or(moderators) }
10+
end
11+
12+
def staff?
13+
admin? || moderator?
14+
end
15+
16+
def role
17+
if admin?
18+
'admin'
19+
elsif moderator?
20+
'moderator'
21+
else
22+
'user'
23+
end
24+
end
25+
26+
def role?(role)
27+
case role
28+
when 'user'
29+
true
30+
when 'moderator'
31+
staff?
32+
when 'admin'
33+
admin?
34+
else
35+
false
36+
end
37+
end
38+
39+
def promote!
40+
if moderator?
41+
update!(moderator: false, admin: true)
42+
elsif !admin?
43+
update!(moderator: true)
44+
end
45+
end
46+
47+
def demote!
48+
if admin?
49+
update!(admin: false, moderator: true)
50+
elsif moderator?
51+
update!(moderator: false)
52+
end
53+
end
54+
end

app/models/user.rb

Lines changed: 6 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141

4242
class User < ApplicationRecord
4343
include Settings::Extend
44-
include Omniauthable
44+
include UserRoles
4545

4646
# The home and list feeds will be stored in Redis for this amount
4747
# of time, and status fan-out to followers will include only people
@@ -61,9 +61,9 @@ class User < ApplicationRecord
6161
devise :registerable, :recoverable, :rememberable, :trackable, :validatable,
6262
:confirmable
6363

64-
devise :pam_authenticatable if ENV['PAM_ENABLED'] == 'true'
65-
66-
devise :omniauthable
64+
include Omniauthable
65+
include PamAuthenticable
66+
include LdapAuthenticable
6767

6868
belongs_to :account, inverse_of: :user
6969
belongs_to :invite, counter_cache: :uses, optional: true
@@ -79,9 +79,6 @@ class User < ApplicationRecord
7979
validates :agreement, acceptance: { allow_nil: false, accept: [true, 'true', '1'] }, on: :create
8080

8181
scope :recent, -> { order(id: :desc) }
82-
scope :admins, -> { where(admin: true) }
83-
scope :moderators, -> { where(moderator: true) }
84-
scope :staff, -> { admins.or(moderators) }
8582
scope :confirmed, -> { where.not(confirmed_at: nil) }
8683
scope :enabled, -> { where(disabled: false) }
8784
scope :inactive, -> { where(arel_table[:current_sign_in_at].lt(ACTIVE_DURATION.ago)) }
@@ -104,39 +101,6 @@ class User < ApplicationRecord
104101

105102
attr_reader :invite_code
106103

107-
def pam_conflict(_)
108-
# block pam login tries on traditional account
109-
nil
110-
end
111-
112-
def pam_conflict?
113-
return false unless Devise.pam_authentication
114-
encrypted_password.present? && pam_managed_user?
115-
end
116-
117-
def pam_get_name
118-
return account.username if account.present?
119-
super
120-
end
121-
122-
def pam_setup(_attributes)
123-
acc = Account.new(username: pam_get_name)
124-
acc.save!(validate: false)
125-
126-
self.email = "#{acc.username}@#{find_pam_suffix}" if email.nil? && find_pam_suffix
127-
self.confirmed_at = Time.now.utc
128-
self.admin = false
129-
self.account = acc
130-
131-
acc.destroy! unless save
132-
end
133-
134-
def ldap_setup(_attributes)
135-
self.confirmed_at = Time.now.utc
136-
self.admin = false
137-
save!
138-
end
139-
140104
def confirmed?
141105
confirmed_at.present?
142106
end
@@ -145,33 +109,6 @@ def invited?
145109
invite_id.present?
146110
end
147111

148-
def staff?
149-
admin? || moderator?
150-
end
151-
152-
def role
153-
if admin?
154-
'admin'
155-
elsif moderator?
156-
'moderator'
157-
else
158-
'user'
159-
end
160-
end
161-
162-
def role?(role)
163-
case role
164-
when 'user'
165-
true
166-
when 'moderator'
167-
staff?
168-
when 'admin'
169-
admin?
170-
else
171-
false
172-
end
173-
end
174-
175112
def disable!
176113
update!(disabled: true,
177114
last_sign_in_at: current_sign_in_at,
@@ -186,6 +123,7 @@ def confirm
186123
new_user = !confirmed?
187124

188125
super
126+
189127
prepare_new_user! if new_user
190128
end
191129

@@ -194,6 +132,7 @@ def confirm!
194132

195133
skip_confirmation!
196134
save!
135+
197136
prepare_new_user! if new_user
198137
end
199138

@@ -202,22 +141,6 @@ def update_tracked_fields!(request)
202141
prepare_returning_user!
203142
end
204143

205-
def promote!
206-
if moderator?
207-
update!(moderator: false, admin: true)
208-
elsif !admin?
209-
update!(moderator: true)
210-
end
211-
end
212-
213-
def demote!
214-
if admin?
215-
update!(admin: false, moderator: true)
216-
elsif moderator?
217-
update!(moderator: false)
218-
end
219-
end
220-
221144
def disable_two_factor!
222145
self.otp_required_for_login = false
223146
otp_backup_codes&.clear
@@ -297,43 +220,6 @@ def reset_password!(new_password, new_password_confirmation)
297220
super
298221
end
299222

300-
def self.pam_get_user(attributes = {})
301-
return nil unless attributes[:email]
302-
303-
resource =
304-
if Devise.check_at_sign && !attributes[:email].index('@')
305-
joins(:account).find_by(accounts: { username: attributes[:email] })
306-
else
307-
find_by(email: attributes[:email])
308-
end
309-
310-
if resource.blank?
311-
resource = new(email: attributes[:email], agreement: true)
312-
313-
if Devise.check_at_sign && !resource[:email].index('@')
314-
resource[:email] = Rpam2.getenv(resource.find_pam_service, attributes[:email], attributes[:password], 'email', false)
315-
resource[:email] = "#{attributes[:email]}@#{resource.find_pam_suffix}" unless resource[:email]
316-
end
317-
end
318-
resource
319-
end
320-
321-
def self.ldap_get_user(attributes = {})
322-
resource = joins(:account).find_by(accounts: { username: attributes[Devise.ldap_uid.to_sym].first })
323-
324-
if resource.blank?
325-
resource = new(email: attributes[:mail].first, agreement: true, account_attributes: { username: attributes[Devise.ldap_uid.to_sym].first })
326-
resource.ldap_setup(attributes)
327-
end
328-
329-
resource
330-
end
331-
332-
def self.authenticate_with_pam(attributes = {})
333-
return nil unless Devise.pam_authentication
334-
super
335-
end
336-
337223
def show_all_media?
338224
setting_display_media == 'show_all'
339225
end

0 commit comments

Comments
 (0)