Skip to content

Fix Spring Security integration docs sample #1304

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
pavankjadda opened this issue Jan 7, 2019 · 11 comments
Closed

Fix Spring Security integration docs sample #1304

pavankjadda opened this issue Jan 7, 2019 · 11 comments
Assignees
Labels
in: docs An issue in Documentation or samples type: bug A general bug
Milestone

Comments

@pavankjadda
Copy link

I am trying to implement RememberMe service for my Spring Security application with Spring Session management. I configured, SpringSessionRememberMeServices and SpringSessionBackedSessionRegistry beans based on Spring Session Documentation. When I try to autowire FindByIndexNameSessionRepository I got the following error

Could not autowire. No beans of 'FindByIndexNameSessionRepository<Session>' type found

SecurityConfig.java

package com.springtesting.security.config;


import com.springtesting.security.MyUserDetailsService;
import com.springtesting.security.handlers.CustomAuthenticationFailureHandler;
import com.springtesting.security.handlers.CustomAuthenticationSuccessHandler;
import com.springtesting.security.handlers.CustomLogoutSuccessHandler;
import com.springtesting.security.providers.CustomDaoAuthenticationProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.session.HttpSessionEventPublisher;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.Session;
import org.springframework.session.jdbc.config.annotation.web.http.EnableJdbcHttpSession;
import org.springframework.session.security.SpringSessionBackedSessionRegistry;
import org.springframework.session.security.web.authentication.SpringSessionRememberMeServices;


