I've seen Common Access Cards (CAC) being read into a program before but I am now modifying a ASP.NET MVC application to use CAC authentication to sign into the app , which I have not done before. There seem to be no straight forward explanations for this issue out there, at least not for someone beginning like myself. My goal is to have the app request the client cert upon opening. Currently I have code to request the cert in a Startup class in the App_Start dir:
HttpClientCertificate cert = Request.ClientCertificate;
cacid = Request.ClientCertificate["SubjectCN"].ToString();
When the app runs I get an empty cert back and cacid (string) comes back as an empty string. I have a cac reader which shows up properly in my managed devices and a card to use. I am so new to this that I may not even know what questions to ask but I'll give it a shot:
Does my site need to be set up in IIS Manager some how? I have Anonymous Auth enabled
Do I need ActivClient or Active Directory to implement or test this?
What have I not considered that I need to test that this works properly?
We need to configure how to authenticate the client with a certificate, either ManyToOne client certificate mapping or OneToOne client certificate mapping in IISClientCertificateMappingAuthentication so that the server-side requires a client to provide a certificate when accessing the website. For the IIS server works with Active directory certificate authentication installed, we chose the ClientCertificateMappingAuthentication to configure that.
Client Authentication via X509 Certificates in asp.net
See these links for how to configure ManyToOne, OneToOne client certificate mapping.
https://support.microsoft.com/en-hk/help/2026113/configuring-many-to-one-client-certificate-mappings-for-internet-infor
https://learn.microsoft.com/en-us/iis/manage/configuring-security/configuring-one-to-one-client-certificate-mappings
After we disabled other authentication modes in the IIS authentication module and enabled IISClientcertificateMapping.
the below code will get the client certificate information when a client provides a client certificate,
HttpClientCertificate cert = Request.ClientCertificate;
if (cert.IsPresent)
TextBox1.Text = "Hello "+cert.Get("SUBJECTCN");
else
TextBox1.Text = "No certificate was found.";
Feel free to let me know if there is anything I can help with.
I have a simple solution. Navigate to your site's SSL Settings in IIS , and check the "Require SSL' Requirecheckbox and under Client Certificate, click on 'Require' Require. Restart your application and you should be able to get your CAC authentication showing up.
Related
I am struggling to get a token from "https://login.microsoftonline.com/common/oauth2/token" with an Azure function by a post-request. The token will give permissions to access SharePoint though CSOM. Here is my code snippet with the post request:
var clientId = defaultAADAppId;
var body = $"resource={resource}&client_id={clientId}&grant_type=password&username={HttpUtility.UrlEncode(username)}&password={HttpUtility.UrlEncode(password)}";
using (var stringContent = new StringContent(body, Encoding.UTF8, "application/x-www-form-urlencoded"))
{
var result = await httpClient.PostAsync(tokenEndpoint, stringContent);
var tokenResult = JsonSerializer.Deserialize<JsonElement>(result);
var token = tokenResult.GetProperty("access_token").GetString();
}
When testing locally, both when running the function in Visual studio and when I try with Postman, I am able to achieve an access token. However, as soon as I publish the function to my Function app in Azure I receive the following error message:
"AADSTS53003: Access has been blocked by Conditional Access policies. The access policy does not allow token issuance"
I have enabled an app registration in the portal and as mentioned, it all works fine until I publish everything to Azure.
Any ideas on how to solve this?
I got it to work now. First of all I reviewed the CA policies as #CaseyCrookston suggested. What I found out was that our CA policies blocked calls outside the country we operate from. However, the calls from the App registration/Azure function were registered from the Azure data centre location and thus, blocked by our CA policies. When running them locally the calls where registered in my country and therefore no errors were showing while debugging.
My first step was trying to add my Client app to the CA policy, which was not possible. The client/secret authentication that I used based on the suggestions in this CSOM guide by Microsoft prevented the App registration to be whitelisted from the CA policies (Github issue).
Based on this I had to change the authentication to a Certificate-based authentication as suggested here: Access token request with a certificate and here: SO answer. With this I was able to whitelist the App registration in the CA policies and successfully authenticate to the Sharepoint CSOM.
As the error message says, your app is blocked by CA policy. Possible causes can be unknown client app, blocking external IP addresses, etc.
You can perform one of the below workarounds:
Add your Client app to your CA policy.
I wouldn’t recommend this because this affects your security - if you take the risk you could exclude the “Microsoft Azure Management” from your CA policy which blocks unknown clients / requires device state and still protect the sign-in with MFA.
A better approach is to use another OAuth 2.0 and OpenID connect flow like the delegated flow where you sign-in directly within the app, if possible.
I'm working on an older web app that I did not originally build, but now maintain. It is a classic ASP app with ASPX pages mixed in.
The site is setup for Kerberos authentication and delegation, and that is working properly to other boxes (e.g. I can run a SQL query against a back-end server from an ASP page in the site and it connects using the front-end client's credentials properly). So SPNs are registered, delegation privileges are configured in AD, etc.
Now, the part I'm having trouble with is an ASPX page which invokes a remote WMI call to check on the status of an IIS website, using the \root\WebAdministration WMI namespace. The ASPX page is itself invoked by way of an XHR which resides in the client-side code of a different ASP page. The ASPX, when invoked, makes the WMI call, then Response.Write's back the necessary data, which the originating ASP page then utilizes to populate the page that the user sees. The problem is, I cannot get the IIS box to properly delegate the user's credentials to the back-end machine that its making the WMI call against.
This all works properly (including the constrained delegation), but only if I enable protocol transition. If I set the delegation on the middle-tier (IIS) box to use only Kerberos authentication, it fails (I get an anonymous logon attempt on the back-end box).
Now, I've done numerous packet captures on both the front-end client and the IIS box to see exactly what is going on here, and I can see several things:
The front-end client is properly getting its Kerberos ticket, and presenting it to the IIS box for authentication.
The IIS box is accepting the Kerberos ticket from the client.
However, the IIS box is not using the ticket received from the client as the "evidence ticket" that it should be presenting to the KDC in order to obtain a service ticket to access the back-end service on behalf of the front-end user. Instead, the IIS box is using a S4U2Self call to the KDC to obtain a ticket on the front-end user's behalf for itself, then using that ticket in the subsequent S4U2Proxy call to try and obtain the ticket to the back-end. This is where the problem lies.
The behavior noted above is why this works when protocol transition is enabled, and does not work when it is not.
I cannot figure out for the life of me, why the IIS box feels the need to obtain a TGS for itself to use as the "evidence ticket" to get the ticket for accessing the back-end, instead of simply using the ticket presented by the client. There is nothing invalid about the client's ticket from what I can tell, and the client is establishing a Kerberos-authenticated connection with the web server just fine, so there should be no need for protocol transition here. I could enable it if really needed, but I really just want to know why its necessary (if there is valid reason and this is by design then so be it).
The IIS app pool is running as the built-in app pool identity, and the delegation settings are thus configured on the IIS machine account in AD. SPNs are registered for the site against the IIS machine account, and for the back-end services against those service and/or machine accounts, and the "allowedToDelegateTo" list is configured on the IIS machine account, allowing constrained delegation to the necessary services. The specific SPN we are trying to delegate creds to in this scenario is RPCSS/[machine] for the WMI call. I've verified via the packet capture that the SPN in the request matches the SPN in the A2D2 list exactly (of course, if it didn't, then it wouldn't be working when protocol transition was enabled anyway).
As for the actual WMI connection code, I've tried a few ways. One was something like this:
ConnectionOptions co = new ConnectionOptions();
// I did try ImpersonationLevel set to both Impersonate and Delegate, but I don't think I need
// Delegate here because I'm not delegating from the remote WMI machine to a different box; instead,
// I'm delegating from the IIS box to the remote WMI machine.
co.Impersonation = ImpersonationLevel.Impersonate;
co.Authentication = AuthenticationLevel.PacketPrivacy;
co.EnablePrivileges = true;
// Tried this for the Authority line because I noticed in the packet captures that the principal
// specified here becomes the SPN that is used in the S4U2Proxy request.
co.Authority = "kerberos:RPCSS/machine.domain.com";
ManagementScope ms = new ManagementScope(#"\\machine.domain.com\root\WebAdministration", co);
Then I also tried this:
ConnectionOptions co = new ConnectionOptions();
co.Impersonation = ImpersonationLevel.Impersonate;
co.Authentication = AuthenticationLevel.PacketPrivacy;
co.EnablePrivileges = true;
// I also tried this for the Authority line based on various other code examples for similar
// issues, but this resulted in an incorrect SPN being used in the request.
co.Authority = #"kerberos:DOMAIN\machine";
ManagementScope ms = new ManagementScope(#"\\machine.domain.com\root\WebAdministration", co);
I also tried the same as above, but without an Authority line, and the correct SPN was used in the request but it still didn't work.
Finally, I also tried this, with no ConnectionOptions object at all, hoping it would just pass on the default creds:
ManagementScope ms = new ManagementScope(#"\\machine.domain.com\root\WebAdministration");
Any help here on either how I can get this working without enabling protocol transition, or info on why this setup would require protocol transition, would be very much appreciated!
I'm building an MVC application with Azure Active Directory authentication. When I develop locally I would like to be able to sign-in for testing/development purposes. And the app url is like http://localhost:43400. This is also encoded in the AD application in Sign-On Url and Reply Url.
When I deploy the same app to the server, the app url is changed - becomes something like myappname.azurewebsites.net and I can't login using the same AD application. The best I could manage is to get through login process, but then AD redirects me back to localhost:43400 which is wrong.
There is PostLogoutRedirectUri property in Startup.Auth.cs that I give to the app, but it makes no difference at all.
Any way to have local application and deployed application using the same Azure AD?
I can do 2 AD Applicaitons with different urls and keys and rewrite the values in web.config on deploy. But that does not sound like the best solution. Anything else I can do?
UPD
Here is the bit I'm referring to in Startup.Auth.cs:
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
Authority = Authority,
PostLogoutRedirectUri = postLogoutRedirectUri, // <-- this is coming from web.config, different in dev and prod
Notifications = new OpenIdConnectAuthenticationNotifications()
{
.....
}
});
See full code listing here.
And in Azure AD application I tried both addresses as a Reply URL at the same time:
But the AD used only one of the addresses to redirect, even though the client specified the redirection that matches one of the records.
You can add multiple redirect uri to your app, that's why the property is implemented as a list! You just need to make sure that you specify which URI to use at runtime. You can do that in many ways - you can specify the return URI at middleware init time, or you can add dynamic code that will inject a redirect URI in the sign in message. For an example of the latter approach, please see RedirectToIdentityProvider in https://github.com/AzureADSamples/WebApp-MultiTenant-OpenIdConnect-DotNet/blob/master/TodoListWebApp/App_Start/Startup.Auth.cs
I have an asp.net site on IIS using windows authentication (pass through) and I am trying to connect to the TFS API programmatically.
When I run it on my dev machine all is fine but once the site is on IIS I keep getting {"TF30063: You are not authorized to access http://mytfsserver."}
I have debugged the live site and it seems like it always takes the user as "NT SYSTEM" instead of the actual logged in user.
If I put my account details for the application pool it works as expected.
Any idea on how I can bypass this?
Code where it fails:
Uri collectionUri = new Uri(rootWebConfig.AppSettings.Settings["TFS_TEST_URI"].Value); //TEST ENV
tpc = new TfsTeamProjectCollection(collectionUri, CredentialCache.DefaultNetworkCredentials);
tpc.Authenticate();
workItemStore = tpc.GetService<WorkItemStore>();
You are hitting a standard active directory double hop authentication issue.
You have two options:
Username & password - if you ask the user to physically enter their username and password you can authenticate as them.
Kerberos - if you enable and configure Kerberos you can enable passthrough authentication. You need properly configured SPN: http://blogs.technet.com/b/askds/archive/2008/06/13/understanding-kerberos-double-hop.aspx
I would go with kerberos tokens. It's a pain to configure but works a treat. Your only other alternative is to run your web app on the TFS server and bypass double hop.
I'm currently using User ID / password basic authentication. What do I need to do, in order to start using X.509 Digital Certificates?
My web application is written in C# and is running on top of IIS.
Additional info: I'll be invoking BAPIs/ zBAPIs with code generated by Rafael My SAP Proxy Visual Studio Plug-in: http://tools.rafaelc.net/default.aspx?id=72. It automatically generates a proxy code.
I'm wondering wether this generated code can be changed to use client certificates and, in this case, what do I need to do.
I assume you want to use client-certificates.
On the AS-ABAP-Serverside:
First you need upload your CA to transaction strust (Directory SSL-Server-Standard).
Secondly view VUSREXTID needs to be maintained (see https://wiki.scn.sap.com/wiki/display/Basis/How+to+configure+client+certificate+logon+to+AS+ABAP).
I recommend to upload the client-certificate, so the view is maintained with the correct DN of the certificate and the issuer-certificate.
The last step is to change the authentication-procedure for the service-node (transaction sicf) to "Required with SSL Certificate":