Configuring IIS Client Certificate Mapping Authentication - asp.net

I'm trying to configure IIS client cert mapping on IIS 8, Windows Server 2012. I don't see the configuration showing up in applicationHost.config, and the cert I'm trying to present isn't offered up as an option by my browser.
Here's what I've tried so far:
In IIS, I created a top-level site called "PackageManager":
SSL Settings are as follows:
Authentication: Enabled Anonymous:
In Configuration Editor,
Section: system.webServer/security/authentication/iisClientCertificateMappingAuthentication
From: ApplicationHost.config <location path=’PackageManager’>
I set the following:
I wanted manyToOneMappings so I could map the cert to my service account (a domain user):
Here I created 2 rules to match the Subject and Issuer CN's of the GoDaddy cert:
Then I generated a PowerShell script for all the above as follows:
Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -location 'PackageManager' -filter "system.webServer/security/authentication/iisClientCertificateMappingAuthentication" -name "enabled" -value "True"
Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -location 'PackageManager' -filter "system.webServer/security/authentication/iisClientCertificateMappingAuthentication" -name "defaultLogonDomain" -value "CMC"
Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -location 'PackageManager' -filter "system.webServer/security/authentication/iisClientCertificateMappingAuthentication/manyToOneMappings" -name "." -value #{name='My 1st Mapping';description='1st User Mapping';userName='DOMAIN\username';password='XXXXXXXXXXX'}
Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -location 'PackageManager' -filter "system.webServer/security/authentication/iisClientCertificateMappingAuthentication/manyToOneMappings/add[#name='My 1st Mapping']/rules" -name "." -value #{certificateField='Subject';certificateSubField='CN';matchCriteria='*.mydomain.com';compareCaseSensitive='False'}
Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -location 'PackageManager' -filter "system.webServer/security/authentication/iisClientCertificateMappingAuthentication/manyToOneMappings/add[#name='My 1st Mapping']/rules" -name "." -value #{certificateField='Issuer';certificateSubField='CN';matchCriteria='Go Daddy Secure Certificate Authority - G2';compareCaseSensitive='False'}
What’s weird about all the above, is that I don’t see any references to this configuration in C:\Windows\System32\inetsrv\Config\applicationHost.config.
When browsing this site, I get prompted to use a cert, but IE doesn't present the cert I was expecting:
That was a self-signed cert I had been experimenting with.
Then I get hit with a lovely 403, so I’m at an impasse.
What am I doing wrong in the config that it doesn't show up in applicationHost.config, and why am I not given a choice to present my client cert (it's in my store)?

I experienced the same problem under Windows Server 2012 and I solved it by adding two additional registry keys under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet \Control\SecurityProviders\Schannel:
• ClientAuthTrustMode Value type: REG_DWORD, Value data: 2
• SendTrustedIssuerList Value type: REG_DWORD, Value data: 0
For more information see IIS 8.5 - Mutual certificates authentication fails with error 403.16

Your GoDaddy certificate seems to be a Server Authentication certificate (Server authentication OID 1.3.6.1.5.5.7.3.1) that can be used by IIS for SSL security and this one should be installed in Certificates>>Local computer>>Personal
For client certificates you need Client authentication OID 1.3.6.1.5.5.7.3.2 and this one should be installed in Certificates>>Current User>>Personal.
demo

Related

How to HTTPS (SSL) with self-hosted ASP.NET Core 2 app (httpsys)

