This section examines the crucial elements in providing the Security Token Service functionality described in the basic WS-Trust scenario. The components that will be discussed are.
STS Implementation
The Apache CXF's STS, SecurityTokenServiceProvider, is a web service provider that is compliant with the protocols and functionality defined by the WS-Trust specification. It has a modular architecture. Many of its components are configurable or replaceable and there are many optional features that are enabled by implementing and configuring plug-ins. Users can customize their own STS by extending from SecurityTokenServiceProvider and overriding the default settings. Extensive information about the CXF's STS configurable and pluggable components can be found here.
This STS implementation class, SimpleSTS, is a POJO that extends from SecurityTokenServiceProvider. Note that the class is defined with a WebServiceProvider annotation and not a WebService annotation. This annotation defines the service as a Provider-based endpoint, meaning it supports a more messaging-oriented approach to Web services. In particular, it signals that the exchanged messages will be XML documents of some type. SecurityTokenServiceProvider is an implementation of the javax.xml.ws.Provider interface. In comparison the WebService annotation defines a (service endpoint interface) SEI-based endpoint which supports message exchange via SOAP envelopes.
As was done in the ServiceImpl class, the WSS4J annotations EndpointProperties and EndpointProperty are providing endpoint configuration for the CXF runtime. This was previous described here.
The InInterceptors annotation is used to specify a JBossWS integration interceptor to be used for authenticating incoming requests; JAAS integration is used here for authentication, the username/passoword coming from the UsernameToken in the ws-requester message are used for authenticating the requester against a security domain on the application server hosting the STS deployment.
In this implementation we are customizing the operations of token issuance, token validation and their static properties.
StaticSTSProperties is used to set select properties for configuring resources in the STS. You may think this is a duplication of the settings made with the WSS4J annotations. The values are the same but the underlaying structures being set are different, thus this information must be declared in both places.
The setIssuer setting is important because it uniquely identifies the issuing STS. The issuer string is embedded in issued tokens and, when validating tokens, the STS checks the issuer string value. Consequently, it is important to use the issuer string in a consistent way, so that the STS can recognize the tokens that it has issued.
The setEndpoints call allows the declaration of a set of allowed token recipients by address. The addresses are specified as reg-ex patterns.
TokenIssueOperation and TokenValidateOperation have a modular structure. This allows custom behaviors to be injected into the processing of messages. In this case we are overriding the SecurityTokenServiceProvider's default behavior and performing SAML token processing and validation. CXF provides an implementation of a SAMLTokenProvider and SAMLTokenValidator which we are using rather than writing our own.
Learn more about the SAMLTokenProvider here.
package org.jboss.test.ws.jaxws.samples.wsse.policy.trust;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import javax.xml.ws.WebServiceProvider;
import org.apache.cxf.annotations.EndpointProperties;
import org.apache.cxf.annotations.EndpointProperty;
import org.apache.cxf.interceptor.InInterceptors;
import org.apache.cxf.sts.StaticSTSProperties;
import org.apache.cxf.sts.operation.TokenIssueOperation;
import org.apache.cxf.sts.operation.TokenValidateOperation;
import org.apache.cxf.sts.service.ServiceMBean;
import org.apache.cxf.sts.service.StaticService;
import org.apache.cxf.sts.token.provider.SAMLTokenProvider;
import org.apache.cxf.sts.token.validator.SAMLTokenValidator;
import org.apache.cxf.ws.security.sts.provider.SecurityTokenServiceProvider;
@WebServiceProvider(serviceName = "SecurityTokenService",
portName = "UT_Port",
targetNamespace = "http://docs.oasis-open.org/ws-sx/ws-trust/200512/",
wsdlLocation = "WEB-INF/wsdl/ws-trust-1.4-service.wsdl")
@EndpointProperties(value = {
@EndpointProperty(key = "ws-security.signature.username", value = "mystskey"),
@EndpointProperty(key = "ws-security.signature.properties", value = "stsKeystore.properties"),
@EndpointProperty(key = "ws-security.callback-handler", value = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.STSCallbackHandler"),
//to let the JAAS integration deal with validation through the interceptor below
@EndpointProperty(key = "ws-security.validate.token", value = "false")
})
@InInterceptors(interceptors = {"org.jboss.wsf.stack.cxf.security.authentication.SubjectCreatingPolicyInterceptor"})
public class SampleSTS extends SecurityTokenServiceProvider
{
public SampleSTS() throws Exception
{
super();
StaticSTSProperties props = new StaticSTSProperties();
props.setSignaturePropertiesFile("stsKeystore.properties");
props.setSignatureUsername("mystskey");
props.setCallbackHandlerClass(STSCallbackHandler.class.getName());
props.setIssuer("DoubleItSTSIssuer");
List<ServiceMBean> services = new LinkedList<ServiceMBean>();
StaticService service = new StaticService();
service.setEndpoints(Arrays.asList(
"http://localhost:(\\d)*/jaxws-samples-wsse-policy-trust/SecurityService",
"http://\\[::1\\]:(\\d)*/jaxws-samples-wsse-policy-trust/SecurityService",
"http://\\[0:0:0:0:0:0:0:1\\]:(\\d)*/jaxws-samples-wsse-policy-trust/SecurityService"
));
services.add(service);
TokenIssueOperation issueOperation = new TokenIssueOperation();
issueOperation.setServices(services);
issueOperation.getTokenProviders().add(new SAMLTokenProvider());
issueOperation.setStsProperties(props);
TokenValidateOperation validateOperation = new TokenValidateOperation();
validateOperation.getTokenValidators().add(new SAMLTokenValidator());
validateOperation.setStsProperties(props);
this.setIssueOperation(issueOperation);
this.setValidateOperation(validateOperation);
}
}
Crypto properties and keystore files
WSS4J's Crypto implementation is loaded and configured via a Java properties file that contains Crypto configuration data. The file contains implementation-specific properties such as a keystore location, password, default alias and the like. This application is using the Merlin implementation. File stsKeystore.properties contains this information.
File servicestore.jks, is a Java KeyStore (JKS) repository. It contains self signed certificates for myservicekey and mystskey. Self signed certificates are not appropriate for production use.
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=stsspass
org.apache.ws.security.crypto.merlin.keystore.file=stsstore.jks
MANIFEST.MF
When deployed on WildFly, this application requires access to the JBossWs and CXF APIs provided in modules org.jboss.ws.cxf.jbossws-cxf-client and org.apache.cxf. The Apache CXF internals, org.apache.cxf.impl, are needed to build the STS configuration in the SampleSTS constructor. The dependency statement directs the server to provide them at deployment.
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.2
Created-By: 1.7.0_25-b15 (Oracle Corporation)
Dependencies: org.jboss.ws.cxf.jbossws-cxf-client,org.apache.cxf.impl
Security Domain
The STS requires a JBoss security domain be configured. The jboss-web.xml descriptor declares a named security domain,"JBossWS-trust-sts" to be used by this service for authentication. This security domain requires two properties files and the addition of a security-domain declaration in the JBoss server configuration file.
For this scenario the domain needs to contain user alice, password clarinet, and role friend. See the listings below for jbossws-users.properties and jbossws-roles.properties. In addition the following XML must be added to the JBoss security subsystem in the server configuration file. Replace "SOME_PATH" with appropriate information.
<security-domain name="JBossWS-trust-sts">
<authentication>
<login-module code="UsersRoles" flag="required">
<module-option name="usersProperties" value="/SOME_PATH/jbossws-users.properties"/>
<module-option name="unauthenticatedIdentity" value="anonymous"/>
<module-option name="rolesProperties" value="/SOME_PATH/jbossws-roles.properties"/>
</login-module>
</authentication>
</security-domain>
jboss-web.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jboss-web PUBLIC "-//JBoss//DTD Web Application 2.4//EN" ">
<jboss-web>
<security-domain>java:/jaas/JBossWS-trust-sts</security-domain>
</jboss-web>
jbossws-users.properties
# A sample users.properties file for use with the UsersRolesLoginModule
alice=clarinet
jbossws-roles.properties
# A sample roles.properties file for use with the UsersRolesLoginModule
alice=friend
WS-MetadataExchange and interoperability
To achieve better interoperability, you might consider allowing the STS endpoint to reply to WS-MetadataExchange messages directed to the /mex URL sub-path (e.g. http://localhost:8080/jaxws-samples-wsse-policy-trust-sts/SecurityTokenService/mex). This can be done by tweaking the url-pattern for the underlying endpoint servlet, for instance by adding a web.xml descriptor as follows to the deployment:<?xml version="1.0" encoding="UTF-8"?>
<web-app
version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
<servlet-name>TestSecurityTokenService</servlet-name>
<servlet-class>org.jboss.test.ws.jaxws.samples.wsse.policy.trust.SampleSTS</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>TestSecurityTokenService</servlet-name>
<url-pattern>/SecurityTokenService/*</url-pattern>
</servlet-mapping>
</web-app>
As a matter of fact, at the time of writing some webservices implementations (including Metro) assume the /mex URL as the default choice for directing WS-MetadataExchange requests to and use that to retrieve STS wsdl contracts.