How can I authenticate using client credentials in WCF just once? - wcf

What is the best approach to make sure you only need to authenticate once when using an API built on WCF?
My current bindings and behaviors are listed below
<bindings>
<wsHttpBinding>
<binding name="wsHttp">
<security mode="TransportWithMessageCredential">
<transport/>
<message clientCredentialType="UserName" negotiateServiceCredential="false" establishSecurityContext="true"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="NorthwindBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceAuthorization principalPermissionMode="UseAspNetRoles"/>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="MembershipProvider"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
Next is what I am using in my client app to authenticate (currently I must do this everytime I want to make a call into WCF)
Dim client As ProductServiceClient = New ProductServiceClient("wsHttpProductService")
client.ClientCredentials.UserName.UserName = "foo"
client.ClientCredentials.UserName.Password = "bar"
Dim ProductList As List(Of Product) = client.GetProducts()
What I would like to do is auth w/ the API once using these credentials, then get some type of token for the period of time my client application is using the web service project. I thought establishsecuritycontext=true did this for me?

If you're on an intranet, Windows authentication can be handled for "free" by configuration alone.
If this isn't appropriate, token services work just fine, but for some situations they may be just too much.
The application I'm working on needed bare-bones authentication. Our server and client run inside a (very secure) intranet, so we didn't care too much for the requirement to use an X.509 certificate to encrypt the communication, which is required if you're using username authentication.
So we added a custom behavior to the client that adds the username and (encrypted) password to the message headers, and another custom behavior on the server that verifies them.
All very simple, required no changes to the client side service access layer or the service contract implementation. And as it's all done by configuration, if and when we need to move to something a little stronger it'll be easy to migrate.

While I hate to give an answer I'm not 100% certain of, the lack of responses so far makes me think a potentially correct answer might be okay in this case.
As far as I'm aware there isn't the kind of session token mechanism you're looking for out-of-the-box with WCF which means you're going to have to do some heavy lifting to get things working in the way you want. I should make it clear there is a session mechanism in WCF but it's focused on guaranteeing message orders and is not the ideal tool for creating an authentication session.
I just finished working on a project where we implemented our own session mechanism to handle all manner of legacy SOAP stacks, but I believe the recommended way to implement authenticated sessions is to use a Secure Token Service (STS) like Pablo Cibraro's.
If you want more details please shout, but I suspect Pablo's blog will have more than enough info for you to steam ahead.

Related

WCF / WIF - Should I find claims in the backend?

I have an ASP.NET application calling a WCF service.
In ASP.NET application, I make a call to ADFS to perform authentication and I can see all the claims of the user in CurrentPrincipal. Then I perform the call of the WCF service (wsHttpBinding), but the list of claims is empty.
What could be the reason?
If I'am not mistake there different ways to get Claims in WCF.
Thread.CurrentPrincipal - Simple and easy to used but need some setting in your configuration, which is most neglected.
<behaviors>
<serviceBehaviors>
<behavior name="Test.Services.WifBehavior">
<serviceCredentials useIdentityConfiguration="true" />
<!---Set principalPermissionMode to always to pass the ClaimsIdentity info to the Thread.CurrentPrincipal-->
<serviceAuthorization principalPermissionMode="Always"/>
</behavior>
<serviceBehaviors>
</behaviors>
OperationContext.Current.ClaimsPrincipal - I can't remember if this needs some configuration but I guess you can get it directly from method invoked.
OperationContext.ServiceSecurityContext.AuthorizationContext.ClaimSets - Create a Custom Authorization Manager for a Service and need to add in config.
Note that I used Windows Identity Foundation (WIF).

