Why can't I just send rest calls to MVC3? - asp.net-mvc-3

I'm trying to send requests to my MVC3 app, I've tried regular WebRequest, I'm trying it with RestSharp applying correct Authenticator, but it still returns the redirect result of login page?
What am i doing wrong?
upd: How should I do forms authentication with RestSharp? I guess it's possible somehow - just need to play around that cookie...

If you are getting redirected to a login page your mvc 3 app must be setup for forms authentication. Forms authentication will want a cookie sent with the request. If you are using the basic authenticator in RestSharp this will not work. I assume that you are using the MVC controller to provide a REST API that you are trying to call.
One option is to upgrade to MVC 4 and use the ASP.NET Web API to develop your REST API's. The authorization behavior is a little different in an ASP.NET Web API in that it will return an HTTP 401 error instead of doing a redirect. And you can customize the AuthorizationAttribute to pull the information out of the HTTP header for basic authentication and authorization.
Another option is if the action on the controller does not require authentication/authorization you can put the AllowAnonymousAttribute on the method.

To pass the Forms authentication you gotta get the cookie and stick it to RestSharp's cookie container. To get the cookie you can use just regular WebRequest.
private Cookie GetAuthCookie(string user, string pass)
{
var http = WebRequest.Create(_baseUrl+"Users/Login") as HttpWebRequest;
http.AllowAutoRedirect = false;
http.Method = "POST";
http.ContentType = "application/x-www-form-urlencoded";
http.CookieContainer = new CookieContainer();
var postData = "UserName=" + user + "&Password=" + pass + "&RememberMe=true&RememberMe=false&ReturnUrl=www.google.com";
byte[] dataBytes = System.Text.Encoding.UTF8.GetBytes(postData);
http.ContentLength = dataBytes.Length;
using (var postStream = http.GetRequestStream())
{
postStream.Write(dataBytes, 0, dataBytes.Length);
}
var httpResponse = http.GetResponse() as HttpWebResponse;
return httpResponse.Cookies[FormsAuthentication.FormsCookieName];
}

Related

Subdomain webapi (asp.net mvc) responds on direct requests, but not from requests at the same domain

