Module: AuthenticationAndSSOConcerns

Extended by:
ActiveSupport::Concern
Includes:
ActionController::Cookies, SignIn::AudienceValidator, SignIn::Authentication
Included in:
ApplicationController
Defined in:
app/controllers/concerns/authentication_and_sso_concerns.rb

Overview

This module only gets mixed in to one place, but is that cleanest way to organize everything in one place related to this responsibility alone.

Constant Summary

Constants included from SignIn::Authentication

SignIn::Authentication::BEARER_PATTERN

Instance Method Summary collapse

Methods included from SignIn::AudienceValidator

#validate_audience!

Methods included from SignIn::Authentication

#access_token, #access_token_authenticate, #authenticate_access_token, #bearer_token, #cookie_access_token, #handle_authenticate_error, #load_user_object, #scrub_bearer_token, #validate_request_ip

Instance Method Details

#authenticateObject (protected)



19
20
21
22
23
24
25
# File 'app/controllers/concerns/authentication_and_sso_concerns.rb', line 19

def authenticate
  if cookies[SignIn::Constants::Auth::ACCESS_TOKEN_COOKIE_NAME]
    super
  else
    validate_session || render_unauthorized
  end
end

#clear_sessionObject (protected)

Destroys the user’s session in Redis



71
72
73
74
75
76
77
78
# File 'app/controllers/concerns/authentication_and_sso_concerns.rb', line 71

def clear_session
  Rails.logger.debug('SSO: ApplicationController#clear_session', sso_logging_info)

  @session_object&.destroy
  @current_user&.destroy
  @session_object = nil
  @current_user = nil
end

#extend_session!Object (protected)

Extends the users session



93
94
95
96
97
# File 'app/controllers/concerns/authentication_and_sso_concerns.rb', line 93

def extend_session!
  @session_object.expire(Session.redis_namespace_ttl)
  @current_user&.identity&.expire(UserIdentity.redis_namespace_ttl)
  @current_user&.expire(User.redis_namespace_ttl)
end

#load_user(skip_terms_check: false) ⇒ Object (protected)



61
62
63
64
65
66
67
68
# File 'app/controllers/concerns/authentication_and_sso_concerns.rb', line 61

def load_user(skip_terms_check: false)
  if cookies[SignIn::Constants::Auth::ACCESS_TOKEN_COOKIE_NAME]
    super()
  else
    set_session_object
    set_current_user(skip_terms_check)
  end
end

#log_sso_infoObject (protected)



111
112
113
114
115
116
117
# File 'app/controllers/concerns/authentication_and_sso_concerns.rb', line 111

def log_sso_info
  action = "#{self.class}##{action_name}"

  Rails.logger.info(
    "#{action} request completed", sso_logging_info
  )
end

#render_unauthorizedObject (protected)



27
28
29
# File 'app/controllers/concerns/authentication_and_sso_concerns.rb', line 27

def render_unauthorized
  raise Common::Exceptions::Unauthorized
end

#reset_sessionObject (protected)

Destroys the users session in 1) Redis, 2) the MHV SSO Cookie, 3) and the Session Cookie



81
82
83
84
85
86
87
88
89
90
# File 'app/controllers/concerns/authentication_and_sso_concerns.rb', line 81

def reset_session
  if Settings.test_user_dashboard.env == 'staging' && @current_user
    TestUserDashboard::UpdateUser.new(@current_user).call
    TestUserDashboard::AccountMetrics.new(@current_user).checkin
  end
  Rails.logger.info('SSO: ApplicationController#reset_session', sso_logging_info)

  clear_session
  super
end

#set_api_cookie!Object (protected)

Sets a cookie “api_session” with all of the key/value pairs from session object.



100
101
102
103
104
105
# File 'app/controllers/concerns/authentication_and_sso_concerns.rb', line 100

def set_api_cookie!
  return unless @session_object

  session.delete :value
  @session_object.to_hash.each { |k, v| session[k] = v }
end

#set_current_user(skip_terms_check) ⇒ Object (private)



132
133
134
135
136
137
# File 'app/controllers/concerns/authentication_and_sso_concerns.rb', line 132

def set_current_user(skip_terms_check)
  return unless @session_object

  user = User.find(@session_object.uuid)
  @current_user = user if (skip_terms_check || !user&.needs_accepted_terms_of_use) && !user&.credential_lock
end

#set_session_expiration_headerObject (protected)



107
108
109
# File 'app/controllers/concerns/authentication_and_sso_concerns.rb', line 107

def set_session_expiration_header
  headers['X-Session-Expiration'] = @session_object.ttl_in_time.httpdate if @session_object.present?
end

#set_session_objectObject (private)



128
129
130
# File 'app/controllers/concerns/authentication_and_sso_concerns.rb', line 128

def set_session_object
  @session_object = Session.find(session[:token])
end

#sign_in_service_exp_timeObject (private)



149
150
151
# File 'app/controllers/concerns/authentication_and_sso_concerns.rb', line 149

def 
  .refresh_expiration.iso8601(0)
end

#sign_in_service_sessionObject (private)



153
154
155
156
157
# File 'app/controllers/concerns/authentication_and_sso_concerns.rb', line 153

def 
  return unless @access_token

  @sign_in_service_session ||= SignIn::OAuthSession.find_by(handle: @access_token.session_handle)
end


139
140
141
142
143
144
145
146
147
# File 'app/controllers/concerns/authentication_and_sso_concerns.rb', line 139

def sso_cookie_content
  return nil if @current_user.blank?

  { 'patientIcn' => @current_user.icn,
    'signIn' => @current_user.identity..deep_transform_keys { |key| key.to_s.camelize(:lower) },
    'credential_used' => @current_user.identity.[:service_name],
    'session_uuid' =>  ? @access_token.session_handle : @session_object.token,
    'expirationTime' =>  ?  : @session_object.ttl_in_time.iso8601(0) }
end

#sso_logging_infoObject (protected)

Info for logging purposes related to SSO.



120
121
122
123
124
# File 'app/controllers/concerns/authentication_and_sso_concerns.rb', line 120

def sso_logging_info
  { user_uuid: @current_user&.uuid,
    sso_cookie_contents: sso_cookie_content,
    request_host: request.host }
end

#validate_inbound_login_paramsObject (protected)



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'app/controllers/concerns/authentication_and_sso_concerns.rb', line 31

def 
  csp_type = params[:csp_type] ||= ''
  if csp_type == SAML::User::LOGINGOV_CSID
    ial = params[:ial]
    raise Common::Exceptions::ParameterMissing, 'ial' if ial.blank?
    raise Common::Exceptions::InvalidFieldValue.new('ial', ial) if %w[1 2].exclude?(ial)

    ial == '1' ? IAL::LOGIN_GOV_IAL1 : IAL::LOGIN_GOV_IAL2
  else
    authn = params[:authn]
    raise Common::Exceptions::ParameterMissing, 'authn' if authn.blank?
    raise Common::Exceptions::InvalidFieldValue.new('authn', authn) if SAML::User::AUTHN_CONTEXTS.keys.exclude?(authn)

    authn
  end
end

#validate_sessionObject (protected)



48
49
50
51
52
53
54
55
56
57
58
59
# File 'app/controllers/concerns/authentication_and_sso_concerns.rb', line 48

def validate_session
  load_user

  if @session_object.nil?
    Rails.logger.debug('SSO: INVALID SESSION', sso_logging_info)
    clear_session
    return false
  end

  extend_session!
  @current_user.present?
end