Java tutorial
/******************************************************************************* * 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 java.util.Properties; 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.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactoryConfigurationError; 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.codec.binary.Base64; 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 org.bouncycastle.util.encoders.UrlBase64; import at.gv.egovernment.moa.id.auth.exception.MOAIDException; import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; 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 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.api.exceptions.UtilsException; 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; import eu.stork.documentservice.data.DatabaseConnectorMySQLImpl; /** * 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 { AuthConfigurationProvider authConfigurationProvider = AuthConfigurationProvider.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(Base64.decodeBase64(base64), "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", Base64.encodeBase64String(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; } }