LEGACY EDGE ONLY: HTTP request is unauthorized with client authentication scheme 'Negotiate'. .' - iis

I have an application that calls a wcf service, the application uses windows authentication and anonymous access is disabled. I am still getting the error in accessing the service:
'The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'Negotiate,NTLM'.' '
The odd part is that it is working fine in IE11 and chrome (v83), this issue is appearing on Windows 10 1809 version only.
Attaching screenshots from my IIS below.
Can anyone suggest what could be the possible issue?

try to set the below setting in iis:
open iis, Select Website
Select ‘Configuration Editor’
Select
‘system.webServer/security/authentication/windowsAuthentication’
useAppPoolCredential to True
Make sure both WCF and the .net application URL using the same protocol.
set the application pool user to the domain account.
at client configuration set below code:
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
you could refer below link for more detail:L
401 Client 'Negotiate', Server 'Negotiate,NTLM' When Calling WCF Server to Server

Related

Azure APIM - OAuth 2.0 - Internal Service API Authentication Issue

I need to expose an internal service API which runs on a server of our domain. The service is written in Java and is a SOAP service supporting basic auth. I need to implement Client Credentials flow via OAuth 2.0 and expose it via APIM (Azure API Management). The service will be used by external client applications (daemons).
What I've done so far is to create 2 Azure App Registrations: 1 Client App and 1 Proxy App.
App Roles have been defined in the proxy app and the client app has permissions on the proxy app.
In the client app I have setup Client Secret.
In the APIM initially I created a static http 200 response (via inbound policy) in order to test the service. Works fine.
<return-response>
<set-status code="200" />
<set-header name="content-type" exists-action="override">
<value>application/json</value>
</set-header>
<set-body>{
"status": "200",
"message": "OK"
}</set-body></return-response>
Then added an inbound JWT validation policy. I request a token from MS via Postman, pass the Bearer token to the API endpoint call and the token is being validated. Works fine.
Then I need to "route" the request to our internal service. We have already setup Azure Application Proxy, so I edit the Internal Url of the proxy enterprise app and set it to the internal service Url. I also remove the inbound static 200 response policy in order to allow the request to reach my internal service.
In such case if the proxy enterprise application "pre authentication" is set to passthrough it works fine but if it is set to "Azure Active Directory" it doesn't - I get a 200 response but requests to sign-in (html).
In case I leave the 200 reply from APIM (not reaching my endpoint) it works no matter if the enterprise application is set to "Passthrough" or "Azure Active Directory".
Any ideas?
Thank you in advance,
Dimitris

azure APIM client certificate towards SAP gateway

