WCF UserNamePasswordValidator - Access credentials after validation - c#

I am using the UserNamePasswordValidator class as part of the UserName security with WCF. This all works great and the Validate function of the class gets called and works properly.
How then can I find out what UserName was used in my service functions?
For example say if a client connects and requests a list of logs using something like
IList<Log> Logs() { ... }
How can that function know which UserName was used on that request?
What I want to do is log what UserName calls what function within the service.

Not sure, but you may be looking for
var userName = OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name;

I believe there is something in the operation context. Try this:
OperationContext oc = OperationContext.Current;
ServiceSecurityContext ssc = oc.ServiceSecurityContext;
string client = ssc.PrimaryIdentity.Name;

Related

Revalidate Credentials on WCF UserNamePasswordValidator on each call

I am using a custom Username/Password Validator on WCF over NetTcp, to authenticate clients connecting to my WCF Service. What I noticed, is that once a client gets authenticated, never gets validated again, meaning that if I want to revoke access from a client, I would need to manually force him to disconnect.
My serviceHost configuration looks like this:
_serviceHost.Description.Behaviors.Add(credentialsBehavior);
_serviceHost.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
_serviceHost.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = _userValidator;
_serviceHost.Credentials.ClientCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
_serviceHost.Credentials.ServiceCertificate.SetCertificate(AppSettingsManager.I.CertificateStoreLocation, AppSettingsManager.I.CertificateStoreName, AppSettingsManager.I.CertificateFindBy, AppSettingsManager.I.CertificateFindValue);
and my clients connect using ChannelFactory:
var client = new DuplexChannelFactory<T>(new InstanceContext(this), binding, endpointAddress);
client.Credentials.UserName.UserName = ConnectionProperties.Authentication.Credentials.Username;
client.Credentials.UserName.Password = ConnectionProperties.Authentication.Credentials.Password;
client.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = AppSettingsManager.I.CertificateValidationMode;
client.CreateChannel();
Is there a way to have the client credentials validated on every call, or periodically?
Generally speaking, after invocation, the server will automatically close the connection, it depends on the following parameter of the binding.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/configuring-timeout-values-on-a-binding
Of course, we can also close it manually on the client.
client.Close()
In addition, I could not get your point. the session is continual, and you have set up the credential in the code snippets before calling the service. What do you mean that Never Gets Validate again?
In my opinion, if you want to revoke access from a client, you could change the validation logic on the server side.

SignalR - authenticate windows forms user on windows forms server

I have a small project which contains a windows forms signalr client and a windows forms server. Clients can connect to server. Now, I want to implement a login system. I read some blogposts, articles and questions about this, but I didn't found a way to do it. I would like to use the signalr authentication system so I can use attributes such as [Authorize] because it's already there.
To use this, I need to validate the username and password. Can the client sends the credentials in header like this
Connection = new HubConnection(BaseEngine.ServerURI);
Connection.Headers.Add("Username", username);
Connection.Headers.Add("Password", password);
HubProxy = Connection.CreateHubProxy("ChatHub");
await Connection.Start();
and the server should validate those credentials somehow in a method and throw an exception if are not valid?
I've tried to use the builtin system, but no luck. I couldn't obtain the Context.User in OnConnected method. As a workaround, I've tried to send the username and password in header and validate them, but the OnConnected method cannot throw errors to client. I am sure the client has to have an auth cookie, but I really don't know how to add it.
Thank you!
It is never a good idea to send password to the server this way , it is better to send a token that the server can validate .
also SignalR has some authentication features read more about this here
I have found something like a workaround: first of all, I implemented an attribute, derived from AuthorizeAttribute used by SignalR. This implementation overrides the AuthorizeHubMethodInvocation method witch is called when a method that is decorated with this attribute is called. So, in this method, I'm checking that an Authorization Token is present in the header of the request and validate the information. The client has to add this header to connect to the server. It's the easiest method I have found so far, but it's still an workaround.
Implementation, server:
[AttributeUsage(AttributeTargets.Method)]
internal class CustomAuthorizeAttribute : AuthorizeAttribute
{
public override bool AuthorizeHubMethodInvocation(Microsoft.AspNet.SignalR.Hubs.IHubIncomingInvokerContext hubIncomingInvokerContext, bool appliesToMethod)
{
string token = hubIncomingInvokerContext.Hub.Context.Headers["AuthenticationToken"];
if (string.IsNullOrEmpty(token))
return false;
else
{
string decryptedValue = Encryptor.Decrypt(token, Encryptor.Password);
string[] values = decryptedValue.Split(';');
string userName = values[0],
deviceId = values[1];
bool b = ...check if it's ok...
return b;
}
}
}
Implementation, client:
ComEngine.Connection = new HubConnection(BaseEngine.ServerURI);
ComEngine.Connection.Headers.Add("AuthenticationToken", Encryptor.Encrypt(string.Format("{0};{1};{2}", BaseEngine.UserName, BaseEngine.DeviceId, BaseEngine.Password), Encryptor.Password));
try
{
await Connection.Start();
}
catch (Exception ex)
{
...
}

