I wanted to implement this solution to handle antiforgery in ajax requests. I know there are other solutions but this is the one I like most.
The problem is I have to deal with System.Web.Webpages 1.0 so I cannot make use of AntiForgeryConfig.CookieName in my code.
public override void OnAuthorization(AuthorizationContext filterContext)
{
var request = filterContext.HttpContext.Request;
// Only validate POSTs
if (request.HttpMethod == WebRequestMethods.Http.Post)
{
// Ajax POSTs and normal form posts have to be treated differently when it comes
// to validating the AntiForgeryToken
if (request.IsAjaxRequest())
{
string cookieName = AntiForgeryData.GetAntiForgeryTokenName(context.Request.ApplicationPath);
var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];
var cookieValue = antiForgeryCookie != null
? antiForgeryCookie.Value
: null;
AntiForgery.Validate(cookieValue, request.Headers["__RequestVerificationToken"]);
}
else
{
new ValidateAntiForgeryTokenAttribute()
.OnAuthorization(filterContext);
}
}
}
How can I retrieve (programmatically) the cookie name set by the antiforgery system in Mvc3? I suspect the AntiForgery.Validate part will also be a problem but I'll handle that before. Any thoughts?
The actual cookie name always starts from "__RequestVerificationToken" with some suffix. So you can find the cookie like this:
private static string FindCookieValueByName(HttpRequestBase request)
{
return request.Cookies
.Cast<string>()
.Where(cn => cn.StartsWith("__RequestVerificationToken", StringComparison.OrdinalIgnoreCase))
.Select(cn => request.Cookies[cn].Value)
.FirstOrDefault();
}
Related
The EU General Data Protection Regulation (GDPR) will come into effect from 25th May 2018. One can read in detail here. This time it has to be all opt-in and they have very heavy fine (€20 million or 4% of global earning!).
Since, it has to be all opt-in(at least in our case), we have decided user accepts our cookies to receive our services.
We will not be logging out current users to give us concept, however, we will present them consent page when they come into one of our sites. If they say yes then we will save an "accept-cookie" or else they won't be able to come into our sites. Afterwards, whenever a use logs into our site, we check the existence of this cookie.
My idea in implementing this solution is to intercept the user request and check the existence of accept-cookie and redirect to the requested resource or controller in our case as we will asp.net mvc accordingly.
My question is can I do this using RegisterRoutes to route request to a controller and if yes, redirect to the requested controller?
What about this solution? Though, the solution is for different aspect. I have modified the variables name from language to consent to make it more meaningful(not trying to copy):
public class EnsureLanguagePreferenceAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var euCookie = filterContext.HttpContext.Request.Cookies["ConsentCookies"];
if (euCookie == null)
{
// cookie doesn't exist, redirect use to a View showing
//all the cookies being saved in client machine
// and to take user consent(accept or deny)
}
// do something with euCookie
base.OnActionExecuting(filterContext);
}
}
As this rule comes into effect on 25th May 2018, it would be nice to hear your idea regarding different kind of implementation.
Finally, I came up with something that I wanted--intercepting user request and redirecting based upon a certain cookie. This can be used as a nuget as we have multiple applications and saving cookies could be done from one of the application. As it is made as an action filter attribute, it can be place above controller:
[MyAcceptCookieCheck]
public class HomeController : Controller
This makes it easy to implement across all application and operations regarding saving cookies will be done from the one of the application so that it will be easy to make any changes i.e., only from one place.
public class MyAcceptCookieCheck : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var cookies = filterContext.HttpContext.Request.Cookies["OurAcceptCookie"];
var values = filterContext.RouteData.Values.Values;
originalRequest = filterContext.HttpContext.Request.Url.AbsoluteUri;
RouteValueDictionary requestOrigin = new RouteValueDictionary { {
"url", originalRequest } };
if (cookies == null && !values.Contains("CookieConsent")) //so that it won't loop endlessly
{
UrlHelper urlHelper = new UrlHelper(filterContext.RequestContext);
//filterContext.Result = new RedirectResult(urlHelper.Action("CookieConsent", "Home"));
filterContext.Result = new RedirectResult(urlHelper.Action("CookieConsent","Cookie",requestOrigin ,"https","www.my-domain.com/mysitename"));
}
else if(cookies != null)
{
string controllerName = filterContext.RouteData.Values["controller"].ToString();
string actionName = filterContext.RouteData.Values["action"].ToString();
UrlHelper urlHelper = new UrlHelper(filterContext.RequestContext);
filterContext.Result = new RedirectResult(urlHelper.AbsolutePath(actionName, controllerName));
}
}
}
Code for AbsolutePath (courtesy):
public static string AbsolutePath(this UrlHelper url, string actionName, string controllerName, object routeValues = null)
{
string scheme = url.RequestContext.HttpContext.Request.Url.Scheme;
return url.Action(actionName, controllerName, routeValues, scheme);
}
Now, I can redirect all requests without having that particular cookie to a cookie consent page and show user all the details about cookies being used and ask for permission to save "ConsentCookie".
I'm currently building a Web API but have run into an authorization problem with GET requests. Essentially my problem is how do I authorize requests based on the request parameters. I've tried looking online but the only solution I can find for resource authorization is to create my own authorization filter attribute. So lets say a client belongs to a Fac 8474, so they should be able to get api/fac/8474. But what is stopping the user from getting api/fac/8475? The code below uses a custom auth filter that gets the users claim value for nId. After getting the requested record I check the nId value on the record. If they are equal I allow access, if not I send a 401 unauthorized. However, I will have to write this code for every route and that I don't like the thought of writing extra code for each request which might include even more logic then a simple int check.
class ClaimsAuthorizationFilter : AuthorizationFilterAttribute
{
public override Task OnAuthorizationAsync(HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken)
{
var principal = actionContext.RequestContext.Principal as ClaimsPrincipal;
KeyValuePair<string, object> facId = actionContext.RequestContext.RouteData.Values.Where(p => p.Key == "facId").SingleOrDefault();
Claim nIdClaim = principal.Claims.Where(p => p.Type == "nId").SingleOrDefault();
if (nIdClaim == null) {
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
return Task.FromResult<object>(null);
}
SM msg = ClientAPI.GenerateResponse("FAC_GET", Convert.ToInt32(facId.Value));
dtoFac fac = (dtoFac)msg.Data;
if (nIdClaim.Value != fac.nId.ToString())
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
return Task.FromResult<object>(null);
}
return Task.FromResult<object>(null);
}
}
I've also looked at this example http://jakeydocs.readthedocs.io/en/latest/security/authorization/resourcebased.html Essentially getting the resource then checking the nId which I also implemented and it works.
var identity = User.Identity as ClaimsIdentity;
Claim nId = identity.Claims.Where(p => p.Type == "nId").SingleOrDefault();
if (nId == null) {
return NotFound();
}
// Get list of resources named bat
if (!IEnumAuthCheck(bat, nId.Value)) {
return NotFound();
}
private bool IEnumAuthCheck(IEnumerable<bat> list, string nId)
{
foreach (bat element in list)
{
if (element.nId != Convert.ToInt32(nId))
{
return false;
}
}
return true;
}
My main question is, what if any are the recommended patterns for solving this issue? Resource based authentication for ids seem like it would be a very common issue but there is a distant lack of articles about it.
I'm currently having an issue with cookies in my Web Application.
First of all, i created 2 generic methods into my controller to simplify my cookie manipulation. Here they are :
public bool SetCookie<T>(string key, T value)
{
try
{
string str = Utils.JSONParser.Serialize(value);
var cookie = new HttpCookie(key, Utils.JSONParser.Serialize(value))
{
HttpOnly = true
};
cookie.Expires = DateTime.UtcNow.AddDays(365);
Response.SetCookie(cookie);
return true;
}
catch (Exception ex)
{
throw ex;
}
}
public T GetCookie<T>(string key)
{
T obj;
if (Request.Cookies[key] != null)
{
HttpCookie cookie = Request.Cookies.Get(key);
obj = Utils.JSONParser.Deserialize<T>(cookie.Value);
return obj;
}
return (typeof(T) == typeof(int) ? (T)(object)-1 : default(T));
}
Note that, theses methods are working perfectly with some "normal" use. (The Utils.JSONParser is a simple encapsulation of JavaScriptSerializer.
I'm having an issue by using this code :
public ActionResult Index(int LineNumber = -1)
{
IndexViewModel model = new IndexViewModel();
if (LineNumber != -1)
this.SetCookie("lineNumber", LineNumber);
model.LineNumber = this.GetCookie<int>("lineNumber");
....
}
Here, LineNumber's value is for example 5, and the current cookie value is (for example) 20. So, here i wanna erase 20, and put 5 instead. But this isn't happening. I have to pass through this method 2 times (with 5 as parameter) to finally store 5 in the cookie value.
So my question is, is there a loading time to store a cookie ? Which would explain this ? Or am i simply missing something ?
Notice how your SetCookie method changes the Response while your GetCookie method gets the value from your Request. So only when you finish your entire request processing and then get a second request will the cookie set in the request be the cookie you set in the first response.
I used following code to implement Basic Authentication filter in my ASP.Net MVC app. everything is working good in local machine while it's not working in production server and it keeps prompting login box because Request.Headers["Authorization"] is null.
I used fiddler to get headers for this request and Authorization header was there with expected values. I have no idea why Request.Headers["Authorization"] is always null :|
I also created a new project only with this filter and one controller and published in server, guess what !? it's working...
public class RequireBasicAuthenticationAttribute : ActionFilterAttribute
{
public string BasicRealm { get; set; }
protected string Username { get; set; }
protected string Password { get; set; }
public RequireBasicAuthenticationAttribute()
{
this.Username = System.Configuration.ConfigurationManager.AppSettings["ProtectedUsername"];
this.Password = System.Configuration.ConfigurationManager.AppSettings["ProtectedPassword"];
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var req = filterContext.HttpContext.Request;
var auth = req.Headers["Authorization"];
auth.LogText();
if (!string.IsNullOrEmpty(auth))
{
var cred = System.Text.ASCIIEncoding.ASCII.GetString(Convert.FromBase64String(auth.Substring(6))).Split(':');
var user = new { Name = cred[0], Pass = cred[1] };
if (Username.Equals(user.Name, StringComparison.InvariantCultureIgnoreCase) && Password.Equals(user.Pass)) return;
}
var res = filterContext.HttpContext.Response;
res.StatusCode = 401;
res.AddHeader("WWW-Authenticate", String.Format("Basic realm=\"{0}\"", BasicRealm ?? "bimeh-takmili"));
res.End();
}
}
Just looking at your code I don't see how it runs at all, production or otherwise.
I would suggest it's throwing an error that your code is swallowing since the code below closes the response and then tries to call the base method.
public override void ExecuteResult(ControllerContext context)
{
if (context == null) throw new ArgumentNullException("context");
// this is really the key to bringing up the basic authentication login prompt.
// this header is what tells the client we need basic authentication
var res = context.HttpContext.Response;
res.StatusCode = 401;
res.AddHeader("WWW-Authenticate", "Basic");
res.End();
base.ExecuteResult(context);
}
You cant do this, the code will throw an error:
Server cannot set status after HTTP headers have been sent.
And since it's throwing an error (i think) and being bounced around, it might not be output a 401 status response. The "WWW-Authenticate" header is still being sent however which is why your getting a dialog.
The credentials dialog is popped a when "WWW-Authenticate" is detected but it will only send back an Authorization header in the request if it received a 401 status from the last response.
So if you drop:
base.ExecuteResult(context);
from your code, what happens?
Edit:
Actually dropping
res.End();
would be the way to go. Duh.
I have web application in Asp.Net MVC4 and I want to use cookie for user's login and logout. So my actions as follows:
Login Action
[HttpPost]
public ActionResult Login(string username, string pass)
{
if (ModelState.IsValid)
{
var newUser = _userRepository.GetUserByNameAndPassword(username, pass);
if (newUser != null)
{
var json = JsonConvert.SerializeObject(newUser);
var userCookie = new HttpCookie("user", json);
userCookie.Expires.AddDays(365);
HttpContext.Response.Cookies.Add(userCookie);
return RedirectToActionPermanent("Index");
}
}
return View("UserLog");
}
LogOut Action
public ActionResult UserOut()
{
if (Request.Cookies["user"] != null)
{
var user = new HttpCookie("user")
{
Expires = DateTime.Now.AddDays(-1),
Value = null
};
Response.Cookies.Add(user);
}
return RedirectToActionPermanent("UserLog");
}
And I use this cookie in _Loyout as follow:
#using EShop.Core
#using Newtonsoft.Json
#{
var userInCookie = Request.Cookies["user"];
}
...
#if (userInCookie != null && userInCookie.Value)
{
<li>Salam</li>
<li>Cıxış</li>
}
else
{
<li>Giriş</li>
}
But When I click *UserOut* action this action happen first time, but then it doesn't work. I put breakpoint for looking process but it get UserLog action doesn't UserOut.
My question is that where I use wrong way of cookie? What is a best way using cookie in Asp.Net Mvc4 for this scenario ?
Try using Response.SetCookie(), because Response.Cookies.Add() can cause multiple cookies to be added, whereas SetCookie will update an existing cookie.
We are using Response.SetCookie() for update the old one cookies and Response.Cookies.Add() are use to add the new cookies. Here below code CompanyId is update in old cookie[OldCookieName].
HttpCookie cookie = Request.Cookies["OldCookieName"];//Get the existing cookie by cookie name.
cookie.Values["CompanyID"] = Convert.ToString(CompanyId);
Response.SetCookie(cookie); //SetCookie() is used for update the cookie.
Response.Cookies.Add(cookie); //The Cookie.Add() used for Add the cookie.
userCookie.Expires.AddDays(365);
This line of code doesn't do anything. It is the equivalent of:
DateTime temp = userCookie.Expires.AddDays(365);
//do nothing with temp
You probably want
userCookie.Expires = DateTime.Now.AddDays(365);