I wrote a little ASP.NET Core 2 application. It runs as a service, so no IIS. It runs on a PC with Windows 7 SP1.
var host = WebHost.CreateDefaultBuilder(args)
.UseContentRoot(pathToContentRoot)
.UseHttpSys(options =>
{
options.Authentication.Schemes = AuthenticationSchemes.None;
options.Authentication.AllowAnonymous = true;
options.MaxConnections = null;
options.MaxRequestBodySize = 30000000;
options.UrlPrefixes.Add("http://*:5050");
})
.UseStartup<Startup>()
.UseApplicationInsights()
.Build();
if (isService)
{
host.RunAsService();
}
else
{
host.Run();
}
As you can see, I want to listen on port 5050. This is working fine without SSL.
My question is, how can I enable https for my application? Again: No IIS, no Domain-Name (no internet connection). Communication is just inside the internal network, so I want to use a self-signed certificate.
I read the documentation (HTTP.sys documentation;Netsh Commands;New-SelfSignedCertificate), but there is always something different to my situation (they use Krestel, or it is for using IIS). Also, I dont know how to get the App-ID (needed for netsh) for my Application. I tryed this: StackOverflow Get GUID but it doesn't work.
var assembly = typeof(Program).Assembly;
// following line produces: System.IndexOutOfRangeException
var attribute = (GuidAttribute)assembly.GetCustomAttributes(typeof(GuidAttribute), true)[0];
var id = attribute.Value;
Console.WriteLine(id);
So I am a bit confused about all the possabilitys and different configurations. And the docs don't consider my specific case.
I created a certificate, and I guess I need to store it on the "my" Store. (Where is that? cert:\LocalMachine\My) And then I need to assign my Applicaion ID and Port to it.
But I have no idea how to do that exactly. Can anyone help?
So I solve the problem in the following way:
First, if you want to know your own GUID, you will get it with the following code:
var id = typeof(RuntimeEnvironment).GetTypeInfo().Assembly.GetCustomAttribute<GuidAttribute>().Value;
Create a SelfSigned Certificate
Now create a SelfSigned-Certificate (Skip this if you already got one, or purchased one)
Run the following OpenSSL command to generate your private key and public certificate. Answer the questions and enter the Common Name when prompted.
openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem
Combine your key and certificate in a PKCS#12 (P12) bundle:
openssl pkcs12 -inkey key.pem -in certificate.pem -export -out certificate.p12
Install the certificate on the client:
For Windows 8 and higher:
Add Certificate to Windows Cert Store with PowerShell
PS C:> $certpwd = ConvertTo-SecureString -String "passwort" -Force –AsPlainText
PS C:> Import-PfxCertificate –FilePath D:\data\cert\certificate.p12 cert:\localMachine\my -Password $certpwd
Get Fingerprint (Hash) of certificate
PS C:\WINDOWS\system32> dir Cert:\LocalMachine\my
Install certificate (replace Hash, IP and Port with your values)
PS C:\WINDOWS\system32> $guid = [guid]::NewGuid()
PS C:\WINDOWS\system32> $certHash =
"A1D...B672E"
PS C:\WINDOWS\system32> $ip = "0.0.0.0"
PS C:\WINDOWS\system32> $port = "5050"
PS C:\WINDOWS\system32> "http add sslcert ipport=$($ip):$port
certhash=$certHash appid={$guid}" | netsh
You are done.
For Windows 7
Add Certificate to Windows Cert Store (note: use .pem file for this operation, because .p12 file seems to be not supported from certutil)
.\certutil.exe -addstore -enterprise -f "Root" C:\lwe\cert\certificate.pem
If his line throws the following error:
SSL Certificate add failed, Error 1312
A specified logon session does not exist. It may already have been terminated.
You have to do the steps manually (please insert the .p12 file when doing it manually, not .pem) :
Run mmc.exe
Go to File-> Add/Remove Snap-In
Choose the Certificates snap-in.
Select Computer Account
Navigate to: Certificates (Local Computer)\Personal\Certificates
Right click the Certificates folder and choose All Tasks -> Import.
Follow the wizard instructions to select the certificate. Be sure you check the export checkbox during wizard.
To get the hash of yor certificate, run the Internet Explorer, press Alt + X and go to Internet Options -> Content -> Certificates. Search your certificate and read the hash.
Now you can run the same commands as for Windows 8+:
Install certificate (replace Hash, IP and Port with your values)
PS C:\WINDOWS\system32> $guid = [guid]::NewGuid()
PS C:\WINDOWS\system32> $certHash =
"A1D...B672E"
PS C:\WINDOWS\system32> $ip = "0.0.0.0"
PS C:\WINDOWS\system32> $port = "5050"
PS C:\WINDOWS\system32> "http add sslcert ipport=$($ip):$port
certhash=$certHash appid={$guid}" | netsh
Edit your Code
After all, you have to set the UrlPrefixes to https. So in your Program.cs file you need to have:
var host = WebHost.CreateDefaultBuilder(args)
.UseContentRoot(pathToContentRoot)
.UseHttpSys(options =>
{
options.Authentication.Schemes = AuthenticationSchemes.None;
options.Authentication.AllowAnonymous = true;
options.MaxConnections = null;
options.MaxRequestBodySize = 30000000;
options.UrlPrefixes.Add("https://*:5050");
})
.UseStartup<Startup>()
.UseApplicationInsights()
.Build();

