RESTful URI Resource mutual exclusion based on query param in CXF - spring

In Spring MVC, for RESTful service, if URI and HTTP Method are same for two or more different resources, then they can be made mutually exclusive based on query params by using NOT(!) operator with Query Param such as :
#RequestMapping(method = RequestMethod.POST, value = "/authentication", params = { "password", "!ssn" })
#ResponseBody
public SessionResponse userLogin(#Valid #ModelAttribute final UsernameAuthFormBean usernameAuthFormBean,
final BindingResult bindingResult, final HttpServletRequest request, final HttpServletResponse response) {}
#RequestMapping(method = RequestMethod.POST, value = "/authentication", params = { "!password", "ssn" })
#ResponseBody
public SessionResponse forgotPassword(#Valid #ModelAttribute final ForgotPasswordFormBean forgotPasswordFormBean,
final BindingResult bindingResult, final HttpServletRequest request, final HttpServletResponse response) {}
How can this be achieved in CXF?

CXF and Spring MVC are not directly comparable. CXF is an implementation of Java Api for RESTful services JAX-RS
This operator ! is not present in the specification and CXF does not implement it. You need to use different URIs
#POST
#Path("/authentication/userLogin")
public Response userLogin(#FormParam("") UsernameBean bean)
#POST
#Path("/authentication/forgotPassword")
public Response forgotPassword(#FormParam("") ForgotPasswordBean bean)

Related

Custom Schema for Spring Boot 2 OpenAPI 3 Documentation

I have a requirement to integrate OpenAPI 3 documentation for my Spring Boot 2 project. We did not used modals/DTOs on controllers.
Here is the sample controller:
#RestController
#RequestMapping(value = "/pet")
public class PetController {
#RequestMapping(value = "/save", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public ResponseEntity<Map<String, Object>> savePet(
#RequestBody Map<String, Object> petObj, HttpServletRequest request)
throws Exception {
String petResponse = petDAO.savePet(petObj, request, true);
return new ResponseEntity<Map<String, Object>>(petResponse, HttpStatus.OK);
}
}
Request body:
{
"name":"Test",
"category":"school"
}
My response:
{
"petId":"1",
"petName":"Test",
"petCategory":"school",
"petStaus":"active"
}
I am not able to find a way to add the OpenAPI doc for my custom Map object. I want to add key, description, type, example(s) for each property in my Map manually.
Can anyone suggest how to do this?
This is the default behaviour of the springdoc-openapi library in order to ignore other injectable parameters supported by Spring MVC.
https://docs.spring.io/spring/docs/5.1.x/spring-framework-reference/web.html#mvc-ann-arguments
If you want to change this behaviour, you can just exlcude it as follow:
SpringDocUtils.getConfig().removeRequestWrapperToIgnore(Map.class);

How to check security acess (#Secured or #PreAuthorize) before validation (#Valid) in my Controller?

here is my Controller code :
#PreAuthorize("hasRole('CREATE_USER')")
#RequestMapping(method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public UserReturnRO createUser(#Valid #RequestBody UserRO userRO) throws BadParameterException{
return userService.createUser(userRO);
}
My need is when a client without the appropriate role tries to create a user, the controller responds "Not authorized" even if the data sent are not valid. Instead of that, if the client (without the appropriate role) tries to create a user with wrong data, my controller responds with the #Valid message (ex : "password cannot be empty"), while I want it responds "not authorized".
In the PreAuthorized Interface we can find this sentence :
Annotation for specifying a method access-control expression which will be evaluated to decide whether a method invocation is allowed or not.
but it seems that it's not the case.
You can not do this directly, since #Valid is processed before an actual method call and as a result before #PreAuthorize.
But what you can do instead is to inject BindingResult just right after your model (userRO) and in doing so - take control of validation process. Then check if BindingResult has some errors and if so return bad request response (similar to what spring does).
Example:
#ResponseBody
#RequestMapping(method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
#PreAuthorize("hasRole('CREATE_USER')")
public ResponseEntity<?> createUser(#RequestBody #Valid UserRO userRO, BindingResult result) {
if (result.hasErrors()) {
return ResponseEntity.badRequest().body(result.getAllErrors());
}
return ResponseEntity.ok(userService.createUser(userRO));
}
As already stated, Spring Security's #PreAuthorize is method advice, which means that it does not get to participate until the method and its arguments have already been resolved.
Aside from the answer already given, there are a few ways to move authorization before argument resolution, instead.
Filter Security
First, Spring Security checks URLs before the request is mapped to a method. And since this is a #Controller, it's reasonable to suppose that you could instead map the request to the role at that level instead of #PreAuthorize:
http
.authorizeRequests()
.mvcMatchers(POST, "/somepath").hasRole("CREATE_USER")
Handler Interceptor
Second, Spring MVC does ship with limited support for checking authorities before parsing method arguments. For example, you can do:
#EnableWebMvc
public static class MvcConfig implements WebMvcConfigurer {
#Override
public void addInterceptors(InterceptorRegistry registry) {
UserRoleAuthorizationInterceptor userRole =
new UserRoleAuthorizationInterceptor();
userRole.setAuthorizedRoles("CREATE_USER");
registry.addInterceptor(userRole);
}
}
This is much more basic than #PreAuthorize since it's a global setting, but I've included it for completeness.
Handler Interceptor, Part 2
Third (warning, some inelegance ahead), you can create your own HandlerInterceptor.
The flow is:
FilterSecurityInterceptor <== where .mvcMatchers(...).hasRole(...) lives
Then HandlerInterceptors
Then argument validation
Then MethodSecurityInterceptor <== where #PreAuthorize lives
So, your HandlerInterceptor would check before arguments are resolved. It doesn't have to be as involved as MethodSecurityInterceptor, though. It could, for example, simply be:
static class AuthorizationInterceptor extends HandlerInterceptorAdapter {
SecurityMetadataSource securityMetadataSource;
AccessDecisionManager accessDecisionManager;
#Override
public void preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) {
Authentication authenticated = (Authentication) request.getUserPrincipal();
MethodInvocation mi = convert(handler);
Collection<ConfigAttribute> attributes =
this.securityMetadataSource.getAttributes(mi);
// throws AccessDeniedException
this.accessDecisionManager.decide(authenticated, mi, attributes);
return true;
}
}
Then you wire it together with:
#EnableGlobalMethodSecurity(prePostEnabled = true)
static class MethodConfig extends GlobalMethodSecurityConfiguration {
#Bean
HandlerInterceptor preAuthorize() throws Exception {
return new AuthorizationInterceptor(
accessDecisionManager(), methodSecurityMetadataSource());
}
}
#EnableWebMvc
public static class MvcConfig implements WebMvcConfigurer {
#Autowired
AuthorizationInterceptor authorizationInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authorizationInterceptor);
}
}
It's inelegant because MethodSecurityInterceptor would still participate in authorized requests, which would ostensibly be the majority.

