1 package org.astrogrid.security;
2
3 import javax.security.auth.x500.X500Principal;
4 import org.apache.axis.AxisFault;
5 import org.apache.axis.MessageContext;
6 import org.apache.axis.handlers.BasicHandler;
7 import org.apache.log4j.Logger;
8 import org.apache.xml.security.Init;
9 import org.w3c.dom.Document;
10 import org.astrogrid.security.wsse.WsseSignature;
11 import org.apache.axis.message.SOAPEnvelope;
12 import org.apache.axis.message.SOAPHeaderElement;
13 import org.globus.gsi.TrustedCertificates;
14
15 /***
16 * An Axis handler to authenticate callers of a service.
17 * <p>
18 * The handler checks digital signatures on the SOAP
19 * body of the request according to the IVOA SSO profile. If a SOAP
20 * header in the WS-Security v1.0 namespace is present, then the handler
21 * looks for and validates a digital signature. If the signature is
22 * missing or invalid (including those cases where some kind of
23 * WS-Security mark-up other than digital signature is present), then the
24 * request is rejected: a fault is thrown. If no WS-Security header is
25 * present, then the request is accepted; it is up to the implementation of
26 * the specific web-service to accept or reject anonymous requests.
27 * <p>
28 * If the handler runs to completion without throwing a fault, it writes
29 * a JAAS Subject to the property org.astrogrid.security.authenticated
30 * of the message context. For anonymous requests, this Subject is empty.
31 * For requests with a valid signature, the Subject is loaded with an
32 * X500Principal giving the authenticated identity and, in the
33 * public-credentials set, the X509Certificate for that identity.
34 *
35 * @author Guy Rixon
36 */
37 public class AxisServiceCredentialHandler extends BasicHandler {
38
39 private static Logger log
40 = Logger.getLogger("org.astrogrid.security.AxisServiceCredentialHandler");
41
42 private static TrustedCertificates trustAnchors;
43
44 /***
45 * The URI for the XML namespace for WS-Security v1.0.
46 */
47 protected final String WSSE_1_0_NAMESPACE
48 = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
49
50 /***
51 * Initializes the handler.
52 */
53 public void init() {
54
55 Init.init();
56
57
58 this.loadTrustAnchors();
59 }
60
61 /***
62 * Checks a digital signature and records the results.
63 *
64 * @param msgContext - message context.
65 * @throws AxisFault - if anything goes wrong.
66 */
67 public void invoke(MessageContext msgContext) throws AxisFault {
68 try {
69 System.out.println();
70 System.out.println("Message in service:");
71 System.out.println(msgContext.getRequestMessage().getSOAPPartAsString());
72 SOAPEnvelope envelope = msgContext.getRequestMessage().getSOAPEnvelope();
73 SOAPHeaderElement header = envelope.getHeaderByName(WSSE_1_0_NAMESPACE,
74 "Security",
75 true);
76 if (header != null) {
77 Document document = envelope.getAsDocument();
78 WsseSignature signature = new WsseSignature(document, this.trustAnchors);
79 signature.verify();
80 header.setProcessed(true);
81 AxisServiceSecurityGuard guard = signature.getServiceGuard();
82 X500Principal p = guard.getX500Principal();
83 log.info("Caller is authenticated as " + p + " by digital signature.");
84 msgContext.setProperty("org.astrogrid.security.guard", guard);
85 }
86 else {
87 msgContext.setProperty("org.astrogrid.security.guard",
88 new AxisServiceSecurityGuard());
89 log.info("Caller is anonymous.");
90 }
91 }
92 catch (Exception e) {
93 log.info("The digital-signature-checking handler failed" + e);
94 e.printStackTrace();
95 throw new AxisFault("The digital-signature-checking handler failed", e);
96 }
97 }
98
99 /***
100 * Loads trust anchors from disc.
101 * Trust anchors are expressed as a set of trusted certificates, and
102 * conventionally stored as a directory full of .pem files. This method
103 * loads all the appropriate files in such a directory. The directory is
104 * set as an option (e.g. via a parameter element in a WSDD file) on the
105 * handler. If the trust anchors cannot be loaded, this method logs the
106 * error but does not throw an exception.
107 */
108 protected void loadTrustAnchors() {
109 String trustAnchorDirectory
110 = System.getProperty("X509_CERT_DIR");
111 if (trustAnchorDirectory == null) {
112 log.info("No directory was specified from which to load trusted certificates. " +
113 "/etc/grid-security/certificates is the default.");
114 trustAnchorDirectory = "/etc/grid-security/certificates";
115 }
116 try {
117 this.trustAnchors = TrustedCertificates.load(trustAnchorDirectory);
118 }
119 catch (Exception e) {
120 log.error(e);
121 }
122 }
123 }