How to do Authentication between a webservice and a mobile phone? - c#

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.

Related

Avoiding redirection to localhost while user authentication

I created an application in windows forms. Login to this application with a username and password. The application can only work after the user is authenticated. I do the user authentication on a php page on the Internet. With the HttpClient, I am sending the username and password to the php page and information about which application to authorize. If the username and password are entered correctly, I send a round of values with json from the php page so that the user can operate on the authorized screen.
So far, so good. However, there is a problem: If the user sets up a local server with Wampserver or a similar program and redirects my domain name to the local server from the host file, the username and password from winforms will be sent to this local server. The user may well generate the appropriate parameters from this local server and send them to winform in json format.
Finding the parameters in windows forms is not difficult with methods such as decompile. That's why I think the parameters can be found very easily. And I think the user can easily bypass my authorization request with local server method. How can I overcome such this problem? In any case, how can I verify from the real website on the Internet?
In my research on the internet, I read something like the username and password can be sent with the timestamp to the php page and compared with the hash values. However, I am very confused. Because I do not keep any hash values in the database.
I think, it would be like this:
var uri = new Uri("http://example.com/login.php");
var ipv4 = Dns.GetHostAddresses(uri.Host)[1];
if (ipv4.ToString() == "127.0.0.1")
{
// Localhost...
}

Generic OAuth Library 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.

How to redirect a user to a different server and include HTTP basic authentication credentials?