Mocking spring controller validator

I want to unit test this Spring controller method:
#Autowired
private MyValidator validator;
public String register(
HttpServletRequest request,
ModelMap model,
Principal principal,
#PathVariable Plain plain,
RedirectAttributes ratts,
#ModelAttribute #Valid PlainMoreObject pmo,
BindingResult result)
{
validator.validate(pmo, result);
I'm using JMock. How do I mock the validator in order to test controller by calling
controller.register(....) ?
There is a helper class in Spring called ReflectionTestUtils (link) you can use to inject mocked beans to fields.
#Mock MyValidator validatorMock;
ReflectionTestUtils.setField(controller, "validator", validatorMock);
controller.register(...);

Get the Servlet Request object in a POJO class

I need to get the current page URL in a POJO that is being called from an Acegi class (need to add some custom logic for the app I'm working on) and need to retrieve the HttpServletRequest so that I can get the subdomain of the URL (on which the logic is based).
I've tried to add:
#Autowired
private HttpServletRequest request;
...
public void setRequest(HttpServletRequest request) {
this.request = request;
}
public HttpServletRequest getRequest() {
return request;
}
However when I try to use the request object in my code, it is null.
Any idea what I am doing wrong or how I can better go about doing this?
If the bean is request scoped you can autowire the HttpServletRequest like you are doing.
#Component
#Scope("request")
public class Foo {
#Autowired private HttpServletRequest request;
//
}
Otherwise you can get the current request as follows:
ServletRequestAttributes sra = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
HttpServletRequest req = sra.getRequest();
This uses thread-local under the covers.
If you are using Spring MVC that's all you need. If you are not using Spring MVC then you will need to register a RequestContextListener or RequestContextFilter in your web.xml.

Spring MVC - Response

How can I access the response object from a bean? To get the request object I use the following.
ServletRequestAttributes attr = (ServletRequestAttributes)
RequestContextHolder.currentRequestAttributes();
Is there something similar to the above for response object?
If you are in a web application context (which it looks like you are) you can auto wire in the HttpServletRequest or HttpServletResponse.
The request/response from the current request scope will be injected.
#Component
public class SomeComponentInAWebApplicationContext {
#Autowired
private HttpServletRequest request;
#Autowired
private HttpServletResponse response;
...
}

Resources