I want to know how ant matcher works in spring security??
I have two rest point:
First Rest class
#RestController
#RequestMapping("/auth")
class RestService1{
#GetMapping("/status")
public String status() {
return "Yes, I am fine";
}
}
Second Rest class
#RestController
#RequestMapping("/test")
class RestService2{
#GetMapping("/status")
public String status() {
return "Yes, Test status";
}
}
Spring security config class:
#EnableWebSecurity
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter{
protected void configure(HttpSecurity http)throws Exception{
http.authorizeRequests().antMatchers("/auth/*").permitAll();
}
}
Here is my question:
As per my understanding the meaning of "antMatchers("/auth/*").permitAll()" line is permit all request urls who contains "auth". But with this code I can able to access localhost:8080/test/status URL as well.
So what i can do if i want to allow only "auth" contains URL and deny all URLs ?
This code will permit only request URLs starting with "auth" and will deny all other URLs.
#EnableWebSecurity
#Configuration
class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/auth/**")
.permitAll()
.anyRequest()
.denyAll();
}
}
anyRequest().authenticate() will make all other routes forbidden, one has to be authenticated before accessing those routes.
#Configuration
class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/auth/**")
.permitAll()
.anyRequest()
.authenticate();
}
}
Related
I'm trying to authenticate with Basic Auth though LDAP but I only need to do so with /login route. All the other routes need to be authenticated through a custom JWT Filter that I implemented. Actually, what I've done just doesn't work.
Edit : just to be more clear, at the moment when I call on /auth/login, it goes through the LDAP filter and not the JWT Filter. But when I call any other route, it goes through JWT Filter and then still goes through the LDAP one and always makes my request fail. The behaviour is only correct when it's the /auth/login call.
Here's the configuration :
public class SecurityConfiguration {
#Configuration
#EnableWebSecurity
#Order(Ordered.HIGHEST_PRECEDENCE + 21)
public static class CompanySecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private LdapContextSource ldapContextSource;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.ldapAuthentication().contextSource(ldapContextSource).userDnPatterns("uid={0},ou=people");
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.httpBasic().and()
.requestMatchers()
.antMatchers("/auth/login")
.and().authorizeRequests().anyRequest().authenticated()
.and().csrf().disable();
}
}
#Configuration
#EnableWebSecurity
#Order(Ordered.HIGHEST_PRECEDENCE + 20)
public static class JWTSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.requestMatchers()
.antMatchers("/projects", "/projects/**", "/credential/**")
.and()
.addFilterAfter(new JWTFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeRequests().anyRequest().authenticated()
.and().cors().disable();
}
}
}
I have several controllers and want to secure only one of them,
spend some time but haven't figure out proper solution.
How to do it via config ?
Controllers :
#RestController
#RequestMapping("/somepath")
public class UnsecController {
// code here
}
#Secured("ROLE_CUSTOM")
#RestController
#RequestMapping("/somepath2")
public class SecController {
// code here
}
Config:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/js/**", "/css/**", "/fonts/**", "/static", "/swagger-ui.html");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.antMatcher("/**")
.addFilterBefore(authFilter(), BasicAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/health").permitAll()
.anyRequest().authenticated()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
#Bean
public MacaroonsAuthFilter authFilter() {
return new MacaroonsAuthFilter();
}
}
Edit:
I have 50 controllers from 100 that I want to secure,
but dont want to write them in configuration manually
Controllers are secured by configuring theWebSecurityConfigurerAdapter. If you only want to secure one controller-method, you need to configure the HttpSecurity in that way, that it only matches this path. All other methods are excluded from security. Something as follows:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/somepath").hasRole("CUSTOM")
.anyRequest().permitAll();
}
The #Secured annotation is normally used on service methods and not in the controller.
I am trying to disable or set the XFrameOptions header to SAME_ORIGIN for a particular URL in my Spring Boot project with Spring Security. I am pasting the code below,
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
RequestMatcher matcher = new AntPathRequestMatcher("**/course/embed/**");
DelegatingRequestMatcherHeaderWriter headerWriter =
new DelegatingRequestMatcherHeaderWriter(matcher,new XFrameOptionsHeaderWriter());
http.headers()
.frameOptions().sameOrigin()
.addHeaderWriter(headerWriter);
}
}
I am using AntRequestMatcher but that does not work, it instead disabled the XFrameOptions header for all the responses. Is there a better way to do this? Please help.
You need to configure multiple HttpSecurity instances. 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 match with **/course/embed/**. If matches X-Frame-Options will be SAMEORIGIN, otherwise DENY.
#EnableWebSecurity
public class WebMVCSecurity {
//Configure Authentication as normal, optional, showing just as a sample to indicate you can add other config like this
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
// Create an instance of WebSecurityConfigurerAdapter that contains #Order to specify which WebSecurityConfigurerAdapter should be considered first.
#Configuration
#Order(1)
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
// The http.antMatcher states that this HttpSecurity will only be applicable to URLs that match with **/course/embed/**
http.antMatcher("**/course/embed/**").headers().frameOptions().sameOrigin();
}
}
// Create another instance of WebSecurityConfigurerAdapter.
// If the URL does not match with **/course/embed/** this configuration will be used.
// This configuration is considered after ApiWebSecurityConfigurationAdapter since it has an #Order value after 1 (no #Order defaults to last).
#Configuration
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin();
//bla bla bla ...
}
}
}
Another option is to:
Disable the default spring security which uses a XFrameOptionsHeaderWriter to add X-Frame-Options to responses
Configure a new HeaderWriter that only delegates to an XFrameOptionsHeaderWriter for the paths you actually want X-Frame-Options to be added to
Sample code:
public class AlignSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception
{
http.headers()
.frameOptions().disable()
.addHeaderWriter(new CustomXFrameOptionsHeaderWriter());
}
private static class CustomXFrameOptionsHeaderWriter implements HeaderWriter {
private final XFrameOptionsHeaderWriter defaultHeaderWriter;
private static final Set<String> ALLOWED_TO_EMBED_IN_IFRAME = ImmutableSet.of("/some/path");
public CustomXFrameOptionsHeaderWriter()
{
this.defaultHeaderWriter = new XFrameOptionsHeaderWriter(XFrameOptionsMode.DENY);
}
#Override
public void writeHeaders(HttpServletRequest request, HttpServletResponse response)
{
if (!ALLOWED_TO_EMBED_IN_IFRAME.contains(request.getRequestURI()))
{
defaultHeaderWriter.writeHeaders(request, response);
}
}
}
}
I am trying to setup a single path (/basic) in my spring-boot spring MVC based application to be basic auth protected. I am just going to configure this using my own custom configuration parameters so the username and password are simply "admin" and "admin".
This currently works for the /basic path (I am prompted and can login correctly). The problem is that logout does not work (and I am not sure why) and also other paths (like /other shown) are being asked for basic auth credentials (before always being denied).
static class MyApplicationSecurity extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/open").permitAll();
http.authorizeRequests().antMatchers("/other").denyAll(); // Block it for now
http.authorizeRequests().antMatchers("/basic").authenticated().and().httpBasic().and().logout().logoutUrl("/basic/logout").invalidateHttpSession(true).logoutSuccessUrl("/");
}
}
I expected /other to always be denied but I don't get why basic auth is coming up for it. /open works as expected. I also don't understand why /basic/logout does not log me out (it also does not produce error messages). I do have a simple bit of code as a placeholder for the logout endpoint but if I do not have that then I get a 404. The "home" view is my web app root so I just want to send the user there after logout.
#RequestMapping("/logout")
public ModelAndView logout() {
// should be handled by spring security
return new ModelAndView("home");
}
UPDATE:
Here is the solution that seemed to work in the end (except the logout part, still not working):
#Configuration
#Order(1) // HIGHEST
public static class OAuthSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/oauth").authorizeRequests().anyRequest().denyAll();
}
}
#Configuration
public static class BasicAuthConfigurationAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/basic").authorizeRequests().anyRequest().authenticated().and().httpBasic();
http.logout().permitAll().logoutUrl("/logout").logoutSuccessUrl("/").invalidateHttpSession(true);
//.and().logout().logoutUrl("/basic/logout").invalidateHttpSession(true).logoutSuccessUrl("/");
}
}
i'm not sure about the logout, but we had a similar problem with having some of our site under basic and some of it not. Our solution was to use a second nested configuration class only for the paths that needed http basic. We gave this config an #Order(1)..but i'm not sure if that was necessary or not.
Updated with code
#Configuration
#EnableWebMvcSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
private static final Logger LOG = LoggerFactory.getLogger(SecurityConfig.class);
#Autowired
public void registerAuthentication(AuthenticationManagerBuilder auth, Config appConfig) throws Exception {
auth.inMemoryAuthentication()
.withUser(appConfig.getString(APIConfig.CONFIG_KEY_MANAGEMENT_USER_NAME))
.password(appConfig.getString(APIConfig.CONFIG_KEY_MANAGEMENT_USER_PASS))
.roles(HyperAPIRoles.DEFAULT, HyperAPIRoles.ADMIN);
}
/**
* Following Multiple HttpSecurity approach:
* http://docs.spring.io/spring-security/site/docs/3.2.x/reference/htmlsingle/#multiple-httpsecurity
*/
#Configuration
#Order(1)
public static class ManagerEndpointsSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/management/**").authorizeRequests().anyRequest().hasRole(HyperAPIRoles.ADMIN).and()
.httpBasic();
}
}
/**
* Following Multiple HttpSecurity approach:
* http://docs.spring.io/spring-security/site/docs/3.2.x/reference/htmlsingle/#multiple-httpsecurity
*/
#Configuration
public static class ResourceEndpointsSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
//fyi: This adds it to the spring security proxy filter chain
.addFilterBefore(createBBAuthenticationFilter(), BasicAuthenticationFilter.class)
;
}
}
}
this seems to secure the actuator endpoints at /management with basic auth while the others work with a custom auth token header. We do not prompt for credentials (no challenge issued) though for anything..we'd have to register some other stuff to get that going (if we wanted it).
Hope this helps
only one path will be protected
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception
{
auth.inMemoryAuthentication()
.withUser("user").password(passwordEncoder().encode("user"))
.roles("USER");
}
#Configuration
#Order(1)
public static class ManagerEndpointsSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/add/**").authenticated()
.anyRequest().permitAll()
.and()
.httpBasic()
.and().csrf().disable();
}
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
I'm trying to define two different security configurations for different url patterns, one of them using form login and another one using basic authentication for an api.
The solution I'm looking for is similar to the one explained here http://meera-subbarao.blogspot.co.uk/2010/11/spring-security-combining-basic-and.html but I would like to do it using java config.
Thanks in advance.
This is the configuration I currently have:
#Configuration
#EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserService userService;
#Override
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService);
}
#Override
public void configure(WebSecurity web) throws Exception {
// Ignore any request that starts with "/resources/".
web.ignoring().antMatchers("/resources/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeUrls().antMatchers("/", "/index", "/user/**", "/about").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and().formLogin()
.loginUrl("/login")
.failureUrl("/login-error")
.loginProcessingUrl("/security_check")
.usernameParameter("j_username").passwordParameter("j_password")
.permitAll();
http.logout().logoutUrl("/logout");
http.rememberMe().rememberMeServices(rememberMeServices()).key("password");
}
#Bean
public RememberMeServices rememberMeServices() {
TokenBasedRememberMeServices rememberMeServices = new TokenBasedRememberMeServices("password", userService);
rememberMeServices.setCookieName("cookieName");
rememberMeServices.setParameter("rememberMe");
return rememberMeServices;
}
}
The solution I found was to create another class extending WebSecurityConfigurerAdapter inside the first one, like is described https://github.com/spring-projects/spring-security-javaconfig/blob/master/samples-web.md#sample-multi-http-web-configuration
My solution is as follows:
#Configuration
#EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserService userService;
#Override
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService);
}
#Override
public void configure(WebSecurity web) throws Exception {
// Ignore any request that starts with "/resources/".
web.ignoring().antMatchers("/resources/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeUrls().antMatchers("/", "/index", "/user/**", "/about").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and().formLogin()
.loginUrl("/login")
.failureUrl("/login-error")
.loginProcessingUrl("/security_check")
.usernameParameter("j_username").passwordParameter("j_password")
.permitAll();
http.logout().logoutUrl("/logout");
http.rememberMe().rememberMeServices(rememberMeServices()).key("password");
}
#Bean
public RememberMeServices rememberMeServices() {
TokenBasedRememberMeServices rememberMeServices = new TokenBasedRememberMeServices("password", userService);
rememberMeServices.setCookieName("cookieName");
rememberMeServices.setParameter("rememberMe");
return rememberMeServices;
}
#Configuration
#Order(1)
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("api").password("pass").roles("API");
}
protected void configure(HttpSecurity http) throws Exception {
http.authorizeUrls()
.antMatchers("/api/**").hasRole("API")
.and()
.httpBasic();
}
}
}
I would say by simply doing it. Specify a second line with authorizeUrls() but for your URLs that are needed with basic authentication. Instead of formLogin() use httpBasic()
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeUrls().antMatchers("/", "/index", "/user/**", "/about").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and().formLogin()
.loginUrl("/login")
.failureUrl("/login-error")
.loginProcessingUrl("/security_check")
.usernameParameter("j_username").passwordParameter("j_password")
.permitAll();
http.authorizeUrls().antMatchers("/api/*").hasRole("YOUR_ROLE_HERE").and().httpBasic();
http.logout().logoutUrl("/logout");
http.rememberMe().rememberMeServices(rememberMeServices()).key("password");
}
Something like that should work.
Links: HttpSecurity, HttpBasicConfgurer.
You can solve it by adding .antMatcher("/api/**") just after http in your first config to manage only /api urls. You must have it on the first adapter:
http
.antMatcher("/api/*")
.authorizeRequests()
.antMatchers("^/api/.+$").hasRole("ADMIN")
....
Obviously As Spring updates these tend to fade in their applicability. Running spring cloud starter security 1.4.0.RELEASE this is my solution. My use case was a bit different as I'm trying to secure the refresh endpoint using basic auth for cloud configuration and using a gateway with spring session to pass the authentication in all other instances.
#EnableWebSecurity
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal1(AuthenticationManagerBuilder auth) throws Exception {
//try in memory auth with no users to support the case that this will allow for users that are logged in to go anywhere
auth.inMemoryAuthentication();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.disable()
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/user").permitAll()
.anyRequest().authenticated()
.and()
.csrf().disable();
}
#Bean
public BCryptPasswordEncoder encoder() {
return new BCryptPasswordEncoder(11);
}
#Configuration
#Order(1)
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
#Autowired
private AuthenticationProvider customAuthenticationProvider;
#Autowired
protected void configureGlobal2(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationProvider(customAuthenticationProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.and()
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/refresh").hasRole("SUPER")
.and()
.csrf().disable();
}
}
}
see the spring security docs for further clarification: Spring Security
The basic idea is that the #Order annotation will dictate what order the auth schemes are run. No #Order means that it is last. If the authorizeRequests() section cannot match on the incoming URL then that configuration will pass and the next one will attempt authentication. This will proceed until authentication succeeds or fails.
The other answers in here are relatively old and for example, I can't find authorizeUrls in Spring 4.
In SpringBoot 1.4.0 / Spring 4, I've implemented the basic/form login like this:
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
{
protected void configure (HttpSecurity aHttp) throws Exception
{
aHttp.authorizeRequests ().antMatchers (("/api/**")).fullyAuthenticated ().and ().httpBasic ();
aHttp.formLogin ()
.loginPage ("/login").permitAll ()
.and ().logout ().permitAll ();
}
}
There may be more ellegant ways of writing this - I'm still working on understanding how this builder works in terms of sequence and so forth. But this worked.