Spring boot security login verify failed - spring

I want to verify the user's identity when he or she send a localhost:8080/submit request, so I added the following to SecurityConfig class:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/submit").access("hasRole('WORKER')")
.antMatchers("/**").permitAll()
.and()
.formLogin()
.loginPage("/login")
.and()
.logout()
.logoutSuccessUrl("/")
.and()
.rememberMe()
.tokenValiditySeconds(4838400)
.key("workerKey");
}
I wish the page could redirect to localhost:8080/login when I input localhost:8080/submit in the address field. My Worker entity has the role "WORKER":
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Arrays.asList(new SimpleGrantedAuthority("WORKER"));
}
I can register an account and redirect to the login page when I input "localhost:8080/submit". But when I input the correct username and password, it responds to me an error page instead of submit page:
There was an unexpected error (type=Forbidden, status=403).
Forbidden
My submit page is simply a "welcome" word page. My mappings are
#RequestMapping(value = "/login", method = RequestMethod.GET)
public String showLogin() {
return "login";
}
#RequestMapping(value = "/submit", method = RequestMethod.GET)
public String showSubmit() {
return "submit";
}
And when I input localhost:8080/submit again, it did not redirect to the login page this time. Instead, it redirects to the error page directly and show the same error. So what forbid me to redirect to the submit page?

#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().fullyAuthenticated()
.antMatchers("/submit").hasRole("WORKER").and().formLogin().permitAll().and().logout().permitAll();
}
#Bean
public UserDetailsService userDetailsService() {
// ensure the passwords are encoded properly
#SuppressWarnings("deprecation")
UserBuilder users = User.withDefaultPasswordEncoder();
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(users.username("me").password("me").roles("WORKER").build());
return manager;
}
}
You can customize even more with your custom login page.

I have find the problem myself. I need to change the role "WORKER" in the Worker class to "ROLE_WORKER". Like this
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Arrays.asList(new SimpleGrantedAuthority("ROLE_WORKER"));
}
It seems I cannot simplify the role "ROLE_WORKER" into "WORKER" in the Worker class but can simplify it in the SecurityConfig class.

Related

Spring Security not letting unauthorized users reach the login page

I am using Spring Security and trying to add a custom login form, the browser does get redirected to the correct URL but I get a message along the lines of
The page isn’t redirecting properly
and can't see the login page at all.
Under the network tab (when I press F12) I see multiple requests to my custom login page, so I'm guessing Spring sees I'm unauthorized then redirects me to the login page over and over effectively creating a loop.
This is the code for my security configuration:
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/showMyLoginPage")
.permitAll();
return http.build();
}
Tried removing the loginPage() bit, solving the issue but yielding the default login page.
requested image
Request and response show no info..
Controller I'm using
#Controller
public class MainController {
#RequestMapping("/")
public String testMapping()
{
return "home";
}
#RequestMapping("/showMyLoginPage")
public String loginPage()
{
return "users-login";
}
}
My debug log: https://pastebin.com/LagTN71L
My configuration classes: (won't show hibernate or c3p0)
#Configuration
#EnableWebMvc
#ComponentScan("com.user.springsecuritydemo")
public class MainConfig implements WebMvcConfigurer {
#Bean
InternalResourceViewResolver configuInternalResourceViewResolver()
{
return new InternalResourceViewResolver("/WEB-INF/view/", ".jsp");
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
registry
.addResourceHandler("/resources/**")
.addResourceLocations("/resources/");
}
}
public class SpringMVCDispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses()
{
// TODO Auto-generated method stub
return null;
}
#Override
protected Class<?>[] getServletConfigClasses()
{
return new Class[] { MainConfig.class };
}
#Override
protected String[] getServletMappings()
{
return new String[] { "/" };
}
}
Okay, I ended up fixing it, so basically my jsp page is under my /WEBINF/ directory, which was not allowed for everyone to access therefore the browser couldn't get to the login page...
This is my SecurityFilterChain method:
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception
{
http
.authorizeHttpRequests()
.requestMatchers("/WEB-INF/**")
.permitAll();
http.authorizeHttpRequests()
.anyRequest()
.authenticated();
http
.formLogin()
.loginPage("/login")
.permitAll();
return http.build();
}

Spring Custom Security With MySQL And JPA Giving 403 Access Denied

