diff options
Diffstat (limited to 'id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/attributeproviders/SignedDocAttributeRequestProvider.java')
-rw-r--r-- | id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/attributeproviders/SignedDocAttributeRequestProvider.java | 688 |
1 files changed, 688 insertions, 0 deletions
diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/attributeproviders/SignedDocAttributeRequestProvider.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/attributeproviders/SignedDocAttributeRequestProvider.java new file mode 100644 index 000000000..def89d0d9 --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/attributeproviders/SignedDocAttributeRequestProvider.java @@ -0,0 +1,688 @@ +/******************************************************************************* + * 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.stork2.attributeproviders; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; +import java.io.UnsupportedEncodingException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.activation.DataSource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.namespace.QName; +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamSource; +import javax.xml.ws.Service; +import javax.xml.ws.soap.SOAPBinding; +import javax.xml.ws.BindingProvider; + +import eu.stork.peps.complex.attributes.eu.stork.names.tc.stork._1_0.assertion.AttributeStatusType; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.NotImplementedException; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; + +import at.gv.egovernment.moa.id.auth.exception.MOAIDException; +import at.gv.egovernment.moa.id.config.auth.AuthConfiguration; +import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProviderFactory; +import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; +import at.gv.egovernment.moa.id.data.IAuthData; +import at.gv.egovernment.moa.id.protocols.stork2.ExternalAttributeRequestRequiredException; +import at.gv.egovernment.moa.id.protocols.stork2.MOASTORKRequest; +import at.gv.egovernment.moa.id.protocols.stork2.UnsupportedAttributeException; +import at.gv.egovernment.moa.id.util.VelocityProvider; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.Base64Utils; +import eu.stork.oasisdss.api.ApiUtils; +import eu.stork.oasisdss.api.LightweightSourceResolver; +import eu.stork.oasisdss.api.ResultMajor; +import eu.stork.oasisdss.api.exceptions.ApiUtilsException; +import eu.stork.oasisdss.profile.AnyType; +import eu.stork.oasisdss.profile.Base64Data; +import eu.stork.oasisdss.profile.DocumentType; +import eu.stork.oasisdss.profile.DocumentWithSignature; +import eu.stork.oasisdss.profile.IncludeObject; +import eu.stork.oasisdss.profile.SignRequest; +import eu.stork.oasisdss.profile.SignResponse; +import eu.stork.peps.auth.commons.IPersonalAttributeList; +import eu.stork.peps.auth.commons.PEPSUtil; +import eu.stork.peps.auth.commons.PersonalAttribute; +import eu.stork.peps.auth.commons.PersonalAttributeList; +import eu.stork.peps.auth.commons.STORKAttrQueryRequest; +import eu.stork.peps.auth.engine.STORKSAMLEngine; +import eu.stork.peps.exceptions.STORKSAMLEngineException; +import eu.stork.documentservice.DocumentService; +/** + * Forwards a signedDoc attribute request to the oasis-dss service instance + */ +public class SignedDocAttributeRequestProvider extends AttributeProvider { + + private String dtlUrl = null; + private PersonalAttribute requestedAttribute; + + /** + * The URL of the service listening for the oasis dss webform post request + */ + private String oasisDssWebFormURL; + + /** + * Instantiates a new signed doc attribute request provider. + * + * @param oasisDssWebFormURL + * the AP location + * @param attributes + */ + public SignedDocAttributeRequestProvider(String oasisDssWebFormURL, String attributes) { + super(attributes); + this.oasisDssWebFormURL = oasisDssWebFormURL; + + try { + AuthConfiguration authConfigurationProvider = AuthConfigurationProviderFactory.getInstance(); + dtlUrl = authConfigurationProvider.getDocumentServiceUrl(); + Logger.info ("SignedDocAttributeRequestProvider, using dtlUrl:"+dtlUrl); + } catch (Exception e) { + dtlUrl = "http://testvidp.buergerkarte.at/DocumentService/DocumentService"; + e.printStackTrace(); + Logger.error("Loading documentservice url failed, using default value:"+dtlUrl); + } + +// Properties props = new Properties(); +// try { +// props.load(DatabaseConnectorMySQLImpl.class.getResourceAsStream("docservice.properties")); +// dtlUrl = props.getProperty("docservice.url"); +// } catch (IOException e) { +// dtlUrl = "http://testvidp.buergerkarte.at/DocumentService/DocumentService"; +// Logger.error("Loading DTL config failed, using default value:"+dtlUrl); +// e.printStackTrace(); +// } + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.stork2.AttributeProvider#acquire(java + * .lang.String) + */ + @Override + protected IPersonalAttributeList acquire(PersonalAttribute attribute, MOASTORKRequest moastorkRequest, IAuthData authData) throws UnsupportedAttributeException, + ExternalAttributeRequestRequiredException { + if(!attributes.contains(attribute.getName())) { + throw new UnsupportedAttributeException(); + } + + requestedAttribute = attribute; + try + { + String tmp = requestedAttribute.getValue().get(0); + }catch(Exception e) + { + Logger.info("SignedDocAttributeProvide failed:"+e.toString()); + throw new UnsupportedAttributeException(); + } + + throw new ExternalAttributeRequestRequiredException(this); + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.stork2.AttributeProvider#parse(javax + * .servlet.http.HttpServletRequest) + */ + public IPersonalAttributeList parse(HttpServletRequest httpReq) throws MOAIDException, UnsupportedAttributeException { + Logger.debug("Beginning to extract OASIS-DSS response out of HTTP Request"); + + try { + String base64 = httpReq.getParameter("signresponse"); + Logger.debug("signresponse url: " + httpReq.getRequestURI().toString()); + Logger.debug("signresponse querystring: " + httpReq.getQueryString()); + Logger.debug("signresponse method: " + httpReq.getMethod()); + Logger.debug("signresponse content type: " + httpReq.getContentType()); + Logger.debug("signresponse parameter:"+base64); + String signResponseString = new String(Base64Utils.decode(base64, false), "UTF8"); + Logger.debug("RECEIVED signresponse:"+signResponseString); + //create SignResponse object + Source response = new StreamSource(new java.io.StringReader(signResponseString)); + SignResponse signResponse = ApiUtils.unmarshal(response, SignResponse.class); + //Check if Signing was successfully or not + + if(!signResponse.getResult().getResultMajor().equals(ResultMajor.RESULT_MAJOR_SUCCESS)) + { + //Pass unmodifed or unmarshal & marshal?? + InputStream istr = ApiUtils.marshalToInputStream(signResponse); + StringWriter writer = new StringWriter(); + IOUtils.copy(istr, writer, "UTF-8"); + signResponseString = writer.toString(); + Logger.info("SignResponse with error (unmodified):"+signResponseString); + istr.close(); + } + else + { + //extract doc from signresponse + DataSource dataSource = LightweightSourceResolver.getDataSource(signResponse); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + IOUtils.copy(dataSource.getInputStream(), baos); + byte[] data = baos.toByteArray(); + baos.close(); + + //update doc in DTL + String docId, dssId = ""; + docId = signResponse.getDocUI(); + //For reference dssId equals docId + dssId = docId; + if (dssId != null && data!=null) + { + boolean success = false; + try{ + success = updateDocumentInDtl(data, docId, signResponseString); + }catch(Exception e){//No document service used? + Logger.info("No document service used?"); + e.printStackTrace(); + success = false; + } + if(success) + { + // set the url in the SignResponse + DocumentWithSignature documentWithSignature = new DocumentWithSignature(); + DocumentType value = new DocumentType(); + if(dtlUrl.endsWith("?wsdl")) + { + String tmp = dtlUrl.replace("?wsdl", ""); + Logger.debug("DocumentUrl ends with ? wsdl, using "+tmp+" instead."); + value.setDocumentURL(tmp); + } + else + { + value.setDocumentURL(dtlUrl); + } + documentWithSignature.setDocument(value); + if(signResponse.getOptionalOutputs()!=null) + { + //signResponse.getOptionalOutputs().getAny().add(documentWithSignature); + for(Object o :signResponse.getOptionalOutputs().getAny()) + { + if(o instanceof DocumentWithSignature) + { + signResponse.getOptionalOutputs().getAny().remove(o); + signResponse.getOptionalOutputs().getAny().add(documentWithSignature); + break; + } + } + } + else + { + AnyType anytype = new AnyType(); + anytype.getAny().add(documentWithSignature); + signResponse.setOptionalOutputs(anytype ); + } + + // System.out.println("overwriting:"+signResponse.getResult().getResultMessage()+" with DTL url:"+dtlUrl); + InputStream istr = ApiUtils.marshalToInputStream(signResponse); + StringWriter writer = new StringWriter(); + IOUtils.copy(istr, writer, "UTF-8"); + signResponseString = writer.toString(); + Logger.info("SignResponse overwritten:"+signResponseString); + istr.close(); + } + else + { + //No document service used? + // do nothing.... + //TODO temporary fix because document is deleted after fetching => SP can't download Doc + //Add doc to Signresponse + + DocumentWithSignature documentWithSignature = new DocumentWithSignature(); + DocumentType value = new DocumentType(); + if(signResponse.getProfile().toLowerCase().contains("xades")) + { + value.setBase64XML(data); + } + else + { + Base64Data base64data = new Base64Data(); + base64data.setValue(data); + base64data.setMimeType(dataSource.getContentType()); + value.setBase64Data(base64data); + } + documentWithSignature.setDocument(value); + if(signResponse.getOptionalOutputs()!=null) + { + //signResponse.getOptionalOutputs().getAny().add(documentWithSignature); + for(Object o :signResponse.getOptionalOutputs().getAny()) + { + if(o instanceof DocumentWithSignature) + { + signResponse.getOptionalOutputs().getAny().remove(o); + signResponse.getOptionalOutputs().getAny().add(documentWithSignature); + break; + } + } + } + else + { + AnyType anytype = new AnyType(); + anytype.getAny().add(documentWithSignature); + signResponse.setOptionalOutputs(anytype ); + } + + // System.out.println("overwriting:"+signResponse.getResult().getResultMessage()+" with DTL url:"+dtlUrl); + InputStream istr = ApiUtils.marshalToInputStream(signResponse); + StringWriter writer = new StringWriter(); + IOUtils.copy(istr, writer, "UTF-8"); + signResponseString = writer.toString(); + Logger.info("SignResponse overwritten:"+signResponseString); + istr.close(); + } + } + else + throw new Exception("No DSS id found."); + } + + //alter signresponse + //done + List<String> values = new ArrayList<String>(); + values.add(signResponseString); + + Logger.debug("Assembling signedDoc attribute"); + PersonalAttribute signedDocAttribute = new PersonalAttribute("signedDoc", false, values, + AttributeStatusType.AVAILABLE.value()); + + // pack and return the result + PersonalAttributeList result = new PersonalAttributeList(); + result.add(signedDocAttribute); + return result; + } catch (UnsupportedEncodingException e) { + Logger.error("Failed to assemble signedDoc attribute"); + throw new MOAIDException("stork.05", null); + } catch (ApiUtilsException e) { + e.printStackTrace(); + Logger.error("Failed to assemble signedDoc attribute"); + throw new MOAIDException("stork.05", null); + } catch (IOException e) { + e.printStackTrace(); + Logger.error("Failed to assemble signedDoc attribute"); + throw new MOAIDException("stork.05", null); + } catch (Exception e) { + e.printStackTrace(); + Logger.error("Failed to assemble signedDoc attribute"); + //throw new MOAIDException("stork.05", null); + throw new UnsupportedAttributeException(); + } + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.stork2.AttributeProvider#performRedirect + * (java.lang.String) + */ + public void performRedirect(String url, HttpServletRequest req, HttpServletResponse resp, OAAuthParameter oaParam) + throws MOAIDException { + + try { + Logger.trace("Initialize VelocityEngine..."); + Logger.info("performRedirect url:"+url); + VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); + Template template = velocityEngine.getTemplate("/resources/templates/oasis_dss_webform_binding.vm"); + VelocityContext context = new VelocityContext(); + + //Parse SignRequest + String signRequestString = requestedAttribute.getValue().get(0); + Logger.debug("performRedirect, signrequest:"+signRequestString); + Source signDoc = new StreamSource(new java.io.StringReader(signRequestString)); + SignRequest signRequest = ApiUtils.unmarshal(signDoc, SignRequest.class); + try{ + //search for DTL link + String dtlURL = getDtlUrlFromRequest(signRequest); + String docId = signRequest.getDocUI(); + + if(dtlURL!=null) + { + String docRequest = getDocTransferRequest(docId, dtlURL);//dtlUrl + + byte[] data = getDocumentFromDtl(docRequest, dtlURL);//dtlUrl + + //load doc from DTL + Logger.debug("data:"+data+" "+data.length); + try{ + Logger.trace("data:"+new String(data,"UTF-8")); + }catch(Exception e) + { + Logger.trace("data: creating String failed:"+e); + } + String mime = getDocumentMimeFromDtl(docId, dtlURL);//dtlUrl + Logger.debug("mime:"+mime); + + //add doc as base64* to signrequest => post doc to oasis + try{ + List<IncludeObject> includeObjects = ApiUtils.findNamedElement( + signRequest.getOptionalInputs(), "IncludeObject", + IncludeObject.class); + signRequest.getOptionalInputs().getAny().removeAll(includeObjects); + + String documentId = null; + Object objDoc = signRequest.getInputDocuments().getDocumentOrTransformedDataOrDocumentHash().get(0); + if (objDoc != null && objDoc instanceof DocumentType) + { + DocumentType document = (DocumentType)objDoc; + documentId = document.getID(); + } + DocumentType document = new DocumentType(); + if(documentId != null) + document.setID(documentId); + if(signRequest.getProfile().toLowerCase().contains("xades")) + { + document.setBase64XML(data); + } + else + { + Base64Data b64data = new Base64Data(); + b64data.setValue(data); + b64data.setMimeType(mime); + document.setBase64Data(b64data); + } + + signRequest.setInputDocuments(ApiUtils.createInputDocuments(document)); + //override old signRequestString + + InputStream istr = ApiUtils.marshalToInputStream(signRequest); + StringWriter writer = new StringWriter(); + IOUtils.copy(istr, writer, "UTF-8"); + signRequestString = writer.toString(); + Logger.info("Signrequest overwritten"); + Logger.debug("Signrequest overwritten:"+signRequestString); + istr.close(); + } catch (Exception e) { + e.printStackTrace(); + throw new Exception("Could not marshall sign request", e); + } + } + else//Do not modify signRequest, document is already included + { + + } + }catch(Exception e) + { + Logger.info("No documentservice used?"); + e.printStackTrace(); + } + + context.put("signrequest", Base64Utils.encode(signRequestString.getBytes("UTF8"))); + context.put("clienturl", url); + context.put("action", oasisDssWebFormURL); + + StringWriter writer = new StringWriter(); + template.merge(context, writer); + + resp.getOutputStream().write(writer.toString().getBytes("UTF-8")); + } catch (Exception e) { + Logger.error("Error sending DSS signrequest.", e); + throw new MOAIDException("stork.11", null); + } + } + + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.stork2.AttributeProvider#getSupportedAttributeNames() + */ + @Override + public List<String> getSupportedAttributeNames() throws MOAIDException { + ArrayList<String> supportedAttributeNames = new ArrayList<String>(); + for (String attributeName : this.attributes.split(",")) { + supportedAttributeNames.add(attributeName); + } + return supportedAttributeNames; + } + + + //From DTLPEPSUTIL + + /** + * Get DTL uril from the oasis sign request + * @param signRequest The signature request + * @return The URL of DTL service + * @throws SimpleException + */ + private String getDtlUrlFromRequest(SignRequest signRequest) throws Exception + { + if (signRequest == null) + throw new Exception("Signature request is empty"); + else + { + try + { + Object objDoc = signRequest.getInputDocuments().getDocumentOrTransformedDataOrDocumentHash().get(0); + if (objDoc instanceof DocumentType) + { + DocumentType document = (DocumentType)objDoc; + if (document.getDocumentURL() != null) + return document.getDocumentURL(); + else + return null;//throw new Exception("No document url found"); + } + else + throw new Exception("No input document found"); + } + catch (Exception ex) + { + throw new Exception("Unable to parse xml.", ex); + } + } + } + + /** + * Get document from DTL + * @param transferRequest The transfer request (attribute query) + * @param eDtlUrl The DTL url of external DTL + * @return the document data + * @throws SimpleException + */ + private byte[] getDocumentFromDtl(String transferRequest, String eDtlUrl) throws Exception + { + URL url = null; + try + { + Logger.debug("getDocumentFromDtl:"+dtlUrl); + url = new URL(dtlUrl); + QName qname = new QName("http://stork.eu", + "DocumentService"); + + Service service = Service.create(url, qname); + DocumentService docservice = service.getPort(DocumentService.class); + + BindingProvider bp = (BindingProvider) docservice; + SOAPBinding binding = (SOAPBinding) bp.getBinding(); + binding.setMTOMEnabled(true); + + if (eDtlUrl.equalsIgnoreCase(dtlUrl)) + return docservice.getDocument(transferRequest, ""); + else + return docservice.getDocument(transferRequest, eDtlUrl); + } + catch (Exception e) + { + e.printStackTrace(); + throw new Exception("Error in getDocumentFromDtl", e); + } + } + + /** + * Get a document transfer request (attribute query) + * @param docId + * @return + * @throws SimpleException + */ + private String getDocTransferRequest(String docId, String destinationUrl) throws Exception + { + String spCountry = docId.substring(0, docId.indexOf("/")); + final STORKSAMLEngine engine = STORKSAMLEngine.getInstance("VIDP"); + STORKAttrQueryRequest req = new STORKAttrQueryRequest(); + req.setAssertionConsumerServiceURL(dtlUrl); + req.setDestination(destinationUrl); + req.setSpCountry(spCountry); + req.setQaa(3);//TODO + PersonalAttributeList pal = new PersonalAttributeList(); + PersonalAttribute attr = new PersonalAttribute(); + attr.setName("docRequest"); + attr.setIsRequired(true); + attr.setValue(Arrays.asList(docId)); + pal.add(attr); + req.setPersonalAttributeList(pal); + + STORKAttrQueryRequest req1; + try { + req1 = engine.generateSTORKAttrQueryRequest(req); + return PEPSUtil.encodeSAMLTokenUrlSafe(req1.getTokenSaml()); + } catch (STORKSAMLEngineException e) { + e.printStackTrace(); + throw new Exception("Error in doc request attribute query generation", e); + } + } + + /** + * Get mime type of document from DTL + * @param docId The document id + * @param dtlUrl The url of dtl + * @return The mime type + */ + private String getDocumentMimeFromDtl(String docId, String eDtlUrl) throws Exception + { + URL url = null; + try + { + url = new URL(dtlUrl); + QName qname = new QName("http://stork.eu", + "DocumentService"); + + Service service = Service.create(url, qname); + DocumentService docservice = service.getPort(DocumentService.class); + + BindingProvider bp = (BindingProvider) docservice; + SOAPBinding binding = (SOAPBinding) bp.getBinding(); + binding.setMTOMEnabled(true); + + if (eDtlUrl.equalsIgnoreCase(dtlUrl)) + return docservice.getDocumentMime(docId, ""); + else + return docservice.getDocumentMime(docId, eDtlUrl); + } + catch (Exception e) + { + e.printStackTrace(); + throw new Exception("Error in getDocumentFromDtl", e); + } + } + + /** + * Add document to DTL service + * @param docData the document data + * @param mime the mime type of data + * @param signRequest the sign request + * @return the document id + * @throws SimpleException + */ + private String addDocumentToDtl(byte[] docData, String mime, String signRequest, String destCountry, String spId) throws Exception + { + throw new NotImplementedException(); +// URL url = null; +// String docID = null; +// try +// { +// url = new URL(dtlUrl); +// QName qname = new QName("http://stork.eu", +// "DocumentService"); +// +// Service service = Service.create(url, qname); +// DocumentService docservice = service.getPort(DocumentService.class); +// +// BindingProvider bp = (BindingProvider) docservice; +// SOAPBinding binding = (SOAPBinding) bp.getBinding(); +// binding.setMTOMEnabled(true); +// +// docID = docservice.addDocument(docData, signRequest, destCountry, spId, mime, ""); +// } +// catch (Exception e) +// { +// e.printStackTrace(); +// throw new Exception("Error in addDocumentToDtl", e); +// } +// +// return docID; + } + + /** + * Update document in DTL + * @param docData The docment data + * @param docId The document ID + * @param signResponse The signature response + * @return True if successful + * @throws SimpleException + */ + private boolean updateDocumentInDtl(byte[] docData, String docId, String signResponse) throws Exception + { + boolean success = false; + URL url = null; + try + { + url = new URL(dtlUrl); + QName qname = new QName("http://stork.eu", + "DocumentService"); + + Service service = Service.create(url, qname); + DocumentService docservice = service.getPort(DocumentService.class); + + BindingProvider bp = (BindingProvider) docservice; + SOAPBinding binding = (SOAPBinding) bp.getBinding(); + binding.setMTOMEnabled(true); + + success = docservice.updateDocument(docId, signResponse, docData); + } + catch (Exception e) + { + e.printStackTrace(); + throw new Exception("Error in updateDocumentInDtl", e); + } + + return success; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.stork2.attributeproviders.AttributeProvider#getPriority() + */ + @Override + public int getPriority() { + return 99; + } +} |