I have a web application (C# - ASP.net) that needs to pass a user to a page on a remote Apache server using HTTP Basic Authentication. I need to be able to pass a user name and password to this server to allow users authenticated by my application to seamlessly use the other application without being prompted to enter credentials he doesn't have. The hand-off should be secure since both systems require SSL as long as the user name and password are not in client-side script. Is there a way to do this?
Basic authentication details are encoded in the request header named "Authorization" from the client. The header contains the base64 encoded result of "username:password".
e.g. Aladdin:open sesame = Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
There are more details on the Basic Access Auth wikipedia page.
For basic authentication, the Authorization header needs to be added to every request. Usually the browser will take care of this after the user has entered their credentials into the dialog presented by the browser. If you want to avoid having your users enter these credentials, then your ASP.net server will need to sit in between the user and the Apache server (acting as a reverse proxy) adding the auth headers to every request that it forwards on behalf of your users.
It is not possible to simply visit your server once and for it to add a "token" to the request then redirect to the apache server. This approach would be possible if you were using forms/cookies for authentication and your servers presented themselves to the user as within the same domain (e.g. asp.domain.com & apache.domain.com) then the auth cookie could be set on the parent domain (e.g. domain.com) and shared - see Forms Authentication across sub-domains.
Assuming that the basic auth scheme on the Apache server is not something you can easily change, it seems like the reverse proxy is the best option. In the reverse proxy code, the HttpWebRequest is the means to create each request to the apache server and add the additional authentication headers to it.
.net will deal with encoding the credentials in the proxied request using something like:
RemoteServer remoteServer = new RemoteServer(httpContext);
HttpWebRequest request = remoteServer.GetRequest();
request.PreAuthenticate = true;
request.Credentials = new NetworkCredential(UserName, SecurelyStoredPassword);
Try using the url format https://username:password#example.com
Only other thing I can think of - if the page doesnt force its way out, load a page of their site in a frame, send it data+ controls, via javascript so it sends the login and so on. Might be feasible.

How to support NTLM authentication with fall-back to form in ASP.NET MVC?

How can I implement following in ASP.NET MVC application:
user opens intranet website
user is silently authenticated if possible
if NTLM authentication didn't worked out, show login form to user
user indicate login password and select domain from list of predefined domains
user is authenticated in code using AD
I know how to implement 4 and 5 but cannot find info on how to combine NTLM and forms.
So that NTLM native login/password dialog is never shown - transparent authentication or nice looking login page.
How should work?
Should user be asked login and password?
Can her current credentials (domain username) be used without asking to enter login and password?
UPDATE for these, investigating same problem:
When I was asking this I was not fully understand how NTLM authentication works internally.
Important thing here to understand is that if user's browser doesn't support NTLM properly or if NTLM support is disabled by user - server will never get chance to work around this.
How Windows authentication is working:
Client send a regular HTTP request to server
Server responds with HTTP status 401 and indication that NTLM authentication must be used to access resources
Client send NTLM Type1 message
Server responds with NTLM Type2 message with challenge
Client send Type3 message with response to challenge
Server responds with actual content requested
As you see, browser not supporting NTLM will not go to step (3), instead user will be shown IIS generated Error 401 page.
If user doesn’t have credentials, after cancelling NTLM authentication popup dialog window browser will not continue to (3) as well.
So we have no chance to automatically redirect users to custom login page.
The only option here is to have a “gateway” page where we decide if user should support NTLM and if so, redirect to NTLM protected home page.
And if not, show login form and allow authentication by manually entering login and password.
Decision is usually made based on users’ IP address and/or host name either by matching IP ranges or by checking table of predefined IPs.
This article might get you pointed in the right direction. Basically you have two apps in two virtual directories under the same host name. One app uses Forms authentication, one uses Windows. The one using Windows authentication creates a valid form authentication cookie and redirects to the second virtual directory.
ASP.NET Mixed Mode Authentication
I have this exact setup in production, I setup my portal to use FormsAuth and wrote a function that takes the visitors IP to look up the user account that is logged in to that IP / PC. Using the name I find (eg. DOMAIN\user), I verify the domain matches my domain and that the user name / account is valid in my FormsAth provider using Membership.GetUser(<user>). If this call returns a match and the user IsApproved I create a FormsAuthenticationTicket & cookie for the user. I have 400+ people on the network and this works perfectly, the only computers that still login are (1. Users without accounts in my portal, 2. A few MAC/Linux users, 3. Mobile users who did not boot on the network and had Group Policy enable their Firewall to High).
The catch to this solution is that it requires impersonation of a domain admin account to query the users PC, and that you use unmanaged code netapi32.dll.
Here is the code I use (external function calls not provided, for brevity). I've tried to simplify this a bit, since have LOTS of external calls.
string account = String.Empty;
string domain = String.Empty;
string user = String.Empty;
ImpersonateUser iu = new ImpersonateUser(); //Helper that Enabled Impersonation
if (iu.impersonateValidUser(StringHelper.GetAppSetting("DomainAccount"), StringHelper.GetAppSetting("DomainName"), StringHelper.GetEncryptedAppSetting("DomainAccountPassword")))
{
NetWorkstationUserEnum nws = new NetWorkstationUserEnum(); //Wrapper for netapi32.dll (Tested on Vista, XP, Win2K, Win2K3, Win2K8)
string host = nws.DNSLookup(Request.UserHostAddress); // netapi32.dll requires a host name, not an IP address
string[] users = nws.ScanHost(host); // Gets the users/accounts logged in
if (nws.ScanHost(host).Length > 0)
{
string workstationaccount = string.Empty;
if (host.IndexOf('.') == -1) // Pick which account to use, I have 99.9% success with this logic (only time doesn't work is when you run a interactive process as a admin e.g. Run As <process>).
{
workstationaccount = String.Format("{0}\\{1}$",StringHelper.GetAppSetting("DomainName"), host).ToUpper();
}
else
{
workstationaccount = String.Format("{0}\\{1}$", StringHelper.GetAppSetting("DomainName"), host.Substring(0, host.IndexOf('.'))).ToUpperInvariant();
}
account = users[users.Length - 1].Equals(workstationaccount) ? users[0] : users[users.Length - 1];
domain = account.Substring(0, account.IndexOf("\\"));
user = account.Substring(account.IndexOf("\\") + 1,
account.Length - account.IndexOf("\\") - 1);
}
iu.undoImpersonation(); // Disable Impersonation
}
Now using the account we grabbed in the first function/process, we now try to verify and decide if we should show a login or auto-login the user.
MembershipUser membershipUser = Membership.GetUser(user);
if (membershipUser != null && membershipUser.IsApproved)
{
string userRoles = string.Empty; // Get all their roles
FormsAuthenticationUtil.RedirectFromLoginPage(user, userRoles, true); // Create FormsAuthTicket + Cookie +
}
I wrote a blog post about this a long time ago, here is a link to the wrapper for netapi32.dll and my Impersonation helper that I provided in the post Source Code Download
You cannot have both NTLM and FormsAuthentication in the same ASP.NET application. You will need two different applications in separate virtual directories.

reusable "save credentials" dialog (like IE's or Vista's) in .NET or Win32

Lately I've been working in an office with a wireless network which uses an annoying authentication scheme: every few hours, you need to open up a browser and type a username/password into an authentication web page, or you lose network access. (When the time expires, your next browser request will redirect to the auth page, and if your creds pass muster, then you'll be redirected back to the page you were trying to get to originally).
This kind of annoyance may be OK for an airport or coffee shop wireless, but in an office it's infuriating-- especially if you're working with network services (e.g. SVN, email) which suddenly stop working every few hours unless you bring up a browser.
So I have written a tiny C# console app which will log in for me by sending an HTTP request to the login form with my credentials.
This is obviously insecure-- my password is sitting inside my source code for all to see. I'd prefer to be able to save my credentials using the same mechanism that IE, for example, uses to save and re-fill passwords in web forms.
Ideally, I'd like a re-usable component for entering, saving, and retrieving credentials(including the UI with an optional "save creds" checkbox) so that my app can simply do something like this (in pseudocode):
// retrieve any saved credentials from some secure place
Credentials creds = GetCreds(some parameters go here);
// if none stored, then show the user an "enter and optionally save credentials" dialog
if (creds == null)
creds = GetCredsDialog(some parameters go here);
// POST to the authentication page
if (creds != null)
{
string authUrl = "https://somehost/login/";
string postDataPattern = "post data pattern here";
// use SecureString here instead?
string postData = string.Format (postDataPattern, HttpUtility.HtmlEncode(creds.Username), HttpUtility.HtmlEncode(creds.Password));
WebClient wc = new WebClient();
string html = wc.UploadString (authUrl, "POST", postData);
// TODO: if html indicates login failure, clear stored credentials
// and ask for new creds. then retry.
}
Essentially I want to shift the burden of securely storing creds from my app to Windows, under the assumption that the Windows guys will be better at this than I will be. :-)
I'm not looking for iron-clad security here, just something comparable to what IE is using to secure my other stored passwords for other websites. I just don't want to keep plain text passwords in my code!
Of course, the right solution here is to work with the IT department to get them to get a real authentication scheme for Wireless, but in the meantime I'm on my own.
A .NET solution would be preferable, but a Win32 solution would be OK too-- I could simply port the app to C++ without much trouble.
To store the credentials, use the ProtectedData class in System.Security.dll.
By passing DataProtectionScope.CurrentUser, no other user will be able to decrypt the data.
EDIT: For the dialog, you can use the CredUIPromptForCredentials API function
See here for a .Net wrapper.

Categories