Deleting media using the WordPress REST API - wordpress

I'm trying to delete media from the WordPress Library using the rest-api with cookie authentication. I can create a file (POST) and retrieve (GET) the file contents, but DELETE do not work. I'm using IIS Version 10.0.
Note: this code is ran on the website domain, not from another domain.
Things I've tried:
Enabling WebDAV on the server
Used Basic WordPress authentication plugin
Here is the XMLHttpRequest that I'm using:
var apiCall = new XMLHttpRequest();
apiCall.onreadystatechange = function() {
...
};
apiCall.open("DELETE", wpApiSettings.root + "wp/v2/media/");
apiCall.setRequestHeader("X-WP-Nonce", wpApiSettings.nonce);
apiCall.send("2000");
The error I get back:
HTTP Error 401.0 - Unauthorized. You do not have permission to view this directory or page.
This error is never present with GET or POST, only when doing the delete, which makes me think about the authentication within IIS. Maybe it's not even reaching the WordPress engine and IIS is intercepting the request and denying it. Which I thought enabling WebDAV would fix, but sadly, it did not.

First, 401 error typically indicates the request is not authenticated. We have to set up the credential based on the authentication mode in IIS. If it requires basic credential, we need to set up the HTTP header like below,
xhr.setRequestHeader('Authorization', 'Basic ZWx1c3VhcmlvOnlsYWNsYXZl');
How to send a correct authorization header for basic authentication
In addition, for supporting Delete HTTP verb, please add the below code to your the webconfig file.
<system.webServer>
<validation validateIntegratedModeConfiguration="false"/>
<modules runAllManagedModulesForAllRequests="true">
<remove name="WebDAVModule"/> <!-- ADD THIS -->
</modules>
Here is a related discussion.
WebAPI Delete not working - 405 Method Not Allowed

Related

I cannot get around the "No 'Access-Control-Allow-Origin' header is present on the requested resource" problem

I have a WebApi done with .net core 3.1. It's hosted in the IIS in my laptop. At the same time I developed an angular UI and published it in the same IIS. Same IIS but each application has it's own port. When I insert a new record from the ui, it is done successfully, meaning the POST is successful. If I try to modify it, meaning a PUT, It does not go through. Seeing the developer tools in the browser, the console displays a message saying the Access to XMLHttpRequest at 'http://blablabla.com:777/api/items/333' from origin [the web application url goes here which is something like http://blablabla.com:778] has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I have tried what I found in this website. Meaning that I modified the Startup.cs adding this in the ConfigureServices:
services.AddCors(options => {
options.AddPolicy(name: "Policy1", builder => {
builder.AllowAnyOrigin().AllowAnyMethod().WithHeaders(HeaderNames.ContentType, "Access-Control-Allow-Origin");
});
options.AddPolicy(name: "Policy2", builder => {
builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader();
});
options.AddPolicy(name: "Policy3", builder => {
builder.WithOrigins("http://name.com:7771").AllowAnyHeader().AllowAnyMethod();
});
});
and this in the Configure method (after app.UseRouting();):
app.UseCors("Policy2");
I have no idea about what else to try.
After some time of full of frustration with this problem I finally found a solution.
Having this problem when trying to update (PUT). I can insert (POST) without any problem.
Access to XMLHttpRequest at 'http://superinspections.com:8000/api/Cities/12962'
from origin 'http://superinspections.com:8001' has been blocked by CORS policy: No 'Access-Control-Allow-Origin'
header is present on the requested resource.
Access to XMLHttpRequest at from origin has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Solution:
In IIS version 10:
click on the website you are having the access origin problem with (the back end) and double click on HTTP Reaponse Headers icon. Add the following entries:
Access-Control-Allow-Headers with valut *
Access-Control-Allow-Methods with value POST, PUT, GET, OPTIONS
Access-Control-Allow-Origin with value *
This will add the following to the web.config file of that site:
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="*" />
<add name="Access-Control-Allow-Methods" value="POST, PUT, GET, OPTIONS" />
</customHeaders>
</httpProtocol>
</system.webServer>
After running the progran I did not have the Access-Control-Allow-Origin problem but I had a new message: HTTP 405 Method Not Allowed.
To solve this I found the solution here:
Web API Put Request generates an Http 405 Method Not Allowed error
And tha solution was to remove the WebDAV module with the following entry in the web config files in both, front end and back end.
Place this inside <system.webServer>.
<modules runAllManagedModulesForAllRequests="true">
<remove name="WebDAVModule"/> <!-- add this -->
</modules>
and add this to the handlers section:
<handlers>
<remove name="WebDAV" />
...
</handlers>
After that, the application was working as expected. I need to add that I needed to keep the cors configuration in the Startup.cs.
In the ConfigureServices:
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder
.AllowAnyMethod());
});
And in the configure, between app.UseRouting() and app.UseAuthentication()
app.UseCors("CorsPolicy");
and the attribute [EnableCors("CorsPolicy")] in the controllers that may need it.
For what I need, which is development and testing of an Angular application, this is sufficient. You may play with the Cors configuration in the client in order to get rid of the server setup, as I will do when I complete the development. But the WebDAV part I think that is unavoidable.
One thing I need to add is that the web config changes go away if you republish your back end.
Any comments will be appreciated. Specially an explanation of what is WebDAV.