WebSite : domain.com
Api : api.domain.com
If I make a direct request to localhost api, it works correctly.
If I make a direct request to hosted api, it works correctly.
But if I make a request from a web site on the same domain, it does not work.
When I make a request from web site to another hosted domain with the same api, it also works.
I also tried from a website with a javascript request. First I didn't work, but after adding <add name="Access-Control-Allow-Origin" value="*" />, it does work.
It is clear that the problem is related to the subdomain. How can I do a same domain website request to get a response from the controller? It looks like it has to do with routing..
Thanks
Thanks for advices..
I try to set CORS settings. I follow this doc (https://learn.microsoft.com/tr-tr/aspnet/web-api/overview/security/enabling-cross-origin-requests-in-web-api)
I forget to say my first post. Website (https://domain.com.tr) works on https but api (http://api.domain.com.tr) works on http
These steps are applied
config.EnableCors(); added webapi project
[EnableCors(origins: "https://domain.com.tr", headers: "*", methods: "*")] added top of the ValuesController : ApiController in webapi project
Then i make a request from other project https://domain.com.tr but it fails again which is my code below
/***NOT WORK***/
string apiUrl = "http://api.domain.com.tr/api/";
/***WORK PROPERLY***/
//string apiUrl = "http://otherdomain.com/api/";
/***WORK PROPERLY***/
//string apiUrl = "http://localhost:57232/api/";
IEnumerable<Modul> students = null;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(apiUrl);
//HTTP GET
var responseTask = client.GetAsync("GetPages");
responseTask.Wait();
/***AFTER THİS LINE GIVE ERROR***/
var result = responseTask.Result;
enter image description here

How can I validate a received token in Asp.NET WebAPI?

My project contains an ASP.NET MVC application (with no authentication) and two Web APIs.
The first API (Account API) is built on top of Owin middleware, using ASP.NET identity, in order to have a token-based authentication for ASP.NET MVC.
This works very fine for ASP.NET MVC.
But the second API is a data handler API (Data API).
The problem is that I need to authorize the incoming requests on Data API. From the ASP.NET MVC application, I have the following request.
Start Edit 1
// The MVC controller makes a request in order to authenticate the user.
// If the authentication succeeds, an access token is returned.
var authorizationUrl = "my.authorization.api";
HttpResponseMessage result = httpClient.PostAsync(authorizationUrl, content).Result;
// In the Home controller I have these lines of code.
var user = ((ClaimsPrincipal) HttpContext.Current.User);
var token = x.Claims.First(t => t.Type == "AccessToken").Value;
// Now I just need to call the Data API.
var dataUrl = "my.data.api/home";
var request = WebRequest.Create(dataUrl) as HttpWebRequest;
request.Method = WebRequestMethods.Http.Get;
request.ContentType = "application/json";
request.Headers.Add("Authorization", "Bearer " + accessToken);
var response = (HttpWebResponse) request.GetResponse();
The data API has an [Authorize] attribute on HomeController and I receive 401 Unauthorized every time I call any method.
End Edit 1
The questions is: how can I validate the incoming request (on Data API) using the accessToken from request's header (sent from MVC application)?
Thank you!

Add facebook parameter display=popup when using Spring SocialAuthenticationFilter

I need to display the facebook social login in a popup window.
In order that facebook login dialog is displayed with minimal decoration, I want to add the facebook parameter display=popup.
But I'm not using Spring Social's ConnectController - in that case I could add the parameter via an interceptor.
Instead I'm using Spring Social's SocialAuthenticationFilter. How can I add display=popup in this scenario?
If you post some code which you use to implement authentication via Facebook, that would help. We're using Spring Social to provide "login via Facebook functionality" for our website. There is related code:
ConnectionFactory connectionFactory = connectionFactoryLocator.getConnectionFactory(providerType);
Method getOAuthOperationsMethod = connectionFactory.getClass().getMethod("getOAuthOperations");
Object oauthOperations = getOAuthOperationsMethod.invoke(connectionFactory);
OAuth2Parameters params = new OAuth2Parameters();
params.setRedirectUri("your redirect URL");
params.setScope("email");
params.put("display", Collections.singletonList("popup"));
params.setState(state);
authorizeUrl = ((OAuth2Operations) oauthOperations).buildAuthorizeUrl(GrantType.AUTHORIZATION_CODE, params);
return "redirect:" + authorizeUrl;
authorizeUrl yields string which looks like this:
https&colon;//www.facebook.com/v2.5/dialog/oauth?client_id=1234&response_type=code&redirect_uri=http%3A%2F%2Fwww.company.com%2Fcallback&scope=email&display=popup&state=8fb43b90-be0f-4d3d-9ee6-8cb1641f08b5

CSRF for Ajax request across applications in one Domain

We have MVC 4 application which is hosted on Web Farm. Site has 5 applications hosted under one domain. These applications communicate with each other. We are implementing Cross Site Request Forgery for our application. We have added AntiForgeyToken(#Html.AntiForgeryToken()) on Layout page. When we try to post data actions across applications using Ajax request, we are facing below exception-
Exception:
The anti-forgery token could not be decrypted. If this application is hosted by a Web Farm or cluster, ensure that all machines are running the same version of ASP.NET Web Pages and that the configuration specifies explicit encryption and validation keys. AutoGenerate cannot be used in a cluster.
For Ajax request we have added “__RequestVerificationToken” value into prefilter as shown below-
Client side implementation:
$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
if (options.type.toLowerCase() == "post") {
if ($('input[name="__RequestVerificationToken"]').length > 0)
jqXHR.setRequestHeader('__RequestVerificationToken',
$('input[name="__RequestVerificationToken"]').val());
}});
On Server side we validated this token as shown below-
string cookie = "";
Dictionary<string, object> cookieCollection = new Dictionary<string, object>();
foreach (var key in HttpContext.Current.Request.Cookies.AllKeys)
{
cookieCollection.Add(key, (HttpContext.Current.Request.Cookies[key]));
}
var res= cookieCollection.Where(x => x.Key.Contains("RequestVerificationToken")).First();
cookie = ((System.Web.HttpCookie)(res.Value)).Value;
string formToken = Convert.ToString(HttpContext.Current.Request.Headers["__RequestVerificationToken"]);
if(string.IsNullOrEmpty(formToken))
{
//To validate HTTP Post request
AntiForgery.Validate();
}
else
{
//To validate Ajax request
AntiForgery.Validate(cookie, formToken);
}
Other configurations which we have done are as below-
We have machine key in config which is same for all applications as well as on all web servers.
We have set AntiForgeryConfig.CookieName = "__RequestVerificationToken" + "_XYZ" cookie name across all applications which is mandatory to access token across applications.
Changes which we tried to resolve this issue-
We tried to post “__RequestVerificationToken” inside each ajax request’s data so that we can access it using Request.Form but no success on this.
We have verified that Content-Type header is appearing with each request.
Please suggest if you have any other way to implement CSRF functionality for Ajax POST requests across multiple applications.

Https and Http only on .net webapi v2 actions

I have been working on a project with webapi 2 using oauth 2 (openid connect to be precise) bearer tokens to grant access. Now the whole idea is that the bearer tokens are only secure if used with a secure connection.
Until now I have simply not allowed http calls to the webserver which kinda worked since no one could do a http call with a bearer token.
We now have some endpoints that need to be avaible over http (no bearer token/authenticaiton required) and we are going to enable http of course. Now my question is, what is normal in these situations?
Would I have an attribute that I can put on all actions that only accept https?
Can I make that the default behaviour and only put attribute on those that are okay on http?
What is the advice on, is it our responsibility that no one use a oauth token over a non secure line or is the user of the api ?
I believe the right way to do this is to add global action filter which forces you to use HTTPs on all controllers/actions on your Web API. The implementation for this HTTPs action filter can be as the below:
public class ForceHttpsAttribute : AuthorizationFilterAttribute
{
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
{
var request = actionContext.Request;
if (request.RequestUri.Scheme != Uri.UriSchemeHttps)
{
var html = "<p>Https is required</p>";
if (request.Method.Method == "GET")
{
actionContext.Response = request.CreateResponse(HttpStatusCode.Found);
actionContext.Response.Content = new StringContent(html, Encoding.UTF8, "text/html");
UriBuilder httpsNewUri = new UriBuilder(request.RequestUri);
httpsNewUri.Scheme = Uri.UriSchemeHttps;
httpsNewUri.Port = 443;
actionContext.Response.Headers.Location = httpsNewUri.Uri;
}
else
{
actionContext.Response = request.CreateResponse(HttpStatusCode.NotFound);
actionContext.Response.Content = new StringContent(html, Encoding.UTF8, "text/html");
}
}
}
}
Now you want to register this globally on WebApiConfig class as the below:
config.Filters.Add(new ForceHttpsAttribute());
As I understand from your question, the number of controllers you want to call them over https are greater than controllers over http, so you want to add override attribute to those http controllers [OverrideActionFiltersAttribute]
Do not forget to attribute your anonymous controllers with [AllowAnonymous] attribute.
But my recommendation is to keep all the communication over https and you just allow anonymos calls.
You can read more about enforcing https on my blog here: http://bitoftech.net/2013/12/03/enforce-https-asp-net-web-api-basic-authentication/
Hope this helps.
Firstly I think you definitely have to make best efforts to ensure the security of that token and so the server should enforce SSL.
We are using web api v1 (infrastructure restrictions :() and we have a global DelegatingHandler that enforces SSL on all requests except for certain uris that are on a whitelist (not the prettiest solution but it works for now).
In web api 2 I reckon you could have a global FilterAttribute to enforce the SSL connectivity and then use the new attribute override feature http://dotnet.dzone.com/articles/new-filter-overrides-feature to create your exceptions - all theory though ! :)
Hope that helps
Garrett

Resources