ErrorController while using WebSecurityConfigurerAdapter - java

I have this class where I am trying to configure WebSecurityConfigurerAdapter. This code gives me permission to / , /home and /signup without needing to get authenticated.
My question is how to implement ErrorController while using HttpSecurity
Bacially if I get the This application has no explicit mapping for /error i dont want spring boot to prompt the login page first then to display the ErrorController. I want just to execetue ErrorController
public class WebConfigAdapter extends WebSecurityConfigurerAdapter {
#Bean
public BCryptPasswordEncoder bCryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
#Override
public void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.authorizeRequests()
.antMatchers("/","/home","/signup").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
httpSecurity.csrf().disable();
}
}
My ErrorController
#Controller
public class ErrorControllerH implements ErrorController {
#Override
#RequestMapping("/error")
public String getErrorPath() {
return "redirect:/";
}
}

What did you do by using antmatchers().permitall? You could imagine as a whitelist so everybody can access declared paths of your endpoint without getting in touch with Spring Security. So any user cann access this paths without authentication.
.antMatchers("/","/home","/signup", "/error").permitAll()
should trigger your ErrorController without getting HTTP status code 401 unauthorized. I try this out with #RestController and it works fine...

Related

how to configure spring security for spring boot project

I'm trying to make a web application that uses:
SpringBoot,
Mysql,
JDBC
, MVC, DAO
Thymeleaf,
IntelliJ
And I'm trying to figure out how Spring security works (which I'm having a lot of difficulty with).
My views are organized as follows:
resources(folder): - ________static(folder)
|____templates(folder):__________images(folder)
|___userOnly(folder):_____header.html
| |__help.html
| |__menu.html
| |__newDocForm.html
| |__profil.html
|
|__firstPage.html
|__header.html
|__home.html
|__index.html
|__inscriptionForm.html
|__loginPage.html
I would like to do that unidentified users can access all views except those contained in "userOnly" and that my "loginPage" page is used as the login page.
If I understood correctly, I must create a class that inherits from "WebSecurityConfigurerAdapter".
What I have done.
And then configure "configure", which I can't do correctly :(
#Configuration
#EnableWebSecurity
public class SecSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(final HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/userOnly/**").hasRole("USER")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/loginPage.html");
}
}
Sorry if my questions seems strange but english is not my first language
As of Spring-Boot 2.7 the use of WebSecurityConfigurerAdapter is deprecated. If you're using Spring-Boot 2.6 or older the other answers might suit you better.
To my best knowledge the recommended way for defining security config in Spring-Boot 2.7 is as follows:
#Configuration
public class WebSecurityConfig
{
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception
{
// #formatter:off
http.authorizeRequests()
.mvcMatchers("/userOnly/**").permitAll()
.anyRequest().permitAll();
http.formLogin()
.permitAll()
.loginPage("/loginPage.html");
http.logout()
.permitAll();
// #formatter:on
return http.build();
}
}
The use of web.ignoring() in the answer from voucher_wolves is, I believe, not recommended, instead one should add those cases to http.mvcMatcher().permitAll().
On a side note, I would personally recommend whitelisting the public pages and adding authentication to everything else, (for example a public folder). This way if you forget to add security to a link it's not public by default.
You need to tell Spring security what URL are public with something like this -
#Configuration
#EnableWebSecurity
public class SecSecurityConfig extends WebSecurityConfigurerAdapter {
private static final String[] PUBLIC_URLS = {"/public/*"};
#Override
protected void configure(final HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/userOnly/**").hasRole("USER")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/loginPage.html");
}
#Override
public void configure(WebSecurity web) {
List<RequestMatcher> matchers =
Arrays.asList(urls).stream().map(url -> new
AntPathRequestMatcher(url)).collect(Collectors.toList());
web.ignoring().requestMatchers(new OrRequestMatcher(matchers));
}
}
With OrRequestMatcher , you can create list of all URLs which you need to be public.
You can also use NegatedRequestMatcher to get all the private URL
RequestMatcher privateUrlMatcher = new
NegatedRequestMatcher(publicUrlMatcher);
I also suggest you to keep all public url under /src/main/resources/static/publicui and all private under /src/main/resources/static/privateui and have public permission for /publicui/*
try the following in your SecSecurityConfig class
#Configuration
#EnableAutoConfiguration
#EnableWebSecurity
public class SecSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/users").authenticated()
.anyRequest().permitAll()
.and()
.formLogin()
.usernameParameter("email")
.defaultSuccessUrl("/lib/allBooks")
.permitAll()
.and()
.logout().logoutSuccessUrl("/lib").permitAll();
http
.csrf().disable();
}
}
Just modify the parameters set for your application. if you don't have login form yo can skip
.usernameParameter("email")
.defaultSuccessUrl("/lib/allBooks")
.permitAll()

Securing app with Spring Security doesn't work

I wrote a simple backend software and I wanted to secure it with Spring Security and LDAP. It is obvious that LDAP part of the project works fine. the problem is that when I use the formLogin() for entring, that doesn't work and when I use postman it shows the result without asking user name and password! I think something in mywebSecurityConfig is wrong. this is my webSecurityConfig code:
#Configuration public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/**").permitAll()
.anyRequest().fullyAuthenticated();
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.userDnPatterns("uid={0},ou=people")
.groupSearchBase("ou=people")
.contextSource()
.url("ldap://localhost:10389/dc=example,dc=com")
.and()
.passwordCompare()
.passwordEncoder(new LdapShaPasswordEncoder() {
})
.passwordAttribute("userPassword");
} }
Use #EnableWebSecurity to enable Spring Security.
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
}
and remove .antMatchers("/**").permitAll() from your configuration as it matches all the requests. This construct is normally used to specify specific whitelisted endpoints like static documentation that does not require security:
.antMatchers("/docs/**").permitAll()

How to skip authentication for TestRestTemplate in Spring Boot Tests?

Below is my test class. The hello-world endpoint simply returns an HTML page containing text i.e. Hello Stranger!
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class HelloWorldTest {
#Autowired
private HelloWorldController controller;
#Autowired
private TestRestTemplate restTemplate;
#LocalServerPort
private int port;
#Test
public void contextLoads() throws Exception {
assertThat(controller).isNotNull();
}
#Test
public void greetingShouldReturnDefaultMessage() throws Exception {
String baseUrl = "http://localhost:" + port;
assertThat(this.restTemplate.getForObject(baseUrl+"/hello-world", String.class))
.contains("Hello Stranger!");
}
}
This is my Security Config:
#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();
}
}
It simply redirects all authenticated users to the login page
I have tried adding #WithMockUser annotation or adding another security config class in my test directory to override the default config. But so far nothing has seemed to work.
Any help or suggestions on documentation to read is appreciated!
Another way to do it that worked for me was to override the normal security configation for running the integration test like so:
#TestConfiguration
#Order(-101)
#EnableWebSecurity
class TestSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity security) throws Exception {
security.httpBasic().and().formLogin().disable();
}
}
I have managed to solve this issue by first creating another web security config without requiring login/authorization, then by adding #Profile to my config class and production/dev/test profile via application.properties in my test directory (i.e. adding "spring.profiles.active=test").
Not sure if this is the best way to solve this issue, but it works for now.

Spring Security with JWT

I am trying to develop Spring Security project with JWT.
I want access Login api with out Spring Security (without JWT token). But with below configuration, every time (for login api as well) it is checking for JWT token giving me 403 error.
Below is my WebSecurityConfig.
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private JwtAuthFilter jwtAuthFilter;
#Autowired
private TokenAuthenticationService jwtAuthenticationProvider;
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(jwtAuthenticationProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().ignoringAntMatchers("/api/v1/login");
http.csrf().disable();
http.authorizeRequests()
.antMatchers("/api/v1/login")
.permitAll()
.and()
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);
}
}
Thanks in advance
For login path configuration something like this can be used:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/**").hasRole("USER").and().formLogin()
.usernameParameter("username") // default is username
.passwordParameter("password") // default is password
.loginPage("/authentication/login") // default is /login with an HTTP get
.failureUrl("/authentication/login?failed") // default is /login?error
.loginProcessingUrl("/authentication/login/process"); // default is /login
// with an HTTP
// post
}
If some paths need to be ignored configure(WebSecurity web) can be overridden:
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/api/v1/somepath").antMatchers("/static/**");
}
There is filter class named JwtAuthFilter that is being executed before every service you call.
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
this code provides to be executed filter before every request, but its okay, you have to see this FilterClass there must be some check if token doesnt exist filter class must be returned and request will directly go to the login service. if you can show that Filter class and I will help you.

Spring Boot testing with Spring Security. How does one launch an alternative security config?

My spring boot application has an Application class. When I run it (as an application), it launches itself within an embedded servlet container (Tomcat, in my case). Somehow (through Application's #annotations, I suppose), WebSecurityConfig (extending WebSecurityConfigurerAdapter) in the same package is loaded.
WebSecurityConfig contains two important blocks of configuration information:
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
#EnableGlobalMethodSecurity(prePostEnabled = true) // enables method-level role-checking
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.userSearchBase("CN=Users,DC=some,DC=domain,DC=com")
.userSearchFilter("(sAMAccountName={0})")
.groupSearchBase("OU=Groups,DC=some,DC=domain,DC=com")
.groupSearchFilter("(member={0})")
.contextSource()
.managerDn("cn=ad-bind,cn=users,dc=some,dc=domain,dc=com")
.managerPassword("APASSWORD!")
.url("ldaps://some.domain.com:636");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
System.out.println("***************** WebSecurityConfig.configure *************************");
http.csrf().disable();
http
.headers()
.frameOptions()
.disable();
http
.authorizeRequests()
.antMatchers("/resources/images/*", "/me", "/products", "/product/**", "/offerings", "/offering/**", "/client/**")
.permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login").defaultSuccessUrl("/me")
.permitAll()
.and()
.logout()
.permitAll();
http.logout().logoutSuccessUrl("/me");
}
}
configureGlobal() contains the configuration for our internal LDAP system and it works just fine.
configure() specifies which URLs are public, which are only to be shown to logged-in users and which relative URLs to send users to as they log in.
Now I'm into integration testing and have written some methods to test controllers that do not require authentication. Those tests work as expected. The Application class fires up and the tests execute against it.
But now I want to test controller methods that DO require authentication. The way I think this is accomplished is by telling the test class to fire up an alternative Application class (TestApplication, in my case) and WebSecurityConfig that creates dummy users:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = TestApplication.class) // fires up with TestApplication.class instead of Application.class
#WebAppConfiguration
public class ProductControllerTests {
// test methods here, this time with username/password included
}
#Configuration
#EnableAutoConfiguration
public class TestApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(applicationClass, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(applicationClass);
}
private static Class<TestApplication> applicationClass = TestApplication.class;
}
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("testuser").password("userpass").roles("USER");
auth.inMemoryAuthentication().withUser("testadmin").password("adminpass").roles("ADMIN");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
System.out.println("***************** WebSecurityConfig.configure *************************");
http.csrf().disable();
http
.headers()
.frameOptions()
.disable();
http
.authorizeRequests()
.antMatchers("/resources/images/*", "/me", "/products", "/product/**", "/offerings", "/offering/**", "/client/**")
.permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login").defaultSuccessUrl("/me")
.permitAll()
.and()
.logout()
.permitAll();
http.logout().logoutSuccessUrl("/me");
}
}
So my question is: When I execute the unit test class, I believe TestApplication is firing. However, it is NOT picking up the alternative WebSecurityConfig class and its auth.inMemoryAuthentication() test users. How do I force my application to use one WebSecurityConfig when running the application normally, but a different WebSecurityConfig when running the unit tests?
You can configure your TestApplication to include just the beans that you would like to test. In other words, make sure that your WebSecurityConfig is not part of the test configuration. If you read the javadoc of #SpringBootApplication you will notice that it is a composite annotation that consists of (among others) the #ComponentScan annotation. Consequently your Application and your TestApplication will perform a recursive scan from the package in which the class is located. The Spring reference docs has a specific chapter about Using filters to customize scanning.
Alternatively, if you are using Spring Security version 4 or greater you may find the additions of #WithMockUser and #WithUserDetails interesting.
In your security configuration class, add #Profile annotation to disable in unit test profile. like:
#Configuration
#Profile("!" + Constants.SPRING_PROFILE_UNITTEST)
public class WebSecurityConfig { ....}
And let your another security config for test just in test dir.

Categories