1

I need spring boot app with two different login/register endpoints one is api/user/auth/registerUser and api/node/auth/registerNode.

I write the code but now i have two authenticationManagerBean see config:

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfiguration {

    @Configuration
    @Order(1)
    public class SecurityConfig1 extends WebSecurityConfigurerAdapter {

        @Autowired
        CustomUserDetailsService customUserDetailsService;

        @Autowired
        private JwtAuthenticationEntryPoint unauthorizedHandler;

        @Bean
        public JwtAuthenticationFilter jwtAuthenticationFilter() {
            return new JwtAuthenticationFilter();
        }

        @Override
        public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
            authenticationManagerBuilder
                    .userDetailsService(customUserDetailsService)
                    .passwordEncoder(passwordEncoder());
        }

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

        @Bean
        public PasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .cors()
                    .and()
                    .csrf()
                    .disable()
                    .exceptionHandling()
                    .authenticationEntryPoint(unauthorizedHandler)
                    .and()
                    .sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and()
                    .authorizeRequests()
                    .antMatchers("/",
                            "/favicon.ico",
                            "/**/*.png",
                            "/**/*.gif",
                            "/**/*.svg",
                            "/**/*.jpg",
                            "/**/*.html",
                            "/**/*.css",
                            "/**/*.js")
                    .permitAll()
                    .antMatchers("/api/user/auth/**")
                    .permitAll()
                    .anyRequest()
                    .authenticated();

            // Add our custom JWT security filter
            http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
        }
    }

    @Configuration
    @Order(2)
    public class SecurityConfig2 extends WebSecurityConfigurerAdapter {

        @Autowired
        CustomUser1DetailsService customUser1DetailsService;

        @Autowired
        private JwtAuthenticationEntryPoint1 unauthorizedHandler1;

        @Bean
        public JwtAuthenticationFilter1 jwtAuthenticationFilter1() {
            return new JwtAuthenticationFilter1();
        }

        @Override
        public void configure(AuthenticationManagerBuilder authenticationManagerBuilder1) throws Exception {
            authenticationManagerBuilder1
                    .userDetailsService(customUser1DetailsService)
                    .passwordEncoder(passwordEncoder1());
        }

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

        @Bean
        public PasswordEncoder passwordEncoder1() {
            return new BCryptPasswordEncoder();
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .cors()
                    .and()
                    .csrf()
                    .disable()
                    .exceptionHandling()
                    .authenticationEntryPoint(unauthorizedHandler1)
                    .and()
                    .sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and()
                    .authorizeRequests()
                    .antMatchers("/",
                            "/favicon.ico",
                            "/**/*.png",
                            "/**/*.gif",
                            "/**/*.svg",
                            "/**/*.jpg",
                            "/**/*.html",
                            "/**/*.css",
                            "/**/*.js")
                    .permitAll()
                    .antMatchers("/api/node/auth/**")
                    .permitAll()
                    .anyRequest()
                    .authenticated();

            // Add our custom JWT security filter
            http.addFilterBefore(jwtAuthenticationFilter1(), UsernamePasswordAuthenticationFilter.class);
        }
    }
}

and i make user controler:

@RestController
@RequestMapping("/api/user/auth")
public class UserAuthController {

    @Autowired
    private  UserRepository userRepository;

    @Autowired
    private  RoleRepository roleRepository;

    @Autowired
    private  PasswordEncoder passwordEncoder;

    @Autowired
    @Qualifier("authenticationManager")
    private  AuthenticationManager authenticationManager;

    @Autowired
    private  JwtTokenProvider tokenProvider;

    public UserAuthController() {
    }

