I'm trying to access /elmah.axd in my broswer, but it returns:
{"message":"No HTTP resource was found that matches the request URI 'http://services.domain.com/elmah.axd'."}
The server is local (127.0.0.1) and even on that I have my web.config Elmah settings to secure it this way:
<elmah>
<security allowRemoteAccess="true" />
</elmah>
My WebApiConfig looks like:
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Locally only you will be able to see the exception errors
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.LocalOnly;
// Web API routes
config.Routes.IgnoreRoute("elmah", "elmah.axd");
config.Routes.IgnoreRoute("allemah", "elmah.axd/{*pathInfo}");
config.Routes.IgnoreRoute("elmahgeneric", "{resource}.axd/{*everything}");
config.MapHttpAttributeRoutes();
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
// Remove the XML formatter
config.Formatters.Remove(config.Formatters.XmlFormatter);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
I even tried ignoring only one route at the time from any of the 3 combinations and no luck.
finally my global.asax looks like this:
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
}
Any hint or idea of what I could be missing, would be good.
Thanks in advance, really appreciate your time looking into this.
I finally made it.
By adding to the WebApiConfig.cs file
config.Routes.MapHttpRoute("AXD", "{resource}.axd/{*pathInfo}", null, null, new StopRoutingHandler());
The entire code of the WebApiConfig.cs file looks like this:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Locally only you will be able to see the exception errors
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.LocalOnly;
// Web API routes
config.MapHttpAttributeRoutes();
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
// Remove the XML formatter
config.Formatters.Remove(config.Formatters.XmlFormatter);
config.Routes.MapHttpRoute("AXD", "{resource}.axd/{*pathInfo}", null, null, new StopRoutingHandler());
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
And the final change is add this to the global.asax under application_start method
RouteTable.Routes.Ignore("{resource}.axd/{*pathInfo}");
Special thanks all who helped me with this issue.
When I added the following in in the global.asax under the application_start method:
RouteTable.Routes.Ignore("{resource}.axd/{*pathInfo}");
It did not work until I put it above ...
GlobalConfiguration.Configure(WebApiConfig.Register);
The order of the routes that you add to the Routes property is significant, because the application uses the first route in the collection that matches the URL.
https://msdn.microsoft.com/en-us/library/system.web.routing.routetable.routes(v=vs.110).aspx
The most likely problem is missing handlers to generate the error page.
Ensure the following handlers are configured your web.config file:
<system.web>
...
<httpHandlers>
...
<add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
</httpHandlers>
<system.webServer>
...
<handlers>
...
<add name="Elmah" verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
</handlers>
With those settings in place you should be able to access elmah.axd and secure it as expected.
You can grab a sample config file that was updated from a fresh project as an example here: https://brutaldev.com/download/30987439.zip
For me adding
config.Routes.IgnoreRoute("axd", "{resource}.axd/{*pathInfo}");
to WebApiConfig was enough.
Related
I'm building a WebApi that will be host on the server with a separate Application pool and port.
What I want is that when I call the server name with the port like this: https://server:8443 to go directly in the webApi and use a specific controller and action.
My WebApiConfig is looking like this:
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { controller = "Feedback", action = "GetFeedback", id = RouteParameter.Optional }
);
}
What I tried was to define a default controller and action when the server name is called. The problem here is that I get a 405 Method Not Allowed error.
Do you have any idea about how can I achieve something like this?
(I cannot use some URL path like https://server:8443/Controller/Action because this is exactly what I'm trying to eliminate).
Thank you!
I have a Web API that worked perfectly on development with all kind of HTTP requests (on the same controller), once I moved it to production (shared server, I don't even have access to it) the DELETE requests stopped working (the others are working fine), I get a 404 error:
Requested
URL https://www.example.com:443/Rejected-By-UrlScan~/API/Users/DeleteUser/1
Physical Path d:\xx\yy\example.com\Rejected-By-UrlScan
Logon Method Anonymous
Logon User Anonymous
This is (a part of) the web.config:
<system.web>
<customErrors mode="Off"/>
<authentication mode="None" />
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<remove name="WebDAVModule" />
</modules>
<handlers>
<remove name="WebDAV" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
The Delete Action:
[Authorize]
[RoutePrefix("Users")]
public class UsersController : ApiController
{
[HttpDelete]
[Route("DeleteUser/{id:int}")]
public void Delete(int id)
{
_UsersRepository.Delete(id);
}
And the AJAX call:
deleteUser = function (id, callback) {
$.ajax({
url: "../API/Users/DeleteUser/" + id,
type: "DELETE",
success: function () {
callback;
}
});
}
WebApiConfig.cs:
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//create json formatter and remove all others
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
jsonFormatter.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented;
config.Formatters.Remove(config.Formatters.FormUrlEncodedFormatter);
config.Formatters.Remove(config.Formatters.XmlFormatter);
}
An example of a working call on the same Controller:
getUsers = function (callback) {
$.get("../API/Users/GetUsers/", callback);
}
And the Action:
[Route("GetUsers")]
public IEnumerable<User> GetUsers()
{
return _UsersRepository.GetUsers();
}
In your IIS do you have the URLScan extension configured ?
https://www.iis.net/downloads/microsoft/urlscan
UrlScan is a security tool that restricts the types of HTTP requests that IIS will process.
The "Rejected-By-UrlScan" in your URL suggests that the extension may be configured to reject "Delete" requests.
You can ask your Administrator of the Server hosting the IIS about whether Delete requests are configured to be allowed in the IIS.
The URL is wrong in the JS snippet. It should be
deleteUser = function (id, callback) {
$.ajax({
url: "[Application_Path]/Users/DeleteUser/" + id,
type: "DELETE",
success: function () {
callback;
}
});
}
[RoutePrefix("Users")] overrides the default routing, so there should be no "API" in the URL.
You should remove the [Application_Path] and put your virtual directory name or use the #Url.Action
I had to got it to work so I changed the type of the request from DELETE to POST and it works perfectly:
[Authorize]
[RoutePrefix("Users")]
public class UsersController : ApiController
{
[HttpPost]
[Route("DeleteUser/{id:int}")]
public void Delete(int id)
{
_UsersRepository.Delete(id);
}
deleteUser = function (id, callback) {
$.ajax({
url: "../API/Users/DeleteUser/" + id,
type: "POST",
success: function () {
callback;
}
});
}
I am using Microsoft.AspNet.WebApi V5.2.3, Microsoft.Owin.Host.HttpListener 3.0.1. Started with the following configuration:
public void Configuration(IAppBuilder appBuilder)
{
HttpConfiguration config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
appBuilder.UseWebApi(config);
}
And the API Controller class is declared using:
[EnableCors("*", "*", "*")]
public class CWebAPIController : ApiController
{
[Route("API/System/Login"), HttpGet]
public IHttpActionResult Login(string UserID, string Password)
{
.... bla bla bla .....
}
}
I am able to invoke the API above using HttpClent on the same computer, but if I trying to invoke the API from another computer (within the same subnet), I got 400 BadRequest response.
I believe this is CORS issue, but may I know how can I solve this. Searching in google yield many results and there are so many version / implementation of WebApi that I don't know which one is correct after trying one whole day.
Thanks in advance
EnableCors attribute should work on your API controller. Alternatively you can do one of the followings.
If you want to allow access from any computer then you can use
appBuilder.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
Else if you want to have control on which domain/computers to allow then use
var cors = new EnableCorsAttribute("www.example.com", "*", "*");
config.EnableCors(cors);
You'll need to install Microsoft.Owin.Cors package.
You need to bring in the Microsoft.Owin.Cors package, and maybe the Microsoft.AspNet.Cors package into your project and initialize CORS in your Startup class like this:
var corsPolicy = new CorsPolicy
{
AllowAnyHeader = true,
AllowAnyMethod = true,
AllowAnyOrigin = true,
SupportsCredentials = true
};
corsPolicy.ExposedHeaders.Add("x-markit-currentpage");
corsPolicy.ExposedHeaders.Add("x-markit-totalpages");
corsPolicy.ExposedHeaders.Add("x-markit-totalresults");
app.UseCors(new CorsOptions
{
PolicyProvider = new CorsPolicyProvider { PolicyResolver = context => Task.FromResult(corsPolicy) }
});
I have added cors like this:
public void Configuration(IAppBuilder app)
{
var config = ConfigureApi();
app.UseWebApi(config);
}
private HttpConfiguration ConfigureApi()
{
var config = new HttpConfiguration();
config.Routes.MapHttpRoute(
"DefaultApi",
"{controller}/{action}/{id}",
new { id = RouteParameter.Optional });
config.MessageHandlers.Add(new CorsMessageHandler ());
return config;
}
CorsMessageHandler is present here:
https://github.com/Microsoft/FetchClimate/blob/master/src/Service/Frontend/CORS/CorsMessageHandler.cs
Hope it will work.
For self hosting we need to run the command below in Admin mode.
netsh http add urlacl url=http://+:<port>/ user=<user id>
Alright, I'm having a tough time locating the problem since it works locally but after doing a publish the results are simply:
Error Code: 403 Forbidden. The server denied the specified Uniform Resource Locator (URL). Contact the server administrator. (12202)
The code:
[RoutePrefix("api/v1/project")]
public class ProjectController : BaseApiController
{
[HttpGet]
public HttpResponseMessage GetProjects()
{
HttpResponseMessage resp = new HttpResponseMessage(HttpStatusCode.OK);
if(User.Identity.IsAuthenticated)
{
var model = new ModelFactory().CreateProjects();
resp = Request.CreateResponse(HttpStatusCode.OK, model);
}
return resp;
}
}
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// all actions under /project routes require authentication
config.Routes.MapHttpRoute(
name: "ProjectApi",
routeTemplate: "api/v1/{controller}/{action}/{apikey}",
defaults: new { apikey = RouteParameter.Optional },
constraints: new { controller = "project" },
handler: new BasicAuthHandler(config));
// all routes requires an api key
config.MessageHandlers.Add(new ApiKeyHandler());
config.MapHttpAttributeRoutes();
}
}
I've tried several "solutions" from the net yet none of them seems to fix this. I've added the:
// Stop IIS/Asp.Net breaking our routes
RouteTable.Routes.RouteExistingFiles = true;
from: http://www.grumpydev.com/2013/09/17/403-14-error-when-trying-to-access-a-webapi-route/
And also made sure that:
<modules runAllManagedModulesForAllRequests="true">
Having the code above, using the following link gives a successful connection where it checks (in the correct order) the APIkey (ApiKeyHandler), checks if the user needs to log in(BasicAuthHandler) and then goes to method in the controller ({controller}/{action}).
// THIS WORKS!
http://localhost:51077/api/v1/project/getprojects?apikey=123456
then we do a publish and tries the same thing
// This is haunted with number 403
http://website.com/api/v1/project/getprojects?apikey=123456
gives the Error Code: 403 Forbidden.
I am clueless. I've even tried changing the whole publish folder's security settings for "NETWORK SERVICE" to full access.. no change.
Let me know if you need any more intel.
Called the web server machine fellas and they had a firewall blocking incoming webapi calls with authenticating. It now works as it should :)
I have the following set-up in my config:
routes.MapHttpRoute("NoAuthRequiredApi", "api/auth/", new { id = RouteParameter.Optional } );
routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}", new { id = RouteParameter.Optional }, null, new WebApiAuthenticationHandler());
If I post anything to the url on api/auth the message handler still runs and checks for an Auth-Token header. Is there any reason why this is happening? Is there something I should change in the configuration of the WebApi routes? I obviously don't want any auth token on the header when making requests to the auth controller because at that point I'm trying to retrieve the token for use on other controllers.
Your topmost route is never being matched as there is no indication of which controller is required. Add the controller name in as a default. (And remove the ID optional if this is not required).
So:
routes.MapHttpRoute(
name: "NoAuthRequiredApi",
routeTemplate: "api/auth/",
defaults: new { Controller = "Auth" }
);