1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace LightSaml\Tests\Model\Metadata; |
4
|
|
|
|
5
|
|
|
use LightSaml\ClaimTypes; |
6
|
|
|
use LightSaml\Model\Context\DeserializationContext; |
7
|
|
|
use LightSaml\Model\Context\SerializationContext; |
8
|
|
|
use LightSaml\Model\Assertion\Attribute; |
9
|
|
|
use LightSaml\Model\Metadata\AssertionConsumerService; |
10
|
|
|
use LightSaml\Model\Metadata\ContactPerson; |
11
|
|
|
use LightSaml\Model\Metadata\EntityDescriptor; |
12
|
|
|
use LightSaml\Model\Metadata\IdpSsoDescriptor; |
13
|
|
|
use LightSaml\Model\Metadata\KeyDescriptor; |
14
|
|
|
use LightSaml\Model\Metadata\Organization; |
15
|
|
|
use LightSaml\Model\Metadata\SingleLogoutService; |
16
|
|
|
use LightSaml\Model\Metadata\SingleSignOnService; |
17
|
|
|
use LightSaml\Model\Metadata\SpSsoDescriptor; |
18
|
|
|
use LightSaml\SamlConstants; |
19
|
|
|
use LightSaml\Credential\X509Certificate; |
20
|
|
|
use LightSaml\Tests\BaseTestCase; |
21
|
|
|
|
22
|
|
|
class EntityDescriptorTest extends BaseTestCase |
23
|
|
|
{ |
24
|
|
|
public function test_serialization() |
25
|
|
|
{ |
26
|
|
|
$ed = new EntityDescriptor(); |
27
|
|
|
$ed |
28
|
|
|
->setEntityID($entityID = 'http://vendor.com/id') |
29
|
|
|
->setID($edID = '_127800fe-39ac-46ad-b073-6fb6106797a0') |
30
|
|
|
->addItem((new IdpSsoDescriptor()) |
|
|
|
|
31
|
|
|
->setWantAuthnRequestsSigned(false) |
32
|
|
|
->addSingleSignOnService((new SingleSignOnService()) |
|
|
|
|
33
|
|
|
->setBinding(SamlConstants::BINDING_SAML2_HTTP_POST) |
34
|
|
|
->setLocation('http://idp.example.com/sso/post')) |
35
|
|
|
->addSingleSignOnService((new SingleSignOnService()) |
|
|
|
|
36
|
|
|
->setBinding(SamlConstants::BINDING_SAML2_HTTP_REDIRECT) |
37
|
|
|
->setLocation('http://idp.example.com/slo/get')) |
38
|
|
|
->addSingleLogoutService((new SingleLogoutService()) |
|
|
|
|
39
|
|
|
->setBinding(SamlConstants::BINDING_SAML2_HTTP_REDIRECT) |
40
|
|
|
->setLocation('http://idp.example.com/slo/redirect')) |
41
|
|
|
->addAttribute((new Attribute()) |
42
|
|
|
->setName(ClaimTypes::COMMON_NAME) |
43
|
|
|
->setFriendlyName('Common Name') |
44
|
|
|
->addAttributeValue('common name value')) |
45
|
|
|
->addNameIDFormat(SamlConstants::NAME_ID_FORMAT_EMAIL) |
46
|
|
|
->addNameIDFormat(SamlConstants::NAME_ID_FORMAT_PERSISTENT) |
47
|
|
|
->addKeyDescriptor((new KeyDescriptor()) |
48
|
|
|
->setCertificate((new X509Certificate()) |
49
|
|
|
->loadFromFile(__DIR__.'/../../../../../resources/sample/Certificate/saml.crt'))) |
50
|
|
|
->addOrganization((new Organization()) |
51
|
|
|
->setOrganizationName('Organization Name') |
52
|
|
|
->setOrganizationDisplayName('Display Name') |
53
|
|
|
->setOrganizationURL('http://organization.org')) |
54
|
|
|
->addContactPerson((new ContactPerson()) |
55
|
|
|
->setContactType(ContactPerson::TYPE_SUPPORT) |
56
|
|
|
->setGivenName('Support') |
57
|
|
|
->setSurName('Smith') |
58
|
|
|
->setEmailAddress('[email protected]'))) |
59
|
|
|
->addItem((new SpSsoDescriptor()) |
|
|
|
|
60
|
|
|
->setAuthnRequestsSigned(false) |
61
|
|
|
->setWantAssertionsSigned(false) |
62
|
|
|
->addSingleLogoutService((new SingleLogoutService()) |
|
|
|
|
63
|
|
|
->setBinding(SamlConstants::BINDING_SAML2_HTTP_POST) |
64
|
|
|
->setLocation('http://sp.example.com/slo/post')) |
65
|
|
|
->addAssertionConsumerService((new AssertionConsumerService()) |
|
|
|
|
66
|
|
|
->setBinding(SamlConstants::BINDING_SAML2_HTTP_POST) |
67
|
|
|
->setLocation('http://sp.example.com/acs/post') |
68
|
|
|
->setIndex(0) |
69
|
|
|
->setIsDefault(true)) |
70
|
|
|
->addAssertionConsumerService((new AssertionConsumerService()) |
|
|
|
|
71
|
|
|
->setBinding(SamlConstants::BINDING_SAML2_HTTP_REDIRECT) |
72
|
|
|
->setLocation('http://sp.example.com/acs/redirect') |
73
|
|
|
->setIndex(1) |
74
|
|
|
->setIsDefault(false)) |
75
|
|
|
->addNameIDFormat(SamlConstants::NAME_ID_FORMAT_PERSISTENT) |
76
|
|
|
->addNameIDFormat(SamlConstants::NAME_ID_FORMAT_TRANSIENT)) |
77
|
|
|
; |
78
|
|
|
|
79
|
|
|
$context = new SerializationContext(); |
80
|
|
|
$ed->serialize($context->getDocument(), $context); |
81
|
|
|
|
82
|
|
|
$context->getDocument()->formatOutput = true; |
83
|
|
|
$xml = $context->getDocument()->saveXML(); |
84
|
|
|
|
85
|
|
|
$expectedXml = <<<EOT |
86
|
|
|
<?xml version="1.0"?> |
87
|
|
|
<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" entityID="http://vendor.com/id" ID="_127800fe-39ac-46ad-b073-6fb6106797a0"> |
88
|
|
|
<IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol" WantAuthnRequestsSigned="false"> |
89
|
|
|
<KeyDescriptor> |
90
|
|
|
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> |
91
|
|
|
<ds:X509Data> |
92
|
|
|
<ds:X509Certificate>MIIDrDCCApSgAwIBAgIJAIxzbGLou3BjMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlJTMQ8wDQYDVQQIEwZTZXJiaWExDDAKBgNVBAoTA0JPUzEUMBIGA1UEAxMLbXQuZXZvLnRlYW0wHhcNMTMxMDA4MTg1OTMyWhcNMjMxMDA4MTg1OTMyWjBCMQswCQYDVQQGEwJSUzEPMA0GA1UECBMGU2VyYmlhMQwwCgYDVQQKEwNCT1MxFDASBgNVBAMTC210LmV2by50ZWFtMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAws7jML47jTQbWleRwihk15wOjuspoKPcxW1aERexAMWe8BMs1MeeTOMXjnA35breGa9PwJi2KjtDz3gkhVCglZzLZGBLLO7uchZvagFhTomZa20jTqO6JQbDli3pYNP0fBIrmEbH9cfhgm91Fm+6bTVnJ4xQhT4aPWrPAVKU2FDTBFBf4QNMIb1iI1oNErt3iocsbRTbIyjjvIe8yLVrtmZXA0DnkxB/riym0GT+4gpOEKV6GUMTF1x0eQMUzw4dkxhFs7fv6YrJymtEMmHOeiA5vVPEtxEr84JAXJyZUaZfufkj/jHUlX+POFWx2JRv+428ghrXpNvqUNqv7ozfFwIDAQABo4GkMIGhMB0GA1UdDgQWBBRomf3Xyc5ck3ceIXq0n45pxUkgwjByBgNVHSMEazBpgBRomf3Xyc5ck3ceIXq0n45pxUkgwqFGpEQwQjELMAkGA1UEBhMCUlMxDzANBgNVBAgTBlNlcmJpYTEMMAoGA1UEChMDQk9TMRQwEgYDVQQDEwttdC5ldm8udGVhbYIJAIxzbGLou3BjMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAGAXc8pe6+6owl9z2iqybE6pbjXTKqjSclMGrdeooItU1xGqBhYu/b2q6hEvYZCzlqYe5euf3r8C7GAAKEYyuwu3xuLDYV4n6l6eWTIl1doug+r0Bl8Z3157A4BcgmUT64QkekI2VDHO8WAdDOWQg1UTEoqCryTOtmRaC391iGAqbz1wtZtV95boGdur8SChK9LKcPrbCDxpo64BMgtPk2HkRgE7h5YWkLHxmxwZrYi3EAfS6IucblY3wwY4GEix8DQh1lYgpv5TOD8IMVf+oUWdp81Un/IqHqLhnSupwk6rBYbUFhN/ClK5UcoDqWHcj27tGKD6aNlxTdSwcYBl3Ts=</ds:X509Certificate> |
93
|
|
|
</ds:X509Data> |
94
|
|
|
</ds:KeyInfo> |
95
|
|
|
</KeyDescriptor> |
96
|
|
|
<Organization> |
97
|
|
|
<OrganizationName xml:lang="en-US">Organization Name</OrganizationName> |
98
|
|
|
<OrganizationDisplayName xml:lang="en-US">Display Name</OrganizationDisplayName> |
99
|
|
|
<OrganizationURL xml:lang="en-US">http://organization.org</OrganizationURL> |
100
|
|
|
</Organization> |
101
|
|
|
<ContactPerson contactType="support"> |
102
|
|
|
<GivenName>Support</GivenName> |
103
|
|
|
<SurName>Smith</SurName> |
104
|
|
|
<EmailAddress>[email protected]</EmailAddress> |
105
|
|
|
</ContactPerson> |
106
|
|
|
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://idp.example.com/slo/redirect"/> |
107
|
|
|
<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</NameIDFormat> |
108
|
|
|
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat> |
109
|
|
|
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://idp.example.com/sso/post"/> |
110
|
|
|
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://idp.example.com/slo/get"/> |
111
|
|
|
<Attribute xmlns="urn:oasis:names:tc:SAML:2.0:assertion" Name="http://schemas.xmlsoap.org/claims/CommonName" FriendlyName="Common Name"> |
112
|
|
|
<AttributeValue>common name value</AttributeValue> |
113
|
|
|
</Attribute> |
114
|
|
|
</IDPSSODescriptor> |
115
|
|
|
<SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol" AuthnRequestsSigned="false" WantAssertionsSigned="false"> |
116
|
|
|
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://sp.example.com/slo/post"/> |
117
|
|
|
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat> |
118
|
|
|
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat> |
119
|
|
|
<AssertionConsumerService index="0" isDefault="true" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://sp.example.com/acs/post"/> |
120
|
|
|
<AssertionConsumerService index="1" isDefault="false" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://sp.example.com/acs/redirect"/> |
121
|
|
|
</SPSSODescriptor> |
122
|
|
|
</EntityDescriptor> |
123
|
|
|
EOT; |
124
|
|
|
$xml = trim(str_replace("\r", '', $xml)); |
125
|
|
|
$expectedXml = trim(str_replace("\r", '', $expectedXml)); |
126
|
|
|
|
127
|
|
|
$this->assertEquals($expectedXml, $xml); |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
public function test_deserialization() |
131
|
|
|
{ |
132
|
|
|
$xml = <<<EOT |
133
|
|
|
<?xml version="1.0"?> |
134
|
|
|
<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" entityID="http://vendor.com/id" ID="_127800fe-39ac-46ad-b073-6fb6106797a0"> |
135
|
|
|
<IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol" WantAuthnRequestsSigned="false"> |
136
|
|
|
<KeyDescriptor> |
137
|
|
|
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> |
138
|
|
|
<ds:X509Data> |
139
|
|
|
<ds:X509Certificate>MIIDrDCCApSgAwIBAgIJAIxzbGLou3BjMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlJTMQ8wDQYDVQQIEwZTZXJiaWExDDAKBgNVBAoTA0JPUzEUMBIGA1UEAxMLbXQuZXZvLnRlYW0wHhcNMTMxMDA4MTg1OTMyWhcNMjMxMDA4MTg1OTMyWjBCMQswCQYDVQQGEwJSUzEPMA0GA1UECBMGU2VyYmlhMQwwCgYDVQQKEwNCT1MxFDASBgNVBAMTC210LmV2by50ZWFtMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAws7jML47jTQbWleRwihk15wOjuspoKPcxW1aERexAMWe8BMs1MeeTOMXjnA35breGa9PwJi2KjtDz3gkhVCglZzLZGBLLO7uchZvagFhTomZa20jTqO6JQbDli3pYNP0fBIrmEbH9cfhgm91Fm+6bTVnJ4xQhT4aPWrPAVKU2FDTBFBf4QNMIb1iI1oNErt3iocsbRTbIyjjvIe8yLVrtmZXA0DnkxB/riym0GT+4gpOEKV6GUMTF1x0eQMUzw4dkxhFs7fv6YrJymtEMmHOeiA5vVPEtxEr84JAXJyZUaZfufkj/jHUlX+POFWx2JRv+428ghrXpNvqUNqv7ozfFwIDAQABo4GkMIGhMB0GA1UdDgQWBBRomf3Xyc5ck3ceIXq0n45pxUkgwjByBgNVHSMEazBpgBRomf3Xyc5ck3ceIXq0n45pxUkgwqFGpEQwQjELMAkGA1UEBhMCUlMxDzANBgNVBAgTBlNlcmJpYTEMMAoGA1UEChMDQk9TMRQwEgYDVQQDEwttdC5ldm8udGVhbYIJAIxzbGLou3BjMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAGAXc8pe6+6owl9z2iqybE6pbjXTKqjSclMGrdeooItU1xGqBhYu/b2q6hEvYZCzlqYe5euf3r8C7GAAKEYyuwu3xuLDYV4n6l6eWTIl1doug+r0Bl8Z3157A4BcgmUT64QkekI2VDHO8WAdDOWQg1UTEoqCryTOtmRaC391iGAqbz1wtZtV95boGdur8SChK9LKcPrbCDxpo64BMgtPk2HkRgE7h5YWkLHxmxwZrYi3EAfS6IucblY3wwY4GEix8DQh1lYgpv5TOD8IMVf+oUWdp81Un/IqHqLhnSupwk6rBYbUFhN/ClK5UcoDqWHcj27tGKD6aNlxTdSwcYBl3Ts=</ds:X509Certificate> |
140
|
|
|
</ds:X509Data> |
141
|
|
|
</ds:KeyInfo> |
142
|
|
|
</KeyDescriptor> |
143
|
|
|
<Organization> |
144
|
|
|
<OrganizationName xml:lang="en-US">Organization Name</OrganizationName> |
145
|
|
|
<OrganizationDisplayName xml:lang="en-US">Display Name</OrganizationDisplayName> |
146
|
|
|
<OrganizationURL xml:lang="en-US">http://organization.org</OrganizationURL> |
147
|
|
|
</Organization> |
148
|
|
|
<ContactPerson contactType="support"> |
149
|
|
|
<GivenName>Support</GivenName> |
150
|
|
|
<SurName>Smith</SurName> |
151
|
|
|
<EmailAddress>[email protected]</EmailAddress> |
152
|
|
|
</ContactPerson> |
153
|
|
|
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://idp.example.com/slo/redirect"/> |
154
|
|
|
<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</NameIDFormat> |
155
|
|
|
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat> |
156
|
|
|
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://idp.example.com/sso/post"/> |
157
|
|
|
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://idp.example.com/slo/get"/> |
158
|
|
|
<Attribute xmlns="urn:oasis:names:tc:SAML:2.0:assertion" Name="http://schemas.xmlsoap.org/claims/CommonName" FriendlyName="Common Name"> |
159
|
|
|
<AttributeValue>common name value</AttributeValue> |
160
|
|
|
</Attribute> |
161
|
|
|
</IDPSSODescriptor> |
162
|
|
|
<SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol" AuthnRequestsSigned="false" WantAssertionsSigned="false"> |
163
|
|
|
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://sp.example.com/slo/post"/> |
164
|
|
|
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat> |
165
|
|
|
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat> |
166
|
|
|
<AssertionConsumerService index="0" isDefault="true" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://sp.example.com/acs/post"/> |
167
|
|
|
<AssertionConsumerService index="1" isDefault="false" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://sp.example.com/acs/redirect"/> |
168
|
|
|
</SPSSODescriptor> |
169
|
|
|
</EntityDescriptor> |
170
|
|
|
EOT; |
171
|
|
|
|
172
|
|
|
$expectedEntityDescriptor = new EntityDescriptor(); |
173
|
|
|
$expectedEntityDescriptor |
174
|
|
|
->setEntityID($entityID = 'http://vendor.com/id') |
175
|
|
|
->setID($edID = '_127800fe-39ac-46ad-b073-6fb6106797a0') |
176
|
|
|
->addItem((new IdpSsoDescriptor()) |
|
|
|
|
177
|
|
|
->setWantAuthnRequestsSigned(false) |
178
|
|
|
->addSingleSignOnService((new SingleSignOnService()) |
|
|
|
|
179
|
|
|
->setBinding(SamlConstants::BINDING_SAML2_HTTP_POST) |
180
|
|
|
->setLocation('http://idp.example.com/sso/post')) |
181
|
|
|
->addSingleSignOnService((new SingleSignOnService()) |
|
|
|
|
182
|
|
|
->setBinding(SamlConstants::BINDING_SAML2_HTTP_REDIRECT) |
183
|
|
|
->setLocation('http://idp.example.com/slo/get')) |
184
|
|
|
->addSingleLogoutService((new SingleLogoutService()) |
|
|
|
|
185
|
|
|
->setBinding(SamlConstants::BINDING_SAML2_HTTP_REDIRECT) |
186
|
|
|
->setLocation('http://idp.example.com/slo/redirect')) |
187
|
|
|
->addAttribute((new Attribute()) |
188
|
|
|
->setName(ClaimTypes::COMMON_NAME) |
189
|
|
|
->setFriendlyName('Common Name') |
190
|
|
|
->addAttributeValue('common name value')) |
191
|
|
|
->addNameIDFormat(SamlConstants::NAME_ID_FORMAT_EMAIL) |
192
|
|
|
->addNameIDFormat(SamlConstants::NAME_ID_FORMAT_PERSISTENT) |
193
|
|
|
->addKeyDescriptor((new KeyDescriptor()) |
194
|
|
|
->setCertificate((new X509Certificate()) |
195
|
|
|
->loadFromFile(__DIR__.'/../../../../../resources/sample/Certificate/saml.crt'))) |
196
|
|
|
->addOrganization((new Organization()) |
197
|
|
|
->setOrganizationName('Organization Name') |
198
|
|
|
->setOrganizationDisplayName('Display Name') |
199
|
|
|
->setOrganizationURL('http://organization.org')) |
200
|
|
|
->addContactPerson((new ContactPerson()) |
201
|
|
|
->setContactType(ContactPerson::TYPE_SUPPORT) |
202
|
|
|
->setGivenName('Support') |
203
|
|
|
->setSurName('Smith') |
204
|
|
|
->setEmailAddress('[email protected]'))) |
205
|
|
|
->addItem((new SpSsoDescriptor()) |
|
|
|
|
206
|
|
|
->setAuthnRequestsSigned(false) |
207
|
|
|
->setWantAssertionsSigned(false) |
208
|
|
|
->addSingleLogoutService((new SingleLogoutService()) |
|
|
|
|
209
|
|
|
->setBinding(SamlConstants::BINDING_SAML2_HTTP_POST) |
210
|
|
|
->setLocation('http://sp.example.com/slo/post')) |
211
|
|
|
->addAssertionConsumerService((new AssertionConsumerService()) |
|
|
|
|
212
|
|
|
->setBinding(SamlConstants::BINDING_SAML2_HTTP_POST) |
213
|
|
|
->setLocation('http://sp.example.com/acs/post') |
214
|
|
|
->setIndex(0) |
215
|
|
|
->setIsDefault(true)) |
216
|
|
|
->addAssertionConsumerService((new AssertionConsumerService()) |
|
|
|
|
217
|
|
|
->setBinding(SamlConstants::BINDING_SAML2_HTTP_REDIRECT) |
218
|
|
|
->setLocation('http://sp.example.com/acs/redirect') |
219
|
|
|
->setIndex(1) |
220
|
|
|
->setIsDefault(false)) |
221
|
|
|
->addNameIDFormat(SamlConstants::NAME_ID_FORMAT_PERSISTENT) |
222
|
|
|
->addNameIDFormat(SamlConstants::NAME_ID_FORMAT_TRANSIENT)) |
223
|
|
|
; |
224
|
|
|
|
225
|
|
|
$context = new DeserializationContext(); |
226
|
|
|
$context->getDocument()->loadXML($xml); |
227
|
|
|
|
228
|
|
|
$entityDescriptor = new EntityDescriptor(); |
229
|
|
|
$entityDescriptor->deserialize($context->getDocument()->firstChild, $context); |
230
|
|
|
|
231
|
|
|
$this->assertEquals($expectedEntityDescriptor, $entityDescriptor); |
232
|
|
|
} |
233
|
|
|
} |
234
|
|
|
|
Let’s take a look at an example:
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.
Available Fixes
Change the type-hint for the parameter:
Add an additional type-check:
Add the method to the parent class: