I try rewrite WCF custom binding from app.config to code.
App.config
<customBinding>
<binding name="cb">
<security defaultAlgorithmSuite="Default"
authenticationMode="IssuedTokenOverTransport"
requireDerivedKeys="true"
includeTimestamp="true"
messageSecurityVersion="WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10">
<issuedTokenParameters keyType="BearerKey"
tokenType="http://docs.oasis-open.org/ws/oasis-wss-saml-token-profile-1.1#SAMLV2.0">
<additionalRequestParameters>
<trust:SecondaryParameters xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
<trust:TokenType xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0</trust:TokenType>
<trust:KeyType xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</trust:KeyType>
</trust:SecondaryParameters>
</additionalRequestParameters>
<issuer address="xxx" />
</issuedTokenParameters>
<localClientSettings detectReplays="false" />
<localServiceSettings detectReplays="false" />
</security>
<textMessageEncoding messageVersion="Soap12" />
<httpsTransport />
</binding>
</customBinding>
Code:
var binding = new CustomBinding();
var issuedTokenParameters = new IssuedSecurityTokenParameters();
issuedTokenParameters.KeyType = SecurityKeyType.BearerKey;
issuedTokenParameters.TokenType = "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0";
XNamespace trust = "http://docs.oasis-open.org/ws-sx/ws-trust/200512";
var secondaryParameters = new XElement(trust + "SecondaryParameters",
new XElement(trust + "TokenType") { Value = "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0" },
new XElement(trust + "KeyType") { Value = "http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer" });
issuedTokenParameters.AdditionalRequestParameters.Add(secondaryParameters.ToXmlElement());
issuedTokenParameters.IssuerAddress = new EndpointAddress("XXX");
var securityElement = SecurityBindingElement.CreateIssuedTokenOverTransportBindingElement(issuedTokenParameters);
securityElement.DefaultAlgorithmSuite = SecurityAlgorithmSuite.Default;
securityElement.IncludeTimestamp = true;
securityElement.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10;
securityElement.LocalClientSettings.DetectReplays = false;
securityElement.LocalServiceSettings.DetectReplays = false;
binding.Elements.Add(securityElement);
binding.Elements.Add(new TextMessageEncodingBindingElement());
binding.Elements.Add(new HttpsTransportBindingElement());
return binding;
Code binding is not good because when I call service I get error:
System.ServiceModel.FaultException: The message with Action '' cannot be processed at the receiver, due to a ContractFilter m
ismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and r
eceiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same co
ntract and the same binding (including security requirements, e.g. Message, Transport, None).
Any advice? I can not find what is wrong or missing in code binding.
Related
I have an app.config to call this service from .Net framework but now I have to do the same from core app. Here's the WCF client config:
<bindings>
<ws2007FederationHttpBinding>
<binding name="WS2007FederationHttpBinding_certificate" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="128" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647"/>
<security mode="TransportWithMessageCredential">
<message establishSecurityContext="false" negotiateServiceCredential="true">
<claimTypeRequirements>
<add claimType="http://docs.oasis-open.org/wsfed/authorization/200706/claims/action" isOptional="true"/>
<add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier" isOptional="false"/>
<add claimType="http://schemas.microsoft.com/ws/2008/06/identity/claims/role"/>
</claimTypeRequirements>
<issuer address="https://some.url.com/STS/Issue.svc/trust/13/certificatemixed" binding="ws2007HttpBinding"
bindingConfiguration="certificateMixed"/>
<issuerMetadata address="https://some.url.com/STS/Issue.svc/mex"/>
<!-- THIS IS THE PROBLEM PART -->
<tokenRequestParameters>
<wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
<EndpointReference xmlns="http://www.w3.org/2005/08/addressing">
<Address>URN:MY.TEST.SERVICE</Address>
</EndpointReference>
</wsp:AppliesTo>
</tokenRequestParameters>
</message>
</security>
</binding>
</ws2007FederationHttpBinding>
<ws2007HttpBinding>
<binding name="certificateMixed">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="Certificate" establishSecurityContext="false"/>
</security>
</binding>
</ws2007HttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="behaviorSECertificate">
<clientCredentials>
<clientCertificate findValue="ab cd .. b4" storeLocation="LocalMachine" storeName="My"
x509FindType="FindByThumbprint"/>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
Pretty basic stuff. So now I do the same in .Net core code:
var issuerBinding = new WS2007HttpBinding(SecurityMode.TransportWithMessageCredential);
issuerBinding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
issuerBinding.Security.Message.EstablishSecurityContext = false;
issuerBinding.Name = "certificateMixed";
var prm = new WsTrustTokenParameters
{
IssuerBinding = issuerBinding,
IssuerAddress = new EndpointAddress(_seOptions.STSEndpoint),
MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10,
EstablishSecurityContext = false,
};
prm.ClaimTypes.Add(new ClaimType() { Uri = "http://docs.oasis-open.org/wsfed/authorization/200706/claims/action", IsOptional = true });
prm.ClaimTypes.Add(new ClaimType() { Uri = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier", IsOptional = false });
prm.ClaimTypes.Add(new ClaimType() { Uri = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role", IsOptional = true });
var binding = new WsFederationHttpBinding(prm);
binding.Security.Message.EstablishSecurityContext = false;
binding.Security.Message.NegotiateServiceCredential = true;
binding.Security.Mode = SecurityMode.TransportWithMessageCredential;
binding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
ChannelFactory<IMyService> factory = new ChannelFactory<IMyService>(binding, new EndpointAddress(_seOptions.MyServiceUrl));
var cert = GetClientCertificate(); //X509Certificate2
var x = factory.Endpoint.EndpointBehaviors[typeof(ClientCredentials)];
((ClientCredentials)x).ClientCertificate.Certificate = cert;
IMyService client = factory.CreateChannel(new EndpointAddress(_seOptions.MyServiceUrl));
So the main question is- how do I add the tokenRequestParameters/AppliesTo section in code? I assume it would be something like this:
RequestSecurityToken tk = new RequestSecurityToken() { AppliesTo = new EndpointAddress("URN:MY.TEST.SERVICE") };
But I have no idea what to assign this object to.
RequestSecurityToken class is not applicable to .net core, you can see its support on this page: RequestSecurityToken Class. So you need to find a replacement for it in .net core. You can refer to Overview of porting from .NET Framework to .NET Core to consider how to migrate from .net framework to .net core. Hope my answer will help you.
I have the need to add to my app.config file this section while my program is running
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="InvioTelematicoSS730pMtomPortBinding" messageEncoding="Mtom">
<security mode="Transport" />
</binding>
<binding name="RicevutaPdf730PortBinding">
<security mode="Transport" />
</binding>
<binding name="RicevutaPdf730PortBinding1" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:9080/InvioTelematicoSS730pMtomWeb/InvioTelematicoSS730pMtomPort"
binding="basicHttpBinding" bindingConfiguration="InvioTelematicoSS730pMtomPortBinding"
contract="InvioFlussi730.InvioTelematicoSS730pMtom" name="InvioTelematicoSS730pMtomPort" />
<endpoint address="https://invioSS730pTest.sanita.finanze.it/Ricevute730ServiceWeb/ricevutePdf"
binding="basicHttpBinding" bindingConfiguration="RicevutaPdf730PortBinding"
contract="ServiceReference1.RicevutaPdf730" name="RicevutaPdf730Port" />
</client>
is there any way possible? Thanks in advance
.NET exposes configuration element classes for WCF services to manage them at runtime. Wrote a simple method to construct and generate the sections for you.
private static void WriteWCFConfig()
{
//standard method from System.Configuration
Configuration appConfig = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
//the main section in the app.config file for WCF
ServiceModelSectionGroup serviceModel = ServiceModelSectionGroup.GetSectionGroup(appConfig);
var httpBindings = serviceModel.Bindings.BasicHttpBinding;
if (!httpBindings.ContainsKey("InvioTelematicoSS730pMtomPortBinding"))
{
BasicHttpBindingElement newHttpBindng = new BasicHttpBindingElement("InvioTelematicoSS730pMtomPortBinding");
newHttpBindng.MessageEncoding = WSMessageEncoding.Mtom;
newHttpBindng.Security.Mode = BasicHttpSecurityMode.Transport;
httpBindings.Bindings.Add(newHttpBindng);
}
if (!httpBindings.ContainsKey("RicevutaPdf730PortBinding"))
{
BasicHttpBindingElement newHttpBindng = new BasicHttpBindingElement("RicevutaPdf730PortBinding");
newHttpBindng.MessageEncoding = WSMessageEncoding.Mtom;
newHttpBindng.Security.Mode = BasicHttpSecurityMode.Transport;
httpBindings.Bindings.Add(newHttpBindng);
}
//the section
ChannelEndpointElementCollection endPoints = serviceModel.Client.Endpoints;
//Get endpoint names
List<string> endpointNames = new List<string>();
foreach (ChannelEndpointElement endpointElement in endPoints)
{
endpointNames.Add(endpointElement.Name);
}
if (!endpointNames.Contains("InvioTelematicoSS730pMtomPort"))
{
ChannelEndpointElement endPoint = new ChannelEndpointElement(new EndpointAddress("http://localhost:9080/InvioTelematicoSS730pMtomWeb/InvioTelematicoSS730pMtomPort"), "InvioFlussi730.InvioTelematicoSS730pMtom");
endPoint.Name = "InvioTelematicoSS730pMtomPort";
endPoint.Binding = "basicHttpBinding";
endPoint.BindingConfiguration = "InvioTelematicoSS730pMtomPortBinding";
endPoints.Add(endPoint);
}
if (!endpointNames.Contains("RicevutaPdf730Port"))
{
ChannelEndpointElement endPoint = new ChannelEndpointElement(new EndpointAddress("https://invioSS730pTest.sanita.finanze.it/Ricevute730ServiceWeb/ricevutePdf"), "ServiceReference1.RicevutaPdf730");
endPoint.Name = "RicevutaPdf730Port";
endPoint.Binding = "basicHttpBinding";
endPoint.BindingConfiguration = "RicevutaPdf730PortBinding";
endPoints.Add(endPoint);
}
appConfig.Save();
}
You can take it and modify it according to your needs.
Hope this helps.
I received an updated WSDL for a service I'm consuming which has below Policy added
<wsp:Policy wssutil:Id="UsernameToken">
<ns0:SupportingTokens xmlns:ns0="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200512">
<wsp:Policy>
<ns0:UsernameToken ns0:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200512/IncludeToken/AlwaysToRecipient">
<wsp:Policy>
<ns0:WssUsernameToken10 />
</wsp:Policy>
</ns0:UsernameToken>
</wsp:Policy>
</ns0:SupportingTokens>
</wsp:Policy>
I have updated my reference by right clicking the Service Reference --> Configure Service option inside Visual Studio. This generated a customBinding replacing my previous basicHttpBinding
<customBinding>
<binding name="myBindingName">
<!-- WsdlImporter encountered unrecognized policy assertions in ServiceDescription 'http://ouaf.oracle.com/webservices/cm/CM-CustConnAcctDetailExtract': -->
<!-- <wsdl:binding name='CM-CustConnAcctDetailExtractSoapBinding'> -->
<!-- <ns0:SupportingTokens xmlns:ns0="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200512">..</ns0:SupportingTokens> -->
<textMessageEncoding messageVersion="Soap11" />
<httpTransport />
</binding>
</customBinding>
Do I need to use this customBinding only? Or is there any option in basicBinding that makes it work?
If I use my basicBinding with TransportWithMessageCredential, I get below error:
The provided URI is Invalid; HTTPS is expected
I ran this using SoapUI. In addition to UserName and Passwrod, I had to supply WSS-PasswordType as PasswordText. Without supplying this parameter, I get an error in SoapUI
Error on verifying message against security policy Error code:1000
I'm not sure how to supply WSS-PasswordType in my basicHttpBinding.
My basicHttpBinding is as below
protected BasicHttpBinding GetBinding()
{
return new BasicHttpBinding()
{
Name = "BasicHttpBinding",
ReceiveTimeout = new TimeSpan(0, 0, 2, 0),
SendTimeout = new TimeSpan(0, 0, 2, 0),
Security =
{
Mode = BasicHttpSecurityMode.TransportCredentialOnly,
Transport =
{
ClientCredentialType = HttpClientCredentialType.Basic,
ProxyCredentialType = HttpProxyCredentialType.None,
Realm = ""
},
Message =
{
ClientCredentialType = BasicHttpMessageCredentialType.UserName,
AlgorithmSuite = SecurityAlgorithmSuite.Default
}
},
MaxBufferSize = Int32.MaxValue,
MaxReceivedMessageSize = Int32.MaxValue,
ReaderQuotas = new XmlDictionaryReaderQuotas()
{
MaxBytesPerRead = 8192
}
};
}
I'm able to work this through by changing my binding to Custom Binding
protected CustomBinding GetCustomBinding()
{
var customBinding = new CustomBinding() { Name = "CustomBinding" };
customBinding.Elements.Add(new TextMessageEncodingBindingElement() { MessageVersion = MessageVersion.Soap11 });
var securityBindingElement = SecurityBindingElement.CreateUserNameOverTransportBindingElement();
securityBindingElement.AllowInsecureTransport = true;
securityBindingElement.EnableUnsecuredResponse = true;
securityBindingElement.IncludeTimestamp = false;
customBinding.Elements.Add(securityBindingElement);
customBinding.Elements.Add(new HttpTransportBindingElement());
return customBinding;
}
I have a WCF service reference which I use with the following client side app.config:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_ManagerService">
<security>
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://myadress:8080/ManagerService.svc"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ManagerService"
contract="Service.ManagerService" name="WSHttpBinding_ManagerService">
<identity>
<certificate encodedValue="AwAAAAEAAAAUAAAAaJ8gJ+2BbDC//Nw76gp1Rx4Ii1AgAAAAAQAAACQDAAAwggMgMIICDKADAgECAhB4jlXUsVcUkE45Bq9sj6cdMAkGBSsOAwIdBQAwIzEhMB8GA1UEAxMYc2tpbGxjb25vbXkuY2xvdWRhcHAubmV0MB4XDTA2MTIzMTIyMDAwMFoXDTE5MTIzMTIyMDAwMFowIzEhMB8GA1UEAxMYc2tpbkjsahdjhdjsdhsjhdsjhdjhdsjhdFAAOCAQ8AMIIBCgKCAQEAwHjDPi/A7+4PfvYt40eySE2I6FgVO2Ewco8gJO21TUqHpKbinmsaNTO6wFJy+l3adMRB0dcmAvH938BPgdwbqbVaaG4mRCDpnekEserWmz5ii+ET1xhm0atIg6xW3sgnDOA+41Y0vB8m8AXTfHQYunILQjn/6xGM/RffK32vbR9WGJKEd/okOJ2/vV5dm2UsejlANwK2kCMe9wNRbjaKsH6PIqv26KeHAXxa0tSzoHfrn/lr46+54WzEXFHRzub1JbZk+IsdsdlakasjdksjdjdksjddjskdZZ0Oj0iG0GjvEVbmHWpBM/WhHrqIfGdqiMtXjOtwIDAQAsdsdsdsdsdsdsdaZtgIq+y6hm91EfPUToJ1ZUhWR8z/RG+IVZrs0O93FCMk6WU8OhYxubIgcVSTx0FDCakyOmfu1gnYeEZv53kVPZSmY4KUAUZz+MCQf/OXN2OGv9cRmsWg4iDlHjzDQwucO+rWkclvQo=" />
</identity>
</endpoint>
</client>
</system.serviceModel>
I now need to refactor the instantiation to work with a blank app.config:
Here is what I've tried:
var binding = new WSHttpBinding();
binding.Security = new WSHttpSecurity { Mode = SecurityMode.Message };
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
var store = new X509Store(StoreName.CertificateAuthority, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
var cers = store.Certificates.Find(X509FindType.FindByThumbprint, "123THUMBPRINTOFCERT", false);
var cer = cers[0];
var identity = new X509CertificateEndpointIdentity(cer);
var endpoint = new EndpointAddress(new Uri("http://myservice:8080/ManagerService.svc"), identity);
var client = new ManagerServiceClient(binding, endpoint);
client.ClientCredentials.UserName.UserName = EMail;
client.ClientCredentials.UserName.Password = Password;
var resultBuilder = new StringBuilder();
var categories = client.Categorize(Text);
This throws an exception:
System.ServiceModel.Security.MessageSecurityException: Client cannot
determine the Service Principal Name based on the identity in the
target address 'http://myservice:8080/ManagerService.svc' for
the purpose of SspiNegotiation/Kerberos. The target address identity
must be a UPN identity (like acmedomain\alice) or SPN identity (like
host/bobs-machine).
I have checked, that the correct certificate is found in the store. I would be very glad to get a hint on what I am missing here and whether the way I'm going here is ok in general...?
you lost row clientCredentialType="UserName"
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
I have a Binding that is configured as such in my .clientconfig file.
<customBinding>
<binding name="CustomBinding_MyService">
<binaryMessageEncoding />
<httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" />
</binding>
</customBinding>
I need to build this same binding programmatically (its a long story, I just do). My question is, how do I do this in C#? Currently, I have
CustomBinding binding = new CustomBinding();
However, I'm not sure where to go from there. Thanks!
It'll look something like this:
var customBinding = new CustomBinding(
new BinaryMessageEncodingBindingElement(),
new HttpTransportBindingElement()
{
MaxReceivedMessageSize = 2147483647,
MaxBufferSize = 2147483647
}
);
var endpoint = new EndpointAddress("http://www.myservice.com/myservice.svc");
var myServiceClient = new MyServiceClient(customBinding, endpoint);
myServiceClient.SayHelloAsync(); // Or whatever
hopefully this helps: Runtime data binding