Generic OAuth Library C# - c#

What i am Trying to do:
Write a Generic Library in C# to handle OAuth Flow to every service ( Just like Twitter,LinkedIn and Foursquare). The hardest part is that, i want to simulate all the user input in code so that no user action is needed to click on buttons like "Ok,I will Allow It",or even writing its username/password.
Doubts That i have so far:
1 - Whats the usage of the authenticity_token in twitters API ?
2 - What are the factors that all services use, so that i can implement a generic usage of OAuth Flow. For example i´ve found the first Step is really easy to make a Generic method to execute. All i have to do is change the URL for the webRequest,and BAM, i have the Request tokens.
3 - How do i Get the Verifier for each service? In LinkedIn Service for instance, i was able to parse a page to fetch this value, but i can't find this verifier for twitter API for example. Even when authorizing in browser my aplication, i see no Verifier in any HTML during the flow, or any JavaScript generating it.
Observations:
1 - I know that there are Lots of OAuth Libraries out there, like this or that ones, but there is no Library that allows me to make what i want to, that is to Authenticate and authorize a user, without prompting for any user input.
2 - I can't,by any means,ask for user input. All the values like username and password for the authentication, will be hardcoded and every user will use the same account for this requests.
3 - I also know, that there are other posts here that i've written, with almost the same doubts, and the reason i am resposting is to try to make it clearer and fresher.
4 - Sorry about any english mistake or missunderstanding of concepts in advance.
Basic Code Sample:
This is, for instance, the method i am using (that is avaible widely abroad the web) for getting request tokens for any service. All i have to do is change the REQUEST_TOKEN value to the specific url to be used for a service,so i can get the Tokens for LinkedIn,Twitter or Foursquare for instance. But i can't manage to apply the same process in the other steps.
public string AuthorizationLinkGet()
{
string ret = null;
string response = oAuthWebRequest(Method.GET, REQUEST_TOKEN, String.Empty);
if (response.Length > 0)
{
//response contains token and token secret. We only need the token.
NameValueCollection qs = HttpUtility.ParseQueryString(response);
if (qs["oauth_callback_confirmed"] != null)
{
if (qs["oauth_callback_confirmed"] != "true")
{
throw new Exception("OAuth callback not confirmed.");
}
}
if (qs["oauth_token"] != null)
{
ret = AUTHORIZE + "?oauth_token=" + qs["oauth_token"];
}
}
return ret;
}

Don't.
OAuth was designed to require a user to press that button once. If you automate it you will have your application key revoked and your program will no longer work.
What you need to do is save locally the authorization token and reuse that. The user clicks"I Allow" once then you re-use the authorization token for future connections. You need to check to make sure it is not expired, and if it is you just re-authorize and they click "I Allow" again.
No website doing OAuth correctly will allow you to bypass the website authorization, some will allow you to pass the username and password via a query and get a token, but if they have a web authorization, you MUST have the user manually do it.
If you are the OAuth provider and consumer you need to do something Dropbox did for their v0 of the API (I can't find any links to their old API, if anyone can find it edit this post) that passed the username and password to a special address that returned a autorization token without using a webpage. Or you need to use a different authentication scheme than OAuth.

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.

How to make sure that all call to asp web api is authorized?

I'm building an saas application using asp web api 2 and asp identity. This api will be consumed by web, mobile and desktop applications. How do i make sure that all calls to my web api method is authorized? In web, we can ask user to login before going to certain page, but how bout mobile/desktop? Does user need to provide login and password on each call? Are there better solution for this? I've been searching and havent found any article about this. A sample or articles will be much appreciated.
Usually when using api's as a back-end you have to authenticate the user on every request.
(it actually also happens with other frameworks, such as mvc.net, but they keep track of the user using cookies which are send back and forth with every request)
I would suggest you use token based authentication (e.g. OAuth). In such a case you set the token in the header of the request. This token will be used to authenticate (and potentially authorize) the user.
If you need more info i can always explain it a bit more.
== Edit: Added Code sample ==
You could use a request handler to validate that the header of the request includes a valid token:
public class AuthorizationHeaderHandler : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(
    HttpRequestMessage pRequest, CancellationToken pCancellationToken)
    {
        IEnumerable<string> apiKeyHeaderValues = null; 
        if (!pRequest.Headers.TryGetValues("Authorization", out apiKeyHeaderValues)
|| !TokenRepo.IsVallidToken(apiKeyHeaderValues))
        {
var response = new HttpResponseMessage(HttpStatusCode.Unauthorized)
            {
                Content = new StringContent("{\"error\": \"invalid_token\"}")
            };
            response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
return Task.Factory.StartNew(() => response);
}
return base.SendAsync(pRequest, pCancellationToken);
}
}
All you have to do is keep which token is associated with which user, and make sure tokens have an expiration period. Once this is passed, it is also not valid anymore.
I hope this clarifies it a bit.
Again, if you have more questions, do not hesitate to ask.

How do I pass information back to my application as part of the facebook login process?

