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
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.
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.
There's a number of things you could do:
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
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
.
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 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!]