WCF message level user credentials with powershell - wcf

Is there some way to connect to a web service that has message level user credentials using powershell.
I have a tested web service that works great with a C# program that I connect specifying credentials as follows:
DEVService.ServerLinkClient webService = new DEVService.ServerLinkClient("ServerLinkEndPoint");
webService.ClientCredentials.UserName.UserName = "*****";
webService.ClientCredentials.UserName.Password = ""*****";
The configuration of the web service is as follows:
<bindings>
<basicHttpBinding>
<binding name="ServerLinkBinding" maxBufferSize="2097152" maxReceivedMessageSize="2097152"
maxBufferPoolSize="2097152" sendTimeout="00:02:00" receiveTimeout="00:02:00">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="APOServiceLibrary.ServerLink"
behaviorConfiguration="SecureBehaviourServerLink">
<endpoint name="ServerLinkEndPoint"
address=""
binding="basicHttpBinding"
bindingConfiguration="ServerLinkBinding"
contract="APOServiceLibrary.IServerLink">
</endpoint>
<endpoint address="mexServerLink"
binding="mexHttpsBinding"
contract="IMetadataExchange">
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="SecureBehaviourServerLink">
<serviceMetadata httpsGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="False"/>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="APOServiceLibrary.ConnectionSecurityServerLink, APOServiceLibrary"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
I have connect to a simple web service in the past with powershell, but that service was setup to use windows authentication. In this case, the transportation layer is just basic secured, and the message is expecting a certain username and password.
This is the scripting I'm trying to use to fetch a data set from the web service:
#setup the credentials to connect
$securePasswd = ConvertTo-SecureString "*******" -AsPlainText -Force
$tempCredentials = New-Object System.Management.Automation.PSCredential (""*******" ", $securePasswd)
# Connect to the web services
$web_serv = New-WebServiceProxy -uri https://127.0.0.1/ServerLink.svc -Credential $tempCredentials
# get some data
$test_data = New-Object System.Data.DataSet
$test_data = $web_serv.getDataSet()
However, when I try to connect using credentials and try to run a command I get the following error:
Exception calling "getDataSet" with "0" argument(s): "An error occurred when verifying security for the message."
Any help would be awesome!
Or even to know if it's possible to put some sort of message level username and password into the powershell connection would be good to!

I found this:
http://social.technet.microsoft.com/Forums/windowsserver/en-US/54d89b12-8623-47d1-8873-b4ba7927a4a5/powershell2-newwebserviceproxy-soap-security-header?forum=winserverpowershell
Basically suggesting that the powershell New-WebServiceProxy commandlet is not detailed enough to deal with this level of complexity.
To that end, I have worked around my problem by changing the web service to only use tranport security as follows:
<binding name="ServerLinkBinding" maxBufferSize="2097152" maxReceivedMessageSize="2097152"
maxBufferPoolSize="2097152" sendTimeout="00:02:00" receiveTimeout="00:02:00">
<security mode="Transport" />
</binding>
And requiring a username and password be provided to each method (which in my case works because of the limited number of methods).

Related

Can't authenticate using wsHttpBinding with ClientCredentialsType=Username

I am new to WCF and now really lost with this problem...
I want my WCF Service to authenticate incoming request using the username and password provided by client.
Relevant parts of Web.Config looks like this:
<endpoint name="wsBinding"
address=""
binding="wsHttpBinding"
contract="ServiceLib.IBooking"
bindingConfiguration="myWSSettings"
/>
And...
<bindings>
<wsHttpBinding>
<binding name="myWSSettings">
<security mode="Transport">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceCredentials>
<userNameAuthentication
userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType= "ServiceLib.MyCustomUserNameValidator, ServiceLib" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
MyCustomUserNameValidator is just a temporary validator which simply throws Exception if username is not equal to password.
Client program (a console app) is doing this:
BookingClient client = new BookingClient("wsBinding");
Passenger passenger = new Passenger();
// ../
client.ClientCredentials.UserName.UserName = "SomeUserName";
client.ClientCredentials.UserName.Password = "WrongPassword";
// ...
// ...
// NOTE: Following should throw My SecurityException Since username and
// Password are not equal
bool confirmed = client.IsTicketConfirmed(passenger);
This is the error I get:
The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'Negotiate,NTLM,Basic
Would really appreciate any help! I have spent tons of time trying to figure this out but in vain.
Thanks
Sandeep
Note:--------
I am using GoDaddy to host my WCF Service. Security mode = "Message" cannot be used there due to partial trust.
SSL certificate is correctly installed.
You must change security mode to TransportWithMessageCredential :
<wsHttpBinding>
<binding name="SafeServiceConf">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
</security>
</binding>
</wsHttpBinding>
You will found a good sample here.

