Commit c44dca3

mo <mo.khan@gmail.com>
2017-11-19 17:53:48
use binding to serialize/deserialize
1 parent fa0ad10
Changed files (8)
airport
proof
app
saml-kit
lib
saml
kit
locales
airport/app/controllers/metadata_controller.rb
@@ -9,11 +9,7 @@ class MetadataController < ApplicationController
 
   def to_xml
     Rails.cache.fetch(metadata_url, expires_in: 1.hour) do
-      builder = Saml::Kit::ServiceProviderMetadata::Builder.new
-      builder.sign = false
-      builder.add_assertion_consumer_service(session_url, binding: :post)
-      builder.add_single_logout_service(session_url, binding: :post)
-      builder.to_xml
+      Sp.default(request).to_xml
     end
   end
 end
airport/app/controllers/sessions_controller.rb
@@ -21,7 +21,8 @@ class SessionsController < ApplicationController
   end
 
   def create
-    @saml_response = Saml::Kit::Response.deserialize(params[:SAMLResponse])
+    saml_binding = binding_for(request)
+    @saml_response = saml_binding.deserialize(params)
     return render :error, status: :forbidden if @saml_response.invalid?
 
     session[:user] = { id: @saml_response.name_id }.merge(@saml_response.attributes)
@@ -29,9 +30,15 @@ class SessionsController < ApplicationController
   end
 
   def destroy
-    @post_uri = idp_metadata.single_logout_service_for(binding: :post)
-    @saml_request = Saml::Kit::LogoutRequest::Builder.new(current_user, sign: true).build.serialize
-    render layout: "spinner"
+    if params['SAMLRequest'].present?
+      redirect_to new_session_path
+    else
+      saml_binding = idp_metadata.single_logout_service_for(binding: :post)
+      builder = Saml::Kit::LogoutRequest::Builder.new(current_user, sign: true)
+      @url, @saml_params = saml_binding.serialize(builder)
+      reset_session
+      render layout: "spinner"
+    end
   end
 
   private
@@ -39,4 +46,13 @@ class SessionsController < ApplicationController
   def idp_metadata
     Rails.configuration.x.idp_metadata
   end
+
+  def binding_for(request)
+    target_binding = request.post? ? :post : :http_redirect
+    sp.single_logout_service_for(binding: target_binding)
+  end
+
+  def sp
+    Sp.default(request)
+  end
 end
airport/app/models/sp.rb
@@ -0,0 +1,15 @@
+class Sp
+  class << self
+    def default(request)
+      @sp ||= begin
+        url_helpers = Rails.application.routes.url_helpers
+        host = "#{request.protocol}#{request.host}:#{request.port}"
+        builder = Saml::Kit::ServiceProviderMetadata::Builder.new
+        builder.sign = false
+        builder.add_assertion_consumer_service(url_helpers.session_url(host: host), binding: :post)
+        builder.add_single_logout_service(url_helpers.session_url(host: host), binding: :post)
+        builder.build
+      end
+    end
+  end
+end
airport/app/views/sessions/destroy.html.erb
@@ -1,6 +1,8 @@
-<%= form_tag(@post_uri, style: "position: absolute; left: -10000px; top: -10000px;") do %>
-  <%= hidden_field_tag("SAMLRequest", @saml_request) %>
-  <%= submit_tag "Submit" %>
+<h1>Loggout out of SP</h1>
+<%= form_tag(@url, style: "position: absolute; left: -10000px; top: -10000px;") do %>
+  <%= @saml_params.each do |(key, value)| %>
+    <%= hidden_field_tag key, value %>
+  <% end %>
 <% end %>
 
 <%= javascript_tag do %>
proof/app/controllers/sessions_controller.rb
@@ -21,8 +21,9 @@ class SessionsController < ApplicationController
 
   def destroy
     user = User.find_by(uuid: @saml_request.name_id)
-    @saml_response = @saml_request.response_for(user)
-    @relay_state = params[:RelayState]
+
+    saml_binding = binding_for(request)
+    @url, @saml_params = saml_binding.serialize(@saml_request.response_for(user), relay_state: params[:RelayState])
     reset_session
     render layout: "spinner"
   end
proof/app/models/idp.rb
@@ -22,7 +22,7 @@ class Idp
         builder.attributes << :email
         builder.attributes << :created_at
         builder.build
-        end
+      end
     end
   end
 end
proof/app/views/sessions/destroy.html.erb
@@ -1,8 +1,8 @@
 <h1>Logging Out of IDP</h1>
-<%= form_tag(@saml_response.destination, style: "position: absolute; left: -10000px; top: -10000px;") do %>
-  <%= hidden_field_tag("SAMLResponse", @saml_response.serialize) %>
-  <%= hidden_field_tag("RelayState", @relay_state) %>
-  <%= submit_tag "Submit" %>
+<%= form_tag(@url, style: "position: absolute; left: -10000px; top: -10000px;") do %>
+  <%= @saml_params.each do |(key, value)| %>
+    <%= hidden_field_tag key, value %>
+  <% end %>
 <% end %>
 
 <%= javascript_tag do %>
saml-kit/lib/saml/kit/locales/en.yml
@@ -6,14 +6,13 @@ en:
         invalid: "must contain AuthnRequest."
         invalid_fingerprint: "does not match."
         unregistered: "is unregistered."
-      SPSSODescriptor:
-        invalid: "must contain SPSSODescriptor."
-        invalid_signature: "invalid signature."
       IDPSSODescriptor:
         invalid: "must contain IDPSSODescriptor."
         invalid_signature: "invalid signature."
       InvalidDocument:
         invalid: "must contain valid SAMLRequest"
+      LogoutResponse:
+        unregistered: "is unregistered."
       Response:
         invalid: "must contain Response."
         unregistered: "must originate from registered identity provider."
@@ -21,3 +20,6 @@ en:
         invalid_version: "must be 2.0."
         invalid_response_to: "must match request id."
         must_match_issuer: "must match entityId."
+      SPSSODescriptor:
+        invalid: "must contain SPSSODescriptor."
+        invalid_signature: "invalid signature."