ClientSide
<cxf:jaxws-client
serviceClass="org.example.MyService"
port="MyServicePort"
operation="MyOperation">
<cxf:inInterceptors>
<spring:bean class="org.example.MyInInterceptor"/>
</cxf:inInterceptors>
</cxf:jaxws-client>
How to get the SOAPBody from the SOAP response in the Interceptor below?
public class MyInInterceptor extends AbstractSoapInterceptor {
#Resource
private WebServiceContext context;
public MyInInterceptor() {
super(Phase.RECEIVE);
}
#Override
public void handleMessage(SoapMessage cxfSoapMessage) throws Fault {
SOAPMessage soapMessage = cxfSoapMessage.getContent(SOAPMessage.class);
System.out.println("soapMessage ===> " + soapMessage);
}
}
Related
I am trying to retrieve the JWT token that comes to our service and pass it to downstream services using filter and interceptor as below but the bean passed between them , of sessionscope is coming up as null in the interceptor. How do I fix this? Any thoughts?
BaseConfiguration.java
#Configuration
public class BaseConfiguration {
#Bean
FilterRegistrationBean<RequestHeaderFilter> requestFilter(RequestHeaderFilter requestFilter){
var registration = new FilterRegistrationBean<RequestHeaderFilter>();
registration.setFilter("requestFilter");
registration.addUrlPatterns("/*");
registration.setName("requestFilter");
registration.setOrder(1);
return registration;
}
#Bean
#RequestScope
JwtTokenData jwtTokenData(){
return new JWTTokenData();
}
#Bean
RestTemplate restTemplate(){
var restTemplate = new RestTemplate();
restTemplate.getInterceptors().add(new RestTemplateInterceptor());
return restTemplate;
}
}
JwtTokenData.java
public class JwtTokenData {
private String token;
public String getToken(){
return token;
}
public void setToken(String token){
this.token = token;
}
}
RequestHeaderFilter.java to intercept all incoming calls and populate the JWT token -
#Component
public class RequestHeaderFilter implements Filter {
#Autowired
private JWTTokenData jwtTokenData;
#override
poublic void dofilter (ServletRequest request, ServletResponse response. FilterChain chain) throws IOException, ServletException {
var httpRequest = (HttpServletRequest) request;
String token = httpServletRequest.getHeader("X-authJWT");
if(StringUtils.isempty(token)){
throw new IllegalArgumentException("Can't retrieve JWT Token");
}
jwtTokenData.setToken(token);
chain.doFilter(request,response);
}
}
RestTemplateInterceptor.java to send the jwtToken to downstream services -
public class RestTemplateInterceptor implements ClientHttpRequestInterceptor {
#Autowired
private JwtTokenData jwtTokenData;
#override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
String token = jwtTokenData.getToken();
request.getHeaders().add("X-AuthJwt");
return execution.execute(request,body);
}
}
I am working with Spring 4 REST API annotation based configuration application. I want to add response header on each/every request once user is authenticate by JWT. I have created interceptor for that which looks as below:
public class AuthenticateInterceptor implements HandlerInterceptor {
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object object, Exception arg3)
throws Exception {
response.addHeader("afterCompletion", "afterCompletion header");
response.setHeader("afterCompletion", "afterCompletion header");
System.out.println("************** afterCompletion **************");
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object object,
ModelAndView modelAndView) throws Exception {
response.addHeader("postHandle", "postHandle header");
System.out.println("************** postHandle **************");
}
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
System.out.println("************** preHandle **************");
return true;
}
}
My interceptor configuration is as below:
#Configuration
public class AdapterConfig extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuthenticateInterceptor());
}
}
When I get JSON response I am not able the see the added header value which are added from interceptor. Any one help me what is the issue and how can I add header from interceptor for each/every request.
I didn't succeed in interceptors, Instead using Filters or WebFilter perfectly works:
#Component
public class ResponseHeaderWebFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setHeader("CustomHeaderName", "SomeValue");
chain.doFilter(request, response);
}
}
In case you are using webflux reactive component, then :
#Component
public class ResponseHeaderWebFilter implements WebFilter {
#Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
exchange.getResponse()
.getHeaders()
.add("CustomHeaderName", "SomeValue");
return chain.filter(exchange);
}
}
If it can help you, I've managed it like this: https://stackoverflow.com/a/49431665/4939245
Look at second point
You can put the response header for each call in the application (this is for Spring annotation-based):
#Component
public class Filter extends OncePerRequestFilter {
....
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
//response.addHeader("Access-Control-Allow-Origin", "*");
//response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.setHeader("Cache-Control", "no-store"); // HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setHeader("Expires", "0"); // Proxies.
filterChain.doFilter(request, response);
}
}
I hope I was helpful!
You are almost doing same but would like to give you consitant way of achieving same. Please do following changes.
1) Add #Component annotation on AuthenticateInterceptor class. And you package containing this class should be in packages scanned list.
#Component
public class AuthenticateInterceptor implements HandlerInterceptor {
...
}
2) Autowire and inject instance of AuthenticateInterceptor like below.
#Configuration
public class AdapterConfig extends WebMvcConfigurerAdapter {
#Autowired
private AuthenticateInterceptor authenticateInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authenticateInterceptor);
}
}
I have Spring Boot application, everything works fine until I implement spring security in front of my application. This is a RESTful api that has a token based authentication. What's even more weird it works (!) intermittently - by intermittently I mean restarting the application will return the right responses such as 401/403 if unauthenticated and other codes if user is authorized to access them. This is being deployed into WebLogic.
2017-01-05 14:12:51.164 WARN 11252 --- [ (self-tuning)'] o.s.web.servlet.PageNotFound : No mapping found for HTTP request with URI [/user] in DispatcherServlet with name 'dispatcherServlet'
WebApplication.java
#SpringBootApplication(exclude = { SecurityAutoConfiguration.class })
public class WebApplication extends SpringBootServletInitializer implements WebApplicationInitializer {
public static void main(String[] args) {
Object[] sources = new Object[2];
sources[0] = WebConfiguration.class;
sources[1] = WebSecurityConfiguration.class;
SpringApplication.run(sources, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(WebApplication.class);
}
}
WebConfiguration.java
#Configuration
#ComponentScan(basePackages = { "com.controller", "com.service", "com.dao"})
#EnableAutoConfiguration(exclude = {
DataSourceAutoConfiguration.class })
public class WebConfiguration extends WebMvcConfigurerAdapter {
private static final Logger logger = LoggerFactory.getLogger(WebConfiguration.class);
/**
* Setup a simple strategy: use all the defaults and return XML by default
* when not sure.
*/
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.defaultContentType(MediaType.APPLICATION_JSON).mediaType("json", MediaType.APPLICATION_JSON)
.mediaType("xml", MediaType.APPLICATION_XML);
}
#Bean(name = "entityManagerFactory")
public EntityManagerFactory getQmsEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setPersistenceUnitName(Config.PERSISTENCE_UNIT_NAME);
em.setPersistenceXmlLocation("META-INF/persistence.xml");
em.setDataSource(getDataSource());
em.setJpaVendorAdapter(getJpaHibernateVendorAdapter());
em.afterPropertiesSet();
return em.getObject();
}
#Bean
public HibernateJpaVendorAdapter getJpaHibernateVendorAdapter() {
HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setShowSql(true);
// adapter.setDatabase("ORACLE");
adapter.setDatabasePlatform("org.hibernate.dialect.Oracle10gDialect");
return adapter;
}
#Bean(name="dataSource", destroyMethod = "")
//http://stackoverflow.com/questions/19158837/weblogic-datasource-disappears-from-jndi-tree
#Qualifier("dataSource")
#Profile("weblogic")
public DataSource dataSource() {
DataSource dataSource = null;
JndiTemplate jndi = new JndiTemplate();
try {
dataSource = (DataSource) jndi.lookup("jdbc/datasource");
} catch (NamingException e) {
logger.error("NamingException for jdbc/datasource", e);
}
return dataSource;
}
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*").allowedMethods("*");
}
};
}
}
WebSecurityConfiguration.java
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
#ComponentScan({
"com.subject",
"com.custom"
})
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private StatelessAuthenticationFilter statelessAuthenticationFilter;
#Autowired
private RestAuthenticationEntryPoint unauthorizedHandler;
#Autowired
private CusAuthenticationProvider cusAuthenticationProvider;
#Override
protected void configure(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(cusAuthenticationProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.securityContext()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests().anyRequest().authenticated()
.and()
.addFilterBefore(statelessAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler);
}
}
StatelessAuthenticationFilter.java
#Component
public class StatelessAuthenticationFilter extends OncePerRequestFilter {
#Inject
private SubjectLookupService subjectLookupService;
#Override
public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
SecurityContextHolder.getContext().setAuthentication(authenticateUser(request));
filterChain.doFilter(request, response);
}
private Authentication authenticateUser(HttpServletRequest request) {
try {
String application = StringUtils.defaultString(request.getParameter("application"));
UserInfo me = subjectLookupService.getUserInfo();
List<GrantedAuthority> roles = me.getRoles().stream()
.map(role -> new SimpleGrantedAuthority("ROLE_" + role.getName())).collect(Collectors.toList());
UserDetails user = new User(me.getUsername(), "", roles);
Authentication authentication = new UserAuthentication(user);
return authentication;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
Controller.java
#RestController
public class Controller {
#Autowired
private QService qService;
#PreAuthorize("hasAnyRole('view', 'admin')")
#RequestMapping(value = "/q/{year}", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET)
public ResponseEntity<?> listQuotas(#PathVariable Integer year) {
return new ResponseEntity<>(qService.listQs(year), HttpStatus.OK);
}
#RequestMapping(value = "/user", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET)
public ResponseEntity<?> user(HttpServletRequest request) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
return new ResponseEntity<>( auth.getPrincipal(), HttpStatus.OK);
}
#PreAuthorize("hasRole('shouldntauthorize')")
#RequestMapping(value = "/unauthorized/{year}", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET)
public ResponseEntity<?> unauthorized(#PathVariable Integer year) {
return new ResponseEntity<>(qService.listQs(year), HttpStatus.OK);
}
}
When it works - I am able to hit any of the above methods using HTTP gets and I am getting correct responses. When it's not working, I am constantly getting:
2017-01-05 14:18:47.506 WARN 11252 --- [ (self-tuning)'] o.s.web.servlet.PageNotFound : No mapping found for HTTP request with URI [/user] in DispatcherServlet with name 'dispatcherServlet'
I can verify in the logs that when Spring Boot initializes the application is also sets the correct mapping URL.
Any ideas what could be the problem here?
when you say "intermittently" I tend to think that the problem is with Spring startup configuration.
So, I'd be weary on the fact that you have #ComponentScan twice, and with different packages.
Could you try removing
#ComponentScan(basePackages = { "com.controller", "com.service", "com.dao"})
from class WebConfiguration.java and
#ComponentScan({ "com.subject", "com.custom" })
from class WebSecurityConfiguration.java, and replace them with a single
#ComponentScan(basePackages = { "com.controller", "com.service", "com.dao", "com.subject", "com.custom"})
in the main SpringBoot class?
I would like to chain a base64 encoder and gzip in jax-rs via interceptors.
The encoder is implemented as follows:
#EncryptPayload
#Provider
#Priority(Priorities.ENTITY_CODER)
public class EncryptPayloadInterceptor implements WriterInterceptor {
private Logger logger;
#Inject
public EncryptPayloadInterceptor(Logger logger) {
this.logger = logger;
}
public EncryptPayloadInterceptor() {
super();
}
#Override
public void aroundWriteTo(WriterInterceptorContext writerInterceptorContext) throws IOException, WebApplicationException {
logger.error("Calling EncryptPayload Interceptor: ");
final OutputStream outputStream = writerInterceptorContext.getOutputStream();
writerInterceptorContext.getHeaders().putSingle("X-ENCRYPTED", "true");
writerInterceptorContext.setOutputStream(new Base64OutputStream((outputStream)));
writerInterceptorContext.proceed();
}
}
The gzip part is implemented as follows:
#Provider
#Priority(Priorities.USER)
public class GZIPWriterInterceptor implements WriterInterceptor {
private Logger logger;
#Inject
public GZIPWriterInterceptor(Logger logger) {
this.logger = logger;
}
public GZIPWriterInterceptor() {
super();
}
#Override
public void aroundWriteTo(WriterInterceptorContext writerInterceptorContext) throws IOException, WebApplicationException {
logger.error("Calling GZIPWriter Interceptor: ");
final OutputStream outputStream = writerInterceptorContext.getOutputStream();
writerInterceptorContext.setOutputStream(new GZIPOutputStream(outputStream));
writerInterceptorContext.getHeaders().putSingle("Content-Encoding", "gzip");
writerInterceptorContext.proceed();
}
}
When disabling gzip as a provider it works nicely. When enabling the provider GZIP I receive the following error within jersey:
LOGGER.log(Level.SEVERE, LocalizationMessages.ERROR_COMMITTING_OUTPUT_STREAM(), e);
First the encoding is called and after that the gzip is called. It seems that Base64 might close the stream.
Any help highly appreciated.
My app is calling an external Soap WS using spring-ws's WebServiceTemplate, which I mock in my tests using MockWebServiceServer.
It works fine to simulate the response depending on the request payload.
But now I'd like to test which SOAP action is called. It should be defined in the "SOAPAction" HTTP header of the request.
I'm using Spring-WS 2.1.4.
Does anyone know if it's possible to test that and how?
Here is my test class :
public class MyWebServiceTest {
#Autowired
private WebServiceTemplate webServiceTemplate;
private MockWebServiceServer mockServer;
#Before
public void createServer() throws Exception {
mockServer = MockWebServiceServer.createServer(webServiceTemplate);
}
#Test
public void callStambiaWithExistingFileShouldSuccess() throws IOException {
Resource requestPayload = new ClassPathResource("request-payload.xml");
Resource responseSoapEnvelope = new ClassPathResource("success-response-soap-envoloppe.xml");
mockServer.expect(payload(requestPayload)).andRespond(withSoapEnvelope(responseSoapEnvelope));
//init job
//myService call the webservice via WebServiceTemplate
myService.executeJob(job);
mockServer.verify();
//some asserts
}
}
So what I want to test is the soap action called. So I want something like this in my test class :
mockServer.expect(....withSoapAction("calledSoapAction")).andRespond(...
Creating your own RequestMatcher is pretty straightforward:
public class SoapActionMatcher implements RequestMatcher {
private final String expectedSoapAction;
public SoapActionMatcher(String expectedSoapAction) {
this.expectedSoapAction = SoapUtils.escapeAction(expectedSoapAction);
}
#Override
public void match(URI uri, WebServiceMessage request)
throws IOException, AssertionError {
assertThat(request, instanceOf(SoapMessage.class));
SoapMessage soapMessage = (SoapMessage) request;
assertThat(soapMessage.getSoapAction(), equalTo(expectedSoapAction));
}
}
Usage
mockServer.expect(connectionTo("http://server/"))
.andExpect(new SoapActionMatcher("calledSoapAction"))
.andRespond(withPayload(...)));