Accessing .ASPX page on password protected site from within same site - asp.net

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>

Related

Deleting media using the WordPress REST API

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

Formsauthentication and owin facebook authentication side by side (web forms)

I need to add Facebook (and later google etc.) authentication to an existing asp.net webforms application using forms authentication.
Im almost there but there seems to be a conflict between formsauthentication and the owin authentication. My solution is based on the standard VS 2015 template.
The relevant code to redirect to the the external authentication provider (facebook) is as follows:
string redirectUrl =
ResolveUrl(String.Format(CultureInfo.InvariantCulture,
"~/Account/RegisterExternalLogin?{0}={1}&returnUrl={2}", IdentityHelper.ProviderNameKey,
provider, ReturnUrl));
var properties = new AuthenticationProperties { RedirectUri = redirectUrl };
Context.GetOwinContext().Authentication.Challenge(properties, provider);
Response.StatusCode = 401;
Response.End();
This works if i turn off forms authentication. If I have forms authentication, the user gets redirected to the forms authentication url defined in the web.config:
<authentication mode="Forms">
<forms name=".ASPXAUTH_Test" loginUrl="~/start/login.aspx" timeout="60" >
</forms>
</authentication>
From my understandint the Http Status code (401) triggers the redirect to the Url in the web.config. I tried to set other status codes, but they don't work at all.
When I turn off forms authentication in the web.config, the actual login process still works (surprisingly) but if I access a protected page while not having logged in a get an ugly IIS error page, instead of being redirected.
It seems, that I can't get work forms authentication and owin external authentication to work together properly :-(
So far all alternatives don't seem enticing to me:
- switch to the identity framework (in our specific environment, this is absolutly NOT an option. I just mention it for the sake for completness)
- try to use web.api or something similar (which probably has the same problem)
- let go of owin external authentication and implement everything by hand
Has anyone been able to make this work? Any help is appreciated. Thanks in advance.
Halleluja, I found the solution:
From .Net 4.5 it is possible to prevent the forms redirect in the response:
Response.SuppressFormsAuthenticationRedirect = true;
so the working code would look like:
var owinContext = Context.GetOwinContext();
owinContext.Authentication.Challenge(properties, provider);
Response.SuppressFormsAuthenticationRedirect = true;
Response.StatusCode = 401;
Response.End();

Forms Authentication SSO - Why does User.Identity.IsAuthenticated == false

I'm trying to set up SSO on two separate IIS web sites (with a common domain) using Forms Authentication. I'm using the common approach of setting the auth cookie to the common domain and using matching machine key to enable decryption.
This works with no issues on test sites that I created. However, when trying to implement this in a legacy Web Forms site, I'm running into something that I don't understand.
When I log into one site, the test code on the second site has the following results:
var cookie = FormsAuthentication.GetAuthCookie("username", false); // works
var ft = FormsAuthentication.Decrypt(cookie.Value); // returns correct info
var isAuthentication = User.Identity.IsAuthenticated; // false
As an added bonus, whenever I sign in one site the other gets signed out (happens both ways.)
There must be something fundamental that I'm missing here.
Why is User.Identity.IsAuthenticated set to false, even though the FormsAuthentication ticket seems to be decrypting with no issues?
UPDATE: as pointed out below - FormsAuthentication.GetAuthCookie is not a valid way to obtain the existing auth cookie. Which brings me to this: I can see the top domain cookie in the browser, but it doesn't show up in the request. I suspect this is where the problem is occuring.
Solution: Both sites were not targeting the same version of .Net Framework as specified by the web.config:
<httpRuntime targetFramework="4.5" />
<compilation debug="true" targetFramework="4.5" />
Updating both sites to target the same framework fixed the problem.
The GetAuthCookie creates a new cookie:
http://msdn.microsoft.com/en-us/library/vstudio/3fay1e4k(v=vs.100).aspx
Creates an authentication cookie for a given user name. This does not set the cookie as part of the outgoing response, so that an application can have more control over how the cookie is issued.
No wonder it works, it doesn't look into the existing cookie.
My theory is that you have your new sites on an x64 machine and the legacy website sits in an x86. The encryption differs in such scenario even if keys are the same. Another possible reason is a different version of .net as the encryption algorithm has been changed in .net 4.

