Spring injection of userdetailsservice in security config class fails - spring

I am new to spring security and i am trying to configure it using java but when i try to inject a UserDetailsService into a security config class i get a 404 error page but when i inject it into a controller the injection works. am using spring version 4.1.6 and spring security 4.0.0
here is my security config class
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
#Qualifier("loginService")
UserDetailsService loginService; //THIS IS THE POINT OF FAILURE
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/")
.usernameParameter("username")
.passwordParameter("password")
.defaultSuccessUrl("/userlist")
.failureUrl("/")
.permitAll()
.and()
.logout()
.permitAll();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
/*auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");*/
auth.userDetailsService(loginService).passwordEncoder(passwordEncoder());
}
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**");
}
#Bean
public Md5PasswordEncoder passwordEncoder(){
Md5PasswordEncoder encoder = new Md5PasswordEncoder();
return encoder;
}
}
This is the UserDetailsService class
#Service("loginService")
public class LoginService implements UserDetailsService{
#Autowired
UserRepository userRepository;
#Transactional
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
SiteUser user = userRepository.findByUsername(username);
Collection<SimpleGrantedAuthority> authorities = new ArrayList<SimpleGrantedAuthority>();
SimpleGrantedAuthority userAuthority = new SimpleGrantedAuthority("ROLE_USER");
SimpleGrantedAuthority adminAuthority = new SimpleGrantedAuthority("ROLE_ADMIN");
User u = null;
if(user == null)
throw new UsernameNotFoundException("No such User: " + username);
else
{
if (user.getRole().equals("USER"))
authorities.add(userAuthority);
else if (user.getRole().equals("ADMIN"))
{
authorities.add(userAuthority);
authorities.add(adminAuthority);
}
u = new User(user.getUsername(), user.getPassword(), authorities);
}
return u;
}
}
The rest of the project is available
here

The solution was to add
#ComponentScan("com.ashken.*")
on top of the securityconfig class

I've found that it is less troublesome to simply register your implementation of UserDetailsService as a bean in SecurityConfig:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
UserRepository userRepository;
#Bean
public UserDetailsService userDetailsService() {
return new UserDetailsService() {
#Transactional
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
SiteUser user = userRepository.findByUsername(username);
Collection<SimpleGrantedAuthority> authorities = new ArrayList<SimpleGrantedAuthority>();
SimpleGrantedAuthority userAuthority = new SimpleGrantedAuthority("ROLE_USER");
SimpleGrantedAuthority adminAuthority = new SimpleGrantedAuthority("ROLE_ADMIN");
User u = null;
if(user == null) {
throw new UsernameNotFoundException("No such User: " + username);
} else {
if (user.getRole().equals("USER")) {
authorities.add(userAuthority);
} else if (user.getRole().equals("ADMIN")) {
authorities.add(userAuthority);
authorities.add(adminAuthority);
}
u = new User(user.getUsername(), user.getPassword(), authorities);
}
return u;
}
};
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/")
.usernameParameter("username")
.passwordParameter("password")
.defaultSuccessUrl("/userlist")
.failureUrl("/")
.permitAll()
.and()
.logout()
.permitAll();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
/*auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");*/
auth.userDetailsService(loginService).passwordEncoder(passwordEncoder());
}
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**");
}
#Bean
public Md5PasswordEncoder passwordEncoder(){
Md5PasswordEncoder encoder = new Md5PasswordEncoder();
return encoder;
}
}

Related

User Authorization with custom roles

