main
1# frozen_string_literal: true
2
3RSpec.describe Saml::Kit::Bindings::HttpPost do
4 subject { described_class.new(location: location) }
5
6 let(:location) { FFaker::Internet.uri('https') }
7
8 specify { expect(subject.binding).to eql(Saml::Kit::Bindings::HTTP_POST) }
9
10 describe 'equality' do
11 it 'is referentially equal' do
12 expect(subject).to eql(subject)
13 end
14
15 it 'is equal by value' do
16 expect(subject).to eql(
17 described_class.new(location: location)
18 )
19 end
20
21 it 'is not equal' do
22 expect(subject).not_to eql(
23 described_class.new(location: FFaker::Internet.uri('https'))
24 )
25 end
26 end
27
28 describe '#serialize' do
29 let(:relay_state) { 'ECHO' }
30 let(:configuration) do
31 Saml::Kit::Configuration.new do |config|
32 config.generate_key_pair_for(use: :signing)
33 end
34 end
35
36 it 'encodes the request using the HTTP-POST encoding for a AuthenticationRequest' do
37 builder = Saml::Kit::AuthenticationRequest.builder_class.new(configuration: configuration)
38 url, saml_params = subject.serialize(builder, relay_state: relay_state)
39
40 expect(url).to eql(location)
41 expect(saml_params['RelayState']).to eql(relay_state)
42 expect(saml_params['SAMLRequest']).to be_present
43 xml = Hash.from_xml(Base64.decode64(saml_params['SAMLRequest']))
44 expect(xml['AuthnRequest']).to be_present
45 expect(xml['AuthnRequest']['Destination']).to eql(location)
46 expect(xml['AuthnRequest']['Signature']).to be_present
47 end
48
49 it 'returns a SAMLRequest for a LogoutRequest' do
50 user = User.new
51 builder = Saml::Kit::LogoutRequest.builder_class.new(user, configuration: configuration)
52 url, saml_params = subject.serialize(builder, relay_state: relay_state)
53
54 expect(url).to eql(location)
55 expect(saml_params['RelayState']).to eql(relay_state)
56 expect(saml_params['SAMLRequest']).to be_present
57 xml = Hash.from_xml(Base64.decode64(saml_params['SAMLRequest']))
58 expect(xml['LogoutRequest']).to be_present
59 expect(xml['LogoutRequest']['Destination']).to eql(location)
60 expect(xml['LogoutRequest']['Signature']).to be_present
61 end
62
63 it 'returns a SAMLResponse for a LogoutResponse' do
64 request = instance_double(Saml::Kit::AuthenticationRequest, id: SecureRandom.uuid)
65 builder = Saml::Kit::LogoutResponse.builder_class.new(request, configuration: configuration)
66 url, saml_params = subject.serialize(builder, relay_state: relay_state)
67
68 expect(url).to eql(location)
69 expect(saml_params['RelayState']).to eql(relay_state)
70 expect(saml_params['SAMLResponse']).to be_present
71 xml = Hash.from_xml(Base64.decode64(saml_params['SAMLResponse']))
72 expect(xml['LogoutResponse']).to be_present
73 expect(xml['LogoutResponse']['Destination']).to eql(location)
74 expect(xml['LogoutResponse']['Signature']).to be_present
75 end
76
77 it 'excludes the RelayState when blank' do
78 builder = Saml::Kit::AuthenticationRequest.builder_class.new
79 url, saml_params = subject.serialize(builder)
80
81 expect(url).to eql(location)
82 expect(saml_params.keys).not_to include('RelayState')
83 end
84 end
85
86 describe '#deserialize' do
87 it 'deserializes to an AuthnRequest' do
88 builder = Saml::Kit::AuthenticationRequest.builder_class.new
89 _, params = subject.serialize(builder)
90 result = subject.deserialize(params)
91 expect(result).to be_instance_of(Saml::Kit::AuthenticationRequest)
92 end
93
94 it 'deserializes to a LogoutRequest' do
95 user = User.new
96 builder = Saml::Kit::LogoutRequest.builder_class.new(user)
97 _, params = subject.serialize(builder)
98 result = subject.deserialize(params)
99 expect(result).to be_instance_of(Saml::Kit::LogoutRequest)
100 end
101
102 it 'deserializes to a Response' do
103 user = User.new
104 request = instance_double(Saml::Kit::AuthenticationRequest, id: SecureRandom.uuid, provider: nil, assertion_consumer_service_url: FFaker::Internet.http_url, name_id_format: Saml::Kit::Namespaces::PERSISTENT, issuer: FFaker::Internet.http_url, signed?: true, trusted?: true)
105 builder = Saml::Kit::Response.builder_class.new(user, request)
106 _, params = subject.serialize(builder)
107 result = subject.deserialize(params)
108 expect(result).to be_instance_of(Saml::Kit::Response)
109 end
110
111 it 'raises an error when SAMLRequest and SAMLResponse are missing' do
112 expect do
113 subject.deserialize({})
114 end.to raise_error(/SAMLRequest or SAMLResponse parameter is required/)
115 end
116
117 it 'can deserialize a request encrypted with unknown keys' do
118 saml_params = { 'SAMLResponse' => IO.read('spec/fixtures/1555534792.3954718-9d1c5e47e1b1abc70e9774d3.saml_response') }
119 result = subject.deserialize(saml_params)
120 expect(result).to be_present
121 expect(result.assertion).to be_present
122 expect(result.assertion).not_to be_decryptable
123 end
124 end
125end