Class: Fortifier::AuthUser

Inherits:
ActiveRecord::Base
  • Object
show all
Defined in:
app/models/fortifier/auth_user.rb

Constant Summary collapse

ABAQIS =
1
EMP_SAT =
2

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.authenticate_batch_sso(account_uuid, token) ⇒ Object



114
115
116
117
118
119
120
121
122
123
# File 'app/models/fortifier/auth_user.rb', line 114

def self.authenticate_batch_sso(, token)
  return nil if token.blank?
  AuthUser.
      joins(:secrets).
      where("find_in_set(? , account_uuids_csv)
      AND (expired IS NULL OR expired = false)
      AND enc_type = '#{Secret::SSO_TOKEN}'
      AND secret_value = ?", , token).
      first
end

.authenticate_on_demand_sso(account_uuid, token) ⇒ Object



125
126
127
128
129
130
131
132
133
134
# File 'app/models/fortifier/auth_user.rb', line 125

def self.authenticate_on_demand_sso(, token)
  return nil if token.blank?
  AuthUser.
      joins(:secrets).
      where("find_in_set(? , account_uuids_csv)
      AND (expired IS NULL OR expired = false)
      AND enc_type = '#{Secret::SSO_TOKEN}'
      AND secret_value = ?", , token).
      first
end

.paged_and_sorted_search(params) ⇒ Object



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'app/models/fortifier/auth_user.rb', line 178

def self.paged_and_sorted_search(params)
  search          = params[:search]
  sort_col        = params[:sortcol] || 'name'
  sort_dir        = params[:sortdir] || 'asc'
  per_page        = (params[:per_page].blank? || params[:per_page]<25) ? 25 : params[:per_page]
  page            = params[:page] || 1
  app_uuid        = params[:app_uuid]
      = params[:account_uuid]
  search_keywords = params[:search_keywords]

  if search.blank?
    user_search_query = ''
  else
    user_search_query = [:login, :email, :name, :note].map{|f| "#{f} LIKE '%#{search}%'"}.join(" OR ")
  end

  # aggregate_query is conditional b/c account_uuid isn't always provided (such as the Users page for providigm users in abaqis)
  app_uuids_query = "app_uuids_csv = '#{app_uuid}'"
   =  ? " AND account_uuids_csv = '#{}'" : ""
  search_keywords_query = search_keywords ? " AND FIND_IN_SET ('#{search_keywords}', search_keywords_csv)" : ''
  undeleted_auth_user_clause = " AND deleted = 0 "
  aggregate_query = app_uuids_query +  + search_keywords_query + undeleted_auth_user_clause

  # b/c there's no 'enabled' field on auth user and abaqis allows this sorting (providigm/users in abaqis)
  if sort_col=='enabled'
    Fortifier::AuthUser.where(aggregate_query)
        .where(user_search_query)
        .order("app_uuids_csv #{sort_dir}, account_uuids_csv #{sort_dir}")
        .paginate(:page=>page, :per_page=>per_page)
  elsif sort_col=='last_login_at'
    # In other words, pull all users associated with the app in question (if available),
    # joined with their most recent AuthLog,
    # sort by the AuthLog created_at date (according to user preference),
    # then paginate with WillPaginate. Capisce?
    Fortifier::AuthUser.find_by_sql("SELECT * FROM fortifier_auth_users fau
                                      LEFT OUTER JOIN ( select auth_user_id, max(created_at)
                                          AS last_login_at
                                          FROM fortifier_auth_logs fal
                                          GROUP BY auth_user_id)
                                        AS last_seen
                                      ON fau.id = last_seen.auth_user_id
                                      #{'WHERE ' + aggregate_query}
                                    #{'AND ' + user_search_query if user_search_query.present?}
                                      ORDER BY last_login_at #{sort_dir}")
        .paginate(:page=>page, :per_page=>per_page)
  else
    Fortifier::AuthUser.where(aggregate_query)
        .where(user_search_query)
        .order("#{sort_col} #{sort_dir}")
        .paginate(:page=>page, :per_page=>per_page)
  end
end

Instance Method Details

#authenticated?(secret_string) ⇒ Boolean

Returns:

  • (Boolean)


101
102
103
104
105
106
107
108
109
110
111
112
# File 'app/models/fortifier/auth_user.rb', line 101

def authenticated?(secret_string)
  # TODO: (DK) do not increase consecutive_failed_logins if user is attempting a pw change
  # move consecutive_failed_logins updates to a different method so this method
  # doesn't do multiple things (code smell)
  if self.secrets_match?(secret_string)
    self.update_column(:consecutive_failed_logins, 0) unless self.blocked?
    true
  else
    self.update_column(:consecutive_failed_logins, self.consecutive_failed_logins + 1)
    false
  end
end

#blocked?Boolean

Returns:

  • (Boolean)


136
137
138
# File 'app/models/fortifier/auth_user.rb', line 136

def blocked?
  self.consecutive_failed_logins > 5
end

#current_secretObject



83
84
85
# File 'app/models/fortifier/auth_user.rb', line 83

def current_secret
  self.secrets.order("created_at, id asc").last
end

#current_secret_non_tokenObject



87
88
89
# File 'app/models/fortifier/auth_user.rb', line 87

def current_secret_non_token
  self.secrets.where(enc_type: (Secret::BCRYPT || Secret::SHA)).order("created_at, id asc").last
end

#disable!Object



140
141
142
143
# File 'app/models/fortifier/auth_user.rb', line 140

def disable!
  self.update_column(:app_uuids_csv, nil)
  self.update_column(:account_uuids_csv, nil)
end

#disabled?Boolean

Returns:

  • (Boolean)


145
146
147
# File 'app/models/fortifier/auth_user.rb', line 145

def disabled?
  self.app_uuids.blank? && self..blank?
end

#email_is_correct_formatObject



61
62
63
64
65
# File 'app/models/fortifier/auth_user.rb', line 61

def email_is_correct_format
  return if (email.blank?)
  return if (Fortifier::Authentication::EMAIL_REGEX.match email).present?
  errors[:base] << :email_format_incorrect
end

#email_is_correct_lengthObject



49
50
51
52
53
# File 'app/models/fortifier/auth_user.rb', line 49

def email_is_correct_length
  return if (email.blank?)
  return if (email.length >= 6 && email.length <= 100)
  errors[:base] << :email_length_incorrect
end

#email_is_uniqueObject



55
56
57
58
59
# File 'app/models/fortifier/auth_user.rb', line 55

def email_is_unique
  return if (email.blank?)
  return if unique?(:email, email)
  errors[:base] << :email_not_unique
end

#login_is_correct_lengthObject



36
37
38
39
40
# File 'app/models/fortifier/auth_user.rb', line 36

def 
  return if .blank?
  return if (.length >= 3 && .length <= 60) unless .blank?
  errors[:base] << :login_length_incorrect
end

#login_is_presentObject

NOTE: These custom validations are used so that symbols/codes can be returned to applications, rather than explicit text. Fortifier provides the symbols and the apps are responsible for handling error messaging.



31
32
33
34
# File 'app/models/fortifier/auth_user.rb', line 31

def 
  return if .present?
  errors[:base] << :login_blank
end

#login_is_uniqueObject



42
43
44
45
46
47
# File 'app/models/fortifier/auth_user.rb', line 42

def 
  return if .blank?
  return if unique?(:login, )

  errors[:base] << :login_not_unique
end

#matching_whitelist_ip?(ip) ⇒ Boolean

Returns:

  • (Boolean)


156
157
158
159
160
161
# File 'app/models/fortifier/auth_user.rb', line 156

def matching_whitelist_ip?(ip)
  return false if ip.blank?
  au_auth_rule_ids = AuthUsersAuthRule.where(auth_user_id: self.id).pluck(:auth_rule_id)
  auth_rule_ips = au_auth_rule_ids.map {|auid| AuthRule.find(auid).rule_value}
  auth_rule_ips.flatten.include?(ip)
end

#name_is_correct_formatObject



67
68
69
70
71
# File 'app/models/fortifier/auth_user.rb', line 67

def name_is_correct_format
  return if (name.blank?)
  return if (Fortifier::Authentication::NAME_REGEX.match name).present?
  errors[:base] << :name_format_incorrect
end

#name_is_correct_lengthObject



73
74
75
76
# File 'app/models/fortifier/auth_user.rb', line 73

def name_is_correct_length
  return if (name.blank? || name.length <= 100)
  errors[:base] << :name_length_incorrect
end

#note_is_correct_lengthObject



78
79
80
81
# File 'app/models/fortifier/auth_user.rb', line 78

def note_is_correct_length
  return if (note.blank? || note.length <= 255)
  errors[:base] << :note_length_incorrect
end

#public_attribute_hashObject



163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'app/models/fortifier/auth_user.rb', line 163

def public_attribute_hash
  auth_log = self.auth_logs.last
  {
      uuid: self.uuid,
      email: self.email,
      login: self.,
      name: self.name,
      note: self.note,
      disabled: self.disabled?,
      deleted:  self.deleted?,
      blocked:  self.blocked?,
      last_auth_log: ({user_agent: auth_log.user_agent, status: auth_log.status, created_at: auth_log.created_at.to_time} if auth_log)
  }
end

#secrets_match?(secret_string) ⇒ Boolean

Returns:

  • (Boolean)


91
92
93
94
95
96
97
98
99
# File 'app/models/fortifier/auth_user.rb', line 91

def secrets_match?(secret_string)
  current_secret_model = current_secret_non_token
  return false if current_secret_model.blank?

  auth_result = current_secret_model.matches?(secret_string)
  current_secret_model.update_encryption_method(secret_string) if (auth_result && current_secret_model.enc_type == "SHA")

  return auth_result
end

#successful_log_in?Boolean

Returns:

  • (Boolean)


149
150
151
152
153
154
# File 'app/models/fortifier/auth_user.rb', line 149

def successful_log_in?
  # TODO: clarify this so there's no confusion (user can be logged out with a count of 0,
  # so technically they wouldn't be succesfully logged in, even though this method would
  # say otherwise).
  self.consecutive_failed_logins == 0
end