If run project with Spring security, the entry point URL is:
http://localhost:8099/login
Meanwhile I need to put global project name in entry point URL as follows:
http://localhost:8099/pojoname/login
Here down is my Spring Security Configuration file:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.antMatchers("/login").permitAll()
.antMatchers("/register", "/registration", "/editProfile").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login").permitAll()
.usernameParameter("email")
.and()
.logout()
.permitAll();
}
The requested feature is what is know as web context (or formerly Servlet context in a Servlet container work).
This is supported out of the box within Spring Boot and can be switched / activated using the configuration property server.servlet.contextPath with the desired value.
Inside your application.properties file, add below line:
For a version < Spring Boot 2.0:
server.contextPath=/pojoname
For a version > Spring Boot 2.0:
server.servlet.contextPath=/pojoname
Related
I'm trying to explore the Spring actuator endpoints through springboot project. I'm unable to expose any of the endpoints. It always shows the 'Exposing 1 endpoint(s) beneath base path '/actuator' in log. Below is my dependency details added in build.gradle and application.yml file. I have used spring security as well, to expose the endpoint only to user with certain role. But still nothing works. Requesting suggestions.
build.gradle:
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
I'm using Spring boot version 2.6.6
application.yml
management:
endpoint:
health:
show-details: always
endpoints:
web:
exposure:
include: health
Spring Security :
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/actuator/**").hasAnyAuthority("ADMIN")
.anyRequest().permitAll()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
http.csrf().disable().headers().frameOptions().disable();
}
}
The issue was with the application.yml. The management.endpoint.web.exposure.health was added below the Spring entry. The actuator entry needed to be added above that.
I'm having a bit of a fight with Theymleaf's security implementation.
I have the following spring security configuration:
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/login*").permitAll()
.antMatchers("/admin/*").hasAuthority("ADMIN"))
.antMatchers("/").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
// ...
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/home")
.invalidateHttpSession(true);
}
In my HTML I've got something simple set up:
<div sec:authorize="hasAuthority('ADMIN')">You're cool bro!</div>
Which, after logging in works perfectly fine.
Logging out also works perfectly fine and hides the div.
However when I login after which I re-start the server (and thus my session is destroyed) and just reload the page(homepage, base url, without logging in) the div is back and thymeleaf seems to 'cache' the authorities.
Another effect is that I'm still able to visit pages like: /admin/page/
Am I missing something magically here? I'm confused as to what the Thymeleaf hasAuthority() method calls.
I'm thinking about just adding the following, which I feel is rather unclean:
#PreDestroy
private void destroySecurityContext() {
SecurityContextHolder.clearContext();
}
Here is my configure code snippet
#Override
public void configure(HttpSecurity http) throws Exception {
http.
authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/api/user/**").hasAnyAuthority("ROLE_ADMIN")
.antMatchers("/api/status/**").hasAuthority("ROLE_ADMIN").anyRequest()
.authenticated()
.and()
.exceptionHandling()
.accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
In this I need to make ROLE_ADMIN to access only POST and PUT httpmethods. He should not be able to access GET or DELETE httpmethod. I need this to be done in a single .antMatchers() method.
How can I do this?
Have a look at this Spring example project. You can define matchers per path and HTTP verb.
http
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/employees").hasRole("ADMIN")
.antMatchers(HttpMethod.PUT, "/employees/**").hasRole("ADMIN")
.antMatchers(HttpMethod.PATCH, "/employees/**").hasRole("ADMIN")
When do we use antMatcher() vs antMatchers()?
For example:
http
.antMatcher("/high_level_url_A/**")
.authorizeRequests()
.antMatchers("/high_level_url_A/sub_level_1").hasRole('USER')
.antMatchers("/high_level_url_A/sub_level_2").hasRole('USER2')
.somethingElse()
.anyRequest().authenticated()
.and()
.antMatcher("/high_level_url_B/**")
.authorizeRequests()
.antMatchers("/high_level_url_B/sub_level_1").permitAll()
.antMatchers("/high_level_url_B/sub_level_2").hasRole('USER3')
.somethingElse()
.anyRequest().authenticated()
.and()
...
What I expect here is,
Any request matches to /high_level_url_A/** should be authenticated + /high_level_url_A/sub_level_1 only for USER and /high_level_url_A/sub_level_2 only for USER2
Any request matches to /high_level_url_B/** should be authenticated + /high_level_url_B/sub_level_1 for public access and /high_level_url_A/sub_level_2 only for USER3.
Any other pattern I don't care - But should be public ?
I have seen latest examples do not include antMatcher() these days. Why is that? Is antMatcher() no longer required?
You need antMatcher for multiple HttpSecurity, see Spring Security Reference:
5.7 Multiple HttpSecurity
We can configure multiple HttpSecurity instances just as we can have multiple <http> blocks. The key is to extend the WebSecurityConfigurationAdapter multiple times. For example, the following is an example of having a different configuration for URL’s that start with /api/.
#EnableWebSecurity
public class MultiHttpSecurityConfig {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) { 1
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
#Configuration
#Order(1) 2
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/api/**") 3
.authorizeRequests()
.anyRequest().hasRole("ADMIN")
.and()
.httpBasic();
}
}
#Configuration 4
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin();
}
}
}
1 Configure Authentication as normal
2 Create an instance of WebSecurityConfigurerAdapter that contains #Order to specify which WebSecurityConfigurerAdapter should be considered first.
3 The http.antMatcher states that this HttpSecurity will only be applicable to URLs that start with /api/
4 Create another instance of WebSecurityConfigurerAdapter. If the URL does not start with /api/ this configuration will be used. This configuration is considered after ApiWebSecurityConfigurationAdapter since it has an #Order value after 1 (no #Order defaults to last).
In your case you need no antMatcher, because you have only one configuration. Your modified code:
http
.authorizeRequests()
.antMatchers("/high_level_url_A/sub_level_1").hasRole('USER')
.antMatchers("/high_level_url_A/sub_level_2").hasRole('USER2')
.somethingElse() // for /high_level_url_A/**
.antMatchers("/high_level_url_A/**").authenticated()
.antMatchers("/high_level_url_B/sub_level_1").permitAll()
.antMatchers("/high_level_url_B/sub_level_2").hasRole('USER3')
.somethingElse() // for /high_level_url_B/**
.antMatchers("/high_level_url_B/**").authenticated()
.anyRequest().permitAll()
I'm updating my answer...
antMatcher() is a method of HttpSecurity, it doesn't have anything to do with authorizeRequests(). Basically, http.antMatcher() tells Spring to only configure HttpSecurity if the path matches this pattern.
The authorizeRequests().antMatchers() is then used to apply authorization to one or more paths you specify in antMatchers(). Such as permitAll() or hasRole('USER3'). These only get applied if the first http.antMatcher() is matched.
I just upgraded from Spring Security 3.2.0.RC1 to 3.2.0.RC2. Everything worked fine under RC1. Under RC2, my custom login page no longer works. The login page is just redislayed after clicking the Login button. If invalid credentials (or no credentials) are submitted, it also redisplays without any error message. Before it would correctly display an error message if the credentials were incorrect.
What is interesting is if I change from:
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
// #formatter:off
httpSecurity
.authorizeRequests()
.antMatchers("/restricted/**").hasRole("admin"))
// all requests must be authenticated
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/myLoginUrl.request")
.failureUrl("/myLoginUrl.request?error")
.permitAll()
.and()
.logout()
.permitAll()
.logoutSuccessUrl("/myLoginUrl.request")
;
// #formatter:on
}
to:
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
// #formatter:off
httpSecurity
.authorizeRequests()
.antMatchers("/restricted/**").hasRole("admin"))
// all requests must be authenticated
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll()
.and()
.logout()
.permitAll()
.logoutSuccessUrl("/myLoginUrl.request")
;
// #formatter:on
}
The default Spring Security login page is displayed and works. I've looked at the source of the default page and compared it to my custom page and it seems to call the same action with fields with the same names.
If I step through the debugger, I find that in AntPathMatcher.java, public boolean matches(HttpServletRequest request):
String url = getRequestPath(request)
The url returned is "/error" when using my custom login page. getRequestPath() just returns request.getServletPath() appended to request.getPathInfo(). I'm not sure why upgrading to RC2 would cause this to return "/error".
There were three things that I changed that made this work.
1) Added a CSRF hidden field to the form:
<input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" />
2) Capitalized POST for the form method:
<form action="login" method="POST">
3) Explicitly added loginProcessingUrl to the configuration:
.formLogin()
.loginPage("/myLoginUrl.request")
.loginProcessingUrl("/login")
.failureUrl("/myLoginUrl.request?error")
.permitAll()