    @PostMapping(path = "/registerUser")
    public ResponseEntity<?> registerUser(@Valid @RequestBody SignUpRequest signUpRequest) {
        if (userRepository.existsByEmail(signUpRequest.getEmail())) {
            return new ResponseEntity(new ApiResponse(false, "Email Address already taken"), HttpStatus.BAD_REQUEST);
        }

        if (userRepository.existsByUsername(signUpRequest.getUsername())) {
            return new ResponseEntity(new ApiResponse(false, "Username already taken"), HttpStatus.BAD_REQUEST);
        }

        // Creating User
        User user = new User(signUpRequest.getUsername(), signUpRequest.getEmail(), passwordEncoder.encode(signUpRequest.getPassword()),
                signUpRequest.getFirstName(), signUpRequest.getMiddleName(), signUpRequest.getLastName());

//      Role userRole = roleRepo.findByName(RoleName.ROLE_USER)
//              .orElseThrow(() -> new AppException("User Role not set."));
//
//      Role adminRole = roleRepo.findByName(RoleName.ROLE_ADMIN)
//              .orElseThrow(() -> new AppException("User Role not set."));
//
//      Set<Role> rules = new HashSet<>();
//      rules.add(userRole);
//      rules.add(adminRole);
//      user.setRoles(rules);

        User result = userRepository.save(user);

        return ResponseEntity.ok(result);
    }

    @PostMapping("/authenticateUser")
    public ResponseEntity<?> authenticateUser(@Valid @RequestBody LoginRequest loginRequest) {
        try {
        Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(
                        loginRequest.getUsernameOrEmail(),
                        loginRequest.getPassword()
                )
        );
        SecurityContextHolder.getContext().setAuthentication(authentication);
        String accessToken = tokenProvider.generateAccessToken(authentication);
        return ResponseEntity.ok(new JwtAuthenticationResponse(accessToken,tokenProvider.getIssuedDateFromAccessToken(accessToken),tokenProvider.getExpirationDateFromAccessToken(accessToken)));
        } catch (BadCredentialsException exception) {
            throw new BadRequestException("Wrong username or password!");
        }
    }

}

and node controler:

@RestController
@RequestMapping("/api/node/auth")
public class NodeAuthController {

    @Autowired
    private User1Repository user1Repository;

    @Autowired
    private Role1Repository role1Repository;

    @Autowired
    private  PasswordEncoder passwordEncoder;

    @Autowired
    @Qualifier("authenticationManager1")
    private  AuthenticationManager authenticationManager1;

    @Autowired
    private JwtTokenProvider1 tokenProvider1;

    @PostMapping(path = "/registerNode")
    public ResponseEntity<?> registerUser(@Valid @RequestBody SignUpRequest signUpRequest) {
        if (user1Repository.existsByEmail(signUpRequest.getEmail())) {
            return new ResponseEntity(new ApiResponse(false, "Email Address already taken"), HttpStatus.BAD_REQUEST);
        }

        if (user1Repository.existsByUsername(signUpRequest.getUsername())) {
            return new ResponseEntity(new ApiResponse(false, "Username already taken"), HttpStatus.BAD_REQUEST);
        }

        // Creating User
        User1 user1 = new User1(signUpRequest.getUsername(), signUpRequest.getEmail(), passwordEncoder.encode(signUpRequest.getPassword()),
                signUpRequest.getFirstName(), signUpRequest.getMiddleName(), signUpRequest.getLastName());

//      Role userRole = roleRepo.findByName(RoleName.ROLE_USER)
//              .orElseThrow(() -> new AppException("User Role not set."));
//
//      Role adminRole = roleRepo.findByName(RoleName.ROLE_ADMIN)
//              .orElseThrow(() -> new AppException("User Role not set."));
//
//      Set<Role> rules = new HashSet<>();
//      rules.add(userRole);
//      rules.add(adminRole);
//      user.setRoles(rules);

        User1 result = user1Repository.save(user1);

        return ResponseEntity.ok(result);
    }

    @PostMapping("/authenticateNode")
    public ResponseEntity<?> authenticateUser(@Valid @RequestBody LoginRequest loginRequest) {
        try {
        Authentication authentication = authenticationManager1.authenticate(
                new UsernamePasswordAuthenticationToken(
                        loginRequest.getUsernameOrEmail(),
                        loginRequest.getPassword()
                )
        );
        SecurityContextHolder.getContext().setAuthentication(authentication);
        String accessToken = tokenProvider1.generateAccessToken(authentication);
        return ResponseEntity.ok(new JwtAuthenticationResponse(accessToken,tokenProvider1.getIssuedDateFromAccessToken(accessToken),tokenProvider1.getExpirationDateFromAccessToken(accessToken)));
        } catch (BadCredentialsException exception) {
            throw new BadRequestException("Wrong username or password!");
        }
    }

}

