Web service calling user is always anonymous - web-services

I have a simple web service written using WCF. I'm trying to get the details of the caller so I can check their details. I'm doing it like this:
var ident = ServiceSecurityContext.Current.PrimaryIdentity;
However, it's coming back as empty and
bool isAnon = ServiceSecurityContext.Current.IsAnonymous;
is returning true.
How do I get the details? I thought if, in the client I added this to the config:
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
to my basicHttpBinding it would do this.
What am I missing? I've been struggling trying to do any kind of authorisation working. This programmatic approach was because I simply failed to get WIA working through IIS.
I tried Current.WindowsIdentity and that was blank too.

Related

Client App with WsHttpBinding gets "no endpoint listening at..."

I have a client application which talks to our Web Service hosted on a server (we'll call it hostServer). My client application can build and connect fine using basicHttpBinding. However, I'm trying to impliment wsHttpBinding for security reasons.
Last week before lunch I could swear it was working with a hardcoded certificate. Came back from lunch, checked in my code and now it won't run. I keep getting "There was no endpoint listening at https://hostServer:1234/Service.svc/MyServiceName that could accept the message. This is often caused by an incorrect address or SOAP action.". I've tried re-checking my settings, retracing my steps, but can't seem to get back to the functioning state I was in.
I am using a ServiceReference with an address of "https ://hostServer:1234/Service.svc?singleWsdl". I can navigate to "https ://hostServer:1234/Service.svc" without a problem and view the Wsdl.
My client code is
WSHttpBinding wsBinding = new WSHttpBinding(SecurityMode.Transport);
wsBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
Client = new MyServiceName(wsBinding, new EndpointAddress(endpoint));
Client.ClientCredentials.ClientCertificate.SetCertificate(
StoreLocation.CurrentUser,
StoreName.My,
X509FindType.FindBySubjectName,
"localCertName");
Client.ChangePassword("test_user", "pt", "a1");
My value endpoint = https://hostServer:1234/Service.svc/MyServiceName
My IIS site is set up with Binding for Http and Https (with correct IP & Port ID)
I really need to get this code working before taking off (my wife is due with our second child any day). I've been working to debug this now for 2 days, in addition to the time it took me to stand it up as is. Please help.
So I was finally able to get this working again. Listing what steps were performed below in hopes that it might help someone else.
On IIS Server (IIS Manager):
Modified "Site Bindings" to include HTTP & HTTPS (w/different Port Numbers)
Set SSL setting to "Require SSL" and "Accept"
On IIS Server (Web.Config):
Added
<bindings>
<wsHttpBinding>
<binding name="wsHttpEndpointBinding">
<security mode="Transport">
<transport clientCredentialType ="Certificate"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
to the "System.ServiceModel" tag.
Also, added 'bindingConfiguration="wsHttpEndpointBinding"' to my endpoint.
In Code
Updated Endpoint address to use that generated on the IIS Server.
Used the following code for creating the endpoint
WSHttpBinding wsBinding = new WSHttpBinding(SecurityMode.Transport);
wsBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
Client = new ServiceClient(wsBinding, new EndpointAddress(endpoint));
Client.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMac‌​hine, StoreName.My, X509FindType.FindByIssuerName, certName);

Calling a soap web service from Microsoft CRM plugin

