Class: SAML::UserAttributes::SSOe
Constant Summary
collapse
- SERIALIZABLE_ATTRIBUTES =
%i[email first_name middle_name last_name gender ssn birth_date
uuid idme_uuid logingov_uuid verified_at sec_id mhv_icn
mhv_correlation_id mhv_account_type edipi loa sign_in multifactor icn].freeze
- INBOUND_AUTHN_CONTEXT =
'urn:oasis:names:tc:SAML:2.0:ac:classes:Password'
Identity::Parsers::GCIdsConstants::ACTIVE_MHV_IDS_REGEX, Identity::Parsers::GCIdsConstants::BIRLS_IDS_REGEX, Identity::Parsers::GCIdsConstants::CERNER_FACILITY_IDS_REGEX, Identity::Parsers::GCIdsConstants::CERNER_ID_REGEX, Identity::Parsers::GCIdsConstants::DOD_ROOT_OID, Identity::Parsers::GCIdsConstants::EDIPI_REGEX, Identity::Parsers::GCIdsConstants::ICN_ASSIGNING_AUTHORITY_ID, Identity::Parsers::GCIdsConstants::ICN_REGEX, Identity::Parsers::GCIdsConstants::IDENTIFIERS_SPLIT_TOKEN, Identity::Parsers::GCIdsConstants::IDME_ID_REGEX, Identity::Parsers::GCIdsConstants::IDS_SPLIT_TOKEN, Identity::Parsers::GCIdsConstants::ID_MAPPINGS, Identity::Parsers::GCIdsConstants::LOGINGOV_ID_REGEX, Identity::Parsers::GCIdsConstants::MHV_IDS_REGEX, Identity::Parsers::GCIdsConstants::MHV_IEN_REGEX, Identity::Parsers::GCIdsConstants::PERMANENT_ICN_REGEX, Identity::Parsers::GCIdsConstants::SEC_ID_REGEX, Identity::Parsers::GCIdsConstants::VA_ROOT_OID, Identity::Parsers::GCIdsConstants::VBA_CORP_ID_REGEX, Identity::Parsers::GCIdsConstants::VET360_ID_REGEX, Identity::Parsers::GCIdsConstants::VHA_FACILITY_IDS_REGEX
Instance Attribute Summary collapse
Instance Method Summary
collapse
#build_hash, #parse_string_gcids, #parse_xml_gcids, #select, #select_extension, #select_icn_with_aaid, #select_token_position
#sanitize_edipi, #sanitize_id, #sanitize_id_array
#log_exception_to_sentry, #log_message_to_sentry, #non_nil_hash?, #normalize_level, #rails_logger, #set_sentry_metadata
Constructor Details
#initialize(saml_attributes, authn_context, tracker_uuid) ⇒ SSOe
Returns a new instance of SSOe.
19
20
21
22
23
24
|
# File 'lib/saml/user_attributes/ssoe.rb', line 19
def initialize(saml_attributes, authn_context, tracker_uuid)
@attributes = saml_attributes @authn_context = authn_context
@tracker_uuid = tracker_uuid
@warnings = []
end
|
Instance Attribute Details
#attributes ⇒ Object
Returns the value of attribute attributes.
17
18
19
|
# File 'lib/saml/user_attributes/ssoe.rb', line 17
def attributes
@attributes
end
|
#authn_context ⇒ Object
Returns the value of attribute authn_context.
17
18
19
|
# File 'lib/saml/user_attributes/ssoe.rb', line 17
def authn_context
@authn_context
end
|
#tracker_uuid ⇒ Object
Returns the value of attribute tracker_uuid.
17
18
19
|
# File 'lib/saml/user_attributes/ssoe.rb', line 17
def tracker_uuid
@tracker_uuid
end
|
#warnings ⇒ Object
Returns the value of attribute warnings.
17
18
19
|
# File 'lib/saml/user_attributes/ssoe.rb', line 17
def warnings
@warnings
end
|
Instance Method Details
#account_type ⇒ Object
157
158
159
160
161
162
|
# File 'lib/saml/user_attributes/ssoe.rb', line 157
def account_type
result = mhv_account_type
result ||= dslogon_account_type
result ||= 'N/A'
result
end
|
#attribute_has_multiple_values?(attribute) ⇒ Boolean
284
285
286
287
|
# File 'lib/saml/user_attributes/ssoe.rb', line 284
def attribute_has_multiple_values?(attribute)
var = safe_attr(attribute)&.split(',') || []
var.reject(&:nil?).uniq.size > 1
end
|
#birth_date ⇒ Object
54
55
56
57
58
59
60
61
|
# File 'lib/saml/user_attributes/ssoe.rb', line 54
def birth_date
bd = safe_attr('va_eauth_birthDate_v1')
begin
Date.parse(bd).strftime('%Y-%m-%d')
rescue TypeError, ArgumentError
nil
end
end
|
#check_id_mismatch(ids, multiple_ids_error_type) ⇒ Object
265
266
267
268
269
270
271
272
273
274
275
276
277
278
|
# File 'lib/saml/user_attributes/ssoe.rb', line 265
def check_id_mismatch(ids, multiple_ids_error_type)
return if ids.blank?
if ids.reject(&:nil?).uniq.size > 1
mismatched_ids_error = SAML::UserAttributeError::ERRORS[multiple_ids_error_type]
error_data = { mismatched_ids: ids, icn: mhv_icn }
Rails.logger.warn("[SAML::UserAttributes::SSOe] #{mismatched_ids_error[:message]}, #{error_data}")
unless mhv_outbound_redirect(mismatched_ids_error)
raise SAML::UserAttributeError.new(message: mismatched_ids_error[:message],
code: mismatched_ids_error[:code],
tag: mismatched_ids_error[:tag])
end
end
end
|
#csid ⇒ Object
289
290
291
|
# File 'lib/saml/user_attributes/ssoe.rb', line 289
def csid
safe_attr('va_eauth_csid')&.downcase
end
|
#dslogon_account_type ⇒ Object
106
107
108
|
# File 'lib/saml/user_attributes/ssoe.rb', line 106
def dslogon_account_type
safe_attr('va_eauth_dslogonassurance')
end
|
#dslogon_loa_highest ⇒ Object
136
137
138
139
|
# File 'lib/saml/user_attributes/ssoe.rb', line 136
def dslogon_loa_highest
dslogon_assurance = dslogon_account_type
LOA::DSLOGON_PREMIUM_VERIFIED.include?(dslogon_assurance) ? 3 : nil
end
|
#edipi ⇒ Object
110
111
112
|
# File 'lib/saml/user_attributes/ssoe.rb', line 110
def edipi
edipi_ids[:edipi]
end
|
#edipi_ids ⇒ Object
241
242
243
244
245
246
247
248
|
# File 'lib/saml/user_attributes/ssoe.rb', line 241
def edipi_ids
@edipi_ids ||= begin
gcids = safe_attr('va_eauth_gcIds')
return {} unless gcids
parse_string_gcids(gcids, DOD_ROOT_OID)
end
end
|
#email ⇒ Object
63
64
65
|
# File 'lib/saml/user_attributes/ssoe.rb', line 63
def email
safe_attr('va_eauth_emailaddress')
end
|
#first_name ⇒ Object
27
28
29
|
# File 'lib/saml/user_attributes/ssoe.rb', line 27
def first_name
safe_attr('va_eauth_firstname')
end
|
#gender ⇒ Object
43
44
45
46
|
# File 'lib/saml/user_attributes/ssoe.rb', line 43
def gender
gender = safe_attr('va_eauth_gender')&.chars&.first&.upcase
%w[M F].include?(gender) ? gender : nil
end
|
#icn ⇒ Object
39
40
41
|
# File 'lib/saml/user_attributes/ssoe.rb', line 39
def icn
mvi_ids[:icn]
end
|
#idme_uuid ⇒ Object
72
73
74
75
76
|
# File 'lib/saml/user_attributes/ssoe.rb', line 72
def idme_uuid
return safe_attr('va_eauth_uid') if csid == SAML::User::IDME_CSID
mvi_ids[:idme_id]
end
|
#last_name ⇒ Object
35
36
37
|
# File 'lib/saml/user_attributes/ssoe.rb', line 35
def last_name
safe_attr('va_eauth_lastname')
end
|
#loa ⇒ Object
164
165
166
|
# File 'lib/saml/user_attributes/ssoe.rb', line 164
def loa
{ current: loa_current, highest: [loa_current, loa_highest].max }
end
|
#loa_current ⇒ Object
va_eauth_credentialassurancelevel is supposed to roll up the federated assurance level from credential provider and broker. It is currently returning a value of “2” for DSLogon level 2 so we are interpreting any value greater than 1 as “LOA 3”.
118
119
120
121
122
123
124
125
126
127
128
129
|
# File 'lib/saml/user_attributes/ssoe.rb', line 118
def loa_current
assurance =
if csid == 'logingov'
safe_attr('va_eauth_ial')&.to_i
else
safe_attr('va_eauth_credentialassurancelevel')&.to_i
end
@loa_current ||= assurance.present? && assurance > 1 ? 3 : 1
rescue NoMethodError, KeyError => e
@warnings << "loa_current error: #{e.message}"
@loa_current = 1
end
|
#loa_highest ⇒ Object
This is the ID.me highest level of assurance attained
142
143
144
145
146
147
|
# File 'lib/saml/user_attributes/ssoe.rb', line 142
def loa_highest
result = mhv_loa_highest
result ||= dslogon_loa_highest
result ||= %w[2 classic_loa3].include?(safe_attr('va_eauth_ial_idme_highest')) ? 3 : 1
result
end
|
#logingov_uuid ⇒ Object
78
79
80
81
82
|
# File 'lib/saml/user_attributes/ssoe.rb', line 78
def logingov_uuid
return safe_attr('va_eauth_uid') if csid == SAML::User::LOGINGOV_CSID
mvi_ids[:logingov_id]
end
|
#mhv_account_type ⇒ Object
102
103
104
|
# File 'lib/saml/user_attributes/ssoe.rb', line 102
def mhv_account_type
safe_attr('va_eauth_mhvassurance')
end
|
#mhv_correlation_id ⇒ Object
98
99
100
|
# File 'lib/saml/user_attributes/ssoe.rb', line 98
def mhv_correlation_id
safe_attr('va_eauth_mhvuuid') || mvi_ids[:mhv_ien]
end
|
#mhv_icn ⇒ Object
94
95
96
|
# File 'lib/saml/user_attributes/ssoe.rb', line 94
def mhv_icn
safe_attr('va_eauth_icn')
end
|
#mhv_iens ⇒ Object
254
255
256
257
|
# File 'lib/saml/user_attributes/ssoe.rb', line 254
def mhv_iens
mhv_iens = mvi_ids[:mhv_iens] || []
mhv_iens.append(safe_attr('va_eauth_mhvuuid')).reject(&:nil?).uniq
end
|
#mhv_loa_highest ⇒ Object
131
132
133
134
|
# File 'lib/saml/user_attributes/ssoe.rb', line 131
def mhv_loa_highest
mhv_assurance = mhv_account_type
LOA::MHV_PREMIUM_VERIFIED.include?(mhv_assurance) ? 3 : nil
end
|
#mhv_outbound_redirect(mismatched_ids_error) ⇒ Object
259
260
261
262
263
|
# File 'lib/saml/user_attributes/ssoe.rb', line 259
def mhv_outbound_redirect(mismatched_ids_error)
return false if mismatched_ids_error[:tag] == :multiple_edipis
@mhv_outbound_redirect ||= %w[mhv myvahealth].include?(tracker&.payload_attr(:application))
end
|
#middle_name ⇒ Object
31
32
33
|
# File 'lib/saml/user_attributes/ssoe.rb', line 31
def middle_name
safe_attr('va_eauth_middlename')
end
|
#multifactor ⇒ Object
149
150
151
152
153
154
155
|
# File 'lib/saml/user_attributes/ssoe.rb', line 149
def multifactor
if csid == SAML::User::LOGINGOV_CSID
safe_attr('va_eauth_aal') == AAL::TWO
else
safe_attr('va_eauth_multifactor')&.downcase == 'true'
end
end
|
#multiple_id_validations ⇒ Object
213
214
215
216
217
218
219
220
221
222
223
224
|
# File 'lib/saml/user_attributes/ssoe.rb', line 213
def multiple_id_validations
check_id_mismatch([safe_attr('va_eauth_icn'), safe_attr('va_eauth_mhvicn')], :mhv_icn_mismatch)
check_id_mismatch(mvi_ids[:vba_corp_ids], :multiple_corp_ids)
check_id_mismatch(edipi_ids[:edipis], :multiple_edipis)
check_id_mismatch(mhv_iens, :multiple_mhv_ids)
if sec_id_mismatch?
log_message_to_sentry('User attributes contains multiple sec_id values',
'warn',
{ sec_id: @attributes['va_eauth_secid'] })
end
end
|
#mvi_ids ⇒ Object
230
231
232
233
234
235
236
237
238
239
|
# File 'lib/saml/user_attributes/ssoe.rb', line 230
def mvi_ids
return @mvi_ids if @mvi_ids
gcids = safe_attr('va_eauth_gcIds')
return {} unless gcids
@mvi_ids = parse_string_gcids(gcids)
end
|
#needs_csp_id_mpi_update? ⇒ Boolean
191
192
193
|
# File 'lib/saml/user_attributes/ssoe.rb', line 191
def needs_csp_id_mpi_update?
idme_uuid == safe_attr('va_eauth_uid') && mvi_ids[:idme_id].blank?
end
|
#safe_attr(key) ⇒ Object
250
251
252
|
# File 'lib/saml/user_attributes/ssoe.rb', line 250
def safe_attr(key)
@attributes[key] == 'NOT_FOUND' ? nil : @attributes[key]
end
|
#sec_id ⇒ Object
90
91
92
|
# File 'lib/saml/user_attributes/ssoe.rb', line 90
def sec_id
safe_attr('va_eauth_secid')
end
|
#sec_id_mismatch? ⇒ Boolean
280
281
282
|
# File 'lib/saml/user_attributes/ssoe.rb', line 280
def sec_id_mismatch?
attribute_has_multiple_values?('va_eauth_secid')
end
|
#should_raise_missing_uuid_error ⇒ Object
226
227
228
|
# File 'lib/saml/user_attributes/ssoe.rb', line 226
def should_raise_missing_uuid_error
idme_uuid.blank? && logingov_uuid.blank?
end
|
#sign_in ⇒ Object
180
181
182
183
184
185
186
187
188
189
|
# File 'lib/saml/user_attributes/ssoe.rb', line 180
def sign_in
sign_in = if authn_context == INBOUND_AUTHN_CONTEXT
{ service_name: csid }
else
SAML::User::AUTHN_CONTEXTS.fetch(authn_context).fetch(:sign_in)
end
sign_in.merge(account_type:,
auth_broker: SAML::URLService::BROKER_CODE,
client_id: tracker&.payload_attr(:application))
end
|
#ssn ⇒ Object
This attribute may sometimes be TIN, Patient identifier, etc. It is not guaranteed to be a SSN
50
51
52
|
# File 'lib/saml/user_attributes/ssoe.rb', line 50
def ssn
safe_attr('va_eauth_pnid')&.delete('-') if safe_attr('va_eauth_pnidtype') == 'SSN'
end
|
#to_hash ⇒ Object
195
196
197
|
# File 'lib/saml/user_attributes/ssoe.rb', line 195
def to_hash
SERIALIZABLE_ATTRIBUTES.index_with { |k| send(k) }.merge(authn_context:)
end
|
#tracker ⇒ Object
293
294
295
|
# File 'lib/saml/user_attributes/ssoe.rb', line 293
def tracker
@tracker ||= SAMLRequestTracker.find(@tracker_uuid)
end
|
#transactionid ⇒ Object
168
169
170
|
# File 'lib/saml/user_attributes/ssoe.rb', line 168
def transactionid
safe_attr('va_eauth_transactionid')
end
|
#uuid ⇒ Object
68
69
70
|
# File 'lib/saml/user_attributes/ssoe.rb', line 68
def uuid
idme_uuid || logingov_uuid
end
|
#validate! ⇒ Object
Raise any fatal exceptions due to validation issues
200
201
202
203
204
205
206
207
208
209
|
# File 'lib/saml/user_attributes/ssoe.rb', line 200
def validate!
multiple_id_validations
if should_raise_missing_uuid_error
data = SAML::UserAttributeError::ERRORS[:uuid_missing]
raise SAML::UserAttributeError.new(code: data[:code],
message: data[:message],
tag: data[:tag],
identifier: mhv_icn)
end
end
|
#verified_at ⇒ Object
only applies to Login.gov IAL2 verification used to automatically upcert IAL1 users without additional service calls
86
87
88
|
# File 'lib/saml/user_attributes/ssoe.rb', line 86
def verified_at
safe_attr('va_eauth_verifiedAt')
end
|
#vha_facility_hash ⇒ Object
176
177
178
|
# File 'lib/saml/user_attributes/ssoe.rb', line 176
def vha_facility_hash
mvi_ids[:vha_facility_hash]
end
|
#vha_facility_ids ⇒ Object
172
173
174
|
# File 'lib/saml/user_attributes/ssoe.rb', line 172
def vha_facility_ids
mvi_ids[:vha_facility_ids]
end
|