@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
    private final MyUserDetailsService userDetailsService;

    private final FindByIndexNameSessionRepository<Session> sessionRepository;

    @Autowired
    public SecurityConfig(MyUserDetailsService userDetailsService, FindByIndexNameSessionRepository<Session> sessionRepository)
    {
        this.userDetailsService = userDetailsService;
        this.sessionRepository = sessionRepository;
    }


    @Override
    public void configure(AuthenticationManagerBuilder auth)
    {
        auth.authenticationProvider(getDaoAuthenticationProvider());
    }

    @Bean
    public CustomDaoAuthenticationProvider getDaoAuthenticationProvider()
    {
        CustomDaoAuthenticationProvider daoAuthenticationProvider=new CustomDaoAuthenticationProvider();
        daoAuthenticationProvider.setUserDetailsService(userDetailsService);
        daoAuthenticationProvider.setPasswordEncoder(getBCryptPasswordEncoder());
        return daoAuthenticationProvider;
    }

    /* BCrypt strength should 12 or more*/
    @Bean
    public PasswordEncoder getBCryptPasswordEncoder()
    {
        return new BCryptPasswordEncoder(12);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception
    {
            http.authorizeRequests()
                    .antMatchers("/anonymous*").anonymous()
                    .antMatchers("/users/**").hasAuthority(AuthorityConstants.Admin)
                    .antMatchers("/admin**").hasAuthority(AuthorityConstants.Admin)
                    .antMatchers("/profile/**").hasAuthority(AuthorityConstants.User)
                    .antMatchers("/api/**").hasAuthority(AuthorityConstants.ApiUser)
                    .antMatchers("/dba/**").hasAuthority(AuthorityConstants.Dba)
                    .anyRequest().authenticated()
            .and()
                    .httpBasic()
            .and()
                    .formLogin()
                        .loginPage("/login")
                        .loginProcessingUrl("/login")
                        .successHandler(new CustomAuthenticationSuccessHandler())
                        .failureHandler(new CustomAuthenticationFailureHandler())
                        .permitAll()
            .and()
                    .logout()
                        .deleteCookies("JSESSIONID")
                        .logoutSuccessHandler(new CustomLogoutSuccessHandler())
                        .permitAll()
            .and()
                    .rememberMe().rememberMeServices(springSessionRememberMeServices());


        http.sessionManagement()
                        .invalidSessionUrl("/invalidSession.html")
                        .sessionFixation()
                        .migrateSession()
                        .maximumSessions(1)
                        .sessionRegistry(sessionRegistry());;
    }

    @Bean
    public SpringSessionRememberMeServices springSessionRememberMeServices()
    {
        SpringSessionRememberMeServices rememberMeServices = new SpringSessionRememberMeServices();
        // optionally customize
        rememberMeServices.setRememberMeParameterName("remember-me");
        rememberMeServices.setValiditySeconds(86000);

        return rememberMeServices;
    }


    @Bean
    SpringSessionBackedSessionRegistry sessionRegistry()
    {
        return new SpringSessionBackedSessionRegistry<>(this.sessionRepository);
    }

    @Override
    public void configure(WebSecurity web) throws Exception
    {
        web
            .ignoring()
            .antMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/images/**");
    }

    @Bean
    public HttpSessionEventPublisher httpSessionEventPublisher()
    {
        return new HttpSessionEventPublisher();
    }

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

application.properties

###################################  MySQL Database as persistent Database  ##############################

spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://localhost:3306/springsecuritydb?useSSL=false
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.datasource.username=root
spring.datasource.password=bcmc1234

management.endpoints.web.exposure.include=*
management.endpoint.auditevents.enabled=true

spring.session.store-type=jdbc
# Name of the database table used to store sessions.
spring.session.jdbc.table-name=SPRING_SESSION
# Database schema initialization mode
spring.session.jdbc.initialize-schema=always



#server.servlet.session.timeout=
#spring.session.jdbc.schema=classpath:org/springframework/session/jdbc/schema-@@platform@@.sql # Path to the SQL file to use to initialize the database schema.


spring.devtools.restart.enabled=true

server.servlet.session.cookie.http-only=true
server.servlet.session.cookie.secure=false

https://docs.spring.io/spring-session/docs/current/reference/html5/#spring-security

@vpavic vpavic self-assigned this Jan 7, 2019
@vpavic vpavic added type: bug A general bug in: docs An issue in Documentation or samples labels Jan 7, 2019
@vpavic vpavic added this to the 2.1.3 milestone Jan 7, 2019
@vpavic
Copy link
Contributor

vpavic commented Jan 8, 2019

Thanks for raising this @pavankjadda - as discussed on Gitter, this is a problem with our documentation, and you should either inject and use raw type, or parameterized (respecting the original contract of FindByIndexNameSessionRepository<S extends Session>). See #849 and #1154 as an examples.

@vpavic vpavic changed the title Could not autowire. No beans of 'FindByIndexNameSessionRepository<Session>' type found Fix Spring Security integration docs sample Jan 8, 2019
@vpavic
Copy link
Contributor

vpavic commented Jan 8, 2019

Fixed via fd5115f in master. We'll also backport this to 2.0.x and 1.3.x via #1305 and #1306.

@vpavic vpavic closed this as completed Jan 8, 2019
@pavankjadda
Copy link
Author

pavankjadda commented Jan 8, 2019

@vpavic I created a Parameterized Consumer and tried to inject it as bean to my Security config. I still get the same error. Is this the right way to inject it?

class ParameterizedConsumer<S extends Session>
{

    @Autowired
    private FindByIndexNameSessionRepository<S> sessionRepository;

    void consume()
    {
        S session = this.sessionRepository
                .findByIndexNameAndIndexValue(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, "principal")
                .values().iterator().next();
        session.setAttribute("test", UUID.randomUUID().toString());
        this.sessionRepository.save(session);
    }

}

SecurityConfig.java

..................
@Bean
   public SpringSessionBackedSessionRegistry<S> sessionRegistry()
   {
       return (SpringSessionBackedSessionRegistry<S>) new ParameterizedConsumer<S>().getSessionRepository(););
   }
...................

@vpavic
Copy link
Contributor

vpavic commented Jan 8, 2019

Is this repo the app you're having issues with?

@pavankjadda
Copy link
Author

@vpavic Yes

@vpavic
Copy link
Contributor

vpavic commented Jan 12, 2019

I've taken a look at your sample @pavankjadda, but I'm afraid that's far from being a minimal sample. To begin with, your app requires a local running instance of MySQL. After working past that, I encountered a different issue from the one you reported:

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.session.jdbc.JdbcOperationsSessionRepository]: Circular reference involving containing bean 'org.springframework.boot.autoconfigure.session.JdbcSessionConfiguration$SpringBootJdbcHttpSessionConfiguration' - consider declaring the factory method as static for independence from its containing instance. Factory method 'sessionRepository' threw exception; nested exception is java.lang.IllegalArgumentException: Property 'dataSource' is required
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:622) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
	... 119 common frames omitted

There's a circular reference problem within your app, and that's something not necessarily related to Spring Session itself. This is unrelated to the originally reported problem of Could not autowire. No beans of 'FindByIndexNameSessionRepository<Session>' type found which could have indeed been caused by a bad config sample in our docs.

I'd suggest you to open a new issue, coupled with minimal, complete, and verifiable sample app that can demonstrate this issue in order to determine whether this indeed is a problem with Spring Session itself.

@pavankjadda
Copy link
Author

@vpavic Thanks. I will create a new app with minimum code and open new issue

@pavankjadda
Copy link
Author

@vpavic I created a new project with minimal code and config. Now, I can run the project without any exception. But I still see the error message (attached below) on IntelliJ despite the fact that I am able to run the project. Not sure what's wrong here. Thanks for the help

screen shot 2019-01-12 at 10 54 25 pm

@vpavic
Copy link
Contributor

vpavic commented Jan 13, 2019

That's simply a tooling warning - you could consider reporting in on IntelliJ issue tracker. I've seen it in the past but honestly didn't pay too much attention as the code compiles and runs without any warnings.

@f3l1xss
Copy link

f3l1xss commented Oct 20, 2020

Hello there,

@vpavic
I have tried creating the same minimum project and still cannot get the findByIndexRepository injected. I am using Spring Boot 2.3.0

demo.zip

Edit: Turns out the root cause of the issue is having

@bean
protected HttpSessionListener httpSessionListener() {
return new HttpSessionEventPublisher();
}

HttpSessionListener bean at the config. it will cause redisConnectionFactory to not be found. I think this should be mentioned at the docs

@vpavic
Copy link
Contributor

vpavic commented Oct 31, 2020

Thanks for the sample project @f3l1xss.

The problem with your project is that you're pulling in spring-boot-starter rather than spring-boot-starter-web, so you don't actually have the needed web components on the classpath and as a result, Spring Boot's auto-configuration for Spring Session backs off.

Once I added spring-boot-starter-web dependency, the project builds fine.

In future, try opening a new issue - commenting on closed issues isn't the best way to report issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: docs An issue in Documentation or samples type: bug A general bug
Projects
None yet
Development

No branches or pull requests

3 participants