How do I return an HTTP 403 from a WebAPI method? I've tried throwing an HttpResponseException with HttpStatusCode.Forbidden, and I've tried
return request.CreateErrorResponse(HttpStatusCode.Forbidden, pEx);
Neither of which work. Both ALWAYS return an HTTP 200. What am I missing? It has to be something simple but I don't see it.
You might have a problem with your routing configuration. Below is a working sample. Put it in your controller and see if it works. If it doesn't, check your routing with a diagnostic tool (i.e. Cobisi Routing Assistant).
public HttpResponseMessage GetSomeString(int id)
{
// This method is not allowed!
return this.Request.CreateErrorResponse(HttpStatusCode.Forbidden, "This method is not allowed!");
}
Related
In my React Native app, I'm trying to hit an endpoint in an API written in .Net. I've got the API code on my local machine, so I'm trying to hit it with a call to fetch(127.0.0.1:5000/api/token). This returns a 404 error. If I instead hit fetch(127.0.0.1:5000/), it returns successfully. The API code hit in this case is HomeController.cs, which contains this:
namespace InTowAPI2.Controllers
{
[AllowAnonymous]
[Route("/a")]
public class HomeController : Controller
{
// GET api/values
[HttpGet]
public string Get()
{
return "Ok";
}
}
}
When I make the call to fetch(127.0.0.1:5000/), it returns "Ok" and hits the breakpoint I set in HomeController.cs. The other file ValuesController.cs that should be hit when I call fetch(127.0.0.1:5000/api/token) contains this code (plus more after it):
namespace InTowAPI2.Controllers
{
[AllowAnonymous]
[Route("/api/[controller]")]
...
...
When I call fetch(127.0.0.1:5000/api/token), the breakpoint in ValuesController.cs is not hit, and it returns a 404 error.
What I tried to do to troubleshoot this was, since HomeController.cs was working, I replaced [Route("/")] with [Route("/api")], and made a call to fetch(127.0.0.1:5000/api). This also returned a 404 error.
What I Want To Know:
Why is it that hitting the API code containing [Route("/")] with fetch(127.0.0.1:5000/) works, but modifying it to hit [Route("/api")] with fetch(127.0.0.1:5000/api) throws a 404 error?
The issue is the routing.
[Route("/api/[controller]")]
This RouteAttribute definition will route the endpoint to the name of the controller.
The other file ValuesController.cs that should be hit...
Seems like you controller name is ValuesController, which would create an endpoint on /api/values, not /api/token.
To fix this, do one of the following things:
Change the name of the controller from ValuesController to TokenController.
Change the RouteAttribute from [Route("/api/[controller]")] to [Route("/api/token")].
I am developing a standalone .Net Core API targeting framework .Net Core 2.2.The authentication scheme is JWTBearerTokens connecting to our ADFS Identify server.
When I call an API endpoing decorated with the [Authorize] attribute I am getting a 401 Unauthorized response, which is expected and default behaviour.
What I want to do next is instead of having that same call return a 401, I would like to return the status code to be 404. (I don't want to get into great details of why 404. Simply, I do not want to expose that the endpoint exists if a valid token is not included in request)
In previous .Net Framework WebAPI you could create your own attribute and override the HandleUnauthorizedRequest method and return the status code you want.
I have reviewed the documentation on policy-based authorization, but have not tried the sample or tried implementing it. The policy handler looks more to do with handling (return success or fail) if a policy is not fulfilled. I do not see anywhere where you can return a different status code on failure. So that only would make sense if I start checking against actual Policies.
Any insights?
Returning 404 instead of 401 is bad practice(as mentioned in the comments by #Chris Pratt) and must be avoided. Consider these cases,
You're leaving the project to someone else and they can't figure why 404 is returned
A 404 is returned when you call the homepage/Index page. Poor ideology.
Later on in the project, you decide to allow post requests without authentication. So on and so forth.
Anyways, as part of the community, I'll give you the answer...
Add this to your global.asax
void Application_EndRequest(object source, System.EventArgs args)
{
if (Response.StatusCode == 401)
{
Response.ClearContent();
Response.RedirectToRoute("ErrorH", (RouteTable.Routes["ErrorH"] as Route).Defaults);
}
}
And in routeConfig, create a route for your errorHandler :
routes.MapRoute(
"ErrorH",
"Error/{action}/{errMsg}",
new { controller = "CustomController", action = "Change401To404", errMsg = UrlParameter.Optional }
);
And in your custom controller :
public class CustomController : Controller //or Base
{
public ActionResult Change401To404(){
//Do whatever you want
}
}
PS: This is not the only way, there are many other ways to do it. But at least in this method, you can differentiate real 404 responses from 401 responses.
I wrote a spring-mvc controller method to get an array of values in the request parameter.The method looks like below
/**
Trying to get the value for request param foo which passes multiple values
**/
#RequestMapping(method=RequestMethod.GET)
public void performActionXX(HttpServletRequest request,
HttpServletResponse response,
#RequestParam("foo") String[] foo) {
......
......
}
The above method works fine when the request url is in below format
...?foo=1234&foo=0987&foo=5674.
However when the request url is in below format the server returns 400 error
...?foo[0]=1234&foo[1]=0987&foo[2]=5674
Any idea how to fix the method to cater to the second format request url?
This is not possible with #RequestParam. What you can do is implement and register your own HandlerMethodArgumentResolver to perform to resolve request parameters like
...?foo[0]=1234&foo[1]=0987&foo[2]=5674
into an array. You can always checkout the code of RequestParamMethodArgumentResolver to see how Spring does it.
Note that I recommend you change how the client creates the URL.
The server is supposed to define an API and the client is meant to follow it, that's why we have the 400 Bad Request status code.
I resolved this issue using the request.getParameterMap().Below is code.
Map<String,String> parameterMap= request.getParameterMap();
for(String key :parameterMap.keySet()){
if(key.startsWith("nameEntry")){
nameEntryLst.add(request.getParameter(key));
}
}
This Web API action returns an HTTP 500 (Internal Server Error) status code:
public IHttpActionResult Post()
{
return InternalServerError();
}
But this action returns an HTTP 400 (Bad Request) status code:
public IHttpActionResult Post()
{
return InternalServerError(new Exception());
}
I would expect both actions to return a 500 status code and the second action puts some of the error's details in the response body.
My first thought is that this is a bug but I wanted to get some other input. Is there any good reason why a 400 should be returned in the second action instead of a 500?
UPDATE:
The documentation on this method reads:
Creates an System.Web.Http.Results.ExceptionResult (500 Internal Server Error) with the specified exception.
I'm thinking more and more this is a bug.
Right, this was a known issue which was fixed after Web API 2 release...you can use the following workaround to fix this issue..example:
return new ResponseMessageResult(Request.CreateErrorResponse(HttpStatusCode.InternalServerError, invalidOpException));
Following was the issue that was logged before:
https://aspnetwebstack.codeplex.com/workitem/1318
I'm building RESTful service using Microsoft ASP.NET Web API.
My problem concerns HttpErrors that Web API throws back to user when something go wrong (e.g. 400 Bad Request or 404 Not Found).
The problem is, that I don't want to get serialized HttpError in response content, as it sometimes provides too much information, therefore it violates OWASP security rules, for example:
Request:
http://localhost/Service/api/something/555555555555555555555555555555555555555555555555555555555555555555555
As a response, I get 400 of course, but with following content information:
{
"$id": "1",
"Message": "The request is invalid.",
"MessageDetail": "The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method 'MyNamespaceAndMethodHere(Int32)' in 'Service.Controllers.MyController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter."
}
Something like this not only indicates that my WebService is based on ASP.NET WebAPI technology (which isn't that bad), but also it gives some information about my namespaces, method names, parameters, etc.
I tried to set IncludeErrorDetailPolicy in Global.asax
GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Never;
Yeah, that did somehow good, now the result doesn't contain MessageDetail section, but still, I don't want to get this HttpError at all.
I also built my custom DelegatingHandler, but it also affects 400s and 404s that I myself generate in controllers, which I don't want to happen.
My question is:
Is there any convinient way to get rid of serialized HttpError from response content? All I want user to get back for his bad requests is response code.
What about using a custom IHttpActionInvoker ?
Basically, you just have to send an empty HttpResponseMessage.
Here is a very basic example :
public class MyApiControllerActionInvoker : ApiControllerActionInvoker
{
public override Task<HttpResponseMessage> InvokeActionAsync(HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken)
{
var result = base.InvokeActionAsync(actionContext, cancellationToken);
if (result.Exception != null)
{
//Log critical error
Debug.WriteLine("unhandled Exception ");
return Task.Run<HttpResponseMessage>(() => new HttpResponseMessage(HttpStatusCode.InternalServerError));
}
else if (result.Result.StatusCode!= HttpStatusCode.OK)
{
//Log critical error
Debug.WriteLine("invalid response status");
return Task.Run<HttpResponseMessage>(() => new HttpResponseMessage(result.Result.StatusCode));
}
return result;
}
}
In Global.asax
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpActionInvoker), new MyApiControllerActionInvoker());
One other important thing you could do, not related to Web Api, is to remove excessive asp.net & IIS HTTP headers. Here is a good explanation.
I believe your approach of using the message handler is correct because regardless of the component in the Web API pipeline that sets the status code to 4xx, message handler can clear out response body. However, you do want to differentiate between the ones you explicitly set versus the ones set by the other components. Here is my suggestion and I admit it is a bit hacky. If you don't get any other better solution, give this a try.
In your ApiController classes, when you throw a HttpResponseException, set a flag in request properties, like so.
Request.Properties["myexception"] = true;
throw new HttpResponseException(...);
In the message handler, check for the property and do not clear the response body, if the property is set.
var response = await base.SendAsync(request, cancellationToken);
if((int)response.StatusCode > 399 && !request.Properties.Any(p => p.Key == "myException"))
response.Content = null;
return response;
You can package this a bit nicely by adding an extension method to HttpRequestMessage so that neither the ApiController nor the message handler knows anything about the hard-coded string "myException" that I use above.