ASP.NET Giving Access to directory by Username

This can be done by making a new HTTP handler, but is there a simple way to configure the following?:
Site is setup on basis of user accounts with username say A001, A002....etc.
Once a user logs in they can access their resources in their directory (/A001) etc...which may contain files and images
The issue that I have had using roles and authorization in ASP.NET is that roles are either generic (defined by roles, example anyone logged in may be able to access the resource) or hard coded in the web.config files which is clearly not feasible in a dynamic environment where user accounts are being created:
<authorization>
<allow users="John"/> // allow John only
<deny users="*"/> // deny others
</authorization>
Is there a simple way to ensure that only a certain user has access to their folder only?
Well using an HTTP Module would be simple enough.
First this is the request life cycle:
Application_BeginRequest.
Application_AuthenticateRequest.
Application_PostAuthenticateRequest.
Application_DefaultAuthentication.
Application_AuthorizeRequest.
Application_PostAuthorizeRequest.
Application_ResolveRequestCache.
Application_PostResolveRequestCache.
Application_MapRequestHandler. Fired only when the server is running IIS 7 in Integrated Mode and at least >Net Framework 3.0
Application_PostMapRequestHandler.
Application_AcquireRequestState.
Application_PostAcquireRequestState.
Application_PreRequestHandlerExecute.
The page event handler is executed. (refer to the page life cycle)
Application_PostRequestHandlerExecute.
Application_ReleaseRequestState.
Application_PostReleaseRequestState
Application_UpdateRequestCache.
Application_PostUpdateRequestCache
Application_LogRequest. Fired only when server is IIS 7 Integrated Mode and at least .Net Framework 3.0
Application_PostLogRequest. Fired only when server is IIS 7 Integrated Mode and at least .Net Framework 3.0
Application_EndRequest.
For more info: http://msdn.microsoft.com/en-us/library/system.web.httpapplication.aspx
I think the best event that fits your needs is the Application_AuthorizeRequest
Here you could get the path being accessed, and you could have a map in your database associating your uses with their allowed paths, something like:
UserID Path
userID1 ~/UserFiles/User1
userID2 ~/UserFiles/User2
userID3 ~/UserFiles/User3
Then in the event read this map and decide if the user should be authorized or not

Passing Active Directory Credentials from an ASP.Net Page to Retrieve Web Content

I've got a site I recently converted from forms authentication to Windows authentication. I finally got it working correctly. I'm running into one issue that I haven't found a suitable workaround for yet. We have several pages that from within the backend code will call other pages and retrieve content sections from the returned page. Since the code is calling the other page, I am getting an access denied error (the code can't pass the authentication). I've tried several ways of passing windows credentials with the request and all have failed.
I'm willing to create an AD user for this function and hardcode the username and password with the request so that the information can be retrieved. Can anyone give me code that will allow me to do this, so far I've been unsuccessful. Thanks.
-Edit-
I don't remember them all, but here's the last one I tried:
Dim wc As New WebClient()
Dim credential As NetworkCredential = New NetworkCredential(ADusername, ADPwd, ADDomain)
wc.Credentials = credential
Dim strXML As String = wc.DownloadString(RssFeedUrl)
This causes the page to return (401) Unauthorized.
Another thing I tried... one of the 'retrievals' is an RSS feed, this is the location of the feed.
<location path="RSS.ashx">
<system.web>
<authorization>
<allow users="*" />
</authorization>
</system.web>
</location>
It didn't seem to help.
Turns out that after some more testing, I found that the code above actually works. I copied it to a windows application and ran it on several machines. All worked correctly with the exception of the server I wanted to host the code on. Did some digging into the Event viewer and there were some failed security audits. Using this information I found that there is a 'loopback check' on the server. Using Microsoft KB article 896861 I disabled the loopback check for the site and voila! it is now working.

Resources