How to get Windows loggedin username in IIS defind anonymous + windows authentication - asp.net-core-2.0

framework : ASP.NET CORE 2.2 as web-api
Server: IIS-10 (Windows server 2016)
I need to work with both WindowsAuthentication and AnonymousAuthentication.
I have these 2 options to somehow get the Windows LoggedIn User:
User.Identity.Name;
System.Security.Principal.WindowsIdentity.GetCurrent().Name
I use them in an end-point (controller method) which is reached anonymous.
Everything works fine with IISExpress, but when working with IIS (local or after deploy), I can't get the wanted results:
User.Identity.Name; // return null
System.Security.Principal.WindowsIdentity.GetCurrent().Name //return IISAPPPOOL\<Application pool name>
Application Pool Identity is ApplicationPoolIdentity.
How can I get the Windows LoggedIn Username in this configuration (anonymous + windows authentication)?

Related

how Iis USES saml2.0 to access adfs

How does IIS use saml2.0 to access adfs?
In my opinion, IIS needs to deploy a web application to access adfs by sending the request with saml 2.0.
But until now, I haven't found the way to deploy a web application that can send saml2.0.
Does it have to use isapi or Shibboleth ?
Resolution: (1) Shibboleth SP should establish the SSO session/HTTP
login session after extracting the user info from SAML response sent
by SAML IdP. (2) Insert the user info into the SSO session/HTTP login
session. How to insert and fetch Data from Sessions instead of
Database in Asp.net MVC C# provides the instruction on how to insert
data into the HTTP session (at IIS) and extract data from the HTTP
session (at Glassfish).
//In IIS Session["HTTP_MAIL"] = Request.Headers["HTTP_MAIL"];
//In Glassfish after HTTP redirect string user_email =
Session["HTTP_MAIL"];
Thanks for you answer!
let me tell about what I know first. If there is any something wrong, please point it out
Shibboleth SP save the value belongs of SAML response which is getting from SAML Idp(this time is ADFS) to three places(※), and we can see it in
https://SP's domaim name/Shibboleth.sso/Session
 ※
