Rudi Wijaya
Rudi Wijaya

Reputation: 930

Http Session is Null in AuthenticatedWebSession Wicket And Spring Security

Environment:

<wicket.version>7.7.0</wicket.version>
<spring.version>4.3.8.RELEASE</spring.version>
<springsecurity.version>4.2.3.RELEASE</springsecurity.version>

I have custom class from AuthenticatedWebSession like:

public class WicketSession extends AuthenticatedWebSession {

    private static final Logger log = LoggerFactory.getLogger(WicketSession.class);

    private static final long serialVersionUID = 1L;

    private final HttpSession httpSession;

    @SpringBean(name = "authenticationManager")
    private AuthenticationManager authenticationManager;

    public WicketSession(Request request) {
        super(request);
        this.httpSession = ((HttpServletRequest) request.getContainerRequest()).getSession();
        log.debug("Got httpSession: {}", this.httpSession);
        Injector.get().inject(this);
    }

    @Override
    public boolean authenticate(String username, String password) {
        try {
            final Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
            log.debug("Username '{}' is {} auth with authorities: {}",
                    username, auth.isAuthenticated(), auth.getAuthorities());
            if (auth.isAuthenticated()) {
                // the authentication object has to be stored in the SecurityContextHolder and in the HttpSession manually, so that the
                // security context will be accessible in the next request
                SecurityContextHolder.getContext().setAuthentication(auth);
                httpSession.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY,
                        SecurityContextHolder.getContext());
                return true;
            } else {
                return false;
            }
        } catch (AuthenticationException e) {
            log.warn("Failed login attempt due to exception!", e);
            return false;
        }
    }


}

Spring Security Config like:

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    public SpringSecurityConfig() {
        super(false);
    }

    @Override
    @Bean
    public UserDetailsService userDetailsService() {
        final InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("admin").password("admin").roles("ADMIN").build());
        manager.createUser(User.withUsername("rudi").password("rudi").roles("USER").build());
        return manager;
    }

    @Bean(name = "authenticationManager")
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers("/user/**").authenticated()
                .antMatchers("/admin/**").hasRole("ADMIN")
                .antMatchers("/**").permitAll()
                .and().formLogin().loginPage("/login")
                .and().addFilter(new SecurityContextPersistenceFilter()).securityContext();
    }    
}

Spring Application Config like:

@PropertySource({"classpath:/META-INF/rcommerce.properties"})
@Configuration
@EnableWebMvc
@EnableTransactionManagement
@Import({
    SpringSecurityConfig.class})
public class AppConfig {

    @Bean
    public AuthenticatedWebApplication webApp() {
        return new WicketApplication();
    }

}

custom class from AbstractSecurityWebApplicationInitializer like:

public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {

    public SecurityWebApplicationInitializer() {
        super(SpringSecurityConfig.class);
    }

}

web.xml:

<web-app 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_3_0.xsd"
    version="3.0">

    <display-name>rcommerce</display-name>

    <!-- WICKET FILTER-->
    <filter>
        <filter-name>wicket.rcommerce</filter-name>
        <filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
        <init-param>
            <param-name>applicationFactoryClassName</param-name>
            <param-value>org.apache.wicket.spring.SpringWebApplicationFactory</param-value>
        </init-param>
        <init-param>
            <param-name>applicationBean</param-name>
            <param-value>webApp</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>wicket.rcommerce</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- MDC FILTER -->
    <filter>
        <description>A servlet filter that inserts various values retrieved from the incoming http request into the MDC.</description>
        <filter-name>MDCInsertingServletFilter</filter-name>
        <filter-class>ch.qos.logback.classic.helpers.MDCInsertingServletFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>MDCInsertingServletFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>MoreMdcServletFilter</filter-name>
        <filter-class>com.rudiwijaya.rcommerce.servlet.MoreMdcServletFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>MoreMdcServletFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- SPRING REST SERVLET-->
    <servlet>
        <servlet-name>spring-web</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextClass</param-name>
            <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
        </init-param>
<!--        <init-param> -->
            <!-- use just the root WebApplicationContext -->
