Apache CXF interceptor configuration - java

I created a SOAP interceptor as described in CXF docs:
public class SoapMessageInterceptor extends AbstractSoapInterceptor {
public SoapMessageInterceptor() {
super(Phase.USER_PROTOCOL);
}
public void handleMessage(SoapMessage soapMessage) throws Fault {
// ...
}
}
and registered it with the bus in Spring's application context:
<cxf:bus>
<cxf:inInterceptors>
<ref bean="soapMessageInterceptor"/>
</cxf:inInterceptors>
</cxf:bus>
<jaxws:endpoint id="customerWebServiceSoap"
implementor="#customerWebServiceSoapEndpoint"
address="/customerService"/>
All was working fine until I added a REST service:
<jaxrs:server id="customerWebServiceRest" address="/rest">
<jaxrs:serviceBeans>
<ref bean="customerWebServiceRestEndpoint" />
</jaxrs:serviceBeans>
</jaxrs:server>
The problems is that the SOAP interceptor is now being triggered on REST requests also, which results in a class cast exception when the REST service is invoked.
<ns1:XMLFault xmlns:ns1="http://cxf.apache.org/bindings/xformat">
<ns1:faultstring xmlns:ns1="http://cxf.apache.org/bindings/xformat">
java.lang.ClassCastException: org.apache.cxf.message.XMLMessage
cannot be cast to org.apache.cxf.binding.soap.SoapMessage
</ns1:faultstring>
</ns1:XMLFault>
Is there any way to restrict the interceptor to SOAP messages only through configuration?
Update
Looks like I missed the page in the docs that describes this.
Scroll down to Difference between JAXRS filters and CXF interceptors

You can attach interceptors to an individual endpoint rather than to the bus:
<jaxws:endpoint id="customerWebServiceSoap"
implementor="#customerWebServiceSoapEndpoint"
address="/customerService">
<jaxws:inInterceptors>
<ref bean="soapMessageInterceptor"/>
</jaxws:inInterceptors>
</jaxws:endpoint>

You can try to configure your interceptor like this:
<cxf:bus name="someBus">
<cxf:inInterceptors>
<ref bean="soapMessageInterceptor"/>
</cxf:inInterceptors>
</cxf:bus>
By defining the name of the bus, which according to documentation, identifies a bus as a unique Spring bean. Then in your JAX-WS endpoint configuration you need to specify the bus referencing to that name:
<jaxws:endpoint id="customerWebServiceSoap"
implementor="#customerWebServiceSoapEndpoint"
address="/customerService"
bus="someBus"/>
And this bus should work only on this JAX-WS endpoint.

Related

Camel CXF - Security (Authentication)

I created a webservice with apache camel using CXF component as bellow :
blueprint.xml:
<bean class="ngtrend.ws.Testws"/>
<!-- Defined the server endpoint to create the cxf-rs consumer -->
<cxf:rsServer id="rsServer" address="http://localhost:9050/route"
serviceClass="ngtrend.ws.Testws" />
<camelContext xmlns="http://camel.apache.org/schema/blueprint">
<route id="timerToLog">
<from uri="cxfrs://bean://rsServer"/>
<to uri="bean:ngtrend.ws.HelloBean?method=test(Exchange)"/>
<log message="${body}"/>
</route>
</camelContext>
Testws.java:
public class Testws {
#GET
#Path("/test/{id}")
#Produces("application/xml")
//#Consumes("text/xml")
public Integer getAssets(#PathParam("id") int id){
return null;
}
}
and I would like to secure it forcing the customer to send ( or enter on a dialog box if using a browser) login and password (BASIC Http authentication). How can i make this configuration ?
In CXF framework, restful services authentication can be done by using the following approach:
<cxf:rsServer id="rsServer"
address="http://localhost:9050/route">
<jaxrs:serviceBeans>
<ref bean="serviceBean"/>
</jaxrs:serviceBeans>
<jaxrs:providers>
<ref bean="authenticationHandler"/>
</jaxrs:providers>
</cxf:server>
<bean id="serviceBean" class="ngtrend.ws.Testws"/>
<bean id="authenticationHandler" class="yourpackage.Class" />
Create your own handler for authenticationHandler that will implement import org.apache.cxf.jaxrs.ext.RequestHandler.
Use the authentication strategy needed in this class , for example authenticate against database etc.. This should allow for basic authentication.
You can write a class which implements ContainerRequestFilter. And then set it in the cxf:providers as below:
<bean id="authenticationHandler" class="a class which implements ContainerRequestFilter" />
<cxf:rsServer id="xxxRsServer"
address="/xxxservice" serviceClass="xxx.XXXService"
loggingFeatureEnabled="true" loggingSizeLimit="20">
<cxf:providers>
<ref component-id="authenticationHandler"/>
</cxf:providers>
</cxf:rsServer>
In this way, you could override below method
public void filter(ContainerRequestContext requestContext)
For example, you could make a simple authentication based on requestContext.getHeaderString("UserPassInfo"). If succeed, do nothing, otherwise call requestContext.abortWith(Response.status(401).header("WWW-Authenticate", "Basic").build());

