Problem with WCF and NTLM - c#

Im trying to call an Axis Ws that has NTLM Security in it, im using BasicHttpBinding, the problem is that if i call it i get an error saying:
The server did not provide a meaningful reply; this might be caused by a contract mismatch, a premature session shutdown or an internal server error.
I dont have any access to that server so i cannot look at how it is configured.
But if the call a Get with HttpWebRequest to that WS with my credentials too, and then call the ws it works fine.
Any idea on what i am missing?

Looks like you need to pass your credentials when calling the web service. Have you tried using impersonation or passing your credentials (like so)?
SomeService client = new SomeService();
client.Credentials = new NetworkCredentials("username","password");
...

You may want to check the following settings are set on your webserver web.config
<system.web>
<identity impersonate="true" />
<authentication mode="Windows">
</system.web>

Related

Default Proxy ASP.NET Core Web API

I need to configure a default proxy to enable Application Insights.
In an ASP.NET Web Api the default proxy can be set in the web.config like below:
<system.net>
<defaultProxy enabled="true" useDefaultCredentials="true">
<proxy proxyaddress="someaddress" bypassonlocal="True" />
</defaultProxy>
</system.net>
With this setting AI works fine. Unfortunately I could not find an option to set the proxy in appsettings.json. Is there any possibility to define the default proxy in an ASP.NET Core Web API?
Or do I have to configure the proxy in IIS, when the application is getting hosted with it?
Edit:
I am setting the default proxy now like this:
WebRequest.DefaultWebProxy = new WebProxy(new Uri("someaddress"), true)
{
UseDefaultCredentials = true
};
When getting the proxy with
WebRequest.DefaultWebProxy.GetProxy(new Uri("https://dc.services.visualstudio.com/v2/track"))
it returns the correct proxy.
Strange things happens when Fiddler is running.
As soon as Fiddler is running the application is logging successfully to AI. When closing Fiddler the logging breaks again.
Has anyone an idea?
Do you mean you want to configure HttpClient proxy globally?
If so, I am afraid it is impossible. You may consider creating an encapsulate class with accepting Proxy configuration and return a HttpClient, you could load the configuration from appsettings.json or anywhere
Perhaps your traffic is going through Fiddler Proxy so when Fiddler shuts down so as your connection to other services.

proper implementation of "windows" authentication in web api?