How can I set the host name for a web site/web application in IIS using tfs release management client?

I have to deploy a few sites using TFS Release Management Client, all of them in them same machine so same IIS. They will be all on port 80 but the requests are served for different host names (domains).
Using IISConfig tool, it is possible to change the port but not the host name, do you know a quick way already implemented to achieve that without creating a custom tool?
As confirmed here, it is not possible but if you scroll down there is a suggestion how to quickly work around the limitation.
Creating 2 actions
-Command "& { Import-Module WebAdministration; New-WebBinding -Name '__Name__' -IPAddress '__IPAddress__' -Port '__Port__' -HostHeader '__HostHeader__' }"
and
-Command "& { Import-Module WebAdministration; Remove-WebBinding -Name '__Name__' -IPAddress '__IPAddress__' -Port '__Port__' -HostHeader '__HostHeader__' } "

Authenticate user via Client Signed SSL Certificate in ASP.NET application

I want to add extra security to a site and generate self-signed client certificates for my users.
I set IIS to require client certificates, created a self-signed certificate for the server and followed a few articles explaining how to create the client sertificate via makecert and pvk2pfx (all of them using the following method):
makecert -r -n "CN=My Personal CA" -pe -sv MyPersonalCA.pvk -a sha1 -len 2048 -b 01/21/2010 -e 01/21/2016 -cy authority MyPersonalCA.cer
makecert -iv MyPersonalCA.pvk -ic MyPersonalCA.cer -n "CN=John Doe" -pe -sv JohnDoe.pvk -a sha1 -len 2048 -b 01/21/2010 -e 01/21/2016 -sky exchange JohnDoe.cer -eku 1.3.6.1.5.5.7.3.2
pvk2pfx -pvk JohnDoe.pvk -spc JohnDoe.cer -pfx JohnDoe.pfx -po PASSWORD
I installed MyPersonalCA in trusted certification authorities and JohnDoe.pfx in appropriate certification storage.
However when I open my site I am getting:
HTTP Error 403.7 - Forbidden
What am I missing? Why isn't the browser sending the client certificate?
There are following conditions under which the browser will let you pick a certificate:
The certificate has to be generated with "client authentication" option
1.3.6.1.5.5.7.3.2 - id_kp_clientAuth
The certificate that signs your certificate has to be installed in the trusted root certification authorities on the server (not on the client!)
The certificate itself has to be installed in browser's certificate store (a system store for ie and chrome, an internal store in firefox)
Note that this is still not enough for authentication, you also need a custom authentication module or configure mappings between certificates and users manually at the server.

IIS 7.0 Creating self signed certificates with comman name

