main
 1# frozen_string_literal: true
 2
 3module Saml
 4  module Kit
 5    # This class can be used to parse a SAML AuthnRequest or generate one.
 6    #
 7    # To generate an AuthnRequest use the builder API.
 8    #
 9    #    request = AuthenticationRequest.build do |builder|
10    #      builder.name_id_format = [Saml::Kit::Namespaces::EMAIL_ADDRESS]
11    #    end
12    #
13    #    <?xml version="1.0" encoding="UTF-8"?>
14    #    <samlp:AuthnRequest
15    #      xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
16    #      xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
17    #      ID="_ca3a0e72-9530-41f1-9518-c53716de88b2"
18    #      Version="2.0"
19    #      IssueInstant="2017-12-19T16:27:44Z"
20    #      Destination="http://hartmann.info"
21    #      AssertionConsumerServiceURL="https://carroll.com/acs">
22    #      <saml:Issuer>Day of the Dangerous Cousins</saml:Issuer>
23    #      <samlp:NameIDPolicy
24    #        Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"/>
25    #    </samlp:AuthnRequest>
26    #
27    # Example:
28    #
29    # {include:file:spec/examples/authentication_request_spec.rb}
30    class AuthenticationRequest < Document
31      include Requestable
32
33      # Create an instance of an AuthnRequest document.
34      #
35      # @param xml [String] the raw xml.
36      # @param configuration [Saml::Kit::Configuration] defaults to the global
37      # configuration.
38      def initialize(xml, configuration: Saml::Kit.configuration)
39        super(xml, name: 'AuthnRequest', configuration: configuration)
40      end
41
42      # Extract the AssertionConsumerServiceURL from the AuthnRequest
43      #    <samlp:AuthnRequest
44      #      AssertionConsumerServiceURL="https://carroll.com/acs">
45      #    </samlp:AuthnRequest>
46      def assertion_consumer_service_url
47        at_xpath('./*/@AssertionConsumerServiceURL').try(:value)
48      end
49
50      # Returns the ForceAuthn attribute as a boolean.
51      def force_authn
52        at_xpath('./*/@ForceAuthn').try(:value) == 'true'
53      end
54
55      def name_id_format
56        name_id_policy
57      end
58
59      # Extract the NameIDPolicy from the AuthnRequest
60      #    <samlp:AuthnRequest>
61      #      <samlp:NameIDPolicy
62      #        Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"/>
63      #    </samlp:AuthnRequest>
64      def name_id_policy
65        at_xpath('./*/samlp:NameIDPolicy/@Format').try(:value)
66      end
67
68      # Generate a Response for a specific user.
69      # @param user [Object] this is a custom user object that can be used for
70      # generating a nameid and assertion attributes.
71      # @param binding [Symbol] the SAML binding to use
72      # `:http_post` or `:http_redirect`.
73      # @param configuration [Saml::Kit::Configuration] the configuration to
74      # use to build the response.
75      def response_for(
76        user, binding:, relay_state: nil, configuration: Saml::Kit.configuration
77      )
78        response =
79          Response.builder(user, self, configuration: configuration) do |x|
80            x.embed_signature = provider.want_assertions_signed
81            yield x if block_given?
82          end
83        provider
84          .assertion_consumer_service_for(binding: binding)
85          .serialize(response, relay_state: relay_state)
86      end
87    end
88  end
89end