cert authentication work with signalr in a mixed case - signalr

I have a hub
Its called by 2 types of clients, browser with identity cookies and c# client with client certs
I can make eitheer work. BUt If I have iis configued to require client certs on /signalr then the browser client connects the user gets prompted for a cert - not good.
I tried
var str = String.Format("https://{0}/cert_signalr", url.Host);
m_hub = new HubConnection(str, false);
setting iis to require certs on /cert_signalr and adding a rewrite rule of cert_signalr -> signalr. Didnt work. Seems like the HubConnection paid no attention to me specifying the URL

my code works - what I did wrong was in web config. I needed to have
<location path="cert_signalr">
<system.webServer>
<security>
<access sslFlags="SslNegotiateCert" />
</security>
</system.webServer>
</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

How can I add token authentication to my IIS so as to secure files in a folder?

I have a Windows Azure WebAPI application with
OWIN
Oauth 2
token authentication
Identity 2 Framework
VS2013 Update 2
IIS (I am not sure which version. As I just updated everything in the stack then I assume the latest version)
Before a user is authenticated when there's a <script> in my index.html file I notice cookies sent to the server looking like this:
Accept-Language: en-US,en;q=0.8
Cookie: .AspNet.Cookies=GWLL4LgeFkn7jDndAwf-Pk_eZAPZ5LYZugSmv- ...
After a user is authenticated I notice the cookies change:
Accept-Language: en-US,en;q=0.8
Cookie: .AspNet.Cookies=OqLMSpIv2aQ8KUcw3pWdAYtPYUI_tYMl4rEYKe16N ...
I thought I was using token authentication so my first question is "why do the cookies get changed and why are they sent at all"?
Once a user is authenticated then with each $http request to the server I send a header like this:
Authorization: Bearer abcdefgetc....
My authorization on the server works when I have WebAPI methods decorated like:
[Authorize(Roles = "Admin")]
Here is the main web-config that shows the security settings:
<system.web>
<authentication mode="None" />
<compilation debug="true" targetFramework="4.5.1" />
<httpRuntime targetFramework="4.5.1" />
</system.web>
<system.webServer>
<modules>
<remove name="FormsAuthenticationModule" />
</modules>
</system.webServer>
Now I would like to add some security to some static javascript files that I have on the server. I know how I can code it so the files can be retrieved by my client and added to the DOM in two ways. Either way is okay for me to use although I prefer the first way if when I do that way then there can be authentication happen through cookies or otherwise:
With a script tag and a load
var el = doc.createElement("script"),
loaded = false;
el.onload = el.onreadystatechange = function () {
if ((el.readyState && el.readyState !== "complete" && el.readyState !== "loaded") || loaded) {
return false;
}
el.onload = el.onreadystatechange = null;
loaded = true;
// done!
};
el.async = true;
el.src = path;
document.getElementsByTagName('head')[0].insertBefore(el, head.firstChild);
With a $http call and then adding it directly to the DOM (I can supply bearer token)
$http({
url: '/Bundles/admin/admin1Bundle.js',
method: "GET"
})
.success(function (result) {
var m = document.createElement('script');
m.appendChild(document.createTextNode(result));
document.getElementsByTagName('head')[0].appendChild(m);
Once added the javascript becomes available. To add security I created a web.config in the folder to protect these files and allow only users with Admin role to have access:
Here is the folders web-config that shows the security settings:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<security>
<authorization>
<remove users="*" roles="" verbs="" />
<add accessType="Allow" roles="Admin" verbs='GET'/>
</authorization>
</security>
</system.webServer>
</configuration>
When a user with the role of Admin tries to access files in the folder with a GET that a has a bearer token they get a message saying:
Most likely causes:
•No authentication protocol (including anonymous) is selected in IIS.
•Only integrated authentication is enabled, and a client browser was used that does not support integrated authentication.
•Integrated authentication is enabled and the request was sent through a proxy that changed the authentication headers before they reach the Web server.
•The Web server is not configured for anonymous access and a required authorization header was not received.
•The "configuration/system.webServer/authorization" configuration section may be explicitly denying the user access.
This error occurs when the WWW-Authenticate header sent to the Web server is not supported by the
server configuration. Check the authentication method for the resource, and verify which authentication
method the client used. The error occurs when the authentication methods are different. To determine
which type of authentication the client is using, check the authentication settings for the client.
It seems like my IIS (the version I am using on my development environment when I click Debug > Start Debugging) is using a different kind of authentication from that used by my WebAPI. Can someone explain to me:
Should I be using <system.web> or <system.webServer> for the security?
How can I make the IIS use the same security path as WebAPI is using when I decorate my WebAPI methods? Note that I need a way to do this with web.config as I don't have access to make changes to the IIS directly once the application is published to the cloud.
I am using token authentication so why is the cookie information sent? Could I just use this cookie information to secure my javascript files from getting downloaded?
Notes:
Here is the way I have authentication set up in Startup.Auth.cs
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
Should I be using or for the security?
How can I make the IIS use the same security path as WebAPI is using
when I decorate my WebAPI methods? Note that I need a way to do this
with web.config as I don't have access to make changes to the IIS
directly once the application is published to the cloud.
You could use the authorization attribute in the webconfig to restrict files and folders, the example below restricts restricts a specific js file to admins only.
<location path="resources/scripts/yourtopsecretjsfile.js">
<system.webServer>
<security>
<authorization>
<remove users="*" roles="" verbs="" />
<add accessType="Allow" roles="Administrators" />
</authorization>
</security>
</system.webServer>
</location>
I am using token authentication so why is the cookie information sent?
It is used by the server to identify the authenticated user. If you don't want to do without sending the cookie info you can look at doing at sending a signed token with every request instead. Check out this article, loosely covers how to do that (but that with an angular JS/ Web API 2 point of view) http://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net-identity/

HTTP error 404: The request resource is not found

I have three systems running on IIS7 with static IP address 192.168.66.5. I have configured the system to run on the same IP address with different ports and subdmain like;
192.168.66.5:81 hostname ams.tpf.go.tz
192.168.66.5:82 hostname gmis.tpf.go.tz
192.168.66.5:83 hostname records.tpf.go.tz
192.168.66.5:84 hostname cmis.tpf.go.tz
I configure all these on IIS7 and defined them in the router.
When the client opens ams.tpf.go.tz without specifying the port number, the error 404 is returned: the requested resource is not found.
This recently occurred to me also - make sure your IIS Website is started - mine had been stopped. This is the error I was receiving in Visual Studio:
Unable to start debugging on the web server. The web server could not find the requested resource.
Right Click on your Website (i.e. Default Website) in IIS Manager and click Manage Web Site --> Start.
Navigating to any applications in the IIS Website was showing this error:
HTTP Error 404. The requested resource is not found.
The easiest way to achieve this is to set the port 80 for the site you want to be the "default" one, since this is the default HTTP port.
Some times IIS Manager -> Manage Web Site -> Start, will not work if the below 2 services are not running
1. Windows Activation Technologies Service
2. World Wide Web Publishing Service
Start these services manually under windows services then start IIS again.
Another cause that happens to me with some frequency is to set the permissions correctly to the physical directory. It can be achieved going to IIS -> clicking on the website and then in the actions panel click over Edit Permissions. Be sure that the user you are going to assign the permissions, are the same as defined on Authentication -> Anonymous Authentication or ASP.NET Impersonation, if any of those authentication methods are enabled.
To know the user assigned on those authentication methods, go to the Authentication icon, select any of the authentication methods mentioned before, right click on it and select edit. After that, you have the option to select the user you want.
Hoping this helps.
My issue for anyone else that comes here from google. I am hosting a django website so in my webconfig file it is set to process requests using the python virtual environment. In the web.config file it is this portion:
<configuration>
<system.webServer>
<handlers>
<add name="Python FastCGI"
path="*"
verb="*"
modules="FastCgiModule"
scriptProcessor="C:\inetpub\wwwroot\receipts\venv\Scripts\python.exe|C:\inetpub\wwwroot\receipts\venv\Lib\site-packages\wfastcgi.py"
resourceType="Unspecified"
requireAccess="Script" />
</handlers>
...
</configuration>
When there was requests to the media folder IIS would say great I know what to do send it through the scriptProcessor (python processor). Requests to the media folder should not do that they only need to serve static files (no extra processing). I placed this web.config in the media directory and it solved my problem!
<configuration>
<system.webServer>
<handlers>
<!-- this configuration overrides the FastCGI handler to let IIS serve these static files -->
<clear />
<add name="StaticFile"
path="*"
verb="*"
modules="StaticFileModule"
resourceType="File"
requireAccess="Read" />
</handlers>
</system.webServer>
</configuration>
In my case IIS server and resolved with the below steps.
Check the security groups - whether we have opened the required ports from ALB SG to EC2 SG.
Login to server and check does IIS server's default site has 443 port opened if your health-check is on 443. (whatever port you are using for health checks).
Use the curl command to troubleshoot the issue.
If you would like to check on HTTPS use the below command to check the response. Use -k or --insecure to ignore the SSL issue.
curl https://[serverIP] -k
For HTTP test use the below command.
curl http://[serverIP]

Client Authentication via X509 Certificates in asp.net

I have an asp.net application and I need to authenticate users using X509 certificates. That is, the user must install a certificate issued by me so that he can browse my website and I can identify which user is, by this certificate.
I have already configured SSL on IIS, but it's not what I'm looking for right now, and I don't know where to start.
How can I achieve this in asp.net c#?
To create a secure authentication mechanism you would use both client certificates and username / password. The reason is that a certificate is something that can be stolen (copied) but a password is something that is only known by the person. An alternative could be a certificate on a smartcard, protected by a PIN.
To use client certificates in ASP.NET applications you need to do the following:
Step 1: In IIS Manager, open your application or web site, choose SSL Settings and choose both Require SSL and Require Client certificate.
Now when the user opens your web site, the browser will prompt him to select a client certificate that will be used in the communication.
Important At this point you have to make sure that the certificate is issued by someone you trust (since anyone can create their own self-signed certificates).
Step 2: Add a configuration item (either web.config, database etc.). In this list you would add the thumbprints of the whole CA (certificate authority) chain for your client certificates.
<add key="ClientCertificateIssuerThumbprints" value="4901f5b87d736cd88792bd5ef7caee91bf7d1a2b,0113e31aa85d7fb02740a1257f8bfa534fb8549e,c9321de6b5a82666cf6971a18a56f2d3a8675602"/>
Step 3: Create a classic username / password login page. Verify the username/password.
Step 4: Add the following code to your login page:
var x509 = new X509Certificate2(this.Request.ClientCertificate.Certificate);
var chain = new X509Chain(true);
chain.ChainPolicy.RevocationMode = X509RevocationMode.Offline;
chain.Build(x509);
var validThumbprints = new HashSet<string>(
System.Configuration.ConfigurationManager.AppSettings["ClientCertificateIssuerThumbprints"]
.Replace(" ", "").Split(',', ';'),
StringComparer.OrdinalIgnoreCase);
// if the certificate is self-signed, verify itself.
for (int i = chain.ChainElements.Count > 1 ? 1 : 0; i < chain.ChainElements.Count; i++)
{
if (!validThumbprints.Contains(chain.ChainElements[i].Certificate.Thumbprint))
throw new UnauthorizedAccessException("The client certificate selected is not authorized for this system. Please restart the browser and pick the certificate issued by XXXXX");
}
// certificate Subject would contain some identifier of the user (an ID number, SIN number or anything else unique). here it is assumed that it contains the login name and nothing else
if (!string.Equals("CN=" + login, x509.Subject, StringComparison.OrdinalIgnoreCase))
throw new UnauthorizedAccessException("The client certificate selected is authorized for another user. Please restart the browser and pick another certificate.");
Only when both the password and the certificate have been checked, the user should be allowed in the system.
Assuming you have IIS 7.0 or higher, you can configure Client Certificate Mapping Authentication
Using Active Directory (Extremely easy, leaves the mapping work to the AD server)
<location path="Default Web Site">
<system.webServer>
<security>
<access sslFlags="Ssl, SslNegotiateCert" />
<authentication>
<windowsAuthentication enabled="false" />
<anonymousAuthentication enabled="false" />
<digestAuthentication enabled="false" />
<basicAuthentication enabled="false" />
<clientCertificateMappingAuthentication enabled="true" />
</authentication>
</security>
</system.webServer>
</location>
Or using IIS (More configuration needed in IIS, needs access to the client certificate, but works standalone, no roundtrips to the AD). In this case, you specify (one or more) user credentials and
map each user to a certificate's public key to a user whose credentials you specify, or
map multiple certificates to a user based on values in the certificate's fields
Configuration (many to one):
<location path="Default Web Site">
<system.webServer>
<security>
<authentication>
<windowsAuthentication enabled="false" />
<anonymousAuthentication enabled="false" />
<digestAuthentication enabled="false" />
<basicAuthentication enabled="false" />
<iisClientCertificateMappingAuthentication enabled="true"
manyToOneCertificateMappingsEnabled="true">
<manyToOneMappings>
<add name="Contoso Employees"
enabled="true"
permissionMode="Allow"
userName="Username"
password="[enc:AesProvider:57686f6120447564652c2049495320526f636b73:enc]">
<rules>
<add certificateField="Subject"
certificateSubField="O"
matchCriteria="Contoso"
compareCaseSensitive="true" />
</rules>
</add>
</manyToOneMappings>
</iisClientCertificateMappingAuthentication>
</authentication>
<access sslFlags="Ssl, SslNegotiateCert" />
</security>
</system.webServer>
</location>
(Sample configuration rather shamelessly copied from the samples on the iis.net documentation pages, which are quite elaborate.)
Or you can configure your application to use Claims-Based Authentication with a Security Token Service (STS) that authenticates clients based on client certificates. ADFS 2.0 can fullfil this role, or if it is not available, you could look at the Thinktecture Identity Server.

Authentication mode=“Forms” causing redirect in WCF service

I have a WCF end point inside my .NET 4.0 Web Application project. Using the VS2010 WCF Test Client, I can connect to the service correctly. However when I go to use the service I get a generic error message:
The content type text/html; charset=UTF-8 of the response message does not match the content type of the binding (text/xml; charset=utf-8). If using a custom encoder, be sure that the IsContentTypeSupported method is implemented properly. The first 1024 bytes of the response were:
When I looked at the requests on IIS Express I got the following:
Request started: POST http://machinename:port/Services/Services.svc
Request started: GET http://machinename:port/Services/Services.svc?AspxAutoDectectCookieSupport=1
Request started: GET http://machinename:port/(X(1)A(LKwosYYszAEkAAAAMDE2YzlmNWItNTZIOS00ZDY1LTgzOTAtNDIxNDgyOWZIYWViJ86TX46muUQoL_psmkZK2rgWbO41))/Services/Services.svc?AspxAutoDectectCookieSupport=1
Request ended: "http://machinename:port/Services/Services.svc" with HTTP status 302.0
Request ended: "http://machinename:port/Services/Services.svc?AspxAutoDectectCookieSupport=1" with HTTP status 302.0
Request ended: "http://machinename:port/Services/Services.svc?AspxAutoDectectCookieSupport=1" with HTTP status 200.0
So it seems like after POSTing to the service it is getting redirected to the standard web page for the service. Yet when I remove:
<authentication mode="Forms">
<forms cookieless="AutoDetect" loginUrl="~/Security/LoginClient.aspx" name="FORMAUTH" />
from the web.config it works. Any ideas what is happening? I have tried to remove the folder the service is in from authentication (http://stackoverflow.com/questions/5593720/authentication-mode-forms-causing-errors-in-wcf-end-point) but the issue still remains.
While this works using the Visual Studio Development Server (Cassini) when I run it through IIS Express 7.5 the same error occurs with or without authentication.
You have to provide authorization for your web services to be contacted anonymously in your web.config:
<location path="MyWebServices">
<system.web>
<authorization>
<allow users="*"/>
</authorization>
</system.web>
</location>
This assumes that you keep all of your services in a folder called MyWebServices relative to the root of the application. You have to allow * or it will force a login for access.
I am experiencing the same issue as soon as I use the machinename instead of localhost in the service address. I did try to use a "baseAddressPrefixFilters" but without success.
<serviceHostingEnvironment>
<baseAddressPrefixFilters>
<add prefix="http://XLSiteSampleD.aginsurance.intranet/PIXLSiteSample" />
</baseAddressPrefixFilters>
</serviceHostingEnvironment>
I thought that option could have been to enable the aspNetCompatibility in the web.config
with the related attribute on the service :
[AspNetCompatibilityRequirements(RequirementsMode =
AspNetCompatibilityRequirementsMode.Allowed)]
But is does not the trick either :(
It only works with an address like http://localhost/VirtualSite/MyService.svc without a domain and without the baseAddressPrefixFilters !
V.

Resources