Disable POST fallback policy for non-standard WebAPI method names - asp.net-web-api

Any ASP.NET WebAPI2 ApiController method names that do NOT begin with a configured METHOD prefix (by default Get..., Post..., Put..., Delete..., Head..., Options..., and Patch...) will match an HTTP 'POST'. (See Is there a default verb applied to a Web API ApiController method? for details.)
I would rather have to opt-in for every method, by convention, than opt-out.
To me, the opt-out approach represents a greater security risk, and has no helpful payoff; for consistency, to support POST the implementer should prefix the class method Post... regardless. For example, an ApiController method named SensitiveFunction() shouldn't match any HTTP METHOD unless I intentionally configure support for a 'SENSITIVE' HTTP METHOD.
Is there a simple configuration change that will allow me to disable this POST fallback policy?
Alternately, am I overlooking some reason I would need this fallback policy?

The default action selection only looks for public instance methods. By making your method public you are effectively "opting in". Scope your methods appropriately with only methods intended to be seen via the API interface as public and everything else private.
http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-and-action-selection
Which methods on the controller are considered "actions"? When selecting an action, the framework only looks at public instance methods on the controller. Also, it excludes "special name" methods (constructors, events, operator overloads, and so forth), and methods inherited from the ApiController class.

Related

Spring Controller Url

I have question about controllers. Always when i working with controller im start to declare #RequestMapping for example if have UserController then is #RequestMapping("/user");
What if i want to declare another path in this same controller? For example im have #GetMapping("/info") and i will get info about user, but what if i want to declare on this same controller path localhost:8080/topic/blablabla? Is another solution than delete #RequestMapping from controller and make on every Get/PostMapping another path?
Defining a #RequestMapping at the controller level; it means narrowing it down to your criteria.
You can use the #RequestMapping annotation to map requests to controllers methods. It has various attributes to match by URL, HTTP method, request parameters, headers, and media types. You can use it at the class level to express shared mappings or at the method level to narrow down to a specific endpoint mapping. Read More
It is good you want to do, sometimes I need it too but as far as I research it is not supported now.

Custom authorization per action call in Web API

I need to grant permissions for users to call exact actions. And also each permission rule can contain validation rules for action arguments:
[CustomAuth]
public MyController : ApiController
{
[ValidateAccess, ActionName("Myaction")]
public void MyAction([MyTypeAccess] MyType myType)
{
}
}
In my logic i need to check can user call this action and can he call this action with passed MyType value (custom validation).
At the moment i dont see how to get attributes from custom AuthorizeAttribute and i see the solution with Castle interceptors, i'm using for my another purposes (from invocation info)..
Is there a standard way to implement this custom authorization?
Didn't find any direct solution in Web API for this issue.
As i'm using Castle interceptors, i've added a new interceptor on all controllers, which are support auth. Interceptor provide access to invocation and you can retrieve any attribute and value passed to the controller/action.
Validation attribute on an action says you need to apply validation routines on this call, ActionName identifies the type of call (if necessary, in a future this will be moved to an own attribute as action name can differ in legacy controllers for old versions).
If you need to validate action parameters there set of attributes you can use, which identify the type of argument and validation algorithm.

Looking for a way to assign #ControllerAdvice to specific url path pattern or controllers

I was looking for a way to make #ControllerAdvice to be called for only specific url path pattern or a group of controllers. So, I found I can create custom ExceptionHandlerExceptionResolver and assign it to custom controllers by setMappedHandlerClasses(). The problem is, there is also a default ExceptionHandlerExceptionResolver and it also picks up my #ControllerAdvice. So I end up with two ExceptionHandlerExceptionResolver's, both of them having handler defined in #ControllerAdvice-annotated class. So, while my custom ExceptionHandlerExceptionResolver isn't called on all beans, default one does. Probably the solution would be to remove #ControllerAdvice and manually assign custom ResponseEntityExceptionHandler inside custom ExceptionHandlerExceptionResolver. I tried last way, but it appeared that I have to override a lot of methods from ExceptionHandlerExceptionResolver and in the end code looks very unclean. So, is there a way to make it in a different way, or maybe implement ExceptionHandlerExceptionResolver with custom handler cleaner?
As Ralph mentioned - as from Spring 4 (which by now had a stable release) ControlerAdvice's can be limited to Controler's with the specified annotations. Take a look at:
http://blog.codeleak.pl/2013/11/controlleradvice-improvements-in-spring.html
(second half of this article) for more details.
Put the Exception handling method in the Controller class and annotated the method with #ExceptionHandler. So this handler will be used only by this controller. -- And of course remove the #ControllerAdvice stuff.
Since Spring 4.0 you can use
#ControllerAdvice(assignableTypes = {OneOfControllersToApply.class})