Error is:java.lang.RuntimeException: java.lang.IllegalArgumentException: Found 2 beans for type interface org.springframework.security.authentication.AuthenticationManager, but none marked as primary

If I make one primary code is run but for controler that is not primary response is

{
    "timestamp": "2020-06-04T03:45:45.638+02:00",
    "status": 401,
    "error": "Unauthorized",
    "message": "",
    "path": "/api/node/auth/registerNode"
}

How to make this work? Thanks for all your help

5
  • You don’t need 2 different qualifier in AuthenticationManagerBean. You just need to keep same bame and implementation in both the pace as: “@Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); }“ Commented Jun 4, 2020 at 2:34
  • There should only be 1 authentication manager, but 2 authentication providers. Also do you really need 2 different ones? Why? The logic and everything else looks the same? Commented Jun 4, 2020 at 5:57
  • @AlokSingh can you please give me an example? How can I make one bame for both implementations Thanks for all the help Commented Jun 4, 2020 at 11:57
  • @M.Deinum This is only an example for testing purpose. In production i have different information for each user . Can you please tell me how to make 1 authentication manager for 2 authentication providers? Thanks for all the help Commented Jun 4, 2020 at 11:57
  • I have added my working code in answer section. Let me know if this is not meeting your requirements. In the code we have 2 authentication mechanisms - basic authentication and form login authentication. Commented Jun 4, 2020 at 13:28

3 Answers 3

1

The similar requirements implemented below works for me:

@Configuration
@EnableWebSecurity
public class ServerSecurityConfig {

    @Configuration
    @Order(1)
public static class CustomAutorizeURLSecurityConfig extends WebSecurityConfigurerAdapter {


    @Autowired
    @Qualifier("sudoUserDetailsService")
    private UserDetailsService sudoUserDetailsService;

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

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(sudoUserDetailsService);
    }

    @Override
        protected void configure(HttpSecurity http) throws Exception {
             http.antMatcher("/oauth/custom_authorize")
            .csrf().disable()
            .authorizeRequests()
            .anyRequest().authenticated()
            .and()
            .httpBasic()
            ;

            http
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.NEVER);
    }
}

@Configuration
    @Order(2)
@Import(Encoders.class)
public static class OtherURLSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier("customUserDetailsService")
    private UserDetailsService customUserDetailsService;

    @Autowired
    private PasswordEncoder userPasswordEncoder;

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

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(customUserDetailsService).passwordEncoder(userPasswordEncoder);
    }

    @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
            .csrf().disable()
            .authorizeRequests()
                .antMatchers("/resources/**").permitAll()
                .antMatchers("/shutdown").permitAll()
                .antMatchers("/health").permitAll()
                .antMatchers("/info").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                    .loginPage("/login")
                .permitAll()
            ;

            http
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.NEVER);
    }
}
}

It implements 2 authentication mechanisms - 1) Basic Authentication and 2) Form Login Authentication

Sign up to request clarification or add additional context in comments.

2 Comments

The bean 'authenticationManagerBean', defined in class path resource [shijakovski/com/springBootLogin/config/SecurityConfiguration$SecurityConfig2.class], could not be registered. A bean with that name has already been defined in class path resource [shijakovski/com/springBootLogin/config/SecurityConfiguration$SecurityConfig1.class] and overriding is disabled.
I have two beans and in the controler i get: Could not autowire. There is more than one bean of 'AuthenticationManager' type. Beans: authenticationManagerBean (SecurityConfiguration.java) authenticationManagerBean (SecurityConfiguration.java)
0

