I expose a Spring REST service like this..
#RequestMapping(value = "/{id}", method = RequestMethod.GET, headers = Constant.ACCEPT_APPLICATION_JSON)
#ResponseBody
public IndividualProviderDto showJson(#PathVariable("id") Long id) {
IndividualProviderDto individualProviderDto = individualProviderService.findIndividualProvider(id);
if (SecurityUtils.getCurrentLogin().equals(individualProviderDto.getUserName())) {
individualProviderDto.setCredential("");
HttpHeaders headers = new HttpHeaders();
headers.add(Constant.CONTENT_TYPE, Constant.APPLICATION_JSON_CHARSET_UTF8);
return individualProviderDto;
}
throw new IllegalArgumentException("User not found");
}
In the above code I am explicitly making a check to ensure that the id belongs to the logged in USER.
SecurityUtils.getCurrentLogin().equals(individualProviderDto.getUserName()
This check has to be applied wherever I need to protect a resource. Of course I can have an Aspect and apply it from one place using pointcut expressions. I have also heard of ESAPI that forges the url
but I was wondering if Spring Security Configuration provides something out of the box, so that I don't reinvent the wheel.
Spring security is not the answer -- it provides facility for authentication and authorization. Checking availability of a particular entity (in your case id) should be a part of service layer, as it's already implemented in your code.
Related
Small question regarding a SonarQube scan on a SpringBoot project please.
I have a very simple handler, super simple, as follow:
#ResponseBody
#RequestMapping(method = { RequestMethod.GET, RequestMethod.POST}, path = "/my/api")
public Mono<String> question() {
return myService.dosomething();
}
I have Spring Security in my class path, this project is a Spring WebFlux Application using 2.6.7 and Java 11.
Upon static analysis scan, I am being flagged with:
Spring CSRF unrestricted RequestMapping
Description
<p>Methods annotated with <code>RequestMapping</code> are by default mapped to all the HTTP request methods.
However, Spring Security's CSRF protection is not enabled by default
for the HTTP request methods <code>GET</code>, <code>HEAD</code>, <code>TRACE</code>, and <code>OPTIONS</code>(as this could cause the tokens to be leaked).
Therefore, state-changing methods annotated with <code>RequestMapping</code> and not narrowing the mapping
to the HTTP request methods <code>POST</code>, <code>PUT</code>, <code>DELETE</code>, or <code>PATCH</code>are vulnerable to CSRF attacks.</p><p> <b>Vulnerable Code:</b><br/><pre><code>#Controller
public class UnsafeController {
...
<b>References</b><br/>Spring Security Official Documentation: Use proper HTTP verbs (CSRF protection)<br/>OWASP: Cross-Site Request Forgery<br/>OWASP: CSRF Prevention Cheat Sheet<br/>CWE-352: Cross-Site Request Forgery (CSRF)</p>
I do not understand this issue.
What I tried:
I tried splitting the Controller onto two different controllers, one for each verb, and for some reason, this fix the issue:
#ResponseBody
#GetMapping(path = "/my/api")
public Mono<String> questionGet() {
return myService.dosomething();
}
#ResponseBody
#PostMapping(path = "/my/api")
public Mono<String> questionPost() {
return myService.dosomething();
}
But I am now carrying a duplicate, therefore, I would like to stay with my:
#ResponseBody
#RequestMapping(method = { RequestMethod.GET, RequestMethod.POST}
I also added Spring Security to protect myself against CSRF, but no luck, the issue still persist.
May I ask what is the proper way to fix this please?
Thank you
I want that all my rest services has as an input parameter HttpServletRequest httpRequest that I need later for some loggin purposes. This parameter sometimes is forgotten to be added and some methods are not logged. As are all rest services, and I am using Spring, all of them has some very specific annotations. I was thinking on using checkstyles to force the parameter to be present.
A little more of explanation of want I want to achieve. I am developing some rest servicies, and I am interested on logging some header that are sent to the rest services with some extra information. For this purpose, I have added HttpServletRequest request to each rest services as follows:
#GetMapping(value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseStatus(HttpStatus.OK)
public Status get(HttpServletRequest request, #PathVariable("id") Integer id) {
....
}
This paremeter is correctly retrieved and I can read the headers correctly (everything automated using AspectJ). My problem now is that is for a new rest service, I forgot to add the parameter, no logs will be shown. As the parameter is optional (you can or cannot add to the rest service without any error) and all logging is automated by AspectJ, is possible that I can forget it for future rest services and no notice the miss until late.
The scope is to ensure that always is present in all my rest services. My first thought was using checkstyle as I am already using for other different purposes.
Is it possible using checkstyle or any similar tool to force that a parameter is present on any method that has an annotation? If not, there is any other different way to achive my objective?
How can I allow only a one request to micorservice method with specific URL #PathVariable per User.
My Controller
#RestController
#RequestMapping(value = "/rest/product", produces = "application/json;charset=UTF-8")
public class ProductRestController {
#Autowired
ProductService productService;
#Autowired
ProductAsm productAsm;
#RequestMapping(value = "/ID/{ID}", method = RequestMethod.GET)
public ResponseEntity<ProductResource> getProductID(#PathVariable("ID") Long ID, #AuthenticationPrincipal User) {
Product product = productService.getProduct(ID);
if (product == null)
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
return new ResponseEntity<>(productAsm.toResource(product), HttpStatus.OK);
}
For example :
first request /rest/product/ID/2231 allowed for USER(with login="xaxa" )
second request /rest/product/ID/2545 allowed for USER(with login="xaxa" )
thirdth request /rest/product/ID/2231 not allowed for USER(with login="xaxa" )
Which is the best way to implement this functionality?(Have I to keep this URL request with User login in DB or there is already solutions)
You could use AOP and implement your own aspect that would be called Before your Rest Endpoint method.
This pointcut would read ID provided in a request and would try to find a Lock corresponding with this ID. Then the usual - try to access resource and potentially wait.
Implementation could base on Guava's Striped class - at least for the start.
There are several problems that need to be taken into consideration:
Striped could be replaced with some LRU Cache for better memory management.
You would of course have to provide synchronization for the case when the same ID is accessed simultaneously by two requests.
It would work only for an application deployed on a single node.
It would not be very good approach performance-wise. Depending on your traffic this may be an issue.
I was wondering if there is a better way to handle handling sessions than running this set of code through each one of my controller methods.
public ModelAndView addUser(#RequestParam("userid") String userId,
#RequestParam("passwd") String passwd,
#RequestParam("usrtype") String usrtype,
HttpSession session,
Model model ){
ModelAndView mav = new ModelAndView();
if ((String) session.getAttribute("userId") == null) {
model.addAttribute("msg", "Session was terminated.");
model.addAttribute("url", "/login");
mav.setViewName("redirect");
return mav;
}
...
How would one go about making this into reusable code?
There are multiple ways to optimize this:
Securing requests is something Spring Security is made for. Spring Security uses a Servlet filter to intercept (and deny) requests before they arrive in your controller. So you do not have to handle security related code in controller actions
If, for whatever reason, you can/want not use Spring Security you should have a look at Spring's MVC interceptions. In interceptors you can place code that need to be executed before and after controller actions.
If you always need to set the same Model attribute you can annotate methods with #ModelAttribute. This method will then be called for every request to populate your model, see ModelAttribute methods documentation. ControllerAdvice is similar, it is used if other classes than the controller should provide model information.
So guys, there is a way to intercept urls, preventing non-logged users to acess, using spring security, but not at xml config or java based, something like #PreAuthorize on methods, and these ones return a view after they done something, but not like actions (add, delete).
Something like these:
#PreAuthorize("isAuthenticated")
#RequestMapping(value = "/home", method = RequestMethod.GET)
public String home()
{
return "home";
}
What you want to do is possible, but it's less performance efficient and scatters the security code all over the controllers. To see the full capabilities of Expression-Based Access Control, check out this documentation