CXF RS: How do I tell the application to use my custom ExceptionMapper?

I found this documentation that documents how to use an ExceptionMapper. But it doesn't provide any information on how to tell the webapp that it should use it. How do I configure that?
You can do this in your Spring configuration file like this:
<jaxrs:server id="foo" address="/v2">
<jaxrs:providers>
<bean class="com.MyExceptionMapper"/>
</jaxrs:providers>
</jaxrs:server>

Restlet Framework and Spring - Global filter

I'm having a problem with RESTlet Framework configuration with Spring. I want to have one global filter for all requests and responses. I guess I can use Filter class and it's methods beforeHandle, afterHandle and setNext like this:
Filter.beforeHandle() -> Router -> Filter.afterHandle()
The problem is, that I'm using Spring configured RESTlet and I don't know if the regular Filter will work correctly with SpringRouter from org.restlet.ext.spring package. My current restlet configuration is as follows:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="root" class="org.restlet.ext.spring.SpringRouter">
<property name="attachments">
<map>
<entry key="/login">
<bean class="org.restlet.ext.spring.SpringFinder">
<lookup-method name="create"
bean="loginResource" />
</bean>
</entry>
</map>
</property>
</bean>
</beans>
I'm thinking about adding a bean with id root and class that extends class Filter, and pass to it as property next a bean with id router (which currently is called root). What do you think about this solution?
Mixing Restlet classes from the Spring extension with other one shouldn't be an issue. Spring* classes only provide additional configurability.

Publish JMX notifications in using Spring without NotificationPublisherAware

I'd like to publish JMX notifications using Spring 3, but would like to avoid using the NotificationPublisherAware interface, since the code is also used by an application that doesn't use Spring. The bean is exposed using MBeanExporter bean. The alternatives I found require registering the mbeans, which I currently do using Spring configuration, so this is a bad option.
Is there a way to avoid using the NotificationPublisherAware interface but still publish notifications?
You don't have to use any Spring class in code. Example:
Interface:
import javax.management.MXBean;
#MXBean
public interface SecurityEventsManagerMXBean {
...
#AttributeMetaData(value="UserLoginFailures", defaultValue="0", description="Total user login failures")
public int getUserLoginFailureCount() ;
...
}
Bean:
import javax.management.Notification;
import javax.management.NotificationBroadcasterSupport;
public class SecurityEventsManager extends NotificationBroadcasterSupport implements SecurityEventsManagerMXBean {
...
private void notifyUserLoginFailure(...) {
Notification notification = new Notification(...) ;
sendNotification(notification)
userLoginFailureCount++ ;
}
}
Here #AttributeMetaData is a convenient meta annotation that defines descriptor keys:
import javax.management.DescriptorKey;
#Documented
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface AttributeMetaData {
#DescriptorKey("displayName")
String value();
....
}
Edit March 08. Configuration to export above Mbean:
<bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean"
p:locateExistingServerIfPossible="true" />
<bean id="jmxAttributeSource" class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource"/>
<bean id="namingStrategy" class="org.springframework.jmx.export.naming.MetadataNamingStrategy"
p:attributeSource-ref="jmxAttributeSource" />
<bean id="assembler" class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler"
p:attributeSource-ref="jmxAttributeSource" />
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
<property name="server" ref="mbeanServer"/>
<property name="assembler" ref="assembler"/>
<property name="registrationBehaviorName" value="REGISTRATION_FAIL_ON_EXISTING"/>
<property name="beans">
<map>
<entry>
<key>
<util:constant
static-field="x.y.z.SecurityEventsManager.OBJECT_NAME" />
</key>
<ref bean="securityEventsManager" />
</entry>
</map>
</property>
</bean>
<bean id="securityEventsManager" class="x.y.z.SecurityEventsManager" />
As per Spring docs:
The NotificationPublisher interface and the machinery to get it all working is one of the nicer features of Spring's JMX support. It does however come with the price tag of coupling your classes to both Spring and JMX; as always, the advice here is to be pragmatic... if you need the functionality offered by the NotificationPublisher and you can accept the coupling to both Spring and JMX, then do so.
Ref: http://static.springsource.org/spring/docs/3.0.0.M3/reference/html/ch24s07.html#jmx-notifications-listeners