I'm looking at .Net code which performs a facebook login, using the C#/.Net library wrappers.
I would like to pass an identifier into the log-in attempt, with the goal of having facebook pass it back to me once the user has been authenticated.
I'm constructing the redirect url for the request manually, and I've tried both of the following without much success:
oAuthClient.RedirectUri =
new Uri( "http://localhost:3434/fbOAuth?token=" + HttpUtility.UrlEncode( token ) );
//fails when attempting to get access token -
//"oAuthClient.ExchangeCodeForAccessToken( code )" throws an exception.
var loginUri = oAuthClient.GetLoginUrl( new Dictionary<string, object>
{ { "state", returnUrl }, {"app_data", HttpUtility.UrlEncode(token)} } );
//doesn't pass app_data back to my application
How do you pass arguments to your application as part of the facebook login process?
I use the Facebook C# SDK for building Facebook apps too. What I don't use is their authentication stuff. In my experience, authentication is the hardest part of the overall Facebook app implementation. Getting it right for all devices and all browsers is hard.
You can use the state parameter to pass data of your choosing to Facebook as part of the server-side OAuth design. The Facebook C# SDK chose to use the state parameter to provide context of where to redirect the user on the completion of authentication. That is not how Facebook intended state to be used. From https://developers.facebook.com/docs/authentication/ :
Cross Site Request Forgery (CSRF)
Cross site request forgery is an attack in which a trusted (authenticated and authorized) user unknowingly performs an action on website. To prevent this attack, you should pass an identifier in the state parameter, and then validate the state parameter matches on the response. We strongly recommend that any app implementing Facebook user login implement CSRF protection using this mechanism.
In my own server-side Facebook OAuth implementation, I generate a GUID, concatenate some state info such as the controller to return to, encrypt that string, and pass it as the state parameter.
When it comes back I decrypt it and away I go. You could do something like that to pass whatever stateful app-specific data you want.
The server-side OAuth design is pretty straightforward and well documented at the page linked above.
I use the following code in an ActionResult. Please note my comment on your question not to use "localhost" in the redirect uri:
string returnUrl = "http://productionserver.com/account/fblogon";
#if DEBUG
returnUrl = "http://local.developmentserver.com:12345/account/fblogon"; // add this host in hostfile to 127.0.0.1
#endif
var parameters = new Dictionary<string, object> { { "response_type", "code" }, { "display", "page" } };
parameters["redirect_uri"] = returnUrl;
var url = oauth.GetLoginUrl(parameters).OriginalString;
return Redirect(url);

Twitter App using C# using OAuth token

I'm trying to get a workaround so that i don't have to press the Allow button everytime when I make use of the Twitter API.
if (Request["oauth_token"] == null)
{
//Redirect the user to Twitter for authorization.
//Using oauth_callback for local testing.
oAuth.CallBackUrl = "http://localhost";
Response.Redirect(oAuth.AuthorizationLinkGet());
}
In the code example above i just get a OAuth token but Twitter asks me to confirm that i want to allow access. Is there a workaround so that i don't have to Accept?
I'm afraid the allow step is quite out of your hands. It would be potentially malicious to let a web site authorize a token request on behalf of a user.

How to do Authentication between a webservice and a mobile phone?

I want to make a windows mobile 6 cellphone application. This application will talk to a web service that I want to make.
I don't know much about web services and programming app for phones so I got a couple questions.
How do I do authentication? Like my user loads up my app and goes to the login page. They type in their credentials. This gets sent to the server and authenticated. Now what do I send back? Is there some sort of FormsAuthentication?
After they log in do I have to keep doing checks to see if they are logged in? Like in asp.net mvc I have AuthorizeAttributes on all my tags. That way no one can just type in the url to that action method and be able to access it. But since this is an application I am not sure if they could (say) go your login form (first form) and then somehow, without logging in, get to your main form (the one after the login form).
Do web services have Authorize tags like asp.net mvc? Since I probably need something along those lines to ensure no one types in their web brower my webservice path and get access to all those methods I made in it.
I am making a asp.net mvc application right now and when the user types their credentials on my site. It is sent what I am guessing is clear text? to the server hashed and then checked. I know maybe one day when I can afford it maybe to get ssl to make it more secure.
So my question how about with sending the credentials from the phone to the server will it be less secure than what I have for my website right now? About the same? What can be done to make it more secure (is it SSL again?).
Thanks
You could also use SOAP headers to pass around user credentials or the authentication token. You can find an article on how to do this on Authentication for Web Services (using SOAP headers), but to summarize, you create a header class:
using System.Web.Services.Protocols;
public class AuthHeader : SoapHeader
{
public string Username;
public string Password;
}
You define a public property on the web service
public AuthHeader AuthenticationInfo;
and add some attributes to any web methods you would like to be only accessible to authenticated users:
[SoapHeader ("AuthenticationInfo", Required=true)]
[WebMethod]
public string HelloSecretWorld()
{
if(!(AuthenticationInfo.UserName == "Hello" && AuthenticationInfo.UserName.Password == "World"))
throw new AuthenticationException();
return "Hello World";
}
The client code would look like:
MyWebService ws = new MyWebService();
ws.AuthenticationInfo = new AuthHeader {Username = "Hello", Password = "World"};
Console.Out.WriteLine(ws.HelloSecretWorld());
This way you don't need to modify the signatures of the methods to add authentication.
i've had to address this issue several times in connecting from hand held (Windows Mobile) applications to web services. The solution i've used is to create a cookie based on a hash of the user's login name and IP address once the authentication process has succeeded. e.g. User ID and pwd matches persisted credentials on the server. You then pass this cookie back to the client which will then be passed along with all web service requests for the rest of the session. e.g. The first parameter of any web method is the cookie.
pseudocode:
string cookie = webServiceInstance.Authenticate("userName", "password");
double balance = webServiceInstance.GetBalance(cookie, someId);
Of course you do want to use SSL so as to avoid passing your user id and pwd in plain text.

Categories