Workflow Services in .NET 4 allow you to do long running processes. But when you do that, there’s an interesting question: when a workflow has been suspended, under which user is the workflow running when it is active again. To answer this question I created a simple workflow that writes the user in the current thread to a log. On the initial call, the user making the call was logged (in this case I used Windows Identity Foundation to authenticate, but this should be the same for all types of authentication). After a Delay of a minute that user was gone, and instead the user in the current thread was unauthenticated. This means that any code you call from the workflow can’t rely on Thread.CurrentPrincipal to get the proper authorizations. You have to save the user, and somehow reinstate principal so it runs under the original context. Alternatively you can use some form of delegation.
Working with Windows Identity Foundation can be quite a minefield. Solve one issue, and the next creeps up. Because it’s all these little tweaks to make it work, I often find myself thinking “How did I solve that last time?” One of those issues is the following exception:
Could not establish trust relationship for the SSL/TLS secure channel with authority ‘somesite.runningunder.ssl’
There are two reasons why you can run into this exception, each discussed below.
The certificate isn’t trusted and/or the URL doesn’t correspond with the URL in the certificate.
If this is the case, you get certificate warnings when you browse to the service WSDL with a browser. The best way to solve the former is to have your (development) environment work with certificates it trusts. This means setting up a Certificate Authority (Active Directory Certificate Services), placing the root CA certificate in the Trusted Root Certificates of the machine your clients (and services) run on, issuing the needed certificates from the CA, and placing these where they are needed. Alternatively, you can just add a
single line of code to your client so it ignores certificate issues before you do any service call:
System.Net.ServicePointManager.ServerCertificateValidationCallback = ((sender, certificate, chain, sslPolicyErrors) => true);
WARNING! ONLY USE THE ABOVE CODE FOR DEVELOPMENT PURPOSES. IT IS NOT SECURE.
If after you’ve done the above you still get an exception, the above code is likely not even being hit. That means you (also) have the problem below.
You’ve setup identity trust in your client, and the certificate reference is incorrect.
This often happens when you copied some configuration from somewhere, and forgot to change the corresponding certificate reference. The red stuff in the client configuration below (which is much longer in a real configuration) is the culprit. It should contain the encoded certificate.
<system.serviceModel> <client> <endpoint address="https://YourServer/Service1.svc" binding="customBinding" bindingConfiguration="CustomBinding_IService1" contract="ServiceReference1.IService1" name="Service1Binding"> <identity> <certificate encodedValue="MIIF5jCCBM6gAwIBAgIKYSt2tQA..."/> </identity> </endpoint> </client> </system.serviceModel>
To solve this, you need to get the base64 encoded certificate string, and paste it in place of what’s in there now. To get it you can do the following:
- Browse to the endpoint with your browser.
- View the certificate information.
- Save the certificate to file.
- Open the certificate with notepad.
- Copy the encoded value between the —–BEGIN CERTIFICATE—– and —–END CERTIFICATE—– placeholders.
I’ve been working with WCF for quite a while, and every so often I run into this exception:
ArgumentException: The provided URI scheme 'https' is invalid; expected 'http'.Parameter name: via
The problem is obvious. You’re trying to access a service under HTTPS, but it’s being called with HTTP. Under most bindings you can solve this by adding something like this to the client binding configuration:
<binding name="MyBinding"> <security mode="Transport"> <transport clientCredentialType="None" /> <message clientCredentialType="None" negotiateServiceCredential="false" establishSecurityContext="false" /> </security> </binding>
When you use a (custom) ws2007FederationHttp binding, for instance when working with Windows Identity Foundation, the above won’t work. In that case you need to look in the binding for the <httpTransport> element and replace it with <httpsTransport>.