my config:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfiguration{

    @Configuration
    @Order(1)
    public static class SecurityConfig1 extends WebSecurityConfigurerAdapter {

        @Autowired
        @Qualifier("customUserDetailsService")
        CustomUserDetailsService customUserDetailsService;

        @Autowired
        private JwtAuthenticationEntryPoint unauthorizedHandler;

        @Bean
        public JwtAuthenticationFilter jwtAuthenticationFilter() {
            return new JwtAuthenticationFilter();
        }

        @Override
        public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
            authenticationManagerBuilder
                    .userDetailsService(customUserDetailsService)
                    .passwordEncoder(passwordEncoder());
        }

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

        @Bean
        public PasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .cors()
                    .and()
                    .csrf()
                    .disable()
                    .exceptionHandling()
                    .authenticationEntryPoint(unauthorizedHandler)
                    .and()
                    .sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and()
                    .authorizeRequests()
                    .antMatchers("/",
                            "/favicon.ico",
                            "/**/*.png",
                            "/**/*.gif",
                            "/**/*.svg",
                            "/**/*.jpg",
                            "/**/*.html",
                            "/**/*.css",
                            "/**/*.js")
                    .permitAll()
                    .antMatchers("/api/user/auth/**")
                    .permitAll()
                    .anyRequest()
                    .authenticated();

            // Add our custom JWT security filter
            http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
        }
    }

    @Configuration
    @Order(2)
    public static class SecurityConfig2 extends WebSecurityConfigurerAdapter {

        @Autowired
        @Qualifier("customUser1DetailsService")
        CustomUser1DetailsService customUser1DetailsService;

        @Autowired
        private JwtAuthenticationEntryPoint1 unauthorizedHandler1;

        @Bean
        public JwtAuthenticationFilter1 jwtAuthenticationFilter1() {
            return new JwtAuthenticationFilter1();
        }

        @Override
        public void configure(AuthenticationManagerBuilder authenticationManagerBuilder1) throws Exception {
            authenticationManagerBuilder1
                    .userDetailsService(customUser1DetailsService)
                    .passwordEncoder(passwordEncoder1());
        }

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

        @Bean
        public PasswordEncoder passwordEncoder1() {
            return new BCryptPasswordEncoder();
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .cors()
                    .and()
                    .csrf()
                    .disable()
                    .exceptionHandling()
                    .authenticationEntryPoint(unauthorizedHandler1)
                    .and()
                    .sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and()
                    .authorizeRequests()
                    .antMatchers("/",
                            "/favicon.ico",
                            "/**/*.png",
                            "/**/*.gif",
                            "/**/*.svg",
                            "/**/*.jpg",
                            "/**/*.html",
                            "/**/*.css",
                            "/**/*.js")
                    .permitAll()
                    .antMatchers("/api/node/auth/**")
                    .permitAll()
                    .anyRequest()
                    .authenticated();

            // Add our custom JWT security filter
            http.addFilterBefore(jwtAuthenticationFilter1(), UsernamePasswordAuthenticationFilter.class);
        }
    }
}

and my user controller:

@RestController
@RequestMapping("/api/user/auth")
public class UserAuthController {

    @Autowired
    private  UserRepository userRepository;

    @Autowired
    private  RoleRepository roleRepository;

    @Autowired
    private  PasswordEncoder passwordEncoder;

    @Autowired
    private  AuthenticationManager authenticationManager; //problem is here 

    @Autowired
    private  JwtTokenProvider tokenProvider;

    public UserAuthController() {
    }

    @PostMapping(path = "/registerUser")
    public ResponseEntity<?> registerUser(@Valid @RequestBody SignUpRequest signUpRequest) {
        if (userRepository.existsByEmail(signUpRequest.getEmail())) {
            return new ResponseEntity(new ApiResponse(false, "Email Address already taken"), HttpStatus.BAD_REQUEST);
        }

        if (userRepository.existsByUsername(signUpRequest.getUsername())) {
            return new ResponseEntity(new ApiResponse(false, "Username already taken"), HttpStatus.BAD_REQUEST);
        }

        // Creating User
        User user = new User(signUpRequest.getUsername(), signUpRequest.getEmail(), passwordEncoder.encode(signUpRequest.getPassword()),
                signUpRequest.getFirstName(), signUpRequest.getMiddleName(), signUpRequest.getLastName());

//      Role userRole = roleRepo.findByName(RoleName.ROLE_USER)
//              .orElseThrow(() -> new AppException("User Role not set."));
//
//      Role adminRole = roleRepo.findByName(RoleName.ROLE_ADMIN)
//              .orElseThrow(() -> new AppException("User Role not set."));
//
//      Set<Role> rules = new HashSet<>();
//      rules.add(userRole);
//      rules.add(adminRole);
//      user.setRoles(rules);

        User result = userRepository.save(user);

        return ResponseEntity.ok(result);
    }

