1 17 package org.apache.servicemix.soap.handlers.security; 18 19 import java.io.IOException ; 20 import java.security.GeneralSecurityException ; 21 import java.security.Principal ; 22 import java.security.cert.X509Certificate ; 23 import java.util.HashMap ; 24 import java.util.HashSet ; 25 import java.util.Iterator ; 26 import java.util.Map ; 27 import java.util.Set ; 28 import java.util.Vector ; 29 30 import javax.security.auth.Subject ; 31 import javax.security.auth.callback.CallbackHandler ; 32 import javax.security.auth.callback.UnsupportedCallbackException ; 33 import javax.xml.namespace.QName ; 34 35 import org.apache.servicemix.jbi.security.auth.AuthenticationService; 36 import org.apache.servicemix.jbi.security.keystore.KeystoreManager; 37 import org.apache.servicemix.soap.Context; 38 import org.apache.servicemix.soap.Handler; 39 import org.apache.servicemix.soap.SoapFault; 40 import org.apache.ws.security.WSConstants; 41 import org.apache.ws.security.WSDocInfo; 42 import org.apache.ws.security.WSDocInfoStore; 43 import org.apache.ws.security.WSPasswordCallback; 44 import org.apache.ws.security.WSSConfig; 45 import org.apache.ws.security.WSSecurityEngine; 46 import org.apache.ws.security.WSSecurityEngineResult; 47 import org.apache.ws.security.WSSecurityException; 48 import org.apache.ws.security.WSUsernameTokenPrincipal; 49 import org.apache.ws.security.components.crypto.Crypto; 50 import org.apache.ws.security.handler.RequestData; 51 import org.apache.ws.security.handler.WSHandler; 52 import org.apache.ws.security.handler.WSHandlerConstants; 53 import org.apache.ws.security.handler.WSHandlerResult; 54 import org.apache.ws.security.message.token.Timestamp; 55 import org.apache.ws.security.processor.Processor; 56 import org.apache.ws.security.util.WSSecurityUtil; 57 import org.w3c.dom.Document ; 58 import org.w3c.dom.Element ; 59 60 66 public class WSSecurityHandler extends WSHandler implements Handler { 67 68 private Map properties = new HashMap (); 69 private String domain = "servicemix-domain"; 70 private AuthenticationService authenticationService; 71 private boolean required; 72 private String sendAction; 73 private String receiveAction; 74 private String actor; 75 private String username; 76 private String keystore; 77 private Crypto crypto; 78 private CallbackHandler handler = new DefaultHandler(); 79 80 private ThreadLocal currentSubject = new ThreadLocal (); 81 82 public WSSecurityHandler() { 83 WSSecurityEngine.setWssConfig(new ServiceMixWssConfig()); 84 } 85 86 89 public AuthenticationService getAuthenticationService() { 90 return authenticationService; 91 } 92 93 96 public void setAuthenticationService(AuthenticationService authenticationService) { 97 this.authenticationService = authenticationService; 98 } 99 100 private class ServiceMixWssConfig extends WSSConfig { 101 public Processor getProcessor(QName el) throws WSSecurityException { 102 if (el.equals(WSSecurityEngine.SIGNATURE)) { 103 return new SignatureProcessor(); 104 } else { 105 return super.getProcessor(el); 106 } 107 } 108 } 109 110 private class SignatureProcessor extends org.apache.ws.security.processor.SignatureProcessor { 111 private String signatureId; 112 public void handleToken(Element elem, Crypto crypto, Crypto decCrypto, CallbackHandler cb, WSDocInfo wsDocInfo, Vector returnResults, WSSConfig wsc) throws WSSecurityException { 113 WSDocInfoStore.store(wsDocInfo); 114 X509Certificate [] returnCert = new X509Certificate [1]; 115 Set returnElements = new HashSet (); 116 byte[][] signatureValue = new byte[1][]; 117 Principal lastPrincipalFound = null; 118 try { 119 lastPrincipalFound = verifyXMLSignature((Element ) elem, 120 crypto, returnCert, returnElements, signatureValue); 121 if (lastPrincipalFound instanceof WSUsernameTokenPrincipal) { 122 WSUsernameTokenPrincipal p = (WSUsernameTokenPrincipal) lastPrincipalFound; 123 checkUser(p.getName(), p.getPassword()); 124 } else { 125 checkUser(returnCert[0].getSubjectX500Principal().getName(), returnCert[0]); 126 } 127 } catch (GeneralSecurityException e) { 128 throw new WSSecurityException("Unable to authenticate user", e); 129 } finally { 130 WSDocInfoStore.delete(wsDocInfo); 131 } 132 if (lastPrincipalFound instanceof WSUsernameTokenPrincipal) { 133 returnResults.add(0, new WSSecurityEngineResult( 134 WSConstants.UT_SIGN, lastPrincipalFound, null, 135 returnElements, signatureValue[0])); 136 137 } else { 138 returnResults.add(0, new WSSecurityEngineResult( 139 WSConstants.SIGN, lastPrincipalFound, 140 returnCert[0], returnElements, signatureValue[0])); 141 } 142 signatureId = elem.getAttributeNS(null, "Id"); 143 } 144 public String getId() { 145 return signatureId; 146 } 147 } 148 149 152 public String getUsername() { 153 return username; 154 } 155 156 159 public void setUsername(String username) { 160 this.username = username; 161 } 162 163 166 public Crypto getCrypto() { 167 return crypto; 168 } 169 170 173 public void setCrypto(Crypto crypto) { 174 this.crypto = crypto; 175 } 176 177 180 public String getActor() { 181 return actor; 182 } 183 184 187 public void setActor(String actor) { 188 this.actor = actor; 189 } 190 191 194 public String getDomain() { 195 return domain; 196 } 197 198 201 public void setDomain(String domain) { 202 this.domain = domain; 203 } 204 205 208 public String getReceiveAction() { 209 return receiveAction; 210 } 211 212 215 public void setReceiveAction(String receiveAction) { 216 this.receiveAction = receiveAction; 217 } 218 219 222 public String getSendAction() { 223 return sendAction; 224 } 225 226 229 public void setSendAction(String action) { 230 this.sendAction = action; 231 } 232 233 236 public boolean isRequired() { 237 return required; 238 } 239 240 public boolean requireDOM() { 241 return true; 242 } 243 244 247 public void setRequired(boolean required) { 248 this.required = required; 249 } 250 251 public Object getOption(String key) { 252 return properties.get(key); 253 } 254 255 public void setOption(String key, Object value) { 256 this.properties.put(key, value); 257 } 258 259 public String getPassword(Object msgContext) { 260 return (String ) ((Context) msgContext).getProperty("password"); 261 } 262 263 public Object getProperty(Object msgContext, String key) { 264 if (WSHandlerConstants.PW_CALLBACK_REF.equals(key)) { 265 return handler; 266 } 267 return ((Context) msgContext).getProperty(key); 268 } 269 270 public void setPassword(Object msgContext, String password) { 271 ((Context) msgContext).setProperty("password", password); 272 } 273 274 public void setProperty(Object msgContext, String key, Object value) { 275 ((Context) msgContext).setProperty(key, value); 276 } 277 278 protected Crypto loadDecryptionCrypto(RequestData reqData) throws WSSecurityException { 279 return crypto; 280 } 281 282 protected Crypto loadEncryptionCrypto(RequestData reqData) throws WSSecurityException { 283 return crypto; 284 } 285 286 public Crypto loadSignatureCrypto(RequestData reqData) throws WSSecurityException { 287 return crypto; 288 } 289 290 public void onReceive(Context context) throws Exception { 291 RequestData reqData = new RequestData(); 292 init(context); 293 try { 294 reqData.setNoSerialization(true); 295 reqData.setMsgContext(context); 296 297 Vector actions = new Vector (); 298 String action = this.receiveAction; 299 if (action == null) { 300 throw new IllegalStateException ("WSSecurityHandler: No receiveAction defined"); 301 } 302 int doAction = WSSecurityUtil.decodeAction(action, actions); 303 304 Document doc = context.getInMessage().getDocument(); 305 if (doc == null) { 306 throw new IllegalStateException ("WSSecurityHandler: The soap message has not been parsed using DOM"); 307 } 308 309 313 doReceiverAction(doAction, reqData); 314 315 Vector wsResult = null; 316 317 try { 318 wsResult = secEngine.processSecurityHeader( 319 doc, actor, handler, 320 reqData.getSigCrypto(), 321 reqData.getDecCrypto()); 322 } catch (WSSecurityException ex) { 323 throw new SoapFault(ex); 324 } 325 326 if (wsResult == null) { if (doAction == WSConstants.NO_SECURITY) { 328 return; 329 } else { 330 throw new SoapFault(new WSSecurityException( 331 "WSSecurityHandler: Request does not contain required Security header")); 332 } 333 } 334 335 if (reqData.getWssConfig().isEnableSignatureConfirmation()) { 336 checkSignatureConfirmation(reqData, wsResult); 337 } 338 339 348 349 WSSecurityEngineResult actionResult = WSSecurityUtil.fetchActionResult(wsResult, WSConstants.SIGN); 351 352 if (actionResult != null) { 353 X509Certificate returnCert = actionResult.getCertificate(); 354 355 if (returnCert != null) { 356 if (!verifyTrust(returnCert, reqData)) { 357 throw new SoapFault(new WSSecurityException( 358 "WSSecurityHandler: the certificate used for the signature is not trusted")); 359 } 360 } 361 } 362 363 372 373 actionResult = WSSecurityUtil.fetchActionResult(wsResult, WSConstants.TS); 375 376 if (actionResult != null) { 377 Timestamp timestamp = actionResult.getTimestamp(); 378 379 if (timestamp != null) { 380 if (!verifyTimestamp(timestamp, decodeTimeToLive(reqData))) { 381 throw new SoapFault(new WSSecurityException( 382 "WSSecurityHandler: the timestamp could not be validated")); 383 } 384 } 385 } 386 387 390 if (!checkReceiverResults(wsResult, actions)) { 391 throw new SoapFault(new WSSecurityException( 392 "WSSecurityHandler: security processing failed (actions mismatch)")); 393 394 } 395 399 Vector results = null; 400 if ((results = (Vector ) context.getProperty(WSHandlerConstants.RECV_RESULTS)) == null) { 401 results = new Vector (); 402 context.setProperty(WSHandlerConstants.RECV_RESULTS, results); 403 } 404 WSHandlerResult rResult = new WSHandlerResult(actor, wsResult); 405 results.add(0, rResult); 406 407 for (Iterator iter = results.iterator(); iter.hasNext();) { 409 WSHandlerResult hr = (WSHandlerResult) iter.next(); 410 for (Iterator it = hr.getResults().iterator(); it.hasNext();) { 411 WSSecurityEngineResult er = (WSSecurityEngineResult) it.next(); 412 if (er.getPrincipal() != null) { 413 context.getInMessage().addPrincipal(er.getPrincipal()); 414 } 415 } 416 } 417 Subject s = (Subject ) currentSubject.get(); 418 if (s != null) { 419 for (Iterator iterator = s.getPrincipals().iterator(); iterator.hasNext();) { 420 Principal p = (Principal ) iterator.next(); 421 context.getInMessage().addPrincipal(p); 422 } 423 } 424 425 } finally { 426 reqData.clear(); 427 currentSubject.set(null); 428 } 429 } 430 431 public void onReply(Context context) throws Exception { 432 434 } 435 436 public void onFault(Context context) throws Exception { 437 439 } 440 441 public void onSend(Context context) throws Exception { 442 RequestData reqData = new RequestData(); 443 reqData.setMsgContext(context); 444 init(context); 445 449 try { 450 453 Vector actions = new Vector (); 454 String action = this.sendAction; 455 if (action == null) { 456 throw new IllegalStateException ("WSSecurityHandler: No sendAction defined"); 457 } 458 459 int doAction = WSSecurityUtil.decodeAction(action, actions); 460 if (doAction == WSConstants.NO_SECURITY) { 461 return; 462 } 463 464 468 reqData.setUsername((String ) getOption(WSHandlerConstants.USER)); 469 if (reqData.getUsername() == null || reqData.getUsername().equals("")) { 470 String username = (String ) getProperty(reqData.getMsgContext(), WSHandlerConstants.USER); 471 if (username != null) { 472 reqData.setUsername(username); 473 } else { 474 reqData.setUsername(this.username); 475 } 476 } 477 478 483 if ((doAction & (WSConstants.SIGN | WSConstants.UT | WSConstants.UT_SIGN)) != 0) { 484 488 if (reqData.getUsername() == null || reqData.getUsername().equals("")) { 489 throw new IllegalStateException ("WSSecurityHandler: Empty username for specified action"); 490 } 491 } 492 498 Document doc = context.getInMessage().getDocument(); 499 if (doc == null) { 500 throw new IllegalStateException ("WSSecurityHandler: The soap message has not been parsed using DOM"); 501 } 502 503 doSenderAction(doAction, doc, reqData, actions, true); 504 } 505 catch (WSSecurityException e) { 506 throw new SoapFault(e); 507 } 508 finally { 509 reqData.clear(); 510 reqData = null; 511 } 512 } 513 514 public void onAnswer(Context context) { 515 517 } 518 519 protected void checkUser(String user, Object credentials) throws GeneralSecurityException { 520 if (authenticationService == null) { 521 throw new IllegalArgumentException ("authenticationService is null"); 522 } 523 Subject subject = (Subject ) currentSubject.get(); 524 if (subject == null) { 525 subject = new Subject (); 526 currentSubject.set(subject); 527 } 528 authenticationService.authenticate(subject, domain, user, credentials); 529 } 530 531 protected class DefaultHandler extends BaseSecurityCallbackHandler { 532 533 protected void processSignature(WSPasswordCallback callback) throws IOException , UnsupportedCallbackException { 534 callback.setPassword(""); 535 } 536 537 protected void processUsernameTokenUnkown(WSPasswordCallback callback) throws IOException , UnsupportedCallbackException { 538 try { 539 checkUser(callback.getIdentifer(), callback.getPassword()); 540 } catch (GeneralSecurityException e) { 541 throw new UnsupportedCallbackException (callback, "Unable to authenticate user"); 542 } 543 } 544 545 } 546 547 550 public String getKeystore() { 551 return keystore; 552 } 553 554 557 public void setKeystore(String keystore) { 558 this.keystore = keystore; 559 } 560 561 protected void init(Context context) { 562 currentSubject.set(null); 563 if (context.getProperty(Context.AUTHENTICATION_SERVICE) != null) { 564 setAuthenticationService((AuthenticationService) context.getProperty(Context.AUTHENTICATION_SERVICE)); 565 } 566 if (crypto == null && context.getProperty(Context.KEYSTORE_MANAGER) != null) { 567 KeystoreManager km = (KeystoreManager) context.getProperty(Context.KEYSTORE_MANAGER); 568 setCrypto(new KeystoreInstanceCrypto(km, keystore)); 569 } 570 } 571 572 } 573 | Popular Tags |