Commit c031428

mo <mo.khan@gmail.com>
2018-09-03 22:53:14
extract responses controller to generate saml response from one place.
1 parent 7138137
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