WCF Web Service needs access to user name and password information [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I have build a wcf web service that simply provides MS Dynamics SQL data to a CRM hosted Silverlight application. Currently the web services are hosted in IIS and are only available via HTTPS so the contents of the messages are secure. I'm now ready to implement the next level of security that has to do with who is logged into the Silverlight client application. I'd like to pass that information to the web service and then use it when creating the SQL Server Connection object. The results will be that the MS Dynamics Database will then only return data that the connected user is authorized to view.
This model is different from the standard model that consists of authenticating a given user for access to the web service. Instead, in my model everyone is granted access to the web service and the results of the SQL queries are based on the user name and password for a given user.
For Clarification: The Silverlight application collects the user name and password from the user when they log on to the application. This is the information that eventually needs to be used by the web service when the web service makes the connection to the SQL Server database. So my goal is to have the Silverlight applicaiton pass the username and password to the web service in such a way that the web service can retrieve it and use it when creating the Connection object.
I'm considering something as simple as adding the user name and password to each web service request. However I'd rather be able to use the standard method for passing user credentials but I can't seem to find any way to get to the password. The user name is accessable throught the OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name.
Any ideas?
You can use the wsHttpBinding for passing credentials to your service, this will however at the very least require you to send the credentials with message security. You can combine this with anonymous authentication in IIS. This way, everyone can access the service on a transport level, but you'll be able to handle the credentials yourself.
To expand, I have a WCF service running in IIS with HTTPS and anonymous authentication. In my web.config I've set up a wsHttpBinding, like this:
<bindings>
<wsHttpBinding>
<binding name="CredentialsBinding" />
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</wsHttpBinding>
</bindings>
In my behaviors, I've set up a servicebehavior for a custom username/password validator, like so:
<behaviors>
<serviceBehaviors>
<behavior name="DefaultBehavior">
<serviceCredentials>
<userNameAuthentication
userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="MyNamespace.CredentialValidator, MyNamespace"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
The validator looks like this:
namespace MyNamespace.CredentialValidator
{
public class CredentialValidator: UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
// you can now handle the username and password passed to your service
// with a wsHttpBinding through HTTPS
}
}
}
--EDIT
Rory Primrose describes what you're probably looking for in his article WCF Security: Getting the password of the user, using a CustomUserNameSecurityTokenAuthenticator to get the password for further use.

WCF (SOAP):Protecting single operations with custom UserName validator - similar to what WcfRestContrib offers but for soap?

I was hoping to be able to protect my WCF services on an operation level not service level.
Hence some methods are protected and others not. I know there is an attribute called PrincipalPermission but this works with Windows
I was hoping something existed for WCF Soap like it does for WCF Rest in this contrib project. WcfRestContrib
This extra project allows the use of a custom username and password validator and allow it only to protect certain methods by decorating the methods with an attribute
Is this possible with WCF (soap)?
Thanks in advance
Yes, it is possible to do operation level authorization checks with SOAP in WCF, but you'll need to do claims based authorization (as far as I know). That's what my team does for our product.
The hook point in WCF is to implement a custom ServiceAuthorizationManger
ServiceAuthorizationManager.CheckAccessCore Method
How to: Create a Custom Authorization Manager for a Service
and plug that into your service behaviour:
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceAuthorization serviceAuthorizationManagerType="MyServiceAuthorizationManager" />
</behavior>
</serviceBehaviors>
When you implement your authorization manager, override CheckAccessCore, and then simply return true/false is they are authorized or not.

WCF - Configuring Client/server authentication in headers?

I've got a WCF service that will need to receive client credentials, and maintain some kind of role-based data, based on my auth method.
The clients will reside on many different systems, and as such, each client will have a unique userID and pw.
I'm using basicHttpBinding and have read a few articles, such as this one,
http://nirajrules.wordpress.com/2009/05/22/username-over-https-custombinding-with-wcf%E2%80%99s-channelfactory-interface/, that describe the process.
So what I'm looking for is if someone has a full client/server configured like this to take a look at so I can derive my own solution from this.
What I'd like to do is have the username and password passed in the headers for each request, passing back some kind of SecurityTokenValidationException on fail, or continuing if passing.
Thanks.
UPDATE
I'm using the wsHttpbinding with the following config on both the client and server:
<wsHttpBinding>
<binding name="wsHttpEndpointBinding" >
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="Basic" />
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
And the call out to the server from the client as follows:
ServiceReference1.ServiceClient myClient = new ServiceReference1.ServiceClient();
myClient.ClientCredentials.UserName.UserName = "billuser";
myClient.ClientCredentials.UserName.Password = "mypassword";
Response.Write("Data from WCF Service: " + myClient.GetData(1));
I think I need a bit of a hand with linking up the CustomUsernamePasswordValidator on the server as I'm still getting the '...could not be activated.' error.
Are you required to use the basicHttpBinding? That binding is really only there to provide support for legacy WS-BasicProfile implementations (i.e. ASMX). If your clients are also .NET/WCF, I would highly recommend using wsHttpBinding, which provides a plethora of security options out of the box. You could use certificates, username/password, etc. with transport and/or message security and not need to write any of the security stuff yourself. Just configure-and-go (CAG).
Security credential information is available to the service itself via the OperationContext, in case you need to access it directly from your code. If your code does need to access it, however, I would recommend writing a behavior to extract the pertinent information from the OperationContext and place it in something more application specific so that you don't have to reference System.ServiceModel everywhere you need to access information on OperationContext.

