import java.io.IOException; import java.util.Vector; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; 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 javax.xml.rpc.Call; import javax.xml.rpc.Service; import javax.xml.rpc.ServiceFactory; import org.apache.axis.message.SOAPBodyElement; import org.apache.xml.serialize.LineSeparator; import org.apache.xml.serialize.OutputFormat; import org.apache.xml.serialize.XMLSerializer; import org.jaxen.JaxenException; import org.jaxen.SimpleNamespaceContext; import org.jaxen.dom.DOMXPath; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * Beispiel für ein Login-Servlet, das von MOA-ID-AUTH über einen Redirect aufgerufen wird. * Es werden demonstriert: * - Parameterübergabe von MOA-ID-AUTH * - Aufruf des MOA-ID-AUTH Web Service zum Abholen der Anmeldedaten über das Apache Axis Framework * - Parsen der Anmeldedaten mittels der XPath Engine "Jaxen" * - Speichern der Anmeldedaten in der HTTPSession * - Redirect auf die eigentliche Startseite der OA * * @author Paul Ivancsics */ public class LoginServletExample extends HttpServlet { // Web Service QName und Endpoint private static final QName SERVICE_QNAME = new QName("GetAuthenticationData"); private static final String ENDPOINT = "http://localhost:8080/moa-id-auth/services/GetAuthenticationData"; // NamespaceContext für Jaxen private static SimpleNamespaceContext NS_CONTEXT; static { NS_CONTEXT = new SimpleNamespaceContext(); NS_CONTEXT.addNamespace("saml", "urn:oasis:names:tc:SAML:1.0:assertion"); NS_CONTEXT.addNamespace("samlp", "urn:oasis:names:tc:SAML:1.0:protocol"); NS_CONTEXT.addNamespace("pr", "http://reference.e-government.gv.at/namespace/persondata/20020228#"); } /** * Servlet wird von MOA-ID-AUTH nach erfolgter Authentisierung über ein Redirect aufgerufen. */ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // Parameter "Target" und "SAMLArtifact" aus dem Redirect von MOA-ID-AUTH lesen String target = req.getParameter("Target"); String samlArtifact = req.getParameter("SAMLArtifact"); try { // DOMBuilder instanzieren DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); DocumentBuilder builder = factory.newDocumentBuilder(); // zusammenstellen und in einen DOM-Baum umwandeln String samlRequest = "" + samlArtifact + ""; Document root_request = builder.parse(new ByteArrayInputStream(samlRequest.getBytes())); // Neues SOAPBodyElement anlegen und mit dem DOM-Baum füllen SOAPBodyElement body = new SOAPBodyElement(root_request.getDocumentElement()); SOAPBodyElement[] params = new SOAPBodyElement[] { body }; // AXIS-Service für Aufruf von MOA-ID-AUTH instanzieren Service service = ServiceFactory.newInstance().createService(SERVICE_QNAME); // Axis-Call erzeugen und mit Endpoint verknüpfen Call call = service.createCall(); call.setTargetEndpointAddress(ENDPOINT); // Call aufrufen und die Antwort speichern System.out.println("Calling MOA-ID-AUTH ..."); Vector responses = (Vector) call.invoke(params); // erstes BodyElement auslesen SOAPBodyElement response = (SOAPBodyElement) responses.get(0); // als DOM-Baum holen Document responseDocument = response.getAsDocument(); Element samlResponse = responseDocument.getDocumentElement(); // auf System.out ausgeben System.out.println("Response received:"); OutputFormat format = new OutputFormat((Document) responseDocument); format.setLineSeparator(LineSeparator.Windows); format.setIndenting(true); format.setLineWidth(0); XMLSerializer serializer = new XMLSerializer(System.out, format); serializer.asDOMSerializer(); serializer.serialize(responseDocument); // auslesen Attr statusCodeAttr = (Attr)getNode(samlResponse, "/samlp:Response/samlp:Status/samlp:StatusCode/@Value"); String samlStatusCode = statusCodeAttr.getValue(); System.out.println("StatusCode: " + samlStatusCode); // auslesen if ("samlp:Success".equals(samlStatusCode)) { Element samlAssertion = (Element)getNode(samlResponse, "/samlp:Response/saml:Assertion"); // FamilyName aus der parsen Node familyNameNode = getNode(samlAssertion, "//saml:AttributeStatement/saml:Attribute[@AttributeName=\"PersonData\"]/saml:AttributeValue/pr:Person/pr:Name/pr:FamilyName"); String familyName = getText(familyNameNode); System.out.println("Family name: " + familyName); // weitere Anmeldedaten aus der parsen // ... // Anmeldedaten und Target in der HTTPSession speichern HttpSession session = req.getSession(); session.setAttribute("UserFamilyName", familyName); session.setAttribute("Geschaeftsbereich", target); // weitere Anmeldedaten in der HTTPSession speichern // ... // Redirect auf die eigentliche Startseite resp.sendRedirect("/index.jsp"); } } catch (Exception ex) { ex.printStackTrace(); } } /** Returns the first node matching an XPath expression. */ private static Node getNode(Node contextNode, String xpathExpression) throws JaxenException { DOMXPath xpath = new DOMXPath(xpathExpression); xpath.setNamespaceContext(NS_CONTEXT); return (Node) xpath.selectSingleNode(contextNode); } /** Returns the text that a node contains. */ public static String getText(Node node) { if (!node.hasChildNodes()) { return ""; } StringBuffer result = new StringBuffer(); NodeList list = node.getChildNodes(); for (int i = 0; i < list.getLength(); i++) { Node subnode = list.item(i); if (subnode.getNodeType() == Node.TEXT_NODE) { result.append(subnode.getNodeValue()); } else if (subnode.getNodeType() == Node.CDATA_SECTION_NODE) { result.append(subnode.getNodeValue()); } else if (subnode.getNodeType() == Node.ENTITY_REFERENCE_NODE) { // Recurse into the subtree for text // (and ignore comments) result.append(getText(subnode)); } } return result.toString(); } }