Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DPC-4244 logout of login #2263

Merged
merged 10 commits into from
Sep 9, 2024
2 changes: 2 additions & 0 deletions dpc-portal/app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

# Parent class of all controllers
class ApplicationController < ActionController::Base
IDP_HOST = ENV.fetch('IDP_HOST')
IDP_CLIENT_ID = "urn:gov:cms:openidconnect.profiles:sp:sso:cms:dpc:#{ENV.fetch('ENV')}".freeze
before_action :block_prod_sbx
before_action :check_session_length
before_action :set_current_request_attributes
Expand Down
5 changes: 2 additions & 3 deletions dpc-portal/app/controllers/invitations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,10 @@ def login
Rails.logger.info(['User began login flow',
{ actionContext: LoggingConstants::ActionContext::Registration,
actionType: LoggingConstants::ActionType::BeginLogin }])
client_id = "urn:gov:cms:openidconnect.profiles:sp:sso:cms:dpc:#{ENV.fetch('ENV')}"
url = URI::HTTPS.build(host: ENV.fetch('IDP_HOST'),
url = URI::HTTPS.build(host: IDP_HOST,
path: '/openid_connect/authorize',
query: { acr_values: 'http://idmanagement.gov/ns/assurance/ial/2',
client_id:,
client_id: IDP_CLIENT_ID,
redirect_uri: "#{redirect_host}/portal/users/auth/openid_connect/callback",
response_type: 'code',
scope: 'openid email all_emails profile phone social_security_number',
Expand Down
4 changes: 4 additions & 0 deletions dpc-portal/app/controllers/login_dot_gov_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ def failure
end
end

def logged_out
redirect_to session.delete(:user_return_to) || new_user_session_path
end

private

def handle_invitation_flow_failure(invitation_id)
Expand Down
9 changes: 8 additions & 1 deletion dpc-portal/app/controllers/users/sessions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,14 @@ def destroy
Rails.logger.info(['User logged out',
{ actionContext: LoggingConstants::ActionContext::Authentication,
actionType: LoggingConstants::ActionType::UserLoggedOut }])
super
session['omniauth.state'] = @state = SecureRandom.hex(16)
sign_out(current_user)
url = URI::HTTPS.build(host: IDP_HOST,
path: '/openid_connect/logout',
query: { client_id: IDP_CLIENT_ID,
post_logout_redirect_uri: "#{root_url}users/auth/logged_out",
state: @state }.to_query)
redirect_to url, allow_other_host: true
end
end
end
3 changes: 2 additions & 1 deletion dpc-portal/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
# and config.ru via config.relative_url_root.
#
Rails.application.routes.draw do
devise_for :users, controllers: { omniauth_callbacks: 'login_dot_gov' }
devise_for :users, controllers: { sessions: 'users/sessions', omniauth_callbacks: 'login_dot_gov' }
devise_scope :user do
get '/users/auth/failure', to: 'login_dot_gov#failure', as: 'login_dot_gov_failure'
get '/users/auth/logged_out', to: 'login_dot_gov#logged_out', as: 'login_dot_gov_logged_out'
get 'active', to: 'users/sessions#active'
get 'timeout', to: 'users/sessions#timeout'
end
Expand Down
77 changes: 45 additions & 32 deletions dpc-portal/spec/requests/login_dot_gov_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,45 +3,45 @@
require 'rails_helper'

RSpec.describe 'LoginDotGov', type: :request do
RSpec.shared_examples 'an openid client' do
context 'user exists' do
before { create(:user, uid: '12345', provider: 'openid_connect', email: 'bob@example.com') }
it 'should sign in a user' do
post '/users/auth/openid_connect'
follow_redirect!
expect(response.location).to eq organizations_url
expect(response).to be_redirect
follow_redirect!
expect(response).to be_ok
end
it 'should log on successful sign in' do
allow(Rails.logger).to receive(:info)
expect(Rails.logger).to receive(:info).with(['User logged in',
{ actionContext: LoggingConstants::ActionContext::Authentication,
actionType: LoggingConstants::ActionType::UserLoggedIn }])
post '/users/auth/openid_connect'
follow_redirect!
end
it 'should not add another user' do
expect(User.where(uid: '12345', provider: 'openid_connect').count).to eq 1
expect do
describe 'POST /users/auth/openid_connect' do
RSpec.shared_examples 'an openid client' do
context 'user exists' do
before { create(:user, uid: '12345', provider: 'openid_connect', email: 'bob@example.com') }
it 'should sign in a user' do
post '/users/auth/openid_connect'
follow_redirect!
end.to change { User.count }.by(0)
end
end

context 'user does not exist' do
it 'should not persist user' do
expect do
expect(response.location).to eq organizations_url
expect(response).to be_redirect
follow_redirect!
expect(response).to be_ok
end
it 'should log on successful sign in' do
allow(Rails.logger).to receive(:info)
expect(Rails.logger).to receive(:info).with(['User logged in',
{ actionContext: LoggingConstants::ActionContext::Authentication,
actionType: LoggingConstants::ActionType::UserLoggedIn }])
post '/users/auth/openid_connect'
follow_redirect!
end.to change { User.count }.by(0)
end
it 'should not add another user' do
expect(User.where(uid: '12345', provider: 'openid_connect').count).to eq 1
expect do
post '/users/auth/openid_connect'
follow_redirect!
end.to change { User.count }.by(0)
end
end

context 'user does not exist' do
it 'should not persist user' do
expect do
post '/users/auth/openid_connect'
follow_redirect!
end.to change { User.count }.by(0)
end
end
end
end

describe 'POST /users/auth/openid_connect' do
let(:token) { 'bearer-token' }
context 'IAL/2' do
before do
Expand Down Expand Up @@ -181,4 +181,17 @@
get '/users/auth/failure'
end
end

describe 'GET /users/auth/logged_out' do
it 'should go to sign in page' do
get '/users/auth/logged_out'
expect(response).to redirect_to(new_user_session_path)
expect(flash).to be_empty
end
it 'should go to bespoke page if set' do
get '/organizations'
get '/users/auth/logged_out'
expect(response).to redirect_to(organizations_path)
end
end
end
35 changes: 35 additions & 0 deletions dpc-portal/spec/requests/users/sessions_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# frozen_string_literal: true

require 'rails_helper'

RSpec.describe 'Users::Sessions', type: :request do
describe 'logout' do
context 'logged in' do
let!(:user) { create(:user) }
before do
sign_in user
end
it 'should prevent access' do
delete '/users/sign_out'
get '/organizations'
expect(response).to redirect_to('/portal/users/sign_in')
expect(flash[:alert]).to be_present
end

it 'should log action' do
allow(Rails.logger).to receive(:info)
expect(Rails.logger).to receive(:info).with(
['User logged out',
{ actionContext: LoggingConstants::ActionContext::Authentication,
actionType: LoggingConstants::ActionType::UserLoggedOut }]
)
delete '/users/sign_out'
end

it 'should redirect to login.gov' do
delete '/users/sign_out'
expect(response.location).to include(ENV.fetch('IDP_HOST'))
end
end
end
end
Loading