Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.


Span

 

 

 

{span:style=
Wiki Markup
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.

...

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 or @PreMatching ContainerRequestFilter filter which will extract a user name and password like this:

Code Block
java
java
public class AuthenticationHandler implements RequestHandlerContainerRequestFilter {

    @Override
    public Responsevoid handleRequestfilter(MessageContainerRequestContext m,requestContext) ClassResourceInfothrows resourceClass)IOException {
        AuthorizationPolicyString policyauthorization = (AuthorizationPolicy)m.get(AuthorizationPolicy.classrequestContext.getHeaderString("Authorization");
        String[] usernameparts = policyauthValues.getUserNameauthorization(" ");
        String password = policy.getPassword(); if (parts.length != 2 || !"Basic".equals(parts[0])) {
        if (isAuthenticated(username, password)) {
  requestContext.abortWith(createFaultResponse());
           // letreturn;
 request to continue
     }
       return null;
        String }decodedValue else= {null;
        try   {
 // authentication failed, request the authetication, add the realm name if neededdecodedValue to= the value of WWW-Authenticate new String(Base64Utility.decode(parts[1]));
        } catch (Base64Exception ex) {
            return ResponserequestContext.status(401).header("WWW-Authenticate", "Basic").build(abortWith(createFaultResponse());
            }return;
       }

}

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:

Code Block
xmlxml
<jaxrs:server address="/jaas">
    <jaxrs:serviceBeans>
        <bean class="org.apache.cxf.systest.jaxrs.security.SecureBookStoreNoAnnotations"/>
    </jaxrs:serviceBeans>		   
    <jaxrs:providers>
 }
        String[] namePassword = decodedValue.split(":"); 
        if (isAuthenticated(namePassword[0], namePassword[1])) {
            // let request to continue
        } else {
            <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 // authentication failed, request the authetication, add the realm name if needed to the value of WWW-Authenticate 
            requestContext.abortWith(Response.status(401).header("WWW-Authenticate", "Basic").build());
        }
    }
    private Response createFaultResponse() {
         while initializing a SecurityContext -->
    <property name="rolePrefix" value="ROLE_"/>return Response.status(401).header("WWW-Authenticate", "Basic realm=\"service.com\"").build();
        
    <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.

}
 }

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 Securing CXF Services 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 JAASLoginInterceptorCXF 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
xml
xml
<jaxrs:server address="/jaas">
    <jaxrs:serviceBeans>
        <bean class="org.apache.cxf.systest.jaxrs.security.SecureBookStoreNoAnnotations"/>
    </jaxrs:serviceBeans>		   
    <jaxrs:providers>
        <ref bean="authorizationFilterauthenticationFilter"/>
    </jaxrs:providers>
</jaxrs:server>
  
<bean id="authorizationFilterauthenticationFilter" class="org.apache.cxf.jaxrs.security.SimpleAuthorizingFilterJAASAuthenticationFilter">
    <property name="methodRolesMap" ref="rolesMap"/>
</bean>
  
<util:map id="rolesMap"<!-- Name of the JAAS Context -->
    <entry<property keyname="getThatBookcontextName" value="ROLE_BOOK_OWNERBookLogin"/>
    <!-- Hint to <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.

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:

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 Securing CXF Services section.
CXF JAX-RS SimpleAuthorizingFilter can be used to wrap those interceptors and return 403 in case of failures:

Code Block
xml
xml
<jaxrs:server address="/jaas">
    <jaxrs:serviceBeans>
        <bean class="org.apache.cxf.systest.jaxrs.security.SecureBookStoreNoAnnotations"/>
    </jaxrs:serviceBeans>		   
Code Block
xmlxml
<jaxrs:server serviceClass="org.customers.CustomerService"
    depends-on="ClientAuthHttpsSettings"
    address="https://localhost:8081/rest">

    <jaxrs:inInterceptors>providers>
        <ref bean="basicAuthValidatorauthorizationFilter"/>
    </jaxrs:inInterceptors>
  
    <jaxrs:properties>
         <entry key="ws-security.sts.clientproviders>
</jaxrs:server>
 
<bean id="authorizationFilter" class="org.apache.cxf.jaxrs.security.SimpleAuthorizingFilter">
    <property        <ref bean="stsclientname="methodRolesMap" ref="rolesMap"/>
</bean>
  
<util:map id="rolesMap">
    <entry  </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.

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:

Code Block
xml
xml
<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</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:keyStore type="jks" password="sspass" resource="servicestore.jks"/>
include>.*_EXPORT_.*</sec:include>
        <sec:include>.*_EXPORT1024_.*</sec:keyManagers>include>
        <sec:cipherSuitesFilter>:include>.*_WITH_DES_.*</sec:include>
        <sec:include>.*_WITH_EXPORTNULL_.*</sec:include>
        <sec:include>exclude>.*_DH_EXPORT1024_.*</sec:include>
        <sec:include>.*_WITH_DES_.*</sec:include>
  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:include>.*_WITH_NULL_.*</sec:include>
        <sec:exclude>.*_DH_anon_.*</sec:exclude>
        </sec:cipherSuitesFilter>
keyStore type="jks" password="sspass" resource="servicestore.jks"/>
    </sec:trustManagers>
    <sec:keyManagers keyPassword="skpass">
       <sec:clientAuthentication wantkeyStore type="jks" password="falsesspass" requiredresource="falseservicestore.jks"/>
    </httpj:tlsServerParameters>
</httpj:engine>sec:keyManagers>
  
<!-- 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>

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

Using STS to validate SAML assertions

Please see this section for more information on how STSTokenValidator can be used to validate the inbound SAML assertions.

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 :

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

Advanced Security

...

</http:tlsClientParameters>
</http:conduit>

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

Using STS to validate SAML assertions

Please see this section for more information on how STSTokenValidator can be used to validate the inbound SAML assertions.

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 :

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

Securing JAX-RS messages

CXF provides a number of different ways to secure JAX-RS messages:

  • XML messages can be secured via XML Signature and XML Encryption. See JAX-RS XML Security for more information.
  • Messages can be signed and/or encryption using JOSE. In addition, authentication and authorization can be achieved using JSON Web Tokens. See JAX-RS JOSE for more information.
  • Security claims can be conveyed via SAML assertions. See JAX-RS SAML for more information.
  • Messages can be signed via HTTP Signature. See JAX-RS HTTP Signature for more information.

OAuth 2.0 / OpenId Connect.

CXF supports both OAuth 2.0 and OpenId Connect:

Restricting large payloads

...