comparison gwt-client/src/main/java/org/dive4elements/river/client/server/auth/saml/TicketValidator.java @ 5941:c1806821860b

Add SAML ticket validator classes.
author Bernhard Herzog <bh@intevation.de>
date Wed, 08 May 2013 17:56:13 +0200
parents
children 0a0b4bfdf372
comparison
equal deleted inserted replaced
5940:05da3cfa4054 5941:c1806821860b
1 /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
2 * Software engineering by Intevation GmbH
3 *
4 * This file is Free Software under the GNU AGPL (>=v3)
5 * and comes with ABSOLUTELY NO WARRANTY! Check out the
6 * documentation coming with Dive4Elements River for details.
7 */
8
9 package org.dive4elements.river.client.server.auth.saml;
10
11 import java.io.FileInputStream;
12 import java.io.IOException;
13 import java.security.Key;
14 import java.util.Iterator;
15 import java.util.Date;
16 import javax.security.cert.X509Certificate;
17 import javax.security.cert.CertificateException;
18 import javax.xml.crypto.Data;
19 import javax.xml.crypto.NodeSetData;
20 import javax.xml.crypto.dsig.Reference;
21 import javax.xml.crypto.dsig.XMLSignature;
22 import javax.xml.crypto.dsig.XMLSignatureFactory;
23 import javax.xml.crypto.dsig.dom.DOMValidateContext;
24
25 import org.apache.log4j.Logger;
26
27 import org.w3c.dom.Element;
28 import org.w3c.dom.Node;
29 import org.w3c.dom.NodeList;
30
31 /**
32 * Validator for SAML tickets.
33 */
34 public class TicketValidator {
35
36 /**
37 * The logger used by the TicketValidator instances.
38 */
39 private static Logger logger = Logger.getLogger(TicketValidator.class);
40
41 /**
42 * The trusted Key for signature checks.
43 */
44 private Key trustedKey;
45
46 /**
47 * Creates a new TicketValidator from a trusted key.
48 * @param trustedKey The trusted key for the signature checks.
49 */
50 public TicketValidator(Key trustedKey) {
51 this.trustedKey = trustedKey;
52 }
53
54 /**
55 * Creates a new TicketValidator, loading the trusted key from a
56 * file.
57 * @param filename The filename of the X509 certificate containing
58 * the trusted public key.
59 */
60 public TicketValidator(String filename) throws IOException,
61 CertificateException {
62 this.trustedKey = loadKey(filename);
63 }
64
65 /**
66 * Loads the public key from a file containing an X509 certificate.
67 */
68 private Key loadKey(String filename) throws IOException,
69 CertificateException {
70 X509Certificate cert = X509Certificate.getInstance(
71 new FileInputStream(filename));
72 cert.checkValidity(new Date());
73 return cert.getPublicKey();
74 }
75
76
77 /**
78 * Check the ticket represented by the given DOM element.
79 * @param root the DOM element under which the signature can be
80 * found.
81 * @return The assertion element from the signed data.
82 */
83 public Assertion checkTicket(Element root) throws Exception {
84 markAssertionIdAttributes(root);
85
86 Node signode = XPathUtils.xpathNode(root, ".//ds:Signature");
87
88 DOMValidateContext context = new DOMValidateContext(this.trustedKey,
89 signode);
90 context.setProperty("javax.xml.crypto.dsig.cacheReference", true);
91
92 XMLSignatureFactory factory = XMLSignatureFactory.getInstance("DOM");
93 XMLSignature signature = factory.unmarshalXMLSignature(context);
94 if (!signature.validate(context)) {
95 logger.error("Signature of SAML ticket could not be validated.");
96 return null;
97 }
98
99 Element assertionElement = extractAssertion(signature, context);
100 if (assertionElement == null) {
101 logger.error("Could not extract assertion from signed content.");
102 return null;
103 }
104
105 Assertion assertion = new Assertion(assertionElement);
106 if (!assertion.isValidNow()) {
107 logger.error("Ticket is not valid now"
108 + " (NotBefore: " + assertion.getFrom()
109 + ", NotOnOrAfter: " + assertion.getUntil());
110 return null;
111 }
112
113 return assertion;
114 }
115
116 /**
117 * Mark the AssertionID attribute of SAML Assertion elements as ID
118 * attribute, so that the signature checker can resolve the
119 * references properly and find the signed data.
120 */
121 private void markAssertionIdAttributes(Element root) {
122 NodeList nodes = XPathUtils.xpathNodeList(root, "saml:Assertion");
123 for (int i = 0; i < nodes.getLength(); i++) {
124 Element el = (Element)nodes.item(i);
125 el.setIdAttribute("AssertionID", true);
126 }
127 }
128
129 private Element extractAssertion(XMLSignature sig,
130 DOMValidateContext context) {
131 for (Object obj: sig.getSignedInfo().getReferences()) {
132 Data data = ((Reference)obj).getDereferencedData();
133 if (data instanceof NodeSetData) {
134 Iterator i = ((NodeSetData)data).iterator();
135 for (int k = 0; i.hasNext(); k++) {
136 Object node = i.next();
137 if (node instanceof Element) {
138 Element el = (Element)node;
139 if (el.getTagName().equals("Assertion"))
140 return el;
141 }
142 }
143 }
144 }
145
146 return null;
147 }
148 }

http://dive4elements.wald.intevation.org