diff options
Diffstat (limited to 'id/server')
9 files changed, 162 insertions, 28 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 diff --git a/id/server/modules/moa-id-module-elga_mandate_service/src/main/java/at/gv/egovernment/moa/id/auth/modules/elgamandates/ELGAMandatesAuthConstants.java b/id/server/modules/moa-id-module-elga_mandate_service/src/main/java/at/gv/egovernment/moa/id/auth/modules/elgamandates/ELGAMandatesAuthConstants.java index e4eaa5ee7..b50d1cf4e 100644 --- a/id/server/modules/moa-id-module-elga_mandate_service/src/main/java/at/gv/egovernment/moa/id/auth/modules/elgamandates/ELGAMandatesAuthConstants.java +++ b/id/server/modules/moa-id-module-elga_mandate_service/src/main/java/at/gv/egovernment/moa/id/auth/modules/elgamandates/ELGAMandatesAuthConstants.java @@ -75,6 +75,9 @@ public class ELGAMandatesAuthConstants {  			Collections.unmodifiableList(new ArrayList<Pair<String, String>>() {  				private static final long serialVersionUID = 1L;  				{	 +					//add PVP Version attribute +					add(Pair.newInstance(PVPConstants.PVP_VERSION_NAME, PVPConstants.PVP_VERSION_FRIENDLY_NAME)); +					  					//request mandate type					  					add(Pair.newInstance(PVPConstants.MANDATE_TYPE_NAME, PVPConstants.MANDATE_TYPE_FRIENDLY_NAME)); diff --git a/id/server/modules/moa-id-module-elga_mandate_service/src/main/java/at/gv/egovernment/moa/id/auth/modules/elgamandates/tasks/ReceiveElgaMandateResponseTask.java b/id/server/modules/moa-id-module-elga_mandate_service/src/main/java/at/gv/egovernment/moa/id/auth/modules/elgamandates/tasks/ReceiveElgaMandateResponseTask.java index 0688e7c64..f976793b8 100644 --- a/id/server/modules/moa-id-module-elga_mandate_service/src/main/java/at/gv/egovernment/moa/id/auth/modules/elgamandates/tasks/ReceiveElgaMandateResponseTask.java +++ b/id/server/modules/moa-id-module-elga_mandate_service/src/main/java/at/gv/egovernment/moa/id/auth/modules/elgamandates/tasks/ReceiveElgaMandateResponseTask.java @@ -46,6 +46,7 @@ import at.gv.egovernment.moa.id.auth.modules.elgamandates.utils.ELGAMandateServi  import at.gv.egovernment.moa.id.auth.modules.elgamandates.utils.ELGAMandatesCredentialProvider;  import at.gv.egovernment.moa.id.process.api.ExecutionContext;  import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants; +import at.gv.egovernment.moa.id.protocols.pvp2x.PVPTargetConfiguration;  import at.gv.egovernment.moa.id.protocols.pvp2x.binding.IDecoder;  import at.gv.egovernment.moa.id.protocols.pvp2x.binding.MOAURICompare;  import at.gv.egovernment.moa.id.protocols.pvp2x.binding.PostBinding; @@ -142,6 +143,8 @@ public class ReceiveElgaMandateResponseTask extends AbstractAuthServletTask {  			} +			 +			  			//load MOASession object  			defaultTaskInitialization(request, executionContext); @@ -216,10 +219,28 @@ public class ReceiveElgaMandateResponseTask extends AbstractAuthServletTask {  		Logger.debug("Start PVP-2.1 assertion processing... ");  		Response samlResp = (Response) msg.getResponse(); +		//validate 'inResponseTo' attribute +		String authnReqID = pendingReq.getGenericData( +				PVPTargetConfiguration.DATAID_INTERFEDERATION_REQUESTID, String.class); +		String inResponseTo = samlResp.getInResponseTo(); +		 +		if (MiscUtil.isEmpty(authnReqID) || MiscUtil.isEmpty(inResponseTo) ||  +				!authnReqID.equals(inResponseTo)) { +			Logger.info("Validation of request/response IDs FAILED." +					+ " ReqID:" + authnReqID + " InRespTo:" + inResponseTo); +			throw new AuthnResponseValidationException("sp.pvp2.07",  +					new Object[]{ELGAMandatesAuthConstants.MODULE_NAME_FOR_LOGGING, +							"'InResponseTo'"}); +			 +		} +		  		// check SAML2 response status-code  		if (samlResp.getStatus().getStatusCode().getValue().equals(StatusCode.SUCCESS_URI)) {				  			//validate PVP 2.1 assertion -			samlVerificationEngine.validateAssertion(samlResp, true, credentialProvider.getIDPAssertionEncryptionCredential()); +			samlVerificationEngine.validateAssertion(samlResp, true,  +					credentialProvider.getIDPAssertionEncryptionCredential(), +					pendingReq.getAuthURL() + ELGAMandatesAuthConstants.ENDPOINT_METADATA, +					ELGAMandatesAuthConstants.MODULE_NAME_FOR_LOGGING);  			msg.setSAMLMessage(SAML2Utils.asDOMDocument(samlResp).getDocumentElement());  			return msg; diff --git a/id/server/modules/moa-id-module-elga_mandate_service/src/main/java/at/gv/egovernment/moa/id/auth/modules/elgamandates/tasks/RequestELGAMandateTask.java b/id/server/modules/moa-id-module-elga_mandate_service/src/main/java/at/gv/egovernment/moa/id/auth/modules/elgamandates/tasks/RequestELGAMandateTask.java index 2a3e72640..d25921167 100644 --- a/id/server/modules/moa-id-module-elga_mandate_service/src/main/java/at/gv/egovernment/moa/id/auth/modules/elgamandates/tasks/RequestELGAMandateTask.java +++ b/id/server/modules/moa-id-module-elga_mandate_service/src/main/java/at/gv/egovernment/moa/id/auth/modules/elgamandates/tasks/RequestELGAMandateTask.java @@ -46,6 +46,7 @@ import at.gv.egovernment.moa.id.auth.modules.elgamandates.utils.ELGAMandateServi  import at.gv.egovernment.moa.id.auth.modules.elgamandates.utils.ELGAMandatesCredentialProvider;  import at.gv.egovernment.moa.id.config.auth.AuthConfiguration;  import at.gv.egovernment.moa.id.process.api.ExecutionContext; +import at.gv.egovernment.moa.id.protocols.pvp2x.PVPTargetConfiguration;  import at.gv.egovernment.moa.id.protocols.pvp2x.builder.PVPAuthnRequestBuilder;  import at.gv.egovernment.moa.logging.Logger;  import at.gv.egovernment.moa.util.Constants; @@ -137,7 +138,13 @@ public class RequestELGAMandateTask extends AbstractAuthServletTask {  			//set MandateReferenceValue as RequestID  			authnReqConfig.setRequestID(moasession.getMandateReferenceValue()); -						 +			pendingReq.setGenericDataToSession( +					PVPTargetConfiguration.DATAID_INTERFEDERATION_REQUESTID, +					authnReqConfig.getRequestID()); +			 +			//store pending-request +			requestStoreage.storePendingRequest(pendingReq); +			  			//build and transmit AuthnRequest  			authnReqBuilder.buildAuthnRequest(pendingReq, authnReqConfig , response); diff --git a/id/server/modules/moa-id-modules-federated_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/federatedauth/tasks/ReceiveAuthnResponseTask.java b/id/server/modules/moa-id-modules-federated_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/federatedauth/tasks/ReceiveAuthnResponseTask.java index d5c5354c0..01163efd6 100644 --- a/id/server/modules/moa-id-modules-federated_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/federatedauth/tasks/ReceiveAuthnResponseTask.java +++ b/id/server/modules/moa-id-modules-federated_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/federatedauth/tasks/ReceiveAuthnResponseTask.java @@ -347,7 +347,10 @@ public class ReceiveAuthnResponseTask extends AbstractAuthServletTask {  		// check SAML2 response status-code  		if (samlResp.getStatus().getStatusCode().getValue().equals(StatusCode.SUCCESS_URI)) {				  			//validate PVP 2.1 assertion -			samlVerificationEngine.validateAssertion(samlResp, true, credentialProvider.getIDPAssertionEncryptionCredential()); +			samlVerificationEngine.validateAssertion(samlResp, true,  +					credentialProvider.getIDPAssertionEncryptionCredential(), +					pendingReq.getAuthURL() + FederatedAuthConstants.ENDPOINT_METADATA, +					FederatedAuthConstants.MODULE_NAME_FOR_LOGGING);  			msg.setSAMLMessage(SAML2Utils.asDOMDocument(samlResp).getDocumentElement());  			return msg; | 
