WCF same Identity as on client? - c#

For an experimenting project I'am struggling with a service. The client is an ASP.NET MVC 4 and the service will be build with WCF. For now all the systems are in a trusted subsystem so SSL/certificates is not necessarily.
The problem I'am currently dealing with is: Is het possible when I create a new GenericIdentity like:
IIdentity newIdentity = new GenericIdentity("Test", "Custom authentication");
string[] newRoles = { "TestRole" };
IPrincipal testPrincipal = new GenericPrincipal(newIdentity, newRoles);
Thread.CurrentPrincipal = testPrincipal;
It is possible to have the created user when I'am on the WCF service calling the following code:
ServiceSecurityContext.Current.WindowsIdentity;
Or
ServiceSecurityContext.Current.PrimaryIdentity;
Or
Thread.CurrentPrinicpal;
I get the user which I created in the client? Or do I have to write a WCF extensibility for this?
I'm currently using a WsHttpBinding and security mode Transport and clientCredentialType: Windows. Maybe something wrong about the configuration?

On server side (WCF), the security context will have the username value you have used to authenticate to the service.
This means, that if you have defined on client side windows authentication, WCF will find the security context filled with the username of the windows identity you used.
In order for you to authenticate to the servive with windows account, you can use the following code
on client side :
channelFactory.Credentials.Windows.ClientCredential =
new NetworkCredential(username, password, domain);
Having used this code, you can access the identity on server side with the below code :
OperationContext.Current.ServiceSecurityContext.PrimaryIdentity
In general, try to be explicit on client side authentication info. Currently, you seem to
be simply using the default behavior of windows authentication schema, by setting identity
on current thread.
I hope this helps.

I discovered to achieve this automatically in WCF that you must specify a certificate...
In the messages that are sent to the WCF service I created a few properties with the information in the datacontracts that is necessary to create a GenericPrinicpal (in this the username en the roles). Because I have an trusted subsystem I don't want to authenticate the user on each WCF-service (to much overhead for my scenario). See also Trusted subsystem
With this I created a WCF extension that implemented a parameter inspector and with reflection I set the credentials from the CurrentPrincipal in the specified properties of the contract. For more information about parameter inspectors and how to apply it

Related

How to pass default credentials in Windows Authentication

I'm developing UWP application using C#.net and it has WCF service with Windows Authentication enabled. I struggling to pass default NetworkCredential after consume a service call using Add service reference option.
Please find below my examinations.
When I pass correct windows authentication credentials, it is working as expected.
var service = new ServiceReference.Service1Client();
service.ClientCredentials.Windows.ClientCredential =new NetworkCredential("pradeep","****");
var test = await service.GetDataAsync(1);
but, I wanted pass default network credentials while using my service methis
var service = new ServiceReference.Service1Client();
service.ClientCredentials.Windows.ClientCredential = System.Net.CredentialCache.DefaultNetworkCredentials;
var test = await service.GetDataAsync(1);
I also tried below option.
service.ClientCredentials.Windows.ClientCredential = (NetworkCredential)CredentialCache.DefaultCredentials;
When I pass default credentials. I'm getting below exception.
The HTTP request is unauthorized with client authentication scheme
'Negotiate'. The authentication header received from the server was
'Negotiate, NTLM'.
I tested same service call with default NetworkCredential in WPF application which is working as expected.
In order to pass the default credentials for the WCF Windows Authentication in UWP by using the System.Net.CredentialCache.DefaultNetworkCredentials, first please make sure that you have added the Enterprise Authentication and Private Networks(Client & Server) capabilities as following:
For the Enterprise Authentication capability, it is because that Windows domain credentials enable a user to log into remote resources using their credentials, and act as if a user provided their user name and password. The enterprise Authentication special capability is typically used in line-of-business apps that connect to servers within an enterprise.
For the Private Networks(Client & Server) capability, it is because that currently in Windows Runtime we can only pass the default credential in the Intranet. For the Internet we have to use the Username and Password as credential.
For more information about the Capabilities, please check:
https://msdn.microsoft.com/en-us/library/windows/apps/hh464936.aspx .
After that please try to use your Computer name or Fully Qualified Computer name instead of the IP address for your WCF Services like this: http://YourComputerName:YourPortNumber/Service1.svc.
At last please use another computer as client to test the WCF Windows Authentication in UWP with the System.Net.CredentialCache.DefaultNetworkCredentials, then it should work fine.
Thanks.

