Is it the true way to implement spring security & CXF webservice - spring

i create a webservice as below:
web.xml
<display-name>MyService</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/beans.xml,/WEB-INF/spring-security.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
<!-- Spring Security Filter -->
<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>
beans.xml
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
<context:component-scan base-package="com.*" />
<jaxrs:server id="employeeService" address="/employeeservices">
<jaxrs:providers>
<bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
</jaxrs:providers>
<jaxrs:serviceBeans>
<ref bean="empService" />
</jaxrs:serviceBeans>
<jaxrs:extensionMappings>
<entry key="xml" value="application/xml" />
<entry key="json" value="application/json" />
</jaxrs:extensionMappings>
</jaxrs:server>
<bean id="empService" class="com.service.impl.EmployeeServiceImpl"/>
<bean id="employeeDao" class="com.dao.EmployeeDao"/>
spring-security.xml
<http auto-config="true" use-expressions="true" create-session="stateless" >
<csrf disabled="true"/>
<http-basic entry-point-ref="restAuthenticationEntryPoint"></http-basic>
<intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
</http>
<beans:bean id="userAuthorService" class="com.auth.UserAuthorService"/>
<beans:bean id="restAuthenticationEntryPoint" class="com.auth.UserBasicAuthenticationEntryPoint">
<beans:property name="realmName" value="Name Of Your Realm"/>
</beans:bean>
<authentication-manager>
<authentication-provider user-service-ref="userAuthorService">
<password-encoder ref="bcryptPasswordEncoder"/>
</authentication-provider>
</authentication-manager>
<beans:bean id="bcryptPasswordEncoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
<beans:constructor-arg name="strength" value="5" />
</beans:bean>
<beans:bean id="loggerListener" class="org.springframework.security.authentication.event.LoggerListener"/>
By this configuration, is it flow of request process? :
request -> Spring security(check authentication) -> cxf -> response.
Are there any issues in this configuration when I deploy it in the real sever? what is the standard configuration when using cxf and spring ?
when i call right uri:http://localhost:8089/MyService/rest/employeeservices/getemployeedetals?employeeId=004. its ok.
But call wrong uri: http://localhost:8089/MyService/rest/employeeservices/getemployeedetallll?employeeId=004. It throw exception:
WARNING: No operation matching request path "/MyService/rest/employeeservices/getemployeedetallll" is found, Relative Path: /getemployeedetal, HTTP Method: GET, ContentType: /, Accept: /,. Please enable FINE/TRACE log level for more details.
Jun 07, 2016 1:55:17 PM org.apache.cxf.jaxrs.impl.WebApplicationExceptionMapper toResponse
WARNING: javax.ws.rs.ClientErrorException
at org.apache.cxf.jaxrs.utils.SpecExceptions.toHttpException(SpecExceptions.java:110)
at org.apache.cxf.jaxrs.utils.ExceptionUtils.toHttpException(ExceptionUtils.java:149)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.findTargetMethod(JAXRSUtils.java:477)
So how can i filter the right uri before access controller class.
Please help me. Thank you.