I've created a Web Api 2 app which will only be used on the corporate network. I've read about Windows authentication in Web API so it seems to be possible. But I need to figure out the proper implementation for this. I've included the following xml in my Web.config:
<system.web>
<authentication mode="Windows" />
</system.web>
I seem to remember some type of event hook in old school webforms app. Something like BeginRequest() where a security check could be made before rendering a page. I included the following line of code as the first line in one of my controller methods but the returned value appears to just be an empty object without any meaningful info:
var identity = HttpContext.Current.User.Identity as WindowsIdentity;
Does Web API 2 support Windows authentication? Am I missing a step? Should Windows authentication work if I submit a general request from Postman for testing? I also tried this code but got a similar empty object:
var x = RequestContext.Principal;
I vaguely recall an IIS setting like "Enable Integrated Security." Can you please specify the exact setting? And would I be able to accomplish this if I'm running the app on IIS Express?
UPDATE
I followed the steps for IIS Express mentioned in one of the answers below but the code samples that I provided in my original post still didn't get a populated user object. I also updated applicationhost.config file to turn off anonymous authentication:
<anonymousAuthentication enabled="false" userName="" />
After I made that updated I resubmitted my test request via Postman but I get the following error:
<h3>HTTP Error 401.2 - Unauthorized</h3>
<h4>You are not authorized to view this page due to invalid authentication headers.</h4>
</div>
<div class="content-container">
<fieldset>
<h4>Most likely causes:</h4>
<ul>
<li>No authentication protocol (including anonymous) is selected in IIS.</li>
<li>Only integrated authentication is enabled, and a client browser was used that does not support integrated authentication.</li>
<li>Integrated authentication is enabled and the request was sent through a proxy that changed the authentication headers before they reach the Web server.</li>
<li>The Web server is not configured for anonymous access and a required authorization header was not received.</li>
<li>The "configuration/system.webServer/authorization" configuration section may be explicitly denying the user access.</li>
</ul>
</fieldset>
</div>
<div class="content-container">
<fieldset>
<h4>Things you can try:</h4>
<ul>
<li>Verify the authentication setting for the resource and then try requesting the resource using that authentication method.</li>
<li>Verify that the client browser supports Integrated authentication.</li>
<li>Verify that the request is not going through a proxy when Integrated authentication is used.</li>
<li>Verify that the user is not explicitly denied access in the "configuration/system.webServer/authorization" configuration section.</li>
<li>Check the failed request tracing logs for additional information about this error. For more information, click
here.
</li>
</ul>
</fieldset>
</div>
Do I need to configure my Postman request with some type of special header in order for this to work?
In addition to the previous answers, we also need to Pass credentials in cross-origin requests.
Server Side (Web API):
Set the SupportsCredentials property to true on the [EnableCors] attribute:
[EnableCors(origins: "http://exampleclient.com", headers: "*",
methods: "*", SupportsCredentials = true)]
Client Side (UI):
Set XMLHttpRequest.withCredentials to true.
jQuery:
$.ajax({
type: 'get',
url: 'http://www.example.com/api/auth',
xhrFields: {
withCredentials: true
}
Angular:
this.http.get('http://www.example.com/api/auth', { withCredentials: true }).subscribe((resp: any) => {
console.log(resp)
}
XMLHttpRequest:
var xhr = new XMLHttpRequest();
xhr.open('get', 'http://www.example.com/api/auth');
xhr.withCredentials = true;
If you are using IIS Express, you need to update applicationhost.config file.
This is the file version of the IIS configuration tool where you can configure the web server itself. you can find this file in the following directory:
%userprofile%\documents\iisexpress\config\applicationhost.config
or
%userprofile%\my documents\iisexpress\config\applicationhost.config
When you find it, update it as:
<windowsAuthentication enabled="true">
<providers>
<add value="Negotiate" />
<add value="NTLM" />
</providers>
</windowsAuthentication>
For IIS:
Select your Application
Double Click - 'Authentication'
Enable Windows Authentication
Restart IIS Server
Check this for more details
Windows authentication that uses the local domain user and that is intended for intranet sites.
Example :
I implemented a TestAuthentication method/action with a fixed route path. For the demo I do not include Authorize attributes yet. The code checks the User property of the ApiController. This contains the same data as Thread.CurrentPrincipal or HttpContext.Current.User. Make sure Anonymous Authentication in IIS is disabled otherwise the Identity.Name will be empty.
public class WinAuthController : ApiController
{
[HttpGet]
[Route("api/testauthentication")]
public IHttpActionResult TestAutentication()
{
Debug.Write("AuthenticationType:" + User.Identity.AuthenticationType);
Debug.Write("IsAuthenticated:" + User.Identity.IsAuthenticated);
Debug.Write("Name:" + User.Identity.Name);
if (User.Identity.IsAuthenticated)
{
return Ok("Authenticated: " + User.Identity.Name);
}
else
{
return BadRequest("Not authenticated");
}
}
}
In Web.config file :
<system.web>
<authentication mode="Windows" />
</system.web>
In IE you can check the setting with Tools > Internet Options > Advanced and look for a setting Enable Windows Integrated Authentication. When you go to the tab Security and then Intranet and Custom Level, then you will find a setting at the bottom to specify if IE should logon automatically or prompt for the username and password.
Please visit below link, it has proper steps to follow for WEP API Windows authentication :
http://www.scip.be/index.php?Page=ArticlesNET38&Lang=EN
Below are the steps to configure windows authentication in web api for both local and server (IIS).
1) For Local:
a) To create a web api project in windows authentication mode, follow below steps:
After choosing ASP.Net Web Application, select Web API template and from the right side click Change Authentication button and select Windows Authentication.
b) For an existing web api project, just add the following lines in your applicationhost.config file.
<location path="YourProjectName">
<system.webServer>
<security>
<authentication>
<anonymousAuthentication enabled="false" />
<windowsAuthentication enabled="true" />
</authentication>
</security>
</system.webServer>
</location>
2) For Server (IIS)
To run windows authentication after hosting the application in IIS just add following lines in your web.config file inside system.web node:
<authentication mode="Windows" />
<authorization>
<allow verbs="OPTIONS" users="?" />
<deny users="?" />
</authorization>
In both the cases, just use the following lines in your code that windows authentication is working properly:
if(User.Identity.IsAuthenticated)
{
//do work
}

