diff options
Diffstat (limited to 'id')
10 files changed, 290 insertions, 38 deletions
| diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationDataBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationDataBuilder.java index 3264fc3bd..cad3354f5 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationDataBuilder.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationDataBuilder.java @@ -71,7 +71,6 @@ import at.gv.egovernment.moa.id.data.AuthenticationRoleFactory;  import at.gv.egovernment.moa.id.data.IAuthData;  import at.gv.egovernment.moa.id.data.MISMandate;  import at.gv.egovernment.moa.id.data.Pair; -import at.gv.egovernment.moa.id.moduls.RequestImpl;  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.builder.AttributQueryBuilder; @@ -1105,16 +1104,20 @@ public class AuthenticationDataBuilder extends MOAIDAuthConstants {  		String baseID = authData.getIdentificationValue();  		String baseIDType = authData.getIdentificationType(); -		 -		String eIDASOutboundCountry = pendingReq.getGenericData(RequestImpl.eIDAS_GENERIC_REQ_DATA_COUNTRY, String.class); -		 -		//TODO: maybe find a better solution -		String cititzenCountryCode =  -				authConfig.getBasicMOAIDConfiguration("moa.id.protocols.eIDAS.node.countrycode",  -						MOAIDAuthConstants.COUNTRYCODE_AUSTRIA); -		 -		 if (Constants.URN_PREFIX_BASEID.equals(baseIDType)) { -			 if (MiscUtil.isNotEmpty(eIDASOutboundCountry) && !cititzenCountryCode.equals(eIDASOutboundCountry)) { +			 +		 if (Constants.URN_PREFIX_BASEID.equals(baseIDType)) {			  +			 //Calculate eIDAS identifier +			 if (oaParam.getBusinessService() &&  +					 oaParam.getIdentityLinkDomainIdentifier().startsWith(Constants.URN_PREFIX_EIDAS)) {  +				 String[] splittedTarget = oaParam.getIdentityLinkDomainIdentifier().split("\\+"); +				 String cititzenCountryCode = splittedTarget[1]; +				 String eIDASOutboundCountry = splittedTarget[2];				  +				  +				 if (cititzenCountryCode.equalsIgnoreCase(eIDASOutboundCountry)) { +					 Logger.warn("Suspect configuration FOUND!!! CitizenCountry equals DestinationCountry"); +					  +				 } +				 				   				 Pair<String, String> eIDASID = new BPKBuilder().buildeIDASIdentifer(baseIDType, baseID,   						 cititzenCountryCode, eIDASOutboundCountry);  				 Logger.debug("Authenticate user with bPK:" + eIDASID.getFirst() + " Type:" + eIDASID.getSecond());	 diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/RequestImpl.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/RequestImpl.java index b612352c6..b87574d52 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/RequestImpl.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/RequestImpl.java @@ -61,7 +61,7 @@ public abstract class RequestImpl implements IRequest, Serializable{  	public static final String DATAID_REQUESTER_IP_ADDRESS = "requesterIP"; -	public static final String eIDAS_GENERIC_REQ_DATA_COUNTRY = "country"; +//	public static final String eIDAS_GENERIC_REQ_DATA_COUNTRY = "country";  	public static final String eIDAS_GENERIC_REQ_DATA_LEVELOFASSURENCE = "eIDAS_LoA"; 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 79dc11f34..1a2f0d1d3 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 @@ -272,6 +272,7 @@ eIDAS.12=Received eIDAS AuthnRequest is not valid. Reason:{0}  eIDAS.13=Generation of eIDAS Response FAILED. Reason:{0}
  eIDAS.14=eIDAS Response validation FAILED: LevelOfAssurance {0} is to low.
  eIDAS.15=Generation of eIDAS Response FAILED. Required attribute: {0} is NOT available.
 +eIDAS.16=eIDAS Response attribute-validation FAILED. Attribute:{0} Reason: {1}.
  pvp2.01=Fehler beim kodieren der PVP2 Antwort
  pvp2.02=Ungueltiges Datumsformat
 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 8d6c77831..c6d0844ce 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 @@ -229,6 +229,7 @@ eIDAS.12=1305  eIDAS.13=1307  eIDAS.14=1301  eIDAS.15=1307 +eIDAS.16=1301  pvp2.01=6100  pvp2.06=6100 diff --git a/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/util/Constants.java b/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/util/Constants.java index 260b2ecb1..129478270 100644 --- a/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/util/Constants.java +++ b/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/util/Constants.java @@ -449,7 +449,7 @@ public interface Constants {    //TODO: update to eIDAS prefix    /** URN prefix for context dependent id (eIDAS). */ -  public static final String URN_PREFIX_EIDAS = URN_PREFIX + ":storkid"; +  public static final String URN_PREFIX_EIDAS = URN_PREFIX + ":eidasid";    /** URN prefix for context dependent id. */    public static final String URN_PREFIX_BASEID = URN_PREFIX + ":baseid"; diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/ReceiveAuthnResponseTask.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/ReceiveAuthnResponseTask.java index c4b2bfeae..45ba3d64e 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/ReceiveAuthnResponseTask.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/ReceiveAuthnResponseTask.java @@ -19,12 +19,12 @@ import at.gv.egovernment.moa.id.auth.modules.eidas.utils.SAMLEngineUtils;  import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException;  import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException;  import at.gv.egovernment.moa.id.process.api.ExecutionContext; +import at.gv.egovernment.moa.id.protocols.eidas.validator.eIDASResponseValidator;  import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants;  import at.gv.egovernment.moa.logging.Logger;  import at.gv.egovernment.moa.util.MiscUtil;  import eu.eidas.auth.commons.EidasStringUtil;  import eu.eidas.auth.commons.protocol.IAuthenticationResponse; -import eu.eidas.auth.commons.protocol.eidas.LevelOfAssurance;  import eu.eidas.auth.engine.ProtocolEngineI;  import eu.eidas.engine.exceptions.EIDASSAMLEngineException; @@ -78,16 +78,8 @@ public class ReceiveAuthnResponseTask extends AbstractAuthServletTask {  			// **********************************************************  			// *******   MOA-ID specific response validation   **********  			// ********************************************************** -			 -			//validate received LoA against minimum required LoA -			LevelOfAssurance reqLoA = LevelOfAssurance.fromString(pendingReq.getOnlineApplicationConfiguration().getQaaLevel()); -			LevelOfAssurance respLoA = LevelOfAssurance.fromString(samlResp.getLevelOfAssurance());  -			if (respLoA.numericValue() < reqLoA.numericValue()) { -				Logger.error("eIDAS Response LevelOfAssurance is lower than the required! " -						+ "(Resp-LoA:" + respLoA.getValue() + " Req-LoA:" + reqLoA.getValue() + ")"); -				throw new MOAIDException("eIDAS.14", new Object[]{respLoA.getValue()}); -				 -			} +			String spCountry = authConfig.getBasicMOAIDConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_COUNTRYCODE, "AT"); +			eIDASResponseValidator.validateResponse(pendingReq, samlResp, spCountry);  			// ********************************************************** diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/eIDASAttributeProcessingUtils.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/eIDASAttributeProcessingUtils.java new file mode 100644 index 000000000..30e1e4505 --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/eIDASAttributeProcessingUtils.java @@ -0,0 +1,75 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.auth.modules.eidas.utils; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import at.gv.egovernment.moa.id.auth.modules.eidas.Constants; +import at.gv.egovernment.moa.id.data.Trible; +import at.gv.egovernment.moa.logging.Logger; + +/** + * @author tlenz + * + */ +public class eIDASAttributeProcessingUtils { +	public static final String PERSONALIDENIFIER_VALIDATION_PATTERN = "^[A-Z,a-z]{2}/[A-Z,a-z]{2}/.*"; +	 +	/** +	 * Validate a eIDAS PersonalIdentifier attribute value  +	 * This validation is done according to eIDAS SAML Attribute Profile -  Section 2.2.3 Unique Identifier  +	 *  +	 * @param uniqueID eIDAS attribute value of a unique identifier +	 * @return true if the uniqueID matches to eIDAS to Unique Identifier specification, otherwise false +	 */ +	public static boolean validateEidasPersonalIdentifier(String uniqueID) { +		Pattern pattern = Pattern.compile(PERSONALIDENIFIER_VALIDATION_PATTERN ); +		Matcher matcher = pattern.matcher(uniqueID);	 +		return matcher.matches(); +		 +	} +	 +	 +	/** +	 * Parse an eIDAS PersonalIdentifier attribute value into it components.  +	 * This processing is done according to eIDAS SAML Attribute Profile -  Section 2.2.3 Unique Identifier  +	 *  +	 * @param uniqueID eIDAS attribute value of a unique identifier +	 * @return {@link Trible} that contains:  +	 * 				<br> First : citizen country +	 * 				<br> Second: destination country +	 * 				<br> Third : unique identifier +	 * 	<br> or null if the attribute value has a wrong format +	 */					 +	public static Trible<String, String, String> parseEidasPersonalIdentifier(String uniqueID) { +		if (!validateEidasPersonalIdentifier(uniqueID)) { +			Logger.error("eIDAS attribute value for " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER  +					+ " looks wrong formated. Value:" + ((String)uniqueID));				 +			return null; +			 +		}		 +		return Trible.newInstance(uniqueID.substring(0, 2), uniqueID.substring(3, 5), uniqueID.substring(6));  +		 +	} +} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EIDASProtocol.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EIDASProtocol.java index aefae939b..589cd9654 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EIDASProtocol.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EIDASProtocol.java @@ -25,6 +25,8 @@ package at.gv.egovernment.moa.id.protocols.eidas;  import java.io.IOException;  import java.io.StringWriter;  import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern;  import javax.servlet.http.HttpServletRequest;  import javax.servlet.http.HttpServletResponse; @@ -213,6 +215,11 @@ public class EIDASProtocol extends AbstractAuthProtocolModulController {  			} +			//check eIDAS node configuration +			IOAAuthParameters oaConfig = authConfig.getOnlineApplicationParameter(samlReq.getIssuer()); +			if (oaConfig == null) +				throw new EIDASAuthnRequestProcessingException("eIDAS.08", new Object[]{samlReq.getIssuer()}); +			  			//validate AssertionConsumerServiceURL against metadata   			EntityDescriptor eIDASNodeEntityDesc = new MOAeIDASMetadataProviderDecorator(eIDASMetadataProvider)  						.getEntityDescriptor(eIDASSamlReq.getIssuer(), SAMLEngineUtils.getMetadataSigner()); @@ -258,8 +265,33 @@ public class EIDASProtocol extends AbstractAuthProtocolModulController {  			}		 +			//validate request country-code against eIDAS node config +			String reqCC = samlReq.getOriginCountryCode(); +			String eIDASTarget = oaConfig.getIdentityLinkDomainIdentifier(); + +			//validate eIDAS target +			Pattern pattern = Pattern.compile("^" + at.gv.egovernment.moa.util.Constants.URN_PREFIX_EIDAS  +					+ "\\+[A-Z,a-z]{2}\\+[A-Z,a-z]{2}$"); +			Matcher matcher = pattern.matcher(eIDASTarget);						 +			if (MiscUtil.isEmpty(eIDASTarget) || !matcher.matches()) { +				Logger.error("Configuration for eIDAS-node:" + samlReq.getIssuer()  +					+ " contains wrong formated eIDAS target:" + eIDASTarget); +				throw new MOAIDException("config.08", new Object[]{samlReq.getIssuer()}); +				 +			} else { +				String[] splittedTarget = eIDASTarget.split("\\+"); +				if (!splittedTarget[2].equalsIgnoreCase(reqCC)) { +					Logger.error("Configuration for eIDAS-node:" + samlReq.getIssuer()  +						+ " Destination Country from request (" + reqCC  +						+ ") does not match to configuration:" + eIDASTarget); +					throw new MOAIDException("eIDAS.01",  +							new Object[]{"Destination Country from request does not match to configuration"}); +					 +				} +				Logger.debug("CountryCode from request matches eIDAS-node configuration target"); +			} -			 +						  			//*************************************************  			//*****  store eIDAS request information  *********  			//************************************************* @@ -269,10 +301,6 @@ public class EIDASProtocol extends AbstractAuthProtocolModulController {  			// - memorize relaystate  			String relayState = request.getParameter("RelayState");  			pendingReq.setRemoteRelayState(relayState); - -			// - memorize country code of target country -			pendingReq.setGenericDataToSession( -					RequestImpl.eIDAS_GENERIC_REQ_DATA_COUNTRY, samlReq.getOriginCountryCode());  			//store level of assurance  			pendingReq.setGenericDataToSession(RequestImpl.eIDAS_GENERIC_REQ_DATA_LEVELOFASSURENCE,  @@ -288,10 +316,6 @@ public class EIDASProtocol extends AbstractAuthProtocolModulController {  			pendingReq.setOAURL(samlReq.getIssuer());  			// - memorize OA config -			IOAAuthParameters oaConfig = authConfig.getOnlineApplicationParameter(pendingReq.getOAURL()); -			if (oaConfig == null) -				throw new EIDASAuthnRequestProcessingException("eIDAS.08", new Object[]{pendingReq.getOAURL()}); -			  			pendingReq.setOnlineApplicationConfiguration(oaConfig);  			// - memorize service-provider type from eIDAS request @@ -302,7 +326,7 @@ public class EIDASProtocol extends AbstractAuthProtocolModulController {  			if (MiscUtil.isEmpty(spType))  				spType = MetadataUtil.getSPTypeFromMetadata(eIDASNodeEntityDesc); -			if (MiscUtil.isEmpty(spType)) +			if (MiscUtil.isNotEmpty(spType))  				Logger.debug("eIDAS request has SPType:" + spType);			  			else  				Logger.info("eIDAS request and eIDAS metadata contains NO 'SPType' element."); diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/eIDASAuthenticationRequest.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/eIDASAuthenticationRequest.java index f0e7e918b..26a171ba8 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/eIDASAuthenticationRequest.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/eIDASAuthenticationRequest.java @@ -43,12 +43,14 @@ import at.gv.egovernment.moa.id.auth.frontend.velocity.VelocityProvider;  import at.gv.egovernment.moa.id.auth.modules.eidas.Constants;  import at.gv.egovernment.moa.id.auth.modules.eidas.engine.MOAeIDASChainingMetadataProvider;  import at.gv.egovernment.moa.id.auth.modules.eidas.utils.SimpleEidasAttributeGenerator; +import at.gv.egovernment.moa.id.auth.modules.eidas.utils.eIDASAttributeProcessingUtils;  import at.gv.egovernment.moa.id.commons.MOAIDConstants;  import at.gv.egovernment.moa.id.commons.api.IRequest;  import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException;  import at.gv.egovernment.moa.id.data.IAuthData;  import at.gv.egovernment.moa.id.data.SLOInformationImpl;  import at.gv.egovernment.moa.id.data.SLOInformationInterface; +import at.gv.egovernment.moa.id.data.Trible;  import at.gv.egovernment.moa.id.moduls.IAction;  import at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator;  import at.gv.egovernment.moa.id.protocols.builder.attributes.MandateLegalPersonFullNameAttributeBuilder; @@ -121,12 +123,28 @@ public class eIDASAuthenticationRequest implements IAction {  						newValue = authData.getBPK();  						isUniqueID = true; +						//generate eIDAS conform 'PersonalIdentifier' attribute +						if (!eIDASAttributeProcessingUtils.validateEidasPersonalIdentifier(newValue)) { +							Logger.debug("preCalculated PersonalIdentifier does not include eIDAS conform prefixes ... add prefix now"); +							if (MiscUtil.isEmpty(authData.getBPKType()) +									|| !authData.getBPKType().startsWith(at.gv.egovernment.moa.util.Constants.URN_PREFIX_EIDAS)) { +								Logger.error("BPKType is empty or does not start with eIDAS bPKType prefix! bPKType:" + authData.getBPKType()); +								throw new MOAIDException("builder.08", new Object[]{"Suspect bPKType for eIDAS identifier generation"}); +								 +							}  +							 +							String prefix = authData.getBPKType().substring(at.gv.egovernment.moa.util.Constants.URN_PREFIX_EIDAS.length() + 1); +							newValue = prefix.replaceAll("\\+", "/") + "/" + newValue; +														 +						} +												  						//generate a transient unique identifier if it is requested  						String reqNameIDFormat = eidasRequest.getEidasRequest().getNameIdFormat();  						if (MiscUtil.isNotEmpty(reqNameIDFormat)   								&& reqNameIDFormat.equals(SamlNameIdFormat.TRANSIENT.getNameIdFormat()))  							newValue = generateTransientNameID(newValue); -																			 + +												  						subjectNameID = newValue;  						break;  					case Constants.eIDAS_ATTR_LEGALPERSONIDENTIFIER: @@ -301,12 +319,20 @@ public class eIDASAuthenticationRequest implements IAction {  	private String generateTransientNameID(String nameID) { -		String random = Random.nextLongRandom(); +		//extract source-country and destination country from persistent identifier  +		Trible<String, String, String> split = eIDASAttributeProcessingUtils.parseEidasPersonalIdentifier(nameID); +		if (split == null) { +			Logger.error("eIDAS 'PersonalIdentifier' has a wrong format. There had to be a ERROR in implementation!!!!"); +			throw new IllegalStateException("eIDAS 'PersonalIdentifier' has a wrong format. There had to be a ERROR in implementation!!!!"); +			 +		}  +		//build correct formated transient identifier +		String random = Random.nextLongRandom();		  		try {  			MessageDigest md = MessageDigest.getInstance("SHA-1"); -			byte[] hash = md.digest((nameID + random).getBytes("ISO-8859-1"));			 -			return Base64Utils.encode(hash); +			byte[] hash = md.digest((split.getThird() + random).getBytes("ISO-8859-1"));			 +			return split.getFirst() + "/" + split.getSecond() + "/" + Base64Utils.encode(hash);  		} catch (Exception e) {  			Logger.error("Can not generate transient personal identifier!", e); diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/validator/eIDASResponseValidator.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/validator/eIDASResponseValidator.java new file mode 100644 index 000000000..f0527bc5e --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/validator/eIDASResponseValidator.java @@ -0,0 +1,130 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.eidas.validator; + +import at.gv.egovernment.moa.id.auth.modules.eidas.Constants; +import at.gv.egovernment.moa.id.auth.modules.eidas.utils.SAMLEngineUtils; +import at.gv.egovernment.moa.id.auth.modules.eidas.utils.eIDASAttributeProcessingUtils; +import at.gv.egovernment.moa.id.commons.api.IRequest; +import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException; +import at.gv.egovernment.moa.id.data.Trible; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.MiscUtil; +import eu.eidas.auth.commons.protocol.IAuthenticationResponse; +import eu.eidas.auth.commons.protocol.eidas.LevelOfAssurance; + +/** + * @author tlenz + * + */ +public class eIDASResponseValidator { +	 + +	public static void validateResponse(IRequest pendingReq, IAuthenticationResponse samlResp, String spCountry) throws MOAIDException {		 + +		/*-----------------------------------------------------| +		 * validate received LoA against minimum required LoA  | +		 *_____________________________________________________| +		 */ +		LevelOfAssurance reqLoA = LevelOfAssurance.fromString(pendingReq.getOnlineApplicationConfiguration().getQaaLevel()); +		LevelOfAssurance respLoA = LevelOfAssurance.fromString(samlResp.getLevelOfAssurance());  +		if (respLoA.numericValue() < reqLoA.numericValue()) { +			Logger.error("eIDAS Response LevelOfAssurance is lower than the required! " +					+ "(Resp-LoA:" + respLoA.getValue() + " Req-LoA:" + reqLoA.getValue() + ")"); +			throw new MOAIDException("eIDAS.14", new Object[]{respLoA.getValue()}); +			 +		} + +		/*-----------------------------------------------------| +		 *     validate 'PersonalIdentifier' attribute         | +		 *_____________________________________________________| +		 */ +		String respCC = samlResp.getCountry();		 +		Object personalIdObj = samlResp.getAttributes().getFirstValue( +	        		SAMLEngineUtils.getMapOfAllAvailableAttributes().get( +	        				Constants.eIDAS_ATTR_PERSONALIDENTIFIER)); +	    +		//check attribute type +		if (personalIdObj == null || !(personalIdObj instanceof String)) +	        	Logger.warn("eIDAS Response include NO 'PersonalIdentifier' attriubte " +	        			+ ".... That can be a BIG problem in further processing steps");	 +		 +		else { +			//validate attribute value format +			Trible<String, String, String> split =  +					eIDASAttributeProcessingUtils.parseEidasPersonalIdentifier((String)personalIdObj); +			if (split == null) { +				throw new MOAIDException("eIDAS.16",  +						new Object[]{ +								Constants.eIDAS_ATTR_PERSONALIDENTIFIER, +								"Wrong identifier format"}); +				 +			} else { +				//validation according to eIDAS SAML Attribute Profile, Section 2.2.3  +				if (MiscUtil.isEmpty(split.getSecond())) { +					Logger.error("eIDAS attribute value for " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER  +							+ " includes NO destination country. Value:" + ((String)personalIdObj));				 +					throw new MOAIDException("eIDAS.16",  +							new Object[]{ +									Constants.eIDAS_ATTR_PERSONALIDENTIFIER, +									"No or empty destination country"}); +					 +				} +				if (!split.getSecond().equalsIgnoreCase(spCountry)) { +					Logger.error("eIDAS attribute value for " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER  +							+ " includes wrong destination country. Value:" + ((String)personalIdObj) +							+ " SP-Country:" + spCountry);				 +					throw new MOAIDException("eIDAS.16",  +							new Object[]{ +									Constants.eIDAS_ATTR_PERSONALIDENTIFIER, +									"Destination country does not match to SP country"}); +					 +				} +				 +				if (MiscUtil.isEmpty(split.getFirst())) { +					Logger.error("eIDAS attribute value for " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER  +							+ " includes NO citizen country. Value:" + ((String)personalIdObj));				 +					throw new MOAIDException("eIDAS.16",  +							new Object[]{ +									Constants.eIDAS_ATTR_PERSONALIDENTIFIER, +									"No or empty citizen country"}); +					 +				} +				if (!split.getFirst().equalsIgnoreCase(respCC)) { +					Logger.error("eIDAS attribute value for " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER  +							+ " includes a citizen country that does not match to eIDAS Response node. " +							+ " Value:" + ((String)personalIdObj) +							+ " Response-Node Country:" + respCC);				 +					throw new MOAIDException("eIDAS.16",  +							new Object[]{ +									Constants.eIDAS_ATTR_PERSONALIDENTIFIER, +									"Citizen country does not match to eIDAS-node country that generates the response"}); +					 +				}				 +			}									 +		} +		 +		 +		 +	} +} | 
