How do I change my wcf service to be able to accept mustunderstand = 1?
This is a scenario where I have to change the service to be able to accept a request from the client. The client sends mustunderstand =1 in the header.
The service is configured to use basichttpBinding
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
<transport clientCredentialType="None"></transport>
</security>
Using soap UI I insert the following username token into the header
<wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-2684C13EA73A35131015516775308851">
<wsse:Username>username</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">password</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
I can reproduce the issue on soap UI when I insert this token in the wcf service request. This is the error
<FaultMsgRec>
<ErrCode>100</ErrCode>
<ErrCat>Error</ErrCat>
<ErrDesc>An unsecured or incorrectly secured fault was received from the other party. See the inner FaultException for the fault code and detail.--> The header 'Security' from the namespace 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' was not understood by the recipient of this message, causing the message to not be processed. This error typically indicates that the sender of this message has enabled a communication protocol that the receiver cannot process. Please ensure that the configuration of the client's binding is consistent with the service's binding. </ErrDesc>
</FaultMsgRec>
Since I have control over the wcf service I can go and add ValidateMustUnderstand = false in the service behavior.
Just like it is explained in the link
https://learn.microsoft.com/en-us/dotnet/api/system.servicemodel.description.mustunderstandbehavior.validatemustunderstand?view=netframework-4.7.2
Once I add this to the service behavior the error disappears.
But I don't want to turn off validation on the header especially if its a username, password. What should I do to allow mustunderstand=1? Am I missing something that the service doesn't automatically process mustunderstand=1 by default. I know there is code to be written on the client in order to sent a 0 in the header.
I am using message contracts in my wcf service not data contract. I understand that for certain properties I can go and add attributes like this link
https://learn.microsoft.com/en-us/dotnet/api/system.servicemodel.messageheaderattribute.mustunderstand?view=netframework-4.7.2. But I am not adding to any properties. I am just adding it to the first linke in soapenv:mustunderstand=1
Please help!.
Thank you
Not sure whether this could solve your problem. But you could try to add your header in web.config.
<endpoint address="http://ws-wuxipc-5077:4000/calculator" binding="basicHttpBinding"
contract="ServiceInterface.ICalculatorService" name="cal">
<headers>
<Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" >
<wsse:UsernameToken xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Username>
</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">monMonDePasse</wsse:Password>
<wsse:Nonce>sdsdsdlojhfdsdM5Nw==</wsse:Nonce>
<wsu:Created>2019-01-21T6:17:34Z</wsu:Created>
</wsse:UsernameToken>
</Security>
</headers>
</endpoint>
Or you could add header using code.
using (ChannelFactory<ICalculatorService> ChannelFactory = new ChannelFactory<ICalculatorService>("cal"))
{
ICalculatorService employeeService = ChannelFactory.CreateChannel();
using (OperationContextScope scope = new OperationContextScope((IContextChannel)employeeService))
{
System.Xml.XmlDocument document = new XmlDocument();
XmlElement element = document.CreateElement("wsse", "UsernameToken", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
XmlElement newChild = null;
newChild = document.CreateElement("wsse", "Username", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
newChild.InnerText = "finance";
element.AppendChild(newChild);
newChild = document.CreateElement("wsse", "password", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
newChild.SetAttribute("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest");
newChild.InnerText = "387";
element.AppendChild(newChild);
MessageHeader messageHeader = MessageHeader.CreateHeader("security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", element, false); // here is mustunderstood is set to false
OperationContext.Current.OutgoingMessageHeaders.Add(messageHeader);
}
Console.Read();
}
Related
I am trying to call SOAP1.2 service using wsHttpBinding. The service accepts rejects the default Soap12WSAddressing10 message version. It only accepts SOAP12.
One suggestion I could get from the Internet search was to create the TextMessageEncodingElement in a custom binding.
How can it be either be accomplished using code or configuration ?
WSHttpBinding myBinding = new WSHttpBinding();
myBinding.Security.Mode = SecurityMode.Transport;
myBinding.Security.Transport.ClientCredentialType =
HttpClientCredentialType.Certificate;
//MessageVersion = SOAP12
On using the custom wsBinding as well, there is no suggested placeholder to specify the message version.
<wsHttpBinding>
<binding name="customWS">
<security mode="Transport">
<message clientCredentialType="Certificate"></message>
</security>
</binding>
</wsHttpBinding>
Soap12 specify the soapaction by content-type header. I think it is not implemented in net core. I use the following code.
var encoding = new TextMessageEncodingBindingElement(MessageVersion.CreateVersion(EnvelopeVersion.Soap12, AddressingVersion.None), Encoding.UTF8);
But this is not implemented in net core.
I've made an STS by overriding SecurityTokenService and hosted it using WCF. Also I've created a relying party and test client. Client is successfully redirected to the STS (the program stops if I put a breakpoint in GetOutputIdentity method). Now I need to deny acces in my RP for all users except one role. How can I do it? Her is my configuraion:
protected override ClaimsIdentity GetOutputClaimsIdentity(ClaimsPrincipal principal,
RequestSecurityToken request,
Scope scope)
{
string authenticationType = principal.Identity.AuthenticationType;
var outputIdentity = new ClaimsIdentity(authenticationType);
outputIdentity.AddClaim(new Claim(ClaimTypes.Role, role));
outputIdentity.AddClaim(new Claim(ClaimTypes.Name, userName));
return outputIdentity;
}
Relying party configuration:
<customBinding>
<binding name="secureBinding">
<security authenticationMode="IssuedToken" requireDerivedKeys="false" >
<issuedTokenParameters>
<issuer address="http://localhost:1318/Services/SecurityTokenService.svc">
</issuer>
<issuerMetadata address="http://localhost:1318/Services/SecurityTokenService.svc/mex"></issuerMetadata>
</issuedTokenParameters>
</security>
<httpTransport></httpTransport>
</binding>
</customBinding>
You can use custom AuthorizationManager to validate each call of RP. This class provide CheckAccess method that implement you custom validation according to incoming claims.
This question is a sort of follow up to this one: How to create a .NET client for a wso2 Secure Token Service
Briefly, I am trying to implement a client for a web service in a federated security scenario. My client should invoke a method of a given web service authenticating itself with a security token provided by another web service (both services are implemented with wso2 platform).
As I stated in the answer to the above question, with the proper binding configuration, the client is able to receive the requested token. The following is my binding configuration:
<wsFederationHttpBinding>
<binding name="fs">
<security mode="TransportWithMessageCredential">
<message issuedKeyType="SymmetricKey" issuedTokenType ="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0">
<issuer address =<!-- STS URL HERE--> binding ="customBinding" bindingConfiguration ="StsBinding"/>
<claimTypeRequirements>
<add claimType="http://wso2.org/claims/userid" />
</claimTypeRequirements>
</message>
</security>
</binding>
</wsFederationHttpBinding>
...
<customBinding>
<binding name="StsBinding">
<textMessageEncoding messageVersion="Soap12WSAddressing10"/>
<useManagedPresentation/>
<security authenticationMode="UserNameOverTransport" includeTimestamp ="true" keyEntropyMode ="ServerEntropy" securityHeaderLayout ="Lax"
messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10" >
</security>
<httpsTransport authenticationScheme ="Basic"/>
</binding>
</customBinding>
However, when my client process the recieved token it fails with a SecurityNegotiationException stating that the "urn:IssueTokenResponse" action is wrong. What does this exception means? What should be the correct action?
I don't have access to any details of both services so I need to know if I can do something on client side only.
I have tried to follow the advice contained in this forum post https://social.msdn.microsoft.com/Forums/vstudio/en-US/6c838f7e-f72f-4fdd-827d-b29c61522aa0/wrong-action-httpdocsoasisopenorgwssxwstrust200512rstrissue?forum=wcf but I don't think it applies to my case because there isn't a single messageSecurityVersion value which seems to work
I finally find a working solution, at least for the "wrong action" error.
Digging through the WCF documentation I found a reference document describing how to set-up a Security Token Service (MSDN address here)
The most intresting part of the document is this small phrase that seems to indicate the expected action for a response sent by a STS:
In addition, it defines the associated Action Uniform Resource
Identifiers (URIs). The action URI associated with the
RequestSecurityToken message is
http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue. The action URI
associated with the RequestSecurityTokenResponse message is
http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Issue.
After some more research on the extensbility mechanism provided by the WCF framework I found a promising reference about IClientMessageInspector that allows to customize client behavior when sending requests or when receiving replies.
The following is the simple code of the behavior:
Public Class ChangeReplyActionMessageInspector
Implements IClientMessageInspector
Public Sub AfterReceiveReply(ByRef reply As Message, correlationState As Object) Implements IClientMessageInspector.AfterReceiveReply
If reply.Headers.Action = "urn:IssueTokenResponse" Then
reply.Headers.Action = "http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Issue"
End If
End Sub
Public Function BeforeSendRequest(ByRef request As Message, channel As ServiceModel.IClientChannel) As Object Implements IClientMessageInspector.BeforeSendRequest
Return Nothing
End Function
End Class
To attach this custom behavior to the client object responsible to talk to the Security Token Service I need a IEndpointBehavior like this one:
Public Class ChangeReplyActionEndpointBehavior
Implements IEndpointBehavior
Public Sub AddBindingParameters(endpoint As ServiceEndpoint, bindingParameters As BindingParameterCollection) Implements IEndpointBehavior.AddBindingParameters
End Sub
Public Sub ApplyClientBehavior(endpoint As ServiceEndpoint, clientRuntime As ClientRuntime) Implements IEndpointBehavior.ApplyClientBehavior
clientRuntime.ClientMessageInspectors.Add(New ChangeReplyActionMessageInspector)
End Sub
Public Sub ApplyDispatchBehavior(endpoint As ServiceEndpoint, endpointDispatcher As EndpointDispatcher) Implements IEndpointBehavior.ApplyDispatchBehavior
End Sub
Public Sub Validate(endpoint As ServiceEndpoint) Implements IEndpointBehavior.Validate
End Sub
End Class
That it is programmatically attached to the client with the following code:
Dim endpointBehaviorCollection As New System.Collections.Generic.KeyedByTypeCollection(Of IEndpointBehavior)
endpointBehaviorCollection.Add(New ChangeReplyActionEndpointBehavior)
client.ClientCredentials.IssuedToken.IssuerChannelBehaviors.Add(New Uri("STS URL HERE"), endpointBehaviorCollection)
In this way the issued security token is sent back to the target service with the final request. I am still getting errors for the final request that however needs further investigation.
We have JAX-WS web service like this:
public class NamedDataHandlerContainer {
public String options; // format is option1_name=option1_value;option2_name=option2_value
#XmlMimeType("application/octet-stream") public DataHandler dataHandler;
}
#WebService
public interface mtomserver {
#WebMethod public int saveFile(String name,
#XmlMimeType("application/octet-stream") List<NamedDataHandlerContainer> contents,
#XmlMimeType("application/octet-stream") #WebParam(mode = WebParam.Mode.OUT) Holder<List<NamedDataHandlerContainer>> results);
}
When WSDL for that web service is processed with SvcUtil of .NET 4.0, it generates byte[] type for NamedDataHandlerContainer.dataHandler:
public partial class namedDataHandlerContainer;
{
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 0)]
public string options;
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, DataType = "base64Binary", Order = 1)]
public byte[] dataHandler;
}
However, in App.config it generates Mtom artifacts:
<basicHttpBinding>
<binding name="mtomserverImplPortBinding" messageEncoding="Mtom" maxReceivedMessageSize="1000000000" />
</basicHttpBinding>
(maxReceivedMessageSize is added by us to allow large attacghments). In fact WCF client sends MTOM attachment to the service - we are dumping HTTP payloads and confirm that:
--uuid:394d798b-e43e-47cc-82dd-64e32ef51edd+id=1
Content-ID: <http://tempuri.org/0>
Content-Transfer-Encoding: 8bit
Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><saveFile xmlns="http://wsserver.mtomtest/"><arg0 xmlns="">myfile.bin</arg0><arg1 xmlns=""><options>my options from .NET</options><dataHandler><xop:Include href="cid:http://tempuri.org/1/634993057692269386" xmlns:xop="http://www.w3.org/2004/08/xop/include"/></dataHandler></arg1></saveFile></s:Body></s:Envelope>
--uuid:394d798b-e43e-47cc-82dd-64e32ef51edd+id=1
Content-ID: <http://tempuri.org/1/634993057692269386>
Content-Transfer-Encoding: binary
Content-Type: application/octet-stream
<binary content goes here>
JAX-WS can successfully apply streaming to such payload. However, is there a way to implement streaming on .NET side? I have read MSDN where it is explicitly said that only one parameter with streaming enabled may exist. However, is there a way to have custom message serializer (or something custom, I'm not an expert in WCF) and still avoid loading entire payload into memory.
WCF has a configuration to enable streaming. You don't need to write any additional code to achieve this.
<basicHttpBinding>
<binding name="mtomserverImplPortBinding" messageEncoding="Mtom" maxReceivedMessageSize="1000000000" transferMode="Streamed"/>
</basicHttpBinding>
Source: http://msdn.microsoft.com/en-us/library/ms789010.aspx
We're developing a Silverlight Client onto a server-based API exposed via WCF.
I'm trying to move my WCF client code (which works fine) from a configuration-based model to a programmatic model. This will enable me to have a single "root" URL which I can apply at start-up and not require installations to have to maintain humongous configuration files.
I'm stuggling converting my configurations to Silverlight-capable code, though.
Where I have the configuration below for one of my services:
<configuration>
<system.serviceModel>
<bindings>
<customBinding>
<binding name="CustomBinding_ISilverlightHelper">
<binaryMessageEncoding />
<httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647">
<extendedProtectionPolicy policyEnforcement="Never" />
</httpTransport>
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="http://localhost:50072/API/WCF/Silverlight/SilverlightHelper.svc"
binding="customBinding" bindingConfiguration="CustomBinding_ISilverlightHelper"
contract="API.WCF.Silverlight.ISilverlightHelper" name="CustomBinding_ISilverlightHelper" />
</client>
</system.serviceModel>
</configuration>
I can't figure out how to create the equivelant client-config code. At the moment I have:
CustomBinding customBinding = new CustomBinding();
// I see I need to do something with customBinding but the properties don't seem
// logical
// I have used BasicHttpBinding, but it just returns with "Not Found" (the service does resolve to a valid URL)
BasicHttpBinding basicHttpBinding = new BasicHttpBinding() { MaxBufferSize = int.MaxValue, MaxReceivedMessageSize = int.MaxValue };
EndpointAddress endpointAddress = new EndpointAddress("http://localhost:50072/API/WCF/Silverlight/SilverlightHelper.svc");
ISilverlightHelper silverlightHelper= new ChannelFactory<ISilverlightHelper>(basicHttpBinding, endpointAddress).CreateChannel();
AsyncCallback asyncCallback = delegate(IAsyncResult result)
{
ISilverlightHelper asyncSilverlightHelper = (ISilverlightHelper)result.AsyncState;
string[] files=asyncSilverlightHelper.EndGetPlugInXapNames(result).ToArray();
};
silverlightHelper.BeginGetPlugInXapNames(asyncCallback, silverlightHelper);
Any clues would be appreciated. I've spent all morning Googling/Binging/Overflowing but haven't come across this scenario. Or I might be just so far wrong ...
Sorted it.
I created the BinaryMessageEncodingBindingElement and HttpTransportBindingElements, added them to the CustomBinding and it all works.
Here's my annotated code:
// create the binding elements
BinaryMessageEncodingBindingElement binaryMessageEncoding = new BinaryMessageEncodingBindingElement();
HttpTransportBindingElement httpTransport = new HttpTransportBindingElement() { MaxBufferSize = int.MaxValue, MaxReceivedMessageSize = int.MaxValue };
// add the binding elements into a Custom Binding
CustomBinding customBinding = new CustomBinding(binaryMessageEncoding,httpTransport);
// create the Endpoint URL (I'll use a configured URL later - all web services will then move as one)
EndpointAddress endpointAddress = new EndpointAddress("http://localhost:50072/API/WCF/Silverlight/SilverlightHelper.svc");
// create an interface for the WCF service
ISilverlightHelper silverlightHelper= new ChannelFactory<ISilverlightHelper>(customBinding, endpointAddress).CreateChannel();
// set-up the asynchronous callback
AsyncCallback asyncCallback = delegate(IAsyncResult result)
{
ISilverlightHelper asyncSilverlightHelper = (ISilverlightHelper)result.AsyncState;
string[] files=asyncSilverlightHelper.EndGetPlugInXapNames(result).ToArray();
};
// execute the call
silverlightHelper.BeginGetPlugInXapNames(asyncCallback, silverlightHelper);