Commit c031428
Changed files (5)
app
controllers
views
sessions
spec
requests
app/controllers/responses_controller.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+class ResponsesController < ApplicationController
+ def show
+ if session[:saml].present?
+ saml_request = Saml::Kit::AuthenticationRequest.new(session[:saml][:xml])
+ if saml_request.invalid?
+ return render_error(:forbidden, model: saml_request)
+ end
+ post_back(saml_request)
+ else
+ redirect_to my_dashboard_path
+ end
+ end
+
+ private
+
+ def post_back(saml_request)
+ relay_state = session[:saml][:params][:RelayState]
+ @url, @saml_params = saml_request.response_for(
+ current_user, binding: :http_post, relay_state: relay_state
+ ) do |builder|
+ @saml_response_builder = builder
+ end
+ render template: 'sessions/create'
+ end
+end
app/controllers/sessions_controller.rb
@@ -23,17 +23,8 @@ class SessionsController < ApplicationController
def create
user_params = params.require(:user).permit(:email, :password)
if (user = User.login(user_params[:email], user_params[:password]))
- unless session[:saml].present?
- login(user)
- return redirect_to(my_dashboard_path)
- end
-
- saml_request = Saml::Kit::AuthenticationRequest.new(session[:saml][:xml])
- if saml_request.invalid?
- render_error(:forbidden, model: saml_request)
- else
- post_back(saml_request, user)
- end
+ login(user)
+ redirect_to response_path
else
redirect_to new_session_path, error: "Invalid Credentials"
end
@@ -80,7 +71,9 @@ class SessionsController < ApplicationController
end
def login(user)
+ saml_data = session[:saml]
reset_session
session[:user_id] = user.to_param
+ session[:saml] = saml_data
end
end
app/views/sessions/create.html.erb
@@ -1,1 +1,1 @@
-<%= render partial: "response" %>
+<%= render partial: "sessions/response" %>
spec/requests/response_spec.rb
@@ -0,0 +1,59 @@
+require 'rails_helper'
+
+RSpec.describe "/response" do
+ describe 'GET /response' do
+ context "when the user has not completed password authentication" do
+ before { get '/response' }
+
+ specify { expect(response).to redirect_to(new_session_path) }
+ end
+
+ context "when the user has completed password authentication" do
+ let(:current_user) { create(:user) }
+
+ before { http_login(current_user) }
+
+ context "when a saml request was present in session" do
+ let(:registry) { Saml::Kit::DefaultRegistry.new }
+ let(:issuer) { Saml::Kit.configuration.entity_id }
+ let(:redirect_binding) { Saml::Kit::Bindings::HttpRedirect.new(location: new_session_url) }
+ let(:relay_state) { SecureRandom.uuid }
+ let(:sp_metadata) do
+ Saml::Kit::ServiceProviderMetadata.build do |x|
+ x.add_assertion_consumer_service(FFaker::Internet.uri("https"), binding: :http_post)
+ x.add_single_logout_service(FFaker::Internet.uri("https"), binding: :http_post)
+ end
+ end
+
+ before :each do
+ Saml::Kit.configuration.registry = registry
+ allow(registry).to receive(:metadata_for).with(issuer).and_return(sp_metadata)
+ get redirect_binding.serialize(Saml::Kit::AuthenticationRequest.builder, relay_state: relay_state)[0]
+ end
+
+ context "when the saml request is still valid" do
+ before { get '/response' }
+
+ specify { expect(response).to have_http_status(:ok) }
+ specify { expect(response.body).to include(sp_metadata.assertion_consumer_service_for(binding: :http_post).location) }
+ specify { expect(response.body).to include('SAMLResponse') }
+ specify { expect(response.body).to include('RelayState') }
+ specify { expect(response.body).to include(relay_state) }
+ end
+
+ context "when the SAML request is no longer valid" do
+ before { allow_any_instance_of(Saml::Kit::AuthenticationRequest).to receive(:valid?).and_return(false) }
+ before { get '/response' }
+
+ specify { expect(response).to have_http_status(:forbidden) }
+ end
+ end
+
+ context "when a saml request was not present in session" do
+ before { get '/response' }
+
+ specify { expect(response).to redirect_to(my_dashboard_path) }
+ end
+ end
+ end
+end
spec/requests/sessions_spec.rb
@@ -138,7 +138,7 @@ describe SessionsController do
context "when a SAMLRequest is not present" do
context "when the credentials are correct" do
before { post '/session', params: { user: { email: user.email, password: password } } }
- specify { expect(response).to redirect_to(my_dashboard_path) }
+ specify { expect(response).to redirect_to(response_path) }
end
context "when the credentials are incorrect" do
@@ -161,18 +161,9 @@ describe SessionsController do
context "when the credentials are correct" do
before { post '/session', params: { user: { email: user.email, password: password } } }
- specify { expect(response).to have_http_status(:ok) }
- specify { expect(response.body).to include(sp_metadata.assertion_consumer_service_for(binding: :http_post).location) }
- specify { expect(response.body).to include('SAMLResponse') }
- specify { expect(response.body).to include('RelayState') }
- specify { expect(response.body).to include(relay_state) }
- end
-
- context "when the credentials are correct but the SAML request is no longer valid" do
- before { allow_any_instance_of(Saml::Kit::AuthenticationRequest).to receive(:valid?).and_return(false) }
- before { post '/session', params: { user: { email: user.email, password: password } } }
-
- specify { expect(response).to have_http_status(:forbidden) }
+ specify { expect(response).to redirect_to(response_path) }
+ specify { expect(session[:saml]).to be_present }
+ specify { expect(session[:saml][:params][:RelayState]).to eql(relay_state) }
end
context "when the credentials are incorrect" do