diff options
| author | Thomas Lenz <tlenz@iaik.tugraz.at> | 2016-03-10 12:31:38 +0100 | 
|---|---|---|
| committer | Thomas Lenz <tlenz@iaik.tugraz.at> | 2016-03-10 12:31:38 +0100 | 
| commit | a6cadad81df2b44a99ca452ea1737abf1fa7d3e8 (patch) | |
| tree | a9358c03beaed2c8955655304f5b081a40b14360 /id/server/idserverlib/src | |
| parent | e34d8e8a2292a0ea049ab3b3aa6e649aa215e82b (diff) | |
| download | moa-id-spss-a6cadad81df2b44a99ca452ea1737abf1fa7d3e8.tar.gz moa-id-spss-a6cadad81df2b44a99ca452ea1737abf1fa7d3e8.tar.bz2 moa-id-spss-a6cadad81df2b44a99ca452ea1737abf1fa7d3e8.zip | |
add additional PVP response validation
Diffstat (limited to 'id/server/idserverlib/src')
5 files changed, 125 insertions, 25 deletions
| diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/PVPTargetConfiguration.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/PVPTargetConfiguration.java index b8ced1198..e7f2a7d4b 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/PVPTargetConfiguration.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/PVPTargetConfiguration.java @@ -50,8 +50,11 @@ public class PVPTargetConfiguration extends RequestImpl {  	public static final String DATAID_INTERFEDERATION_NAMEID = "federatedNameID";  	public static final String DATAID_INTERFEDERATION_QAALEVEL = "federatedQAALevel";	 +	public static final String DATAID_INTERFEDERATION_REQUESTID = "authnReqID"; +	  	private static final long serialVersionUID = 4889919265919638188L; +	  	InboundMessage request;  	String binding;  	String consumerURL; diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/assertion/PVP2AssertionBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/assertion/PVP2AssertionBuilder.java index 7a7044ebf..3aa05bb2d 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/assertion/PVP2AssertionBuilder.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/assertion/PVP2AssertionBuilder.java @@ -435,6 +435,7 @@ public class PVP2AssertionBuilder implements PVPConstants {  				.createSAMLObject(SubjectConfirmationData.class);  		subjectConfirmationData.setInResponseTo(authnRequest.getID());  		subjectConfirmationData.setNotOnOrAfter(new DateTime(authData.getSsoSessionValidTo().getTime())); +		subjectConfirmationData.setNotBefore(date);  		subjectConfirmationData.setRecipient(assertionConsumerService.getLocation()); diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerificationEngineSP.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerificationEngineSP.java index cd80d8c24..1e13da179 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerificationEngineSP.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerificationEngineSP.java @@ -26,10 +26,15 @@ import java.util.ArrayList;  import java.util.List;  import org.joda.time.DateTime; +import org.opensaml.common.binding.decoding.BasicURLComparator; +import org.opensaml.saml2.core.Audience; +import org.opensaml.saml2.core.AudienceRestriction;  import org.opensaml.saml2.core.Conditions;  import org.opensaml.saml2.core.EncryptedAssertion;  import org.opensaml.saml2.core.Response;  import org.opensaml.saml2.core.StatusCode; +import org.opensaml.saml2.core.validator.AudienceRestrictionSchemaValidator; +import org.opensaml.saml2.core.validator.AudienceSchemaValidator;  import org.opensaml.saml2.encryption.Decrypter;  import org.opensaml.saml2.encryption.EncryptedElementTypeEncryptedKeyResolver;  import org.opensaml.xml.encryption.ChainingEncryptedKeyResolver; @@ -38,9 +43,11 @@ import org.opensaml.xml.encryption.InlineEncryptedKeyResolver;  import org.opensaml.xml.encryption.SimpleRetrievalMethodEncryptedKeyResolver;  import org.opensaml.xml.security.credential.Credential;  import org.opensaml.xml.security.keyinfo.StaticKeyInfoCredentialResolver; +import org.opensaml.xml.validation.ValidationException;  import org.springframework.beans.factory.annotation.Autowired;  import org.springframework.stereotype.Service; +import at.gv.egovernment.moa.id.auth.MOAIDAuthConstants;  import at.gv.egovernment.moa.id.config.ConfigurationException;  import at.gv.egovernment.moa.id.config.auth.AuthConfiguration;  import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.AssertionValidationExeption; @@ -56,7 +63,17 @@ public class SAMLVerificationEngineSP extends SAMLVerificationEngine {  	@Autowired AuthConfiguration authConfig; -	public void validateAssertion(Response samlResp, boolean validateDestination, Credential assertionDecryption) throws AssertionValidationExeption { +	/** +	 * Validate a PVP response and all included assertions +	 *  +	 * @param samlResp +	 * @param validateDestination +	 * @param assertionDecryption +	 * @param spEntityID +	 * @param loggerSPName +	 * @throws AssertionValidationExeption +	 */ +	public void validateAssertion(Response samlResp, boolean validateDestination, Credential assertionDecryption, String spEntityID, String loggerSPName) throws AssertionValidationExeption {  		try {  			if (samlResp.getStatus().getStatusCode().getValue().equals(StatusCode.SUCCESS_URI)) {  				List<org.opensaml.saml2.core.Assertion> saml2assertions = new ArrayList<org.opensaml.saml2.core.Assertion>(); @@ -74,15 +91,28 @@ public class SAMLVerificationEngineSP extends SAMLVerificationEngine {  				}  				if (!isValidDestination && validateDestination) {  					Logger.warn("PVP 2.1 assertion destination does not match to IDP URL"); -					throw new AssertionValidationExeption("PVP 2.1 assertion destination does not match to IDP URL", null);					 +					throw new AssertionValidationExeption("sp.pvp2.07", new Object[]{loggerSPName, "'Destination' attribute is not valid"});					  				} -				//check encrypted Assertion +				//validate response issueInstant +				DateTime issueInstant = samlResp.getIssueInstant(); +				if (issueInstant == null) { +					Logger.warn("PVP response does not include a 'IssueInstant' attribute"); +					throw new AssertionValidationExeption("sp.pvp2.07", new Object[]{loggerSPName, "'IssueInstant' attribute is not included"}); +					 +				} 								 +				if (issueInstant.minusMinutes(MOAIDAuthConstants.TIME_JITTER).isAfterNow()) { +					Logger.warn("PVP response: IssueInstant DateTime is not valid anymore."); +					throw new AssertionValidationExeption("sp.pvp2.07", new Object[]{loggerSPName, "'IssueInstant' Time is not valid any more"}); +					 +				} +					 +				 +				//check encrypted Assertions  				List<EncryptedAssertion> encryAssertionList = samlResp.getEncryptedAssertions();  				if (encryAssertionList != null && encryAssertionList.size() > 0) { -					//decrypt assertions -					 +					//decrypt assertions					  					Logger.debug("Found encryped assertion. Start decryption ...");  					StaticKeyInfoCredentialResolver skicr = @@ -93,13 +123,10 @@ public class SAMLVerificationEngineSP extends SAMLVerificationEngine {  					encryptedKeyResolver.getResolverChain().add( new EncryptedElementTypeEncryptedKeyResolver() );  					encryptedKeyResolver.getResolverChain().add( new SimpleRetrievalMethodEncryptedKeyResolver() ); -					Decrypter samlDecrypter = -							  new Decrypter(null, skicr, encryptedKeyResolver); +					Decrypter samlDecrypter = new Decrypter(null, skicr, encryptedKeyResolver); -					for (EncryptedAssertion encAssertion : encryAssertionList) {							 +					for (EncryptedAssertion encAssertion : encryAssertionList)							  						saml2assertions.add(samlDecrypter.decrypt(encAssertion)); -	 -					}  					Logger.debug("Assertion decryption finished. "); @@ -108,35 +135,90 @@ public class SAMLVerificationEngineSP extends SAMLVerificationEngine {  				} +				//validate all assertions  				List<org.opensaml.saml2.core.Assertion> validatedassertions = new ArrayList<org.opensaml.saml2.core.Assertion>();				  				for (org.opensaml.saml2.core.Assertion saml2assertion : saml2assertions) { -					 + +					boolean isAssertionValid = true;  					try { +						//schema validation  						performSchemaValidation(saml2assertion.getDOM()); -											 + +						 +						//validate DateTime conditions  						Conditions conditions = saml2assertion.getConditions(); -					DateTime notbefore = conditions.getNotBefore().minusMinutes(5); -					DateTime notafter = conditions.getNotOnOrAfter(); -					if ( notbefore.isAfterNow() || notafter.isBeforeNow() ) { -						Logger.warn("PVP2 Assertion is out of Date. " -								+ "{ Current : " + new DateTime()  -								+ " NotBefore: " + notbefore  -								+ " NotAfter : " + notafter -								+ " }");; +						if (conditions != null) { +							DateTime notbefore = conditions.getNotBefore().minusMinutes(5); +							DateTime notafter = conditions.getNotOnOrAfter(); +							if ( notbefore.isAfterNow() || notafter.isBeforeNow() ) { +								isAssertionValid = false; +								Logger.info("Assertion:" + saml2assertion.getID()  +										+ " is out of Date. " +										+ "{ Current : " + new DateTime()  +										+ " NotBefore: " + notbefore  +										+ " NotAfter : " + notafter +										+ " }");; +																		 +							} 						 +						 +							//validate audienceRestrictions are valid for this SP +							List<AudienceRestriction> audienceRest = conditions.getAudienceRestrictions(); +							if (audienceRest == null || audienceRest.size() == 0) { +								Logger.info("Assertion:" + saml2assertion.getID() +										+ " has not 'AudienceRestriction' element"); +								isAssertionValid = false; +								 +							} else { +								for (AudienceRestriction el : audienceRest) { +									el.registerValidator(new AudienceRestrictionSchemaValidator()); +									el.validate(false); +									 +									for (Audience audience : el.getAudiences()) { +										audience.registerValidator(new AudienceSchemaValidator()); +										audience.validate(false); +										 +										if (!urlCompare(spEntityID, audience.getAudienceURI())) { +											Logger.info("Assertion:" + saml2assertion.getID() +											+ " 'AudienceRestriction' is not valid."); +											isAssertionValid = false; +										} +									} +								}															 +							} +							  						} else { +							Logger.info("Assertion:" + saml2assertion.getID()  +								+ " contains not 'Conditions' element"); +							isAssertionValid = false; +							 +						} +						 +						//add assertion if it is valid +						if (isAssertionValid)  { +							Logger.debug("Add valid Assertion:" + saml2assertion.getID());  							validatedassertions.add(saml2assertion); -						} +						} else +							Logger.warn("Remove non-valid Assertion:" + saml2assertion.getID());  					} catch (SchemaValidationException e) { +						isAssertionValid = false; +						Logger.info("Assertion:" + saml2assertion.getID() +								+ " Schema validation FAILED. Msg:" + e.getMessage()); +												 +					} catch (ValidationException e) { +						isAssertionValid = false; +						Logger.info("Assertion:" + saml2assertion.getID() +								+ " AudienceRestriction schema-validation FAILED. Msg:" + e.getMessage());  					}  				}  				if (validatedassertions.isEmpty()) {  					Logger.info("No valid PVP 2.1 assertion received."); -					throw new AssertionValidationExeption("No valid PVP 2.1 assertion received.", null); +					throw new AssertionValidationExeption("sp.pvp2.10", new Object[]{loggerSPName}); +					  				}  				samlResp.getAssertions().clear(); @@ -146,16 +228,26 @@ public class SAMLVerificationEngineSP extends SAMLVerificationEngine {  			} else {  				Logger.info("PVP 2.1 assertion includes an error. Receive errorcode "   						+ samlResp.getStatus().getStatusCode().getValue()); -				throw new AssertionValidationExeption("PVP 2.1 assertion includes an error. Receive errorcode "  -						+ samlResp.getStatus().getStatusCode().getValue(), null); +				throw new AssertionValidationExeption("sp.pvp2.05",  +						new Object[]{loggerSPName,  +								samlResp.getIssuer().getValue(),  +								samlResp.getStatus().getStatusCode().getValue(), +								samlResp.getStatus().getStatusMessage().getMessage()}); +				  			}  		} catch (DecryptionException e) {  			Logger.warn("Assertion decrypt FAILED.", e); -			throw new AssertionValidationExeption("Assertion decrypt FAILED.", null, e); +			throw new AssertionValidationExeption("sp.pvp2.11", null, e);  		} catch (ConfigurationException e) {  			throw new AssertionValidationExeption("pvp.12", null, e);  		} 		  	} +	 +	protected static boolean urlCompare(String url1, String url2) { +		BasicURLComparator comparator = new BasicURLComparator(); +		comparator.setCaseInsensitive(false); +		return comparator.compare(url1, url2); +	}  } diff --git a/id/server/idserverlib/src/main/resources/resources/properties/id_messages_de.properties b/id/server/idserverlib/src/main/resources/resources/properties/id_messages_de.properties index a53d7e920..34ef9c1d0 100644 --- a/id/server/idserverlib/src/main/resources/resources/properties/id_messages_de.properties +++ b/id/server/idserverlib/src/main/resources/resources/properties/id_messages_de.properties @@ -292,6 +292,8 @@ sp.pvp2.06=Receive invalid PVP Response from {0}. Assertion does not contain all  sp.pvp2.07=Receive invalid PVP Response from {0}. Attribute {1} is not valid.
  sp.pvp2.08=Receive invalid PVP Response from {0}. Response issuer {1} is not valid or allowed.
  sp.pvp2.09=Receive invalid PVP Response from {0} {1}. StatusCodes:{2} {3} Msg:{4}
 +sp.pvp2.10=Receive invalid PVP Response from {0}. No valid assertion included.
 +sp.pvp2.11=Receive invalid PVP Response from {0}. Assertion decryption FAILED.
  oauth20.01=Fehlerhafte redirect url
  oauth20.02=Fehlender oder ung\u00FCltiger Parameter "{0}"
 diff --git a/id/server/idserverlib/src/main/resources/resources/properties/protocol_response_statuscodes_de.properties b/id/server/idserverlib/src/main/resources/resources/properties/protocol_response_statuscodes_de.properties index a81540e2b..27070cc84 100644 --- a/id/server/idserverlib/src/main/resources/resources/properties/protocol_response_statuscodes_de.properties +++ b/id/server/idserverlib/src/main/resources/resources/properties/protocol_response_statuscodes_de.properties @@ -111,6 +111,8 @@ sp.pvp2.06=TODO  sp.pvp2.07=TODO  sp.pvp2.08=TODO  sp.pvp2.09=TODO +sp.pvp2.10=TODO +sp.pvp2.11=TODO  validator.00=1102  validator.01=1102 | 
