I am trying to deploy a SAML secured service in JBoss Fuse. I have consulted this link - http://cxf.apache.org/docs/jax-rs-saml.html#JAX-RSSAML-SAMLAssertionValidation.
I would like to use the Authorization header option and so have configured the server and the client as below. I am always getting the exception as "Assertion can not be validated".
Server log -->
Address: http://....
Http-Method: GET
Content-Type: /
Headers: {Accept=[/], Authorization=[SAML --encoded-string--], Cache-Control=[no-cache], connection=[keep-alive], content-type=[/], Host=[localhost:8181], Pragma=[no-cache], User-Agent=[Apache CXF 3.0.4.redhat-620123]}
2015-10-19 16:52:14,536 | WARN | p1930854886-1149 | AbstractSamlInHandler | 849 - org.apache.cxf.cxf-rt-rs-security-xml - 3.0.4.redhat-620123 | Assertion must be signed
2015-10-19 16:52:14,536 | WARN | p1930854886-1149 | AbstractSamlInHandler | 849 - org.apache.cxf.cxf-rt-rs-security-xml - 3.0.4.redhat-620123 | Assertion can not be validated
2015-10-19 16:52:14,536 | WARN | p1930854886-1149 | WebApplicationExceptionMapper | 128 - org.apache.cxf.cxf-rt-frontend-jaxrs - 3.0.4.redhat-620123 | javax.ws.rs.NotAuthorizedException: HTTP 401 Unauthorized
at org.apache.cxf.jaxrs.utils.SpecExceptions.toNotAuthorizedException(SpecExceptions.java:94)
at org.apache.cxf.jaxrs.utils.ExceptionUtils.toNotAuthorizedException(ExceptionUtils.java:134)
at org.apache.cxf.rs.security.saml.AbstractSamlInHandler.throwFault(AbstractSamlInHandler.java:243)
at org.apache.cxf.rs.security.saml.AbstractSamlInHandler.validateToken(AbstractSamlInHandler.java:181)
at org.apache.cxf.rs.security.saml.AbstractSamlInHandler.validateToken(AbstractSamlInHandler.java:115)
at org.apache.cxf.rs.security.saml.AbstractSamlInHandler.validateToken(AbstractSamlInHandler.java:98)
at org.apache.cxf.rs.security.saml.AbstractSamlBase64InHandler.handleToken(AbstractSamlBase64InHandler.java:53)
at org.apache.cxf.rs.security.saml.SamlHeaderInHandler.filter(SamlHeaderInHandler.java:52)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.runContainerRequestFilters(JAXRSUtils.java:1647)
at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.processRequest(JAXRSInInterceptor.java:106)
at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.handleMessage(JAXRSInInterceptor.java:77)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:307)
at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)
at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:251)
at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:234)
at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:208)
at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:160)
at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:171)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:293)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doGet(AbstractHTTPServlet.java:217)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:575)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:268)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:684)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:503)
at org.ops4j.pax.web.service.jetty.internal.HttpServiceServletHandler.doHandle(HttpServiceServletHandler.java:69)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:533)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:231)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1086)
at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext.doHandle(HttpServiceContext.java:240)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:429)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1020)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135)
at org.ops4j.pax.web.service.jetty.internal.JettyServerHandlerCollection.handle(JettyServerHandlerCollection.java:75)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116)
at org.eclipse.jetty.server.Server.handle(Server.java:370)
at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:494)
at org.eclipse.jetty.server.AbstractHttpConnection.headerComplete(AbstractHttpConnection.java:971)
at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.headerComplete(AbstractHttpConnection.java:1033)
at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:644)
at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:235)
at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:82)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:696)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:53)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543)
at java.lang.Thread.run(Thread.java:745)
Server -->
<jaxrs:server id="service111" address="/saml/test">
<jaxrs:serviceBeans>
<ref component-id="serviceBean"/>
</jaxrs:serviceBeans>
<jaxrs:features>
<bean class="org.apache.cxf.jaxrs.swagger.SwaggerFeature"/>
</jaxrs:features>
<jaxrs:providers>
<ref component-id="jaxbProvider" />
<ref component-id="jsonProvider" />
<!-- SAML -->
<ref component-id="samlHandler"/>
</jaxrs:providers>
<!-- SAML -->
<jaxrs:properties>
<entry key="ws-security.signature.properties" value="alice.properties"/>
</jaxrs:properties>
</jaxrs:server>
<!-- SAML -->
<!-- Authorization Header -->
<bean id="samlHandler" class="org.apache.cxf.rs.security.saml.SamlHeaderInHandler"/>
Client code -->
public class JavaTestAPI {
/*
* SAML
*/
private WebClient createWebClient(String address) {
JAXRSClientFactoryBean bean = new JAXRSClientFactoryBean();
bean.setAddress(address);
Map<String, Object> properties = new HashMap<String, Object>();
/*properties.put("ws-security.callback-handler", "org.apache.cxf.systest.jaxrs.security.saml.KeystorePasswordCallback");
properties.put("ws-security.saml-callback-handler", "org.apache.cxf.systest.jaxrs.security.saml.SamlCallbackHandler");
*/
properties.put("ws-security.callback-handler", "org.rest.test.saml.KeystorePasswordCallback");
properties.put("ws-security.saml-callback-handler", "org.rest.test.saml.SamlCallbackHandler");
properties.put("ws-security.signature.username", "alice");
properties.put("ws-security.signature.properties", "alice.properties");
properties.put("ws-security.self-sign-saml-assertion", "true");
bean.setProperties(properties);
bean.getOutInterceptors().add(new SamlHeaderOutInterceptor());
return bean.createWebClient();
}
public static void main(String[] args) {
JavaTestSolrAPI test = new JavaTestAPI();
String address = "http://localhost:8181/cxf/saml/test/1.0.0?codes=usa,ger&format=json";
System.out.println("before createWebClient..");
WebClient wc = test.createWebClient(address);
System.out.println("wc=" + wc);
Response resp = wc.get();
System.out.println("after response=" + resp.getStatus());
System.out.println("response=" + resp.readEntity(String.class));
}
}
I'm not sure if it's the root of your problem, but it appears that the assertion statement you're getting back isn't signed, when it should be.
Related
I am trying to call Web Service that is based on IIS WPF and its WSDL has following policy:
<wsp:Policy wsu:Id="custom_policy">
<wsp:ExactlyOne>
<wsp:All>
<sp:TransportBinding xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<wsp:Policy>
<sp:TransportToken>
<wsp:Policy>
<sp:HttpsToken RequireClientCertificate="false"/>
</wsp:Policy>
</sp:TransportToken>
<sp:AlgorithmSuite>
<wsp:Policy>
<sp:Basic256/>
</wsp:Policy>
</sp:AlgorithmSuite>
<sp:Layout>
<wsp:Policy>
<sp:Strict/>
</wsp:Policy>
</sp:Layout>
<sp:IncludeTimestamp/>
</wsp:Policy>
</sp:TransportBinding>
<sp:SignedSupportingTokens xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<wsp:Policy>
<sp:UsernameToken sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient">
<wsp:Policy>
<sp:WssUsernameToken10/>
</wsp:Policy>
</sp:UsernameToken>
</wsp:Policy>
</sp:SignedSupportingTokens>
<sp:Wss11 xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<wsp:Policy/>
</sp:Wss11>
<sp:Trust10 xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<wsp:Policy>
<sp:MustSupportIssuedTokens/>
<sp:RequireClientEntropy/>
<sp:RequireServerEntropy/>
</wsp:Policy>
</sp:Trust10>
<wsaw:UsingAddressing/>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
with Apache CXF client and following code:
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(ITerytWs1.class);
factory.setAddress("https://uslugaterytws1test.stat.gov.pl/terytws1.svc");
ITerytWs1 info = (ITerytWs1) factory.create();
Map ctx = ((BindingProvider)info).getRequestContext();
ctx.put("ws-security.username", "TestPubliczny");
ctx.put("ws-security.password", "1234abcd");
ctx.put("ws-security.callback-handler", ClientPasswordCallback.class.getName());
var zal = info.isLoggedIn();
Dependencies are:
compile group: 'org.apache.cxf', name: 'cxf-rt-frontend-jaxws', version: '3.3.7'
compile group: 'org.apache.cxf', name: 'cxf-rt-transports-http', version: '3.3.7'
compile group: 'com.sun.activation', name: 'javax.activation', version: '1.2.0'
compile group: 'org.apache.cxf', name: 'cxf-rt-ws-security', version: '3.3.7'
compile group: 'com.sun.xml.messaging.saaj', name: 'saaj-impl', version: '1.5.2'
I receive only Read time out:
lip 16, 2020 1:58:31 PM org.apache.cxf.phase.PhaseInterceptorChain doDefaultLogging
WARNING: Interceptor for {http://tempuri.org/}ITerytWs1Service#{http://tempuri.org/}CiekawostkiSIMC has thrown exception, unwinding now
org.apache.cxf.interceptor.Fault: Could not receive Message.
at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:65)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)
at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:530)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:441)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:356)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:314)
at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:96)
[...]
Caused by: java.net.SocketTimeoutException: SocketTimeoutException invoking https://uslugaterytws1test.stat.gov.pl/terytws1.svc: Read timed out
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
[..]
Caused by: java.net.SocketTimeoutException: Read timed out
at java.base/java.net.SocketInputStream.socketRead0(Native Method)
[...]
Could not receive Message.
javax.xml.ws.WebServiceException: Could not receive Message.
at org.apache.cxf.jaxws.JaxWsClientProxy.mapException(JaxWsClientProxy.java:183)
[...]
Caused by: java.net.SocketTimeoutException: SocketTimeoutException invoking https://uslugaterytws1test.stat.gov.pl/terytws1.svc: Read timed out
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
[...]
How to configure this WS policy right and is it the problem of client or something else?
I had to use SoapUI to check what kind of envelope is sent to the service to get the right answer, then I had to do the same with the code. Problem before was that wrong request was sent to the server and server got internal exception (probably) and has not returned answer of bad request.
This is what I have done with the class:
import lombok.Getter;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.ws.addressing.WSAddressingFeature;
import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
import org.apache.wss4j.dom.WSConstants;
import org.apache.wss4j.dom.handler.WSHandlerConstants;
import org.tempuri.ITerytWs1;
import javax.inject.Inject;
import java.util.HashMap;
import java.util.Map;
public class WebServiceClient {
#Getter
private ITerytWs1 service;
private final ApiClientConfiguration apiClientConfiguration;
private final ClientPasswordCallback clientPasswordCallback;
#Inject
public WebServiceClient(ApiClientConfiguration apiClientConfiguration) {
this.apiClientConfiguration = apiClientConfiguration;
this.clientPasswordCallback = new ClientPasswordCallback(apiClientConfiguration);
initializeService();
configureService();
}
private void configureService() {
var client = ClientProxy.getClient(service);
var endpoint = client.getEndpoint();
Map<String, Object> outInterceptorProperties = createOutInterceptorProperties();
var wssOutInterceptor = new WSS4JOutInterceptor(outInterceptorProperties);
endpoint.getOutInterceptors().add(wssOutInterceptor);
}
private void initializeService() {
var factory = new JaxWsProxyFactoryBean();
var wsAddressingFeature = new WSAddressingFeature();
factory.getFeatures().add(wsAddressingFeature);
factory.setServiceClass(ITerytWs1.class);
factory.setAddress(apiClientConfiguration.getAddress());
service = (ITerytWs1) factory.create();
}
private Map<String, Object> createOutInterceptorProperties() {
Map<String,Object> outInterceptorProperties = new HashMap<>();
outInterceptorProperties.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
outInterceptorProperties.put(WSHandlerConstants.USER, apiClientConfiguration.getUsername());
outInterceptorProperties.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
outInterceptorProperties.put(WSHandlerConstants.ADD_USERNAMETOKEN_NONCE, "true");
outInterceptorProperties.put(WSHandlerConstants.ADD_USERNAMETOKEN_CREATED, "true");
outInterceptorProperties.put(WSHandlerConstants.MUST_UNDERSTAND, "false");
// Callback used to retrieve password for given user.
outInterceptorProperties.put(WSHandlerConstants.PW_CALLBACK_REF, clientPasswordCallback);
return outInterceptorProperties;
}
}
I'm building an app with an AngularJS front end and Spring backend. I have everything setup for CSRF on both the front end and the backend and it was working fine until a change I made.
When I log into my app everything goes fine, I login at an endpoint I made at /rest/user. It's when I logout that the 403 error is thrown. I have Spring Security printing to a log file in debug mode and I see that it fails when it tries to validate the CSRF token. I'll go ahead and explain what I did that cause this to happen.
I'm serving the AngularJS app as static content from the Spring dispatcher servlet and I don't want Spring Security to secure that static content. I figure it's just more load on the server. So I've set the Spring Security Filter Chain entry point to be where my rest services are mapped to instead of the root of the app.
Here's the sections of my web.xml showing this:
<servlet>
<servlet-name>gravytrack</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>gravytrack</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>gravytrack</servlet-name>
<url-pattern>*.*</url-pattern>
</servlet-mapping>
<!-- Security entry point -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/rest/*</url-pattern>
</filter-mapping>
Because of this change, I've had to map my logout url to /rest/logout instead of the normal /logout that spring security maps it to by default. Here's my security configuration showing this:
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<global-method-security pre-post-annotations="enabled"
secured-annotations="enabled"/>
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/rest/**" requires-channel="https"/>
<access-denied-handler error-page="/"/>
<http-basic entry-point-ref="gtBasicAuthenticationEntryPoint"/>
<!-- CRSF FILTER CONFIG -->
<custom-filter ref="csrfHeaderFilter" after="CSRF_FILTER"/>
<csrf token-repository-ref="csrfTokenRepository" />
<!-- LOGOUT CONFIG -->
<logout logout-url="/rest/logout" invalidate-session="true" delete-cookies="JSESSIONID"/>
<!--<session-management invalid-session-url="/">-->
<!--<concurrency-control max-sessions="10" error-if-maximum-exceeded="true" />-->
<!--</session-management>-->
</http>
<!--<beans:bean id="gtBasicAuthenticationEntryPoint" class="com.gbsolutions.gravytrack.security.GtBasicAuthenticationEntryPoint">-->
<!--<beans:property name="realmName" value="gravytrack" />-->
<!--</beans:bean>-->
<beans:bean id="csrfTokenRepository" class="org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository">
<beans:property name="headerName" value="X-XSRF-TOKEN" />
</beans:bean>
<!--<beans:bean class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" id="passwordEncoder" />-->
<authentication-manager alias="authenticationManager">
<authentication-provider>
<!--<password-encoder ref="passwordEncoder"/>-->
<!--<jdbc-user-service data-source-ref="dataSource"-->
<!--users-by-username-query="SELECT email as username, password, enabled FROM user_account-->
<!--WHERE email = ?" />-->
<user-service>
<user name="admin#admin.com" password="admin" authorities="ROLE_USER"/>
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
I have a custom filter that you can see on this line of the security config:
<custom-filter ref="csrfHeaderFilter" after="CSRF_FILTER"/>
This is where I modify the returned cookie to take a CSRF token customized for Angular. Here's the csrfHeaderFilter class:
#Service("csrfHeaderFilter")
public class CsrfHeaderFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrf.getToken();
if (cookie==null || token!=null && !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
filterChain.doFilter(request, response);
}
}
I believe the problem has something to do with this line:
cookie.setPath("/");
I've had a similar problem to this before and I fixed it by changing the path to the path of my app. But right now the path of my app is the root of tomcat because of how I have setup tomcat. So instead of https://localhost:8443/gravytrack it's just https://localhost:8443/.
I've also tried changing the path to /rest (the entry point of my Spring Security) and this didn't help. What could be causing this 403 error?
I need to set the use-x-forwarded-headers Http header in camel-cxf like the below and make it as an OSGi bundle to be deployed in Karaf.
<servlet>
<servlet-name>cxf</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<init-param>
<param-name>use-x-forwarded-headers</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
I don't want to package this as a WAR, instead i want to make it an OSGi bundle.
Hence, i created a class which extends CXFNonSpringServlet as the code below and set the init-params,
public class XForwadedServlet extends CXFNonSpringServlet {
#Override
protected void loadBus(ServletConfig sc) {
sc.getServletContext().setInitParameter("use-x-forwarded-headers",
"true");
super.loadBus(sc);
Bus bus = getBus();
BusFactory.setDefaultBus(bus);
// createFactoryBean();
}
#Override
public void init(ServletConfig sc) throws ServletException {
sc.getServletContext().setInitParameter("use-x-forwarded-headers",
"true");
super.init(sc);
}
And here's my camel route,
<cxf:cxfEndpoint id="serviceEndpoint"
address="http://localhost:8123/cxf/testCxfRedirect"
loggingFeatureEnabled="true" serviceClass="com.redhat.HelloServiceImpl">
</cxf:cxfEndpoint>
<camelContext trace="false" xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="cxf:bean:serviceEndpoint"/>
<log message="${body}" loggingLevel="INFO"/>
<bean ref="clientAddress" method="getClientAddress"/>
</route>
</camelContext>
<bean id="destinationRegistry" class="org.apache.cxf.transport.http.DestinationRegistryImpl">
</bean>
<bean id="osgiServlet" class="com.redhat.XForwadedServlet">
<constructor-arg ref="destinationRegistry"></constructor-arg>
<constructor-arg value="true"></constructor-arg>
</bean>
Through soapui, i set the X-Forwarded-For header as below,
Address: http://localhost:8123/cxf/testCxfRedirect
Encoding: UTF-8
Http-Method: POST
Content-Type: text/xml
Headers: {Accept=[*/*], SOAPAction=[""], X-Forwarded-For=[http://google.com]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns1:sayHello xmlns:ns1="http://redhat.com/"><arg0 xmlns="http://redhat.com/">Test</arg0></ns1:sayHello></soap:Body></soap:Envelope>
--------------------------------------
How can i register the CXFNonSpringServlet in OSGi Blueprint container with setting that init-params ?
Is there a way to do this in OSGi ?
This can be achieved by using the pax-web-extender support in Fuse, Camel.
However the packaging will need to be WAR.
Here's the reference from Karaf:
https://ops4j1.jira.com/wiki/display/ops4j/Pax+Web+Extender+-+War+-+Examples
Here's a reference implementation from the Camel Committers:
https://github.com/apache/camel/tree/master/examples/camel-example-reportincident
Hope it helps.
I Already tried many of the aswers about this topic, no one works for me.
I Have a basic CRUD with Spring MVC 4.1.7, Spring Security 3.2.3 working on MySQL + Tomcat7.
The problem is, when i try to POST form with AngularJS, I keep being blocked by error 403 ( access denied ).
I figured out that I need to send my CSRF_TOKEN with the POST request, but I can't figure out HOW!
I Tried so many diferent ways and no one works.
My Files
Controller.js
$scope.novo = function novo() {
if($scope.id){
alert("Update - " + $scope.id);
}
else{
var Obj = {
descricao : 'Test',
saldo_inicial : 0.00,
saldo : 33.45,
aberto : false,
usuario_id : null,
ativo : true
};
$http.post(urlBase + 'caixas/adicionar', Obj).success(function(data) {
$scope.caixas = data;
}).error(function(data) {alert(data)});
}
};
Spring-security.xml
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="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
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<!-- enable use-expressions -->
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/seguro**"
access="hasAnyRole('ROLE_USER','ROLE_ADMIN')" />
<intercept-url pattern="/seguro/financeiro**"
access="hasAnyRole('ROLE_FINANCEIRO','ROLE_ADMIN')" />
<!-- access denied page -->
<access-denied-handler error-page="/negado" />
<form-login login-page="/home/" default-target-url="/seguro/"
authentication-failure-url="/home?error" username-parameter="inputEmail"
password-parameter="inputPassword" />
<logout logout-success-url="/home?logout" />
<!-- enable csrf protection -->
<csrf />
</http>
<!-- Select users and user_roles from database -->
<authentication-manager>
<authentication-provider>
<password-encoder hash="md5" />
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="SELECT login, senha, ativo
FROM usuarios
WHERE login = ?"
authorities-by-username-query="SELECT u.login, r.role
FROM usuarios_roles r, usuarios u
WHERE u.id = r.usuario_id
AND u.login = ?" />
</authentication-provider>
</authentication-manager>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name>Barattie ~ Soluções Integradas</display-name>
<!-- The definition of the Root Spring Container shared by all Servlets
and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/spring-security.xml
/WEB-INF/spring/spring-database.xml
/WEB-INF/spring/spring-hibernate.xml
</param-value>
</context-param>
<context-param>
<param-name>com.sun.faces.writeStateAtFormEnd</param-name>
<param-value>false</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/home</url-pattern>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- Spring Security -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/erro</location>
</error-page>
UPDATE
I tried to add to rename at client side the xsrf, but I keep getting access denied.
var app = angular.module('myApp', []).config(function($httpProvider) {
$httpProvider.defaults.xsrfCookieName = '_csrf';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRF-Token';
});
** UPDATE 2 **
I tried to implement a filter like this.
package sys.barattie.util;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.web.csrf.CsrfToken;
import org.springframework.web.filter.OncePerRequestFilter;
public class CsrfFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
if (csrf != null) {
Cookie cookie = new Cookie("XSRF-TOKEN", csrf.getToken());
cookie.setPath("/");
response.addCookie(cookie);
}
filterChain.doFilter(request, response);
}
}
And changed my spring security to it.
<csrf token-repository-ref="csrfTokenRepository" />
<beans:bean id="csrfTokenRepository" class="org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository">
<beans:property name="headerName" value="X-XSRF-TOKEN" />
</beans:bean>
Web.xml
<filter>
<filter-name>csrfFilter</filter-name>
<filter-class>sys.barattie.util.CsrfFilter</filter-class>
</filter>
But it is like that the server doesn't run the filter, I've added a System.out.println to it, but can't see the messages in the debug
I did some tests and end up with this.
In my login controller, if my user authentication is successful, I create a token with the name of the AngularJS Token, just like this.
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
if (csrf != null) {
Cookie cookie = new Cookie("XSRF-TOKEN", csrf.getToken());
cookie.setPath("/");
response.addCookie(cookie);
}
After that, I can manage my $http.post successfully.
I don't know if this is the best way, but is the way that worked for me!
Thanks for the help #Joao Evangelista
The main problem is the integration, Angular always look for a cookie name XSRF-TOKEN and Spring sends a CSRF_TOKEN, you need to provide a filter to change this. Something like this:
private static Filter csrfHeaderFilter() {
return new OncePerRequestFilter() {
#Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName())
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN")
String token = csrf.getToken()
if (cookie == null || token != null && !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token)
cookie.setPath("/")
response.addCookie(cookie)
}
}
filterChain.doFilter(request, response)
}
}
}
static CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository()
repository.setHeaderName("X-XSRF-TOKEN")
return repository
}
NOTICE The only example I have is this, is written in Groovy, but is just missing some ;
Then you need to add the filter and the repository to <csrf/> properties, you can explicity set a class implementing a Filter as <bean>, using #Component or declaring this methods as #Bean on a configuration class
Otherwise you can change the $http configuration on Angular, according to docs setting this settings to match Spring token cookie name and header name
xsrfHeaderName – {string} – Name of HTTP header to populate with the XSRF token.
xsrfCookieName – {string} – Name of cookie containing the XSRF token.
More info about this you can check the docs on Usage section
i was facing this problem also, and this is the solution that is working for me (from the Spring documentation), notice that im not using $http. Instead im using $resource.
'
You can ask Spring to save a cookie with Angular's defaults:
<csrf token-repository-ref="tokenRepository"/>
...
</http>
<b:bean id="tokenRepository"
class="org.springframework.security.web.csrf.CookieCsrfTokenRepository"
p:cookieHttpOnly="false"/>
Please notice that if you use $http, there is a field in the config object called xsrfCookieName, where you can set explicitly the name of the cookie. But this option i havent tried it, so i dont know how useful it is.
Best Regards.
This should work:
Class that extends WebSecurityConfigurerAdapter:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
..
And then in your AngularJS you can use any module for csrf, etc.: spring-security-csrf-token-interceptor
I could not get along with the Camel CXF component. The problem is, th WS operation that I want to call has only a String parameter which is a JSON expression.
But , with every dataFormat (MESSAGE,POJO,PAYLOAD), it gives exception.
There are classes which are generated from wsdl2java by cxf itself and I am using them to call ws.
<cxf:cxfEndpoint id="wsEndpoint" address="http://www.wssss.com" serviceClass="aa.bb.cc.WebService" serviceName="sendMessage">
<cxf:properties>
<entry key="dataFormat" value="CXF_MESSAGE"/>
<entry key="defaultOperationName" value="sendMessage"/>
<entry key="relayHeaders" value="false"/>
<entry key="wrapped" value="true"/>
<entry key="loggingFeatureEnabled" value="true"/>
<entry key="synchronous" value="true"/>
<entry key="defaultOperationNamespace" value="http://com.asdad.ns"/>
</cxf:properties>
</cxf:cxfEndpoint>
and I am using this in:
camel:to uri="cxf:bean:wsEndpoint"/>
And generated service class is:
#WebResult(name = "response", targetNamespace = "")
#RequestWrapper(localName = "sendMessage", targetNamespace = "http://com.xxx.comet.ws.notification", className = "aaa.bbb.ccc.SendMessage")
#WebMethod
#ResponseWrapper(localName = "sendMessageResponse", targetNamespace = "http://com.xxx.comet.ws.notification", className = "aaa.bbb.ccc.SendMessageResponse")
public java.lang.String sendMessage(
#WebParam(name = "request", targetNamespace = "")
java.lang.String request
);
Any help will be appreciated
Thanks
EDIT: The problem is, exchange.in body could not be bound with the service method's parameter so request is empty. There is the problem in here
INFO: Outbound Message
---------------------------
ID: 1
Address: http://www.wssss.com
Encoding: UTF-8
Http-Method: POST
Content-Type: text/xml
Headers: {Accept=[*/*], breadcrumbId=[ID-TT08328507-61662-1416561287466-0-1], SOAPAction=[""]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"/><soap:Body/></soap:Envelope>
--------------------------------------
Nov 21, 2014 4:45:04 AM org.apache.cxf.services.sendMessage.MessagePort.Message
INFO: Inbound Message
----------------------------
ID: 1
Response-Code: 500
Encoding: UTF-8
Content-Type: text/xml;charset=UTF-8
Headers: {connection=[close], Content-Length=[271], content-type=[text/xml;charset=UTF-8], Date=[Fri, 21 Nov 2014 09:15:04 GMT], Server=[Apache-Coyote/1.1]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><soap:Fault><faultcode>soap:Server</faultcode><faultstring>No binding operation info while invoking unknown method with params unknown.</faultstring></soap:Fault></soap:Body></soap:Envelope>
--------------------------------------
org.apache.cxf.binding.soap.SoapFault: No binding operation info while invoking unknown method with params unknown.
at org.apache.cxf.binding.soap.interceptor.Soap11FaultInInterceptor.unmarshalFault(Soap11FaultInInterceptor.java:84)
at org.apache.cxf.binding.soap.interceptor.Soap11FaultInInterceptor.handleMessage(Soap11FaultInInterceptor.java:51)
at org.apache.cxf.binding.soap.interceptor.Soap11FaultInInterceptor.handleMessage(Soap11FaultInInterceptor.java:40)
The outbind message is an empty SOAP envelop.
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"/><soap:Body/></soap:Envelope>
Did setup the invocation parameter rightly?