diff options
| -rw-r--r-- | id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/GenerateAuthnRequestTask.java | 178 | 
1 files changed, 133 insertions, 45 deletions
| diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/GenerateAuthnRequestTask.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/GenerateAuthnRequestTask.java index 3522a16fd..a9c4d5d3a 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/GenerateAuthnRequestTask.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/GenerateAuthnRequestTask.java @@ -22,10 +22,13 @@   */  package at.gv.egovernment.moa.id.auth.modules.eidas.tasks; +import java.io.ByteArrayOutputStream;  import java.io.StringWriter;  import java.util.ArrayList;  import java.util.Collection;  import java.util.List; +import java.util.zip.Deflater; +import java.util.zip.DeflaterOutputStream;  import javax.servlet.http.HttpServletRequest;  import javax.servlet.http.HttpServletResponse; @@ -39,6 +42,7 @@ import org.opensaml.common.xml.SAMLConstants;  import org.opensaml.saml2.metadata.EntityDescriptor;  import org.opensaml.saml2.metadata.SingleSignOnService;  import org.opensaml.saml2.metadata.provider.MetadataProviderException; +import org.opensaml.xml.util.Base64;  import org.springframework.beans.factory.annotation.Autowired;  import org.springframework.stereotype.Component; @@ -55,10 +59,12 @@ import at.gv.egovernment.moa.id.auth.modules.eidas.exceptions.EIDASEngineExcepti  import at.gv.egovernment.moa.id.auth.modules.eidas.utils.SAMLEngineUtils;  import at.gv.egovernment.moa.id.commons.MOAIDAuthConstants;  import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters; +import at.gv.egovernment.moa.id.commons.api.IRequest;  import at.gv.egovernment.moa.id.commons.api.data.CPEPS;  import at.gv.egovernment.moa.id.commons.api.data.StorkAttribute;  import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException;  import at.gv.egovernment.moa.id.process.api.ExecutionContext; +import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils;  import at.gv.egovernment.moa.logging.Logger;  import at.gv.egovernment.moa.util.MiscUtil;  import eu.eidas.auth.commons.EidasStringUtil; @@ -111,15 +117,15 @@ public class GenerateAuthnRequestTask extends AbstractAuthServletTask {  			// select SingleSignOnService Endpoint from eIDAS-node metadata  -			String destination = null; +			SingleSignOnService authnReqEndpoint = null;  			String metadataUrl = cpeps.getPepsURL().toString().split(";")[0].trim();  			try {  				EntityDescriptor eIDASNodeMetadata = eIDASMetadataProvider.getEntityDescriptor(metadataUrl);  				if (eIDASNodeMetadata != null) {  					SingleSignOnService ssoDescr = selectSingleSignOnServiceFromMetadata(eIDASNodeMetadata);  					if (ssoDescr != null) { -						destination = ssoDescr.getLocation(); -						Logger.debug("Use destination URL:" + destination + " from eIDAS metadata:" + metadataUrl); +						authnReqEndpoint = ssoDescr; +						Logger.debug("Use destination URL:" + authnReqEndpoint.getLocation() + " from eIDAS metadata:" + metadataUrl);  					} else  						Logger.warn("eIDAS metadata for node:" + metadataUrl + " has no IDPSSODescriptor or no SingleSignOnService information."); @@ -134,13 +140,21 @@ public class GenerateAuthnRequestTask extends AbstractAuthServletTask {  			// load SingleSignOnService Endpoint from configuration, if Metadata contains no information  			// FIXME convenience function for not standard conform metadata  -			if (MiscUtil.isEmpty(destination)) { +			if (authnReqEndpoint == null) { +				String destination = null;  				String[] splitString = cpeps.getPepsURL().toString().split(";");  				if (splitString.length > 1)				  					destination = cpeps.getPepsURL().toString().split(";")[1].trim(); -				if (MiscUtil.isNotEmpty(destination)) +				if (MiscUtil.isNotEmpty(destination)) {  					Logger.debug("Use eIDAS node destination URL:" + destination + " from configuration"); +					 +					//set POST binding as default binding, if Authn. request endpoint from config is used +					authnReqEndpoint = SAML2Utils.createSAMLObject(SingleSignOnService.class); +					authnReqEndpoint.setLocation(destination); +					authnReqEndpoint.setBinding(SAMLConstants.SAML2_POST_BINDING_URI); +					 +				}  				else {  					Logger.error("No eIDAS-node destination URL FOUND. Request eIDAS node not possible."); @@ -193,7 +207,7 @@ public class GenerateAuthnRequestTask extends AbstractAuthServletTask {  			authnRequestBuilder.providerName(pendingReq.getAuthURL());  			String issur = pendingReq.getAuthURL() + Constants.eIDAS_HTTP_ENDPOINT_METADATA;  			authnRequestBuilder.issuer(issur); -			authnRequestBuilder.destination(destination); +			authnRequestBuilder.destination(authnReqEndpoint.getLocation());  			authnRequestBuilder.nameIdFormat(Constants.eIDAS_REQ_NAMEID_FORMAT);			 @@ -226,45 +240,21 @@ public class GenerateAuthnRequestTask extends AbstractAuthServletTask {  			String SAMLRequest = EidasStringUtil.encodeToBase64(token); -			//send -	        try { -	            VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); -	            Template template = velocityEngine.getTemplate("/resources/templates/eidas_postbinding_template.vm"); -	            VelocityContext context = new VelocityContext(); - -	            String actionType = "SAMLRequest"; -	            context.put(actionType, SAMLRequest); -	            Logger.debug("Encoded " + actionType + " original: " + SAMLRequest); - -	            context.put("RelayState", pendingReq.getRequestID()); -	             -	            Logger.debug("Using assertion consumer url as action: " + destination); -	            context.put("action", destination); - -	            Logger.debug("Starting template merge"); -	            StringWriter writer = new StringWriter(); - -	            Logger.debug("Doing template merge"); -	            template.merge(context, writer); -	            Logger.debug("Template merge done"); - -	            Logger.debug("Sending html content: " + writer.getBuffer().toString()); -	             -	             -	            byte[] content = writer.getBuffer().toString().getBytes("UTF-8");	             -	            response.setContentType(MediaType.HTML_UTF_8.toString()); -	            response.setContentLength(content.length); -	            response.getOutputStream().write(content); +			if (SAMLConstants.SAML2_POST_BINDING_URI.equals(authnReqEndpoint.getBinding()))  +				buildPostBindingRequest(pendingReq, authnReqEndpoint, SAMLRequest, authnRequest, response); +			 +			//TODO: redirect Binding is not completely implemented +			//else if (SAMLConstants.SAML2_REDIRECT_BINDING_URI.equals(authnReqEndpoint.getBinding())) +				//buildRedirecttBindingRequest(pendingReq, authnReqEndpoint, token, authnRequest, response); +			 +			else { +				Logger.error("eIDAS-node use an unsupported binding (" +						+ authnReqEndpoint.getBinding() + "). Request eIDAS node not possible."); +				throw new MOAIDException("eIDAS.02", new Object[]{"eIDAS-node use an unsupported binding"}); +				 +			} +				 -	            revisionsLogger.logEvent(oaConfig, pendingReq,  -						MOAIDEventConstants.AUTHPROCESS_PEPS_REQUESTED, -						authnRequest.getRequest().getId()); -	            	         -	        } catch (Exception e) { -	            Logger.error("Velocity general error: " + e.getMessage()); -	            throw new MOAIDException("eIDAS.02", new Object[]{e.getMessage()}, e); -	             -	        }  		}catch (EIDASSAMLEngineException e){  			throw new TaskExecutionException(pendingReq, "eIDAS AuthnRequest generation FAILED.",  @@ -280,6 +270,102 @@ public class GenerateAuthnRequestTask extends AbstractAuthServletTask {  		}  	} +	/** +	 * Encode the eIDAS request with Redirect binding +	 *  +	 * @param pendingReq +	 * @param authnReqEndpoint +	 * @param token +	 * @param authnRequest +	 * @param response +	 * @throws MOAIDException +	 */ +	private void buildRedirecttBindingRequest(IRequest pendingReq, SingleSignOnService authnReqEndpoint,  +			byte[] token, IRequestMessage authnRequest, HttpServletResponse response)  +			throws MOAIDException { + +		//FIXME: implement correct deflat encoding accodring to SAML2 Redirect Binding specification +		 +		try {		 +			ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); +			Deflater deflater = new Deflater(Deflater.DEFLATED, true); +			DeflaterOutputStream deflaterStream = new DeflaterOutputStream(bytesOut, deflater); +			deflaterStream.write(token); +			deflaterStream.finish(); +			String samlReqBase64 =  Base64.encodeBytes(bytesOut.toByteArray(), Base64.DONT_BREAK_LINES); +			 +			 +			 +		} catch (Exception e) { +			 Logger.error("eIDAS Redirect-Binding request encoding error: " + e.getMessage()); +	         throw new MOAIDException("eIDAS.02", new Object[]{e.getMessage()}, e); +			 +		} +		 +	} +	 +	/** +	 * Encode the eIDAS request with POST binding +	 *  +	 * @param pendingReq +	 * @param authnReqEndpoint +	 * @param SAMLRequest +	 * @param authnRequest +	 * @param response +	 * @throws MOAIDException +	 */ +	private void buildPostBindingRequest(IRequest pendingReq, SingleSignOnService authnReqEndpoint,  +			String SAMLRequest, IRequestMessage authnRequest, HttpServletResponse response)  +			throws MOAIDException { +		//send +        try { +            VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); +            Template template = velocityEngine.getTemplate("/resources/templates/eidas_postbinding_template.vm"); +            VelocityContext context = new VelocityContext(); + +            String actionType = "SAMLRequest"; +            context.put(actionType, SAMLRequest); +            Logger.debug("Encoded " + actionType + " original: " + SAMLRequest); + +            context.put("RelayState", pendingReq.getRequestID()); +             +            Logger.debug("Using assertion consumer url as action: " + authnReqEndpoint.getLocation()); +            context.put("action", authnReqEndpoint.getLocation()); + +            Logger.debug("Starting template merge"); +            StringWriter writer = new StringWriter(); + +            Logger.debug("Doing template merge"); +            template.merge(context, writer); +            Logger.debug("Template merge done"); + +            Logger.debug("Sending html content: " + writer.getBuffer().toString()); +             +             +            byte[] content = writer.getBuffer().toString().getBytes("UTF-8");	             +            response.setContentType(MediaType.HTML_UTF_8.toString()); +            response.setContentLength(content.length); +            response.getOutputStream().write(content); + +            revisionsLogger.logEvent(pendingReq.getOnlineApplicationConfiguration(), pendingReq,  +					MOAIDEventConstants.AUTHPROCESS_PEPS_REQUESTED, +					authnRequest.getRequest().getId()); +            	         +        } catch (Exception e) { +            Logger.error("Velocity general error: " + e.getMessage()); +            throw new MOAIDException("eIDAS.02", new Object[]{e.getMessage()}, e); +             +        } +		 +	} +	 +	/** +	 * Select a SingleSignOnService endPoint from eIDAS node metadata. +	 * This endPoint receives the Authn. request +	 *  +	 * @param idpEntity +	 * @return +	 */  	private SingleSignOnService selectSingleSignOnServiceFromMetadata(EntityDescriptor idpEntity) {  		//select SingleSignOn Service endpoint from IDP metadata  		SingleSignOnService endpoint = null; @@ -294,7 +380,9 @@ public class GenerateAuthnRequestTask extends AbstractAuthServletTask {  			// use POST binding as default if it exists   			if (sss.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI))    				endpoint = sss; -				 +			 +			//TODO: redirect Binding is not completely implemented +			// use Redirect binding as backup	  //			else if ( sss.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI)   //					&& endpoint == null )  //				endpoint = sss; | 
