I've come a long way since the last issue, and I think I have most of that stuff worked out. Now the problem is that what I really need is to be able to use the Dual Http binding, in conjunction with an STS to provide the SAML tokens. I have it working fine (with Dual binding) as long as I issue the token myself and attach it using ClientCredentials.
The server side binding looks like this
<behaviors>
<serviceBehaviors>
<behavior name="tokenBehavior">
<serviceCredentials>
<clientCertificate>
<certificate findValue="CN=VoyagerClient" />
<authentication certificateValidationMode="PeerOrChainTrust"
revocationMode="NoCheck" />
</clientCertificate>
<serviceCertificate findValue="CN=VoyagerServer" />
<issuedTokenAuthentication allowUntrustedRsaIssuers="true">
<knownCertificates>
<add findValue="CN=VoyagerSecureTokenService" storeLocation="LocalMachine"
storeName="My" x509FindType="FindBySubjectDistinguishedName" />
</knownCertificates>
</issuedTokenAuthentication>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsDualHttpBinding>
<binding name="tokenBinding" clientBaseAddress="http://localhost:8897/client">
<security>
<message clientCredentialType="IssuedToken" />
</security>
</binding>
</wsDualHttpBinding>
</bindings>
the client side binding like so
<behaviors>
<endpointBehaviors>
<behavior name="tokenBehavior">
<clientCredentials>
<clientCertificate findValue="CN=VoyagerClient" storeLocation="LocalMachine" />
<serviceCertificate>
<defaultCertificate findValue="CN=VoyagerServer" storeLocation="LocalMachine" />
<authentication certificateValidationMode="PeerOrChainTrust"
revocationMode="NoCheck" />
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<wsDualHttpBinding>
<binding name="tokenBinding" clientBaseAddress="http://localhost:8897/client">
<security>
<message clientCredentialType="IssuedToken"/>
</security>
</binding>
</wsDualHttpBinding>
</bindings>
On the client side, I'm using the SamlClientCredentials from the SamlTokenProvider sample, and attaching it to the outgoing endpoint.
SamlClientCredentials cred = new SamlClientCredentials();
cred.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectDistinguishedName, "CN=VoyagerClient");
cred.ServiceCertificate.SetDefaultCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectDistinguishedName, "CN=VoyagerSecureTokenService");
cred.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.
X509CertificateValidationMode.PeerOrChainTrust;
cred.ServiceCertificate.Authentication.RevocationMode = X509RevocationMode.NoCheck;
IList<Claim> claims = new List<Claim>();
claims.Add(Claim.CreateNameClaim("Fred"));
ClaimSet claimset = new DefaultClaimSet(claims);
cred.Claims = claimset;
CallBack callback = new CallBack();
InstanceContext ic = new InstanceContext(callback);
HelloWorldClient client = new HelloWorldClient(ic);
client.ChannelFactory.Endpoint.Behaviors.Remove(typeof(ClientCredentials));
client.ChannelFactory.Endpoint.Behaviors.Add(cred);
This all works like I would expect, and I get properly authorized on the server side. The only catch here is that since I'm signing the SAML token with a cert I created myself, I have to set the certificateValidationMode for the issuedTokenAuthorization bit on the server side, which sadly isn't supported through the config file, so I have to tweak the ServiceHost myself.
myServiceHost = new ServiceHost(typeof(HelloService), baseAddress);
myServiceHost.Credentials.IssuedTokenAuthentication.
CertificateValidationMode =
X509CertificateValidationMode.PeerOrChainTrust;
myServiceHost.Credentials.IssuedTokenAuthentication.RevocationMode = X509RevocationMode.NoCheck;
myServiceHost.Open();
Not too much trouble, but unfortunate. Means things will be a little more interesting when it's hosted in IIS.
So, that all works, but what I really need is for it to ask an STS for the correct token rather than creating one myself.
I was hoping that putting this in my clientCredentials on the client side would do it
<issuedToken>
<localIssuer address="http://localhost:9001/sts" binding="wsHttpBinding" bindingConfiguration="" />
</issuedToken>
but it doesn't seem to. I'm assuming that's behavior that's built into the wsFederationHttpBinding, and not in wsDualHttpBinding. I'm hoping that I won't have to make the call to the STS myself, but as a last resort, that'll do...