How to configure secure RESTful services with WCF using username/password + SSL

I'm looking to write a config file that allows for RESTful services in WCF, but I still want the ability to 'tap into' the membership provider for username/password authentication.
The below is part of my current config using basicHttp binding or wsHttp w/out WS Security, how will this change w/ REST based services?
<bindings>
<wsHttpBinding>
<binding name="wsHttp">
<security mode="TransportWithMessageCredential">
<transport/>
<message clientCredentialType="UserName" negotiateServiceCredential="false" establishSecurityContext="false"/>
</security>
</binding>
</wsHttpBinding>
<basicHttpBinding>
<binding name="basicHttp">
<security mode="TransportWithMessageCredential">
<transport/>
<message clientCredentialType="UserName"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="NorthwindBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceAuthorization principalPermissionMode="UseAspNetRoles"/>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="MembershipProvider"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
Here's a podcast on securing WCF REST services with the ASP.net membership provider:
http://channel9.msdn.com/posts/rojacobs/endpointtv-Securing-RESTful-services-with-ASPNET-Membership/
I agree with Darrel that complex REST scenarios over WCF are a bad idea. It just isn't pretty.
However, Dominick Baier has some good posts about this on his least privilege blog.
If you'd like to see WSSE authentication support with fallback to FormsAuthenticationTicket support on WCF, check out the source code of BlogService.
Before you continue down this path of fighting to implement REST over WCF, I suggest you read this post by Tim Ewald. I was especially impacted by the following statement:
I'm not sure I want to build on a
layer designed to factor HTTP in on
top of a layer that was designed to
factor it out.
I've spent the last 12 months developing REST based stuff with WCF and that statement has proven itself to be so true over and over again. IMHO what WCF brings to the table is outweighed by the complexity it introduces for doing REST work.
Regardless if the community has opinions against REST on WCF (I'm personally on the fence) Microsoft has taken a swipe at it, http://msdn.microsoft.com/en-us/netframework/cc950529.aspx
Yes agreed with Moto, a link off the WCF Starter Kit is the closest thing I saw to authentication of credentials using a custom HTTP header (http://msdn.microsoft.com/en-us/library/dd203052.aspx).
However I could not get the example going.
Try custombasicauth # codeplex
UPDATE 01/23/2012
Since I wrote this question I've seen a much better approach to securing REST like web services in the wild. It sounded complex when I first heard about it but the idea is simple and all over the web for both web services and other secure communication.
It requires the use of public/private keys.
1.) each user (customer) of the endpoint will need to register with your REST web service
a.) you give this user a private key that should not be shared with
anyone
b.) you also generate a public key that can go over the wire
in plain text if need be (this will also be used to identify the client)
2.) each request from the user needs to generate a hash to sign the request
a.) One example of this might look like: private key + a timestamp + encoded payload (if small enough like a simple user info to be updated for example)
b.) you take these 3 (or whatever you decided on) and generate a 1 way hash (using hmac for example)
c.) in the request being sent over the wire you include the public key (so the server side knows who is attempting to send this request), the hash that was generated w/ the private key, and the timestamp.
3.) the server endpoint (your REST method) will need to generate a hash using the same inputs used on the client. This step will prove that both client and server knew a private key that matched the public key passed along with the request. (this in turn means that the user sending the request is legit as no one else could know the private key)
a.) lookup the customers private key by the public key being passed along during the request
b.) take the other params (timestamp and the encoded payload) along with the private key you found in the previous step and use the same algorithm to generate a 1 way hash (again hmac is what I've seen used in the real world)
c.) the resulting 1 way hash needs to match the hash sent over the wire, if not send back a 400 (or whatever http code you deem to be a "bad request")