[[WS-Security]] = WS-Security ifdef::env-github[:imagesdir: ../../] [[ws-security-overview]] == WS-Security overview WS-Security provides the means to secure your services beyond transport level protocols such as _HTTPS_. Through a number of standards such as http://www.w3.org/TR/xmlenc-core/[XML-Encryption], and headers defined in the http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=wss[WS-Security] standard, it allows you to: * Pass authentication tokens between services. * Encrypt messages or parts of messages. * Sign messages. * Timestamp messages. WS-Security makes heavy use of public and private key cryptography. It is helpful to understand these basics to really understand how to configure WS-Security. With public key cryptography, a user has a pair of public and private keys. These are generated using a large prime number and a key function. image:images/Public_key_making.png[Public_key_making.png] The keys are related mathematically, but cannot be derived from one another. With these keys we can encrypt messages. For example, if Bob wants to send a message to Alice, he can encrypt a message using her public key. Alice can then decrypt this message using her private key. Only Alice can decrypt this message as she is the only one with the private key. image:images/Public_key_encryption-mod.svg.png[images/Public_key_encryption-mod.svg.png] Messages can also be signed. This allows you to ensure the authenticity of the message. If Alice wants to send a message to Bob, and Bob wants to be sure that it is from Alice, Alice can sign the message using her private key. Bob can then verify that the message is from Alice by using her public key. image:images/250px-Public_key_making.svg.png[images/250px-Public_key_making.svg.png] [[jboss-ws-security-support]] == JBoss WS-Security support JBoss Web Services supports many real world scenarios requiring WS-Security functionalities. This includes signature and encryption support through X509 certificates, authentication and authorization through username tokens as well as all ws-security configurations covered by WS- http://docs.oasis-open.org/ws-sx/ws-securitypolicy/v1.3/ws-securitypolicy.html[SecurityPolicy] specification. <>, the core of WS-Security functionalities is provided through the Apache CXF engine. On top of that the JBossWS integration adds few configuration enhancements to simplify the setup of WS-Security enabled endpoints. [[apache-cxf-ws-security-implementation]] === Apache CXF WS-Security implementation Apache CXF features a top class WS-Security module supporting multiple configurations and easily extendible. The system is based on _interceptors_ that delegate to http://ws.apache.org/wss4j[Apache WSS4J] for the low level security operations. Interceptors can be configured in different ways, either through Spring configuration files or directly using Apache CXF client API. Please refer to the http://cxf.apache.org/docs/ws-security.html[Apache CXF documentation] if you're looking for more details. Recent versions of Apache CXF, however, introduced support for WS-Security Policy, which aims at moving most of the security configuration into the service contract (through policies), so that clients can easily be configured almost completely automatically from that. This way users do not need to manually deal with configuring / installing the required interceptors; the Apache CXF WS-Policy engine internally takes care of that instead. [[ws-security-policy-support]] ==== WS-Security Policy support WS-SecurityPolicy describes the actions that are required to securely communicate with a service advertised in a given WSDL contract. The WSDL bindings / operations reference WS-Policy fragments with the security requirements to interact with the service. The http://docs.oasis-open.org/ws-sx/ws-securitypolicy/v1.3/ws-securitypolicy.html[WS-SecurityPolicy specification] allows for specifying things like asymmetric/symmetric keys, using transports (https) for encryption, which parts/headers to encrypt or sign, whether to sign then encrypt or encrypt then sign, whether to include timestamps, whether to use derived keys, etc. However some mandatory configuration elements are not covered by WS-SecurityPolicy, basically because they're not meant to be public / part of the published endpoint contract; those include things such as keystore locations, usernames and passwords, etc. Apache CXF allows configuring these elements either through Spring xml descriptors or using the client API / annotations. Below is the list of supported configuration properties: [cols=",",options="header"] |======================================================================= |ws-security.username |The username used for UsernameToken policy assertions |ws-security.password |The password used for UsernameToken policy assertions. If not specified, the callback handler will be called. |ws-security.callback-handler |The WSS4J security CallbackHandler that will be used to retrieve passwords for keystores and UsernameTokens. |ws-security.signature.properties |The properties file/object that contains the WSS4J properties for configuring the signature keystore and crypto objects |ws-security.encryption.properties |The properties file/object that contains the WSS4J properties for configuring the encryption keystore and crypto objects |ws-security.signature.username |The username or alias for the key in the signature keystore that will be used. If not specified, it uses the the default alias set in the properties file. If that's also not set, and the keystore only contains a single key, that key will be used. |ws-security.encryption.username |The username or alias for the key in the encryption keystore that will be used. If not specified, it uses the the default alias set in the properties file. If that's also not set, and the keystore only contains a single key, that key will be used. For the web service provider, the useReqSigCert keyword can be used to accept (encrypt to) any client whose public key is in the service's truststore (defined in ws-security.encryption.properties.) |ws-security.signature.crypto |Instead of specifying the signature properties, this can point to the full WSS4J Crypto object. This can allow easier "programmatic" configuration of the Crypto information." |ws-security.encryption.crypto |Instead of specifying the encryption properties, this can point to the full WSS4J Crypto object. This can allow easier "programmatic" configuration of the Crypto information." |ws-security.enable.streaming |Enable streaming (StAX based) processing of WS-Security messages |======================================================================= Here is an example of configuration using the client API: [source,xml] ---- Map ctx = ((BindingProvider)port).getRequestContext(); ctx.put("ws-security.encryption.properties", properties); port.echoString("hello"); ---- Please refer to the http://cxf.apache.org/docs/ws-securitypolicy.html[Apache CXF documentation] for additional configuration details. [[jbossws-configuration-additions]] === JBossWS configuration additions In order for removing the need of Spring on server side for setting up WS-Security configuration properties not covered by policies, the JBossWS integration allows for getting those pieces of information from a defined _endpoint configuration_. <>can include property declarations and endpoint implementations can be associated with a given endpoint configuration using the `@EndpointConfig` annotation. [source,xml] ---- Custom WS-Security Endpoint ws-security.signature.properties bob.properties ws-security.encryption.properties bob.properties ws-security.signature.username bob ws-security.encryption.username alice ws-security.callback-handler org.jboss.test.ws.jaxws.samples.wsse.policy.basic.KeystorePasswordCallback ---- [source, java] ---- import javax.jws.WebService; import org.jboss.ws.api.annotation.EndpointConfig;   @WebService ( portName = "SecurityServicePort", serviceName = "SecurityService", wsdlLocation = "WEB-INF/wsdl/SecurityService.wsdl", targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy", endpointInterface = "org.jboss.test.ws.jaxws.samples.wsse.policy.basic.ServiceIface" ) @EndpointConfig(configFile = "WEB-INF/jaxws-endpoint-config.xml", configName = "Custom WS-Security Endpoint") public class ServiceImpl implements ServiceIface { public String sayHello() { return "Secure Hello World!"; } } ---- [[apache-cxf-annotations]] === Apache CXF annotations The JBossWS configuration additions allow for a descriptor approach to the WS-Security Policy engine configuration. If you prefer to provide the same information through an annotation approach, you can leverage the Apache CXF `@org.apache.cxf.annotations.EndpointProperties` annotation: [source, java] ---- @WebService( ... ) @EndpointProperties(value = { @EndpointProperty(key = "ws-security.signature.properties", value = "bob.properties"), @EndpointProperty(key = "ws-security.encryption.properties", value = "bob.properties"), @EndpointProperty(key = "ws-security.signature.username", value = "bob"), @EndpointProperty(key = "ws-security.encryption.username", value = "alice"), @EndpointProperty(key = "ws-security.callback-handler", value = "org.jboss.test.ws.jaxws.samples.wsse.policy.basic.KeystorePasswordCallback") } ) public class ServiceImpl implements ServiceIface { ... } ---- [[examples]] == Examples In this section some sample of WS-Security service endpoints and clients are provided. Please note they're only meant as tutorials; you should really careful isolate the ws-security policies / assertion that best suite your security needs before going to production environment. [WARNING] The following sections provide directions and examples on understanding some of the configuration options for WS-Security engine. Please note the implementor remains responsible for assessing the application requirements and choosing the most suitable security policy for them. [[signature-and-encryption]] === Signature and encryption [[endpoint]] ==== Endpoint First of all you need to create the web service endpoint using JAX-WS. While this can generally be achieved in different ways, it's required to use a contract-first approach when using WS-Security, as the policies declared in the wsdl are parsed by the Apache CXF engine on both server and client sides. So, here is an example of WSDL contract enforcing signature and encryption using X 509 certificates (the referenced schema is omitted): [source,xml] ----   ---- The service endpoint can be generated using the `wsconsume` tool and then enriched with a `@EndpointConfig` annotation: [source, java] ---- package org.jboss.test.ws.jaxws.samples.wsse.policy.basic;   import javax.jws.WebService; import org.jboss.ws.api.annotation.EndpointConfig;   @WebService ( portName = "SecurityServicePort", serviceName = "SecurityService", wsdlLocation = "WEB-INF/wsdl/SecurityService.wsdl", targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy", endpointInterface = "org.jboss.test.ws.jaxws.samples.wsse.policy.basic.ServiceIface" ) @EndpointConfig(configFile = "WEB-INF/jaxws-endpoint-config.xml", configName = "Custom WS-Security Endpoint") public class ServiceImpl implements ServiceIface { public String sayHello() { return "Secure Hello World!"; } } ---- The referenced _jaxws-endpoint-config.xml_ descriptor is used to provide a custom endpoint configuration with the required server side configuration properties; this tells the engine which certificate / key to use for signature / signature verification and for encryption / decryption: [source,xml] ---- Custom WS-Security Endpoint ws-security.signature.properties bob.properties ws-security.encryption.properties bob.properties ws-security.signature.username bob ws-security.encryption.username alice ws-security.callback-handler org.jboss.test.ws.jaxws.samples.wsse.policy.basic.KeystorePasswordCallback ---- ... the _bob.properties_ configuration file is also referenced above; it includes the WSS4J Crypto properties which in turn link to the keystore file, type and the alias/password to use for accessing it: .... org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin org.apache.ws.security.crypto.merlin.keystore.type=jks org.apache.ws.security.crypto.merlin.keystore.password=password org.apache.ws.security.crypto.merlin.keystore.alias=bob org.apache.ws.security.crypto.merlin.keystore.file=bob.jks .... A callback handler for the letting Apache CXF access the keystore is also provided: [source, java] ---- package org.jboss.test.ws.jaxws.samples.wsse.policy.basic;   import java.io.IOException; import java.util.HashMap; import java.util.Map; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.UnsupportedCallbackException; import org.apache.ws.security.WSPasswordCallback;   public class KeystorePasswordCallback implements CallbackHandler { private Map passwords = new HashMap();   public KeystorePasswordCallback() { passwords.put("alice", "password"); passwords.put("bob", "password"); }   /** * It attempts to get the password from the private * alias/passwords map. */ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { for (int i = 0; i < callbacks.length; i++) { WSPasswordCallback pc = (WSPasswordCallback)callbacks[i];   String pass = passwords.get(pc.getIdentifier()); if (pass != null) { pc.setPassword(pass); return; } } }   /** * Add an alias/password pair to the callback mechanism. */ public void setAliasPassword(String alias, String password) { passwords.put(alias, password); } } ---- Assuming the _bob.jks_ keystore has been properly generated and contains Bob's (server) full key (private/certificate + public key) as well as Alice's (client) public key, we can proceed to packaging the endpoint. Here is the expected content (the endpoint is a _POJO_ one in a _war_ archive, but _EJB3_ endpoints in _jar_ archives are of course also supported): .... alessio@inuyasha /dati/jbossws/stack/cxf/trunk $ jar -tvf ./modules/testsuite/cxf-tests/target/test-libs/jaxws-samples-wsse-policy-sign-encrypt.war 0 Thu Jun 16 18:50:48 CEST 2011 META-INF/ 140 Thu Jun 16 18:50:46 CEST 2011 META-INF/MANIFEST.MF 0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/ 586 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/web.xml 0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/ 0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/ 0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/ 0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ 0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/ 0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/ 0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/ 0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/ 0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/ 0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/basic/ 1687 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/basic/KeystorePasswordCallback.class 383 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/basic/ServiceIface.class 1070 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/basic/ServiceImpl.class 0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaxws/ 705 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaxws/SayHello.class 1069 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaxws/SayHelloResponse.class 1225 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/jaxws-endpoint-config.xml 0 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/wsdl/ 4086 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/wsdl/SecurityService.wsdl 653 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/wsdl/SecurityService_schema1.xsd 1820 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/classes/bob.jks 311 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/classes/bob.properties .... As you can see, the jaxws classes generated by the tools are of course also included, as well as a basic _web.xml_ referencing the endpoint bean: [source,xml] ---- TestService org.jboss.test.ws.jaxws.samples.wsse.policy.basic.ServiceImpl TestService /* ---- [IMPORTANT] If you're deploying the endpoint archive on WildFly, remember to add a dependency to _org.apache.ws.security_ module in the MANIFEST.MF file. .... Manifest-Version: 1.0 Ant-Version: Apache Ant 1.7.1 Created-By: 17.0-b16 (Sun Microsystems Inc.) Dependencies: org.apache.ws.security .... [[client]] ==== Client You start by consuming the published WSDL contract using the _wsconsume_ tool on client side too. Then you simply invoke the the endpoint as a standard JAX-WS one: [source, java] ---- QName serviceName = new QName("http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy", "SecurityService"); URL wsdlURL = new URL(serviceURL + "?wsdl"); Service service = Service.create(wsdlURL, serviceName); ServiceIface proxy = (ServiceIface)service.getPort(ServiceIface.class);   ((BindingProvider)proxy).getRequestContext().put(SecurityConstants.CALLBACK_HANDLER, new KeystorePasswordCallback()); ((BindingProvider)proxy).getRequestContext().put(SecurityConstants.SIGNATURE_PROPERTIES, Thread.currentThread().getContextClassLoader().getResource("META-INF/alice.properties")); ((BindingProvider)proxy).getRequestContext().put(SecurityConstants.ENCRYPT_PROPERTIES, Thread.currentThread().getContextClassLoader().getResource("META-INF/alice.properties")); ((BindingProvider)proxy).getRequestContext().put(SecurityConstants.SIGNATURE_USERNAME, "alice"); ((BindingProvider)proxy).getRequestContext().put(SecurityConstants.ENCRYPT_USERNAME, "bob");   proxy.sayHello(); ---- As you can see, the WS-Security properties are set in the request context. Here the `KeystorePasswordCallback` is the same as on server side above, you might want/need different implementation in real world scenarios, of course. + The _alice.properties_ file is the client side equivalent of the server side _bob.properties_ and references the _alice.jks_ keystore file, which has been populated with Alice's (client) full key (private/certificate + public key) as well as Bob's (server) public key. .... org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin org.apache.ws.security.crypto.merlin.keystore.type=jks org.apache.ws.security.crypto.merlin.keystore.password=password org.apache.ws.security.crypto.merlin.keystore.alias=alice org.apache.ws.security.crypto.merlin.keystore.file=META-INF/alice.jks .... The Apache CXF WS-Policy engine will digest the security requirements in the contract and ensure a valid secure communication is in place for interacting with the server endpoint. [[endpoint-serving-multiple-clients]] ==== Endpoint serving multiple clients The server side configuration described above implies the endpoint is configured for serving a given client which a service agreement has been established for. In some real world scenarios though, the same server might be expected to be able to deal with (including decrypting and encrypting) messages coming from and being sent to multiple clients. Apache CXF supports that through the `useReqSigCert` value for the `ws-security.encryption.username` configuration parameter. Of course the referenced server side keystore then needs to contain the public key of all the clients that are expected to be served. [[authentication-and-authorization]] === Authentication and authorization The Username Token Profile can be used to provide client's credentials to a WS-Security enabled target endpoint. Apache CXF provides means for setting basic _password callback handlers_ on both client and server sides to set/check passwords; the _ws-security.username_ and _ws-security.callback-handler_ properties can be used similarly as shown in the signature and encryption example. Things become more interesting when requiring a given user to be authenticated (and authorized) against a security domain on the target application server. On server side, you need to install two additional interceptors that act as bridges towards the application server authentication layer: * an interceptor for performing authentication and populating a valid SecurityContext; the provided interceptor should extend org.apache.cxf.ws.interceptor.security.AbstractUsernameTokenInInterceptor, in particular JBossWS integration comes with _org.jboss.wsf.stack.cxf.security.authentication.SubjectCreatingInterceptor_ for this; * an interceptor for performing authorization; CXF requires that to extend org.apache.cxf.interceptor.security.AbstractAuthorizingInInterceptor, for instance the _SimpleAuthorizingInterceptor_ can be used for simply mapping endpoint operations to allowed roles. So, here follows an example of WS-SecurityPolicy endpoint using Username Token Profile for authenticating through the application server security domain system. [[endpoint-1]] ==== Endpoint As in the other example, we start with a wsdl contract containing the proper WS-Security Policy: [source,xml] ----     ---- [IMPORTANT] If you want to send hash / digest passwords, you can use a policy such as what follows: [source,xml] ---- ---- Please note the specified JBoss security domain needs to be properly configured for computing digests. The service endpoint can be generated using the `wsconsume` tool and then enriched with a `@EndpointConfig` annotation and `@InInterceptors` annotation to add the two interceptors mentioned above for JAAS integration: [source, java] ---- package org.jboss.test.ws.jaxws.samples.wsse.policy.jaas;   import javax.jws.WebService; import org.apache.cxf.interceptor.InInterceptors; import org.jboss.ws.api.annotation.EndpointConfig;   @WebService ( portName = "SecurityServicePort", serviceName = "SecurityService", wsdlLocation = "WEB-INF/wsdl/SecurityService.wsdl", targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy", endpointInterface = "org.jboss.test.ws.jaxws.samples.wsse.policy.jaas.ServiceIface" ) @EndpointConfig(configFile = "WEB-INF/jaxws-endpoint-config.xml", configName = "Custom WS-Security Endpoint") @InInterceptors(interceptors = { "org.jboss.wsf.stack.cxf.security.authentication.SubjectCreatingPolicyInterceptor", "org.jboss.test.ws.jaxws.samples.wsse.policy.jaas.POJOEndpointAuthorizationInterceptor"} ) public class ServiceImpl implements ServiceIface { public String sayHello() { return "Secure Hello World!"; }   public String greetMe() { return "Greetings!"; } } ---- The `POJOEndpointAuthorizationInterceptor` is included into the deployment and deals with the roles cheks: [source, java] ---- package org.jboss.test.ws.jaxws.samples.wsse.policy.jaas;   import java.util.HashMap; import java.util.Map; import org.apache.cxf.interceptor.security.SimpleAuthorizingInterceptor;   public class POJOEndpointAuthorizationInterceptor extends SimpleAuthorizingInterceptor {   public POJOEndpointAuthorizationInterceptor() { super(); readRoles(); }   private void readRoles() { //just an example, this might read from a configuration file or such Map roles = new HashMap(); roles.put("sayHello", "friend"); roles.put("greetMe", "snoopies"); setMethodRolesMap(roles); } } ---- The _jaxws-endpoint-config.xml_ descriptor is used to provide a custom endpoint configuration with the required server side configuration properties; in particular for this Username Token case that's just a CXF configuration option for leaving the username token validation to the configured interceptors: [source,xml] ---- Custom WS-Security Endpoint ws-security.validate.token false ---- In order for requiring a given JBoss security domain to be used to protect access to the endpoint (a POJO one in this case), we declare that in a _jboss-web.xml_ descriptor (the _JBossWS_ security domain is used): [source,xml] ---- java:/jaas/JBossWS TestService org.jboss.test.ws.jaxws.samples.wsse.policy.jaas.ServiceImpl TestService /* ---- The endpoint is packaged into a war archive, including the JAXWS classes generated by wsconsume: .... alessio@inuyasha /dati/jbossws/stack/cxf/trunk $ jar -tvf ./modules/testsuite/cxf-tests/target/test-libs/jaxws-samples-wsse-policy-username-jaas.war 0 Thu Jun 16 18:50:48 CEST 2011 META-INF/ 155 Thu Jun 16 18:50:46 CEST 2011 META-INF/MANIFEST.MF 0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/ 585 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/web.xml 0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/ 0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/ 0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/ 0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ 0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/ 0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/ 0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/ 0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/ 0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/ 0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaas/ 982 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaas/POJOEndpointAuthorizationInterceptor.class 412 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaas/ServiceIface.class 1398 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaas/ServiceImpl.class 0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaxws/ 701 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaxws/GreetMe.class 1065 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaxws/GreetMeResponse.class 705 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaxws/SayHello.class 1069 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaxws/SayHelloResponse.class 556 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/jaxws-endpoint-config.xml 241 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/jboss-web.xml 0 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/wsdl/ 3183 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/wsdl/SecurityService.wsdl 1012 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/wsdl/SecurityService_schema1.xsd .... [IMPORTANT] If you're deploying the endpoint archive on WildFly, remember to add a dependency to _org.apache.ws.security_ and _org.apache.cxf_ module (due to the `@InInterceptor` annotation) in the MANIFEST.MF file. .... Manifest-Version: 1.0 Ant-Version: Apache Ant 1.7.1 Created-By: 17.0-b16 (Sun Microsystems Inc.) Dependencies: org.apache.ws.security,org.apache.cxf .... [[client-1]] ==== Client Here too you start by consuming the published WSDL contract using the _wsconsume_ tool. Then you simply invoke the the endpoint as a standard JAX-WS one: [source,java] ---- QName serviceName = new QName("http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy", "SecurityService"); URL wsdlURL = new URL(serviceURL + "?wsdl"); Service service = Service.create(wsdlURL, serviceName); ServiceIface proxy = (ServiceIface)service.getPort(ServiceIface.class);   ((BindingProvider)proxy).getRequestContext().put(SecurityConstants.USERNAME, "kermit"); ((BindingProvider)proxy).getRequestContext().put(SecurityConstants.CALLBACK_HANDLER, "org.jboss.test.ws.jaxws.samples.wsse.policy.jaas.UsernamePasswordCallback");   proxy.sayHello(); ---- The `UsernamePasswordCallback` class is shown below and is responsible for setting the passwords on client side just before performing the invocations: [source,java] ---- package org.jboss.test.ws.jaxws.samples.wsse.policy.jaas;   import java.io.IOException; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.UnsupportedCallbackException; import org.apache.ws.security.WSPasswordCallback;   public class UsernamePasswordCallback implements CallbackHandler { public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { WSPasswordCallback pc = (WSPasswordCallback)callbacks[0]; if ("kermit".equals(pc.getIdentifier())) pc.setPassword("thefrog"); } } ---- If everything has been done properly, you should expect to calls to `sayHello()` fail when done with user "snoopy" and pass with user "kermit" (and credential "thefrog"); moreover, you should get an authorization error when trying to call `greetMe()` with user "kermit", as that does not have the "snoopies" role. [[secure-transport]] === Secure transport Another quite common use case is using WS-Security Username Token Profile over a secure transport (HTTPS). A scenario like this is implemented similarly to what's described in the previous example, except for few differences explained below. First of all, here is an excerpt of a wsdl wth a sample security policy for Username Token over HTTPS: [source,xml] ---- ...                                                      ---- The endpoint then needs of course to be actually available on HTTPS only, so we have a _web.xml_ setting the _transport-guarantee_ such as below: [source,xml] ---- TestService org.jboss.test.ws.jaxws.samples.wsse.policy.basic.ServiceImpl TestService /*   TestService /* CONFIDENTIAL ---- [[secure-conversation]] === Secure conversation Apache CXF supports http://docs.oasis-open.org/ws-sx/ws-secureconversation/200512/ws-secureconversation-1.3-os.html[WS-SecureConversation] specification, which is about improving performance by allowing client and server to negotiate initial security keys to be used for later communication encryption/signature. This is done by having two policies in the wsdl contract, an outer one setting the security requirements to actually communicate with the endpoint and a bootstrap one, related to the communication for establishing the secure conversation keys. The client will be automatically sending an initial message to the server for negotiating the keys, then the actual communication to the endpoint takes place. As a consequence, Apache CXF needs a way to specify which WS-Security configuration properties are intended for the bootstrap policy and which are intended for the actual service policy. To accomplish this, properties intended for the bootstrap policy are appended with `.sct`. [source, java] ---- ... ((BindingProvider)proxy).getRequestContext().put("ws-security.signature.username.sct", "alice"); ((BindingProvider)proxy).getRequestContext().put("ws-security.encryption.username.sct", "bob"); ... ---- [source, java] ---- @WebService( ... ) @EndpointProperties(value = { @EndpointProperty(key = "ws-security.encryption.properties.sct", value = "bob.properties"), @EndpointProperty(key = "ws-security.signature.properties.sct", value = "bob.properties"), ... } ) public class ServiceImpl implements ServiceIface { ... } ----