99use SimpleSAML \{Configuration , Error , Logger };
1010use SimpleSAML \HTTP \RunnableResponse ;
1111use SimpleSAML \Metadata \MetaDataStorageHandler ;
12- use SimpleSAML \Module \saml \Message ;;
1312use SimpleSAML \SAML2 \Binding ;
1413use SimpleSAML \SAML2 \Binding \HTTPPost ;
1514use SimpleSAML \SAML2 \Constants as C ;
16- use SimpleSAML \SAML2 \Utils ;
15+ use SimpleSAML \SAML2 \Utils as SAML2_Utils ;
1716use SimpleSAML \SAML2 \XML \saml \{
1817 Assertion ,
1918 Attribute ,
2322 AudienceRestriction ,
2423 Conditions ,
2524 Issuer ,
26- Status ,
27- StatusCode ,
2825 Subject ,
2926 SubjectConfirmation ,
3027 SubjectConfirmationData ,
3128};
32- use SimpleSAML \SAML2 \XML \samlp \{AttributeQuery , Response };
29+ use SimpleSAML \SAML2 \XML \samlp \{AttributeQuery , Response , Status , StatusCode };
30+ use SimpleSAML \Utils ;
3331use SimpleSAML \XML \Utils \Random ;
32+ use SimpleSAML \XMLSecurity \Alg \Signature \SignatureAlgorithmFactory ;
33+ use SimpleSAML \XMLSecurity \CryptoEncoding \PEM ;
34+ use SimpleSAML \XMLSecurity \Key \PrivateKey ;
35+ use SimpleSAML \XMLSecurity \XML \ds \{KeyInfo , X509Certificate , X509Data };
36+ use SimpleSAML \XMLSecurity \XML \SignableElementInterface ;
3437use Symfony \Bridge \PsrHttpMessage \Factory \{HttpFoundationFactory , PsrHttpFactory };
3538use Symfony \Component \HttpFoundation \Request ;
3639
@@ -118,7 +121,7 @@ public function main(/** @scrutinizer ignore-unused */ Request $request): Runnab
118121 new AttributeValue ('value1 ' ),
119122 new AttributeValue ('value2 ' ),
120123 new AttributeValue ('value3 ' ),
121- ]
124+ ],
122125 ),
123126 new Attribute (
124127 'test ' ,
@@ -139,13 +142,20 @@ public function main(/** @scrutinizer ignore-unused */ Request $request): Runnab
139142 } else {
140143 foreach ($ message ->getAttributes () as $ reqAttr ) {
141144 foreach ($ attributes as $ attr ) {
142- if ($ attr ->getName () === $ reqAttr ->getName () && $ attr ->getNameFormat () === $ reqAttr ->getNameFormat ()) {
145+ if (
146+ $ attr ->getName () === $ reqAttr ->getName ()
147+ && $ attr ->getNameFormat () === $ reqAttr ->getNameFormat ()
148+ ) {
143149 // The requested attribute is available
144150 if ($ reqAttr ->getAttributeValues () === []) {
145151 // If no specific values are requested, return all
146152 $ returnAttributes [] = $ attr ;
147153 } else {
148- $ returnValues = $ this ->filterAttributeValues ($ reqAttr ->getAttributeValues (), $ attr ->getAttributeValues ());
154+ $ returnValues = $ this ->filterAttributeValues (
155+ $ reqAttr ->getAttributeValues (),
156+ $ attr ->getAttributeValues (),
157+ );
158+
149159 $ returnAttributes [] = new Attribute (
150160 $ attr ->getName (),
151161 $ attr ->getNameFormat (),
@@ -159,7 +169,7 @@ public function main(/** @scrutinizer ignore-unused */ Request $request): Runnab
159169 }
160170
161171 // $returnAttributes contains the attributes we should return. Send them
162- $ clock = Utils ::getContainer ()->getClock ();
172+ $ clock = SAML2_Utils ::getContainer ()->getClock ();
163173
164174 $ assertion = new Assertion (
165175 issuer: new Issuer ($ idpEntityId ),
@@ -192,24 +202,22 @@ public function main(/** @scrutinizer ignore-unused */ Request $request): Runnab
192202 ],
193203 );
194204
195- // TODO: Fix signing; should use xml-security lib
196- Message::addSign ($ idpMetadata , $ spMetadata , $ assertion );
205+ self ::addSign ($ idpMetadata , $ spMetadata , $ assertion );
197206
198207 $ response = new Response (
199208 status: new Status (
200209 new StatusCode (C::STATUS_SUCCESS ),
201210 ),
202211 issueInstant: $ clock ->now (),
203- issuer: new Issuer ( $ issuer) ,
212+ issuer: $ issuer ,
204213 id: (new Random ())->generateID (),
205214 version: '2.0 ' ,
206215 inResponseTo: $ message ->getId (),
207216 destination: $ endpoint ,
208217 assertions: [$ assertion ],
209218 );
210219
211- // TODO: Fix signing; should use xml-security lib
212- Message::addSign ($ idpMetadata , $ spMetadata , $ response );
220+ self ::addSign ($ idpMetadata , $ spMetadata , $ response );
213221
214222 $ httpPost = new HTTPPost ();
215223 $ httpPost ->setRelayState ($ binding ->getRelayState ());
@@ -238,4 +246,60 @@ private function filterAttributeValues(array $reqValues, array $values): array
238246
239247 return $ result ;
240248 }
249+
250+
251+ /**
252+ * @deprecated This method is a modified version of \SimpleSAML\Module\saml\Message::addSign and
253+ * should be replaced with a call to a future ServiceProvider-class in the saml2-library
254+ *
255+ * Add signature key and sender certificate to an element (Message or Assertion).
256+ *
257+ * @param \SimpleSAML\Configuration $srcMetadata The metadata of the sender.
258+ * @param \SimpleSAML\Configuration $dstMetadata The metadata of the recipient.
259+ * @param \SimpleSAML\XMLSecurity\XML\SignableElementInterface $element The element we should add the data to.
260+ */
261+ private static function addSign (
262+ Configuration $ srcMetadata ,
263+ Configuration $ dstMetadata ,
264+ SignableElementInterface &$ element ,
265+ ): void {
266+ $ dstPrivateKey = $ dstMetadata ->getOptionalString ('signature.privatekey ' , null );
267+ $ cryptoUtils = new Utils \Crypto ();
268+
269+ if ($ dstPrivateKey !== null ) {
270+ /** @var array $keyArray */
271+ $ keyArray = $ cryptoUtils ->loadPrivateKey ($ dstMetadata , true , 'signature. ' );
272+ $ certArray = $ cryptoUtils ->loadPublicKey ($ dstMetadata , false , 'signature. ' );
273+ } else {
274+ /** @var array $keyArray */
275+ $ keyArray = $ cryptoUtils ->loadPrivateKey ($ srcMetadata , true );
276+ $ certArray = $ cryptoUtils ->loadPublicKey ($ srcMetadata , false );
277+ }
278+
279+ $ algo = $ dstMetadata ->getOptionalString ('signature.algorithm ' , null );
280+ if ($ algo === null ) {
281+ $ algo = $ srcMetadata ->getOptionalString ('signature.algorithm ' , C::SIG_RSA_SHA256 );
282+ }
283+
284+ $ privateKey = PrivateKey::fromFile ($ keyArray ['PEM ' ], $ keyArray ['password ' ]);
285+
286+ $ keyInfo = null ;
287+ if ($ certArray !== null ) {
288+ $ certificate = new X509Certificate (PEM ::fromString ($ keyArray ['PEM ' ]));
289+ $ keyInfo = new KeyInfo ([
290+ new X509Data (
291+ [
292+ new X509Certificate ($ certArray ['PEM ' ]),
293+ ],
294+ ),
295+ ]);
296+ }
297+
298+ $ signer = (new SignatureAlgorithmFactory ())->getAlgorithm (
299+ $ algo ,
300+ $ privateKey ,
301+ );
302+
303+ $ element ->sign ($ signer , C::C14N_EXCLUSIVE_WITHOUT_COMMENTS , $ keyInfo );
304+ }
241305}
0 commit comments