WCF, custom authorization with data being passed to service class - c#

I wrote a UserNamePasswordValidator descendant for validation purpose (basicHttpBinding).
The problem is when I validate a user against back service I receive its identifier that I have to use in service class method. That turns out to be a huge problem... unless you know how to do it ...
Is there another authorization alternative that I will not have to pass userName / password in method header or even worse in method's parameters of the Service?

WCF service authentication and authorization can use UserNamePasswordValidator and IAuthorizationPolicy. Here's an article on how to do it. If not, try using IPrincipal.

Related

Ways to secure an anonymous Web API request

I have a ASP.NET MVC (NOT ASP.NET Core) single page application with angular js on the front end.
My client (browser) talks to server through ASP.NET Web APIs. Now, the web application is on https but anonymous. There is no login/ user authentication.
The web app is in the form of a wizard where user can go back and forth and add or update input fields on the web page. The form input values are then updated on the server through Web API.
I'm looking for a way to secure my Web API calls alone, especially the POST/ PUT requests. In summary, I want to prevent any user calling my Web API directly from POSTMAN or Fiddler. The Web API, though anonymous can be only called from the browser session where the request originated.
What are options do I have to achieve this?
Can I use Anti-Forgery token here (without authentication)?
One way, I can think of achieving this is to add a custom header to each request and store some kind of session key in the header. Then, validate the custom header on every request I received from client. Are any other ways of achieving this out-of-box or some proven library without going for custom solution?
If I have to go for the above custom solution, what are the pitfalls or potential issues I need to be aware of?
First of all when you remove login and there's no authentication mechanism in your application, there's really no way to secure anything, because anyone can access your APIs. I think what you want is to make sure that your APIs are called only from your own website. Unfortunately you can't completely achieve that, since your web APIs are http/https, and anyone, from anywhere (like postman, fiddler, ...) can create a http request and call your API.
All you can do is to make it harder for your API to response to requests, like using Anti-Forgery as you mentioned.
And also I suggest you add a cookie for your application and check that cookie in every request, in this case it's more complicated ( not impossible ) to call your API using Fiddler or Postman.
And last I suggest that you use CORS, so browsers would only allow your domain to call your APIs. So nobody can call your APIs in a browser from different domain.
Based on answer from #Arvin and comment from #Evk, here's how I plan to proceed:
Once, the user starts the anonymous session generate a GUID using regular Guid.NewGuid() method and save it in DB to identify the request (I'm doing this now). However, as mentioned here,
GUID can be unique but they are not cryptographically secured.
Hence, instead of using plain-text GUID, encrypt it with current timestamp as token and append it with request query string.
For every subsequent API request, read the token from query string, decrypt it and validate it as follows:
Check the timestamp. If the time difference is more than pre-defined time (i.e. token expired), reject the request
Validate the unique id (GUID) against DB
Since, I'm not using plain text GUID anymore, the URI would not easy to guess.
Additionally, with the timestamp, URI is invalidated after sometime. While theoretically it is still possible to call the API through Fiddler but this should make it very difficult for the attacker, if not impossible.
As a further security measure, I can also add Anti-Forgery token to the request
As per my understanding this helps solving my underlying problem and with this approach, I may not even need add a cookie to secure my anonymous session.
Love to hear from you all if this approach looks good and how can it be improved.
I also once had the weird need for having session functionality on WebAPI and created an OWIN Session middleware that does exactly what you're aiming for.
The library is called OwinSessionMiddleware and is available on github and NuGet.
Usage
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseSessionMiddleware();
// other middleware registrations...
app.UseWebApi();
}
}
You can also pass some options to further tweak cookie-name, add a database backed session store (instead of in-memory), add your own session id generator (instead of default id generator which is based on GUID + secure random part generated by RNGCryptoServiceProvider).
The unique session id itself is stored as a secure cookie and the session is restored automatically by the middleware on each request.
There are extension methods you can call inside your API controller to get and set session data:
public SomeApiController : ApiController
{
public IHttpActionResult MyAction()
{
var requestCount = Request.GetSessionProperty<int>("RequestCount");
Request.SetSessionProperty("RequestCount", ++requestCount);
}
}
Create Anonymous JWT token with some claims related to your scenario, Sign it with some key, Use that as in cookie (Http Only) or As bearer token. To make it little more harder further combine it with some cookies.
1)verify token signature and
2) Verify token expiry time
3) Verify Claim(skey) against cookies(skey)- no database storage required everything is in ur JWT token.

Microsoft.Owin.Security.Oauth Bearer Token Authorization Interception