Spring MVC - Form Mapping

Probably missing something completely obvious here, but here goes. I'm starting out with Spring MVC. I have a form controller to process inbound requests to /share/edit.html. When I hit this url from my browser, I get the following error:
The requested resource (/inbox/share/share/edit) is not available.
Here is my applicationContext-mvc.xml:
<bean id="publicUrlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping" >
<property name="mappings" >
<value>
/share/edit.html=shareFormController
/share/list.html=shareController
/share/view.html=shareController
/folders.json=foldersController
/studies.json=studiesController
</value>
</property>
</bean>
<bean id="internalPathMethodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.InternalPathMethodNameResolver" />
<bean id="shareFormController" class="com.lifeimage.lila.controller.ShareFormController" />
<bean id="shareController" class="com.lifeimage.lila.controller.ShareController" >
<property name="methodNameResolver" ref="internalPathMethodNameResolver" />
</bean>
and my form Controller:
public class ShareFormController extends SimpleFormController {
public ShareFormController() {
setCommandClass( Share.class );
}
#Override
protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors)
throws Exception {
//controller impl...
}
}
You should look at your view resolver. Make sure that it is resolving the logical name in your controller as you think it should. Looks like the name it is resolving it to does not exist currently
I think I've resolved this issue. There were two problems:
1) Implementations of SimpleFormController require a form and success view; which I had not configured here. As this is a server method for an AJAX client, I added a Spring-JSON view as follows:
<?xml version="1.0" encoding="UTF-8"?>
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"
default-lazy-init="false" default-autowire="no"
default-dependency-check="none">
<bean name="jsonView" class="org.springframework.web.servlet.view.json.JsonView">
<property name="jsonErrors">
<list>
<ref bean="statusError" />
<ref bean="modelflagError" />
</list>
</property>
</bean>
<bean name="statusError"
class="org.springframework.web.servlet.view.json.error.HttpStatusError">
<property name="errorCode"><value>311</value></property>
</bean>
<bean name="modelflagError"
class="org.springframework.web.servlet.view.json.error.ModelFlagError">
<property name="name"><value>failure</value></property>
<property name="value"><value>true</value></property>
</bean>
which can be used for all controllers that return JSON.
2) I switched from a SimpleURLHandlerMapping to ControllerClassNameHandlerMapping and relied on Spring naming conventions ( controllerClassName/method.html ), which fixed the routing issue. Might not be a long term solution, but got me through the task.
Did you check your log output? Spring MVC is generally pretty verbose in what it outputs.
Also, the URL you've posted (/inbox/share/share/edit) does not seem to match what you are configuring (/share/edit.html).
#jordan002 when I see all the hoops you had to jump to accomplish your task, I feel obliged to share a very powerful Java MVC framework that requires much less configuration. The framework is called Induction, check out the article Induction vs. Spring MVC, http://www.inductionframework.org/induction-vs-spring-mvc.html

Categories

Resources