Java tutorial
/* * eID Identity Provider Project. * Copyright (C) 2010 FedICT. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version * 3.0 as published by the Free Software Foundation. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, see * http://www.gnu.org/licenses/. */ package test.unit.be.fedict.eid.idp.protocol.ws_federation; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.KeyStore; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import java.security.Security; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.security.spec.RSAKeyGenParameterSpec; import java.util.LinkedList; import java.util.List; import javax.servlet.http.HttpServletResponse; import javax.xml.crypto.dsig.XMLSignature; import javax.xml.crypto.dsig.XMLSignatureFactory; import javax.xml.crypto.dsig.dom.DOMValidateContext; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier; import org.bouncycastle.asn1.x509.BasicConstraints; import org.bouncycastle.asn1.x509.SubjectKeyIdentifier; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.asn1.x509.X509Extensions; import org.bouncycastle.jce.X509Principal; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.x509.X509V3CertificateGenerator; import org.easymock.EasyMock; import org.joda.time.DateTime; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.mortbay.jetty.servlet.ServletHolder; import org.mortbay.jetty.testing.ServletTester; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import be.fedict.eid.applet.service.signer.KeyInfoKeySelector; import be.fedict.eid.idp.protocol.ws_federation.AbstractWSFederationProtocolService; import be.fedict.eid.idp.protocol.ws_federation.WSFederationMetadataHttpServletAuthIdent; import be.fedict.eid.idp.spi.AttributeConfig; import be.fedict.eid.idp.spi.IdPIdentity; import be.fedict.eid.idp.spi.IdentityProviderConfiguration; import be.fedict.eid.idp.spi.IdentityProviderConfigurationFactory; public class WSFederationMetadataHttpServletTest { private static final Log LOG = LogFactory.getLog(WSFederationMetadataHttpServletTest.class); private String location; @BeforeClass public static void init() throws Exception { Security.addProvider(new BouncyCastleProvider()); } @Before public void setUp() throws Exception { KeyPair keyPair = generateKeyPair(); DateTime notBefore = new DateTime(); DateTime notAfter = notBefore.plusMonths(1); X509Certificate certificate = generateSelfSignedCertificate(keyPair, "CN=Test", notBefore, notAfter); IdPIdentity identity = new IdPIdentity("test", new KeyStore.PrivateKeyEntry(keyPair.getPrivate(), new Certificate[] { certificate })); List<AttributeConfig> attributes = new LinkedList<AttributeConfig>(); attributes.add(new AttributeConfig("test", "description", "uri")); ServletTester servletTester = new ServletTester(); servletTester.setContextPath("/eid-idp"); ServletHolder servletHolder = servletTester.addServlet(WSFederationMetadataHttpServletAuthIdent.class, "/ws-federation-auth-ident-metadata"); IdentityProviderConfiguration mockConfiguration = EasyMock.createMock(IdentityProviderConfiguration.class); EasyMock.expect(mockConfiguration.findIdentity()).andStubReturn(identity); EasyMock.expect(mockConfiguration.getAttributes(AbstractWSFederationProtocolService.WS_FED_PROTOCOL_ID)) .andReturn(attributes); EasyMock.replay(mockConfiguration); servletTester.start(); servletHolder.getServletHandler().getServletContext().setAttribute( IdentityProviderConfigurationFactory.IDENTITY_PROVIDER_CONFIGURATION_CONTEXT_ATTRIBUTE, mockConfiguration); this.location = servletTester.createSocketConnector(true) + "/eid-idp/ws-federation-auth-ident-metadata"; } @Test public void get() throws Exception { // setup LOG.debug("URL: " + this.location); HttpClient httpClient = new HttpClient(); GetMethod getMethod = new GetMethod(this.location); // operate int result = httpClient.executeMethod(getMethod); // verify assertEquals(HttpServletResponse.SC_OK, result); String responseBody = getMethod.getResponseBodyAsString(); LOG.debug("Response body: " + responseBody); Header contentTypeHeader = getMethod.getResponseHeader("Content-Type"); assertNotNull(contentTypeHeader); assertEquals("application/samlmetadata+xml", contentTypeHeader.getValue()); } // @Test public void testSignatureVerification() throws Exception { // setup InputStream documentInputStream = WSFederationProtocolServiceTest.class .getResourceAsStream("/FederationMetadata.xml"); assertNotNull(documentInputStream); Document document = loadDocument(documentInputStream); NodeList signatureNodeList = document.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature"); assertEquals(1, signatureNodeList.getLength()); Node signatureNode = signatureNodeList.item(0); KeyInfoKeySelector keySelector = new KeyInfoKeySelector(); DOMValidateContext domValidateContext = new DOMValidateContext(keySelector, signatureNode); XMLSignatureFactory xmlSignatureFactory = XMLSignatureFactory.getInstance(); XMLSignature xmlSignature = xmlSignatureFactory.unmarshalXMLSignature(domValidateContext); // operate boolean validity = xmlSignature.validate(domValidateContext); // verify assertTrue(validity); } private Document loadDocument(InputStream documentInputStream) throws ParserConfigurationException, SAXException, IOException { InputSource inputSource = new InputSource(documentInputStream); DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); documentBuilderFactory.setNamespaceAware(true); DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); return documentBuilder.parse(inputSource); } private KeyPair generateKeyPair() throws Exception { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); SecureRandom random = new SecureRandom(); keyPairGenerator.initialize(new RSAKeyGenParameterSpec(1024, RSAKeyGenParameterSpec.F4), random); return keyPairGenerator.generateKeyPair(); } private SubjectKeyIdentifier createSubjectKeyId(PublicKey publicKey) throws IOException { ByteArrayInputStream bais = new ByteArrayInputStream(publicKey.getEncoded()); SubjectPublicKeyInfo info = new SubjectPublicKeyInfo((ASN1Sequence) new ASN1InputStream(bais).readObject()); return new SubjectKeyIdentifier(info); } private AuthorityKeyIdentifier createAuthorityKeyId(PublicKey publicKey) throws IOException { ByteArrayInputStream bais = new ByteArrayInputStream(publicKey.getEncoded()); SubjectPublicKeyInfo info = new SubjectPublicKeyInfo((ASN1Sequence) new ASN1InputStream(bais).readObject()); return new AuthorityKeyIdentifier(info); } private X509Certificate generateSelfSignedCertificate(KeyPair keyPair, String subjectDn, DateTime notBefore, DateTime notAfter) throws Exception { PublicKey subjectPublicKey = keyPair.getPublic(); PrivateKey issuerPrivateKey = keyPair.getPrivate(); String signatureAlgorithm = "SHA1WithRSAEncryption"; X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator(); certificateGenerator.reset(); certificateGenerator.setPublicKey(subjectPublicKey); certificateGenerator.setSignatureAlgorithm(signatureAlgorithm); certificateGenerator.setNotBefore(notBefore.toDate()); certificateGenerator.setNotAfter(notAfter.toDate()); X509Principal issuerDN = new X509Principal(subjectDn); certificateGenerator.setIssuerDN(issuerDN); certificateGenerator.setSubjectDN(new X509Principal(subjectDn)); certificateGenerator.setSerialNumber(new BigInteger(128, new SecureRandom())); certificateGenerator.addExtension(X509Extensions.SubjectKeyIdentifier, false, createSubjectKeyId(subjectPublicKey)); PublicKey issuerPublicKey; issuerPublicKey = subjectPublicKey; certificateGenerator.addExtension(X509Extensions.AuthorityKeyIdentifier, false, createAuthorityKeyId(issuerPublicKey)); certificateGenerator.addExtension(X509Extensions.BasicConstraints, false, new BasicConstraints(true)); X509Certificate certificate; certificate = certificateGenerator.generate(issuerPrivateKey); /* * Next certificate factory trick is needed to make sure that the * certificate delivered to the caller is provided by the default * security provider instead of BouncyCastle. If we don't do this trick * we might run into trouble when trying to use the CertPath validator. */ CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); certificate = (X509Certificate) certificateFactory .generateCertificate(new ByteArrayInputStream(certificate.getEncoded())); return certificate; } }