The remote server returned an error: (413) Request Entity Too Large + WCF

May be this question is a duplicate. I have a WCF upload service through which the client uploads a particular file to the server.
I could successfully send files of size 12MB through the service.
Now I have integrated a self certified SSL certificate to the WCF Service. The same application which was working fine without SSL now returns an error saying Remote server returned an error (413) request entity too large.
how do I fix this error is this something to do with SSL ?
where am I going wrong.
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="customHttpBinding" openTimeout="00:10:00" sendTimeout="00:10:00"
maxReceivedMessageSize="10067108864"
messageEncoding="Mtom" transferMode="Streamed">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="customServiceBehavior">
<serviceMetadata httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="PeerOrChainTrust" trustedStoreLocation="LocalMachine"/>
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="customServiceBehavior" name="FileTransferService">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="customHttpBinding"
contract="IFileTransferService" />
</service>
</services>
thanks
This seems to be the ticket to fixing the 413 Request Entity too large error with WCF over HTTPS
C:\Windows\System32\inetsrv>appcmd.exe set config "Default Web Site" -section:system.webServer/serverRunTime /uploadReadAheadSize:10485760 /commit:apphost
The reason seems to be related to how IIS handles authentication of incoming requests over SSL.
Another resource: http://blogs.msdn.com/b/jiruss/archive/2007/04/13/http-413-request-entity-too-large-can-t-upload-large-files-using-iis6.aspx
I just spent most of my afternoon tracking this problem down...many other suggestions didn't help me much but this certainly did, so hopefully this will get you fixed up.

Custom UserName/Password authentication in IIS6

I have a WCF service I'm hosting in IIS6. I'm trying to set up custom username/password authentication using Transport level security. I've set up a test certificate and got a client to connect over SSL with no authentication specified, i.e:
<security mode="Transport">
<transport clientCredentialType="Basic" />
</security>
I've set up a custom validator with Message security and client credential type "UserName", but I'd like to incorporate this now with Transport level security. When I have my web.config set, when I try to view the WSDL, I get an error:
"Security settings for this service require 'Basic' Authentication but it is not enabled for the IIS application that hosts this service."
Here are the important parts of my web.config:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="UserNameBinding">
<security mode="Transport">
<transport clientCredentialType="Basic" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="ServiceAuthenticationBehavior"
name="Service.WebServices.MyService">
<endpoint address="mex" binding="mexHttpsBinding" bindingConfiguration=""
name="mexBinding" contract="IMetadataExchange" />
<endpoint binding="wsHttpBinding" bindingConfiguration="UserNameBinding"
name="wsHttpBindingWithAuth" contract="Service.WebServices.IMyService" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceAuthenticationBehavior">
<serviceMetadata httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials>
<serviceCertificate findValue="TestCert01" storeLocation="LocalMachine"
storeName="TrustedPeople" x509FindType="FindBySubjectName" />
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="Service.WebServices.ClientCredentialsValidator, Service.WebServices" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
Is there something I'm supposed to set in IIS6 to enable this?
In IIS, I started initially with the "Enable anonymous access" option enabled. I also tried enabling "Basic authentication (password is sent in clear text)" checkbox, but no success.
This post seems to suggest that Basic is only available for Windows account, with a 3rd party solution...
Basic Authentication with WCF REST service to something other than windows accounts?
I've been here myself, and ended up going with 1-legged openauth which worked nicely.
edit
this post sent me well on my way to a solution http://www.cleancode.co.nz/blog/523/oauth-dot-net
its worth mentioning the diff between 1 and 2-leg OAuth. 1-leg is where the client and the service both know the client's secret (password) for the client's account name which is used to encrypt and decrypt the authentication request (which all gets added to the querystring). with 2-legged, this is generated by a 3rd party such as google, facebook etc.

Using client certificates for authentication

