0

Recently I've been trying to integrate Spring Security into my REST API. I found the following SO answer Login/logout in REST with Spring 3 and tried to implement it in my project.

After tinkering a few minor things, I seem to have run into some issues.

  1. In my intercept-url even if I set the access to permitAll, I get the following error:

    HTTP Status 500 - An Authentication object was not found in the SecurityContext

  2. When I visit localhost:8080/Login to try to login no popup appears and I get a 404.

Here is my code:

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    version="3.1">
    <display-name>name</display-name>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
        classpath:applicationContext.xml,
        classpath:spring-security.xml
    </param-value>
    </context-param>

    <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>
    <servlet>
        <servlet-name>jersey-serlvet</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>jersey.config.server.provider.packages</param-name>
            <param-value>com.trackmygymlife.webservices</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>jersey-serlvet</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>

</web-app>

spring-security.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:sec="http://www.springframework.org/schema/security" 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
    classpath:org/springframework/beans/factory/xml/spring-beans-4.1.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security-4.0.xsd
    http://www.springframework.org/schema/util 
    http://www.springframework.org/schema/util/spring-util-4.1.xsd">


    <bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
        <constructor-arg>
            <list>
                <sec:filter-chain pattern="/login" filters="sif,wsFilter" />
                <sec:filter-chain pattern="/logout" filters="sif,logoutFilter" />
                <sec:filter-chain pattern="/rest/**" filters="sif,fsi" />
            </list>
        </constructor-arg>
    </bean>

    <bean id="sif"
        class="org.springframework.security.web.context.SecurityContextPersistenceFilter" />

    <bean id="wsFilter" class="com.trackmygymlife.security.UserAuthenticationFilter">
        <property name="authenticationManager" ref="authenticationManager" />
        <property name="authenticationSuccessHandler" ref="authSuccessHandler" />
        <property name="passwordParameter" value="pass"></property>
        <property name="usernameParameter" value="user"></property>
        <property name="postOnly" value="false"></property>
    </bean>

    <bean id="authSuccessHandler"
        class="com.trackmygymlife.security.AuthenticationSuccessHandler"></bean>

    <sec:authentication-manager alias="authenticationManager">
        <sec:authentication-provider user-service-ref="userService" >
            <sec:password-encoder hash="bcrypt"></sec:password-encoder>
        </sec:authentication-provider>
    </sec:authentication-manager>

    <bean id="authenticationProvider"
        class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
        <property name="preAuthenticatedUserDetailsService">
            <bean id="userDetailsServiceWrapper"
                class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
                <property name="userDetailsService" ref="userService" />
            </bean>
        </property>
    </bean>

    <bean id="userService"
        class="com.trackmygymlife.serviceimpl.TrackMyGymLifeUserService" />

    <bean id="logoutFilter"
        class="org.springframework.security.web.authentication.logout.LogoutFilter">
        <constructor-arg index="0" value="/">
        </constructor-arg>
        <constructor-arg index="1">
            <bean
                class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler" />
        </constructor-arg>
    </bean>

    <bean id="httpRequestAccessDecisionManager"
        class="org.springframework.security.access.vote.AffirmativeBased">
        <property name="allowIfAllAbstainDecisions" value="false" />
        <constructor-arg>
            <list>
                <ref bean="roleVoter" />
                <bean class="org.springframework.security.access.vote.RoleVoter "/>
            </list>
        </constructor-arg>
        <!-- <property name="decisionVoters"> -->
        <!-- <list> -->
        <!-- </list> -->
        <!-- </property> -->
    </bean>

    <bean id="roleVoter"
        class="org.springframework.security.web.access.expression.WebExpressionVoter" />

    <bean id="securityContextHolderAwareRequestFilter"
        class="org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter" />

    <bean id="fsi"
        class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
        <property name="authenticationManager" ref="authenticationManager" />
        <property name="accessDecisionManager" ref="httpRequestAccessDecisionManager" />
        <property name="securityMetadataSource">
            <sec:filter-security-metadata-source>
                <sec:intercept-url pattern="/rest/**" access="hasRole('ROLE_USER')" />
            </sec:filter-security-metadata-source>
        </property>
    </bean>

</beans>

AuthenticationSuccessHandler:

public class AuthenticationSuccessHandler  extends SimpleUrlAuthenticationSuccessHandler{

    @PostConstruct
    public void afterPropertiesSet() {
        setRedirectStrategy(new NoRedirectStrategy());
    }

    protected class NoRedirectStrategy implements RedirectStrategy {
        @Override
        public void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url)
                throws IOException {            
        }
    }

UserAuthenticationFilter:

public class UserAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    @Override
    protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
        return (StringUtils.hasText(obtainUsername(request)) && StringUtils.hasText(obtainPassword(request)));
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
            Authentication authResult) throws IOException, ServletException {

        super.successfulAuthentication(request, response, chain, authResult);
        chain.doFilter(request, response);
    }
}

Any help would be appreciated.

Community
  • 1
  • 1
  • Have you tried to debug authentication? I would start from putting a breakpoint in UsernamePasswordAuthenticationFilter on **public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)**, looking if at all this point is reached as it should, and if later the resulting Authentication object is put in the ThreadLocal object inside SecurityContextHolder **SecurityContextHolder.getContext().setAuthentication(authResult);** (I refer to Spring Security 3, presumably in Spring 4 this should be similar). – John Donn Oct 11 '16 at 08:50
  • John Down. I was under the understanding that this was never reached, however I was wrong. I am currently in the process of debugging. Will update here with my results. Thanks! – Raymond.Aggarwal Oct 11 '16 at 10:49
  • sorry, I did not pay attention; I don't think you have the (default) login page with zero configuration (at least not in Spring Security 3). Here should be an example with xml spring security "namespace" configuration (Spring Security 4) http://websystique.com/spring-security/spring-security-4-custom-login-form-annotation-example/ (there is an element ****. One has to understand then how to refer to your filterChain definition from the spring security xml file. – John Donn Oct 11 '16 at 11:08

0 Answers0