How to map a path to multiple controllers?

I'm currently working on a spring based web application and have a special requirement that seems not (at least not out of the box) be provided by spring MVC. The application serves data for multiple users each organized in their own "company". Once a user has logged in, I'm able to identify to which company he belongs to.
The application itself is built with multiple "modules", each with it's own domain objects, DAO, Service and Controller classes. The idea behind this concept is that I can for example extend a certain controller class (let's say to use a different service class) based upon the user and here is my problem.
Since i do not want to change my request paths for certain users, I'm currently looking for a way how to serve a request issued on a certain request path with different instances of a controller based upon the user issuing the request.
I came up with the idea to attach a HTTP Header Field for the company
Example:
X-Company:12345
and have my controllers configured like this:
#Controller
#RequestMapping(value="/foo/")
public class FooController {
// ...
}
#Controller
#RequestMapping(value="/foo" headers="X-Company=12345")
public class SpecialFooController extends FooController {
// ...
}
However this is not possible, since spring MVC treats each header (except Content-Type and Accept) as a kind of restriction, so in my case it would handle all requests with the FooController instead of the SpecialFooController unless i add a "headers" restriction on the FooController as well, which is not practicable.
Is there some way how to customize this behaviour or some direction one could point me to look for? Or maybe someone has another idea how to achieve this. It'll be highly appreciated.
Thanks!
I'am not sure but I think you can do this with HandlerMapping. Have a look at the documentation
To take your own suggestion, you can use the #RequestHeader annotation in your controller methods:
#Controller
public class MyController {
#RequestMapping("/someAction")
public void myControllerMethod(#RequestHeader('X-Company-Id') String companyId) {
}
}
Or you could use #PathVariable:
#Controller
public class MyController {
#RequestMapping("/{companyId}/someAction")
public void myControllerMethod(#PathVariable("companyId") String companyId) {
}
}
Using this approach would mean that it is in fact different URLs for each company, but if you can set the company id header, I guess you also can suffix the URLs with the company id.
But there are also other possibilities. You could write an interceptor that puts the company id in a session or request variable. Then you wouldn't have to add the annotation to every controller method. You could also use a subdomain for each company, but that wouldn't look too pretty if the company id is a random alphanumeric string. E.g: companyone.mydomain.com, companytwo.mydomain.com
Edit
#RequestMapping can be added to the controller level as you know, so you should be able to do
#Controller
#RequestMapping("/controller/{companyId}")
as the base url, if that's a better option.
I was able to meet the requirement by making usage of a customized RequestCondition. By defining your own annotation that can be placed at the type and method level of a controller. Extending the RequestMappingHandlerMapping by your own implementation and overriding the getCustomTypeCondition() and getCustomMethodCondition() methods translates a controller annotation into your own RequestCondition.
When a request comes in, the custom RequestCondition will be evaluated and the annotated controller(method) will then be called to serve the request. However this has the downside, that one needs to remove a servlet-context.xml file and switch to the WebMvcConfigurationSupport class instead in order to be able to use your customized RequestMappingHandlerMapping class.
This question was also discussed here.
Edit:
A pretty good example using this can be found here.

Accessing Spring Controller Name from View

With Spring, how can i retrieve the following Controller attributes in the view?
Controller name
Controller's #RequestMapping URI
Action method name
Action method's #RequestMapping URI
One approach which i have tried is by creating a subclass of HandlerInterceptorAdapter and overriding postHandle. I register my subclass as an mvc:interceptor for a list of given paths - which is clunky to maintain but was the only way to avoid my interceptor being called for ResourceHandler requests (which i don't want). In my postHandle i can easily add the 2 name attributes, but not the URIs...
Parsing from the HttpRequest object requires constraints on all Controller RequestMappings. I.e. i must always map /Controller/Action or equiv scheme. Quite limiting.
Creating an ApplicationContext and querying that with the requestURI is too long-winded.
I am thinking about dropping the HandlerInterceptorAdapter and instead defining a BaseController for all my controllers to extend.
I wanted to ask before i do this, is there a better approach?
You haven't stated why you need to do this (it sometimes helps to include your motivation, as others can suggest alternative approaches).
But I'm guessing that the Spring 3.1 features loosely termed "end point documentation" may do what you are asking... See RequestMappingHandlerMapping in the Spring documentation which doesn't provide a lot of detail, so this example project is the best place to see it in action:
Spring MVC 3.1 Demo App
example controller
example JSP page

Resources