You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 6 Next »

Unknown macro: {span}

JAX-RS: Security

HTTPS

Transport-level protection of JAX-RS endpoints can be managed by underlying Servlet containers, for example, see this Tomcat SSL Configuration section.

Additionally CXF provides support for configuring endpoints which depend on embedded Jetty. CXF JAX-RS clients can also be configured to support SSL.

Configuring endpoints

JAX-RS endpoints using embedded Jetty can rely on the configuration like this one:

<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:

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:

<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:

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);
    }
}

Having JAX-RS endpoints declared alongside CXF Jetty HTTPS configuration is only needed when an embedded Jetty container is used. If you have application WARs deployed into Tomcat or Jetty then please follow container-specific guides on how to set up SSL.

Please also see this HTTPS-based demo in the CXF distribution.

Additionally check the CXF Jetty Configuration section.

Configuring clients

Secure HTTPConduits for CXF JAX-RS proxies and WebClients can be configured as described in this section.

For example, check this configuration file. Endpoint addresses used by proxies or clients have to match the pattern used in the HTTPConduit configuration.

The configuration file can be referenced during the proxy or WebClient creation:

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);

HTTPConduits can also be 'bound' to proxies or WebClients using expanded QNames. Please see this section for more information.

Authentication

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:

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 
            return Response.status(401).build();   
        }
    }

}

One other thing you may want to do, after authenticating a user, is to initialize org.apache.cxf.security.SecurityContext with Principals representing the user and its roles (if available).

If you prefer using Spring Security then see how the authentication is handled in a spring-security demo.

Next, please see the [Security] section on how CXF Security interceptors can help.

Additionally check this blog entry for more information on how CXF JAX-RS wraps the CXF security interceptors with helper filters.

For example, see how a JAX-RS filter can be used to wrap CXF JAASLoginInterceptor:

<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.JAASAutheenticationFilter">
        <!-- 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>

The filter will redirect the client to "/login.jsp" if the authentication fails. If no 'redirectURI' property is set then 401 will be returned. A "realmName" property can also be set.

If the JAAS Authentication succeeds then the filter will set a SecurityContext instance on the message. This context can be used for authorization decisions.

Authorization

It is often containers like Tomcat or frameworks like Spring Security which handle user authorization, similarly to the way the authentication is handled.

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:

<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>

SimpleAuthorizingFilter can also wrap CXF SecureAnnotationsInterceptor.

Note that wrapping CXF security interceptors with JAX-RS filters is not required; it simply makes it easier to handle authentication and authorization exceptions and return appropriate HTTP error statuses.

WS-Trust integration

One of the requirements for deploying CXF endpoints into secure web service environments is to ensure that existing WS-Trust STS services can be used to protect the endpoints. JAX-WS endpoints can rely on CXF WS-Security and WS-Trust support. Making sure CXF JAX-RS endpoints can be additionally secured by STS is strategically important task. CXF provides close integration between JAX-WS and JAX-RS frontends thus reusing CXF JAX-WS and WS-Security is the most effective way toward achieving this integration.

At the moment what can be done is to have Basic Authentication credentials validated with STS. The next step is to provide a more advanced integration with STS, stay tuned.

Validating BasicAuth credentials with STS

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:

<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:8081/sts?wsdl"/>
       <property name="serviceName" value="{http://tempuri.org/}STSService"/>
       <property name="endpointName" value="{http://tempuri.org/STSServicePort"/>
   </bean> 

AuthPolicyValidatingInterceptor converts Basic Auth info into WSS4J UsernameToken and delegates to STS to validate.

Note about SecurityManager

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 :

grant codeBase "file:${catalina.home}/webapps/yourwebapp/lib/cxf.jar" {
    permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
};
  • No labels