Adding authentication to security header in WCF to consume Metro WSIT service - wcf

I use this simple way to attach username and password to the SOAP request header. This works fine inside Java boundaries, but I want to be able to call it with my WCF client. How do I do this?
I've tried the following code, but it does not include the credentials in the header:
wsClient.ClientCredentials.UserName.UserName = "Hello";
wsClient.ClientCredentials.UserName.Password = "World";
Thanks in advance!

That is quite awful non-standardized way. It uses custom HTTP Headers so you cannot expect that built in WCF mechanism will magically support such approach. How should WCF know that you want to add custom non-standard HTTP header to HTTP request (not SOAP header)?
Use this:
var proxy = new YourServiceClient();
using (var scope = new OperationContextScope(proxy.InnerChannel))
{
var prop = new HttpRequestMessageProperty();
prop.Headers.Add("UserName", "Hello");
prop.Headers.Add("Password", "World");
OperationContext context = OperationContext.Current;
context.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = prop;
proxy.CallYourOperation();
}

Related

NetCore 3.1 PostAsync CustomHeaders not working

I have several RESTful services that working with each other. In one scenario I want to post some data from one service to another service and I want to attach some information in Header of the request. I saw several cases to do this and in the end I came up with this workaround:
var httpClient = new HttpClient();
httpClient.Timeout = TimeSpan.FromMinutes(3);
var httpRequestMessage = new HttpRequestMessage {
Method = HttpMethod.Post,
RequestUri = new Uri(service2Address),
Content = new StringContent(JsonConvert.SerializeObject(obj))
};
httpRequestMessage.Headers.Add("myCustomHeaderKey", "myCustomHeaderValue");
var response = await httpClient.SendAsync(httpRequestMessage);
var responseString = await response.Content.ReadAsStringAsync();
With these lines of code, a Post request sent, but in service2 when I want to get the headers from request, there is no sign of myCustomHeaderKey in headers collection. I inspect Request.Headers in Visual Studio Watch and even try to get custom header with Request.Headers["myCustomHeaderKey"]. So what's wrong here?
EDIT 1
This implementation in based on this tutorial.
I have developed code like yours. Have created Two Asp.net core 3.1 project with standart template. One service is starting localhost:44320 and other localhost:44300
localhost:44320/PostService wrote the your codes.
Then get this url with browser. localhost:44320/weatherforecast/IncomeService function is like below
Finally i put breakpoint to where get request header. Result is like below
There is a not a problem. Maybe you use change request header middleware. Or if you are using something like nginx. this problem maybe nginx configuration.

ASP.NET Core making SOAP API request with WCF client how to add a Cookie header to the request?

