Commit b4ca282

mo <mo.khan@gmail.com>
2018-09-09 22:05:48
generate logout response in response controller.
1 parent d319be7
Changed files (3)
app/controllers/responses_controller.rb
@@ -3,7 +3,12 @@
 class ResponsesController < ApplicationController
   def show
     if session[:saml].present?
-      saml = Saml::Kit::AuthenticationRequest.new(session[:saml][:xml])
+      xml = session[:saml][:xml]
+      saml = if session[:saml][:type] == 'authnrequest'
+               Saml::Kit::AuthenticationRequest.new(xml)
+             else
+               Saml::Kit::LogoutRequest.new(xml)
+             end
       return render_error(:forbidden, model: saml) if saml.invalid?
       post_back(saml, session[:saml][:params][:RelayState])
     else
@@ -14,10 +19,24 @@ class ResponsesController < ApplicationController
   private
 
   def post_back(saml, relay_state)
-    @url, @saml_params = saml.response_for(
-      current_user, binding: :http_post, relay_state: relay_state
-    ) do |builder|
-      @saml_response_builder = builder
+    if saml.is_a?(Saml::Kit::AuthenticationRequest)
+      @url, @saml_params = saml.response_for(
+        current_user, binding: :http_post, relay_state: relay_state
+      ) do |builder|
+        @saml_response_builder = builder
+      end
+      user_id = current_user.to_param
+      mfa_issued_at = session[:mfa].present? ? session[:mfa][:issued_at] : nil
+      reset_session
+      session[:user_id] = user_id
+      session[:mfa] = { issued_at: mfa_issued_at } if mfa_issued_at.present?
+    else
+      @url, @saml_params = saml.response_for(
+        binding: :http_post, relay_state: relay_state
+      ) do |builder|
+        @saml_response_builder = builder
+      end
+      reset_session
     end
   end
 end
app/controllers/sessions_controller.rb
@@ -18,7 +18,11 @@ class SessionsController < ApplicationController
     )
     @saml_request = binding.deserialize(saml_params)
     if @saml_request.valid?
-      session[:saml] = { params: saml_params.to_h, xml: @saml_request.to_xml }
+      session[:saml] = {
+        type: 'authnrequest',
+        params: saml_params.to_h,
+        xml: @saml_request.to_xml
+      }
       return redirect_to response_path if current_user?
     else
       render_error(:forbidden, model: @saml_request)
@@ -44,13 +48,12 @@ class SessionsController < ApplicationController
       saml = binding.deserialize(saml_params)
       raise ActiveRecord::RecordInvalid.new(saml) if saml.invalid?
       raise 'Unknown NameId' unless current_user.uuid == saml.name_id
-
-      @url, @saml_params = saml.response_for(
-        binding: :http_post, relay_state: saml_params[:RelayState]
-      ) do |builder|
-        @saml_response_builder = builder
-      end
-      reset_session
+      session[:saml] = {
+        type: 'logout_request',
+        params: saml_params.to_h,
+        xml: saml.to_xml
+      }
+      redirect_to response_path
     elsif saml_params[:SAMLResponse].present?
       saml = binding.deserialize(saml_params)
       raise ActiveRecord::RecordInvalid.new(saml) if saml.invalid?
spec/requests/sessions_spec.rb
@@ -12,6 +12,12 @@ describe SessionsController do
 
   before { Saml::Kit.configuration.registry = registry }
 
+  def session_id_from(response)
+    cookies = response.headers['Set-Cookie']
+    return if cookies.nil?
+    cookies.split("\;")[0].split("=")[1]
+  end
+
   describe "POST /session/new" do
     let(:post_binding) { Saml::Kit::Bindings::HttpPost.new(location: new_session_url) }
 
@@ -184,6 +190,7 @@ describe SessionsController do
     context "when receiving a logout request" do
       before :each do
         http_login(user)
+        @session_id = session_id_from(response)
 
         allow(registry).to receive(:metadata_for).with(issuer).and_return(sp_metadata)
         builder = Saml::Kit::LogoutRequest.builder(user) do |x|
@@ -192,11 +199,14 @@ describe SessionsController do
         end
         url, saml_params = post_binding.serialize(builder)
         post url, params: saml_params
+        follow_redirect!
       end
 
       specify { expect(response).to have_http_status(:ok) }
       specify { expect(response.body).to include("SAMLResponse") }
       specify { expect(response.body).to include(sp_metadata.single_logout_service_for(binding: :http_post).location) }
+      specify { expect(session_id_from(response)).to be_present }
+      specify { expect(session_id_from(response)).not_to eql(@session_id) }
     end
 
     context "when receiving a logout response" do
@@ -216,12 +226,6 @@ describe SessionsController do
     context "when logging out of the IDP only" do
       let(:user) { create(:user) }
 
-      def session_id_from(response)
-        cookies = response.headers['Set-Cookie']
-        return if cookies.nil?
-        cookies.split("\;")[0].split("=")[1]
-      end
-
       before :each do
         http_login(user)
         @session_id = session_id_from(response)