When defining new spring boot REST resources, I tend to forget to also create a spring security configuration for their url patterns.
How can I, by default, deny access to all URLs, and only allow access to explicitly configured URL patterns? (I am using .hasRole for to allow access) I want to avoid as many unintended security holes as possible.
Let's say I have three REST resources: /jobs, /desks and /salary. My current code might look like this:
http.authorizeRequests()
.antMatchers(HttpMethod.GET, "/jobs")
.hasRole("my_user")
.antMatchers(HttpMethod.GET, "/desks")
.hasRole("my_user");
But currently, access to url /salary is provided to everyone (because it is not yet configured)!
Spring's Expression-Based Access Control has a denyAll expression which always evaluates to false.
So what you can do is use this denyAll method to deny access to everything, and then perhaps allow access to a certain URL(s) via hasRole:
http.authorizeRequests().antMatchers("/admin/**").access("hasRole('ADMIN')").antMatchers("/**").denyAll();
So for example, this will allow users with ADMIN access to access any page starting with /admin. And then it will deny access to all other pages. Note that the order is important as if you put in .antMatchers("/**").denyAll() first, it will deny all access and ignore the rest of your expression.
Or alternatively, you could use permitAll() for a certain URL pattern:
http.authorizeRequests().antMatchers("/users/**").permitAll().antMatchers("/**").denyAll();
Just to note that you might need to allow access to some way of logging in too, so the system can let someone log in with a specific role, so to combine it all together, and allow everyone to try login, only admin users to access the admin page(s) and deny all others, then something like:
http.authorizeRequests().antMatchers("/login").permitAll().antMatchers("/admin/**").access("hasRole('ADMIN')").antMatchers("/**").denyAll();
You can deny all requests by default with: .anyRequest().denyAll()
and explicit allow requests with .hasRole
anyRequest().denyAll() to deny all requests by default and
.hasRole to explicit allow requests
Related
I am trying to understand if there is a way to use spring security which helps my used case. Basically, I want to call spring security on each REST call in spring boot, rather than one time during the start of the application, and find the role of the user and further restrict endpoints based on the user roles.
I have 3 different rest controllers namely /admin1/*, /admin2/*, /admin3/*.
I have tried restricting endpoints manually as below.
http.authorizeRequests()
.antMatchers("/admin1/**").permitAll()
.and()
.authorizeRequests()
.antMatchers("/admin2/**").permitAll()
.anyRequest().authenticated();
This will actually allow /admin1/* and /admin2/* APIs to work and restrict /admin3/*. However, my used case is as below.
In each rest call, we pass the user id in the header. I would like to use spring security on each rest call, and use the user id from the header to find the user roles from the database.
If user has ADMIN 1 user role, we have to just enable /admin1/* endpoints and restrict /admin2/* and /admin3/*. Similarly, if user has ADMIN 2 user role, we have to just enable /admin2/* endpoints and restrict /admin1/* and /admin3/*. In the same way, if user has ADMIN 3 user role, we have to just enable /admin3/* endpoints and restrict /admin1/* and /admin2/*.
Is there a way to achieve this using spring security?
Thank you
AS far as I understood, you want to authenticate & authorize users on each call. True?
one way is tokenizing your REST APIs with JWT (JSON Web Token).
The example in https://dzone.com/articles/spring-boot-security-json-web-tokenjwt-hello-world would probably help.
I Also suggest that instead of using antMatchers In configure method to restrict URL access based on Roles, you use #PreAuthorize and #PostAuthorize annotations above the classes or methods you want to secure. This way gives you more flexibility on your restriction policies.
The example in https://www.baeldung.com/spring-security-method-security also may help you with that.
I just want to make sure if I get this correctly, so I would be thankful for any response; in my configure-override:
#Override
protected void configure(HttpSecurity http) throws Exception
{
http.
[...]
permitAll()
[...]
}
the permitAll() allows any request, while:
anonymous()
will only grant access for users that are not logged in but
in both cases a HttpSession-Object is created by default.
Is that right?
From the Spring documentation:
It's generally considered good security practice to adopt a “deny-by-default” where you explicitly specify what is allowed and disallow everything else. Defining what is accessible to unauthenticated users is a similar situation, particularly for web applications. Many sites require that users must be authenticated for anything other than a few URLs (for example the home and login pages). In this case it is easiest to define access configuration attributes for these specific URLs rather than have for every secured resource. Put differently, sometimes it is nice to say ROLE_SOMETHING is required by default and only allow certain exceptions to this rule, such as for login, logout and home pages of an application. You could also omit these pages from the filter chain entirely, thus bypassing the access control checks, but this may be undesirable for other reasons, particularly if the pages behave differently for authenticated users.
This is what we mean by anonymous authentication.
and
Note that there is no real conceptual difference between a user who is "anonymously authenticated" and an unauthenticated user. Spring Security’s anonymous authentication just gives you a more convenient way to configure your access-control attributes.
Using the .permitAll() will configure the authorization so that all requests(both from anonymous and logged in users) are allowed on that particular path.
The .anonymous() expression mainly refers to the status of the user(logged in or not).
Basically until a user is "authenticated" it is an "Anonymous user". It is like having a "default role" for everybody.
I would like to ask if there is a point to secure the methods which I call in a REST Controller with Pre and Post annotations. I have configured a security through java configuration like this:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.and()
.formLogin()
(...)
.and()
.authorizeRequests()
.antMatchers("/api/**").hasAuthority("ROLE_USER");
}
So every request under /api should be authorized with ROLE_USER. I tried to find some information about this in the internet but the only thing i could find was this:
https://coderanch.com/t/549265/Spring/method-security-spring-security
However I really can't think of a use case where a hacker would access somehow the methods in the service layer.
URL security and method security in service layer aims at different use cases.
If all you need is control that only users with a certain role can call URL with a given prefix (here API) URL security is what you need full stop.
If you have a complex application where some service methods can be called from different controllers and you want to make sure that you did not fail to restrict an access, method security can come to help by ensuring that only valid users can do certain business actions.
If you have a complex security model, for example several officse with one manager in each that has read and/or write access to his own employees data, method security on service layer directly using business model objects is the way to go.
BTW, using method security in a controller or even worse on a rest controller is generally design smell: if you can do it inside a controller it is generally better to use URL security. If it seems to make sense, you probably have imported business logic into a Fat Ugly Controller. Not speaking about method security being implemented with Spring AOP using by default JDK proxies, when controllers generally do not implement interfaces.
In addition to making it possible to have some kinds of functionality, using both techniques gives an additional layer of security.
Method level security is used to authorize the user. Spring security performs two basic operations before allowing the access.
Authenticate (Who is the user)
Authorize (What authorities the user has)
so for example if the user is having an authority of ROLE_USER and later in the architecture you decide to have rights assigned to some of the roles.
for example let's consider a role 'ROLE_USER'
and following rights has been assigned to the USER
CAN_VIEW_DATA
CAN_ADD_SUB_USERS
and so on.
so when some of the users have the right of CAN_ADD_SUB_USERS and some dont, then the method level security comes in handy.
Of course you have to play with the spring configurations for the rights and authority. But Once configured it provides an extra level of security that the applicaton might need.
Refer to this link for more info http://www.baeldung.com/role-and-privilege-for-spring-security-registration
REST is stateless. You should send something like access token (like Google API) with every request:
https://{server}/api/customers?access_token=BGhznFGDS
You can also send this information via Header-Attribute. The validation layer (Filter) decides whether the controller method may be called or not.
I prefer to implement my own Filters to get 100% of control.
I am using my own MVC implementation and I am not sure, whether the Spring Security isn't designed specifically for the Spring MVC implementation. Is it still okay to use it?
It is not clear to me, which parts of Spring Security I should use and which I don't need to. I suppose I don't need the URL filters as I need to validate the access specifically on the URL parameters in my controllers (for instance to check whether User is the owner of the Article). Something like:
if (request.getUser().isAllowedTo("EditArticle", 27)) {...}
if (request.getUser().isAllowedTo("CategoryManager", 123)) {...}
if (request.getUser().isInRole("Admin")) {...}
I could not find some clear way of users logging in/out programmatically. I've implemented my UserDetails and UserDetailsService classes to handle the users with JPA, but I don't see a way, how I can proceed with login and logout in my controllers.
EDIT:
I don't see a way how to put the <form> in my Freemarker templates - the only way of creating the form I found is with:
<http pattern="/login.htm*" security="none"/>
<form-login login-page="/login.htm" default-target-url="/home.htm"/>
</http>
How can I configure the structure of the login form? Can I create it by myself?
What I would like the most is to be able to handle the login by myself (for example with DWR) and not to use the magic j_security_checks...
It would be great, if I could handle the login request by myself and ask the auth service to login the user by myself (so I could easily use Direct Web Remoting (DWR)):
if (user.username.ok() and user.password.ok()) {
authService.setUser(user);
authService.setLoggedIn(true);
}
Spring security is not limited to spring mvc and can be used with your own framework implementation. It provides handy services for authentication and session management.
Spring is very convenient to use to leverage access by certain URLs but not limited to. You will be able to get which roles the current user has at the moment from the spring context and all the custom info you would include in your UserDetails object. There are number of ways to restrict access to certain actions by certain roles. However the code like if (request.getUser().isAllowedTo("EditArticle", 27)) {...} I think it will be simplier to check by yourself.
Login and logout are done by calling specific urls. For login: /j_spring_security_check. For logout: /j_spring_security_logout.
I have an application deployed on WebLogic 10.3.2 (11g), in which the user logs in through SSO. In other words, if the user is not logged in, he is redirected to SSO, where he logs in, and then is redirected back to the application. The whole redirection takes place by an the Oracle HTTP Server (a modified apache), which makes sure that only SSO-authenticated users can see the applciation.
So, when the user finally sees the application, he is already logged in.
Is there a way to use Seam security with this scenario? What I would like is to use the roles of the Subject to restrict access to certain pages and components.
A way I thought of, but for which I am not sure, is to use the subject that is populated by the SSO authentication provider of WebLogic, and use it to populate the Identity component of Seam. That would take place in the authentication method, which will always return true (since the user is already logged in). Inside the method, the credentials and roles of the Subject will be "transfered" inside the Seam identity.
Is this feasible at all?
Cheers!
You could write your own authenticate method, or override the Identity class and the login() method to achieve this. I've done something similar with a reverse proxy that performed our authentication. In the scenario, the proxy sent back the user ID of the authenticated user and all the groups they were a member of as header values. I wrote a filter to intercept the headers and then used my custom Identity class to do the rest.