We're trying to use a client certificate to authenticate when calling an OData service in SAP S/4HANA. And we're calling from an azure APIM instance. As certificate we've created a self-signed certificate and configured SAP S/4HANA according to this blog (https://blogs.sap.com/2020/05/03/x.509-certificate-based-logon-to-odata-services/)
Then we test this from the browser it works like a charm.
But calling from azure APIM we get the following response from SAP S/4HANA:
<?xml version="1.0" encoding="utf-8"?> <error xmlns:xsi="http://www.w3.org/2001/XMLSchema-Instance">
<code>HTTP/404/E/Not Found</code>
<message> Service /sap/opu/odata/sap/xxxxyyyy/xxyyzz call was terminated because the corresponding service is not available.The termination occurred in system UFI with error code 404 and for the reason Not found. Please select a valid URL. If it is a valid URL, check whether service /sap/opu/odata/sap/xxxxyyyy/xxyyzz is active in transaction SICF. If you do not yet have a user ID, contact your system administrator. </message>
SAP S/4HANA support says that then calling from browser they can 'see' certificate in payload but then calling from APIM, the payload is 'empty'.
I've got the trace logs from the SAP S/4HANA gateway server and I've noticed this subtly difference calling from browser vs calling from APIM:
Browser call (successfull):
[Thr 140708195055360] HttpModGetDefRules: determined the defactions: COPY_CERT_TO_MPI (1)
APIM call (failed):
[Thr 140708197697280] HttpModGetDefRules: determined the defactions: NOTHING (0)
So the certificate is obviously reaching SAP S/4HANA gateway server but not the SAP S/4HANA Odata server. So somehow, for some reason it's lost on the SAP S/4HANA gateway server only then it comes from azure APIM.
I've tried to make the calls 100% identical (same headers same values) but I can't control the way the certificate is added in azure apim or can one ?
I read that one can set the certificate body using policy below:
<authentication-certificate body="#(context.Variables.GetValueOrDefault<byte[]>("byteCertificate"))" password="optional-certificate-password" />
but I can't figure out how to get a proper value for "byteCertificate".
Has anyone done this? Or has anyone had a similar issue?
We finally found the solution!
Thanks to microsoft APIM support team, thanks a lot :)
APIM acts like a reverse proxy and adds headers related to this role. The header "X-Forwarded-For" causes SAP to deny the request with the above misleading error message. We found a solution that SAP could configure:
ICM parameter "icm/HTTPS/accept_ccert_for_x_forwarded_for_requests" has to be set to "true" - per default it's set to "false".
(The header can't be deleted with a policy on APIM side.)

Requests to third party API from .NET Core app timeout in IIS

I have a .NET Core Web API app running in IIS that can receive and respond to requests, but it needs to make requests to a third party API (Twilio). Those requests succeed when hosted locally but they time out when hosted in IIS.
The .NET Core Web API app is targeting v2.1 and running on Windows Server and IIS 7. I setup a dedicated app pool for the site following guidelines in this article.
App pool settings:
I'm using Postman to make GET and POST requests to the app.
GET and POST requests to a test controller work fine. All I'm doing with these test endpoints is returning the parameters that are received.
[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{
[HttpGet]
public string Get(int id)
{
return $"response to GET; id:{id}";
}
[HttpPost]
public string Post([FromBody] int id)
{
return $"response to POST; foo:{id}";
}
}
The above endpoints work locally running debug mode in VS2019 using IISExpress, and they also work when deployed to the web server and hosted with IIS7.
The trouble starts when I try to call out to a third party API (Twilio). Again these calls succeed when the app runs locally. There's almost no delay. I post to the SMSController's post endpoint, the request is triggered, and I get a text message within seconds. However, GET and POST requests to these endpoints fails from the web server and IIS.
[Route("api/[controller]")]
[ApiController]
public class SMSController : ControllerBase
{
private string twilioSID = "xxxxxx";
private string twilioAuthToken = "xxxxxx";
private string twilioPhoneNumber = "+15555555555";
[HttpGet]
public string Get(string phoneNumber)
{
TwilioClient.Init(twilioSID, twilioAuthToken);
var message = MessageResource.Create(
body: $"TEST message via Twilio",
from: new Twilio.Types.PhoneNumber(twilioPhoneNumber),
to: new Twilio.Types.PhoneNumber(phoneNumber)
);
return message.Status.ToString();
}
[HttpPost]
public string Post([FromBody] GeoEvent geoEvent)
{
TwilioClient.Init(twilioSID, twilioAuthToken);
var message = MessageResource.Create(
body: $"TEST message via Twilio",
from: new Twilio.Types.PhoneNumber(twilioPhoneNumber),
to: new Twilio.Types.PhoneNumber(geoEvent.PhoneNumber)
);
return message.Status.ToString();
}
}
GET and POST requests to the above endpoints get a 500 response when hosted in IIS. The following exception is thrown:
System.Net.Http.HttpRequestException: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond ---> System.Net.Sockets.SocketException: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
Lastly, here is the web.config that the SDK generated for me when I published the app in VS2019.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<location path="." inheritInChildApplications="false">
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath=".\TwilioService.exe" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" />
</system.webServer>
</location>
</configuration>
Neither my local machine nor the web server running IIS are behind a corporate proxy.
Am I missing an IIS or web.config setting that will allow .NET Core to make requests through IIS to a third party?
UPDATE:
I have now reproduced the same issue on a different web server running Windows Server 2016. This machine is setup with .NET 5, IIS 10, and the hosting bundle for .NET 5. I also installed VS2019 and recreated the web api project to run locally on the server. Here are the results:
Running locally in IIS Express, the api controller can successfully
make a request to the Twilio api and gets a response. The SMS
message is sent successfully. No errors.
Running locally in IIS 10, the api controller calls Twilio but
fails to get a response. The following error occurs:
Twilio.Exceptions.ApiConnectionException: Connection Error: POSThttps://api.twilio.com/2010-04-01/Accounts//Messages.json
---> System.Net.Http.HttpRequestException: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. (api.twilio.com:443)
To reiterate, both of the above scenarios are running on the same machine. The only difference is IIS Express vs IIS 10. Is this an SSL cert issue? Because IIS 10 works as a reverse proxy for .NET core apps, could there be a problem with a cert getting recognized or forwarded from the .net core app through IIS?
Try to ping the third-party service URL from your machine command prompt.
Make sure the firewall port is set to allow. check the antivirus is now blocking the connection.
try to add the defaultProxy section to my web.config in order to get my website to connect to a web service.
https://learn.microsoft.com/en-US/troubleshoot/dotnet/framework/cannot-consume-web-service-via-http-proxy
Solved. It turned out to be a corporate proxy after all. I had bad information that the web server was not behind a proxy but it was. Twilio has a solution for this exact scenario in their documentation involving the use of a custom proxied rest client class. It's a wrapper around System.Net.HttpClient. The service can now make calls to Twilio through the proxy using this class with the proxy server url set.

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.

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