①Session
②Server Variables
③Request Headers
refer to SP's AttributeAccess
After Shibboleth SP save the value, automatically jumps to the interface accessed in the browser.
There is information in ②Server Variables and ③Request Headers, so applications above IIS can get it through the following code
through by both mail and HTTP_MAIL can get the value.
<% # Page Language="C#" %>
<%
Response.Write("<h3>Server Variables</h3>");
Response.Write("Name = " + Request["name"] + "<br>");
Response.Write("Email = " + Request["mail"] + "<br>");
Response.Write("Tel = " + Request["tel"] + "<br>");
%>
the result is :
Server Variables
Name = tom
Email = tom#yahoo.com
Tel = 0251-4584-635
the question is when use HTTP Redirect(HTTP Rewrite and other way is also ok),
How are the above values passed to glassfish~
Refer to your answer, I did the following things ~
Modify the program above iis to this:
<% # Page Language="C#" %>
<%
Response.Write("<h3>Server Variables</h3>");
Response.Write("Name = " + Request["name"] + "<br>");
Response.Write("Email = " + Request["mail"] + "<br>");
Response.Write("Tel = " + Request["tel"] + "<br>");
Session["HTTP_MAIL"] = Request["HTTP_MAIL"]; ※set value to Session
Response.Write("Mail2 = " + Session["HTTP_TEST"] + "<br>");
%>
create Glassfish's app to this:
#RequestMapping(value = "/info2", method = RequestMethod.GET)
public Object getUserInfo2(HttpSession session, Model model) {
Enumeration<String> headerNames = session.getAttributeNames();
StringBuffer stringBuffer = new StringBuffer();
while (headerNames.hasMoreElements()) {
String key = (String) headerNames.nextElement();
String value = (String) session.getAttribute(key);
stringBuffer.append(key + ":" + value + "\n");
}
model.addAttribute("StringBuffer", stringBuffer);
return "index";
}
there is nothing in session.
it seems that using IIS's HTTP redirect function to redirect the app on IIS before it executes.
In other words, the session assignment does not appear to have been performed
Did I do that right?
Question #1:
How does IIS use saml2.0 to access adfs?
In my opinion, IIS needs to deploy a web application to access adfs by sending the request with saml 2.0.
Answer:
Yes. You are correct.
(1) IIS needs to deploy a SAML SP (service provider) to send SAML auth request to ADFS.
(2) You need to configure ADFS to be SAML IdP (Identity Provider).
The official Microsoft website of Add ADFS as a SAML identity provider provides the instruction on how to configure ADFS to be SAML IdP.
Question #2:
Does it have to use isapi or Shibboleth ?
Answer:
You can deploy Shibboleth SP (service provider) on IIS.
The official link of Shibboleth SP with IIS provides the instruction on how to deploy Shibboleth SP on IIS.
Follow-up Question #1:
The final effect is as follows: adfs's end point:
iis.*.com/Shibboleth.sso/SAML2/POST
iis.*.com/Shibboleth.sso/SAML2/Artifact
However, adfs is returned as a post, and I did not get the information in the request header through the program on the iis side
Refer to this website Shibboleth SP for IIS でSAML対応
How can I get the data returned by adfs through get
Answer:
(1) Shibboleth SP AssertionConsumerService does NOT provide "HTTP-Redirect" endpoint/URL for "GET".
(I) You can NOT "get the data returned by adfs through get".
(II) You have to get the data returned by adfs through POST.
(2) Assume that your website is https://shibbolethiis.int.secioss.work
(I) Shibboleth SP AssertionConsumerService endpoint/URL demonstrated by your Shibboleth SP metadata "https://shibbolethiis.int.secioss.work/Shibboleth.sso/Metadata"
<md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://shibbolethiis.int.secioss.work/Shibboleth.sso/SAML2/POST" index="1"/>
(II) Quote the link from your comment. i.e., Shibboleth SP for IIS でSAML対応
「Default Web Site」を選択し。IISを再起動します。
これでShibboleth-SPの設定は終了です。
以下のURLに接続し、正常に稼働しているか確認してください。
https://shibbolethiis.int.secioss.work/Shibboleth.sso/Status
正常に稼働している場合、以下のようなXMLが返ります。
最後のStatusタグの内容がOKなら正常です。
(III) Check your website Shibbolth SP session
https://shibbolethiis.int.secioss.work/Shibboleth.sso/Session
The above Shibboleth SP Session URL should display the user info carried by SAML response sent by ADFS
If you can NOT find any user info from the above Shibboleth SP Session URL
(III.a) Configure ADFS to send the user info with SAML attribute/SAML assertion/SAML response
(III.b) Modify Shibboleth SP "attribute-map.xml" to accept SAML attributes sent by ADFS with reference to the example provided by Shibboleth SP shibboleth-sp-testapp/shibboleth-sp/attribute-map.xml at the GitHub repository.
Usually Shibboleth SP uses SAML attribute such as "mail" attribute (e.g., ethan.smith#example.com) to log the user in to your website.
(4) Remarks:
(I) How to build and run Shibboleth SAML IdP and SP using Docker container at GitHub repository provides Shibboleth SP configuration example.
(II) For your convenience, I have made a new commit to add ADFS attributes to Shibboleth SP shibboleth-sp-testapp/shibboleth-sp/attribute-map.xml at the above GitHub repository. Note that I have used the same ADFS attributes to log in to Box account successfully.
(III) Configuring Attributes for SAML 2.0 and ADFS 3.0 provides the valuable information and discussion on how Shibboleth SP extract the user info/data returned by ADFS through "attribute-map.xml".
Follow-up Question #2:
After modifying attribute. XML, and visit shibboleth.sso/Session, it can display the following information.
Attributes mail: 1 value(s)
tel: 1 value(s)
Refer to this website Shibboleth SP for IIS でSAML対応
5.動作確認
Display the following information
HTTP_MAIL:ya*#cn.*.com
HTTP_TEL:17*
how can i get information from the request header when i redirect it to glassfish via iis's HTTP redirect function?
Answer:
Another StackOverflow question Getting a Request.Headers value provides the solution on how to get information from the request header using C#, for example,
if (Request.Headers["HTTP_MAIL"] != null) {
string user_email = Request.Headers["HTTP_MAIL"];
}
Follow-up Question #3:
Instead of asking how to get headers on IIS, my question is how to get login information on glassfish~ In other words, how do i pass the request-header information to glassfish after getting it from iis? I also asked a question in glassfish get shibboleth sp attribute on iis, and it is more detailed than his current comment.
Answer:
From the cybersecurity perspective, you can NOT redirect the user info to establish the HTTP login session for Glassfish application. Otherwise, hackers can use the same user info to log in to Glassfish application without any authentication such as local username/password authentication or third-party SAML authentication.
Follow-up Question #4:
when use HTTP Redirect(HTTP Rewrite and other way is also ok), How are the above values passed to glassfish?
there is nothing in session.
it seems that using IIS's HTTP redirect function to redirect the app on IIS before it executes. In other words, the session assignment does not appear to have been performed
Did I do that right?
Answer:
(1) Apache, GlassFish, IIS, Jetty, and Tomcat can be regarded as parallel web servers for hosting web applications.
Top Java Application Servers: Tomcat vs. Jetty vs. GlassFish vs. WildFly
Microsoft IIS vs Apache Tomcat: What are the differences?
Microsoft IIS and Apache Tomcat belong to "Web Servers" category of the tech stack.
Windows Server 2016 can run both IIS 10 web server and GlassFish 5.1.0 web server, while IIS 10 web server and GlassFish 5.1.0 web server can run their own web application.
(2) From the cybersecurity perspective, different web application should establish their HTTP login session on their backend server (such as Apache, Glassfish, IIS, JETTY, and Tomcat) after their user has been authenticated by a third-party SAML IdP (such as Shibboleth SAML IdP).
Therefore, you can NOT redirect the user info from IIS to Glassfish, because IIS and Glassfish should establish their own different HTTP sessions for their user who is granted access to web application.
Resolution:
You can use OneLogin Java SAML SP tookit (Code Your Java App to Provide SSO via OneLogin) to build SAML SP for your Java-based GlassFish web application.
Note that OneLogin SAML SP for your Java-based GlassFish web application can communicate with any SAML IdP including their own OneLogin SAML IdP, Shibboleth SAML IdP running on Docker container, or SAML IdP provided by our Zero-Password Authentication and Authorization System.

OWIN Mixed Authentication IIS Issue

I have a project where Windows Authentication and Forms login are required. I came across OWIN Mixed Authentication which seems to meet my requirements.
Before implementing into my own project I tried running the sample solution from the source link.
I debugged the solution using IIS Express and when I entered my credentials into the windows authentication dialog my correct credentials where found in the logonUserIdentity variable.
But when I set up a local IIS site add set the following feature delegation property as stated in the readme file:
Authentication - Windows to Read/Write
When I entered my credentials into the windows authentication dialog NT AUTHORITY\IUSR is coming through in the logonUserIdentity variable instead of the username I entered in the dialog.
I feel this happening because AllowAnonymous is enabled on the IIS site but its needed to stop a login loop that occurs because of the CookieAuthentication within the Startup.Auth class.
How should I be setting up my IIS site so that the windows credential dialog passes through the entered credentials and not NT AUTHORITY\IUSR.
I debugged the solution using IIS Express and when I entered my credentials into the windows authentication dialog my correct credentials where found in the logonUserIdentity variable.
As far as I know, the IIS express use current computer login account as the Anonymous login account. So you will find the logonUserIdentity is right. You could try to login the application with different domain account. You will find it still use current computer login account not changed to the login user account.
Since the mix auth allow multiple ways to login,you should always enable anonymous login to let the person who doesn't have the domain account.
The mix own auth use asp.net identity external login to achieve login with windows.The asp.net identity external login will firstly go to the mixauth provider to check the windows auth result.
If success, it will go back to the account controller's ExternalLoginCallback method with the windows info and use this info the identity will generate an identity user.
In my opinion, if you want to get the current login in user, I suggest you could try to use session to store the windows login in user's account in ExternalLoginCallback method.
More details, you could refer to below codes:
[AllowAnonymous]
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
Session["LoginonUsername"] = loginInfo.DefaultUserName;
if (loginInfo == null)
{
return RedirectToAction("Login");
}
// Sign in the user with this external login provider if the user already has a login
var result = await SignInManager.ExternalSignInAsync(loginInfo, isPersistent: false);
switch (result)
{
case SignInStatus.Success:
return RedirectToLocal(returnUrl);
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresVerification:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = false });
case SignInStatus.Failure:
default:
// If the user does not have an account, then prompt the user to create an account
ViewBag.ReturnUrl = returnUrl;
ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = loginInfo.Email });
}
}
Result:
My IIS site binding was set to http://projectname
When I changed the binding on the IIS site to http://localhost or http://pcname it was allowing me to pass through the correct windows credentials.