The client machine has the "TicketSalesClient" certificate in "My" storage of current user and the "TicketSalesServer" certificate in "TrustedPeople" storage of current user. The server machine has "TicketSalesClient" certificate in "TrustedPeople" storage of local machine and the "TicketSalesServer" certificate in "My" storage of local machine.
The service runs under IIS 7. Below is the web.config file:
<system.serviceModel>
<services>
<service behaviorConfiguration="secureBehavior" name="InternetRailwayTicketSales.TicketSalesImplementations.TicketSalesService">
<endpoint address="TicketSalesService"
binding="basicHttpBinding"
bindingConfiguration="secureHttpBinding" contract="InternetRailwayTicketSales.TicketSalesInterface.ITicketSales" />
<endpoint address="TicketSalesServiceSecureMex"
binding="basicHttpBinding"
bindingConfiguration="secureHttpBinding"
contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="https://localhost:443/TicketSales/" />
</baseAddresses>
</host>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="secureHttpBinding">
<security mode="Transport">
<transport clientCredentialType="Certificate"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="secureBehavior">
<serviceThrottling maxConcurrentInstances="5000" maxConcurrentSessions="5000" />
<serviceMetadata httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="True" />
<serviceCredentials>
<serviceCertificate findValue="TicketSalesServer"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName"/>
<clientCertificate>
<authentication certificateValidationMode="PeerTrust"/>
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
The service in IIS is configured for SSL and certificate requiring.
1)Now when I try to add service reference in the client I receieve: "The HTTP request was forbidden with client authentication scheme 'Anonymous'. The remote server returned an error: (403) Forbidden."
2)If I try to request the metadata endpoint using browser I firstly apply the SSL certificate and then receieve an error that "The credentials do not give the right to view this directory or page." As I understand this is because I can't give the client credentials through the browser.
3)I tried to use svcutil with configuration file which contains client credentials:
<configuration>
<system.serviceModel>
<client>
<endpoint
behaviorConfiguration="ClientCertificateBehavior"
binding="basicHttpBinding"
bindingConfiguration="Binding1"
contract="IMetadataExchange"
name="https" />
</client>
<bindings>
<basicHttpBinding>
<binding name="Binding1">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="ClientCertificateBehavior">
<clientCredentials>
<clientCertificate findValue="TicketSalesClient"
storeLocation="CurrentUser"
storeName="My"
x509FindType="FindBySubjectName" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
And then:
svcutil https://veryLongAddress.svc?wsdl /config:svcutilConf.config
And the response is that the "The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel. The remote certificate is invalid according to the validation procedure"
So what am I doing wrong?
Seems like your certificates installation is fine. Can you try as shown below and see the output. Try to browse to the service from IE and you should be able to see the service and its wsdl.
Go to IE and then
Tools --> Internet Options --> Security --> Internet --> Custom Level
Tools --> Internet Options --> Security --> Intranet --> Custom Level
Now scroll down to Misc section to find the option "Dont Prompt for client certificate selection when no certificate is present or only one certificate is present" to Diable.
Now restart IE and browse to the service and IE should ask you to select a client certificate from the personal store and you need to select mvc.localhost.
If TicketSalesClient cert is not visible then your client certificate is not in the appropriate store.
The reason for this is that the file you are using to install the certificates do matter as well as the purpose for which the certificate has been created. You can find the purpose of each certificate when you double click them in the certificate store you have a column that is called Intended Purpose. Make sure its for your client certificate.
When hosting the service in IIS all endpoints must have the same transport security configuration. I played with this before and I ended with redefining binding for WSDL GET (yes it has also internal binding defined). So modify your bindings on service to:
<basicHttpBinding>
<binding name="secureHttpBinding">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</basicHttpBinding>
<customBinding>
<binding name="wsdlBinding">
<textMessageEncoding messageVersion="None" />
<httpsTransport requireClientCertificate="true" />
</binding>
</customBinding>
And in service behaviors use:
<serviceMetadata httpsGetEnabled="true"
httpsGetBinding="customBinding"
httpsGetBindingConfiguration="wsdlBinding" />
This should force WSDL get to require client certificate and it "should" work from browser (unless there is some other problem).
When we host WCF service in IIS with security type transport and client credential type certificate, Then put your client certificate on Root store and enable anonymous authentication in IIS. Enable anonymous authentication in IIS But most important, add your certificate to root store.

Adding a service reference to a WCF service with webHttpBinding and security mode Transport results in an incorrect config file