<!--            <param-name>contextConfigLocation</param-name> -->
<!--            <param-value>org.soluvas.sanad.app.ServletConfig</param-value> -->
<!--            <param-value></param-value> -->
<!--        </init-param> -->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>spring-web</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
    <!-- SPRING REST FILTER-->
    <filter>
        <filter-name>httpPutFormFilter</filter-name>
        <filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>httpPutFormFilter</filter-name>
        <servlet-name>spring-web</servlet-name>
    </filter-mapping>

    <!-- The SpringWebApplicationFactory will need access to a Spring Application 
        context, configured like this... -->
    <!-- SPRING CONFIG -->
    <context-param>
        <param-name>contextClass</param-name>
        <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
    </context-param>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>com.rudiwijaya.rcommerce.AppConfig</param-value>
    </context-param>

    <!-- LISTENERS -->
    <listener>
        <listener-class>ch.qos.logback.classic.selector.servlet.ContextDetachingSCL</listener-class>
    </listener>
    <listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>

    <!-- ERROR PAGE HANDLING -->
    <error-page>
        <error-code>404</error-code>
        <location>/404.html</location>
    </error-page>

    <!-- TIMEOUT -->
    <session-config>
        <session-timeout>120</session-timeout>
    </session-config>

</web-app>

when I call session.signIn, got error like:

Root cause:

java.lang.NullPointerException
     at com.rudiwijaya.rcommerce.WicketSession.authenticate(WicketSession.java:60)
     at org.apache.wicket.authroles.authentication.AuthenticatedWebSession.signIn(AuthenticatedWebSession.java:66)
     at com.rudiwijaya.rcommerce.pages.LoginButton.doAuthenticate(LoginButton.java:132)
     at com.rudiwijaya.rcommerce.pages.LoginButton.onSubmit(LoginButton.java:165)
     at org.apache.wicket.ajax.markup.html.form.AjaxButton$1.onSubmit(AjaxButton.java:113)
     at org.apache.wicket.ajax.form.AjaxFormSubmitBehavior$AjaxFormSubmitter.onSubmit(AjaxFormSubmitBehavior.java:215)
     at org.apache.wicket.markup.html.form.Form.delegateSubmit(Form.java:1307)
     at org.apache.wicket.markup.html.form.Form.process(Form.java:976)
     at org.apache.wicket.markup.html.form.Form.onFormSubmitted(Form.java:797)
     at org.apache.wicket.ajax.form.AjaxFormSubmitBehavior.onEvent(AjaxFormSubmitBehavior.java:171)
     at org.apache.wicket.ajax.AjaxEventBehavior.respond(AjaxEventBehavior.java:155)
     at org.apache.wicket.ajax.AbstractDefaultAjaxBehavior.onRequest(AbstractDefaultAjaxBehavior.java:601)
     at java.lang.reflect.Method.invoke(Method.java:498)
     at org.apache.wicket.RequestListenerInterface.internalInvoke(RequestListenerInterface.java:258)
     at org.apache.wicket.RequestListenerInterface.invoke(RequestListenerInterface.java:241)
     at org.apache.wicket.core.request.handler.ListenerInterfaceRequestHandler.invokeListener(ListenerInterfaceRequestHandler.java:248)
     at org.apache.wicket.core.request.handler.ListenerInterfaceRequestHandler.respond(ListenerInterfaceRequestHandler.java:234)
     at org.apache.wicket.request.cycle.RequestCycle$HandlerExecutor.respond(RequestCycle.java:895)
     at org.apache.wicket.request.RequestHandlerStack.execute(RequestHandlerStack.java:64)

The error (it is httpSession is null) in line:

httpSession.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY,
                        SecurityContextHolder.getContext());

What should I do, please?

Upvotes: 0

Views: 1206

Answers (1)

martin-g
martin-g

Reputation: 17503

Do you have more than one web container nodes ? With session replication ?

As a general rule you should never keep a hard reference to the Http Session. Especially in Wicket applications! Because if WicketSession is serialized and then deserialized this member field will be null!

Better lookup the HttpSession whenever you need it, i.e. extract((HttpServletRequest) request.getContainerRequest()).getSession(); in a method and call it when you need the session in the methods' bodies.

Upvotes: 1

Related Questions