SignalR - Send message to user using UserID Provider

Using SignalR, I believe I should be able to send messages to specific connected users by using UserID Provider
Does anyone have an example of how this would be implemented? I've searched and searched and can not find any examples. I would need to target a javascript client.
The use case is, users to my site will have an account. They may be logged in from multiple devices / browsers. When some event happens, I will want to send them a message.
I have not looked into SignalR 2.0 but I think this is an extension of what the previous versions of SignalR used to have. When you connect to the hub you can decorate it with an Authorize attribute
[HubName("myhub")]
[Authorize]
public class MyHub1 : Hub
{
public override System.Threading.Tasks.Task OnConnected()
{
var identity = Thread.CurrentPrincipal.Identity;
var request = Context.Request;
Clients.Client(Context.ConnectionId).sayhello("Hello " + identity.Name);
return base.OnConnected();
}
}
As you can see you are able to access the Identity of the user accessing the Hub. I believe the new capability would be nothing more than an extension of this. Since the connection is always kept alive between the client and the hub you will always have the principal identity which will give you the UserId.
I believe this can help you: (linked from here)
A specific user, identified by userId.
Clients.User(userid).addContosoChatMessageToPage(name, message);
The userId can be determined using the IUserId interface:
public interface IUserIdProvider
{
string GetUserId(IRequest request);
}
The default implementation of IUserIdProvider is PrincipalUserIdProvider. To use this default implementation, first register it in GlobalHost when the application starts up:
var idProvider = new PrincipalUserIdProvider();
GlobalHost.DependencyResolver.Register (typeof(IUserIdProvider), () => idProvider);
The user name can then be determined by passing in the Request object from the client.

DotNetOpenAuth: Want to access username while storing Nonce

I am using DotNetOpenAuth 4.0.20926 and trying to implement an OAuth2 based Authentication server with Db Nonce provider.
For some purpose I want to access username in NonceStore's StoreNonce function while processing the GetToken request.
I am not getting a way to retrieve Username in that call.
How can I solve this problem?
Hey Andrew thanks for your reply and DotNetOpenAuth.
My GetToken Method is like this
public ActionResult Token()
{
string userName = "";
//Want to fetch username here
//Using username here
var result = this.authorizationServer.HandleTokenRequest(this.Request);
return result.AsActionResult();
}
And I want to fetch the username before calling HandleTokenRequest.
Is there any Message Parser or Helper method to fetch the username from the request data / Code value .
As you've observed, the interface does not pass the username into the StoreNonce method. So the only way you may possibly be able to get the username would be for you to discover what it is first, before you instantiate your INonceStore instance, and pass it to that nonce store first, so that later when StoreNonce is invoked, it already knows the username.
That said, I believe any design where storing and checking a nonce requires the username needs some rethinking. Not only is it a mixing of concerns that otherwise should remain separate, you may be limiting yourself going forward or even introducing security holes.

Where to store data in WCF request

I'm using a custom username and password validation for my WCF security. Now i would like to store the username during the request so that i can access it later in the method that is called. How do i do that?
Some sample code to describe my problem:
public class CustomUserValidator : UserNamePasswordValidator
{
public override void Validate(string username, string password)
{
if (username == "aaa" && password == "bbb")
{
// store username where i can get it in method called later.
return;
}
throw new SecurityTokenException("Unknown Username or Password");
}
}
Now the method that is being called:
public void WebServiceMethod()
{
Database.User.Single(c => c.Username == /* username from above */);
}
BR
Andreas
You would typically do this by issuing a custom "principal", which is done via IAuthorizationPolicy; IIRC, the username is made available to the auth-policy via the evaluation-context parameter. A general walkthrough to custom principals in WCF is here, however you may need to experiment a bit in Evaluate to find the incoming username in the evaluation context. In particular, if any of the keys is a "claims" dictionary, look at that. And look at the .Claims on the evaluation context - you should find a "claim" in their issued by CustomUserValidator with the username in it.
I have, however, done exactly what you describe in a previous job - and IIRC it worked fine, using the above page as my starting point.
Once you have issued a principal, it will be available, as normal, via:
string cn = Thread.CurrentPrincipal.Identity.Name;
To store data of any kind through a single WCF request, Darin Dimitrov suggests hooking up a simple IExtension<> helper class to the current OperationContext here: Where to store data for current WCF call?

Categories