LDAP Authentication Fails in Azure App Service

I have created a Java web app and deployed it on Azure App Service. In the app, we are providing users with a Login Page and upon submitting the credentials the users are authenticated using LDAP. This is working when deployed locally.
When I deploy this to Azure as WebApp, the authentication doesn't happen and the application gives an error. I am trying to authenticate like below. The LDAPContext is always returned as null in Azure.
The Authentication/Authorization settings in Azure Portal is turned OFF.
LdapContext ctx = null;
String dn= "uid=" + username + ",ou=users,ou=xxxx,o=xxxxx";
String ldapURL = "ldap://ldap.example.com:389";
Hashtable<String, String> environment =new Hashtable<String, String>();
environment.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
environment.put(Context.PROVIDER_URL, ldapURL);
environment.put(Context.SECURITY_AUTHENTICATION, "simple");
environment.put(Context.SECURITY_PRINCIPAL, dn);
environment.put(Context.SECURITY_CREDENTIALS, password);
ctx = new InitialLdapContext(environment,null);
Server Side: Check the inbound Security rule for Which Ip address are can access the LDAP
If you pass the LDAP domain name in code . Try pass empty value that place
Try to give Auth type is Basic or Negotiate or Anonymous etc . these are in .Net Frame work same way try some other type in Java may be . So try like that
ldap://ldap.example.com - For this example.com is domain name

