View Javadoc

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