Allow all URLs but one in Spring security - java

I would like to protect just a single URL, while allowing anonymous access for everything else.
The Java configuration examples i'm seeing in the internet all seem to indicate that you need to explicitly permitAll each and every URL, and appropriate hasRole for URLs that need to be protected. This in my case, creates a really unwieldy java code which I have modify every time I add a new URL to the application. Is there an easier java configuration that I can use.
And note also that in my case, the URL i'm protecting is a sub-resource, say employee/me, I would like employee/list, etc., to be anonymously accessible.

If you're using Java Configuration, you can use something like following in your configure method:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/employee/me").authenticated()
.antMatchers("/**").permitAll();
}

#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/employee/me").authenticated()
.antMatchers("/**").permitAll();
}

Related

Adding Spring Boot Keycloak configuration of HTTP requests

Currently in my SecurityConfig.java class file where I define my KeycloakWebSecurityConfigurerAdapter I want to define so that every GET request can be done by two different roles. But only one role can do the other types of HTTP requests (POST, PUT, PATCH etc). How can this be achieved in my code below:
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests()
.antMatchers(HttpMethod.GET).hasAnyRole("user", "admin")
.anyRequest().hasRole("admin");
}
What happens is that when trying to do POST request I get access denied 403. GET requests works fine. Any ideas?
You should disable csrf on your configure method :
public void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.csrf().disable().authorizeRequests().anyRequest().authenticated();
}
}
You should not use KeycloakWebSecurityConfigurerAdapter nor anything else from Keycloak libs for Spring, it is deprecated.
Instead, you can follow this tutorial which proposes two solutions based on:
spring-boot-starter-oauth2-resource-server which requires quite some Java conf
spring-addons-webmvc-jwt-resource-server which enables to configure most of security from properties (way simpler than preceding)
All tutorials linked here show how to map Keycloak roles to spring-security authorities (and will keep CSRF protection enabled, even for stateless resource-servers).

Spring WebSecurity configuration using .ignoring() not working

I've been struggling for a few days over this. Aside from quirky things that seem to be happening inconsistently and unpredictably by simply commenting out a bit of code, running the program, and then uncommenting and running again, I'm failing to understand how overriding various configure methods are working.
I want WebSecurity to always ignore "/static/**".
Upon launching the application and navigating to the homepage, I can access all of the pages for which I have permitted all, but all of the content in "/static/**" is being ignored until after I have navigated to the login page and logged in as an authenticated user. So the application just appears as white pages with text, without any of the styling at all until logged in.
Here is the code for my AppSecurityConfig class. I have omitted the helper methods for handling success and failure of logging in, and I also have to different account types that serve different roles, so I have only included one account here for simplification. The part where I believe the problem exists is in the configure(WebSecurity web) method where I am calling the .ignoring() method and passing the "/static/**" arg. Thank you in advance:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private CompanyService companyService;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(companyService);
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/static/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/",
"/account_registration",
"/candidate_registration",
"/addCandidate",
"/company_registration",
"/addCompany",
"/select_account_type",
"/candidate_login",
"/company_login").permitAll()
.antMatchers("/company_profile").hasRole("COMPANY")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/company_login")
.permitAll()
.successHandler(companyLoginSuccessHandler())
.failureHandler(companyLoginFailureHandler())
.and()
.logout()
.logoutSuccessUrl("/");
}
}
The path to my static folder is "src/main/resources/static", but I did what Sam said and opened the developer tools and realized that all of the contents within the "static" directory were being referenced directly. For example, there are directories referenced in this way: "/vendor/..." and "/images/...", that were being referenced but ignored due to security. There are also some files in the "static" directory like "app.css", "app.js" and "favicon.png" that are having some strange behavior. It appears that they are not being ignored but different colors and styling are being displayed unless I also add them as arguments to the .gitIgnoring() method like "/app.css" etc. This project was built by working through a TeamTreehouse tutorial and then refactoring and adding custom styling between a few people on my 6 person team, and I'm pretty sure there are multiple things under the hood inherited in this project that myself and the front end people are not understanding when it comes to the styling.
The fix that seems to work, although maybe not ideal, was removing "/static/**" from the .ignoring() method and replacing it with all of the contents that were actually inside the "static/" directory:
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers( "/images/**",
"/vendor/**",
"/app.css",
"/app.js",
"/favicon.png");
}