So I am currently working on making SOAP API request to a service with WCF generated code "Client object", I am wondering how to set the Cookie header to the request?
In general, we add the custom HTTP header by using HttpRequestMessageProperty. Please refer to the below code.
ServiceReference1.ServiceClient client = new ServiceReference1.ServiceClient();
try
{
using (OperationContextScope ocs=new OperationContextScope(client.InnerChannel))
{
var requestProp = new HttpRequestMessageProperty();
requestProp.Headers["myhttpheader"] = "Boom";
OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestProp;
var result = client.SayHelloAsync();
Console.WriteLine(result.Result);
}
Result.
WebOperationContext is a convenience wrapper around the OperationContext. At present, it hasn’t been implemented yet in the Aspnet Core.
https://github.com/dotnet/wcf/issues/2686
Feel free to let me know if there is anything I can help with.

How can I add my own action that I can give access in the SharePoint Portal to my API to allow

I have an API that I have deployed to Azure.
This API has a number of Actions. I would like to be able to add these Actions to my API and configure them in a client app that uses the API
Could anybody provide some guidance on this please?
What do you mean here. You have an API and want to configure them in a client app? Do you you mean you want to call the API in your Client App?
In this case, assuming your API is REST, you can use HttpClient and use the PostAsyc(), PutAsync(), DeleteAsync, GetAsync() methods with the url and httpcontent you API requires to sent.
var httpClient = new HttpClient
{
BaseAddress = new Uri("...")
};
var response = await httpClient.GetAsync($"api/....");
if (response.IsSuccessStatusCode)
{
...
]
Sander

.net WCF - CXF/WSS4j interoperability

I would like to consume a CXF web-service from a .net c# client. We are currently working with java-to-java requests and we protect SOAP envelopes through ws-security (WSS4J library).
My question is: how can I implement a C# WS-client which produces the same SOAP requests as the following client-side java code?
//doc is the original SOAP envelope to process with WSS4J
WSSecHeader secHeader = new WSSecHeader();
secHeader.insertSecurityHeader(doc);
//add username token with password digest
WSSecUsernameToken usrNameTok = new WSSecUsernameToken();
usrNameTok.setPasswordType(WSConstants.PASSWORD_DIGEST);
usrNameTok.setUserInfo("guest",psw_guest);
usrNameTok.prepare(doc);
usrNameTok.appendToHeader(secHeader);
//sign the envelope body with client key
WSSecSignature sign = new WSSecSignature();
sign.setUserInfo("clientx509v1", psw_clientx509v1);
sign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
Document signedDoc = null;
sign.prepare(doc, sigCrypto, secHeader);
signedDoc = sign.build(doc, sigCrypto, secHeader);
//encrypt envelope body with server public key
WSSecEncrypt encrypt = new WSSecEncrypt();
encrypt.setUserInfo("serverx509v1");
// build the encrypted SOAP part
String out = null;
Document encryptedDoc = encrypt.build(signedDoc, encCrypto, secHeader);
return encryptedDoc;
Does anybody know where I could find a microsoft how-to or a .net working example?
================================ EDIT ====================================
Thank you Ladislav! I applied your suggestions and I came up with something like:
X509Certificate2 client_pk, server_cert;
client_pk = new X509Certificate2(#"C:\x509\clientKey.pem", "blablabla");
server_cert = new X509Certificate2(#"C:\x509\server-cert.pfx", "blablabla");
// Create the binding.
System.ServiceModel.WSHttpBinding myBinding = new WSHttpBinding();
myBinding.TextEncoding = ASCIIEncoding.UTF8;
myBinding.MessageEncoding = WSMessageEncoding.Text;
myBinding.Security.Mode = SecurityMode.Message;
myBinding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
myBinding.Security.Message.AlgorithmSuite =
System.ServiceModel.Security.SecurityAlgorithmSuite.Basic128;
// Disable credential negotiation and the establishment of
// a security context.
myBinding.Security.Message.NegotiateServiceCredential = false;
myBinding.Security.Message.EstablishSecurityContext = false;
// Create the endpoint address.
EndpointAddress ea =
new EndpointAddress(new Uri("http://bla.bla.bla"),
EndpointIdentity.CreateDnsIdentity("issuer"));
// configure the username credentials on the channel factory
UsernameClientCredentials credentials = new UsernameClientCredentials(new
UsernameInfo("superadmin", "secret"));
// Create the client.
PersistenceClient client = new PersistenceClient(myBinding, ea);
client.Endpoint.Contract.ProtectionLevel =
System.Net.Security.ProtectionLevel.EncryptAndSign;
// replace ClientCredentials with UsernameClientCredentials
client.Endpoint.Behaviors.Remove(typeof(ClientCredentials));
client.Endpoint.Behaviors.Add(credentials);
// Specify a certificate to use for authenticating the client.
client.ClientCredentials.ClientCertificate.Certificate = client_pk;
// Specify a default certificate for the service.
client.ClientCredentials.ServiceCertificate.DefaultCertificate = server_cert;
// Begin using the client.
client.Open();
clientProxyNetwork[] response = client.GetAllNetwork();
As a result I get (server-side) the following CXF exception:
java.security.SignatureException: Signature does not match.
at sun.security.x509.X509CertImpl.verify(X509CertImpl.java:421)
at sun.security.provider.certpath.BasicChecker.verifySignature(BasicChecker.java:133)
at sun.security.provider.certpath.BasicChecker.check(BasicChecker.java:112)
at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate (PKIXMasterCertPathValidator.java:117)
Therefore it seems a key jks->pem conversion problem... Or am I am missing something in the client-code above?
Well, in the end the solution is to encrypt and sign the whole username token. As for the interoperability, the ws addressing must be activated in cxf and a custom binding in c# is needed. The custom binding that did the trick is basically
AsymmetricSecurityBindingElement abe =
(AsymmetricSecurityBindingElement)SecurityBindingElement.
CreateMutualCertificateBindingElement(MessageSecurityVersion.
WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10);
           
Wcf signs each ws addressing element, therefore the same must be done server side.
This is usually pretty big problem because WCF does not support UserNameToken Profile with Digested password. I needed it few months ago and we had to implement our own custom binding but that code is not ready for publishing. Fortunatelly this blog article describes other implementation and contains sample code with new UserNameClientCredentials class supporting digested password.
Btw. same security configuration should be possible with older API called WSE 3.0. It was replaced by WCF but still some WS-* stack configuration are much simpler with that API and old ASMX services.

HttpListner: intercept requests to WCF DataService

I want to use the .net class HttpListener to intercept requests to my selfhosted (WebServiceHost) WCF Data Service in order to add the "WWW-Authenticate" header to the response (for user authentication). But it seems like that the HttpListener doesn't intercept any requests that go to my dataservice. The HttpListner works for different paths just fine. Example: HttpListner Prefix: http://localhost/somePath/Works: http://localhost/somePath/Doesn't Work: http://localhost/somePath/myWCFDataService
Is it possible to intercept also requests that go to a selfhosted WCF Data Service (WebServiceHost) with the HttpListner?
Here are the relevant code snippets...
Hosting the WCF DataService:
WebServiceHost dataServiceHost = new WebServiceHost(typeof(MyWCFDataService));
WebHttpBinding binding = new WebHttpBinding();
dataServiceHost.AddServiceEndpoint(typeof(IRequestHandler), binding,
"http://localhost/somePath/myWCFDataService");
dataServiceHost.Open();
The HTTP Listner:
HttpListener httpListener = new HttpListener();
httpListener.Prefixes.Add("http://localhost/somePath/");
httpListener.AuthenticationSchemes = AuthenticationSchemes.Anonymous;
httpListener.Start();
while (true)
{
HttpListenerContext context = httpListener.GetContext();
string authorization = context.Request.Headers["Authorization"];
if (string.IsNullOrEmpty(authorization))
{
context.Response.StatusCode = 401;
context.Response.AddHeader("WWW-Authenticate", "Basic realm=\"myDataService\"");
context.Response.OutputStream.Close();
context.Response.Close();
}
}
Is there a better way for doing HTTP basic authentication within WCF Data Services? I wan't to be able to authenticate via the login dialog of the web browser.
Many thanks,
JeHo
You're barking up the wrong tree messing with proxying via HttpListener. Have a look at this.