Creating a service for client authentication with servicestack?

I have a couple of applications (mobile and desktop) that I need a simple webservice created for authentication and to post information back to the clients.
After having man problems trying to figure out how to create a membership database or even find a previous one to check against with the WCF service I am using, I have stumbled upon service stack. So I have a couple of questions.
Does service stack have an out of the box database and provider so that I can simply add authentication for the clients, and have it create the database itself. So I do not have to create it from scratch.
Is their an example of a servicestack service and database already so I can use as a foundation?
The whole WCF services thing is having me confused. Basically all I am looking for is a service that I can use to authorize a mobile app and desktop app, and maybe later on add some extra functionality to it. It would need its own db since it won't be run from an existing website, and a way for me to manage them.
With WCF it seems overly complex for the task and I haven't found any examples with a database already to use and a way to manage them. Ideally I would of liked to have a blank website set up just so I could administer the accounts and have the WCF service use the same database.
Can this all be done easily with service stack, and could anyone point to an example for it already? If you have any tips on my current approach that would help aswell.
I recommend reading the Authentication and authorization wiki which explains the Authentication support built-into ServiceStack.
Backend Repository options
It describes all the potential backend repositories you can persist the authenticated UserData to, long-term:
OrmLite: OrmLiteAuthRepository in ServiceStack
Redis: RedisAuthRepository in ServiceStack
In Memory: InMemoryAuthRepository in ServiceStack
Mongo DB: MongoDBAuthRepository in ServiceStack.Authentication.MongoDB
Raven DB: RavenUserAuthRepository in ServiceStack.Authentication.RavenDB
NHibernate: NHibernateUserAuthRepository in ServiceStack.Authentication.NHibernate
Short-term Session / Caching providers
As well as all the different caching options that's used for fast, short-term data-access of authenticated client sessions:
In Memory: MemoryCacheClient in ServiceStack
Redis: RedisClient, PooledRedisClientManager or BasicRedisClientManager in ServiceStack.Redis
Memcached: MemcachedClientCache in ServiceStack.Caching.Memcached
Azure: AzureCacheClient in ServiceStack.Caching.Azure
By default the MemoryCacheClient is used if one isn't specified.
Example project
You can look at the source code for the SocialBootstrap API project which is deployed on http://bootstrapapi.apphb.com which is an example demo that showcases all of ServiceStack's supported authentication options enabled in a web application.
I'll re-post the code and documentation from the AppHost.ConfigureAuth(), since it already does a good job explaining how to configure it.
The AppSettings is used by most Auth Providers to access additional information stored the Web.Config:
var appSettings = new AppSettings();
You use the AuthFeature plugin to Register all Authentication methods you want to enable for this web app:
Plugins.Add(new AuthFeature(
() => new CustomUserSession(), //Use your own typed Custom UserSession type
new IAuthProvider[] {
new CredentialsAuthProvider(), //HTML Form post of UserName/Password credentials
new TwitterAuthProvider(appSettings), //Sign-in with Twitter
new FacebookAuthProvider(appSettings), //Sign-in with Facebook
new DigestAuthProvider(appSettings), //Sign-in with Digest Auth
new BasicAuthProvider(), //Sign-in with Basic Auth
new GoogleOpenIdOAuthProvider(appSettings), //Sign-in with Google OpenId
new YahooOpenIdOAuthProvider(appSettings), //Sign-in with Yahoo OpenId
new OpenIdOAuthProvider(appSettings), //Sign-in with Custom OpenId
}));
ServiceStack allows you to specify your own typed CustomUserSession which is what it will use to persist the UserAuth data into the Session.
If you want to enable Registration services for new users so they can register and login with their supplied credentials:
Plugins.Add(new RegistrationFeature());
You can optionally override the default registration validation with your own custom implementation:
//container.RegisterAs<CustomRegistrationValidator, IValidator<Registration>>();
If you are using an OrmLite RDBMS backend repository you need to register a DB Factory, in this case it's configured to access the UserAuth SQL Server DB:
var connStr = appSettings.Get("SQLSERVER_CONNECTION_STRING", //AppHarbor or Local connection string
ConfigUtils.GetConnectionString("UserAuth"));
container.Register<IDbConnectionFactory>(
new OrmLiteConnectionFactory(connStr, //ConnectionString in Web.Config
SqlServerOrmLiteDialectProvider.Instance) {
ConnectionFilter = x => new ProfiledDbConnection(x, Profiler.Current)
});
The above ConnectionFilter is optional, but allows you to profile the DB queries with ServiceStack's built-in Mini Profiler.
Now that you've registered your RDBMS connection above, you can hook it up so it becomes the IUserAuthRepository for the Authentication Feature:
//Use OrmLite DB Connection to persist the UserAuth and AuthProvider info
container.Register<IUserAuthRepository>(c =>
new OrmLiteAuthRepository(c.Resolve<IDbConnectionFactory>()));
If you use the OrmLiteAuthRepository, it can automatically create the backend User Auth tables required by the AuthFeature:
//Drop and re-create all Auth and registration tables
var authRepo = (OrmLiteAuthRepository)container.Resolve<IUserAuthRepository>();
if (appSettings.Get("RecreateAuthTables", false))
authRepo.DropAndReCreateTables();
else
authRepo.CreateMissingTables(); //Create only the missing tables