I have a plugin which calls a soap based web service on creation of a new contact.Its a simple soap web service which displays a welcome message when called
Below is app.config which contains all configuration requirements.
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="WelcomeBinding" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None" realm=""/>
<message clientCredentialType="UserName" algorithmSuite="Default"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://revesinc.com/WelcomeSeamService/Welcome" binding="basicHttpBinding" bindingConfiguration="WelcomeBinding" contract="ServiceReference1.Welcome" name="WelcomePort"/>
</client>
</system.serviceModel>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
and below is C# plugin code
BasicHttpBinding myBinding = new BasicHttpBinding();
myBinding.Name = "WelcomeBinding";
myBinding.Security.Mode = BasicHttpSecurityMode.None;
myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
myBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
EndpointAddress endPointAddress = new EndpointAddress("http://revesinc.com/WelcomeSeamService/Welcome");
WelcomeClient client = new WelcomeClient(myBinding,endPointAddress);
when i create a contact in CRM, nothing gets displayed on my server. there is no exception on CRM side either.
Any idea???
thanks
At first I want to ask you how are you going to display something on your server? I don't see any way to do this using plugin, but might be I'm not right. In any case, please, show part of code where you are displaying something.
You are saying that nothing happen. At first you should check that the plugin is registered properly. As I understood, you should check that there was added step with entity Contact and Message Create. Also usually plugins are created using some templates. Might be some error is in the part of your code, before calling Web Service.
And another issue I want to emphasize. You have a config file with the configurations of your assembly. I think that for plugin assemblies is better to do not store any configurations in config files, but do all the settings in code.
There are few different ways to check that plugin was fired. At first you can deploy not only dll but also pdb files and attach to the IIS process with the debugger. If there is no Visual Studio installed, you can use Remote Debugger. If it's not possible due some reason, you can throw PluginExecutionException at the beginning of your code to be sure that plug in is really called. And when you will be sure that plug in is working, you can start test working with Web Service.
I assume that you are calling some method which shows the welcome message after this line:
WelcomeClient client = new WelcomeClient(myBinding,endPointAddress);
I would suggest that you should use the tracing service for logging in your plugin. Put your plugin code in try catch and throw InvalidPluginExecutionException after tracing.
Your code may look something like this in the plugin Execute method:
try
{
ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
BasicHttpBinding myBinding = new BasicHttpBinding();
myBinding.Name = "WelcomeBinding";
myBinding.Security.Mode = BasicHttpSecurityMode.None;
myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
myBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
EndpointAddress endPointAddress = new EndpointAddress("http://revesinc.com/WelcomeSeamService/Welcome");
WelcomeClient client = new WelcomeClient(myBinding, endPointAddress);
client.ShowWelcomeMessage(); // Assuming this is your service method
tracingService.Trace("All went well. service called.");
throw new InvalidPluginExecutionException("All went well. Exception just to show the traces on the form");
}
catch (Exception ex)
{
tracingService.Trace("Error calling welcome service " + ex.Message);
throw new InvalidPluginExecutionException(ex.Message);
}
If your plugin is registered properly , you will be able to see the exception on the user action (create, update etc). You will know from traces if the service called succesfully or not.

The HTTP request is unauthorized with client authentication scheme 'Ntlm'. The authentication header received from the server was 'NTLM'

I am trying to program a VisualWebPart using Visual Studio 2010 which has to do a simple thing: invoke a web service (hosted in a remote server, NOT locally). When I execute within the Sharepoint site (version 2010, which I have published in my IIS) I get this error:
"The HTTP request is unauthorized with client authentication scheme 'Ntlm'. The authentication header received from the server was 'NTLM'."
Pardon my ignorance, but the only difference here is the case of the Ntlm authentication scheme! I have been all over the web and found many related problems, but none of the solutions worked. Almost ALL solutions i found involve modifications in the webservice security configuration, this is not an option for me.
Looking for a solution, I created a sample windows form and invoked the web service from it: no problems whatsoever.
In order to be able to invoke the webservice correctly this is the necessary security configuration:
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Ntlm" proxyCredentialType="Ntlm" realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
I believe the problem is that I haven´t been able to properly set this security property to the web.config of my Sharepoint site, since I tried to put it in the security tag that appears in the web.config but still get the same error.
Any further information needed please ask, I am REALLY desperate, for days I have been with the SAME error.
In the end I was given permissions in their server: more precisely in the database which was the one that wouldn't let me create the web part in the server. Once this was done, the call to the webservice worked just fine, because they have the web.config correctly configured.