I am trying to access my rest api on postman by providing authentication using UserDetailsService, but each time I am firing the request every time request giving 403 Access Denied. The behavior is same for POST and GET method. I have read the other issues logged on forum but every answers says it is due to CSRF, I disabled it but issue remains same.
Complete code is on : https://github.com/afulz29/spring-security-demo.git
Please help me, I am struggling with this issue since 3 days.
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class ApplicationSecurityConfig extends WebSecurityConfigurerAdapter implements WebMvcConfigurer{
#Autowired
UserDetailsService userDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http
.authorizeRequests()
.antMatchers("/api/**").authenticated().anyRequest().hasAnyRole("ADMIN");
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedMethods("*");
}
}
#RestController
#RequestMapping("/api")
public class UserController {
#Autowired
private UserService userService;
#GetMapping(path = "/users")
public User getUserById(#RequestParam("userId") Integer userId) {
return userService.getUserById(userId);
}
#PostMapping(path = "/users", consumes = MediaType.APPLICATION_JSON_VALUE)
public User addUser(#RequestBody User user) {
return userService.addUser(user);
}
}
I see couple of problems with your security config:
BASIC AUTH is not enabled but you are trying to do Basic Auth in postman
Do the following to enable Basic Auth
http
.authorizeRequests()
...
.and()
.httpBasic();
I guess the POST /api/users is a user registration endpoint. You must whitelist this endpoint so that anyone can register
http
.authorizeRequests()
.antMatchers( HttpMethod.POST,"/api/users").permitAll()
.antMatchers("/api/**").authenticated()
.anyRequest().hasAnyRole("ADMIN")
.and()
.httpBasic();
Test:
Create user
POST: localhost:8080/api/users
{
"userName" : "user1",
"password": "pass"
}
Get user info
GET: localhost:8080/api/users?userId=1 //use the correct ID
With Basic Auth: userName = user1, password = pass
BONUS Feedback:
User.userName --> you might want to make this field unique
#Repository this annotation is not required in your Repository interfaces
UserService interface. I don't see any reason to use the interface and impl.

successForwardUrl does not work with Spring Social after authenticating successfully

I'm working on a Spring Boot project integrating with Spring Social. After authenticating with google successfully, I want to redirect to the end point /userInfo, but it seems to redirect to the previous page where I make a request to authenticate to Google: http://localhost:8080/auth/google
I've also tried to create a bean CustomAuthenticationSuccessHandler, which implements the AuthenticationSuccessHandler and add that to the configuration file, but it didn't work either
My WebSecurityConfiguration:
#Configuration
#EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
DataSource dataSource;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
// This bean is load the user specific data when form login is used.
#Override
public UserDetailsService userDetailsService() {
return userDetailsService;
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
// Enable jdbc authentication
#Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication()
.dataSource(dataSource)
.passwordEncoder(passwordEncoder())
.usersByUsernameQuery("select user_name, encryted_password"
+ " from app_user where user_name=?");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
// Pages do not require login
http.authorizeRequests()
.antMatchers("/", "/signup", "/login", "/logout")
.permitAll();
http.authorizeRequests()
.antMatchers("/user/**")
.access("hasRole('" + AppRole.ROLE_USER + "')");
// For ADMIN only.
http.authorizeRequests()
.antMatchers("/admin/**")
.access("hasRole('" + AppRole.ROLE_ADMIN + "')");
// When the user has logged in as XX.
// But access a page that requires role YY,
// AccessDeniedException will be thrown.
http.authorizeRequests()
.and()
.exceptionHandling()
.accessDeniedPage("/403");
// Form Login config
http.authorizeRequests()
.and()
.formLogin()
.loginProcessingUrl("/j_spring_security_check") // the url to submit the username and password to
.loginPage("/login") // the custom login page
.successForwardUrl("/userInfo") // the landing page after a successful login
.failureUrl("/login?error=true") // the landing page after an unsuccessful login
.usernameParameter("username")
.passwordParameter("password");
// Logout Config
http.authorizeRequests()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/logoutSuccessful");
http.apply(new SpringSocialConfigurer())
.signupUrl("/signup");
}
}
MyController:
#RestController
#Transactional
public class MainController {
#Autowired
private AppUserDAO appUserDAO;
#Autowired
private ConnectionFactoryLocator connectionFactoryLocator;
#Autowired
private UsersConnectionRepository userConnectionRepository;
#Autowired
private AppUserValidator appUserValidator;
#RequestMapping(value = {"/", "/welcome"}, method = RequestMethod.GET)
public String welcomePage(Model model) {
model.addAttribute("title", "Welcome");
model.addAttribute("message", "This is welcome page!");
return "welcomePage";
}
#RequestMapping(value = "/logoutSuccessful", method = RequestMethod.GET)
public String logoutSuccessfulPage(Model model) {
model.addAttribute("title", "Logout");
return "logoutSuccessfulPage";
}
#RequestMapping(value = "/userInfo", method = RequestMethod.GET)
public String userInfo(Model model, Principal principal) {
// After user login successfully.
String userName = principal.getName();
System.out.println("User Name: " + userName);
UserDetails loginedUser = (UserDetails) ((Authentication) principal).getPrincipal();
String userInfo = WebUtils.toString(loginedUser);
model.addAttribute("userInfo", userInfo);
return "userInfoPage";
}
Are there any ways to forward to /userInfo url after logging in with Spring Social ?
Try in POST "/userInfo" return "redirect:/userInfoPage".

Auth websocket session after manual web auth

I am using Spring Security with STOMP WebSocket on SpringBoot. Auth on websocket worked fine with this config when I used simple login form:
#EnableWebSecurity
#Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/webjars/**", "/resources/**").permitAll()
.antMatchers("/register").anonymous()
.anyRequest()
.fullyAuthenticated()
.and()
.formLogin()
.loginPage("/login")
.successHandler(customLoginSuccessHandler)
.failureUrl("/login?error")
.permitAll()
.and()
.csrf().disable()
.logout().logoutSuccessHandler(customLogoutSuccessHandler);
}
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
#Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
messages
.nullDestMatcher().authenticated()
.simpTypeMatchers(CONNECT).authenticated()
.simpSubscribeDestMatchers(Channel.SYSTEM_ERROR.value()).permitAll()
.simpDestMatchers("/app/publish*").hasRole("USER")
.simpSubscribeDestMatchers("/user/**", "/topic/**", "/system/*").hasRole("USER")
.anyMessage().denyAll();
}
But when I wanted to manually auth client after register new user in RegisterController:
#RequestMapping(value = "/register", method = RequestMethod.POST)
public String signup(#Valid #ModelAttribute SignupForm signupForm, Errors errors) {
if (errors.hasErrors()) {
return SIGNUP_VIEW_NAME;
}
User user = signupForm.createAccount();
try {
userService.persist(user);
} catch (EntityExistsException ex) {
errors.rejectValue("login", "user.exists");
return SIGNUP_VIEW_NAME;
}
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(user, null, Collections.singletonList(new SimpleGrantedAuthority("USER"))));
return "redirect:/";
}
I've got problem with auth websocket. When I get redirected to page where websocket connects I am getting org.springframework.security.access.AccessDeniedException: Access is denied
So. Problem was in define Role. In controller when I defined new SimpleGrantedAuthority("USER") it should be "ROLE_USER" because Spring adds refix ROLLE_ by default. Sure we can change default behaviour of this by add next in WebSecurity configuration
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**", "/favicon.ico");
web.expressionHandler(new DefaultWebSecurityExpressionHandler() {
#Override
protected SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, FilterInvocation fi) {
WebSecurityExpressionRoot root = (WebSecurityExpressionRoot) super.createSecurityExpressionRoot(authentication, fi);
root.setDefaultRolePrefix(""); //remove the prefix ROLE_
return root;
}
});
}
. Yes, dummy mistake but so common. So I will leave it here