My database is a table with Users with {Username, Password, Role}. This role can either be Administrator or student.
I want my security Config file to permit some pages for students while others are only for administrators. For now this SecurityConfig looks like this...
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/api/auth/**")
.permitAll()
.antMatchers("/api/reservation").hasRole("administrator")
.antMatchers("/api/reservation/**").hasRole("student")
.antMatchers("/api/rooms/**")
.permitAll()
.antMatchers("/v2/api-docs",
"/configuration/ui",
"/swagger-resources/**",
"/configuration/security",
"/swagger-ui.html",
"/webjars/**")
.permitAll()
.anyRequest()
.authenticated();
http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
}
I think you also need my UserDetailsImplementation in order to help:
#Service
#AllArgsConstructor
public class UserDetailsServiceImpl implements UserDetailsService {
private final UserRepo userRepository;
#Override
#Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username) {
Optional<User> userOptional = userRepository.findByUsername(username);
User user = userOptional.orElseThrow(() -> new UsernameNotFoundException("No user " + "Found with username : " + username));
String rol = "";
if (user.getRole().equals("administrator")) {
rol = "ADMIN";
}
else if (user.getRole().equals("student")) {
rol = "STUDENT";
}
return new org.springframework.security
.core.userdetails.User(user.getUsername(), user.getPassword(),
user.isEnabled(), true, true,
true, getAuthorities(rol));
}
private Collection<? extends GrantedAuthority> getAuthorities(String role) {
return singletonList(new SimpleGrantedAuthority(role));
}
}
I already tried the SecurityConfig with .hasRole("student"), etc. But it didn't work.
I found this old project of mine that worked with a inMemory DB and used this:
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// users worden hier gedefined
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
auth
.inMemoryAuthentication()
.withUser("user").password(encoder.encode("t")).roles("USER")
.and()
.withUser("admin").password(encoder.encode("t")).roles("ADMIN", "USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// welke httprequests afgeschermd moeten worden
http
.authorizeRequests()
// hier patronen definieren die moeten matchen
.antMatchers("/").hasRole("USER")
.antMatchers("/maincontroller/add-bus").hasRole("ADMIN")
.antMatchers("/maincontroller/add-team").hasRole("ADMIN")
.antMatchers("/maincontroller/add-speler").hasRole("ADMIN")
.antMatchers("/maincontroller/add-wedstrijd").hasRole("ADMIN")
.antMatchers("/maincontroller/update-bus/*").hasRole("ADMIN")
.antMatchers("/maincontroller/update-team/*").hasRole("ADMIN")
.antMatchers("/maincontroller/update-speler/*").hasRole("ADMIN")
.antMatchers("/maincontroller/update-wedstrijd/*").hasRole("ADMIN")
.antMatchers("/maincontroller/delete-bus/*").hasRole("ADMIN")
.antMatchers("/maincontroller/delete-team/*").hasRole("ADMIN")
.antMatchers("/maincontroller/delete-speler/*").hasRole("ADMIN")
.antMatchers("/maincontroller/delete-wedstrijd/*").hasRole("ADMIN")
.antMatchers("/maincontroller/*").hasRole("USER")
.antMatchers("/api/**").permitAll()
So to summarize my problem: I would like to link the roles in my database with the hasRole() function in my securityConfig.
Thanks in advance!

Spring Security multiple UserDetailsService

I have 3 different tables and every table has user-information. (Maybe the same username but different passwords)
Also, have 3 different URLs for authorization. Is it possible to use multiple UserDetailsService with one configuration and during authorization control which table to use?
Here is my configuration code but I can't control which table to use during authorization:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
#Import(SecurityProblemSupport.class)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final AuthenticationManagerBuilder authenticationManagerBuilder;
#Qualifier("userDetailsService")
private final UserDetailsService userDetailsService;
#Qualifier("customerDetailsService")
private final UserDetailsService customerDetailsService;
private final TokenProvider tokenProvider;
private final CorsFilter corsFilter;
private final SecurityProblemSupport problemSupport;
public SecurityConfiguration(AuthenticationManagerBuilder authenticationManagerBuilder, UserDetailsService userDetailsService, UserDetailsService customerDetailsService, TokenProvider tokenProvider, CorsFilter corsFilter, SecurityProblemSupport problemSupport) {
this.authenticationManagerBuilder = authenticationManagerBuilder;
this.userDetailsService = userDetailsService;
this.customerDetailsService = customerDetailsService;
this.tokenProvider = tokenProvider;
this.corsFilter = corsFilter;
this.problemSupport = problemSupport;
}
#PostConstruct
public void init() {
try {
authenticationManagerBuilder
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder())
.and()
.userDetailsService(customerDetailsService)
.passwordEncoder(passwordEncoder());
} catch (Exception e) {
throw new BeanInitializationException("Security configuration failed", e);
}
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(HttpMethod.OPTIONS, "/**")
.antMatchers("/app/**/*.{js,html}")
.antMatchers("/i18n/**")
.antMatchers("/content/**")
.antMatchers("/swagger-ui/index.html")
.antMatchers("/test/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
.exceptionHandling()
.authenticationEntryPoint(problemSupport)
.accessDeniedHandler(problemSupport)
.and()
.csrf()
.disable()
.headers()
.frameOptions()
.disable()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/register").permitAll()
.antMatchers("/api/activate").permitAll()
.antMatchers("/api/authenticate").permitAll()
.antMatchers("/api/account/reset-password/init").permitAll()
.antMatchers("/api/account/reset-password/finish").permitAll()
.antMatchers("/api/**").authenticated()
.antMatchers("/management/health").permitAll()
.antMatchers("/management/info").permitAll()
.antMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/v2/api-docs/**").permitAll()
.antMatchers("/swagger-resources/configuration/ui").permitAll()
.antMatchers("/swagger-ui/index.html").hasAuthority(AuthoritiesConstants.ADMIN)
.and()
.apply(securityConfigurerAdapter());
}
private JWTConfigurer securityConfigurerAdapter() {
return new JWTConfigurer(tokenProvider);
}
}
userDetailsService and customerDetailsService are my UserDetailsService implementations that use different tables for check credential. But I can't control exactly which UserDetailsService to use when a request came.
You can use this article
https://sanketdaru.com/blog/multiple-sources-user-details-spring-security/ .
It has example in which it defines two services in service and use that single service. Just like my code of user detail service.
#Override
public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {
List<UserEntity> users = userRepository.findByName(name);
if (users.isEmpty()){
return inMemoryUserDetailsService.loadUserByUsername(name);
}
return new UserDetailEntity (users.get(0));
}
#PostConstruct
public void init() {
this.inMemoryUserDetailsService = initInMemoryUserDetailsService();
}
private UserDetailsService initInMemoryUserDetailsService() {
List<UserDetails> userDetails = new ArrayList<>();
UserDetails userDetails1 = new User("user1", "$2a$10$t/U97dFDQ0e8ujCq6728P.E1axs/aoAMsopoSUQtTchiKTP/Ps4um", Collections.singletonList(new SimpleGrantedAuthority("USER")));
UserDetails userDetails2 = new User("admin1", "$2a$10$t/U97dFDQ0e8ujCq6728P.E1axs/aoAMsopoSUQtTchiKTP/Ps4um", Arrays.asList(new SimpleGrantedAuthority("USER"),new SimpleGrantedAuthority("ADMIN")));
userDetails.add(userDetails1);
userDetails.add(userDetails2);
return new InMemoryUserDetailsManager(userDetails);
}
Please try it in WebSecurityConfigurerAdapter
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(yourCustomUserDetailsService).passwordEncoder(passwordEncoder);
}

Spring security: My Authorization filter authorizes my request even tho the URL is permited

In my security configuration class i have permitted the request to the welcome url and any other url which follows the "welcome/**" format.
this is my securityconfiguration class:
#EnableGlobalMethodSecurity(prePostEnabled = true)
//#Configuration
#EnableWebSecurity
public class JwtSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
private final CustomerDetailsService customerDetailsService;
#Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
#Autowired
public JwtSecurityConfiguration(CustomerDetailsService customerDetailsService) {
this.customerDetailsService = customerDetailsService;
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(customerDetailsService)
.passwordEncoder(passwordEncoderBean());
}
#Bean
public PasswordEncoder passwordEncoderBean() {
return new BCryptPasswordEncoder();
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("**/resources/static/**")
.and()
.ignoring()
.antMatchers(
HttpMethod.GET,
"/",
"/*.html",
"/favicon.ico",
"/**/*.html",
"/**/*.css",
"/**/*.js",
"/index_assets/**"
);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/welcome/login").permitAll()
.antMatchers("/welcome").permitAll()
.antMatchers("/welcome/signup").permitAll()
.antMatchers("admin/rest/**").authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler)
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
//http.addFilterBefore(new JWTAuthenticationFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class);
http.addFilterBefore(new JWTAuthorizationFilter(authenticationManager(),customerDetailsService),UsernamePasswordAuthenticationFilter.class);
// disable page caching
http
.headers()
.frameOptions().sameOrigin() // required to set for H2 else H2 Console will be blank.
.cacheControl();
//http.headers().cacheControl();
}
}
but I noticed that in my JWTAuthorizationFilter.class the doFilterInternal() method picks up this URL
public class JWTAuthorizationFilter extends OncePerRequestFilter {
private final CustomerDetailsService customerDetailsService;
#Autowired
DefaultCookieService defaultCookieService;
public JWTAuthorizationFilter(AuthenticationManager authenticationManager, CustomerDetailsService customerDetailsService) {
// super(authenticationManager);
this.customerDetailsService = customerDetailsService;
}
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
String header = request.getHeader(HEADER);
if(Objects.isNull(header) || !header.startsWith(TOKEN_PREFIX)){
return;
}
UsernamePasswordAuthenticationToken usernamePasswordAuth = getAuthenticationToken(request);
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuth);
chain.doFilter(request,response);
}
private UsernamePasswordAuthenticationToken getAuthenticationToken(HttpServletRequest request){
String token = request.getHeader(HEADER);
if(Objects.isNull(token)) return null;
String username = Jwts.parser().setSigningKey(SECRET)
.parseClaimsJws(token.replace(TOKEN_PREFIX,""))
.getBody()
.getSubject();
UserDetails userDetails = customerDetailsService.loadUserByUsername(username);
return username != null ? new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()) : null;
}
}
What is the cause of this ?
Filter is suppose to pick up each and every request. It doesn't matter if that you have permitted or not in security configuration.
You have got two options:
If you don't want welcome/** to go through the filter you add it to web ignore
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("**/resources/static/**")
.and()
.ignoring()
.antMatchers(
HttpMethod.GET,
"/",
"/*.html",
"/favicon.ico",
"/**/*.html",
"/**/*.css",
"/**/*.js",
"/index_assets/**",
"/welcome/**"
);
}
But note, it will skip all filters and you may not want that.
In doFilterInternal method skip it when you find welcome/** pattern.

Spring-boot Spring Security; Users without the correct roles are still accessing role-specific pages

I am attempting to make a web page that is only accessible by the 'Admin' role, however all users are able to access it. I have User and Role entities with a functioning ManyToMany relationship set up.
Here is my SecurityConfig.java:
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserService userService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(
"/registration",
"/js/**",
"/css/**",
"/img/**",
"/webjars/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.authorizeRequests()
.antMatchers("/competition/**").hasRole("Admin")
.and()
.logout()
.invalidateHttpSession(true)
.clearAuthentication(true)
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login?logout")
.permitAll();
}
#Bean
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
#Bean
public DaoAuthenticationProvider authenticationProvider(){
DaoAuthenticationProvider auth = new DaoAuthenticationProvider();
auth.setUserDetailsService(userService);
auth.setPasswordEncoder(passwordEncoder());
return auth;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
as you can see with the line
.antMatchers("/competition/**").hasRole("Admin")
I'm trying to make link /competition/** admin-only.
Here is the controller:
#Controller
public class CompetitionController {
#Autowired
CompetitionRepository competitionRepository;
#GetMapping("/competition/{competitors}")
public String match(ModelMap map, #PathVariable(value = "competitors") String competitors, Principal principal) {
String[] parts = competitors.split("-");
String part1 = parts[0];
String part2 = parts[1];
map.addAttribute("part1", part1);
map.addAttribute("part2", part2);
return "match";
}
}
Finally here is my UserService:
#Service
public class UserServiceImpl implements UserService {
#Autowired
private UserRepository userRepository;
#Autowired
private BCryptPasswordEncoder passwordEncoder;
#Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
User user = userRepository.findByEmail(email);
if (user == null){
throw new UsernameNotFoundException("Invalid username or password.");
}
return new org.springframework.security.core.userdetails.User(user.getEmail(),
user.getPassword(),
mapRolesToAuthorities(user.getRoles()));
}
public User findByEmail(String email){
return userRepository.findByEmail(email);
}
public User save(UserRegistrationDto registration){
User user = new User();
user.setFirstName(registration.getFirstName());
user.setLastName(registration.getLastName());
user.setEmail(registration.getEmail());
user.setPassword(passwordEncoder.encode(registration.getPassword()));
user.setRoles(Arrays.asList(new Role("ROLE_USER")));
User userAdmin = userRepository.findByEmail("admin#email.com");
if (userAdmin == null){
userAdmin = new User();
userAdmin.setFirstName("Admin");
userAdmin.setLastName("");
userAdmin.setEmail("admin#email.com");
userAdmin.setPassword(passwordEncoder.encode("admin"));
userAdmin.setRoles(Arrays.asList(new Role("ROLE_Admin")));
userRepository.save(userAdmin);
}
return userRepository.save(user);
}
private Collection<? extends GrantedAuthority> mapRolesToAuthorities(Collection<Role> roles){
return roles.stream()
.map(role -> new SimpleGrantedAuthority(role.getName()))
.collect(Collectors.toList());
}
}
I attempted to change .hasRole to .hasAuthority as seen in this answer (to no avail): Spring Security Java configuration for authenticated users with a role.

spring security - role based access

I have implemented spring security for my webapp.
I want to configure role based access. Only users with the role "ROLE_ADMIN" should be abeĺe to login.
I added the model "Role" and added a table in my database.
However users with the role "ROLE_USER" are still able to login.
#Override
protected void configure(HttpSecurity http) {
try {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/resources/**").hasRole("ROLE_ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
} catch (Exception e) {
e.printStackTrace();
}
}
Thanks!
Edit: complete spring security config
#Configuration
#EnableWebSecurity
#ComponentScan(basePackageClasses = UserDetailsServiceImpl.class)
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
public void configure(WebSecurity web) {
web.ignoring().antMatchers("/css/**", "/js/**");
}
#Override
protected void configure(HttpSecurity http) {
try {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/resources/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
} catch (Exception e) {
e.printStackTrace();
}
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
authProvider.setPasswordEncoder(bCryptPasswordEncoder());
return authProvider;
}
#Autowired
public void globalSecurityConfiguration(AuthenticationManagerBuilder auth) {
try {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
} catch (Exception e) {
e.printStackTrace();
}
}
}
Are you extending WebMvcConfigurerAdapter ? Also hasRole will prefix the provided string with "ROLE_"
from doc:
the role to require (i.e. USER, ADMIN, etc). Note, it should not start with "ROLE_" as this is automatically inserted.
example:
#SpringBootApplication
public class SampleWebSecureJdbcApplication extends WebMvcConfigurerAdapter {
public static void main(String[] args) throws Exception {
new SpringApplicationBuilder(SampleWebSecureJdbcApplication.class).run(args);
}
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
protected static class ApplicationSecurity extends WebSecurityConfigurerAdapter {
#Autowired
private DataSource dataSource;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/resources/**", "/signup", "/about").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/login").failureUrl("/login?error").permitAll()
.and()
.logout().permitAll();
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(this.dataSource);
}
}
}
I have implemented a Role based access where after the login admin user will be directed to the admin homepage and normal user will be redirected to the user homepage.
Below is my SecurityConfiguration class.
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
#Autowired
private DataSource dataSource;
#Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
final String sqlUserName = "select email, password, active from user where email=?";
final String sqlAuthorities= "select u.email, r.role from user u inner join user_role ur on(u.user_id=ur.user_id) inner join role r on(ur.role_id=r.role_id) where u.email=?";
auth.
jdbcAuthentication()
.usersByUsernameQuery(sqlUserName)
.authoritiesByUsernameQuery(sqlAuthorities)
.dataSource(dataSource)
.passwordEncoder(bCryptPasswordEncoder);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http. authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/login").permitAll()
.antMatchers("/registration").permitAll()
.antMatchers("/resources/**", "/static/**", "/static.css/**", "/js/**", "/static.images/**").permitAll()
.antMatchers("/user").hasAuthority("USER")
.antMatchers("/home").hasAuthority("ADMIN").anyRequest()
.authenticated().and().csrf().disable().formLogin()
.loginPage("/login").failureUrl("/login?error=true")
.defaultSuccessUrl("/loginroute",true)
.usernameParameter("email")
.passwordParameter("password")
.and().logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/").and().exceptionHandling()
.accessDeniedPage("/access-denied");
}
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**", "/static/**", "/static.css/**", "/js/**", "/static.images/**");
}
}
.defaultSuccessUrl("/loginroute",true) will redirect to the /loginroute controller. Below is the controller methods.
#RequestMapping (value = "/loginroute",method = RequestMethod.GET)
public String sample(){
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
User user = userService.findUserByEmail(auth.getName());
String rolevalue = null;
for (Role role : user.getRoles()) {
rolevalue = role.getRole();
}
System.out.println(user.getRoles().contains("role"));
if(rolevalue.equals("ADMIN"))
return "redirect:home";
else if(rolevalue.equals("USER"))
return "redirect:user";
return "User does not have permission";
}
#RequestMapping(value="/home", method = RequestMethod.GET)
public ModelAndView home(){
ModelAndView modelAndView = new ModelAndView();
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
User user = userService.findUserByEmail(auth.getName());
modelAndView.addObject("userName", "Welcome " + user.getName() + " " + user.getLastName() + " (" + user.getEmail() + ")");
modelAndView.addObject("adminMessage","Content Available Only for Users with Admin Role");
modelAndView.setViewName("home");
return modelAndView;
}
#RequestMapping(value="/user", method = RequestMethod.GET)
public ModelAndView userhome(){
ModelAndView modelAndView = new ModelAndView();
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
User user = userService.findUserByEmail(auth.getName());
modelAndView.addObject("userName", "Welcome user: " + user.getName() + " " + user.getLastName() + " (" + user.getEmail() + ")");
modelAndView.addObject("userMessage","Content Available Only for Users with User Role");
modelAndView.setViewName("user");
return modelAndView;
}

Resources