Skip to content

Commit

Permalink
Mocked auth views (#12444)
Browse files Browse the repository at this point in the history
* mocked_auth ERB files

* 53352 - moves mocked_users controller to credential; fix templating + routes + credential/service

* updates authorize callback to include state + encoded_credential

* updates mocked_auth routes.rb; adds JS to credential#index

* updates verbage in template; fixes formatting in mock_auth/lib/credential/service

* updates specs for lib/credential/service_spec.rb

* changes mock_auth view to only show credential_payload

* adds validate_credential_list_params check + updates validate_index_params

* adds credential#index spec; adds resuce error json; fixes linting issue

* fix linting of rescue json vs html

* fix linting issue 2nd

* [53015] Updating mocked auth credential specs

---------

Co-authored-by: Trevor Bosaw <[email protected]>
  • Loading branch information
asg5704 and Trevor Bosaw authored Apr 24, 2023
1 parent 052c5ae commit 584154b
Show file tree
Hide file tree
Showing 8 changed files with 291 additions and 4 deletions.
2 changes: 1 addition & 1 deletion config/settings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ sign_in:
cookies_secure: false
info_cookie_domain: localhost
auto_uplevel: true
mock_auth_url: http://localhost:3000/mock_auth_frontend
mock_auth_url: http://localhost:3000/mocked_authentication/profiles
mock_redirect_uri: http://localhost:3000/v0/sign_in/callback
mock_credential_dir: '../vets-api-mockdata'
mockdata_sync_api_key: ~
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,29 @@ def authorize
def credential_list
type = params[:type].presence

validate_index_params(type)
validate_credential_list_params(type)
mock_profiles = Mockdata::Reader.find_credentials(credential_type: type)

render json: { mock_profiles: }
rescue => e
render json: { errors: e }, status: :bad_request
end

def index
type = params[:type].presence
state = params[:state].presence

validate_index_params(type, state)
@mock_profiles = Mockdata::Reader.find_credentials(credential_type: type)
@state = state

respond_to do |format|
format.html
end
rescue => e
render json: { errors: e }, status: :bad_request
end

private

def validate_authorize_params(credential_info, state, error)
Expand All @@ -38,7 +53,14 @@ def validate_authorize_params(credential_info, state, error)
end
end

def validate_index_params(type)
def validate_index_params(type, state)
raise SignIn::Errors::MalformedParamsError.new message: 'State is not defined' unless state
unless SignIn::Constants::Auth::CSP_TYPES.include?(type)
raise SignIn::Errors::MalformedParamsError.new message: 'Invalid credential provider type'
end
end

def validate_credential_list_params(type)
unless SignIn::Constants::Auth::CSP_TYPES.include?(type)
raise SignIn::Errors::MalformedParamsError.new message: 'Invalid credential provider type'
end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<!DOCTYPE html>
<html>
<%= yield %>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="robots" content="none" />
<title>VA.gov | Mocked Authentication</title>
<link
href="https://unpkg.com/@department-of-veterans-affairs/formation/dist/formation.min.css"
rel="stylesheet"
crossorigin="anonymous"
/>
</head>
<style>
body { min-height: 100vh; margin: 0; display: flex; flex-direction: column; }
main { flex: 1 }
.content div:first-of-type > h2 { margin-top: 0; }
.container { margin: 0 auto; padding: 60px 16px; }

.code-block {
font-family: Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console",
"Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono",
"Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier,
monospace;
background: #d9d9d9;
overflow-y: scroll;
max-height: 600px;
}

pre {
white-space: pre-wrap;
overflow-x: auto;
tab-size: 4;
}

code {
overflow-wrap: break-word;
display: block;
color: #333;
padding: 0 2em;
margin: -24px 0;
}

header {
position: absolute;
width: 100%;
top: 0; left: 0;
text-align: center;
}

.header-container {
min-height: 85px;
padding-top: 1em;
background: #112e51;
color: #fff;
}

footer {
height: 2.5rem;
width: 100%;
bottom: 0;
text-align: center;
}

@media screen and (min-width: 1600px) {
main {
display: flex;
justify-content: center;
align-items: center;
}

.container {
margin: 6em auto 0;
max-width: 1400px;
display: grid;
grid-template-columns: 600px 700px;
grid-template-rows: 1fr;
}
}
</style>
<body>
<noscript>
<p>
Your browser does not support JavaScript or you do not have JavaScript
enabled. Please press the Continue button once to proceed with sign-in.
</p>
</noscript>
<header>
<div class="header-container">
<h1>Mocked Authentication</h1>
</div>
</header>
<main>
<div class="container">
<section class="content">
<div>
<h2>Select a profile to continue</h2>
<p>
Select a mock user profile from the dropdown below to continue with the mocked authentication flow. <em>(*Available only in the local and development environments)</em>
</p>
<form>
<label for="profiles">
<select id="profiles_select">
<option value="">Select a profile</option>
<% @mock_profiles.each do |profile_name, profile| %>
<option value="<%= profile[:encoded_credential] %>">
<%= profile[:credential_payload]['email'] %>
</option>
<% end %>
</select>
</label>
<button id="authorize">Continue signing in</button>
</form>
</div>
<div>
<h2>Mock user profile not what you expected?</h2>
<p>
Use the instructions found in the
<a
href="https://github.com/department-of-veterans-affairs/vets-api-mockdata"
rel="noopener noreferrer"
target="_blank"
>
vets-api-mockdata repo</a> to create and/or update a mocked user.
</p>
</div>
<div>
<h2>What is Mocked Authentication?</h2>
<p>
Read through our
<a
href="https://github.com/department-of-veterans-affairs/vets-api-mockdata"
rel="noopener noreferrer"
target="_blank"
>documentation</a
>
to find more information on how to use Mocked Authentication.
</p>
</div>
</section>
<div class="code-block">
<pre>
<code id="selected_profile"></code>
</pre>
</div>
</div>
</main>
<footer>
Need help? Reach out in the
<a
href="slack://app.slack.com/client/T03FECE8V/CSFV4QTKN"
rel="noopener noreferrer"
target="_blank"
>
#vsp-identity Slack
</a>
channel.
</footer>
<script>
document.addEventListener('DOMContentLoaded', () => {
const profileSelectDropdown = document.getElementById('profiles_select')
const selectedProfileCode = document.getElementById('selected_profile');
const authorizeBtn = document.getElementById('authorize');
const profiles = <%= raw(@mock_profiles.to_json) %>;
const currentUri = new URL(window.location);
let currentlySelected = {};

if(!currentUri.searchParams.has('state') || !Object.keys(currentlySelected).length) {
const copyOfCurrentlySelected =
selectedProfileCode.innerText = JSON.stringify(currentlySelected.credential_payload || {}, null, 2);
authorizeBtn.disabled = true;
}

profileSelectDropdown
.addEventListener('change', e => {
currentlySelected = Object.values(profiles).find(({ encoded_credential }) => encoded_credential === e.target.value) || {}
selectedProfileCode.innerText = JSON.stringify(currentlySelected.credential_payload ?? {}, null, 2);
authorizeBtn.disabled = !Object.keys(currentlySelected).length ? true : false;
})

authorizeBtn
.addEventListener('click', e => {
e.preventDefault();
const url = `authorize/?state=<%= @state %>&credential_info=${currentlySelected.encoded_credential}`
window.location = url;
})
})
</script>
</body>
2 changes: 2 additions & 0 deletions modules/mocked_authentication/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@
get '/authorize', to: 'credential#authorize'
get '/credential_list', to: 'credential#credential_list'
end

get '/profiles', to: 'credential#index'
end
3 changes: 2 additions & 1 deletion modules/mocked_authentication/lib/credential/service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ def render_auth(state:, acr:)
url: Settings.sign_in.mock_auth_url,
params:
{
type:,
acr_values: acr,
mock_redirect_uri: Settings.sign_in.mock_auth_redirect,
mock_redirect_uri: Settings.sign_in.mock_redirect_uri,
state:
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

let(:state) { 'some-state' }
let(:acr) { 'some-acr' }
let(:type) { 'some-type' }
let(:expected_redirect_url) { Settings.sign_in.mock_auth_url }

it 'renders the oauth_get_form template' do
Expand All @@ -28,6 +29,10 @@
expect(subject.to_s).to include("value=\"#{acr}\"")
end

it 'renders type value' do
expect(subject.to_s).to include("value=\"#{type}\"")
end

it 'directs to the Mocked Authorization frontend page' do
expect(subject.to_s).to include("action=\"#{expected_redirect_url}\"")
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,4 +207,69 @@
end
end
end

describe 'GET index' do
subject { get(index_path, params: index_params) }

let(:index_path) { '/mocked_authentication/profiles' }
let(:index_params) { { type: credential_type, state: passed_state } }
let(:credential_type) { 'logingov' }
let(:passed_state) { 'some-state' }

shared_examples 'error response' do
let(:expected_status) { :bad_request }
let(:expected_error_hash) { { 'errors' => expected_error_message } }

it 'returns expected status' do
subject
expect(response).to have_http_status(expected_status)
end
end

shared_examples 'successful response' do
let(:expected_status) { :ok }
let(:html_title) { '<title>VA.gov | Mocked Authentication</title>' }

it 'returns expected status' do
subject
expect(response).to have_http_status(expected_status)
end

it 'returns expected html' do
subject
expect(response.body).to include(html_title)
end
end

context 'parameter validations' do
context 'when CSP type parameter is missing' do
let(:credential_type) { nil }
let(:expected_error_message) { 'Invalid credential provider type' }

it_behaves_like 'error response'
end

context 'when CSP type parameter is not included in CSP_TYPES' do
let(:credential_type) { 'some-csp-type' }
let(:expected_error_message) { 'Invalid credential provider type' }

it_behaves_like 'error response'
end

context 'when CSP type parameter is included in CSP_TYPES' do
let(:credential_type) { 'logingov' }

context 'and state is not defined' do
let(:passed_state) { {} }
let(:expected_error_message) { 'State is not defined' }

it_behaves_like 'error response'
end

context 'and state parameter is included' do
it_behaves_like 'successful response'
end
end
end
end
end

0 comments on commit 584154b

Please sign in to comment.