C# 407 Proxy Authentication Required

I want to make a request to a resource (that resource is behind a proxy). I have the proxy address and the port as well. I have tried with NetworkCredentialn no success, with CacheCredentials no success. WebException is:
ProtocolError
The remote server returned an error: (407) Proxy Authentification Required
I always get error at this line:
WebResponse response = request.GetResponse();
I have already done this:
Package manager in Visual Studio 2015 "407 (Proxy Authentication Required)"
I tried to configure my App.config file
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.net>
<defaultProxy useDefaultCredentials="true" />
</system.net>
</configuration>
From our corporate network, we usually employ this code:
WebProxy proxy = new WebProxy("http://your.proxy.server:8080", true);
proxy.Credentials = new NetworkCredential("user", "password");
WebRequest.DefaultWebProxy = proxy;
The idea is you put this code somewhere at the beginning of your program (or in the App start if you're on IIS) and then every single request will take the default proxy configuration.
No change in web.config is required. AFAICT, in web.config you cannot set the credentials.
In my experience, it works also for web services and WCF communications.

WebRequest.Proxy - What is the default value

Background: We have a service installed at a remote site that has started failing to call an external webservice. According to the network\support engineers on site no proxy should be required, but when attempting to execute the WebRequest an exception is returned:
System.Net.WebException: The remote server returned an error: (407) Proxy Authentication Required.
The exception is relatively self-explanatory, but looking at the code, no Proxy is specified in the call to the WebRequest and no proxy is defined in the app.config file.
Referring to the MSDN documentation for WebRequest.Proxy:
"The IWebProxy object to use to proxy the request. The default value is set by calling the GlobalProxySelection.Select property."
and then referring to the documentation for GlobalProxySelection.Select:
"Gets or sets the global HTTP proxy."
And given that GlobalProxySelection.Select is not set anywhere in the application, where does the default value come from? And are there any other global config files where the global HTTP proxy may be set?
You have to set the proxy manually. You can do it by doing the following, if you want to use the Default system proxy. (Internet settings in windows)
myRequest.Proxy = WebRequest.GetSystemWebProxy();
You are getting the error because your network is blocking access to the server directly without using a proxy.
While this doesn't solve your problem directly, can I recommend trying a <defaultProxy /> element in your app.config / web.config under <system.net> with useDefaultCredentials="true" - this may well get your application authenticating through the proxy and therefore not requiring a special bypass rule at all.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.net>
<defaultProxy useDefaultCredentials="true" />
</system.net>
</configuration>

WCF Web Services - Multiple Hop impersonation on the same server

I have 3 web services, all located on the same server.
My Client calls Service A, which impersonates the client to call Service B, and all is well.
Now, I want to impersonate the caller of service B (which is my username) to call Service C. When I use the same technique as before (AllowedImpersonationLevel = Impersonate, user.Impersonate()), The user doesnt get passed to service C. Instead, Service C sees the user as the user I am running it under in IIS (which is a UPN, not the standard NETWORK SERVICE account).
Is there anything special I need to do to get this working? Is this a delegation issue? (I thought it would not be delegation because they are all on the same server)
Thanks SO!
You require delegation in this scenario. The configuration you require is ImpersonationLevel.Delegation (set in config or code). Have a look at the WCF Security Guidance on codeplex it is a very good source. Be careful as achieving delegation, particularly in a production environment, requirements more than simply selecting the correct option in the config file. You need to ensure that the application you connect to, e.g. SQL server, are configured for delegation, and that certain infrastructure requirements are met within active directory and the like, such as service principal names (SPN).
You can try turning on ASP.Net Compatibility on Service C
In Web.cofig
<system.web>
<identity impersonate="true"/>
<authentication mode="Windows"/>
</system.web>
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
In your service class
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Service : IService
{
public string ExecuteRequest(string xmlRequest)
{
IRequestManager requestManager = new RequestManager();
return requestManager.ProcessRequest(xmlRequest);
}
}
I would have expected to have to use delegation since you are crossing process boundaries twice. Have you tried TokenImpersonationLevel.Delegation?

Categories