By this configuration, is it flow of request process? : request ->
Spring security(check authentication) -> cxf -> response.
Yes, because J2EE filters are executed around J2EE servlets (before and after euqeust), so springSecurityFilterChain will be executed before CXFServlet
Are there any issues in this configuration when I deploy it in the
real sever?
This is not necessary with latests versions of CXF
<import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
Also you are catching in CXFServlet /rest/* but in auth *. Is this an issue? Do you need rest services without authentication? Is difficult to analyze issues if we do not know the context of your system. Detail your doubts and I could try to help
what is the standard configuration when using cxf and spring ?
There is no any recommended configuration, because CXF can be used with spring or standalone, jax-ws or jax-rs, as a server or acting as a client, with authentication executed via spring security or integrated with RequestContextFilter or inInterceptor in jax-rs server or even at global level in CXF bus.
If you are talking about the necessary modules to configure so CXF was executed with spring, you have the needed ones.
For authentication, you could consider use a JWT token instead of a bcrypt passwod.
when i call right
uri:http://localhost:8089/MyService/rest/employeeservices/getemployeedetals?employeeId=004.
its ok. But call wrong uri:
http://localhost:8089/MyService/rest/employeeservices/getemployeedetallll?employeeId=004.
It throw exception:
WARNING: No operation matching request path
This warning is normal. The server is responding with an http error code 404-Not found because there is no resource available at rest/employeeservices/getemployeedetallll
So how can i filter the right uri before access controller class.
CXF is doing for you by returning a 404 if the path is not found. It is the correct behaviour. Do you mean CXF uri filter be executed before spring-security? You can not with this configuration because auth filter is previous.

Related

Spring Session changed the cookie value causing HTTP 302 on succeeding requests

Migrating from servlet container HTTP session to spring session has caused HTTP 302 after successful login. I've got an HTTP 200 on first request after login, but succeeding requests seem redirected to login page again. Cannot debug on succeeding requests as it seems not able to reach through the servlet where I put some breakpoint.
Right now, we are using spring session 1.3.5 version. And have noticed that in spring's SessionRepositoryFilter, it replaced the original request cookies (e.g. servlet container) to the value from spring session. I am not sure if this is the root cause of the issue. If it is, can someone suggest how to resolve it? Or is it related to some sort of missing configuration?
Here's the current setup based on the guide from spring session: here
Spring session XML configuration:
<context:annotation-config/>
<bean class="org.springframework.session.hazelcast.config.annotation.web.http.HazelcastHttpSessionConfiguration"/>
<bean id="hazelcastInstance" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="com.xxx.xxx.xxx.xxx.CustomHazelcastProvider.getInstance"/>
</bean>
<bean class="org.springframework.session.web.http.DefaultCookieSerializer">
<property name="cookieName" value="JSESSIONID"/>
<property name="cookiePath" value="/"/>
<property name="domainNamePattern" value="^.+?\.(\w+\.[a-z]+)$"/>
</bean>
Reference of spring XML configuration in web.xml:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:application-context.xml</param-value>
</context-param>
Registration of spring session repository filter in web.xml. As describe in the guide, I placed it as the first entry of the filter chain.
<filter>
<filter-name>springSessionRepositoryFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSessionRepositoryFilter</filter-name>
<url-pattern>/rs/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
I have been working on it for days now and don't know yet how to fix it. Will appreciate any help or suggestion that you can advise.
Thank you in advance.
I resolved the issue using spring session HeaderHttpSessionStrategy.
Steps I've made:
In my spring session XML configuration, I removed the entry related to cookie serializer to change the cookie name.
<bean class="org.springframework.session.web.http.DefaultCookieSerializer">
<property name="cookieName" value="JSESSIONID"/>
<property name="cookiePath" value="/"/>
<property name="domainNamePattern" value="^.+?\.(\w+\.[a-z]+)$"/>
</bean>
By default, spring session uses CookieHttpSessionStrategy. Added below entry in spring session XML configuration.
<bean id="httpSessionStrategy" class="org.springframework.session.web.http.HeaderHttpSessionStrategy"/>
Then on every request, I am passing x-auth-token in the http request header.
After the said change, the application works as expected. Able to login without an issue.
Hope this solution will help others who have encountered the same issue.

Does Spring Session require the use of Spring Security?

Does spring session internally require the use of spring security?
Right now, we have an existing application which uses HTTP session from servlet container (e.g. WebLogic). Due to some issues on session replication and for future plans to use another servlet container, we decided to look for existing framework that would make the HTTP session container independent.
The team decided to look at Spring Session in combination with Hazelcast as described in official documentation. We use spring session version 1.3.5.RELEASE.
For hazelcast configuration, we use this session configuration.
<context:annotation-config/>
<bean class="org.springframework.session.hazelcast.config.annotation.web.http.HazelcastHttpSessionConfiguration"/>
<bean id="hazelcastInstance" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="xxx.xxx.xxx.cache.CustomHazelcastProvider.getInstance"/>
</bean>
<bean class="org.springframework.session.web.http.SessionEventHttpSessionListenerAdapter">
<constructor-arg>
<list>
<bean class="xxx.xxx.xxx.util.CustomHttpSessionListener"/>
</list>
</constructor-arg>
</bean>
<bean class="org.springframework.session.web.http.DefaultCookieSerializer">
<property name="cookieName" value="JSESSIONID"/>
<property name="cookiePath" value="/"/>
<property name="domainNamePattern" value="^.+?\.(\w+\.[a-z]+)$"/>
</bean>
In web.xml, we put this filter chain.
<filter>
<filter-name>springSessionRepositoryFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSessionRepositoryFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>CustomServletRequestFilter</filter-name>
<filter-class>xxx.xxx.xxx.servlet.filter.CustomServletRequestFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CustomServletRequestFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
And added spring configuration below in web.xml
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:application-context.xml</param-value>
</context-param>
In the same web.xml, we use form-based authentication.
<login-config>
<auth-method>FORM</auth-method>
<realm-name>myrealm</realm-name>
<form-login-config>
<form-login-page>/login.html</form-login-page>
<form-error-page>/loginerror.html</form-error-page>
</form-login-config>
</login-config>
In addition, we are using the default cookie based HTTP strategy.
After deploying the said changes in weblogic, we are able to get a successful login. Able to check the session ID coming from spring session. However, the next hop or succeeding REST calls, it always returns HTTP 302. It gets redirected to login page.
Does spring session require the use of spring security? Is there some configuration that we need to add to resolve this issue?
Will appreciate any help or suggestion to resolve this issue.
Thank you.

Spring basic authentication not working

Trying to set up basic authentication in a web-app using spring. I am patterning what I do off this example: http://howtodoinjava.com/2013/04/16/custom-userdetailsservice-example-for-spring-3-security/. I am using Spring 4.
The behavior is that my HttpRequestHandler runs, never challenging for password. LoginDao never runs.
spring config:
<security:http auto-config="true" use-expressions="true">
<security:intercept-url pattern="/*" access="hasRole('ROLE_USER')" />
<security:http-basic />
</security:http>
<security:authentication-manager>
<security:authentication-provider user-service-ref="loginDao" />
</security:authentication-manager>
<bean id="loginDao" class="weight.dao.LoginDao" />
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="/WEB-INF/wt.properties" />
</bean>
What's missing in this tutorial are the entries you have to add to your web.xml. These will load you security context and add the security filter chain to your whole app (which is the main strut of Spring Security):
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:/your-security-context-file.xml
classpath:/your-other-context-files.xml
...
</param-value>
</context-param>
<filter>
<display-name>Spring Security Filter</display-name>
<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>

Spring Controller method executed twice

I have integrated Spring Security with Spring MVC and seeing strange behaviour. Every method in the Controller is executed twice for the same request. I googled for it quite a bit but didn't help much. The closest I could find is this http://forum.springsource.org/archive/index.php/t-83158.html I tried the suggestions without any success.
Here is my web.xml :
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<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>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/appServlet/security-app-context.xml
/WEB-INF/application-context.xml
</param-value>
</context-param>
Here is relevant part of applicationcontext.xml :
<context:component-scan base-package="com.*" />
<context:spring-configured/>
<mvc:annotation-driven />
<context:property-placeholder location="classpath:/conf/myConfig.properties" />
<mvc:resources mapping="/resources/**" location="/resources/" />
The servlet-context.xml only has mapping for the InternalResourceViewResolver
The security-context.xml is as follows :
<http pattern="/resources/**" security="none"/>
<http auto-config="false" create-session="stateless" entry-point-ref="loginUrlAuthenticationEntryPoint" >
<intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/j_spring_security_check" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/accessdenied" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/login" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/logout" access="ROLE_USER"/>
<custom-filter before="SECURITY_CONTEXT_FILTER" ref="cookieSecurityContextFilter" />
<custom-filter position="LOGOUT_FILTER" ref="logoutfilter" />
<custom-filter position="FORM_LOGIN_FILTER" ref="authenticationFilter" />
<custom-filter after="EXCEPTION_TRANSLATION_FILTER" ref="customExceptionFilter" />
</http>
<beans:bean id="logoutfilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
<beans:constructor-arg value="/"/>
<beans:constructor-arg ref="customLogouthandler"/>
</beans:bean>
And then further mapping for the filters.
Am I doing something wrong in the configuration that could lead to the controller being called twice. I have checked the logs and the beans are instantiated only once. Please help.
Thanks in advance.
Just in case someone stumbles on this post and solution posted here thinking it will fix the duplicate requests, please first check if it is your browser/rest client making the additional call.
I wasted many hours trying to configure app and servlet contexts "after seeing the first suggested solution", until I figured it was the rest client on certain browsers (Chrome) creating an additional request for "GET requests on image resources". Curl showed only one method execution.
However, I do agree that it is a good practice to separate controller specific beans and their required Spring beans into servlet-context and keep all common beans in app-context. This is especially important if you have multiple Spring dispatcher servlet- in your web.xml.
Elaborating the previous answer:
You can either define both component-scan and mvc in the same context file to keep it simple.
app-context.xml:
<context:component-scan base-package="..." />
<mvc:annotation-driven />
...
Or separate them as follows:
app-context.xml:
<context:component-scan base-package="....">
<context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
<context:exclude-filter expression="org.springframework.web.bind.annotation.ControllerAdvice" type="annotation"/>
<context:exclude-filter expression="org.springframework.web.bind.annotation.ExceptionHandler" type="annotation"/>
</context:component-scan>
...
servlet-context.xml:
<context:component-scan base-package="...">
<context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
<context:include-filter expression="org.springframework.web.bind.annotation.ControllerAdvice" type="annotation"/>
<context:include-filter expression="org.springframework.web.bind.annotation.ExceptionHandler" type="annotation"/>
</context:component-scan>
<mvc:annotation-driven />
...
I would try moving <mvc:.. elements to servlet-context.xml, maybe having it on applicationContext.xml causes you to have duplicate dispatcher servlet (although beans are only created once)
Scan all components except #Controller on applicationContext.xml by using <context:exclude-filter... Likewise scan only #Controller on servlet-context.xml using <context:include-filter..

Access a controller before authentication Spring Security

I've been trying to implement a solution for multiple login pages. I currently have a unique LoginController, and all it does is to retrieve the login jsp when somebody request /app_name/login.htm. I want that to stay that way, but also add two more locations: /app_name/customers/login.htm and /app_name/employees/login.htm each one with an individual controller CustomerLoginController and EmployeeLoginController.
So my idea is that employees access through their URL and customer using theirs, but if someone try to access the old login.htm the controller redirects him/her to their respective login using an stored cookie and customer as default.
To me it sounds good, but when I tried to access /app_name/customers/login.htm or /app_name/employees/login.htm it just redirects me to login.htm when I'm not authenticated.
I really don't know why it's not resolving them. Any opinion, suggestion, guide, tutorial, example code or link would be helpful.
The project I'm working on has this configs
Web.xml
<!-- 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>
servlet-config.xml
<!-- Controllers Mapping -->
<context:component-scan base-package="com.company.project.controllers">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
security-context.xml
<sec:http auto-config="false" entry-point-ref="authenticationProcessingFilterEntryPoint" access-denied-page="/warning/accessDenied.htm" >
<sec:intercept-url pattern="/employees/login.htm" filters="none" />
<sec:intercept-url pattern="/customers/login.htm" filters="none" />
<sec:intercept-url pattern="/login**" filters="none" />
</sec:http>
<bean id="authenticationProcessingFilterEntryPoint" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint">
<property name="loginFormUrl" value="/login.htm" />
<property name="forceHttps" value="false" />
</bean>
<bean id="authenticationProcessingFilter" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilter">
<property name="authenticationFailureUrl" value="/login.htm?login_error=1"/>
<property name="defaultTargetUrl" value="/home.htm"/>
<property name="alwaysUseDefaultTargetUrl" value="true"/>
<property name="filterProcessesUrl" value="/j_spring_security_check"/>
</bean>
PD: using Spring 2.5.4 and Spring Security 2.0.4 -_- I Know, but is a fairly sized project and it's been in production for a while
Multiple login pages can be done with 2 separate http declarations:
<http pattern="/customers/**" authentication-manager-ref="customerAuthenticationManager">
<form-login login-page="/customers/login" default-target-url="/customers" login-processing-url="/customers/j_spring_security_check"/>
<logout logout-url="/customers/logout"/>
...
</http>
<http pattern="/employees/**" authentication-manager-ref="employeeAuthenticationManager">
<form-login login-page="/employees/login" default-target-url="/employees" login-processing-url="/employees/j_spring_security_check"/>
<logout logout-url="/employees/logout"/>
...
</http>

Resources