| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| |
| <meta charset="UTF-8"> |
| <title>Securing a Web Service</title> |
| <meta name="description" content="Apache TomEE"> |
| <meta name="author" content="Apache TomEE"> |
| <meta name="google-translate-customization" content="f36a520c08f4c9-0a04e86a9c075ce9-g265f3196f697cf8f-10"> |
| <meta http-equiv="Pragma" content="no-cache"> |
| <meta http-equiv="Expires" content="0"> |
| <meta http-equiv="Cache-Control" content="no-store, no-cache, must-revalidate, max-age=0"> |
| |
| <!-- Le HTML5 shim, for IE6-8 support of HTML elements --> |
| <!--[if lt IE 9]> |
| <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script> |
| <![endif]--> |
| |
| <!-- Le styles --> |
| <link href="./resources/css/bootstrap.css" rel="stylesheet"> |
| <link href="./resources/css/prettify.css" rel="stylesheet"> |
| <!--link href="./resources/css/bootstrap-mods.css" rel="stylesheet"--> |
| <link href="./resources/css/main.css" rel="stylesheet"> |
| <link href="./resources/font-awesome-4.6.3/css/font-awesome.min.css" rel="stylesheet"> |
| |
| <script type="text/javascript"> |
| var t = encodeURIComponent(document.title.replace(/^\s+|\s+$/g,"")); |
| var u = encodeURIComponent(""+document.URL); |
| |
| function fbshare () { |
| window.open( |
| "http://www.facebook.com/sharer/sharer.php?u="+u, |
| 'Share on Facebook', |
| 'width=640,height=426'); |
| }; |
| function gpshare () { |
| window.open( |
| "https://plus.google.com/share?url="+u, |
| 'Share on Google+', |
| 'width=584,height=385'); |
| }; |
| function twshare () { |
| window.open( |
| "https://twitter.com/intent/tweet?url="+u+"&text="+t, |
| 'Share on Twitter', |
| 'width=800,height=526'); |
| }; |
| function pinshare () { |
| window.open("//www.pinterest.com/pin/create/button/?url="+u+"&media=http%3A%2F%2Ftomee.apache.org%2Fresources%2Fimages%2Ffeather-logo.png&description="+t, |
| 'Share on Pinterest', |
| 'width=800,height=526'); |
| }; |
| </script> |
| |
| <!-- Le fav and touch icons --> |
| <link rel="shortcut icon" href="./favicon.ico"> |
| <link rel="apple-touch-icon" href="./resources/images/apple-touch-icon.png"> |
| <link rel="apple-touch-icon" sizes="72x72" href="./resources/images/apple-touch-icon-72x72.png"> |
| <link rel="apple-touch-icon" sizes="114x114" href="./resources/images/apple-touch-icon-114x114.png"> |
| |
| <script src="./resources/js/prettify.js" type="text/javascript"></script> |
| <script src="./resources/js/jquery-latest.js"></script> |
| <script src="http://platform.twitter.com/widgets.js" type="text/javascript"></script> |
| <script src="./resources/js/common.js"></script> |
| <script src="./resources/js/prettyprint.js"></script> |
| <!--script src="//assets.pinterest.com/js/pinit.js" type="text/javascript" async></script//--> |
| |
| <script type="text/javascript"> |
| |
| var _gaq = _gaq || []; |
| _gaq.push(['_setAccount', 'UA-2717626-1']); |
| _gaq.push(['_setDomainName', 'apache.org']); |
| _gaq.push(['_trackPageview']); |
| |
| (function() { |
| var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; |
| ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; |
| var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); |
| })(); |
| |
| </script> |
| </head> |
| |
| <body> |
| |
| <div class="topbar" data-dropdown="dropdown"> |
| <div class="fill"> |
| <div class="container"> |
| <a class="brand" href="./index.html">Apache TomEE</a> |
| <ul class="nav"> |
| <li class="dropdown"> |
| <a class="dropdown-toggle" data-toggle="dropdown" href="#"> |
| Apache |
| <b class="caret"></b> |
| </a> |
| <ul class="dropdown-menu"> |
| <!-- <li><a href="./misc/whoweare.html">Who we are?</a></li> --> |
| <!-- <li><a href="./misc/heritage.html">Heritage</a></li> --> |
| <li><a href="http://www.apache.org">Apache Home</a></li> |
| <!-- <li><a href="./misc/resources.html">Resources</a></li> --> |
| <li><a href="./misc/contact.html">Contact</a></li> |
| <li><a href="./misc/legal.html">Legal</a></li> |
| <li><a href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li> |
| <li><a href="http://www.apache.org/foundation/thanks.html">Thanks</a></li> |
| <li class="divider"/> |
| <li><a href="http://www.apache.org/security">Security</a></li> |
| </ul> |
| </li> |
| <li><a href="./index.html">Home</a></li> |
| <li><a href="./downloads.html">Downloads</a></li> |
| <li><a href="./documentation.html">Documentation</a></li> |
| <li><a href="./examples-trunk/index.html">Examples</a></li> |
| <li><a href="./support.html">Support</a></li> |
| <li><a href="./contribute.html">Contribute</a></li> |
| <li><a href="./security/index.html">Security</a></li> |
| </ul> |
| |
| <!-- Google CSE Search Box Begins --> |
| <FORM class="pull-right" id="searchbox_010475492895890475512:_t4iqjrgx90" action="http://www.google.com/cse"> |
| <INPUT type="hidden" name="cx" value="010475492895890475512:_t4iqjrgx90"> |
| <INPUT type="hidden" name="cof" value="FORID:0"> |
| <INPUT size="18" width="130" style="width:130px" name="q" type="text" placeholder="Search"> |
| </FORM> |
| <!--<SCRIPT type="text/javascript" src="http://www.google.com/coop/cse/brand?form=searchbox_010475492895890475512:_t4iqjrgx90"></SCRIPT>--> |
| <!-- Google CSE Search Box Ends --> |
| </div> |
| </div> |
| </div> |
| |
| <div class="container"> |
| |
| |
| <div class="page-header"> |
| <small><a href="./index.html">Home</a></small><br> |
| <h1>Securing a Web Service |
| |
| <div style="float: right; position: relative; bottom: -10px; "> |
| <a onclick="javascript:gpshare()" class="gp-share sprite" title="Share on Google+">share [gp]</a> |
| <a onclick="javascript:fbshare()" class="fb-share sprite" title="Share on Facebook">share [fb]</a> |
| <a onclick="javascript:twshare()" class="tw-share sprite" title="Share on Twitter">share [tw]</a> |
| <a onclick="javascript:pinshare()" class="pin-share sprite" title="Share on Pinterest">share [pin]</a> |
| <a data-toggle="modal" href="#edit" class="edit-page" title="Contribute to this Page">contribute</a> |
| </div> |
| </h1> |
| </div> |
| |
| <p>Web Services are a very common way to implement a Service Oriented |
| Architecture (SOA).</p> |
| |
| <p>There are lots of web service standards/specifications (XML, SOAP, WSDL, |
| UUDI, WS-*, ...) coming from organizations like W3C, OASIS, WS-I, ... |
| And there are java web service standards like JAX-WS 1.x (JSR 181), JAX-WS |
| 2.0 (JSR 224). </p> |
| |
| <p>OpenEJB provides a standard way to implement web services transport |
| protocol throughout the JAX-WS specification. |
| Java basic standards for web services (JAX-WS) do lack some features that |
| are required in most real world applications, e.g. standard ways for |
| handling security and authentication (there is no java specification for |
| Oasis's WS-Security specification).</p> |
| |
| <p>OpenEJB provides two mechanisms to secure webservices - HTTP authentication |
| and WS-Security: </p> |
| |
| <p>HTTPS : works at the transport level, enables a point-to-point security. |
| It has no impact on developments. It allows you :</p> |
| |
| <ol> |
| <li>To secure data over the network with data encrypted during transport</li> |
| <li>To identify the end user with SSLv3 with client certificate required</li> |
| <li>OpenEJB supports BASIC authentication over HTTP(S), using the configured |
| JAAS provider. This will honour any EJB security roles you have setup using |
| @RolesAllowed. See the webservice-security example in the OpenEJB codebase <a href="http://svn.apache.org/repos/asf/tomee/tomee/trunk/examples/">http://svn.apache.org/repos/asf/tomee/tomee/trunk/examples/</a></li> |
| </ol> |
| |
| <p><em>Warning: |
| Currently only BASIC is the only HTTP authentication mechanism available |
| when running OpenEJB standalone or in a unit test, but we hope to support |
| DIGEST in the future.</em></p> |
| |
| <p>WS-Security: works at the message (SOAP) level, enables a higher-level |
| security, |
| Nowadays, SOAP implementations use other protocols than just HTTP so we |
| need to apply security to the message itself and not only at the transport |
| layer. Moreover, HTTPS can only be used for securing point-to-point |
| services which tend to decrease with Enterprise Service Bus for example. </p> |
| |
| <p>The Oasis organization has defined a standard (part of well-known WS-*) |
| which aims at providing high level features in the context of web services: |
| WS-Security. It provides a standard way to secure your services above and |
| beyond transport level protocols such as HTTPS. WS-Security relies on other |
| standards like XML-Encryption.</p> |
| |
| <p>Main features are:</p> |
| |
| <ol> |
| <li>Timestamp a message,</li> |
| <li>Pass credentials (plain text and/or ciphered) between services,</li> |
| <li>Sign messages,</li> |
| <li>Encrypt messages or part of messages.</li> |
| </ol> |
| |
| <p>Again, JAX-WS doesn't standardize security for web services. OpenEJB |
| provides a common and highly configurable way to configure WS-Security in |
| association with the JAX-WS usage without vendor dependence. Internally, |
| OpenEJB integrates Apache WSS4J as the WS-Security implementation. To use |
| the integration, you will need to configure WSS4J using the |
| <em>openejb-jar.xml</em>.</p> |
| |
| <p><em>Warning: |
| the proposed WS-Security integration is only used at server side. |
| Currently, WS-Security client configuration is not managed by OpenEJB. You |
| can use the JAX-WS API to create a stub and then rely on the implementation |
| to set up WS-Security properties.</em> </p> |
| |
| <p>This configuration file lets you set up incoming and outgoing security |
| parameters. Incoming and outgoing configuration is independent so that you |
| can configure either one or the other or both. You can decide to check |
| client credentials for incoming messages and sign outgoing messages |
| (response).</p> |
| |
| <p><a name="SecuringaWebService-Configurationprinciples"></a></p> |
| |
| <h1>Configuration principles</h1> |
| |
| <p>The configuration is made in the <em>openejb-jar.xml</em>. Each endpoint web |
| service can provide a set of properties to customize WS-Security behavior |
| through the <properties> element. The content of this element is consistent |
| with the overall structure of <em>openejb.xml</em>. The format for properties is |
| the same as if you would use a common java property file.</p> |
| |
| <pre><code><properties> |
| wss4j.in.action = UsernameToken |
| wss4j.in.passwordType = PasswordDigest |
| wss4j.in.passwordCallbackClass=org.superbiz.calculator.CustomPasswordHandler |
| </properties> |
| </code></pre> |
| |
| <p>In order to recover WSS4J properties both for input and output, we use |
| naming conventions. |
| Each property is made of |
| <wss4j>.<in|out>.<wss4j property name>=<wss4j property value></p> |
| |
| <p>For example : <em>wss4j.in.action = UsernameToken</em></p> |
| |
| <p><a name="SecuringaWebService-UsernameToken(Passworddigest)example"></a></p> |
| |
| <h1>Username Token (Password digest) example</h1> |
| |
| <p><a name="SecuringaWebService-Excerptfrom*openejb-jar.xml*."></a></p> |
| |
| <h4>Excerpt from <em>openejb-jar.xml</em>.</h4> |
| |
| <pre><code><openejb-jar xmlns="http://tomee.apache.org/xml/ns/openejb-jar-2.2"> |
| <enterprise-beans> |
| ... |
| <session> |
| <ejb-name>CalculatorImpl</ejb-name> |
| <web-service-security> |
| <security-realm-name/> |
| <transport-guarantee>NONE</transport-guarantee> |
| <auth-method>WS-SECURITY</auth-method> |
| <properties> |
| wss4j.in.action = UsernameToken |
| wss4j.in.passwordType = PasswordDigest |
| wss4j.in.passwordCallbackClass=org.superbiz.calculator.CustomPasswordHandler |
| </properties> |
| </web-service-security> |
| </session> |
| ... |
| </enterprise-beans> |
| </openejb-jar> |
| </code></pre> |
| |
| <p><a name="SecuringaWebService-Requestsentbytheclient."></a></p> |
| |
| <h4>Request sent by the client.</h4> |
| |
| <p>This request contains SOAP headers to manage security. You can see |
| <em>UsernameToken</em> tag from the WS-Security specification.</p> |
| |
| <pre><code>POST /CalculatorImplUsernameTokenHashedPassword HTTP/1.1 |
| Content-Type: text/xml; charset=UTF-8 |
| SOAPAction: "" |
| Accept: * |
| Cache-Control: no-cache |
| Pragma: no-cache |
| User-Agent: Java/1.5.0_05 |
| Host: 127.0.0.1:8204 |
| Connection: keep-alive |
| Transfer-Encoding: chunked |
| |
| 524 |
| <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> |
| <soap:Header> |
| <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soap:mustUnderstand="1"> |
| <wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" |
| wsu:Id="UsernameToken-22402238" |
| xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> |
| <wsse:Username xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">jane</wsse:Username> |
| <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest" |
| xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">tf7k3a4GREIt1xec/KXVmBdRNIg=</wsse:Password> |
| <wsse:Nonce xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">cKhUhmjQ1hGYPsdOLez5kA==</wsse:Nonce> |
| <wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2009-04-14T20:16:26.203Z</wsu:Created> |
| </wsse:UsernameToken> |
| </wsse:Security> |
| </soap:Header> |
| <soap:Body> |
| <ns1:sum xmlns:ns1="http://superbiz.org/wsdl"> |
| <arg0>4</arg0> |
| <arg1>6</arg1> |
| </ns1:sum> |
| </soap:Body> |
| </soap:Envelope> |
| </code></pre> |
| |
| <p><a name="SecuringaWebService-Theresponsereturnedfromtheserver."></a></p> |
| |
| <h4>The response returned from the server.</h4> |
| |
| <pre><code>HTTP/1.1 200 OK |
| Content-Length: 200 |
| Connection: close |
| Content-Type: text/xml; charset=UTF-8 |
| Server: OpenEJB/??? (unknown os) |
| |
| <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> |
| <soap:Body> |
| <ns1:sumResponse xmlns:ns1="http://superbiz.org/wsdl"> |
| <return>10</return> |
| </ns1:sumResponse> |
| </soap:Body> |
| </soap:Envelope> |
| </code></pre> |
| |
| <p><a name="SecuringaWebService-JAASwithWS-Security"></a></p> |
| |
| <h1>JAAS with WS-Security</h1> |
| |
| <p>@RolesAllowed doesn't work straight off with WS-Security, but you can add |
| calls to the OpenEJB SecurityService to login to a JAAS provider to a |
| CallbackHandler. Once you have done this, any permissions configured with |
| @RolesAllowed should be honoured.</p> |
| |
| <p>Here is a snippet from the webservice-ws-security example demonstrating |
| this:</p> |
| |
| <pre><code>public class CustomPasswordHandler implements CallbackHandler { |
| |
| public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { |
| WSPasswordCallback pc = (WSPasswordCallback) callbacks[0]; |
| |
| if (pc.getUsage() == WSPasswordCallback.USERNAME_TOKEN) { |
| // TODO get the password from the users.properties if possible |
| pc.setPassword("waterfall"); |
| |
| } else if (pc.getUsage() == WSPasswordCallback.DECRYPT) { |
| |
| pc.setPassword("serverPassword"); |
| |
| } else if (pc.getUsage() == WSPasswordCallback.SIGNATURE) { |
| |
| pc.setPassword("serverPassword"); |
| |
| } |
| |
| if ((pc.getUsage() == WSPasswordCallback.USERNAME_TOKEN) || (pc.getUsage() == WSPasswordCallback.USERNAME_TOKEN_UNKNOWN)) { |
| |
| SecurityService securityService = SystemInstance.get().getComponent(SecurityService.class); |
| Object token = null; |
| try { |
| securityService.disassociate(); |
| |
| token = securityService.login(pc.getIdentifer(), pc.getPassword()); |
| securityService.associate(token); |
| |
| } catch (LoginException e) { |
| e.printStackTrace(); |
| throw new SecurityException("wrong password"); |
| } |
| } |
| } |
| } |
| </code></pre> |
| |
| <p><a name="SecuringaWebService-Examples"></a></p> |
| |
| <h1>Examples</h1> |
| |
| <p>A full example (webservice-ws-security) is available with OpenEJB Examples.</p> |
| |
| |
| |
| |
| <div id="edit" class="modal hide fade in" style="display: none; "> |
| <div class="modal-header"> |
| <a class="close" data-dismiss="modal">x</a> |
| |
| <h3>Thank you for contributing to the documentation!</h3> |
| </div> |
| <div class="modal-body"> |
| <h4>Any help with the documentation is greatly appreciated.</h4> |
| <p>All edits are reviewed before going live, so feel free to do much more than fix typos or links. If you see a page that could benefit from an entire rewrite, we'd be thrilled to review it. Don't be surprised if we like it so much we ask you for help with other pages :)</p> |
| <small>NOTICE: unless indicated otherwise on the pages in question, all editable content available from apache.org is presumed to be licensed under the Apache License (AL) version 2.0 and hence all submissions to apache.org treated as formal Contributions under the license terms.</small> |
| <!--[if gt IE 6]> |
| <h4>Internet Explorer Users</h4> |
| <p>If you are not an Apache committer, click the Yes link and enter a <i>anonymous</i> for the username and leave the password empty</p> |
| <![endif]--> |
| |
| </div> |
| <div class="modal-footer"> |
| Do you have an Apache ID? |
| <a href="javascript:void(location.href='https://cms.apache.org/redirect?uri='+escape(location.href))" class="btn">Yes</a> |
| <a href="javascript:void(location.href='https://anonymous:@cms.apache.org/redirect?uri='+escape(location.href))" class="btn">No</a> |
| </div> |
| </div> |
| <script src="./resources/js/bootstrap-modal.js"></script> |
| |
| <footer> |
| <p>Copyright © 1999-2016 The Apache Software Foundation, Licensed under the Apache License, Version 2.0. |
| Apache TomEE, TomEE, Apache, the Apache feather logo, and the Apache TomEE project logo are trademarks of The Apache Software Foundation. |
| All other marks mentioned may be trademarks or registered trademarks of their respective owners.</p> |
| </footer> |
| |
| </div> <!-- /container --> |
| |
| <!-- Javascript |
| ================================================== --> |
| <!-- Placed at the end of the document so the pages load faster --> |
| <script src="./resources/js/bootstrap-dropdown.js"></script> |
| |
| </body> |
| </html> |