Wiki Markup |
---|
{span:style=font-size:2em;font-weight:bold} JAX-RS: Security {span} |
Table of Contents |
---|
HTTPS
Transport-level protection of JAX-RS endpoints can be managed by underlying Servlet containers, for example, see this Tomcat SSL Configuration section.
...
JAX-RS endpoints using embedded Jetty can rely on the configuration like this one:
Code Block | ||||
---|---|---|---|---|
| ||||
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:http="http://cxf.apache.org/transports/http/configuration"
xmlns:httpj="http://cxf.apache.org/transports/http-jetty/configuration"
xmlns:sec="http://cxf.apache.org/configuration/security"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
http://cxf.apache.org/transports/http-jetty/configuration http://cxf.apache.org/schemas/configuration/http-jetty.xsd
http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd">
<httpj:engine-factory id="port-9095-tls-config">
<httpj:engine port="9095">
<httpj:tlsServerParameters>
<sec:keyManagers keyPassword="password">
<sec:keyStore type="JKS" password="password"
file="src/test/java/org/apache/cxf/systest/http/resources/Bethal.jks"/>
</sec:keyManagers>
<sec:trustManagers>
<sec:keyStore type="JKS" password="password"
file="src/test/java/org/apache/cxf/systest/http/resources/Truststore.jks"/>
</sec:trustManagers>
</httpj:tlsServerParameters>
</httpj:engine>
</httpj:engine-factory>
</beans>
|
If you use JAXRSServerFactoryBean to create and start JAX-RS endpoints from the code then the above configuration can be utilized like this:
Code Block | ||||
---|---|---|---|---|
| ||||
JAXRSServerFactoryBean bean = new JAXRSServerFactoryBean();
SpringBusFactory bf = new SpringBusFactory();
Bus bus = bf.createBus("configuration/beans.xml");
bean.setBus(bus);
bean.setAddress("http://localhost:9095/rest");
bean.setServiceClass(CustomerService.class);
|
If you also have a jaxrs:server endpoint declared in the above beans.xml, then make sure you have a 'depends-on' attribute set:
Code Block | ||||
---|---|---|---|---|
| ||||
<jaxrs:server serviceClass="CustomerService.class" address="http://localhost:9095/rest"
depends-on="port-9095-tls-config"/>
|
Once you have JAX-RS and Jetty HTTPS combined then you can get the application context initiated like this:
Code Block | ||||
---|---|---|---|---|
| ||||
public class Server {
public void main(String[] args) throws Exception {
Bus busLocal = new SpringBusFactory().createBus("configuration/beans.xml");
BusFactory.setDefaultBus(busLocal);
new Server();
Thread.sleep(60000);
}
}
|
...
The configuration file can be referenced during the proxy or WebClient creation:
Code Block | ||||
---|---|---|---|---|
| ||||
final String address = "http://localhost:9095/rest";
final String configLocation;
WebClient client = WebClient.create(address, configLocation);
// or
BookStore proxy = JAXRSClientFactory.create(address, configLocation, BookStore.class);
|
...
It is often containers like Tomcat or frameworks like Spring Security which handle the user authentication. Sometimes you might want to do the custom authentication instead. CXF HTTP Transport adds decoded Basic Authentication credentials into an instance of AuthorizationPolicy extension and sets it on the current message. Thus the easiest way is to register a custom invoker or RequestHandler
filter which will extract a user name and password like this:
Code Block | ||||
---|---|---|---|---|
| ||||
public class AuthenticationHandler implements RequestHandler {
public Response handleRequest(Message m, ClassResourceInfo resourceClass) {
AuthorizationPolicy policy = (AuthorizationPolicy)m.get(AuthorizationPolicy.class);
String username = policy.getUserName();
String password = policy.getPassword();
if (isAuthenticated(username, password)) {
// let request to continue
return null;
} else {
// authentication failed, request the authetication, add the realm name if needed to the value of WWW-Authenticate
return Response.status(401).header("WWW-Authenticate", "Basic").build();
}
}
}
|
...
For example, see how a JAX-RS filter can be used to wrap CXF JAASLoginInterceptor:
Code Block | ||||
---|---|---|---|---|
| ||||
<jaxrs:server address="/jaas">
<jaxrs:serviceBeans>
<bean class="org.apache.cxf.systest.jaxrs.security.SecureBookStoreNoAnnotations"/>
</jaxrs:serviceBeans>
<jaxrs:providers>
<ref bean="authenticationFilter"/>
</jaxrs:providers>
</jaxrs:server>
<bean id="authenticationFilter" class="org.apache.cxf.jaxrs.security.JAASAuthenticationFilter">
<!-- Name of the JAAS Context -->
<property name="contextName" value="BookLogin"/>
<!-- Hint to the filter on how to have Principals representing users and roles separated
while initializing a SecurityContext -->
<property name="rolePrefix" value="ROLE_"/>
<property name="redirectURI" value="/login.jsp"/>
</bean>
|
...
CXF also provides two interceptors which make it easy to enforce authorization decisions, as described in the Security section.
CXF JAX-RS SimpleAuthorizingFilter can be used to wrap those interceptors and return 403 in case of failures:
Code Block | ||||
---|---|---|---|---|
| ||||
<jaxrs:server address="/jaas">
<jaxrs:serviceBeans>
<bean class="org.apache.cxf.systest.jaxrs.security.SecureBookStoreNoAnnotations"/>
</jaxrs:serviceBeans>
<jaxrs:providers>
<ref bean="authorizationFilter"/>
</jaxrs:providers>
</jaxrs:server>
<bean id="authorizationFilter" class="org.apache.cxf.jaxrs.security.SimpleAuthorizingFilter">
<property name="methodRolesMap" ref="rolesMap"/>
</bean>
<util:map id="rolesMap">
<entry key="getThatBook" value="ROLE_BOOK_OWNER"/>
<entry key="getBook" value="ROLE_BOOK_OWNER"/>
</util:map>
|
...
Validating Basic Authentication credentials with STS is possible starting from CXF 2.4.1. JAX-RS and JAX-WS services can rely on this feature. Here is an example on how a jaxrs endpoint can be configured:
Code Block | ||||
---|---|---|---|---|
| ||||
<jaxrs:server serviceClass="org.customers.CustomerService"
depends-on="ClientAuthHttpsSettings"
address="https://localhost:8081/rest">
<jaxrs:inInterceptors>
<ref bean="basicAuthValidator"/>
</jaxrs:inInterceptors>
<jaxrs:properties>
<entry key="ws-security.sts.client">
<ref bean="stsclient"/>
</entry>
</jaxrs:properties>
</jaxrs:server>
<bean id="basicAuthValidator" class="org.apache.cxf.ws.security.trust.AuthPolicyValidatingInterceptor">
<property name="validator">
<bean class="org.apache.cxf.ws.security.trust.STSTokenValidator">
<constructor-arg value="true"/>
</bean>
</property>
</bean>
<bean id="stsclient" class="org.apache.cxf.ws.security.trust.STSClient">
<constructor-arg ref="cxf"/>
<property name="wsdlLocation" value="https://localhost:8083/sts?wsdl"/>
<property name="serviceName" value="{http://tempuri.org/}STSService"/>
<property name="endpointName" value="{http://tempuri.org/STSServicePort"/>
</bean>
<!-- jaxrs:server depends on this SSL configuration -->
<httpj:engine-factory id="ClientAuthHttpsSettings" bus="cxf">
<httpj:engine port="8081">
<httpj:tlsServerParameters>
<sec:keyManagers keyPassword="skpass">
<sec:keyStore type="jks" password="sspass" resource="servicestore.jks"/>
</sec:keyManagers>
<sec:cipherSuitesFilter>
<sec:include>.*_EXPORT_.*</sec:include>
<sec:include>.*_EXPORT1024_.*</sec:include>
<sec:include>.*_WITH_DES_.*</sec:include>
<sec:include>.*_WITH_NULL_.*</sec:include>
<sec:exclude>.*_DH_anon_.*</sec:exclude>
</sec:cipherSuitesFilter>
<sec:clientAuthentication want="false" required="false"/>
</httpj:tlsServerParameters>
</httpj:engine>
<!-- STSClient depends on this SSL configuration -->
<http:conduit name="https://localhost:8083/.*">
<http:tlsClientParameters disableCNCheck="true">
<sec:trustManagers>
<sec:keyStore type="jks" password="sspass" resource="servicestore.jks"/>
</sec:trustManagers>
<sec:keyManagers keyPassword="skpass">
<sec:keyStore type="jks" password="sspass" resource="servicestore.jks"/>
</sec:keyManagers>
</http:tlsClientParameters>
</http:conduit>
|
...
Please see this section for more information on how STSSamlAssertionValidator STSTokenValidator can be used to validate the inbound SAML assertions.
...
If java.lang.SecurityManager
is installed then you'll likely need to configure the trusted JAX-RS codebase with a 'suppressAccessChecks' permission for the injection of JAXRS context or parameter fields to succeed. For example, you may want to update a Tomcat catalina.policy with the following permission :
Code Block |
---|
grant codeBase "file:${catalina.home}/webapps/yourwebapp/lib/cxf.jar" {
permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
};
|
...