    @PostMapping("/authenticateUser")
    public ResponseEntity<?> authenticateUser(@Valid @RequestBody LoginRequest loginRequest) {
        try {
        Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(
                        loginRequest.getUsernameOrEmail(),
                        loginRequest.getPassword()
                )
        );
        SecurityContextHolder.getContext().setAuthentication(authentication);
        String accessToken = tokenProvider.generateAccessToken(authentication);
        return ResponseEntity.ok(new JwtAuthenticationResponse(accessToken,tokenProvider.getIssuedDateFromAccessToken(accessToken),tokenProvider.getExpirationDateFromAccessToken(accessToken)));
        } catch (BadCredentialsException exception) {
            throw new BadRequestException("Wrong username or password!");
        }
    }

}

node controler:

@RestController
@RequestMapping("/api/node/auth")
public class NodeAuthController {

    @Autowired
    private User1Repository user1Repository;

    @Autowired
    private Role1Repository role1Repository;

    @Autowired
    private  PasswordEncoder passwordEncoder;

    @Autowired
    private  AuthenticationManager authenticationManager1;

    @Autowired
    private JwtTokenProvider1 tokenProvider1;

    @PostMapping(path = "/registerNode")
    public ResponseEntity<?> registerUser(@Valid @RequestBody SignUpRequest signUpRequest) {
        if (user1Repository.existsByEmail(signUpRequest.getEmail())) {
            return new ResponseEntity(new ApiResponse(false, "Email Address already taken"), HttpStatus.BAD_REQUEST);
        }

        if (user1Repository.existsByUsername(signUpRequest.getUsername())) {
            return new ResponseEntity(new ApiResponse(false, "Username already taken"), HttpStatus.BAD_REQUEST);
        }

        // Creating User
        User1 user1 = new User1(signUpRequest.getUsername(), signUpRequest.getEmail(), passwordEncoder.encode(signUpRequest.getPassword()),
                signUpRequest.getFirstName(), signUpRequest.getMiddleName(), signUpRequest.getLastName());

//      Role userRole = roleRepo.findByName(RoleName.ROLE_USER)
//              .orElseThrow(() -> new AppException("User Role not set."));
//
//      Role adminRole = roleRepo.findByName(RoleName.ROLE_ADMIN)
//              .orElseThrow(() -> new AppException("User Role not set."));
//
//      Set<Role> rules = new HashSet<>();
//      rules.add(userRole);
//      rules.add(adminRole);
//      user.setRoles(rules);

        User1 result = user1Repository.save(user1);

        return ResponseEntity.ok(result);
    }

    @PostMapping("/authenticateNode")
    public ResponseEntity<?> authenticateUser(@Valid @RequestBody LoginRequest loginRequest) {
        try {
        Authentication authentication = authenticationManager1.authenticate(
                new UsernamePasswordAuthenticationToken(
                        loginRequest.getUsernameOrEmail(),
                        loginRequest.getPassword()
                )
        );
        SecurityContextHolder.getContext().setAuthentication(authentication);
        String accessToken = tokenProvider1.generateAccessToken(authentication);
        return ResponseEntity.ok(new JwtAuthenticationResponse(accessToken,tokenProvider1.getIssuedDateFromAccessToken(accessToken),tokenProvider1.getExpirationDateFromAccessToken(accessToken)));
        } catch (BadCredentialsException exception) {
            throw new BadRequestException("Wrong username or password!");
        }
    }

}

If i add @Primary on one of the beans and beans is with different name code is working but only for the primary bean another bean is not use ant vot that controller auth is wrong. if no @Primary annotation i get error:java.lang.RuntimeException: java.lang.IllegalArgumentException: Found 2 beans for type interface org.springframework.security.authentication.AuthenticationManager, but none marked as primary

Comments

0

I started getting the same errors with my Grails application.

The desired authentication manager in my case was oauth2AuthenticationManager. Adding this line in spring/resources.groovy at the end of all bean definitions fixed the problem.

springConfig.getBeanConfig("oauth2AuthenticationManager").getBeanDefinition().setPrimary(true)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.