.NET Sessions with React Cross Origin

I'm currently working on putting together my first React application, and I'm using fetch in order to communicate with my API which is currently being developed using the .net webapi. I am running into a bit of a wall however with getting my session variables on the .net server to work properly. Currently I'm running the react application separately locally and using the url of my .net server in order to make a request to the API server. Both of which are on the same machine despite using separate ports. The request is going through, but when i try to make a follow up request to get the current user information, it is not pull any information. I have looked, and it seems no cookies are being stored locally in the browser, so I'm assuming this is the issue. The code for my fetch looks something like this:
let url = "http://localhost:50405";
let requestObject = {
mode: 'cors',
credentials: 'include'
}
fetch(url + '/api/currentuser/get', requestObject).then((res) => {
console.log(res);
});
However, res is null even after the session has been set.
Also, on the server end, I have the following in my config file in order to allow for the cross-site request:
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="http://localhost:3000" />
<add name="Access-Control-Allow-Credentials" value="true" />
</customHeaders>
</httpProtocol>
I figured I would see if there's something obvious I am missing here.

CORS Server Settings for ASP.net?

I am attempting to implement CORS in my web API layer of a project and limit the domains that the API will allow requests from. I am using the app.UseCors() method in my Startup.cs to setup CORS globally:
new public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
SystemConfiguration config = base.InitializeWebApiConfiguration();
// add our Cors Policy
app.UseCors(new CorsOptions
{
PolicyProvider = new CorsPolicyProvider
{
PolicyResolver = context => Task.FromResult(CorsPolicyHelper.GetCorsPolicy())
}
});
var authorizeAttribute = new AuthorizeAttribute();
config.HttpConfiguration.Filters.Add(authorizeAttribute);
app.UseNinjectMiddleware(() => this._kernel.Value);
app.UseNinjectWebApi(config.HttpConfiguration);
InitializeMappingProfiles();
}
The CorsPolicyHelper simply sets up a CorsPolicy object with the settings for Headers, Methods, Origins, etc. which are:
-AllowAnyMethod = true
-AllowAnyHeader = true
-SupportCredentials = true
-PreflightMaxAge = 604800 (7 days)
-Origins: "https://example.dev.com", "https://example-ci.test.com", "https://example-qa.test.com"
The problem I have is CORS is working on my dev and CI servers, however, it does not work on my QA server. My request has the correct origin "https://example-qa.test.com" but the resposne header does not include "Access-Control-Allow-Origin", and I am getting back:
XMLHttpRequest cannot load https://services-qa.test.com/api/data/. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://example-qa.test.com' is therefore not allowed access. The response had HTTP status code 500.
I'm not sure what the difference is between my dev, CI, and QA servers are. They should be the same. But is it possible there is a server setting I need to change on my QA server to make it work? Possibly something in IIS?
Try this in your Web API's web.config (this version is cut down, but I'm sure you can put it together).
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>
So, it's working 2 out of 3. My understanding is that for a preflight request to be successful, your IIS site needs to be set to allow anonymous access. Check your IIS settings on all three boxes to verify.
It ended up being a different problem. The app.UseCors() method I described above does work to enable CORS globally. The problem was in a transform I had for my web.config for the QA environment. It was a problem with the connection to the server that gives me my identity token. Thanks for the suggestions though!

Accessing .ASPX page on password protected site from within same site

