There's a Dynamic CRM instance on a server ("on-premises"). It will be used by a few sites that run on distant machines (another domain, another Active Directory). The communication between those sites and the CRM instance is done via a CRM proxy, a WCF service that sits near it (near CRM), handles requests, queries CRM etc.
That WCF service is facing the Internet. Although secured communication channels aren't that necessary, authentication is. We cannot let random clients to use the services provided by the CRM proxy.
So, Authentication Service (cookies?) / hand-coded token passing (as a parameter for each service operation) / this solution - on stackoverflow.
Thank you in advance!
PS: hand-coded tokens would be "time-sensitive" and hashed a few times with some secret keys. Man-in-the-middle might not be such a big problem, as a token can be invalidated after a request.
Hand-coded token passing is not very elegant. It pollutes your method signatures and makes you duplicates checks all over the place.
If you are able to distribute credentials to your service clients, or pass in credentials that they already use for your system, then I suggest using message security with a custom username & password validator.
The steps to implement it are simple enough. You only need to implement a UserNamePasswordValidator:
A short configuration summary from the linked article:
Specify the security mode in your binding:
<security mode="Message">
<message clientCredentialType="UserName"/>
</security>
In your service behavior add:
<serviceCredentials>
<userNameAuthentication
userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="YourFullUserNameValidatorType"/>
</serviceCredentials>
Then clients just need to set their credentials directly on the service proxies. So they're not passed in service operations.
serviceClient.ClientCredentials.UserName.UserName = "username";
serviceClient.ClientCredentials.UserName.Password = "password";
Your UserNamePasswordValidator will get these credential for each service operation call and you will have the chance to validate them against your credentials store.
However, for more security, you could look into certificate authentication. It's more reliable and you are not required to buy a cert from a CA. If you can also setup yourself as a CA on the client computers, then your good to go. It's appropriate especially because you only have a few clients, so they would be easy to manage.
For the question above the preivous answer is good enough. However, I want to suggest another approach: Custom Token Authentication.
It is more poweful by giving a possibility to create/support Custom Service Credentials which are created based on the authentification token (UserName).
In my case I have encrypted access token which holds all needed information for the access: user name, user groups (authorization information), validation period, ect.
In your case it can be UserName & Password. The Credential will hold the information about your user and can be used later on in the code.
See the following link for implementing Custom Token Authentication:
https://learn.microsoft.com/en-us/dotnet/framework/wcf/samples/token-authenticator
Related
I'm developing the authentication/authorization architecture for several APIs.
I'm using IdentityServer4 as a Security Token Service (STS).
From what I've read from "Dominick Baier" (one of the persons that built IdentitySever4), there are only two types of Flows that should be used:
Client Credentials Flow. (machine-to-machine)
Authorization Code Flow + PCKE. (for iteractive users).
I have several C# Web API's that will communicate with each (Machine-To-Machine), and I will use the Client Credentials Flow.
But then there are some WPF Desktop Applications, that will need to access some APIs, and don't have a user.
Which flow should be used?
I've read that:
Desktop/Native & Mobile Applications should use Authorization with Authorization Code Flow (with Public Client and PKCE), since they are hosted on the Client side, and the Client/Secret is can be leaked (maybe on a Desktop application we can Encrypt the Secret? But then will need to manage a way how to store the secret that decrypts that right?)
Then I've read:
"Anytime you have a system that isn’t concerned with the end-user identity (and just needs to authenticate the system), use the OAuth2 Client Credential Grant."
For now, this is my case, I'm not concerned with the end-user identity (but maybe in a near future I will).
So since the above points conflict with each other:
- Which flow should I use?
- Can I have a Desktop Client using Clients Credential Flow and be safe?
Also, I've read a bit about Mutual TLS, If I use that, does this change which flow should I use?
You can't trust a client because you can't be sure a request originates from the client. And another problem is that clients are not good in keeping secrets. But there are different types of clients.
Clients that run on servers often having a single task, like synchronizing data which is user independent, are suitable to use the client credentials flow. To some degree they can keep a secret (running on a server).
You can use unique credentials for each instance but that doesn't make it safer. It helps you to identify the client, but doesn't add security. Security is about monitoring behaviour and detecting anomalies. Or perhaps narrowing access by filtering on ip address.
But you are not limited to use the two flows you've mentioned. Being a token provider, you can extend IdentityServer with custom flows using extension grants.
Without user the client credentials are somewhat similar to the resource owner password credentials (ROPC) flow (another option that is no longer covered in the grant type documentation but still exists, see the old docs). Neither are really safe in the sense that both can be automated. The user factor can be eliminated since user interaction isn't required for these flows.
But I wonder why your app has no user, running on a user machine. Because ideally you have a client (without secret) where the user logs in and let the client contact the api (delegation).
So there are two things: do you need to identify the client? If not you could suffice with an ApiKey, like e.g. Sendgrid. And you can never trust a client. Security has to be server side.
So basically it doesn't really matter, there is nothing you can do to make it much safer client side. The only thing you can do is add the requirement of user interaction. So perhaps now you don't need it, but it will increase security and allows you to delegate api access to the client.
When creating a WCF service application I've implemented UserNamePassValidator for custom authentication and this works as expected.
But due to the large amount of functionality on the service, I've decoupled this into different service contracts such as a stock management service, location management service, task management service etc. and I've then exposed these on different endpoints within the same service.
This seems to work fine, however what I would prefer is to authenticate with one endpoint and have this session state maintained across all of the endpoints. At present what happens is I authenticate to one, I can then access the functionality of that service contract but if I was to connect to another endpoint it requires me to authenticate again.
My current crutch solution is to pass the ClientCredentials between forms on the client side for authenticating, and although it's using Message security so they're encrypted over the wire this is obviously not an ideal solution.
Is there a solution to first part? And if not, what's the best practice for storing user entered credentials in memory (during runtime) at the client side.
You can implement a scheme similar to WS-Federation. It is kind of Federated Security for service level.
Firstly, your Authentication endpoint should be called STS (Security
Token Service). What it does is authentication and return a security
token to the client.
Secondly, STS should be trusted by all the Service Endpoints. When
invoking the endpoints you should pass in the security token that STS
provided so that the endpoints will be able to read that token and
recognize that the token was issued by a trusted STS.
I have implemented one with Thinktecture at https://github.com/khoanguyen/Test-WS-Federation but sorry that I didn't give explanation you will need to research a little bit about WS-Federation and Thinktecture and WIF. But you should know that it is possible to do.
A lightweight solution that I am using for REST services for mobile project is below:
I set up a Authentication endpoint. That endpoint hold a DSA private/public key pair. When client is authenticated, this endpoint generate a token and sign it with DSA private key. Then I combine the signature and token together and return it as a security token to the client.
At the service endpoints, I gave them the DSA public key (from the key pair of Authentication endpoint). The DSA public key is for verifying the security tokens.
When client call the service endpoints, it attaches the security token as a Header of HTTP message. Then, the service endpoints read the header to retrieve the security token -> extract the token and the signature from the security token -> use DSA public to verify it.
The strategy for generating the token depends on your need. In my case, my token contains client's username, expiration timestamp. By using DSA, the hacker can extract all the token's data but they cannot alter it because they must have the DSA private key to sign the altered token. Our job is just keeping the private key in secret and don't leave any sensitive info (e.g password) in the token.
This is very cheap way. I don't need to access DB to verify user, just ensure got a valid security token, token's data is just for extra need, you can even generate a random token and sign it. No session state needed.
I have a client, which calls a service (passing it a user id and password). The first service can validate these credentials against users in a database. The first service then needs to call another service, but this second service cannot be passed the user id and password given to the first service (this is a requirement outside of my control).
The services will most likely be on different domains and both exposed to the internet (so security is a big issue here).
I am therefore looking at options for how the second service should check/validate that it is being called by my first service (and not by someone else trying to impersonate it).
One idea I've had is to add an additional service that acts as an authentication service, this could issue a token that is then passed to the second service which in turn calls the authentication service to check the token. Another idea (from a colleague) has been to assign an SSL certificate to each service, and check the certificate when the call comes into Server B - I haven't seen certificates used in this way though so am not sure if it's viable.
This is still at the design stage, so I am open to alternative ideas/approaches.
If you need an easy fix, then creating an extra set of credentials for service A so that service B can be sure it's called from an authorized party without knowing the clients credentials might be enough.
In the long run, something like Windows Identity Foundation sounds exactly like your plans with the authentication service.
So, both A and B parties are exposed to the internet (distrusted environment). Taking into account security requirements what you need is mutual WCF authentication. Certificates are the easiest way to achieve the goal - your server has to ensure that proper client calls it and the client has to be sure it calls proper server (DNS attacks, etc.). That means each party must have public key of the other to authenticate. Check this article for the details on how to configure your server and client.
We are building a web service with WCF on .net 4.0. The service will be used mainly by an ASP.net MVC frontend, but will also be used by a .net Windows App.
The basic username/password auth provided won't do since we don't want to save user credentials, so I was thinking about authenticating once and creating a simple token (or should I call it a cookie?) with RNGCryptoServiceProvider.GetBytes() and then using that to authenticate further requests.
I've looked into the various common methods to do security with WCF and they mostly seem overly complex, especially when all we want to do is essentially pass a cookie to every method call.
What would be the best strategy to pass this cookie from a WCF client to our WCF services? The preferred method would be as tightly coupled with WCF's security architecture as possible.
So far I was leaning on either using custom HTTP headers, or custom authorization but I'm not convinced which is the more appropriate method, if any.
Keep in mind that for the ASP website, a new channel would be created for every request, while it would be reused on the Windows app.
IMO there are two ways to do wcf security, Transport or Messsage.
You could implement username type authentication in your application. So the client side would have to fill in a username and password for sending a message.
so the binding on the client side would look like
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
</security>
On the server side you could implement your own password validator, as shown in this example
doing this would authenticate your message on the server, you can implement whatever logic you want for your password validation. using this your message would be encrypted using ssl and authenticated using your own logic implemented on the service side.
I am building a wcf service that needs to be secured as information that the client inter-exchanges with the service is sensitive to the company. I am planning to have it hosted on iis6. What would be the best practice to make sure that nobody but the client application can call the service to get/set data?
The service calls need to happen under the user's real identity as all the calls have to be monitored and audited. I am planning to use PolicyInjection for audit calls.
It all depends.
But basically there are two main approaches:
Transport security with SSL with basicHttpBinding
SSL security with wsHttpBinding
If you provide more information, I should be able to help you more.
There are certain aspects of security:
1) Data integrity: no-one has tampered with data but the data itself are not secret. This is achieved by signing.
2) Data security: This is so that no one could see sensitive/secret information. This is by encryption.
3) Authentication: this is by sending username/password or using certificates. This makes sure the person is the same who is claiming.
4) Authorization: This is to make sure the person has access to the specific features in the service.