Not able to recognize user ROLE when redirecting page using Spring Security

I am working on my project with Spring security and Thymeleaf. I have basic Spring Security integration.
SecurityConfig.java
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
#Autowired
private DataSource dataSource;
#Autowired
public void configureGlobal (AuthenticationManagerBuilder auth) throws Exception
{
auth
.jdbcAuthentication()
.dataSource(dataSource);
}
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/success", true)
.and()
.httpBasic();
}
}
SecurityWebApplicationInitializer.java
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer
{
public SecurityWebApplicationInitializer(){
super(SecurityConfig.class);
}
}
Controller.java
#Controller
public class HomeController {
#RequestMapping(value = "/login", method = RequestMethod.GET)
public String loginPage(Model model) {
return "login";
}
#RequestMapping("/success")
public String loginPageRedirect(HttpServletRequest httpServletRequest){
if(httpServletRequest.isUserInRole("ROLE_ADMIN")) {
return "index1";
} else if(httpServletRequest.isUserInRole("ROLE_USER")) {
return "index2";
} else {
return "index3";
}
}
}
When I have successful login my user is redirected, but to wrong page. My user has role ROLE_USER but method loginPageRedirect is redirecting him to page index3 when it should be index2. I guess my user role is not recognize. How can I do that? Should I add something as parameter to loginPageRedirect so it recognizes role?
I found solution that works for me.
I edited my loginPageRedirect method like this:
#RequestMapping("/success")
public void loginPageRedirect(HttpServletRequest request, HttpServletResponse response, Authentication authResult) throws IOException, ServletException {
String role = authResult.getAuthorities().toString();
if(role.contains("ROLE_ADMIN")){
response.sendRedirect(response.encodeRedirectURL(request.getContextPath() + "/index1"));
}
else if(role.contains("ROLE_USER")) {
response.sendRedirect(response.encodeRedirectURL(request.getContextPath() + "/index2"));
}
}
Hope it helps someone with same issue :)

Resources