|
9 | 9 | use SimpleSAML\{Configuration, Error, Logger}; |
10 | 10 | use SimpleSAML\HTTP\RunnableResponse; |
11 | 11 | use SimpleSAML\Metadata\MetaDataStorageHandler; |
12 | | -use SimpleSAML\Module\saml\Message;; |
13 | 12 | use SimpleSAML\SAML2\Binding; |
14 | 13 | use SimpleSAML\SAML2\Binding\HTTPPost; |
15 | 14 | use SimpleSAML\SAML2\Constants as C; |
16 | | -use SimpleSAML\SAML2\Utils; |
| 15 | +use SimpleSAML\SAML2\Utils as SAML2_Utils; |
17 | 16 | use SimpleSAML\SAML2\XML\saml\{ |
18 | 17 | Assertion, |
19 | 18 | Attribute, |
|
23 | 22 | AudienceRestriction, |
24 | 23 | Conditions, |
25 | 24 | Issuer, |
26 | | - Status, |
27 | | - StatusCode, |
28 | 25 | Subject, |
29 | 26 | SubjectConfirmation, |
30 | 27 | SubjectConfirmationData, |
31 | 28 | }; |
32 | | -use SimpleSAML\SAML2\XML\samlp\{AttributeQuery, Response}; |
| 29 | +use SimpleSAML\SAML2\XML\samlp\{AttributeQuery, Response, Status, StatusCode}; |
| 30 | +use SimpleSAML\Utils; |
33 | 31 | use 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; |
34 | 37 | use Symfony\Bridge\PsrHttpMessage\Factory\{HttpFoundationFactory, PsrHttpFactory}; |
35 | 38 | use Symfony\Component\HttpFoundation\Request; |
36 | 39 |
|
@@ -159,7 +162,7 @@ public function main(/** @scrutinizer ignore-unused */ Request $request): Runnab |
159 | 162 | } |
160 | 163 |
|
161 | 164 | // $returnAttributes contains the attributes we should return. Send them |
162 | | - $clock = Utils::getContainer()->getClock(); |
| 165 | + $clock = SAML2_Utils::getContainer()->getClock(); |
163 | 166 |
|
164 | 167 | $assertion = new Assertion( |
165 | 168 | issuer: new Issuer($idpEntityId), |
@@ -192,24 +195,22 @@ public function main(/** @scrutinizer ignore-unused */ Request $request): Runnab |
192 | 195 | ], |
193 | 196 | ); |
194 | 197 |
|
195 | | - // TODO: Fix signing; should use xml-security lib |
196 | | - Message::addSign($idpMetadata, $spMetadata, $assertion); |
| 198 | + self::addSign($idpMetadata, $spMetadata, $assertion); |
197 | 199 |
|
198 | 200 | $response = new Response( |
199 | 201 | status: new Status( |
200 | 202 | new StatusCode(C::STATUS_SUCCESS), |
201 | 203 | ), |
202 | 204 | issueInstant: $clock->now(), |
203 | | - issuer: new Issuer($issuer), |
| 205 | + issuer: $issuer, |
204 | 206 | id: (new Random())->generateID(), |
205 | 207 | version: '2.0', |
206 | 208 | inResponseTo: $message->getId(), |
207 | 209 | destination: $endpoint, |
208 | 210 | assertions: [$assertion], |
209 | 211 | ); |
210 | 212 |
|
211 | | - // TODO: Fix signing; should use xml-security lib |
212 | | - Message::addSign($idpMetadata, $spMetadata, $response); |
| 213 | + self::addSign($idpMetadata, $spMetadata, $response); |
213 | 214 |
|
214 | 215 | $httpPost = new HTTPPost(); |
215 | 216 | $httpPost->setRelayState($binding->getRelayState()); |
@@ -238,4 +239,60 @@ private function filterAttributeValues(array $reqValues, array $values): array |
238 | 239 |
|
239 | 240 | return $result; |
240 | 241 | } |
| 242 | + |
| 243 | + |
| 244 | + /** |
| 245 | + * @deprecated This method is a modified version of \SimpleSAML\Module\saml\Message::addSign and |
| 246 | + * should be replaced with a call to a future ServiceProvider-class in the saml2-library |
| 247 | + * |
| 248 | + * Add signature key and sender certificate to an element (Message or Assertion). |
| 249 | + * |
| 250 | + * @param \SimpleSAML\Configuration $srcMetadata The metadata of the sender. |
| 251 | + * @param \SimpleSAML\Configuration $dstMetadata The metadata of the recipient. |
| 252 | + * @param \SimpleSAML\XMLSecurity\XML\SignableElementInterface $element The element we should add the data to. |
| 253 | + */ |
| 254 | + private static function addSign( |
| 255 | + Configuration $srcMetadata, |
| 256 | + Configuration $dstMetadata, |
| 257 | + SignableElementInterface &$element, |
| 258 | + ): void { |
| 259 | + $dstPrivateKey = $dstMetadata->getOptionalString('signature.privatekey', null); |
| 260 | + $cryptoUtils = new Utils\Crypto(); |
| 261 | + |
| 262 | + if ($dstPrivateKey !== null) { |
| 263 | + /** @var array $keyArray */ |
| 264 | + $keyArray = $cryptoUtils->loadPrivateKey($dstMetadata, true, 'signature.'); |
| 265 | + $certArray = $cryptoUtils->loadPublicKey($dstMetadata, false, 'signature.'); |
| 266 | + } else { |
| 267 | + /** @var array $keyArray */ |
| 268 | + $keyArray = $cryptoUtils->loadPrivateKey($srcMetadata, true); |
| 269 | + $certArray = $cryptoUtils->loadPublicKey($srcMetadata, false); |
| 270 | + } |
| 271 | + |
| 272 | + $algo = $dstMetadata->getOptionalString('signature.algorithm', null); |
| 273 | + if ($algo === null) { |
| 274 | + $algo = $srcMetadata->getOptionalString('signature.algorithm', C::SIG_RSA_SHA256); |
| 275 | + } |
| 276 | + |
| 277 | + $privateKey = PrivateKey::fromFile($keyArray['PEM'], $keyArray['password']); |
| 278 | + |
| 279 | + $keyInfo = null; |
| 280 | + if ($certArray !== null) { |
| 281 | + $certificate = new X509Certificate(PEM::fromString($keyArray['PEM'])); |
| 282 | + $keyInfo = new KeyInfo([ |
| 283 | + new X509Data( |
| 284 | + [ |
| 285 | + new X509Certificate($certArray['PEM']), |
| 286 | + ], |
| 287 | + ), |
| 288 | + ]); |
| 289 | + } |
| 290 | + |
| 291 | + $signer = (new SignatureAlgorithmFactory())->getAlgorithm( |
| 292 | + $algo, |
| 293 | + $privateKey, |
| 294 | + ); |
| 295 | + |
| 296 | + $element->sign($signer, C::C14N_EXCLUSIVE_WITHOUT_COMMENTS, $keyInfo); |
| 297 | + } |
241 | 298 | } |
0 commit comments