| = Securing a Web Service |
| :index-group: OpenEJB Standalone Server |
| :jbake-date: 2018-12-05 |
| :jbake-type: page |
| :jbake-status: published |
| |
| |
| Web Services are a very common way to implement a Service Oriented |
| Architecture (SOA). |
| |
| 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). |
| |
| 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). |
| |
| OpenEJB provides two mechanisms to secure webservices - HTTP |
| authentication and WS-Security: |
| |
| HTTPS : works at the transport level, enables a point-to-point security. |
| It has no impact on developments. It allows you : |
| |
| [arabic] |
| . To secure data over the network with data encrypted during transport |
| . To identify the end user with SSLv3 with client certificate required |
| . OpenEJB supports BASIC authentication over HTTP(S), using the |
| configured JAAS provider. This will honour any EJB security roles you |
| have setup using |
| |
| . See the webservice-security example in the OpenEJB codebase |
| http://svn.apache.org/repos/asf/tomee/tomee/trunk/examples/ |
| |
| _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._ |
| |
| 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. |
| |
| 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. |
| |
| Main features are: |
| |
| [arabic] |
| . Timestamp a message, |
| . Pass credentials (plain text and/or ciphered) between services, |
| . Sign messages, |
| . Encrypt messages or part of messages. |
| |
| 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 _openejb-jar.xml_. |
| |
| _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._ |
| |
| 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). |
| |
| = Configuration principles The configuration is made in the |
| _openejb-jar.xml_. Each endpoint web service can provide a set of |
| properties to customize WS-Security behavior through the element. The |
| content of this element is consistent with the overall structure of |
| _openejb.xml_. The format for properties is the same as if you would use |
| a common java property file. |
| |
| [source,xml] |
| ---- |
| <properties> |
| wss4j.in.action = UsernameToken |
| wss4j.in.passwordType = PasswordDigest |
| wss4j.in.passwordCallbackClass=org.superbiz.calculator.CustomPasswordHandler |
| </properties> |
| ---- |
| |
| In order to recover WSS4J properties both for input and output, we use |
| naming conventions. Each property is made of .<in|out>.= |
| |
| For example : _wss4j.in.action = UsernameToken_ |
| |
| = Username Token (Password digest) example #### Excerpt from |
| _openejb-jar.xml_. |
| |
| [source,xml] |
| ---- |
| <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> |
| ---- |
| |
| == Request sent by the client. This request contains SOAP headers to |
| manage security. You can see _UsernameToken_ tag from the WS-Security |
| specification. |
| |
| [source,properties] |
| ---- |
| 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> |
| ---- |
| |
| == The response returned from the server. |
| |
| [source,properties] |
| ---- |
| 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> |
| ---- |
| |
| = JAAS with WS-Security |
| |
| 1 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 1 should be honoured. |
| |
| Here is a snippet from the webservice-ws-security example demonstrating |
| this: |
| |
| [source,java] |
| ---- |
| 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"); |
| } |
| } |
| } |
| } |
| ---- |
| |
| = Examples A full example (webservice-ws-security) is available with |
| OpenEJB Examples. |