Class: V0::SignInController
Constant Summary
ExceptionHandling::SKIP_SENTRY_EXCEPTION_TYPES
SignIn::Authentication::BEARER_PATTERN
Instance Attribute Summary
#current_user
Instance Method Summary
collapse
-
#anti_csrf_token_param ⇒ Object
private
-
#auth_service(type, client_id = nil) ⇒ Object
private
-
#authorize ⇒ Object
rubocop:disable Metrics/MethodLength.
-
#callback ⇒ Object
rubocop:disable Metrics/MethodLength.
-
#client_config(client_id) ⇒ Object
private
-
#cookie_authentication?(client_id) ⇒ Boolean
private
-
#create_login_code(state_payload, user_info, credential_level) ⇒ Object
private
rubocop:disable Metrics/MethodLength.
-
#delete_cookies ⇒ Object
private
-
#handle_credential_provider_error(error, type) ⇒ Object
private
-
#handle_pre_login_error(error, client_id) ⇒ Object
private
-
#logingov_logout_proxy ⇒ Object
-
#logout ⇒ Object
rubocop:disable Metrics/MethodLength.
-
#refresh ⇒ Object
-
#refresh_token_param ⇒ Object
private
-
#render_uplevel_credential(state_payload) ⇒ Object
private
-
#revoke ⇒ Object
-
#revoke_all_sessions ⇒ Object
-
#sign_in_logger ⇒ Object
private
-
#token ⇒ Object
-
#token_cookies ⇒ Object
private
-
#token_params ⇒ Object
private
-
#validate_authorize_params(type, client_id, acr, operation) ⇒ Object
private
-
#validate_callback_params(code, state, error) ⇒ Object
private
#cors_preflight
Methods included from Traceable
#set_trace_tags
#set_tags_and_extra_context, #tags_context, #user_context
#log_exception_to_sentry, #log_message_to_sentry, #non_nil_hash?, #normalize_level, #rails_logger, #set_sentry_metadata
Methods included from Headers
#set_app_info_headers
#render_errors, #report_mapped_exception, #report_original_exception, #skip_sentry_exception?, #skip_sentry_exception_types
#append_info_to_payload, #session
#access_token, #access_token_authenticate, #authenticate, #authenticate_access_token, #bearer_token, #cookie_access_token, #handle_authenticate_error, #load_user, #load_user_object, #scrub_bearer_token, #validate_request_ip
Instance Method Details
#anti_csrf_token_param ⇒ Object
#auth_service(type, client_id = nil) ⇒ Object
#authorize ⇒ Object
rubocop:disable Metrics/MethodLength
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
# File 'app/controllers/v0/sign_in_controller.rb', line 12
def authorize type = params[:type].presence
client_state = params[:state].presence
code_challenge = params[:code_challenge].presence
code_challenge_method = params[:code_challenge_method].presence
client_id = params[:client_id].presence
acr = params[:acr].presence
operation = params[:operation].presence || SignIn::Constants::Auth::AUTHORIZE
scope = params[:scope].presence
validate_authorize_params(type, client_id, acr, operation)
delete_cookies if token_cookies
acr_for_type = SignIn::AcrTranslator.new(acr:, type:).perform
state = SignIn::StatePayloadJwtEncoder.new(code_challenge:,
code_challenge_method:,
acr:,
client_config: client_config(client_id),
type:,
client_state:,
scope:).perform
context = { type:, client_id:, acr:, operation: }
sign_in_logger.info('authorize', context)
StatsD.increment(SignIn::Constants::Statsd::STATSD_SIS_AUTHORIZE_SUCCESS,
tags: ["type:#{type}", "client_id:#{client_id}", "acr:#{acr}", "operation:#{operation}"])
render body: auth_service(type, client_id).render_auth(state:, acr: acr_for_type, operation:),
content_type: 'text/html'
rescue SignIn::Errors::StandardError => e
sign_in_logger.info('authorize error', { errors: e.message, client_id:, type:, acr: })
StatsD.increment(SignIn::Constants::Statsd::STATSD_SIS_AUTHORIZE_FAILURE)
handle_pre_login_error(e, client_id)
rescue => e
log_message_to_sentry(e.message, :error)
StatsD.increment(SignIn::Constants::Statsd::STATSD_SIS_AUTHORIZE_FAILURE)
handle_pre_login_error(e, client_id)
end
|
#callback ⇒ Object
rubocop:disable Metrics/MethodLength
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
# File 'app/controllers/v0/sign_in_controller.rb', line 52
def callback code = params[:code].presence
state = params[:state].presence
error = params[:error].presence
validate_callback_params(code, state, error)
state_payload = SignIn::StatePayloadJwtDecoder.new(state_payload_jwt: state).perform
SignIn::StatePayloadVerifier.new(state_payload:).perform
handle_credential_provider_error(error, state_payload&.type) if error
service_token_response = auth_service(state_payload.type, state_payload.client_id).token(code)
raise SignIn::Errors::CodeInvalidError.new message: 'Code is not valid' unless service_token_response
user_info = auth_service(state_payload.type,
state_payload.client_id).user_info(service_token_response[:access_token])
credential_level = SignIn::CredentialLevelCreator.new(requested_acr: state_payload.acr,
type: state_payload.type,
logingov_acr: service_token_response[:logingov_acr],
user_info:).perform
if credential_level.can_uplevel_credential?
render_uplevel_credential(state_payload)
else
create_login_code(state_payload, user_info, credential_level)
end
rescue SignIn::Errors::StandardError => e
sign_in_logger.info('callback error', { errors: e.message,
client_id: state_payload&.client_id,
type: state_payload&.type,
acr: state_payload&.acr })
StatsD.increment(SignIn::Constants::Statsd::STATSD_SIS_CALLBACK_FAILURE)
handle_pre_login_error(e, state_payload&.client_id)
rescue => e
log_message_to_sentry(e.message, :error)
StatsD.increment(SignIn::Constants::Statsd::STATSD_SIS_CALLBACK_FAILURE)
handle_pre_login_error(e, state_payload&.client_id)
end
|
#client_config(client_id) ⇒ Object
354
355
356
357
|
# File 'app/controllers/v0/sign_in_controller.rb', line 354
def client_config(client_id)
@client_config ||= {}
@client_config[client_id] ||= SignIn::ClientConfig.find_by(client_id:)
end
|
#cookie_authentication?(client_id) ⇒ Boolean
350
351
352
|
# File 'app/controllers/v0/sign_in_controller.rb', line 350
def cookie_authentication?(client_id)
client_config(client_id)&.cookie_auth?
end
|
#create_login_code(state_payload, user_info, credential_level) ⇒ Object
rubocop:disable Metrics/MethodLength
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
|
# File 'app/controllers/v0/sign_in_controller.rb', line 294
def create_login_code(state_payload, user_info, credential_level) user_attributes = auth_service(state_payload.type,
state_payload.client_id).normalized_attributes(user_info, credential_level)
verified_icn = SignIn::AttributeValidator.new(user_attributes:).perform
user_code_map = SignIn::UserCodeMapCreator.new(
user_attributes:, state_payload:, verified_icn:, request_ip: request.remote_ip
).perform
context = {
type: state_payload.type,
client_id: state_payload.client_id,
ial: credential_level.current_ial,
acr: state_payload.acr,
icn: verified_icn,
user_uuid: user_info.sub,
authentication_time: Time.zone.now.to_i - state_payload.created_at
}
sign_in_logger.info('callback', context)
StatsD.increment(SignIn::Constants::Statsd::STATSD_SIS_CALLBACK_SUCCESS,
tags: ["type:#{state_payload.type}",
"client_id:#{state_payload.client_id}",
"ial:#{credential_level.current_ial}",
"acr:#{state_payload.acr}"])
params_hash = { code: user_code_map.login_code, type: user_code_map.type }
params_hash.merge!(state: user_code_map.client_state) if user_code_map.client_state.present?
render body: SignIn::RedirectUrlGenerator.new(redirect_uri: user_code_map.client_config.redirect_uri,
terms_code: user_code_map.terms_code,
terms_redirect_uri: user_code_map.client_config.terms_of_use_url,
params_hash:).perform,
content_type: 'text/html'
end
|
#handle_credential_provider_error(error, type) ⇒ Object
#handle_pre_login_error(error, client_id) ⇒ Object
254
255
256
257
258
259
260
261
262
263
264
|
# File 'app/controllers/v0/sign_in_controller.rb', line 254
def handle_pre_login_error(error, client_id)
if cookie_authentication?(client_id)
error_code = error.try(:code) || SignIn::Constants::ErrorCode::INVALID_REQUEST
params_hash = { auth: 'fail', code: error_code, request_id: request.request_id }
render body: SignIn::RedirectUrlGenerator.new(redirect_uri: client_config(client_id).redirect_uri,
params_hash:).perform,
content_type: 'text/html'
else
render json: { errors: error }, status: :bad_request
end
end
|
#logingov_logout_proxy ⇒ Object
214
215
216
217
218
219
220
221
222
223
224
225
|
# File 'app/controllers/v0/sign_in_controller.rb', line 214
def logingov_logout_proxy
state = params[:state].presence
raise SignIn::Errors::MalformedParamsError.new message: 'State is not defined' unless state
render body: auth_service(SignIn::Constants::Auth::LOGINGOV).render_logout_redirect(state),
content_type: 'text/html'
rescue => e
sign_in_logger.info('logingov_logout_proxy error', { errors: e.message })
render json: { errors: e }, status: :bad_request
end
|
#logout ⇒ Object
rubocop:disable Metrics/MethodLength
#refresh_token_param ⇒ Object
#render_uplevel_credential(state_payload) ⇒ Object
282
283
284
285
286
287
288
289
290
291
292
|
# File 'app/controllers/v0/sign_in_controller.rb', line 282
def render_uplevel_credential(state_payload)
acr_for_type = SignIn::AcrTranslator.new(acr: state_payload.acr, type: state_payload.type, uplevel: true).perform
state = SignIn::StatePayloadJwtEncoder.new(code_challenge: state_payload.code_challenge,
code_challenge_method: SignIn::Constants::Auth::CODE_CHALLENGE_METHOD,
acr: state_payload.acr,
client_config: client_config(state_payload.client_id),
type: state_payload.type,
client_state: state_payload.client_state).perform
render body: auth_service(state_payload.type, state_payload.client_id).render_auth(state:, acr: acr_for_type),
content_type: 'text/html'
end
|
#revoke_all_sessions ⇒ Object
#sign_in_logger ⇒ Object
359
360
361
|
# File 'app/controllers/v0/sign_in_controller.rb', line 359
def sign_in_logger
@sign_in_logger = SignIn::Logger.new(prefix: self.class)
end
|
#token_cookies ⇒ Object
335
336
337
|
# File 'app/controllers/v0/sign_in_controller.rb', line 335
def token_cookies
@token_cookies ||= defined?(cookies) ? cookies : nil
end
|
#token_params ⇒ Object
249
250
251
252
|
# File 'app/controllers/v0/sign_in_controller.rb', line 249
def token_params
params.permit(:grant_type, :code, :code_verifier, :client_assertion, :client_assertion_type,
:assertion, :subject_token, :subject_token_type, :actor_token, :actor_token_type, :client_id)
end
|
#validate_authorize_params(type, client_id, acr, operation) ⇒ Object
#validate_callback_params(code, state, error) ⇒ Object