Account management

I'm completely new to WCF, so I'm sorry if this question sounds dumb..
I'd like to create a web service which will have account management. What I mean is that I have a client which can request the service to register a new account, login and link things to my account.
The accounts are stored in a SQL Server database.
I have this interface:
[ServiceContract]
public interface IService1
{
[OperationContract]
bool Register(string username, string password);
}
In the class that implements the service, the new account is entered into the database.
Is this the right way of doing this or should I do this another way? Also, what about security? Obviously the password will be hashed in the database (I'm creating the hash in the method), but sending it to the service in clear text doesn't seem like the correct way.
The second problem is that I'd like to use a custom UserNamePasswordValidator so the client can only call the methods after authenticating (see my previous question: Basic authentication and WCF)
The problem is that I'd like to create an exception: you have to log in for every method EXCEPT the register method. Is there a way to do this? Or should I create a seperate service just for this one method?
I hope someone can help me out.
Thanks!
In WCF you sould use Transport or Message security to secure your messages. Implementing this is enought for you to secure your sending password. The Transport security will provide you SSL/TSL, while the message security will secure your messages according to WS-Security specification. If you want you can use both of them. See http://msdn.microsoft.com/en-us/library/ms733137.aspx about advantages and disadvantages of message security and http://msdn.microsoft.com/en-us/library/ms729700.aspx about transport.
Before enabling your custom validation you MUST implement one of above security models. When you implement your custom validation, it is just another security check before opening your channel. For example you have a code with custom security
factory = new ChannelFactory<IContract>(binding,
new EndpointAddress(address, EndpointIdentity.CreateX509CertificateIdentity(serviceCertificate)));
factory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.PeerOrChainTrust;
factory.Credentials.UserName.UserName = "admin";
factory.Credentials.UserName.Password = "qwerty";
channel = factory.CreateChannel();
When you create such channel, there first will be certificate check, then in your service side it will call Validate() method. There you can check your login and pass and throw exception, if they are wrong. So factory.CreateChannel() will return you exception, and the channel will not be built, so you would not be able to call any of your service methods. If you want to use only one method, I would recommend you to use stand-alone service for registaration purposes only or you can try to put your registration logic into your Validate() method.

Accessing SelfHosted WCF Services outside a domain

We have WCF services being self-hosted by a Windows Service inside our domain, using NetTCP with the following settings.
// Set Binding Security.
netTcpBinding.Security.Mode = SecurityMode.Transport;
netTcpBinding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Windows;
netTcpBinding.Security.Transport.ProtectionLevel = System.Net.Security.ProtectionLevel.EncryptAndSign;
We now have a requirement to allow people outside the domain to access these Services (as long as they can provide proper domain credentials). Our goal isn't to host the services via IIS, just allow those outside folks into our services. In my testing I was able to connect to a service from outside by "impersonating" the client proxy credentials during the WCF call as such.
proxy.ClientCredentials.Windows.ClientCredential.Domain = "MyDomainName";
proxy.ClientCredentials.Windows.ClientCredential.UserName = "MyUserName";
proxy.ClientCredentials.Windows.ClientCredential.Password = "MyPassword";
My question is: Is this the correct way? Is there a better way? Any advice would be greatly appreciated.
This route is perfectly valid if you need to imperatively (in code, e.g. a credential popup, or read from a configuration file) set the credentials. A more secure option is to use the windows credential cache. Firstly you would set it up to use the cache:
proxy.ChannelFactory.Credentials.Windows.ClientCredential = CredentialCache.DefaultNetworkCredentials;
Next you would set up the credentials in the credential cache. In Windows XP/2003 this is under "Stored Usernames and Passwords," (in the control panel) in Vista/7/2008 this is under "User Account > Credential Manager" (in the control panel).
As said, your way is perfectly valid - the cache is just more secure.

WCF windows credentials

my client on server A calls a service on B which calls a service on C.
In order to get the call working from B->C I have to do this:
channel.Credentials.Windows.ClientCredential =
new System.Net.NetworkCredential("WndowsUserName", "WindowsPassWord");
IService1 service = channel.CreateChannel();
etc...
the user name and password are the windows credentials used from A->B
Of course I do not want to hardcode this so how can I do this without hardcoding?
I tried, with no luck:
WindowsIdentity callerWindowsIdentity =
ServiceSecurityContext.Current.WindowsIdentity;
using (callerWindowsIdentity.Impersonate())
Use
System.Net.CredentialCache.DefaultNetworkCredentials
property. It represents the authentication credentials for the current security context in which the application is running. Details can be found here.
It seems to be a "double hop" authentication problem.
In short, NTLM doesn't alllow more than one "hop" with it's credentials (token). So user authenticates on server 1 with it's token, and in turn, server 1 tries to send the token to server 2. This won't work, unless Kerberos deleguation is allowed between server 1 and 2.
More details here : http://weblogs.asp.net/owscott/archive/2008/08/22/iis-windows-authentication-and-the-double-hop-issue.aspx
And here : http://blogs.msdn.com/nunos/archive/2004/03/12/88468.aspx
Perhaps the class
System.Net.CredentialCache
could be helpfull ...
It has the DefaultCredentials and DefaultNetworkCredentials properties that you can use.
Offcourse, you will have to make sure that your application runs under the credentials that you want (that is , the credentials of the current user).
This can be done by calling
AppDomain.CurrentDomain.SetPrincipalPolicy (PrincipalPolicy.WindowsPrincipal);
At the start of your program.
Then, when you initialize the WCF service, you can use the DefaultNetworkCredentials provided by the CredentialCache.
channel.Credentials.Windows.ClientCredential = CredentialCache.DefaultNetworkCredentials;
IService1 service = channel.CreateChannel();

Categories