View Javadoc

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      // Initialize the XML-security library
55      Init.init();
56      
57      // Load the trust anchors used for checking signatures.
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 }