IDX10803 and IDX10804 error with Azure AD

I have created a Web API in ASP.NET Core 2 and it is secured with Azure AD. The requests work fine in my dev environment. However when I publish the API to IIS and pass in a Authorization header in request I am getting these error:
fail: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[3]
Exception occurred while processing message.
System.InvalidOperationException: IDX10803: Unable to obtain configuration from: 'https://login.microsoftonline.com/xxxx/.well-known/openid-configuration'. ---> System.IO.IOException: IDX10804: Unable to retrieve document from: 'https://login.microsoftonline.com/xxxx/.well-known/openid-configuration'. ---> System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.Http.WinHttpException: A connection with the server could not be established
What am I doing wrong? I can browse the url in browser successfully.
I figured it out. It was because of a proxy setting to access the internet. Since ASP.NET Core does not pick up proxy setting from system.net area of web.config, the ideal solution was to create a middle ware to act as proxy.
I was running short of time. So I created a new user and logged on server with that new user and configured the proxy settings in Internet Explorer options. Then I configured the App Pool in IIS to run under that user's identity. Problem solved!
The correct answer is to add a proxy to the metadata request that ADAL makes using BackchannelHttpHandler. You can do it like this:
public void Configure(string name, JwtBearerOptions options)
{
options.BackchannelHttpHandler = new HttpClientHandler
{
UseProxy = true,
Proxy = new WebProxy
{
Address = new Uri($"{appSettings.InternetProxyUrl}:{appSettings.InternetProxyPort}"),
UseDefaultCredentials = true
}
};
}

Unable to authenticate to ASP.NET Web Api service with HttpClient

