1414use ReflectionMethod ;
1515use SimpleSAML \Configuration ;
1616use SimpleSAML \SAML2 \Binding \HTTPArtifact ;
17+ use SimpleSAML \SAML2 \XML \samlp \AbstractMessage ;
1718use SimpleSAML \SAML2 \XML \samlp \ArtifactResponse ;
1819use SimpleSAML \XMLSecurity \TestUtils \PEMCertificatesMock ;
1920use SimpleSAML \XMLSecurity \XML \ds \Signature ;
@@ -155,6 +156,84 @@ public function testVerifyArtifactResponseSignatureBasicScenarios(
155156 }
156157
157158
159+ /**
160+ * @return array<
161+ * string,
162+ * array{
163+ * verifyThrowsMessage: ?string,
164+ * idpMetadata: \SimpleSAML\Configuration,
165+ * expectedExceptionMessage: ?string
166+ * }
167+ * >
168+ */
169+ public static function provideVerifyMessageSignatureCases (): array
170+ {
171+ $ base64Cert = PEMCertificatesMock::getPlainCertificateContents ();
172+
173+ $ idpMetadataWithSigningKey = Configuration::loadFromArray (
174+ [
175+ 'entityid ' => 'https://idp.example.test ' ,
176+ 'keys ' => [
177+ [
178+ 'type ' => 'X509Certificate ' ,
179+ 'signing ' => true ,
180+ 'encryption ' => false ,
181+ 'X509Certificate ' => $ base64Cert ,
182+ ],
183+ ],
184+ ],
185+ '[idp] ' ,
186+ );
187+
188+ $ idpMetadataWithoutKeys = Configuration::loadFromArray (
189+ [
190+ 'entityid ' => 'https://idp.example.test ' ,
191+ ],
192+ '[idp] ' ,
193+ );
194+
195+ return [
196+ 'signed message but metadata has no keys => throws (metadata required) ' => [
197+ 'verifyThrowsMessage ' => null ,
198+ 'idpMetadata ' => $ idpMetadataWithoutKeys ,
199+ 'expectedExceptionMessage ' => 'Missing certificate in metadata. ' ,
200+ ],
201+ 'signed message but verification fails => throws verify exception ' => [
202+ 'verifyThrowsMessage ' => 'Unable to validate Signature ' ,
203+ 'idpMetadata ' => $ idpMetadataWithSigningKey ,
204+ 'expectedExceptionMessage ' => 'Unable to validate Signature ' ,
205+ ],
206+ 'signed message and verification ok => returns verified instance ' => [
207+ 'verifyThrowsMessage ' => null ,
208+ 'idpMetadata ' => $ idpMetadataWithSigningKey ,
209+ 'expectedExceptionMessage ' => null ,
210+ ],
211+ ];
212+ }
213+
214+
215+ #[DataProvider('provideVerifyMessageSignatureCases ' )]
216+ public function testVerifyMessageSignatureBasicScenarios (
217+ ?string $ verifyThrowsMessage ,
218+ Configuration $ idpMetadata ,
219+ ?string $ expectedExceptionMessage ,
220+ ): void {
221+ $ message = $ this ->buildSignedMessageStub ($ verifyThrowsMessage );
222+
223+ if ($ expectedExceptionMessage !== null ) {
224+ $ this ->expectException (Exception::class);
225+ $ this ->expectExceptionMessage ($ expectedExceptionMessage );
226+ }
227+
228+ $ ha = new HTTPArtifact ();
229+ $ verified = $ this ->callVerifyMessageSignature ($ ha , $ message , $ idpMetadata );
230+
231+ if ($ expectedExceptionMessage === null ) {
232+ $ this ->assertSame ($ message , $ verified );
233+ }
234+ }
235+
236+
158237 private function callVerifyArtifactResponseSignature (
159238 HTTPArtifact $ ha ,
160239 ArtifactResponse $ artifactResponse ,
@@ -167,6 +246,18 @@ private function callVerifyArtifactResponseSignature(
167246 }
168247
169248
249+ private function callVerifyMessageSignature (
250+ HTTPArtifact $ ha ,
251+ AbstractMessage $ message ,
252+ Configuration $ idpMetadata ,
253+ ): AbstractMessage {
254+ $ m = new ReflectionMethod (HTTPArtifact::class, 'verifyMessageSignature ' );
255+ /** @var \SimpleSAML\SAML2\XML\samlp\AbstractMessage $result */
256+ $ result = $ m ->invoke ($ ha , $ message , $ idpMetadata );
257+ return $ result ;
258+ }
259+
260+
170261 private function buildArtifactResponseStub (bool $ signed , ?string $ verifyThrowsMessage ): ArtifactResponse
171262 {
172263 $ stub = $ this ->createStub (ArtifactResponse::class);
@@ -191,6 +282,24 @@ private function buildArtifactResponseStub(bool $signed, ?string $verifyThrowsMe
191282 }
192283
193284
285+ private function buildSignedMessageStub (?string $ verifyThrowsMessage ): AbstractMessage
286+ {
287+ $ stub = $ this ->createStub (AbstractMessage::class);
288+
289+ $ stub ->method ('getSignature ' )->willReturn (
290+ self ::buildMinimalDsSignature ('http://www.w3.org/2001/04/xmldsig-more#rsa-sha256 ' ),
291+ );
292+
293+ if ($ verifyThrowsMessage !== null ) {
294+ $ stub ->method ('verify ' )->willThrowException (new Exception ($ verifyThrowsMessage ));
295+ } else {
296+ $ stub ->method ('verify ' )->willReturn ($ stub );
297+ }
298+
299+ return $ stub ;
300+ }
301+
302+
194303 private static function buildMinimalDsSignature (string $ signatureAlgorithm ): Signature
195304 {
196305 $ xml =
0 commit comments