main
1# frozen_string_literal: true
2
3module Saml
4 module Kit
5 module Builders
6 # This class is responsible for building a SAML Assertion
7 # {include:file:lib/saml/kit/builders/templates/assertion.builder}
8 class Assertion
9 include XmlTemplatable
10
11 attr_reader :user, :request, :configuration
12 attr_accessor :reference_id
13 attr_accessor :now, :destination
14 attr_accessor :issuer, :version
15 attr_accessor :default_name_id_format
16
17 def initialize(user, request, configuration: Saml::Kit.configuration)
18 @user = user
19 @request = request
20 @configuration = configuration
21 @issuer = configuration.entity_id
22 @reference_id = ::Xml::Kit::Id.generate
23 @version = '2.0'
24 @now = Time.now.utc
25 self.default_name_id_format = Saml::Kit::Namespaces::UNSPECIFIED_NAMEID
26 end
27
28 def name_id_format
29 request.try(:name_id_format)
30 end
31
32 def name_id
33 user.name_id_for(name_id_format)
34 end
35
36 def assertion_attributes
37 return {} unless user.respond_to?(:assertion_attributes_for)
38
39 user.assertion_attributes_for(request)
40 end
41
42 def build
43 Saml::Kit::Assertion.new(to_xml, configuration: configuration)
44 end
45
46 private
47
48 def assertion_options
49 {
50 ID: reference_id,
51 IssueInstant: now.iso8601,
52 Version: version,
53 xmlns: Namespaces::ASSERTION,
54 }
55 end
56
57 def subject_confirmation_data_options
58 options = {}
59 options[:InResponseTo] = request.id if request.present?
60 options[:Recipient] = destination if destination.present?
61 options[:NotOnOrAfter] = (now + 5.minutes).utc.iso8601
62 options
63 end
64
65 def conditions_options
66 {
67 NotBefore: now.utc.iso8601,
68 NotOnOrAfter: not_on_or_after.iso8601,
69 }
70 end
71
72 def authn_statement_options
73 {
74 AuthnInstant: now.iso8601,
75 SessionIndex: reference_id,
76 }
77 end
78
79 def name_id_options
80 { Format: name_id_format || default_name_id_format }
81 end
82
83 def not_on_or_after
84 configuration.session_timeout.since(now).utc
85 end
86 end
87 end
88 end
89end