I am following the documentation from Spring.io to setup user authentication using Spring Boot.
Here are the files in question:
MvcConfig.java
package com.*********.*******;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
#Configuration
public class MvcConfig implements WebMvcConfigurer {
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/home").setViewName("home");
registry.addViewController("/").setViewName("home");
registry.addViewController("/hello").setViewName("hello");
registry.addViewController("/login").setViewName("login");
}
}
WebSecurityConfig.java
package com.*********.*******;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
#Bean
#Override
public UserDetailsService userDetailsService() {
UserDetails user =
User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
}
How can I eliminate the home.html file and wire it so that localhost:808 takes the user directly to the login which, if successful, brings them to the hello.html file?
If I change the default controller to the following code, then it just enters a loop of the login page because the login takes you to the previous page you were trying to access. How can I instead have it send the user to hello.html?
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/home").setViewName("home");
registry.addViewController("/").setViewName("login");
registry.addViewController("/hello").setViewName("hello");
registry.addViewController("/login").setViewName("login");
}
I apologize if this post is worded poorly. If there is anything I can add for clarity, please don't hesitate to ask and I will make any corrections.
Remove the line .antMatchers("/", "/home").permitAll() so all urls are protected and redirected to login.
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
Related
So i have created a Security Config where i defined the patterns that i want to be granted access to without logging in. And it is not working. In my mind either the file its self is not getting scanned(even though i set it so it would be using #ComponentScan tag in the main Spring application) or the code is faulty.
Here is the code :
package com.projects.AProj.security;
import com.projects.AProj.service.AccountUserDetailsService;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.PasswordEncoder;
import static com.projects.AProj.security.Permission.DATA_READ;
import static com.projects.AProj.security.Permission.DATA_WRITE;
#Configuration
#EnableWebSecurity
#AllArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final PasswordEncoder passwordEncoder;
private final AccountUserDetailsService accountUserDetailsService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeRequests()
.antMatchers("/","/**","/api/**")
.permitAll()
.antMatchers("/my-tree", "/my-tree/*")
.hasAnyAuthority(DATA_READ.getPermission_info(), DATA_WRITE.getPermission_info())
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/login").permitAll()
.defaultSuccessUrl("/",true)
.and()
.logout()
.logoutSuccessUrl("/");
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(getDaoAuthenticationProvider());
}
#Bean
public DaoAuthenticationProvider getDaoAuthenticationProvider(){
DaoAuthenticationProvider daoAuthenticationProvider =
new DaoAuthenticationProvider();
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder);
daoAuthenticationProvider.setUserDetailsService(accountUserDetailsService);
return daoAuthenticationProvider;
}
}
btw i would think that it would be helpful to note that the project it self has been acting a tad bit strange. I would get errors that the Repositories are not getting recognized, stuff like can't create bean with name "baseController", unsatisfied dependencies and those kinds of stuff.
Thanks.
I have a circular dependency forming on my WebSecurityCongfig. I have tracked it down to the UserDetailsService and once I remove it it builds but I cannot perform jwt filter because of it. The interesting part is that on my other services the exact same code works flawlessly.
package com.fain.events.events.security;
import commons.src.main.java.software.commons.config.filters.ExceptionHandlerFilter;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
#Configuration
#EnableWebSecurity
#SuppressWarnings("SpringJavaAutowiringInspection")
#RequiredArgsConstructor
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Lazy
private final UserDetailsService userDetailsServiceImpl;
#Lazy
private final JwtAuthenticationEntryPoint unauthorizedHandler;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler)
.and()
.authorizeRequests()
.antMatchers(
"/favicon.ico",
"/configuration/ui",
"/configuration/security",
"/swagger-ui.html",
"/v2/api-docs",
"/swagger-resources/**",
"/healthcheck",
"/webjars/**",
"/**/*.html",
"/**/*.css",
"/**/*.js",
"/*.html")
.permitAll()
.antMatchers(
HttpMethod.POST,
"/api/auth/register",
"/api/auth/socialMedia",
"/api/auth/login",
"/api/auth/refreshToken",
"/api/auth/forgotPassword",
"/api/auth/resetPassword",
"/api/auth/facebook/login",
"/api/auth/resendRegistrationEmail",
"/api/auth/facebook/forwardLogin",
"/api/auth/google/login",
"/api/auth/validateTwoFactorAuthenticationCode",
"/api/auth/activateAccount",
"/api/auth/confirmAccount",
"/api/auth/validateToken",
"/api/auth/generateToken",
"/api/auth/confirmEmail",
"/resetPassword",
"/Callback/**")
.permitAll()
.antMatchers(HttpMethod.PATCH,"/api/users/{\\d+}/give-role/{\\d+}", "/api/users/{\\d+}/remove-role/{\\d+}").permitAll()
.antMatchers(
HttpMethod.GET,
"/resetPassword",
"/images/**",
"/settings/**",
"/confirmEmail",
"/api/location/**",
"/api/auth/facebook/login")
.permitAll()
.antMatchers(
HttpMethod.GET,
"/api/users/{\\d+}",
"/api/users/profiles"
).access(("isAuthenticated() or hasIpAddress('127.0.0.1')"))
.antMatchers(HttpMethod.OPTIONS)
.permitAll()
.anyRequest()
.authenticated()
.and()
// And filter other requests to check the presence of JWT in header
.addFilterBefore(
authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new ExceptionHandlerFilter(), JwtTokenVerificationFilter.class);
}
#Autowired
public void configureAuthentication(#Lazy AuthenticationManagerBuilder authenticationManagerBuilder)
throws Exception {
authenticationManagerBuilder
.userDetailsService(this.userDetailsServiceImpl)
.passwordEncoder(new BCryptPasswordEncoder());
}
#Bean
public JwtTokenVerificationFilter authenticationTokenFilterBean() throws Exception {
JwtTokenVerificationFilter authenticationTokenFilter = new JwtTokenVerificationFilter();
authenticationTokenFilter.setAuthenticationManager(authenticationManagerBean());
return authenticationTokenFilter;
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
#Lazy
#Override
public UserDetailsService userDetailsService() {
return super.userDetailsService();
}
}
Here is the circular dependency error
I'm trying to use authenticate using in-memory users but i always keep getting "bad credentials" even when they are right .
WebSecurityConfig.java:
package com.skillshare.project.config;
import org.springframework.context.annotation.Configuration;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers( "/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll()
.and()
.logout()
.permitAll();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("test").password("{noop}test").roles("USER");
}
}
Why #PreAuthorize doesn't work? It does not throw any exceptions or errors. I have been struggling with this task for several days. I've tried many options but It doesn't work.
I will be very grateful to anyone who can help solve this problem.
SecurityConfig.java
package com.testpreauthorize.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
UserDetailsService userDetailsService;
#Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest()
.permitAll()
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/")
.and()
.logout()
.permitAll()
.logoutUrl("/logout")
.logoutSuccessUrl("/")
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
.and()
.csrf().disable();
}
}
HomeController.java
package com.testpreauthorize.controller;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
#Controller
public class HomeController {
#GetMapping(value = "/")
public String home () {
return "/home";
}
#PreAuthorize("isAuthenticated()")
#GetMapping(value = "/user")
public String user () {
return "/user";
}
#GetMapping(value = "/login")
public String loginGet () {
return "/login";
}
#PostMapping(value = "/login")
public String loginPost () {
return "redirect:/user";
}
}
I have a fundamental problem with spring boot application. The start webpage is http://127.0.0.1:8080/login and after log in user is redirect to http://127.0.0.1:8080/MainMenu. Unfortunatelly it is also possible to write in url bar http://127.0.0.1:8080/MainMenu and going there without authentication.
What is the main idea to block that action?
#edit
This is my configuration:
package local.vlex.security;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "src/main/resources/static/assets/css/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
}
and Controller:
#GetMapping("/MainMenu")
public ModelAndView correctCredentials(){
ModelAndView mav = new ModelAndView();
mav.setViewName("MainMenu");
return mav;
}
Sum up:
I would like to block going to other sites without authentication - if someone is not logged in then it should go 404 on everything other than /login
if someone is not logged in then it should go 404 on everything other
than /login
This is a bit pecular requirement. What is usually done is that people get redirected to login page on all other urls than login, or get 401 Unauthorized or 403 Forbidden. However, it's not hard to do this one either.
You mentioned you need your static resources (css, js, images) in the assets directory as well, so given that, this should work:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
#Configuration
#EnableWebSecurity
public class YourSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login", "/assets/**").permitAll()
.anyRequest().authenticated()
.and()
.exceptionHandling()
.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.NOT_FOUND))
;
}
}
Using
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
</parent>
and
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
in Maven pom.xml
Note that there is also accessDeniedHandler() in exceptionHandling(), but that seems to only fire when user is already authenticated but denied access, so you'd need authenticationentrypoint for your use case.
Addition:
Sometimes having a custom authentication entrypoint messes the existing entry point handler. That is the case at least if you use default spring-generated form login. One way to go around that is to specify your entrypoint to only match urls that are not matching your authentication handler url, like this:
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
// snip...
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login", "/assets/**").permitAll()
.anyRequest().authenticated()
.and()
.exceptionHandling()
.defaultAuthenticationEntryPointFor(new HttpStatusEntryPoint(HttpStatus.NOT_FOUND),
new NegatedRequestMatcher(new AntPathRequestMatcher("/login")) )
.and()
.formLogin()
;
}
Add the following code, It will block all the request except "/" & "/login"
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers(
"/css/**",
"/js/**",
"/lib/**",
"/video/**",
"/images/**"
);
}
}
And add WebConfig
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter{
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/**")
.addResourceLocations("classpath:/static/")
.setCachePeriod(31556926)
.resourceChain(true);
}
}
Don't forget to add the security dependency in your pom.xml file.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Provided that you have spring-security dependencies on classpath, this is a working example from my code.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "/login**")
.permitAll()
.anyRequest()
.authenticated();
This blocks me from any other requests than '/' or 'login' or 'loginPage' etc. with Authorization.
Follow that with ignoring the static ones, css, js etc.,
If this still doesn't work, for now try working on blocking the page alone:
http.authorizeRequests()
.antMatchers("/MainMenu")
.authenticated();
The above would give idea what's happening. Dependency issue or something like that.