/*******************************************************************************
* 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.
******************************************************************************/
/*
* Copyright 2003 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.parser;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.cert.CertificateException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import org.apache.xpath.XPathAPI;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import at.gv.egiz.eaaf.core.api.idp.auth.data.IIdentityLink;
import at.gv.egiz.eaaf.core.impl.utils.DOMUtils;
import at.gv.egiz.eaaf.core.impl.utils.XPathUtils;
import at.gv.egovernment.moa.id.auth.exception.AuthenticationException;
import at.gv.egovernment.moa.id.auth.exception.ParseException;
import at.gv.egovernment.moa.id.commons.api.exceptions.BKUException;
import at.gv.egovernment.moa.util.Base64Utils;
import at.gv.egovernment.moa.util.Constants;
import iaik.x509.X509Certificate;
/**
* Parses an <InfoboxReadResponse>
.
*
* @author Stefan Knirsch
* @version $Id$
*/
public class InfoboxReadResponseParser {
/** This is the root element of the XML-Document provided by the Security Layer Card*/
private Element infoBoxElem_;
private static final Map parserFeatures =
Collections.unmodifiableMap(new HashMap() {
private static final long serialVersionUID = 1L;
{
put(DOMUtils.DISALLOW_DOCTYPE_FEATURE, true);
}
});
/**
* Parses and validates the document given as string and extracts the
* root element.
*
* @param xmlResponse <InfoboxReadResponse>
as String
* @throws ParseException If an element cannot be parsed
* @throws AuthenticationException If any authentication error occurs
* @throws BKUException
*/
public InfoboxReadResponseParser(String xmlResponse) throws ParseException, AuthenticationException, BKUException {
try {
InputStream s = new ByteArrayInputStream(xmlResponse.getBytes("UTF-8"));
init(s);
}
catch (BKUException e) {
throw e;
} catch (Throwable t) {
throw new ParseException("parser.01", new Object[] { t.toString()}, t);
}
}
/**
* Parses and validates the document given as stream and extracts the
* root element.
*
* @param is <InfoboxReadResponse>
as InputStream
* @throws ParseException If an element cannot be parsed
* @throws AuthenticationException If any authentication error occurs
* @throws BKUException
*/
public InfoboxReadResponseParser(InputStream is) throws ParseException, AuthenticationException, BKUException {
init(is);
}
/**
* Initializes the parser.
* Parses and validates the document given as stream and extracts the
* root element.
*
* @param is The InfoBoxReadResponse as stream.
* @throws AuthenticationException If an authentication error occurs.
* @throws ParseException If an error occurs on parsing the the document.
* @throws BKUException
*/
private void init(InputStream is) throws AuthenticationException, ParseException, BKUException {
try {
Element responseElem = DOMUtils.parseXmlValidating(is, parserFeatures);
if ("InfoboxReadResponse".equals(responseElem.getLocalName())) {
infoBoxElem_ = responseElem;
} else {
ErrorResponseParser erp = new ErrorResponseParser(responseElem);
throw new BKUException("auth.08",
new Object[] { erp.getErrorCode(), erp.getErrorInfo()},
erp.getErrorCode(),
erp.getErrorInfo());
}
} catch (BKUException e) {
throw e;
} catch (Throwable t) {
throw new ParseException("parser.01", new Object[] { t.toString()}, t);
}
}
/**
* Parses the embedded <saml:Assertion>
element from <InfoboxReadResponse>
* @return <saml:Assertion>
as String
* @throws ParseException on any parsing error
*/
// public String parseSAMLAssertion() throws ParseException {
// try {
//
// String slPrefix = XPathUtils.getSlPrefix(infoBoxElem_);
// StringBuffer sb = new StringBuffer("/");
// sb.append(slPrefix);
// sb.append(":InfoboxReadResponse/");
// sb.append(slPrefix);
// sb.append(":BinaryFileData/");
// sb.append(slPrefix);
// sb.append(":XMLContent/");
// sb.append(Constants.SAML_PREFIX);
// sb.append(":Assertion");
// String samlAssertionXPath = sb.toString();
// Element samlAssertion = (Element) XPathUtils.selectSingleNode(infoBoxElem_, samlAssertionXPath);
// return DOMUtils.serializeNode(samlAssertion);
//
// }
// catch (Throwable t) {
// throw new ParseException("parser.01", new Object[] { t.toString()}, t);
// }
// }
/**
* Parses the embedded <saml:Assertion>
element from <InfoboxReadResponse>
* @return <saml:Assertion>
as String
* @throws ParseException on any parsing error
*/
public Element parseSAMLAssertion() throws ParseException {
try {
String slPrefix = XPathUtils.getSlPrefix(infoBoxElem_);
StringBuffer sb = new StringBuffer("/");
sb.append(slPrefix);
sb.append(":InfoboxReadResponse/");
sb.append(slPrefix);
sb.append(":BinaryFileData/");
sb.append(slPrefix);
sb.append(":XMLContent/");
sb.append(Constants.SAML_PREFIX);
sb.append(":Assertion");
String samlAssertionXPath = sb.toString();
Element samlAssertion = (Element) XPathUtils.selectSingleNode(infoBoxElem_, samlAssertionXPath);
return samlAssertion;
}
catch (Throwable t) {
throw new ParseException("parser.01", new Object[] { t.toString()}, t);
}
}
/**
* Parses the identity link from the <saml:Assertion>
* @return Identity link
* @throws ParseException on any parsing error
*/
// public IdentityLink parseIdentityLink() throws ParseException {
// String samlAssertionString = parseSAMLAssertion();
// IdentityLinkAssertionParser ilParser = new IdentityLinkAssertionParser(samlAssertionString);
// return ilParser.parseIdentityLink();
// }
/**
* Parses the identity link from the <saml:Assertion>
* @return Identity link
* @throws ParseException on any parsing error
*/
public IIdentityLink parseIdentityLink() throws ParseException {
Element samlAssertion = parseSAMLAssertion();
IdentityLinkAssertionParser ilParser = new IdentityLinkAssertionParser(samlAssertion);
return ilParser.parseIdentityLink();
}
/**
* Returns the certificate given in the InfoboxReadResponse
* @return
* @throws ParseException
*/
public X509Certificate parseCertificate() throws ParseException {
try {
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = builder.newDocument();
Element nameSpaceNode = doc.createElement("NameSpaceNode");
nameSpaceNode.setAttribute("xmlns:" + Constants.PD_PREFIX, Constants.PD_NS_URI);
nameSpaceNode.setAttribute("xmlns:" + Constants.DSIG_PREFIX, Constants.DSIG_NS_URI);
nameSpaceNode.setAttribute("xmlns:" + Constants.SL12_PREFIX, Constants.SL12_NS_URI);
Element base64ContentElement = (Element)XPathAPI.selectSingleNode(infoBoxElem_.getParentNode(), "//sl:Base64Content[1]", nameSpaceNode);
if (base64ContentElement == null) {
throw new ParseException("parser.01", new Object[] { "Could not find Base64Content for X509Certificate."});
}
String base64Content = DOMUtils.getText(base64ContentElement);
// Decode Base64 value to X509Certificate
byte[] content = Base64Utils.decode(base64Content, false);
return new X509Certificate(content);
} catch (ParserConfigurationException | TransformerException |
CertificateException | IOException e) {
throw new ParseException("parser.01", new Object[] { "Could not parse X509Certificate from InfoboxReadRequest."}, e);
}
}
}