@@ -38,6 +38,13 @@ class OneLogin_Saml2_Response
38
38
*/
39
39
public $ encrypted = false ;
40
40
41
+ /**
42
+ * The response contains an encrypted nameId in the assertion.
43
+ *
44
+ * @var bool
45
+ */
46
+ public $ encryptedNameId = false ;
47
+
41
48
/**
42
49
* After validation, if it fail this var has the cause of the problem
43
50
* @var string
@@ -200,14 +207,12 @@ public function isValid($requestId = null)
200
207
);
201
208
}
202
209
203
- if ($ security ['wantNameIdEncrypted ' ]) {
204
- $ encryptedIdNodes = $ this ->_queryAssertion ('/saml:Subject/saml:EncryptedID/xenc:EncryptedData ' );
205
- if ($ encryptedIdNodes ->length != 1 ) {
206
- throw new OneLogin_Saml2_ValidationError (
207
- "The NameID of the Response is not encrypted and the SP requires it " ,
208
- OneLogin_Saml2_ValidationError::NO_ENCRYPTED_NAMEID
209
- );
210
- }
210
+ $ this ->encryptedNameId = $ this ->encryptedNameId || $ this ->_queryAssertion ('/saml:Subject/saml:EncryptedID/xenc:EncryptedData ' )->length > 0 ;
211
+ if (!$ this ->encryptedNameId && $ security ['wantNameIdEncrypted ' ]) {
212
+ throw new OneLogin_Saml2_ValidationError (
213
+ "The NameID of the Response is not encrypted and the SP requires it " ,
214
+ OneLogin_Saml2_ValidationError::NO_ENCRYPTED_NAMEID
215
+ );
211
216
}
212
217
213
218
// Validate Conditions element exists
@@ -366,17 +371,6 @@ public function isValid($requestId = null)
366
371
}
367
372
}
368
373
369
- // Detect case not supported
370
- if ($ this ->encrypted ) {
371
- $ encryptedIDNodes = OneLogin_Saml2_Utils::query ($ this ->decryptedDocument , '/samlp:Response/saml:Assertion/saml:Subject/saml:EncryptedID ' );
372
- if ($ encryptedIDNodes ->length > 0 ) {
373
- throw new OneLogin_Saml2_ValidationError (
374
- 'SAML Response that contains a an encrypted Assertion with encrypted nameId is not supported. ' ,
375
- OneLogin_Saml2_ValidationError::NOT_SUPPORTED
376
- );
377
- }
378
- }
379
-
380
374
if (empty ($ signedElements ) || (!$ hasSignedResponse && !$ hasSignedAssertion )) {
381
375
throw new OneLogin_Saml2_ValidationError (
382
376
'No Signature found. SAML Response rejected ' ,
@@ -585,9 +579,15 @@ public function getNameIdData()
585
579
if ($ encryptedIdDataEntries ->length == 1 ) {
586
580
$ encryptedData = $ encryptedIdDataEntries ->item (0 );
587
581
588
- $ key = $ this ->_settings ->getSPkey ();
582
+ $ pem = $ this ->_settings ->getSPkey ();
583
+ if (empty ($ pem )) {
584
+ throw new OneLogin_Saml2_Error (
585
+ "No private key available, check settings " ,
586
+ OneLogin_Saml2_Error::PRIVATE_KEY_NOT_FOUND
587
+ );
588
+ }
589
589
$ seckey = new XMLSecurityKey (XMLSecurityKey::RSA_1_5 , array ('type ' =>'private ' ));
590
- $ seckey ->loadKey ($ key );
590
+ $ seckey ->loadKey ($ pem );
591
591
592
592
$ nameId = OneLogin_Saml2_Utils::decryptElement ($ encryptedData , $ seckey );
593
593
@@ -1139,6 +1139,17 @@ protected function _decryptAssertion($dom)
1139
1139
if ($ check === false ) {
1140
1140
throw new Exception ('Error: string from decrypted assertion could not be loaded into a XML document ' );
1141
1141
}
1142
+
1143
+ // check if the decrypted assertion contains an encryptedID
1144
+ $ encryptedID = $ decrypted ->getElementsByTagName ('EncryptedID ' )->item (0 );
1145
+ if ($ encryptedID ) {
1146
+ // decrypt the encryptedID
1147
+ $ this ->encryptedNameId = true ;
1148
+ $ encryptedData = $ encryptedID ->getElementsByTagName ('EncryptedData ' )->item (0 );
1149
+ $ nameId = $ this ->decryptNameId ($ encryptedData , $ pem );
1150
+ OneLogin_Saml2_Utils::treeCopyReplace ($ encryptedID , $ nameId );
1151
+ }
1152
+
1142
1153
if ($ encData ->parentNode instanceof DOMDocument) {
1143
1154
return $ decrypted ;
1144
1155
} else {
@@ -1171,6 +1182,46 @@ protected function _decryptAssertion($dom)
1171
1182
}
1172
1183
}
1173
1184
1185
+ /**
1186
+ * Decrypt EncryptedID element
1187
+ *
1188
+ * @param \DOMElement $encryptedData The encrypted data.
1189
+ * @param string $key The private key
1190
+ *
1191
+ * @return \DOMElement The decrypted element.
1192
+ *
1193
+ * @throws OneLogin_Saml2_Error
1194
+ * @throws OneLogin_Saml2_ValidationError
1195
+ */
1196
+ private function decryptNameId (\DOMElement $ encryptedData , string $ pem )
1197
+ {
1198
+ $ objenc = new XMLSecEnc ();
1199
+ $ encData = $ objenc ->locateEncryptedData ($ encryptedData );
1200
+ $ objenc ->setNode ($ encData );
1201
+ $ objenc ->type = $ encData ->getAttribute ("Type " );
1202
+ if (!$ objKey = $ objenc ->locateKey ()) {
1203
+ throw new OneLogin_Saml2_ValidationError (
1204
+ "Unknown algorithm " ,
1205
+ ValidationError::KEY_ALGORITHM_ERROR
1206
+ );
1207
+ }
1208
+ $ key = null ;
1209
+ if ($ objKeyInfo = $ objenc ->locateKeyInfo ($ objKey )) {
1210
+ if ($ objKeyInfo ->isEncrypted ) {
1211
+ $ objencKey = $ objKeyInfo ->encryptedCtx ;
1212
+ $ objKeyInfo ->loadKey ($ pem , false , false );
1213
+ $ key = $ objencKey ->decryptKey ($ objKeyInfo );
1214
+ } else {
1215
+ // symmetric encryption key support
1216
+ $ objKeyInfo ->loadKey ($ pem , false , false );
1217
+ }
1218
+ }
1219
+ if (empty ($ objKey ->key )) {
1220
+ $ objKey ->loadKey ($ key );
1221
+ }
1222
+ return OneLogin_Saml2_Utils::decryptElement ($ encryptedData , $ objKey );
1223
+ }
1224
+
1174
1225
/**
1175
1226
* After execute a validation process, if fails this method returns the cause
1176
1227
*
0 commit comments