How do I make my WCF client authenticate using the ACS to my internally hosted WCF service? The issue revolves around setting a custom Realm (which I can't figure out how to set.)
My ACS is configured similar to the ACS Samples however the "Realm" is defined as shown below.
Excerpt from Azure ACS Configuration page
Client Side Code
EndpointAddress serviceEndpointAddress = new EndpointAddress( new Uri( "http://localhost:7000/Service/Default.aspx"),
EndpointIdentity.CreateDnsIdentity( GetServiceCertificateSubjectName() ),
new AddressHeaderCollection() );
ChannelFactory<IStringService> stringServiceFactory = new ChannelFactory<IStringService>(Bindings.CreateServiceBinding("https://agent7.accesscontrol.appfabriclabs.com/v2/wstrust/13/certificate"), serviceEndpointAddress );
// Set the service credentials.
stringServiceFactory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
stringServiceFactory.Credentials.ServiceCertificate.DefaultCertificate = GetServiceCertificate();
// Set the client credentials.
stringServiceFactory.Credentials.ClientCertificate.Certificate = GetClientCertificateWithPrivateKey();
Server Side Code
string acsCertificateEndpoint = String.Format( "https://{0}.{1}/v2/wstrust/13/certificate", AccessControlNamespace, AccessControlHostName );
ServiceHost rpHost = new ServiceHost( typeof( StringService ) );
rpHost.Credentials.ServiceCertificate.Certificate = GetServiceCertificateWithPrivateKey();
rpHost.AddServiceEndpoint( typeof( IStringService ),
Bindings.CreateServiceBinding( acsCertificateEndpoint ),
"http://localhost:7000/Service/Default.aspx"
);
//
// This must be called after all WCF settings are set on the service host so the
// Windows Identity Foundation token handlers can pick up the relevant settings.
//
ServiceConfiguration serviceConfiguration = new ServiceConfiguration();
serviceConfiguration.CertificateValidationMode = X509CertificateValidationMode.None;
// Accept ACS signing certificate as Issuer.
serviceConfiguration.IssuerNameRegistry = new X509IssuerNameRegistry( GetAcsSigningCertificate().SubjectName.Name );
// Add the SAML 2.0 token handler.
serviceConfiguration.SecurityTokenHandlers.AddOrReplace( new Saml2SecurityTokenHandler() );
// Add the address of this service to the allowed audiences.
serviceConfiguration.SecurityTokenHandlers.Configuration.AudienceRestriction.AllowedAudienceUris.Add( new Uri( "urn:federation:customer:222:agent:11") );
FederatedServiceCredentials.ConfigureServiceHost( rpHost, serviceConfiguration );
return rpHost;
... where urn:federation:customer:222:agent:11
is the Relying party ID
... and http://localhost:7000/Service/Default.aspx
is the location I want the above WCF / WIF client to bind to once the ACS authentication is made.
Question
How do I edit the code above so that the client and server will both operate against a certain port (localhost:700) and also with a realm of urn:federation:customer:222:agent:11
I think I have the server code correct; however how do I set AudienceRestriction
on the client?
Your server side code looks fine, but Sixto is right about standard channel factories. Luckily, you can request a security token from ACS yourself using a WSTrustChannelFactory. In the context of your sample, your code would look like this:
//
// Get the token from ACS
//
WSTrustChannelFactory trustChannelFactory = new WSTrustChannelFactory(
Bindings.CreateAcsCertificateBinding(),
new EndpointAddress( acsCertificateEndpoint ) );
trustChannelFactory.Credentials.ClientCertificate.Certificate = GetClientCertificateWithPrivateKey();
RequestSecurityToken rst = new RequestSecurityToken()
{
RequestType = RequestTypes.Issue,
AppliesTo = new EndpointAddress( new Uri( "urn:federation:customer:222:agent:11" ) ),
KeyType = KeyTypes.Symmetric
};
WSTrustChannel wsTrustChannel = (WSTrustChannel)trustChannelFactory.CreateChannel();
SecurityToken token = wsTrustChannel.Issue( rst );
//
// Call StringService, authenticating with the retrieved token
//
WS2007FederationHttpBinding binding = new WS2007FederationHttpBinding( WSFederationHttpSecurityMode.Message );
binding.Security.Message.EstablishSecurityContext = false;
binding.Security.Message.NegotiateServiceCredential = false;
ChannelFactory<IStringService> factory = new ChannelFactory<IStringService>(
binding,
new EndpointAddress(
new Uri( ServiceAddress ),
EndpointIdentity.CreateDnsIdentity(GetServiceCertificateSubjectName()) ) );
factory.ConfigureChannelFactory<IStringService>();
factory.Credentials.SupportInteractive = false;
factory.Credentials.ServiceCertificate.DefaultCertificate = GetServiceCertificate();
IStringService channel = factory.CreateChannelWithIssuedToken<IStringService>( token );
string reversedString = channel.Reverse( "string to reverse" );