View Javadoc

1   /*
2    * $Id: MuleWSSInHandler.java 7976 2007-08-21 14:26:13Z dirk.olmes $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.extras.wssecurity.handlers;
12  
13  import org.mule.umo.security.SecurityException;
14  
15  import java.security.cert.X509Certificate;
16  import java.util.Properties;
17  import java.util.Vector;
18  
19  import javax.security.auth.callback.CallbackHandler;
20  
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  import org.apache.ws.security.WSConstants;
24  import org.apache.ws.security.WSSecurityEngineResult;
25  import org.apache.ws.security.WSSecurityException;
26  import org.apache.ws.security.handler.RequestData;
27  import org.apache.ws.security.handler.WSHandlerConstants;
28  import org.apache.ws.security.handler.WSHandlerResult;
29  import org.apache.ws.security.util.WSSecurityUtil;
30  import org.codehaus.xfire.MessageContext;
31  import org.codehaus.xfire.XFireRuntimeException;
32  import org.codehaus.xfire.exchange.AbstractMessage;
33  import org.codehaus.xfire.fault.XFireFault;
34  import org.codehaus.xfire.handler.Handler;
35  import org.codehaus.xfire.handler.Phase;
36  import org.codehaus.xfire.security.wss4j.AbstractWSS4JHandler;
37  import org.codehaus.xfire.soap.handler.ReadHeadersHandler;
38  import org.codehaus.xfire.util.dom.DOMInHandler;
39  import org.w3c.dom.Document;
40  
41  public class MuleWSSInHandler extends AbstractWSS4JHandler implements Handler
42  {
43      /**
44       * logger used by this class
45       */
46      protected static final Log log = LogFactory.getLog(MuleWSSInHandler.class);
47  
48      public MuleWSSInHandler()
49      {
50          super();
51          setPhase(Phase.PARSE);
52          getBefore().add(ReadHeadersHandler.class.getName());
53          getAfter().add(DOMInHandler.class.getName());
54      }
55  
56      public MuleWSSInHandler(Properties properties)
57      {
58          this();
59          setProperties(properties);
60      }
61  
62      /**
63       * The method invoke performs the security checks on the soap headers for the
64       * incoming message.
65       */
66      public void invoke(MessageContext msgContext)
67          throws SecurityException, XFireFault, WSSecurityException
68      {
69          boolean doDebug = log.isDebugEnabled();
70  
71          if (doDebug)
72          {
73              log.debug("MuleWSSInSecurityHandler: enter invoke()");
74          }
75  
76          RequestData reqData = new RequestData();
77  
78          try
79          {
80              reqData.setMsgContext(msgContext);
81  
82              Vector actions = new Vector();
83              String action;
84  
85              // the action property in the security header is necessary to know which
86              // type of security measure to adopt. It cannot be null.
87              if ((action = (String)getOption(WSHandlerConstants.ACTION)) == null)
88              {
89                  action = getString(WSHandlerConstants.ACTION, msgContext);
90              }
91              if (action == null)
92              {
93                  throw new XFireRuntimeException("MuleWSSInHandler: No action defined");
94              }
95  
96              int doAction = WSSecurityUtil.decodeAction(action, actions);
97  
98              String actor = (String)getOption(WSHandlerConstants.ACTOR);
99  
100             AbstractMessage sm = msgContext.getCurrentMessage();
101             Document doc = (Document)sm.getProperty(DOMInHandler.DOM_MESSAGE);
102 
103             if (doc == null)
104                 throw new XFireRuntimeException("DOMInHandler must be enabled for WS-Security!");
105 
106             // Check if it's a response and if its a fault it doesn't continue.
107             if (sm.getBody() instanceof XFireFault) return;
108 
109             // Get the password using a callback handler
110             CallbackHandler cbHandler = null;
111             if ((doAction & (WSConstants.ENCR | WSConstants.UT)) != 0)
112             {
113                 cbHandler = getPasswordCB(reqData);
114             }
115 
116             // Get and check the parameters pertaining to the signature and
117             // encryption actions. Doesn't get SAML properties, though
118             doReceiverAction(doAction, reqData);
119 
120             // If we're using signed SAML, we need to get the signature file in order
121             // to decrypt the SAML token
122             if (action.equals(WSHandlerConstants.SAML_TOKEN_SIGNED))
123             {
124                 reqData.setSigCrypto(loadSignatureCrypto(reqData));
125             }
126 
127             Vector wsResult;
128 
129             // process the security header
130             try
131             {
132                 wsResult = secEngine.processSecurityHeader(doc, actor, cbHandler, reqData
133                     .getSigCrypto(), reqData.getDecCrypto());
134             }
135             catch (WSSecurityException ex)
136             {
137                 throw new XFireFault("MuleWSSInHandler: security processing failed: " + ex.toString(), ex,
138                     XFireFault.SENDER);
139             }
140 
141             // no security header found we check whether the action was set to
142             // "no_security" or else we throw an exception
143             if (wsResult == null)
144             {
145                 if (doAction == WSConstants.NO_SECURITY)
146                 {
147                     return;
148                 }
149                 else
150                 {
151                     throw new XFireFault(
152                         "MuleWSSInHandler: Request does not contain required Security header",
153                         XFireFault.SENDER);
154                 }
155             }
156 
157             // confim that the signature is valid
158             if (reqData.getWssConfig().isEnableSignatureConfirmation())
159             {
160                 checkSignatureConfirmation(reqData, wsResult);
161             }
162 
163             // Extract the signature action result from the action vector
164             WSSecurityEngineResult actionResult = WSSecurityUtil.fetchActionResult(wsResult,
165                 WSConstants.SIGN);
166 
167             if (actionResult != null)
168             {
169                 X509Certificate returnCert = actionResult.getCertificate();
170 
171                 if (returnCert != null)
172                 {
173                     if (!verifyTrust(returnCert, reqData))
174                     {
175                         throw new XFireFault(
176                             "MuleWSSInHandler: The certificate used for the signature is not trusted",
177                             XFireFault.SENDER);
178                     }
179                 }
180             }
181 
182             if (actions.elementAt(0).equals(new Integer(16)))
183             {
184                 actions.clear();
185                 actions.add(new Integer(2));
186                 actions.add(new Integer(8));
187             }
188 
189             // now check the security actions: do they match, in right order?
190             if (!checkReceiverResults(wsResult, actions))
191             {
192                 throw new XFireFault(
193                     "MuleWSSInHandler: security processing failed (actions mismatch)",
194                     XFireFault.SENDER);
195 
196             }
197             /*
198              * Construct and setup the security result structure. The service may
199              * fetch this and check it.
200              */
201             Vector results;
202             if ((results = (Vector)msgContext.getProperty(WSHandlerConstants.RECV_RESULTS)) == null)
203             {
204                 results = new Vector();
205                 msgContext.setProperty(WSHandlerConstants.RECV_RESULTS, results);
206             }
207             WSHandlerResult rResult = new WSHandlerResult(actor, wsResult);
208             results.add(0, rResult);
209 
210             if (doDebug)
211             {
212                 log.debug("MuleWSSInHandler: exit invoke()");
213             }
214         }
215         catch (WSSecurityException e)
216         {
217             throw new WSSecurityException(e.getErrorCode());
218         }
219         finally
220         {
221             reqData.clear();
222             reqData = null;
223         }
224     }
225 }