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.
Related
When sending an encrypted msmq message it seems like the authentication bogs down the speed (from 2500 msg/sec to 150 msgs/sec).
This seems to be the case for both System.Messaging.MessageQueue and the Wcf client with msmqIntegration binding.
My requirement is for encrypted transport, I can do without authentication. I would prefer the WCF client since settings can be changed from app.config.
Is there a way for the msmqIntegrationBinding to do transport encryption without authentication ?
<msmqIntegrationBinding>
<binding name="VisionAirMessagingBinding"
timeToLive="12:00:00"
maxReceivedMessageSize="4100000"
receiveErrorHandling="Move"
retryCycleDelay="00:30:00"
useMsmqTracing="false"
serializationFormat="Stream">
<security mode="Transport">
<transport msmqAuthenticationMode="WindowsDomain"
msmqEncryptionAlgorithm="RC4Stream"
msmqProtectionLevel="EncryptAndSign"
msmqSecureHashAlgorithm="Sha1"/>
</security>
</binding>
I found out that authentication slows me down by commenting out the following when using the System.
q1.Send(new Message
{
BodyStream = new MemoryStream(
Encoding.ASCII.GetBytes("ABCDEFGHIJKLMNOPQRSTUVXYZ")),
Label = i.ToString(),
//UseAuthentication = true,
UseEncryption = true
}, msmqTx);
If I switch on the authentication, sendings becomes slow again!
Thx for any help!
WindowsDomain authentication means Kerberos authentication. It is necessarily a multiple agent protocol (using something like 4+ different messages being sent). Since you are using the blocking .Send() method. This is going to limit your rate (due to multiple latency paths), if you do not throw in some asynchronicity/concurrency.
You might find that switching to simple Certificate authentication will suffice.
The result is that the server will be executing the message without the user's credentials, but will be authenticated (you know who sent the message, but you can't elevate to the that user's permissions).
We need to create a WCF service (.NET 4.0) that will be consumed by a client outside of our organization.
The case is that we have two servers that are behind a load balancer which terminates the SSL. This is where it gets confusing for me.
How we could and should handle the authentication?
The previous experience about WCF is only about services for internal use. If I understood correctly we should use basicHttpBinding to guarantee interoperability with Java based client. I don't know if this is an issue with JAX-WS based client.
There will only be this one client that is going to use the service.
We need to somehow ensure that caller is authenticated to use the
system
Make sure the message is encrypted when moving in public network
So far the best article that I found was
http://devproconnections.com/net-framework/wcf-and-ssl-processing-load-balancers
There were few suggestions how to do this.
WCF services can be configured for basic authentication and receive credentials in the clear over HTTP. This can work; however, it precludes passing credentials in the message, and the use of more interesting credentials (such as issued tokens).
We use forms authentication on our website under which the service will be hosted. I think it is not easy or even possible to make the service then use basic authentication.
WCF services can be configured to fake the presence of transport security so that the runtime will allow receiving message credentials without transport or message protection
Will this be the way to go and will this work with basicHttpBinding?
The client and server binding will be different. The client binding will use username auth in eitehr message or transport level with transport security (ssl):
<bindings>
<basicHttpBinding>
<binding name="NewBinding0">
<security mode="Message" />
</binding>
</basicHttpBinding>
</bindings>
then the server config will use the same config but without the transport security. If you chose to use message security then check out WCF ClearUsernameBinding. If you use trasnport security (basic http) then set mode="TransportCredentialOnly".
I have converted my webservice to wcf service keeping the extension of wcf service as asmx since I have a large client base and do not want to ask users to change the extension. Currently I have username / pwd authentication for my clients which I want them to move out of. Since my user base calls my web service from all sorts of machines and OS's, I am not able to get what type of authentication I can move them to.
X509 Certificate, issued tokens, username pwd or something else..? Any help or guidance with some sample code blocks or urls' would be appreciated.
If you are replacing ASMX service with WCF service you are using BasicHttpBinding (and perhaps also AspNetCompatibility). In that case you don't have many choices. You can use Transport security (HTTPS) with client certificates or TransportWithMessageSecurity (HTTPS + UserName token profile). If you don't want to use HTTPS and you still want to use UserName token profile you need .NET 4.0 and you have to create custom binding like:
<customBinding>
<binding name="InsecureCredentials">
<security mode="UserNameOverTransport" allowInsecureTransport="true" />
<textMessageEncoding messageVersion="Soap11" />
<httpTransport />
</binding>
</customBinding>
Ultimately, it depends on whose doing the calling for to your service, IMO.
If this is primarily B-to-B, meaning that your clients are some automated process rather than, say, a silverlight app, I'd prefer identity certs (i.e. x509). If this is a user-driven call such as a silverlight app, then I'd stick with username/password, but consider federated identity.
That said, given the fact that you have many different types of clients, even if it's b-to-b there's no guarantee you'll be able to service every client with x509. In my experience, too many shops just aren't flexible enough to adopt "newer" standards (even though x509 has been around a long time, it's still "new" to a lot of people making web service calls). Therefore, it might be best for you to stick with username/password.
You could offer all three, however. WCF is very very nice that way; it's quite simple to set up a single service implementation that just happens support either username/password auth or x509 or federated identity. Almost all of that is handled by the binding configuration; you might need some plugin code for the username/password auth (depending on how you're set up) but the auth code is completely divorced from the service code.
My question is in regards to the best (aka "least painful") way to secure access to a WCF service that is only exposed to our company's internal users. The goal is to ensure that the service is only accessed via a single Windows forms application that each of our users has installed. When the service is called, I want the service to be able to validate that it was called from the permitted application.
The service to be secured uses basicHttpBinding, which supports streaming, so I believe I am limited to Transport level security.
Below are simplified versions of the <bindings> and <services> sections from my service's config file.
<bindings>
<basicHttpBinding>
<binding name="Service1Binding" transferMode="Streamed"/>
</basicHttpBinding>
</bindings>
<services>
<service name="WCFServiceSecurity.Service1"
behaviorConfiguration="WCFServiceSecurity.Service1Behavior">
<endpoint address=""
binding="basicHttpBinding"
contract="WCFServiceSecurity.IService1"
bindingConfiguration="Service1Binding"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
Can anyone offer some details as to what actions I would need to take in order to implement security on this service?
Note: I'm new to WCF and am not familiar with security at all, so let me know if I haven't provided enough detail.
UPDATE:
As suggested by marc_s, I'd like to secure the WCF service using some sort of username/password mechanism. This gives a little more direction towards an answer, but I'm still somewhat blurry on how to actually do this.
Because my service requires streaming to be enabled, I have to use basicHttpBinding and Transport level security (right?); further to that, the method contained in my service can only accept a Stream object.
Taking those constraints into consideration along with my preference to use username/password validation...
How should I modify my service's config file to force username/password credentials to be supplied?
How will my service validate the supplied credentials?
How will my client application pass credentials the service when making a call?
Will this require using SSL and, if so, will all client machines require a certificate as well?
UPDATE:
After explaining the trouble I've been having with securing this service to my boss, I was given the go-ahead to try the Windows Authentication route. Sadly, I've had no luck in implementing this type of authentication with my Streamed service (argh). After making the appropriate changes (as outlined here - the only exception being that my transferMode="Streamed") and accessing my service, I was presented with the following error:
HTTP request streaming cannot be used in conjunction with HTTP authentication. Either disable request streaming or specify anonymous HTTP authentication.
I then stumbled upon the following quote here which offers some clarification:
You can't do transport auth. with streaming. If you have to use HTTP request streaming, you'll have to run without security.
The way security works is:
WCF Client makes an http request to the Server.
The Server responds with something saying, "You aren't authorized, send me a basic/digest/etc credential."
The Client gets that response and resends its message with the credentials tacked on.
Now the Server gets the message, verifies the credentials, and continues.
Request Streaming isn't designed to work with that security pattern. If it did, it would be really slow, since the Client would send the entire stream, get the message from the Server that it wasn't authorized, then it would have to resend the entire stream with credentials.
So now I'm looking for opinions, how would you secure your streaming-enabled WCF service? As mentioned previously, some sort of username/password mechanism would be preferred. Feel free to think outside the box on this one...
Any help is greatly appreciated!
Well, I found a lot of issues surrounding security/streaming while working on this problem. The hack (er...um...workaround) I finally ended up going with was to create a new DataContract that inherits MemoryStream and decorated it with a BaseStream property (for holding the data I want streamed) along with appropriate properties used for simple authentication.
Here is the resulting DataContract:
[DataContract]
[KnownType( typeof( MemoryStream ) )]
public class StreamWithCredentials : MemoryStream
{
[DataMember]
public Stream BaseStream { get; set; }
[DataMember]
public string Username { get; set; }
[DataMember]
public string Password { get; set; }
}
The above DataContract ends up being the input parameter of my service's method. The first action my service takes is to authenticate the supplied credentials against known valid values and to continue as appropriate.
Now I do know that this is not the most secure option but my directive was to avoid using SSL (which I'm not even sure is possible anyway - as stated here) for this internal process.
That being said, this was the best solution to the above stated problem I could come up with, hope this helps anyone else stricken with this issue.
Thanks to all who responded.
There's a number of things you could do:
add a certificate to each and every machine that's allowed to use your service, and check for that certificate. That only allows you to exclude "unauthorized" machines - you cannot limit it to a specific application
same as above, but include the certificate embedded in your winforms app and send it from there (do not store it in the machine's certificate store)
require a username / password that only that particular app of yours knows about and can transmit to your service; e.g. someone else would not be able to present the appropriate credentials
EDIT 2: OK, so the username/password approach seems to get out of hand.... what if you just have basic transport security (SSL) for basic protection, and then use the MessageContract to define header and body of your SOAP message, include a specific value in the header, and then just check for that presence of the element in the header in your service?
Something like that:
[DataContract]
class YourRequestData
{
...
}
[MessageContract]
public class YourRequest
{
[MessageBodyMember]
public YourRequestData bodyData { get; set; }
[MessageHeader]
public string AppThumbprint { get; set; }
}
And then on your server in your code just check for the presence and the validity of that AppThumbprint code:
public Stream RequestStream(YourRequest request)
{
if(AppThumbprintIsValid(request.AppThumbprint))
{
.... begin your streaming
}
}
That might end up being a lot easier than the username/password security scenario.
Marc
Please correct me if I am wrong, but:
if you are using forms authentication for your WCf service (on asp.net), just add a login method to your service, in it you create the required cookie (formsAuthentication.Authenticate()). which is automatically sent with the response, the client can then call the stream API without needing extra parameters (a requirement for it to be STREAM) and you can check the identity in the streaming api before you fire off the returning stream.
As for securing access to the whole WCF, I get the feeling that embedding a certificate in the .net app is one way to go. they would have to ildump your app to get at it.
you can tell asp.net/wcf not to provide the wsdl, or more accurately, to not automatically generate the wsdl. Without wsdl access it gets much harder for them to generate a proxy....
If you want to use basicHttpBinding (for interop) you can only pass your credential at the message level. You have to set your security configuration to TransportWithMessageCredential.
To do that you have to create a SSL channel, so you need a certificate at server side, and it's not necesary for a cliente to have one.
It is possible to use Windows authentication with Streaming and SSL, but you must use TransportWithMessageCredential:
<basicHttpBinding>
<binding name="FileService.FileServiceBinding" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" transferMode="Streamed">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
You need to set in code proxy.ClientCredentials.UserName.UserName and proxy.ClientCredentials.UserName.Password.
If this is going to be an application that lives on the intranet it might be easiest to just create a new group in your Active Directory and only give members of that group the ability to use the service.
You can add Authentication (using windows credentials) with something like this:
<basicHttpBinding>
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</basicHttpBinding>
Could then Authorise by decorating the Interface to your services methods:
<PrincipalPermission(SecurityAction.Demand, Role:="MyAppsUsers")> _
Public Function MyMethod() As String Implements IService.MyMethod
Heres a good link to Security in WCF. It has lots of How To's at the end (the one titled 'How To - Use basicHttpBinding with Windows Authentication and TransportCreditals' might be of use to you).
Wcf Secruity
[Disclaimer: I'm also new to WCF and haven’t done this exact case before so apologises if this is slightly off!]
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")