I am in the process of implementing OAuth 2 on a web API with Microsoft.Owin.Security.Oauth.
I would like to keep the bearer token small and keep private data out of it. To do this, I'd like to store a session ID in it and then fill out the ClaimsIdentity programmatically once the session ID has been received and processed. This would also give me greater flexibility related to how logging out, role changes, and other things can be handled.
This should be a matter of intercepting the right event and adding a delegate. However, I can't find an event that gets fired on my authorization provider, a subclass of "OAuthAuthorizationServerProvider". I thought that "AuthorizeEndpoint" would do it, but it does NOT get fired for API methods decorated with the [Authorize] attribute, even though these methods clearly get checked for a valid bearer token. When I overrode "MatchEndpoint", all I found is that a call to a method that was decorated with [Authorize] showed up with "IsAuthorizeEndpoint" and "IsTokenEndpoint" both set to false. The latter makes sense to me, the former does not.
I am very confused. Can somebody who knows this library tell me what's going on and what I need to do to accomplish this seemingly simple idea?
I think you may be conflating resources marked with the AuthorizeAttribute with the OWIN Authorize endpoint. The AuthorizeEndpoint and TokenEndpoint are setup in the OWIN configuration as receivers for their respective authentication types. The Authorize Endpoint is used for web-base, user-agent authentication and is where you would expect a browser to be redirected should they be unauthorized to access a resource. The token endpoint is used instead for username-password token authentication and refreshing, and is the one you want. Assuming you are assigning both of these within your OWIN startup configuration, the event you may be looking to overload for OnValidateTokenRequest to ensure that your customizations to the token do not cause it to be invalid once the client tries to utilize it again. You would want to do your actual modifications to the token at the OnTokenEndpoint event.

Account management

I'm completely new to WCF, so I'm sorry if this question sounds dumb..
I'd like to create a web service which will have account management. What I mean is that I have a client which can request the service to register a new account, login and link things to my account.
The accounts are stored in a SQL Server database.
I have this interface:
[ServiceContract]
public interface IService1
{
[OperationContract]
bool Register(string username, string password);
}
In the class that implements the service, the new account is entered into the database.
Is this the right way of doing this or should I do this another way? Also, what about security? Obviously the password will be hashed in the database (I'm creating the hash in the method), but sending it to the service in clear text doesn't seem like the correct way.
The second problem is that I'd like to use a custom UserNamePasswordValidator so the client can only call the methods after authenticating (see my previous question: Basic authentication and WCF)
The problem is that I'd like to create an exception: you have to log in for every method EXCEPT the register method. Is there a way to do this? Or should I create a seperate service just for this one method?
I hope someone can help me out.
Thanks!
In WCF you sould use Transport or Message security to secure your messages. Implementing this is enought for you to secure your sending password. The Transport security will provide you SSL/TSL, while the message security will secure your messages according to WS-Security specification. If you want you can use both of them. See http://msdn.microsoft.com/en-us/library/ms733137.aspx about advantages and disadvantages of message security and http://msdn.microsoft.com/en-us/library/ms729700.aspx about transport.
Before enabling your custom validation you MUST implement one of above security models. When you implement your custom validation, it is just another security check before opening your channel. For example you have a code with custom security
factory = new ChannelFactory<IContract>(binding,
new EndpointAddress(address, EndpointIdentity.CreateX509CertificateIdentity(serviceCertificate)));
factory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.PeerOrChainTrust;
factory.Credentials.UserName.UserName = "admin";
factory.Credentials.UserName.Password = "qwerty";
channel = factory.CreateChannel();
When you create such channel, there first will be certificate check, then in your service side it will call Validate() method. There you can check your login and pass and throw exception, if they are wrong. So factory.CreateChannel() will return you exception, and the channel will not be built, so you would not be able to call any of your service methods. If you want to use only one method, I would recommend you to use stand-alone service for registaration purposes only or you can try to put your registration logic into your Validate() method.

Intercept WCF Method Call and "Re-route" based on Authentication status

Was curious if there was a way to check if a user is authenticated before making a method call and then returning a custom object and not completing the call if they aren't. For example:
We set the user principal in the Application_PostAuthenticateRequest in the global.asax to the user making the request if they are authenticated or to an anonymous user if they aren't. Currently in all methods that require authentication we have something similar to the following code:
public Result GetSomeObject()
{
if (HttpContext.Current.Request.IsAuthenticated)
{
}
}
Bottom line: We want to be able to check IsAuthenticated BEFORE we let WCF get inside the method on methods that require authentication, and if true, continue, if not, return a Result object (JSON) with an authentication error.
What you need to develop is called ServiceAuthorizationManager in WCF. You can find more information about this on:
http://pieterderycke.wordpress.com/2011/04/07/implementing-restricted-access-to-a-wcf-service-with-the-serviceauthorizationmanager/
You can write a custom httpmodule to intercept the requests to the service layer and do the authentication in there.
This article may be a starting point for what you are looking for: http://pieterderycke.wordpress.com/2010/12/04/extending-wcf-creating-a-logging-component/

Retrieving the currently authenticated user in a WCF service

Today, I implemented a custom authentication provider for my WCF service. It is able to determine if my user is valid or not, just as expected.
So, now I have this class:
public class MyCustomValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
User apiUser = User.Login(userName, password);
// other logic goes here.
}
}
The behaviour of my application depends on what objects the User can access. So, how can I get my User object from here to my service class? There is no immediately obvious way that I can see, as my service class does not inherit from anything by default, unlike the ASP.NET controllers.
My first instinct is to set up a static parameter in MyCustomValidator and then read it from there, but I suspect that a race condition could occur. Can anyone confirm or deny my suspicions?
And most importantly: Is there a better way to do this? This is the first time I have ever used WCF, so I'm not aware of the best practices involved here.
Thank you for your time.
You want to pass some data from validator to service instance. It is bad because you can't do it. UserNamePasswordValidator is only for validating credentials (user name and password). You don't have access to anything from your validator. It even doesn't see current operation context because it runs in different thread. Using static parameter is not a sloution - as you mentioned it is race condition.
I think you need to implement custom authentication and authorization and it is not easy:
WCF Authorizaton, Custom Authorization, Custom credentials and validation

Categories