We recently migrated our staging server to a new hosting provider and setup forms authentication from within the hosting account control panel so that crawlers and unwanted visitors could not access it.
Now we are finding at least one area of the site's logic that is failing due to HTTP 401 Unauthorized.
There is a section of the site that generates PDF for site users. The conversion is from HTML to PDF. The source pages are .ASPX written in C#. The generate .HTM by downloading the ASPX files using their URL, such as http://www.mysite.com/mypage.aspx.
Now that the site is password protected, these routines fail with the HTTP 401 and I'm not sure how to overcome this. We don't want to remove the site authentication because we don't want anything accessing it.
Can anyone point me on how to code around this so that our internal routines will have access to local pages like we need?
EDIT
Some more detail. Since this is just a development site, I performed a quick and dirty configuration from within the hosting provider's control panel to enable Folder Security. I added the root folder '/' and then created 2 users. This works fine. When I go to the site I am prompted with what appears to be a forms authentication dialog box. I enter my username and password, access is granted.
I've noted that this configuration created 4 files in my root /' web site folder. They are .htaccess, .htpasswd, .htgroup, and .htfolders. This site has a lot of folders. Configuring each one in this manner would be time consuming and tedious. Therefore the '/' root configuration.
Our purpose is to block access to crawlers/search engines and also casual visitors who stumble onto the hostname.
This configuration causes the side effect that a small part of the site can no longer access it's own pages via http:// without getting an HTTP 401 error. What I would love to do is configure all of this using <security><ipSecurity>, blacklist all except for myself and the web site, but the provider doesn't install the needed IP module to do this.
The C# code that is receiving the HTTP 401 is:
webrequest = (HttpWebRequest)WebRequest.Create(url);
webrequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322)";
webrequest.Timeout = 600000;
resp = webrequest.GetResponse();
I've also tried:
CredentialCache credCache = new CredentialCache();
credCache.Add(new Uri(url), "Basic", new NetworkCredential("username", "password"));
webrequest = (HttpWebRequest)WebRequest.Create(url);
webrequest.Credentials = credCache;
webrequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322)";
webrequest.Timeout = 600000;
resp = webrequest.GetResponse();
Both methods receive HTTP 401 Unauthorized. I really don't want to fix this in the C# code because this security issue will not exist on the live site. I would much rather perform this configuration in web.config and/or the .ht* files if needed.
So, I am wondering, is there anything I can place in web.config that will help? Does anyone see a problem the way this is setup? (Other than it's not working! :P)
If you want you can remove authentication for just one page as follows.
<location path="mypage.aspx">
<system.web>
<authorization>
<allow users="*"/>
</authorization>
</system.web>
</location>

ASP.net HTTP 404 - File not found instead of MaxRequestLength exception

I have a file upload control on my webpage. The maximum request length is set to 8 MB (maxRequestLength = 8192). I also have server validation that throws an error if the file is more than 4MB. The reason that its 8MB in the config is the leverage that's given to the user and also so that the application can be tested.
If I upload a file that's 9MB, I get thrown an exception Maximum request length exceeded., which is fine and working as expected. But when I try to upload a file that's 1GB, it shows me a HTTP 404 - File not found. Can someone please explain why this is happening and how can I get it to throw me a maxRequestLength exception?
I'm using IIS6.
I experienced this condition today (HTTP 404 on large file upload with IIS 7) but I thought I had made all the correct configuration settings. I wanted to upload files up to 300MB so I made the following web.config settings in a sub-folder of the application:
<configuration>
<system.web>
<httpRuntime maxRequestLength="307200" />
</system.web>
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="314572800" />
</requestFiltering>
</security>
</system.webServer>
</configuration>
This configuration worked in test but when I copied the updated files including the web.config to the production server, I received the HTTP 404 error on uploading a 90MB file. Smaller files under the application-wide limit of 30MB were working fine, so I knew it was a request size problem of some sort.
I figured there was a chance IIS had cached some application settings and just hadn't updated them, so I recycled the Application Pool, after which everything worked as expected.
I feel none of the answers here explain why you get a 404, they just tell you the usual stuff of how to fix the problem.
The 404 is not due to misconfiguration, it is intentional and documented behaviour:
When request filtering blocks an HTTP request because an HTTP request exceeds the request limits, IIS 7 will return an HTTP 404 error to the client and log one of the following HTTP statuses with a unique substatus that identifies the reason that the request was denied:
HTTP Substatus Description
404.13 Content Length Too Large
404.14 URL Too Long
404.15 Query String Too Long
These substatuses allow Web administrators to analyze their IIS logs and identify potential threats.
In addition, when an HTTP request exceeds the header limits that are defined in the in the <headerLimits> element, IIS 7 will return an HTTP 404 error to the client with the following substatus:
HTTP Substatus Description
404.10 Request Header Too Long
This is a bit of an old thread, but I thought I should add my experiences with this.
I faced the same problem with large file uploads and the web api. A 404.13 is thrown before it gets to a controller at all, so I had to find out where to jump in and handle this case.
My solution was the following web.config entries:
I handle the 404.13 by redirecting it to a mvc controller (it could be a webforms page just the same), and regular 404 errors hit my 404 route. it's critical that the responseMode="redirect" for the 404.13
<httpErrors errorMode="Custom">
<remove statusCode="404" subStatusCode="-1" />
<error statusCode="404" subStatusCode="13" path="/errors/filesize" responseMode="Redirect" />
<error statusCode="404" path="/errors/notfound" responseMode="ExecuteURL" />
</httpErrors>
Then, in my Errors controller, I have the following:
public ActionResult FileSize()
{
Response.StatusCode = 500;
Response.StatusDescription = "Maximum file size exceeded.";
Response.End();
return null;
}
Again, this could be a regular webforms page.
To my knowledge, there is no way to gracefully handle exceeding IIS's "maxRequestLength" setting. It can't even display a custom error page (since there is no corresponding HTTP code to respond to). The only way around this is to set maxRequestLength to some absurdly high number of kbytes, for example 51200 (50MB), and then check the ContentLength after the file has been uploaded (assuming the request didn't time out before 90 seconds). At that point, I can validate if the file <=5MB and display a friendly error.
You can also try this link.
You could also try something like this:
private void application_EndRequest(object sender, EventArgs e)
{
HttpRequest request = HttpContext.Current.Request;
HttpResponse response = HttpContext.Current.Response;
if ((request.HttpMethod == "POST") &&
(response.StatusCode == 404 && response.SubStatusCode == 13))
{
// Clear the response header but do not clear errors and transfer back to requesting page to handle error
response.ClearHeaders();
HttpContext.Current.Server.Transfer(request.AppRelativeCurrentExecutionFilePath);
}
}
I have found that this problem can also be caused on IIS7 (and presumably IIS6) when the URLScan tool is installed and running on the site.
When uploading the file to a website i was receiving the message "File or directory not found. The resource you are looking for might have been removed, had its name changed, or is temporarily unavailable."
If the problem is being caused by URLScan then if you try to upload the large file to the site whilst browsing the site on the hosting server itself, you will be served a full asp.net error message instead of a 404 that mentions URLScan.
You can also check if URLScan is running on you site in IIS7 by viewing the ISAPI Filters for the website in IIS, URLScan will be listed if it is used.
This can be fixed by altering the ini file for URLScan is located at "%WINDIR%\System32\Inetsrv\URLscan" and changing the MaxAllowedContentLength.
The MaxAllowedContentLength is in bytes.
This may require a IIS restart to take effect, though it did not when i tried it myself with IIS7.
http://www.iis.net/learn/extensions/working-with-urlscan/urlscan-overview
http://www.iis.net/learn/extensions/working-with-urlscan/common-urlscan-scenarios
You could configure the default error page in IIS itself.
The request limit is a setting is IIS. Open the Request Filtering section of your site in IIS and select Edit Request Settings. For me it was that simple.
A more detailed How To from Microsoft.
https://learn.microsoft.com/en-us/iis/configuration/system.webserver/security/requestfiltering/#how-to-edit-the-request-filtering-feature-settings-and-request-limits
I just met the same problem, i made the similar operation like pseudocoder's answer but have different( i think maybe is not the cache) :
edit your Web.config --> maxRequestLength
<system.web>
<httpRuntime maxRequestLength="1073741824" executionTimeout="3600" />
</system.web>
edit this:
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="1073741824" />
</requestFiltering>
</security>
just like this,and try it.
The problem with the 1GB uploads is more browser related. I have had heaps of trouble with it and tried a lot of solutions but really the question to ask here is what are the chances of this happening in the real world for your business needs and maybe it should be recorded as a known issue in the business rules or non functional requirements document.

Resources