PSI authentication only returns 401

I'm developing a web-service that is going to be a "gatekeeper" between many apps and the PSI. the thing is that the "many apps" will supply a login/password and the web-service must authenticate them against the PSI. But whatever i do i always get a 401 Unauthorized error when i call the "PSIFormsLogin.Login(user,password)" method... ive used even the user that runs the farm...
ive also already followed the following MS tutorial: http://msdn.microsoft.com/en-us/library/ff181538.aspx
in the end all i wanna do is validate the account/password supplyed using the PSI web-Services, can anyone pls tell me what am i doing wrong???
PS: not the WCF
New Info: something funny happened. I intentionally switched the URL to a non-existent on: http://myserver/pwa/_vti_bin/psi/bla.asmx but i still got a 401...
Make sure you have modified the web.config of your application like this. Just overwrite the security node in the binding node:
<binding name="WssInteropSoap">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Ntlm" proxyCredentialType="Ntlm"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
Now you can authenticate without a special account (passtrough from windows) or with this code, you can specify an account:
//credential impersonation (just if you changed your binding settings)
projectSvc.ClientCredentials.Windows.ClientCredential = new NetworkCredential("username", "password", "domain");
projectSvc.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
I hope it will help :)
But, I've never heard of a function which is called: "PSIFormsLogin.Login"
Maybe my blog entry for setting up a connection to the PSI with C# is interesting for you: Read Project Server 2010 CustomFields over PSI

Consuming HTTPS web service using WCF

I'm trying to consuming a client's web service using WCF. The client's web service is done over HTTPS, and I can consume it fine with the following Binding:
<bindings>
<basicHttpBinding>
<binding name="PurchaseOrderSoap" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="Transport" />
</binding>
</basicHttpBinding>
</bindings>
However, our security team have told me I need to use Message or TransportWithMessageCredential security, because Fortify 360 complains that Transport security is too weak.
When I try Meesage I get this error:
System.InvalidOperationException: BasicHttp binding requires that
BasicHttpBinding.Security.Message.ClientCredentialType be equivalent to the
BasicHttpMessageCredentialType.Certificate credential type for secure messages. Select
Transport or TransportWithMessageCredential security for UserName credentials.
And with TransportWithMessageCredential I get the following error:
System.InvalidOperationException: The username is not provided. Specify username in
ClientCredentials.
I've not got a username/password (I can connect to it fine in my browser), so my question is:
Can I use Message or TransportWithMessageCredentials when consuming an existing HTTPS web service (without the publisher making any changes)? If so, what changes do I need to make to my configuration?
Edited to clarify question.
If you cannot get the third party vendor to add an endpoint to their service that supports message security then you are stuck. It seems they currently only support basicHttpBinding with transport level security.
Transport security is not "less" secure than message level security. Message level security means the contents of the soap message are encrypted. This allows you to either store or relay a message in a clear text way and still be assured no one can peek at the message. If all you are doing is communicating between your system and the vendor over the internet then transport and message level security are equally secure.
The basicHttpBinding only supports username and certificate message security. So one option is, if you don't have a mechanism for validating user credentials on your sysstem, is to use certificates.
<security mode="TransportWithMessageCredential">
...
<message clientCredentialType="UserName"/>
</security>
The other option is to use a different binding, like wsHttpBinding which has message security enabled by default and also supports Windows and Issued Token credential types. Which of these you implement is largely dependent on your implementation requirements and environment.
Do you not have some sort of exception policy by which you can take a note of why it's impossible to implement Fortify's best recommendation?
I would think the best you can do is communicate with your webservice vendor and ask for an enhancement to support Fortify's transport guidelines.
Also: I'm suspicious that you say the web browser connects you without a credential. This probably means the system you are connecting to is a little more complex than your assumptions. different connections or different urls may be served by different servers (SSO?) or may be subject to different security policies (client certificate, etc)