I have an ASP.NET Web API service that runs on a web server with Windows Authentication enabled.
I have a client site built on MVC4 that runs in a different site on the same web server that uses the HttpClient to pull data from the service. This client site runs with identity impersonation enabled and also uses windows authentication.
The web server is Windows Server 2008 R2 with IIS 7.5.
The challenge I am having is getting the HttpClient to pass the current windows user as part of its authentication process. I have configured the HttpClient in this manner:
var clientHandler = new HttpClientHandler();
clientHandler.UseDefaultCredentials = true;
clientHandler.PreAuthenticate = true;
clientHandler.ClientCertificateOptions = ClientCertificateOption.Automatic;
var httpClient = new HttpClient(clientHandler);
My understanding is that running the site with identity impersonation enabled and then building the client in this manner should result in the client authenticating to the service using the impersonated identity of the currently logged in user.
This is not happening. In fact, the client doesn't seem to be authenticating at all.
The service is configured to use windows authentication and this seems to work perfectly. I can go to http://server/api/shippers in my web browser and be prompted for windows authentication, once entered I receive the data requested.
In the IIS logs I see the API requests being received with no authentication and receiving a 401 challenge response.
Documentation on this one seems to be sparse.
I need some insight into what could be wrong or another way to use windows authentication with this application.
Thank You,
Craig
I have investigated the source code of HttpClientHandler (the latest version I was able to get my hands on) and this is what can be found in SendAsync method:
// BeginGetResponse/BeginGetRequestStream have a lot of setup work to do before becoming async
// (proxy, dns, connection pooling, etc). Run these on a separate thread.
// Do not provide a cancellation token; if this helper task could be canceled before starting then
// nobody would complete the tcs.
Task.Factory.StartNew(startRequest, state);
Now if you check within your code the value of SecurityContext.IsWindowsIdentityFlowSuppressed() you will most probably get true. In result the StartRequest method is executed in new thread with the credentials of the asp.net process (not the credentials of the impersonated user).
There are two possible ways out of this. If you have access to yours server aspnet_config.config, you should set following settings (setting those in web.config seems to have no effect):
<legacyImpersonationPolicy enabled="false"/>
<alwaysFlowImpersonationPolicy enabled="true"/>
If you can't change the aspnet_config.config you will have to create your own HttpClientHandler to support this scenario.
UPDATE REGARDING THE USAGE OF FQDN
The issue you have hit here is a feature in Windows that is designed to protect against "reflection attacks". To work around this you need to whitelist the domain you are trying to access on the machine that is trying to access the server. Follow below steps:
Go to Start --> Run --> regedit
Locate HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0 registry key.
Right-click on it, choose New and then Multi-String Value.
Type BackConnectionHostNames (ENTER).
Right-click just created value and choose Modify.
Put the host name(s) for the site(s) that are on the local computer in the value box and click OK (each host name/FQDN needs to be on it's own line, no wildcards, the name must be exact match).
Save everything and restart the machine
You can read full KB article regarding the issue here.
I was also having this same problem. Thanks to the research done by #tpeczek, I developed the following solution: instead of using the HttpClient (which creates threads and sends requests async,) I used the WebClient class which issues requests on the same thread. Doing so enables me to pass on the user's identity to WebAPI from another ASP.NET application.
The obvious downside is that this will not work async.
var wi = (WindowsIdentity)HttpContext.User.Identity;
var wic = wi.Impersonate();
try
{
var data = JsonConvert.SerializeObject(new
{
Property1 = 1,
Property2 = "blah"
});
using (var client = new WebClient { UseDefaultCredentials = true })
{
client.Headers.Add(HttpRequestHeader.ContentType, "application/json; charset=utf-8");
client.UploadData("http://url/api/controller", "POST", Encoding.UTF8.GetBytes(data));
}
}
catch (Exception exc)
{
// handle exception
}
finally
{
wic.Undo();
}
Note: Requires NuGet package: Newtonsoft.Json, which is the same JSON serializer WebAPI uses.
The reason why this is not working is because you need double hop authentication.
The first hop is the web server, getting impersonation with Windows authentication to work there is no problem. But when using HttpClient or WebClient to authenticate you to another server, the web server needs to run on an account that has permission to do the necessary delegation.
See the following for more details:
http://blogs.technet.com/b/askds/archive/2008/06/13/understanding-kerberos-double-hop.aspx
Fix using the "setspn" command:
http://www.phishthis.com/2009/10/24/how-to-configure-ad-sql-and-iis-for-two-hop-kerberos-authentication-2/
(You will need sufficient access rights to perform these operations.)
Just consider what would happen if any server was allowed to forward your credentials as it pleases... To avoid this security issue, the domain controller needs to know which accounts are allowed to perform the delegation.
To impersonate the original (authenticated) user, use the following configuration in the Web.config file:
<authentication mode="Windows" />
<identity impersonate="true" />
With this configuration, ASP.NET always impersonates the authenticated user, and all resource access is performed using the authenticated user's security context.

Resources