I have searched and searched and I cannot find a solution. It seems like it would be relatively common to run into this... WCF REST service over https. When I add the service reference all of the proxy classes are correct and I can create the objects defined in the service, call the services, etc. However, I can't create a configured client with the proxy's client classes. I have to explicity create the bindings, behaviors, and endpoints and add them to the client. FOr example, what I should be able to do, based on all of my research is:
ServiceClient = new ServiceClient();
And be off and running. However, what I have to do is:
WebHttpBinding serviceBinding = new WebHttpBinding(WebHttpSecurityMode.Transport);
serviceBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
EndpointAddress endPointAddress
= new EndpointAddress(<endpointaddress>);
// Create Service Client
ServiceClient = new ServiceClient(serviceBinding, endPointAddress);
// Add Web Behavior to the EndPoint
WebHttpBehavior webHttpBehavior = new WebHttpBehavior();
ServiceClient.Endpoint.Behaviors.Add(webHttpBehavior);
// Set up the request to POST with a wrapped request
WebInvokeAttribute postAttribute = new WebInvokeAttribute();
postAttribute.Method = "POST";
postAttribute.BodyStyle = WebMessageBodyStyle.WrappedRequest;
ServiceClient.Endpoint.Contract.Operations.Find(<operationname>).Behaviors.Add(postAttribute);
In order to mimic the service configuration:
<behaviors>
<endpointBehaviors>
<behavior name="AspNetAjaxBehaviorXml">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="AuthenticationServicesBehavior">
<serviceMetadata httpsGetEnabled="true" policyVersion="Policy15" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
<behavior name="LoggingServicesBehavior">
<serviceMetadata httpsGetEnabled="true" policyVersion="Policy15" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="True" />
<bindings>
<webHttpBinding>
<binding name="WebSslBinding">
<security mode="Transport">
<transport clientCredentialType="None" />
</security>
</binding>
</webHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="AuthenticationServicesBehavior"
name="AuthenticationServices">
<endpoint address="authenticate" behaviorConfiguration="AspNetAjaxBehaviorXml"
binding="webHttpBinding" bindingConfiguration="WebSslBinding"
name="AuthenticationEndPoint" bindingNamespace="<mynamespace>"
contract="IService" />
</service>
The "Add Service Reference" is giving me this:
<bindings>
<customBinding>
<binding name="AuthenticationEndPoint">
<!-- WsdlImporter encountered unrecognized policy assertions in ServiceDescription 'EchoAppsServices': -->
<!-- <wsdl:binding name='AuthenticationEndPoint'> -->
<!-- <sp:HttpsToken xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">..</sp:HttpsToken> -->
<textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16"
messageVersion="Soap12" writeEncoding="utf-8">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
</textMessageEncoding>
</binding>
</customBinding>
</bindings>
<client>
<endpoint binding="customBinding" bindingConfiguration="AuthenticationEndPoint"
contract="AuthenticationService"
name="AuthenticationEndPoint" />
</client>
I believe my inability to create a default client that works out of the box is related to the problem with WsdlImporter. I get a similar error when I use svcutil:
Warning: The following Policy Assertions were not Imported:
XPath://wsdl:definitions[#targetNamespace='<mynamespace>']/wsdl:binding[#na
me='AuthenticationEndPoint']
Assertions:
<sp:HttpsToken xmlns:sp='http://schemas.xmlsoap.org/ws/2005/07/securitypolic
y'>..</sp:HttpsToken>
I'm sure it has something to do with my self signed cert, but I can't get makecert to give me a functioning cert with a CA that doesn't cause my IIS to crash.
Environment details:
VS2008
XP 64bit
.NET 3.5
IIS6
Thanks in advance for any help...
If you want to create client proxy classes, why would you use webHttpBinding. Why not just use wsHttpBinding?
The whole point of webHttpBinding was so that you could use standard Http toolkits like HttpWebRequest and Microsoft.Http.HttpClient on the client to access the service.
Not sure if that's just a typo - but your code and config don't match.
See in your code:
serviceBinding.Security.Transport.ClientCredentialType =
HttpClientCredentialType.Windows;
but in your config:
<webHttpBinding>
<binding name="WebSslBinding">
<security mode="Transport">
<transport clientCredentialType="None" />
</security>
</binding>
</webHttpBinding>
In code, you set your HttpClientCredentialType to Windows (integrated Windows authentication), but in config, you set it to None.
Try changing your config to use Windows as well:
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
and try again.
If you don't get any better results : why not just update the client config manually, after the import? The WSDL importer is known to have hiccups here and there, and most often, just using your brain and manual config adaption can solve the problem. You basically just need to copy the <endpointBehaviors> and the <bindings> sections into your client side config and define a <client> section which references the appropriate endpoint - that's pretty much all.
You bring up a good point, but I started down this road to make a RESTful web service that can be called either from the client or the server. I can call it from both right now just the way it is but I have to explicitly configure the server side. This is unacceptable because this application will be deployed to multiple end users and it's easier to change a configuration file than it is to patch. I know that I could create multiple endpoints, but I would much rather only have to maintain one per service.
Thank you for your reply.