Spring Security disable security for requests made FROM a certain url

my application uses spring security. I know you can use antMatchers to permit requests for some URI that are mapped into your application. But I need too allow requests made from an external api to a URI in my application and just for that api. I need something like this:
#Override
protected void configure(WebSecurity web) throws Exception
{
web.ignoring()
.antMatchers("http://externalTestApi.com");
}
Does anybody know if this is possible? I did not find anything on this.
You can do something like this (if you want to combine multiple conditions)
.authorizeRequests()
.antMatchers("/user/list")
.access("authenticated or hasIpAddress('666.666.666.666') or hasIpAddress('127.0.0.1') or hasIpAddress('0:0:0:0:0:0:0:1')")
or
.authorizeRequests()
.antMatchers("/user/list")
.hasIpAddress("0.0.0.0/0");

pass HttpServletRequest in a hasPermission expression

In my spring security config I've got the following settings:
#Override
protected void configure(HttpSecurity http) throws Exception
{
http
.authorizeRequests()
.antMatchers("/login.htm", "/signup.htm").permitAll()
.antMatchers("/page1.htm", "/page2.htm", "/page3.htm").access("#permission.hasPermission(principal.username))
....
}
The #permission which contains the method hasPermission is a #Component bean which decides whether the principal username has an access to the pages. In the bean I use my dao methods to determine this. However, I need more knowledge to make the decision because it's not a single page. For instance, is there any way to know what page the user has requested and pass that in the hasPermission method? In other words, I want to do something like:
.antMatchers("/page1.htm", "/page2.htm", "/page3.htm").access("#permission.hasPermission(principal.username, HttpServletRequest http))
See the 2nd parameter of the method. It's the http request which is the requested page so I will know whether the user requested page1, page2 or page3..
Or if I cannot pass that as a parameter how can I get the current requested page in my implementation of the hasPermission method?
You should be able to access it using the following:
#Override
protected void configure(HttpSecurity http) throws Exception
{
http
.authorizeRequests()
.antMatchers("/login.htm", "/signup.htm").permitAll()
.antMatchers("/page1.htm", "/page2.htm", "/page3.htm").access("#permission.hasPermission(principal.username,request))
....
}
This is due to the fact that the WebSecurityExpressionRoot.request property is exposed as a public final variable

Security config when using #PreAuthorize

My security config class (which inherits from WebSecurityConfigurerAdapter) has a method like the following.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/restaurant/**").access("hasRole('ROLE_USER')")
.and()
.formLogin();
}
However I'd rather use #PreAuthorize on my controllers instead. If I remove the method everything requires auth. What should my method look like so everything is available and access is only determined by PreAuthorize?
As has been already stated, it is not very common to use method level security to secure controller methods but rather to secure methods with business logic. And even if you need to perform authorization based on request attributes, it should be possible to achieve this with URL based security and web security expressions.
Available expressions are defined by WebSecurityExpressionRoot class, an instance of which is used as the expression root object when evaluation web-access expressions. This object also directly exposed the HttpServletRequest object under the name request so you can invoke the request directly in an expression.
Here you can find more details on when to use URL based security and when method level security.
It is rather uncommon to use #PreAuthorize on controller methods, but there may me use cases, if the decision depends on request parameters ...
If you do not want to do any authorization at the request level, you can simply have :
#Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin();
}
You only declare a form login, and no request security. But do not forget that request security uses less resources than method security.
Instead of .access("hasRole('ROLE_USER')"), try .access("permitAll"). Note that for request mappings that doesn't have a #PreAuthorize, everyone will be given access.

Categories