I am facing an problem when creating a self signed certificate with common name.
System: Windows Server 2008, 64 bit machine, framework 3.5, IIS 7
Tools used: Selfssl7 to create an certificate with common name
Commands used:
SelfSSL7 /Q /T /I "Default Web SIte" /N:CN="GamecardRoot"/V:2000 /S:1 /K 2048 /V 3456 /p:443
SelfSSL7 /I "Default Web SIte" /N:CN="GamecardRoot"/V:2000 /S:1 /K 2048 /V 3456 /p:443
It does not create a certifcate with a comman name what i have used :GamecardRoot it creates an certficate with system name like :"Sontrx09"
Name Issuedby Issuedby
Sontrx09 Sontrx09 Sontrx09
Reference used:http://www.kevinlabranche.com/blog/SelfSSLOnIIS7.aspx

MSDTC - Communication with the underlying transaction manager has failed (Firewall open, MSDTC network access on)

I'm having problems with my ASP.NET web forms system.
It worked on our test server but now we are putting it live one of the servers is within a DMZ and the SQL server is outside of that (on our network still though - although a different subnet)
I have open up the firewall completely between these two boxes to see if that was the issue and it still gives the error message "Communication with the underlying transaction manager has failed" whenever we try and use the "TransactionScope". We can access the data for retrieval it's just transactions that break it.
We have also used msdtc ping to test the connection and with the amendments on the firewall that pings successfully, but the same error occurs!
How do i resolve this error?
Any help would be great as we have a system to go live today. Panic :)
Edit: I have created a more straightforward test page with a transaction as below and this works fine. Could a nested transaction cause this kind of error and if so why would this only cause an issue when using a live box in a dmz with a firewall?
AuditRepository auditRepository = new AuditRepository();
try
{
using (TransactionScope scope = new TransactionScope())
{
auditRepository.Add(DateTime.Now, 1, "TEST-TRANSACTIONS#1", 1);
auditRepository.Save();
auditRepository.Add(DateTime.Now, 1, "TEST-TRANSACTIONS#2", 1);
auditRepository.Save();
scope.Complete();
}
}
catch (Exception ex)
{
Response.Write("Test Error For Transaction: " + ex.Message + "<br />" + ex.StackTrace);
}
This is the ErrorStack we are getting when the problem occurs:
at
System.Transactions.TransactionInterop.GetOletxTransactionFromTransmitterPropigationToken(Byte[]
propagationToken) at
System.Transactions.TransactionStatePSPEOperation.PSPEPromote(InternalTransaction tx)
at System.Transactions.TransactionStateDelegatedBase.EnterState(InternalTransaction tx)
at System.Transactions.EnlistableStates.Promote(InternalTransaction tx) at
System.Transactions.Transaction.Promote() at
System.Transactions.TransactionInterop.ConvertToOletxTransaction(Transaction
transaction) at System.Transactions.TransactionInterop.GetExportCookie(Transaction
transaction, Byte[] whereabouts) at
System.Data.SqlClient.SqlInternalConnection.GetTransactionCookie(Transaction
transaction, Byte[] whereAbouts) at
System.Data.SqlClient.SqlInternalConnection.EnlistNonNull(Transaction tx) at
System.Data.SqlClient.SqlInternalConnection.Enlist(Transaction tx) at
System.Data.SqlClient.SqlInternalConnectionTds.Activate(Transaction transaction) at
System.Data.ProviderBase.DbConnectionInternal.ActivateConnection(Transaction
transaction) at System.Data.ProviderBase.DbConnectionPool.GetConnection(DbConnection
owningObject) at
System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection
owningConnection) at
System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection
outerConnection, DbConnectionFactory connectionFactory) at
System.Data.SqlClient.SqlConnection.Open() at
System.Data.Linq.SqlClient.SqlConnectionManager.UseConnection(IConnectionUser user) at
System.Data.Linq.SqlClient.SqlProvider.get_IsSqlCe() at
System.Data.Linq.SqlClient.SqlProvider.InitializeProviderMode() at
System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(Expression
query) at
System.Data.Linq.ChangeDirector.StandardChangeDirector.DynamicInsert(TrackedObject
item) at System.Data.Linq.ChangeDirector.StandardChangeDirector.Insert(TrackedObject
item) at System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode) at
System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode) at
System.Data.Linq.DataContext.SubmitChanges() at RegBook.classes.DbBase.Save() at
RegBook.usercontrols.BookingProcess.confirmBookingButton_Click(Object sender, EventArgs e)
I realised the code I provided would not escalate the transaction to the DTC. I was getting the problem when using multiple data contexts within one transaction.
Although I thought the firewall was open it needed a range of ports and that was why the problem was still occuring.
This article helped me resolve it
In my case, I was trying it over VPN. It was working perfectly fine in LAN but not in VPN. I also opened the ports (i.e. 135,5000-5020) in Hardware Firewall at both sites but invain. After searching a lot over it, I came to know that BOTH THE MACHINES SHOULD BE ABLE TO COMMUNICATE WITH THEIR NetBIOS NAME. I just added the entry of another machin in the hosts file & it is now wroking perfectly fine.
Thanks Andrew & Mike for the valuable help.
Thank you.
I understand you can open ports and configure MSDTC, but not for all the clients where your app is installed. Is there a way to block TransactionScope from promoting to DTC.
I know I am working with one DB only. I just need multiple contexts in order to dispose context with changes made in error or after error occured. THe best way of course is to detach object from a data context, but this feature is not available in .NET 3.5SP1 Linq to SQL.
So I have to submit changes under a different context and throw it away if something goes wrong.
Here is some powershell script that can make all the changes required to get DTC to work properly. You have to run this on both machines that are participating in the transaction, i.e. your web server and the sql server machine.
function Enable-MSDTC
{
[CmdletBinding()]
param()
Write-Host "Updating registry entries for MSDTC"
$msdtcRegKey = "HKLM:\SOFTWARE\Microsoft\MSDTC\Security"
Set-ItemProperty -Path $msdtcRegKey -Name "NetworkDtcAccessTransactions" -Value 1
Set-ItemProperty -Path $msdtcRegKey -Name "NetworkDtcAccess" -Value 1
Set-ItemProperty -Path $msdtcRegKey -Name "NetworkDtcAccessOutbound" -Value 1
Set-ItemProperty -Path $msdtcRegKey -Name "NetworkDtcAccessClients" -Value 1
Set-ItemProperty -Path $msdtcRegKey -Name "NetworkDtcAccessInbound" -Value 1
Set-ItemProperty -Path $msdtcRegKey -Name "LuTransactions" -Value 1
#Configure MSDTC to use specific ports
#see: https://support.microsoft.com/en-us/kb/250367
$msdtcPortKey = "HKLM:\SOFTWARE\Microsoft\Rpc\Internet"
New-Item -Path $msdtcPortKey
New-ItemProperty -Path $msdtcPortKey -Name "Ports" -PropertyType "MultiString" -Value "5000-5200"
New-ItemProperty -Path $msdtcPortKey -Name "PortsInternetAvailable" -PropertyType "String" -Value "Y"
New-ItemProperty -Path $msdtcPortKey -Name "UseInternetPorts" -PropertyType "String" -Value "Y"
#open firewall ports 135, 1433, 5000-5100
#also add MSDTC program exclusion
netsh advfirewall firewall add rule name='MSDTC Endpoint Mapper (In)' localport=135 dir=in action=allow protocol=TCP
netsh advfirewall firewall add rule name='MSDTC SQL Server (In)' localport=1433 dir=in action=allow protocol=TCP
netsh advfirewall firewall add rule name='MSDTC Dynamic Ports (In)' localport=5000-5200 dir=in action=allow protocol=TCP
netsh advfirewall firewall add rule name='MSDTC exe' dir=in action=allow program=$env:windir\system32\msdtc.exe enable=yes
Write-Host "Restarting MSDTC service"
#restart the MSDTC service
Restart-Service MSDTC -Force -Confirm:$false
}
Enable-MSDTC -ErrorAction SilentlyContinue

Resources