We have a WCF (Windows Communication Foundation) client and service application. We're using Windows Authentication with Kerberos.
The issue is that the service may be run under one of many accounts (maybe Network Service, maybe a specific user account -- depends on the IT group). This account is not not likely to change daily, but possibly on occassion (every few months maybe). Additionally, we deliver this client/service package to several groups, and each group may have its own account that they use to run the service on (this is to just let you know that we can't do a custom solution for a single team).
Now the reason the above paragraph is an issue is apparently if the service is not running in the SYSTEM or NETWORK SERVICE account, i.e., a user account, then the client must specify the name of the user account in the identity of its endpoint.
For more on this restriction see: http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/feb6bc31-9a4b-4f8d-a887-ef6d2c7abe41
and http://www.vistax64.com/indigo/146204-using-localhost-v-s-environment-machinename.html
Now this seemingly makes it tough to deal with the situation where the IT department changes the account that the service runs on. What is the pattern for handling this, if there is one? How have other people handled this? One solution I've thought of is that the admin sends out an email when the user account of the service has changed, which has a weblink to an application that updates the client or a config file, so the client refers to the new user account. But that seems hackish.
Admittedly, this is a lot like the URI of the endpoint moving. Except, I think there's a lot more expectation on behalf of people that changing the URI is something the client should have to know about, but changing the account the service is running on is something that should be relatively transparent to the client.
BTW, this is required to be hosted on IIS 7.0, if that matters.
I think you can set NegotiateServiceCredential property to True so your binding uses SPNego instead of hard-cold Kerberos. When is set to true, the client does not need to specify the SPN and it can connect to a server running a non-machine account.
Note that since the client no longer requests a specific SPN, it can no longer detect if is connected to a hijacked impersonator of the service, but this is usually a minor concern unless you are really paranoid about security.
Also, as a side rant: the fact that WCF requests as SPN the account name is basically a brain fart. It client should use the DsMakeSpn API to compose the SPN from the service name, host and port. The server should register that SPN for itslef at start up or let an administrator do it using setspn.exe. This is the way they do it by all traditional (well behaved) services in the Kerberos/ActiveDirecotry/Windows environment.
Update
On second though I don't see anything specifying that the client must use the account name as SPN. Looks more like a documentation oversight, instead of documenting the proper way they just recommended what is basically a bad practice. Or maybe just the forum advice is bad, since I did not dig to see what does the MSDN binding spec actually says about the SPN to use...
I don't have a WCF environment handy to test with, but perhaps you can configure the clients to requests a proper SPN like YourService/server:port and you also register the same SPN on the server side. Either manually as an exercise left to the admins, or automatically from your service when it starts up, and unregister it at shut down. The proper way to do it is to let the admins do it, but in reality that is such a pain that most services register the SPN themselves and you can probably follow this practice too. To register an SPN, your service calls DsWriteAccountSpn. The write has to propagate to the AD and be replicated between AD servers, and this at least one reason why having the service auto-register/auto-unregister the SPN is a questionable practice.
If you want to learn more about the wonderfool world of SPNs and how they can wreck your day, you can read up on How Service Publication and Service Principal Names Work.
Update
I'm pretty sure you can use any SPN you like. Most exmaples out there use the account name as 'UPN' (User Principal Name) instead of SPN, but that is just for the convenience of samples as using a true SPN would run into administrative issues setting up the SPN under an user account (again, why admins should do it...). From Overriding the Identity of a Service for Authentication, relevant emphasized:
By default, when a service is
configured to use a Windows
credential, an element that
contains a <userPrincipalName> or
<servicePrincipalName> element is
generated in the WSDL. If the service
is running under the LocalSystem,
LocalService, or NetworkService
account, a service principal name
(SPN) is generated by default in the
form of host/<hostname> because those
accounts have access to the computer's
SPN data. If the service is running
under a different account, Windows
Communication Foundation (WCF)
generates a UPN in the form of
<username>#<domainName>. This occurs
because Kerberos authentication
requires that a UPN or SPN be supplied
to the client to authenticate the
service.
You can also use the Setspn.exe tool
to register an additional SPN with a
service's account in a domain. You can
then use the SPN as the identity of
the service. To download the tool, see
Windows 2000 Resource Kit Tool :
Setspn.exe. For more information about
the tool, see Setspn Overview.
Set NegotiateServiceCredential and EstablishSecurityContext properties to False.
Related
I've been reading about WCF security for a whole day and can't say I'm comfortable with it.
I've developed some WCF services and deployed them to a test server and can call from a client. Both sides C# / VS 2010. The services are hosted under IIS 6. No option to go more recent at the moment.
So - I've read that I can only use HTTP with IIS 6 - which I believe restricts me to basicHttpBinding or wsHttpBinding as the binding.
I've also read that the XML sent over the wire using wsHttpBinding is encrypted, whereas basicHttpBinding is not.
So it looks like I want to go with wsHttpBinding as I will want some sort of authentication and I suppose user name / password will be passed along with the incoming messages.
First question is - if I use wsHttpBinding do clients have to call using https? And then do I need to worry about certificates etc. on the server?
Second question is - what security options are available to me? Do the callers have to be Windows users on the server, or can I make up my own user name / password and have that part of the service and the service do the validation and have nothing to do with Windows users? If I have to go with Windows users I suppose it's common to set up one user account on the server and have all callers use that?
The basic idea is I need to open this service to selected callers, but don't want just anyone to be able to discover the service and call it. I need to control somehow who calls the service. Is user name / password the standard way of doing this? Could I define a GUID for example which all callers would have to pass?
In answer to your first question. wsHttpBinding does not require HTTPS. You can use HTTP if you set the SecurityMode to Message or None. However, since you are proposing to send a username and password with the service calls you definately shouldn't do that. If you do then anyone will be able to look at the message in transit and read the username and password and your security is totally compromised. I'm afraid you will have to get a certificate and use HTTPS. It's not so bad though and there are lots of resources on the web to help you.
By the way, you can do HTTPS with basicHttpBinding aswell as wsHttpBinding. Also, you should consider using REST for simplicity. WCF has good support for it (webHttpBinding) and better support coming with the Web API.
In answer to your second questions, you do not need the callers to be Windows users on your server and you can use a username and password. This is called Basic Authentication. Again, there is lots about it on the web. Start here.
If you do this you will obviously have to have a database to store usernames and password so you can validate then and grant or denay access to your service. The simplest way to achieve this with WCF is to use one of the default membership providers.
We are using WCF services. Right now, we are using Windows Auth but this is not for long. Some services will sit outside the firewall and use username/password verified in the database.
My tech lead is "scared" at how easy any user can "Add Reference" to the services we have and just party on. He wants to "guard" the services by adding another identity - the application. He wants the service to accept requests from certain applications so the certain users cannot just use the service - add reference to it and call. It’s the notion of the application having an identity + credentials that is the operative principle here, as services on the network may need to authenticate those credentials prior to fulfilling a request, in order to prevent rogue code inside the network (i.e., NOT the application) from accessing services using “Joe User” end-user credentials.
Does this make any sense?
Then he believes the Juval Lowy's book has, in an Appendix that discusses sending more than one identity during a WCF call (Security Interceptor). There is no specific suggestion that all of those have to be end-user identities and if that is the case, one of those could be the identity of the application making the request.
How can this be done?
Thanks,
Sam
The problem with sending an application identity is that the secret used to confirm that identity has to be stored somewhere. If it is visible to one application on a machine then generally it will be visible to other applications running under the same identity.
Would your manager be happy with "it came from an authorised machine"? If that's the case you could simply use Client Certs
Its also worth taking a step back: if the user is authenticated and is authorized to perform the functionality they have requested, why do you care which application they came from - if they are who they say they are and they are allowed to do what they are requesting then why couldn't they use, say, fiddler to make the request - isn't that the point of a service (rather than a closely coupled client server app)?
You might want to look through Common Security Scenarios in the MSDN documentation to see if any of those options fit your needs.
The options that pops to my eye are Transport Security with Certificate Authentication and Message Security with Mutual Certificates. Both rely on X.509 certificates. The latter option is on the message level, so you can handle certificate delivery and security negotiation however you want.
To make it a lot harder for someone to add a reference to your service you could just remove the mex endpoint. This way it would be very difficult for a stranger to create a valid request message.
You can then distribute the WSDL manually, only to people you trust.
After some theoretical help on the best approach for allowing a SaaS product to authenticate users against a tenant's internal Active Directory (or other LDAP) server.
The application is hosted, but a requirement exists that tenants can delegate authentication to their existing user management provider such as AD or OpenLDAP etc. Tools such as Microsoft Online's hosted exchange support corporate AD sync.
Assuming the client doesn't want to forward port 389 to their domain controller, what is the best approach for this?
After doing some research and talking to a few system admins who would be managing this, we've settled on an two options, which should satisfy most people. I'll describe them here for those who were also interested in the outcome.
Authentication Service installed in the origanisation's DMZ
If users wish to utilise authentication with an on-premises active directory server they will be required to install an agent in their DMZ and open port 443 to it. Our service will be configured to hit this service to perform authentication.
This service will sit in the DMZ and receive authentication requests from the SaaS application. The service will attempt to bind to active directory with these credentials and return a status to indicate success or failure.
In this instance the application's forms based authentication will not change, and the user will not be aware of the authentication behind the scenes.
OpenId
Similar to the first approach, a service will be installed in the client's DMZ, and port 443 will be opened. This will be an OpenId provider.
The SaaS application will be an OpenId consumer (already is for Facebook, Twitter, Google etc login).
When a user wishes to log in, the OpenId provider will be presented, asking them to enter their user name and password. This login screen would be served from the client's DMZ. The user would never enter their username or password into the SaaS application.
In this instance, the existing forms based authentication is replaced with the OpenId authentication from the service in the client's DNZ.
A third option that we're investigating is Active Directory Federated Services, but this is proprietary to Active Directory. The other two solutions support any LDAP based authentication across the internet.
Perhaps this might help…
This vendor, Stormpath, offers a service providing: user authentication, user account management, with hookups to your customers’ on-premise directories.
What about an LDAPS connection to the customer's user directory? They can firewall this off so that only your servers have access if they're concerned about it being public. Since it's SSL it's secure end to end. All you need from them is the certificate from their issuing CA (if it's not a public one). I struggled to get this working for an internal web project in the DMZ and there's a real lack of any guides online. So I wrote one up when I'd got it working:
http://pcloadletter.co.uk/2011/06/27/active-directory-authentication-using-ldaps/
Your best bet is to implement a SAML authentication for your SaaS application, and then sign up with identity providers like Okta or OneLogin. Once that's done then you can also connect it with ADFS to provide Single Sign On for your web application through Active Directory.
I'm just doing this research myself and this is what I've came across of, will have more updates once implementation is done. Hope this gives you enough keywords to do another google search
My understanding is that there are three possible solutions:
Installing something on the domain controller to capture all user changes (additions, deletions, password changes) and send updates to the remote server. Unfortunately there's no way for the website to know the initial user passwords - only new ones once they are changed.
Provide access for the web server to connect to your domain controller via LDAP/WIF/ADFS. This would probably mean opening incoming ports in the company's firewall to allow a specific IP.
Otherwise, bypass usernames/passwords and use email-based authentication instead. Users would just have to authenticate via email once every 3-6 months for each device.
I have to begin implementing this for an upcoming project and I'm seriously leaning towards option #3 for simplicity.
Please suggest me the best authentication way to implement in the scenario mentioned below:
The requirement is I have to deploy a WCF web service in multiple countries across the world.
NOTE : All the machines on which the service is deployed are on the same domain.
1.The clients that access this service should fall in the same domain else the authentication should fail.
Currently I am using Message Security mode using "Windows"
I am curous why you would want the domain to be the same if it needs to be deployed in different countries around the world. Unless you are talking about hosting the service on an internal network that is not publicly exposed, enforcing the same domain name might be difficult. Different countries have different domain standards. America has a much richer set of domain roots to choose from. Other countries often have a country specific root, possibly with a regional subroot.
I would not couple your service to the domain that hosts it, nor would I recommend using the domain as a factor in authentication. If your service needs to be publicly exposed on the internet in each of these countries, I would recommend using something other than Windows security. A Claims-based security mechanism might work best. Internally inside the service implementation, claims can be checked, and if necessary, the windows identity can be authenticated separately from WCF authentication. Claims also allow you to utilize more than just a username/password or certificate to fully authenticate and authorize a client request. You can request the callers domain, country, region, and other evidence be included in the claim, allowing you to verify that calls are being made from the appropriate location and by the appropriate clients with much more flexibility than with Windows authentication (and if you publicly expose your service, Windows authentication will likely not be available anyway.)
Since you are running on an intranet and assuming that your Windows application will connect directly to the service, I would go with Transport Security using Windows authentication.
For some guidance consult patterns & practices Improving Web Services Security Guide.
I still question whether or not you need authorization. If you go with Windows authentication without any authorization it will simplify your service but will allow any domain user to access your service whether or not they are using the Windows application. Granted, they would have to have knowledge of the endpoint and the message structure but it would still be possible for them to do.
If Windows authentication is really all that is required, I would still raise the authorization issue and document it (and get sign off if applicable). On the one hand this covers you but also makes people explicitly aware of the decision and the possible risks.
We are planning on utilising kerberos in our architecture. I would like to know what perceived or actual advantages this technology has, and if there are any alternatives.
Note that we have a .net client side and java server side. communication will be via messaging bus and SOA
If you are working within a mostly Windows environment (i.e. Windows Server 2k3, a domain controller, Active Directory, etc.) one in particular is that you can use impersonation through .NET with a split web server and database server. Using the older NTLM method, you cannot do a "double-hop".
Let's look at an example:
You have a web server (WEB1)
You have a database server on a separate machine (DB1)
You have a user access your website (USER1)
USER1 hits a page that displays a list of orders. Your WEB1 server has to query DB1 for this info to display on the page. You want to constrain what orders are seen based on the user's credentials and access rights. Thus, you set up active directory groups and assign users accordingly. On your database you give the different groups different security (GROUP1 might have select only and GROUP2 might get select, insert, and update, for example).
NTLM doesn't support the double-hop necessary to do this. WEB1 has to send USER1's credentials to DB1 (otherwise WEB1 must log into DB1 with a known dedicated user id and password hardcoded into the web.config for example that usually has to have full access to support all possible user roles). You can imagine this could be a security hazard should WEB1 be compromised, so you can't do it, otherwise anyone who gains control of WEB1 (via sql injection perhaps) could do anything the dedicated user account could or impersonate whomever they want. Kerberos, through delegation on Windows Server, supports doing this second hop by keeping the encrypted credential key from your domain server intact and passed along, as well as verified that this is allowed (on both ends, see below for setting this up on your servers because it MUST be EXPLICITLY allowed).
It's very useful to do this when developing intranet web apps that have a database back-end (which is 99% of the time the case, right?) and you want to control authorization and authentication through Windows Integrated Security. Kerberos is really your only choice unless your web server and database server are on the same machine, which means there is no transferring of credentials and no impersonation necessary.
See also:
MSDN - How To: Use Impersonation and Delegation in ASP.NET 2.0
Microsoft Help & Support - How to configure an ASP.NET application for a delegation scenario
MSDN Magazine - Security Briefs: Credentials and Delegation