Asp.net forms authenticated webservice - c#

I have a small conundrum where I have an asp.net application that's using forms based authentication. Inside of the application, I have a webservice that checks User.IsInRole("somerole") which works fine with ajax calls from the application since the user is logged in, and the ajax calls come from his logged in browser.
Now, I want to make a fat client call the webservices (c# console client for starters), but cant figure out how to pass the credential information to it.
I've looked at doing something like the following to no avail:
SomeWebService svc = new SomeWebService();
svc.Credentials = new NetworkCredential("formsusername","formspassword","");
String returnValue = svc.CallMyWebMethod();
Can anyone out there show me the trick to this? :-)
Thanks!

Forms Authentication works by having the client send a Cookie along each request. This cookie is emitted by the server when the client successfully authenticates by sending the correct credentials.
So here are the steps that you need to do in your console application in order to authenticate the user using forms authentication:
Send an HTTP POST request to some web page passing the username and password. In response the web server will give you the authentication cookie (Set-Cookie HTTP response header) that you need to capture. That's usually your Log page.
When calling your web service you need to pass this cookie (Cookie HTTP request header). In order to set a cookie along with the request, you will have to override the GetWebRequest method on the client proxy class that was generated for you:
protected override WebRequest GetWebRequest(Uri uri)
{
var request = (HttpWebRequest)base.GetWebRequest(uri);
request.CookieContainer.Add(
new Cookie(
".ASPXAUTH",
"THE VALUE YOU HAVE RETRIEVED WHEN YOU SEND YOUR FIRST LOGON REQUEST"
)
);
return request;
}

Related

HttpWebRequest with impersonation

I am working on an application in an environment where users have NTLM, single-sign-on authentication for all applications. Basically, the applications open and they are recognized by gathering information from the user's profile. The application I am working on is an extension to an existing Web Application. This application uses impersonations with an existing service account in Active Directory. Now, inside my application I do a System.Net.HttpWebRequest to a second server that is running a data service. When I place the request I do this:
System.Net.HttpWebRequest request = System.Net.WebRequest.Create(URL) as System.Net.HttpWebRequest;
request.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
request.Method = "Get";
using (System.Net.HttpWebResponse response = request.GetResponse() as System.Net.HttpWebResponse)
{ ...
As you can see I set the credentials to DefaultNetworkCredentials to make sure that whoever is logged the credentials will be passed in the request. It works well when I tried from the VM hosting my the application. So, if I place the request to my application inside the hosting VM as http://localhost/myapplication it all works fine. However, when I call the same application from outside the VM with the explicit server name as in http://myservername/myapplication, then the secondary server I am requesting the data from rejects the call with a 401 Unauthorized error.
Any ideas? How can I trace what is happening? I tried Fiddler and I do not see anything going on.
Thanks in advance!
UDPATE: I changed the account the application pool runs on to an admin user. I got the same result.

MVC 5 Authentication and HttpClient No MediaTypeFormatter is available

I have a MVC 5 Web Api and a desktop app that connects to it.
I have a controller and connect to it from the app without any issue, but when I put the [Authorize] attribute in the controller, the httpclient in desktop app stops working and says that there is not MediaTypeFormatter available.
I think the HttpClient is working fine, I tried defining authentication using the request header:
httpClient.DefaultRequestHeaders.Authorization
and using this way httpclient = new HttpClient(new HttpClientHandler { Credentials = new NetworkCredential("UserName", "password") });.
In the pass using MVC 4 it works with authentication.
In this case, wit MVC 5, it works perfectly when using Anonymous, but when I authenticate I get this exception in the httpresponse.Content.ReadAsAsync
No MediaTypeFormatter is available to read an object of type 'Dictionary`2' from content with media type 'text/html'.
Where should I see?
Update
I read the httpResponse as a string, to see what the httpclient is getting and I in the string the HTML of the login page. Aparently the authentication fails and the MVC + API redirects to the login page.
What should I do now?
Why the authentication doesnt work like in the previous MVC 4 web API? Is because the new OWIN authentication?
These issue was because the authentication was not working. MVC5 use Web Forms authentication, so I had to cread a new way to authenticate the HttpClient.
Make a Get to the /Account/Login page and read the _RequestVerificationToken
Post to /Account/Login the UserName, Password, and _RequestVerificationToken
The error was because, when authentication fails, MVC5 redirects the HttpClient to the Login Page. So I was not getting JSON, I was getting HTML. The HTML of the Login Page.
Try:
httpClient.Accept = "text/html,application/xhtml+xml,application/json";
This article should be helpful.
http://www.asp.net/web-api/overview/security/basic-authentication
It is telling us that we need to implement the authentication handler for Web API.
And I think Web API is a stand alone project type in VS2013, make sure you are not using MVC which is using forms authentication by default.
If you have to use the whole MVC package, then you have to make a http post to login page like Ricardo Polo said, and then attach the cookie you got to every api call. For example:
HttpWebRequest request = (HttpWebRequest)System.Net.WebRequest.Create(string.Format("https://{0}/login", server));
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
bool loginSuccess = false;
if (response.StatusCode == HttpStatusCode.OK)
{
//If there's a cookie in the response, it means login successful,
//and the cookie is the one returned by the server that can be used to identify
//the client when calling Authorized api calls.
loginSuccess = (response.Cookies.Count > 0);
}
response.Close();
//Now make a request to the api
HttpWebRequest ApiRequest = (HttpWebRequest)System.Net.WebRequest.Create(string.Format("https://{0}/api/values", server));
ApiRequest.CookieContainer = new CookieContainer();
ApiRequest.CookieContainer.Add(response.Cookies[0]);
//From here add code to get the response.
The above code can be done using HttpClient.
I have exception like that when my Action input parameter was Dictionary, i solved it by creating custom Model which holds all my input parameters and Dictionary and after that it was working
MVC 5 Web API (Web API 2) templates in Visual Studio uses Token based OWIN middle-ware for authentication.
Read the following article:
Authenticate and Get a Bearer Token
http://www.asp.net/vnext/overview/authentication/individual-accounts-in-aspnet-web-api
In the Fiddler Composer tab, enter the following URL (remember to change "port" to the actual port number):
http://localhost:port/Token
Leave the request method as POST. Change the Content-Type header to application/x-www-form-urlencoded. Replace the request body with the following:
grant_type=password&username=Alice&password=password123
Click Execute to send the request. Here is the raw HTTP request:
POST http://localhost:49436/Token HTTP/1.1
User-Agent: Fiddler
Host: localhost:49436
Content-Type: application/x-www-form-urlencoded
Content-Length: 55
grant_type=password&username=Alice&password=password123
In MVC 5 Web API templates you can enable cookie based authentication but to get Authenticated you need to use the /Token end point by sending a Http Post message with the form body having three fields 1. grant_type 2. username 3. password.
In response to this message you will get a JSON object in which you can find access_token (which you can ignore if you dont want to use Token based authorization) and the server will set a cookie if the use cookie authentication is configured (default). By default controllers derived from ApiControllers does not use cookie authentication in some of the VS templates. You need to store the access_token and place it in header of all further requests to ApiController's. Http header should be like:
Authorization: Bearer [place_accesstoken_without_sorrunding_braces]

check if a web service using authentication is available for a specific login (combo of user and password)

I am doing a http get to an url of a webservice, which is actually a WCF hosted in IIS using binding transport with credentials.
I want to check if I can do a call to that service using a specific login. How can write the httpget request to do that?
Have you tried setting HttpWebRequest.Credentials property? Something like request.Credentials = new NetworkCredential("login", "password") . See link: http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.credentials.aspx

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 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