Example of an WE using WS-SEC
From GEANT2-JRA1 Wiki
There is available a Java library for WE developers, so you can add a security token in the request sent to a perfSONAR service. Its main purpose is that WEs are not WS-SEC aware. The class diagram of this library is:
There is one helper class, org.perfsonar.client.base.authn.edugain.EduGAINFilterHelper, which has defined the method getAuthenticationAssertion(HttpSession session). This gets SAML assertions provided by an eduGAIN filter and get the Authentication one.
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { . . . SAMLAssertion authStatementAssertion = EduGAINFilterHelper.getAuthenticationAssertion(request.getSession()); . . . }
Also, there is an interface which adds the security token in a message: org.perfsonar.client.base.authn.AuthNData. At the moment, there is only one implementation based on Apache Axis 1 Library, as perfSONAR is using it right now, and the class name is WSSAuthNData. The method addSAMLSTInMessage(...) needs the following parameters:
- A SOAPBodeElement object, which contains generally a NMWG message (or what ever you want).
- A PrivateKey object, containing a private key for signing the SAML assertion.
- A X509Certificate object, containing the certificate for adding into the SAML assertion.
- An String object, containing the URN which represents the perfSONAR resource that client are going to send the message to.
- An String object, containing the URN which represents the client.
SOAPBodyElement requestMessage; PrivateKey pk; X509Certificate cert; String cID; String cID_pSR; . . . AuthNData authnData=AuthNDataFactory.getDefaultAuthNData(); SOAPEnvelope envelope = (SOAPEnvelope)authnData.addSAMLSTInMessage(requestMessage, authStatementAssertion, pk, cert, cID_pSR, cID);
Java Servlet Example
This example is a servlet which gets all information provided by an eduGAIN filter, print out and send a message to a perfSONAR resource:
And the Java code is:
package es.rediris.perfsonar; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.net.URL; import java.security.KeyFactory; import java.security.PrivateKey; import java.security.Provider; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.security.spec.PKCS8EncodedKeySpec; import java.util.Enumeration; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.xml.namespace.QName; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.apache.axis.client.Call; import org.apache.axis.client.Service; import org.apache.axis.message.SOAPBodyElement; import org.apache.axis.message.SOAPEnvelope; import org.apache.commons.lang.StringEscapeUtils; import org.apache.ws.security.util.Base64; import org.apache.xml.serialize.OutputFormat; import org.apache.xml.serialize.XMLSerializer; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.opensaml.SAMLAssertion; import org.perfsonar.client.commons.authn.AuthNData; import org.perfsonar.client.commons.authn.AuthNDataFactory; import org.perfsonar.client.commons.authn.edugain.EduGAINFilterHelper; import org.w3c.dom.Document; import org.w3c.dom.Node; public class EduGAINed_ASTest extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet { public static final String END_POINT_PARAM="endPoint"; public static final String QUERY_FILE_PARAM="queryFile"; public static final String PRIV_KEY_PARAM="privateKey"; public static final String PUBLIC_KEY_PARAM="publicKey"; public static final String COMPONENT_ID_PARAM="componentId"; public static final String COMPONENT_ID_pSR_PARAM="componentId_pSR"; private X509Certificate certificate=null; private PrivateKey privKey=null; /* (non-Java-doc) * @see javax.servlet.http.HttpServlet#HttpServlet() */ public EduGAINed_ASTest() { super(); // add the security provider BouncyCastleProvider bcp = new BouncyCastleProvider(); java.security.Security.addProvider((Provider)bcp); } private PrivateKey getPrivateKey() { if (privKey!=null) return privKey; try { BufferedReader in = new BufferedReader(new FileReader(getServletContext().getRealPath(getServletConfig().getInitParameter(EduGAINed_LSClient.PRIV_KEY_PARAM)))); String str; String previousStr=""; String data=""; in.readLine(); while ((str = in.readLine()) != null) { data+=previousStr; previousStr=str+"\n"; } in.close(); byte[] bytes=Base64.decode(data); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PrivateKey privateKey = keyFactory.generatePrivate(keySpec); return privateKey; } catch (Exception e) { e.printStackTrace(); return null; } } public X509Certificate getCertificate() { if (certificate!=null) return certificate; try { FileInputStream is = new FileInputStream(new File(getServletContext(). getRealPath(getServletConfig().getInitParameter(EduGAINed_LSClient.PUBLIC_KEY_PARAM)))); CertificateFactory cf = CertificateFactory.getInstance("X.509"); X509Certificate cert = (X509Certificate)cf.generateCertificate(is); return cert; } catch (Exception e) { e.printStackTrace(); return null; } } private Document getQueryMessage() { try { Document request = null; DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); DocumentBuilder builder = factory.newDocumentBuilder(); request = builder.parse(new File(getServletContext(). getRealPath(getServletConfig().getInitParameter(EduGAINed_ASTest.QUERY_FILE_PARAM)))); return request; } catch (Exception e) { e.printStackTrace(); return null; } } /* (non-Java-doc) * @see javax.servlet.http.HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter writer = response.getWriter(); try { // prepare to call - set service elements Service serviceAxis = new Service(); Call call = (Call)serviceAxis.createCall(); call.setTargetEndpointAddress(new URL(getServletConfig().getInitParameter(EduGAINed_ASTest.END_POINT_PARAM))); call.setOperationName(new QName("http://soapinterop.org/","submit")); writer.println("<html>"); writer.println("<head>"); writer.println("<title>eduGAINed ASTest</title>"); writer.println("<link href='style.css' rel='stylesheet' type='text/css'>"); writer.println("</head>"); writer.println("<body>"); writer.println("<div><h3>Configuration:</h3></div>"); writer.println("<ul>"); writer.println("<li><span class='attrName'>End point</span>: "+getServletConfig(). getInitParameter(EduGAINed_ASTest.END_POINT_PARAM)+"</li>"); writer.println("<li><span class='attrName'>XML Message</span>: "+getServletConfig(). getInitParameter(EduGAINed_ASTest.QUERY_FILE_PARAM)+"</li>"); writer.println("<li><span class='attrName'>Private Key</span>: "+getServletConfig(). getInitParameter(EduGAINed_ASTest.PRIV_KEY_PARAM)+"</li>"); writer.println("<li><span class='attrName'>Certificate</span>: "+getServletConfig(). getInitParameter(EduGAINed_ASTest.PUBLIC_KEY_PARAM)+"</li>"); writer.println("<li><span class='attrName'>Component ID</span>: "+getServletConfig(). getInitParameter(EduGAINed_ASTest.COMPONENT_ID_PARAM)+"</li>"); writer.println("<li><span class='attrName'>Component ID pSR</span>: "+getServletConfig(). getInitParameter(EduGAINed_ASTest.COMPONENT_ID_pSR_PARAM)+"</li>"); writer.println("</ul>"); SAMLAssertion authStatementAssertion=EduGAINFilterHelper.getAuthenticationAssertion(request.getSession()); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); DocumentBuilder builder = factory.newDocumentBuilder(); Document authStatementAssertionDoc=builder.newDocument(); Node elem=authStatementAssertion.toDOM(authStatementAssertionDoc); authStatementAssertionDoc.appendChild(elem); if (authStatementAssertion==null) { writer.println("<h3>No SAML authentication statement found!<h3>"); } else { writer.println("<div><h3>SAML authentication statement:</h3></div>"); String data=StringEscapeUtils.escapeXml(formatDocument(authStatementAssertionDoc)); data=data.replaceAll("\n", "<br />"); data=data.replaceAll(" ", " "); writer.println("<div class='infoXML'>"+data+"</div>"); Document docQuery=getQueryMessage(); writer.println("<div><h3>Sent query:</h3></div>"); data=StringEscapeUtils.escapeXml(formatDocument(docQuery)); data=data.replaceAll("\n", "<br />"); data=data.replaceAll(" ", " "); writer.println("<div class='infoXML'>"+data+"</div>"); SOAPBodyElement requestMessage = new SOAPBodyElement(docQuery.getDocumentElement()); String cID=getServletConfig().getInitParameter(EduGAINed_ASTest.COMPONENT_ID_PARAM); String cID_pSR=getServletConfig().getInitParameter(EduGAINed_ASTest.COMPONENT_ID_pSR_PARAM); AuthNData authnData=AuthNDataFactory.getDefaultAuthNData(); SOAPEnvelope envelope = (SOAPEnvelope)authnData.addSAMLSTInMessage(requestMessage, authStatementAssertion,getPrivateKey(), getCertificate(), cID_pSR,cID); Document wssDoc = envelope.getAsDocument(); writer.println("<div><h3>Sent SOAP query:</h3></div>"); data=StringEscapeUtils.escapeXml(formatDocument(wssDoc)); data=data.replaceAll("\n", "<br />"); data=data.replaceAll(" ", " "); writer.println("<div class='infoXML'>"+data+"</div>"); // call on the end point Object resultObject = call.invoke(envelope); SOAPEnvelope envelopeResult=(SOAPEnvelope)resultObject; SOAPBodyElement resultSBE= envelopeResult.getFirstBody(); Document result = resultSBE.getAsDocument(); writer.println("<div><h3>Received response:</h3></div>"); data=StringEscapeUtils.escapeXml(formatDocument(result)); data=data.replaceAll("\n", "<br />"); data=data.replaceAll(" ", " "); writer.println("<div class='infoXML'>"+data+"</div>"); } writer.println("</body>"); writer.println("</html>"); } catch (Exception e) { writer.println("<div><h3>ERROR:</h3></div>"); writer.println("<div class='infoXML'>"+e.toString()+"</div>"); } } private String formatDocument(Document doc) throws IOException { StringWriter sw=new StringWriter(); OutputFormat format = new OutputFormat( doc ); format.setIndent(4); format.setIndenting(true); format.setLineSeparator("\n"); XMLSerializer serial = new XMLSerializer(sw, format ); serial.asDOMSerializer(); serial.serialize( doc.getDocumentElement() ); return sw.toString(); } }

