CSRF on singlepage using Web Api 2 backend - c#

I'm trying to implement CSRF using AntiForgeryToken from .Net Framework on a single page application. I've implemented some code inside my .csthml file and i've created an AuthorizeAttribute:
Index.cshtml
<script>
#functions{
public string GetAntiForgeryToken()
{
string cookieToken, formToken;
System.Web.Helpers.AntiForgery.GetTokens(null, out cookieToken, out formToken);
return cookieToken + ":" + formToken;
}
}
$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
var xxx = '#GetAntiForgeryToken()';
jqXHR.setRequestHeader("X-CSRF", xxx);
});
</script>
ValidateHttpAntiForgeryTokenAttribute.cs
public class ValidateHttpAntiForgeryTokenAttribute : AuthorizeAttribute
{
protected override bool IsAuthorized(HttpActionContext actionContext)
{
var headers = actionContext.Request.Headers;
var headerToken = headers.Contains("X-CSRF") ? headers.GetValues("X-CSRF").FirstOrDefault() : null;
if (headerToken == null)
{
return false;
}
var tokenValues = headerToken.Split(':');
if (tokenValues.Length < 2)
{
return false;
}
else
{
var cookieToken = tokenValues[0];
var formToken = tokenValues[1];
try
{
AntiForgery.Validate(cookieToken, formToken);
}
catch(Exception ex)
{
return false;
}
}
return base.IsAuthorized(actionContext);
}
}
MyController.cs
[HttpGet]
[ValidateHttpAntiForgeryTokenAttribute]
public HttpResponseMessage Get()
{
...
}
Every time that ValidateHttpAntiForgeryTokenAttribute is called, i got the following error:
The provided anti-forgery token was meant for user "CMP\usr", but the current user is "dev#company.net"
I would like to know why it displays the username of computer instead the username that is logged on application and why the token isn't changing when call GetAntiForgeryToken() is executed.
Thank in advance.

As quick fix (if you don't care about username validation inside anti-CSRF logic) would be:
AntiForgeryConfig.SuppressIdentityHeuristicChecks = true
somewhere in AppStart logic (global.asax).

Related

Webapi AuthorizeAttribute is not allowing me to access methode when its giving Status message as 200

Here i wrote small Authentication as
public override void OnAuthorization
(System.Web.Http.Controllers.HttpActionContext actionContext)
{
var authenticationTokenPersistant = "abc";
base.OnAuthorization(actionContext);
if (actionContext.Request.Headers.GetValues("Authorization") != null)
{
string authenticationToken = Convert.ToString(
actionContext.Request.Headers
.GetValues("Authorization").FirstOrDefault());
authenticationTokenPersistant = authenticationToken;
if (authenticationTokenPersistant == authenticationToken)
{
HttpContext.Current.Response.AddHeader("Authorization", authenticationToken);
HttpContext.Current.Response.AddHeader("AuthenticationStatus", "NotAuthorized");
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.OK);
return;
}
HttpContext.Current.Response.AddHeader("Authorization", authenticationToken);
HttpContext.Current.Response.AddHeader("AuthenticationStatus", "Authorized");
return;
}
actionContext.Response = actionContext.Request
.CreateResponse(HttpStatusCode.ExpectationFailed);
actionContext.Response.ReasonPhrase = "Please provide valid inputs";
}
this function i decorated CustomAuthorize its Executing my function but allowing me to Enter inside ValidateSession()
[CustomAuthorize]
public IHttpActionResult ValidateSesion()
{
return ok("Success..");
}
when i get 200 Response Even though im getting going inside

Angular service function is undefined - MVC6

I am trying to write a login service (in typescript), which posts the username and password to my C# controller. The C# controller then makes a service call that hits my database to authenticate the user, but that is out of scope for this question.
The issue is that when I try to call my authentication function (which is found in my angular service) from my angular controller, I get an error in my console that it is unable to get property 'Authenticate' of undefined or null reference.
Here is the base class (Handler) for my services:
module app.Services {
export class HttpHandlerService {
httpService: ng.IHttpService;
handlerUrl: string;
constructor($http: ng.IHttpService) {
super();
this.httpService = $http;
}
useGetHandler(params: any): ng.IPromise<any> {
var result: ng.IPromise<any> = this.httpService.get(this.handlerUrl, params)
.then((response: any): ng.IPromise<any> => this.handlerResponded(response, params));
return result;
}
usePostHandler(params: any): ng.IPromise<any> {
var result: ng.IPromise<any> = this.httpService.post(this.handlerUrl, params)
.then((response: any): ng.IPromise<any> => this.handlerResponded(response, params));
return result;
}
handlerResponded(response: any, params: any): any {
response.data.requestParams = params;
return response.data;
}
}
}
Then my login service inherits it:
module app.Services {
export interface ILoginService {
Authenticate(email: string, password: string): ng.IPromise<any>;
}
export class LoginService extends Services.HttpHandlerService {
static $inject = ['$http'];
constructor($http: ng.IHttpService) {
this.handlerUrl = '/Login';
super($http);
}
// Authentication function I am attempting to call
Authenticate(email: string, password: string): ng.IPromise<any> {
// I have not completed the actual request that is being sent
var config: any = {};
var request = {
"Email": email,
"Password": password
}
return this.usePostHandler(config);
}
}
angular.module('App').factory('loginService', LoginService);
}
Here is my login controller where I'm calling the service:
module app.Login {
import Services = app.Services;
interface ILoginController {
email: string;
password: string;
login(): void;
}
class LoginController implements ILoginController{
email: string;
password: string;
loginService: Services.ILoginService;
loginForm: any;
static $inject = ["$state"];
constructor(private $state: ng.ui.IStateParamsService, loginService: Services.ILoginService) {
this.email = "";
this.password = "";
this.loginService = loginService;
}
login() {
if (this.loginForm.$invalid) {
return;
}
var request = this.loginService.Authenticate(this.email, this.password);
request.success(function (data) {
console.log("User authenticated.");
});
request.error(function () {
console.log("Error: User not authenticated.");
});
}
}
angular.module('App').controller('loginController', LoginController);
}
And finally my c# controller"
[HttpPost]
[Route("/Login")]
public async Task<IActionResult> Login()
{
// . . . .
}
Any help would be appreciated. Let me know if you need more information.
EDIT:
This is the javascript generated from the login service typescript:
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var app;
(function (app) {
var Services;
(function (Services) {
var LoginService = (function (_super) {
__extends(LoginService, _super);
function LoginService($http) {
this.handlerUrl = '/Login';
_super.call(this, $http);
}
LoginService.prototype.Authenticate = function (email, password) {
var config = {};
var request = {
"Email": email,
"Password": password
};
return this.usePostHandler(config);
};
LoginService.$inject = ['$http'];
return LoginService;
})(Services.HttpHandlerService);
Services.LoginService = LoginService;
angular.module('App').factory('loginService', LoginService);
})(Services = app.Services || (app.Services = {}));
})(app || (app = {}));
I do get an error, only in IE, that _super is undefined.
Unable to get property 'Authenticate' of undefined or null reference. means that this.loginService was not properly injected by Angular.
You can try changing this:
static $inject = ["$state"];
to this:
static $inject = ["$state", "LoginService"];
Proper Dependency Injection in Your AngularJS TypeScript Apps

Login Dialog Appears When User is Not Authorized

In an attempt to implement security in my web app, I created an attribute that derives from AuthorizeAttribute.
public class FunctionalityAttribute : AuthorizeAttribute
{
public string FunctionalityName { get; set; }
protected override bool IsAuthorized(HttpActionContext actionContext)
{
string adGroup = WebConfigurationManager.AppSettings[FunctionalityName];
if (actionContext.RequestContext.Principal.IsInRole(adGroup)) { return true; }
return false; // This causes a login dialog to appear. I don't want that.
}
}
And here is how it's used in my Web API method:
[Functionality(FunctionalityName = "GetApps")]
public IEnumerable<ApplicationDtoSlim> Get()
{
using (var prestoWcf = new PrestoWcf<IApplicationService>())
{
return prestoWcf.Service.GetAllApplicationsSlim().OrderBy(x => x.Name);
}
}
It actually works. But the issue is what happens when I'm not authorized:
I don't want that dialog to come up. I'm already signed in. I want to let the user know that they're not authorized. How do I make it so that login dialog doesn't come up?
You need to also override HandleUnauthorizedRequest
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
System.Web.Routing.RouteValueDictionary rd = null;
if (filterContext.HttpContext.User.Identity.IsAuthenticated)
{
//Redirect to Not Authorized
rd = new System.Web.Routing.RouteValueDictionary(new { action = "NotAuthorized", controller = "Error", area = "" });
}
else
{
//Redirect to Login
rd = new System.Web.Routing.RouteValueDictionary(new { action = "Login", controller = "Account", area = "" });
//See if we need to include a ReturnUrl
if (!string.IsNullOrEmpty(filterContext.HttpContext.Request.RawUrl) && filterContext.HttpContext.Request.RawUrl != "/")
rd.Add("ReturnUrl", filterContext.HttpContext.Request.RawUrl);
}
//Set context result
filterContext.Result = new RedirectToRouteResult(rd);
}
In HandleUnauthorizedRequest, use HttpStatusCode Forbidden because Unauthorized causes a login prompt to display. Here is the entire attribute class.
public class FunctionalityAttribute : AuthorizeAttribute
{
public string FunctionalityName { get; set; }
protected override bool IsAuthorized(HttpActionContext actionContext)
{
string adGroup = WebConfigurationManager.AppSettings[FunctionalityName];
if (actionContext.RequestContext.Principal.IsInRole(adGroup)) { return true; }
return false;
}
protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
{
// Authenticated, but not authorized.
if (actionContext.RequestContext.Principal.Identity.IsAuthenticated)
{
// Use Forbidden because Unauthorized causes a login prompt to display.
actionContext.Response = new HttpResponseMessage(HttpStatusCode.Forbidden);
}
}
}
And this is how I'm handling it in my angular repository:
$http.get('/PrestoWeb/api/apps/')
.then(function (result) {
// do success stuff
}, function (response) {
console.log(response);
if (response.status == 403) {
$rootScope.setUserMessage("Unauthorized");
callbackFunction(null);
}
});

Not able to delete the cookies on logout

//Interface--Injecting into controller
public interface IContext
{
HttpRequestBase Request { get; }
HttpResponseBase Response { get; }
}
//Implementation
public class Context : IContext
{
public HttpRequestBase Request { get { return new HttpRequestWrapper(HttpContext.Current.Request); } }
public HttpResponseBase Response { get { return new HttpResponseWrapper(HttpContext.Current.Response); } }
}
//Setting Cookie on login.
SetCookie(_context, login);
public void SetCookie(IContext context, Login login)
{
var loginDetails = new JavaScriptSerializer().Serialize(login);
var cokie = new HttpCookie("login", login);
context.Response.Cookies.Add(cokie);
}
//Trying to Logout.
public ActionResult Logout()
{
foreach (var key in _context.Request.Cookies.AllKeys)
{
try
{
_context.Response.Cookies.Remove(key); //this didn't work
//tried this even this is not working
var login = new Login {Identity = "", LogIn = false};
_login.SetCookie(_context, login);
}
catch (Exception e)
{
}
}
_context.Response.Cookies.Clear(); //this didn't work either
return RedirectToAction("Index", "Login");
}
On Login Index when I check the current login cookie value it always has the value of the logged in user is just not getting set to null or empty.
I suspect there is something wrong in the Implementation of the IContext. Should there be a setter on it? Not sure..
Also Tried:
var cokie = context.Request.Cookies["login"];
cokie.Expires = DateTime.Now.AddDays(-2);
cokie.Value = null;
context.Response.Cookies.Add(cokie);
You can use the below code if you are using forms authentication. It will clear all the required cookies
FormsAuthentication.SignOut();
Session.Abandon();
Alternatively you can use
Session.Abandon();
Response.Cookies.Clear();
or
YourCookies.Expires = DateTime.Now.AddDays(-1d);
For more information please visit
MSDN Cookie Help
If to log user in you use
SignInManager.PasswordSignInAsync(...)
you can try
AuthenticationManager.SignOut();
instead of
_context.Response.Cookies.Clear();

ASP.Net Web API with Digest Authentication

I have written a bunch of restful ASP.Net Web API and I want to authenticate some of the API. I have gone with Digest Authentication implementation from here
Also I have referred demo code from here
I have understood the code a bit but I have no idea where and how do I connect my existing database for getting data from customer table. If anyone has information regarding how to achieve this then please share.
Following are some methods for authentication:
DigestAuthorizationFilterAttributeBase.cs
protected override string GetAuthenticatedUser(HttpActionContext actionContext)
{
var auth = actionContext.Request.Headers.Authorization;
if (auth == null || auth.Scheme != Scheme)
return null;
var header = DigestHeader.Create(
actionContext.Request.Headers.Authorization.Parameter,
actionContext.Request.Method.Method);
if (!DigestNonce.IsValid(header.Nonce, header.NounceCounter))
{
return null;
}
var password = GetPassword(header.UserName);
var hash1 = String.Format(
"{0}:{1}:{2}",
header.UserName,
header.Realm,
password).ToMd5Hash();
var hash2 = String.Format(
"{0}:{1}",
header.Method,
header.Uri).ToMd5Hash();
var computedResponse = String.Format(
"{0}:{1}:{2}:{3}:{4}:{5}",
hash1,
header.Nonce,
header.NounceCounter,
header.Cnonce,
"auth",
hash2).ToMd5Hash();
return header.Response.Equals(computedResponse, StringComparison.Ordinal)
? header.UserName
: null;
}
DigestAuthorizationFilterAttribute.cs
public DigestAuthorizationFilterAttribute(bool issueChallenge = true) : base(issueChallenge)
{
}
protected override bool IsUserAuthorized(string userName)
{
return true;
}
protected override string GetPassword(string userName)
{
return userName;
}
One example would be in the following method:
protected override bool IsUserAuthorized(string userName)
{
return true;
}
You could do something roughly similar to:
protected override bool IsUserAuthorized(string userName)
{
var user = db.Users.Where(u => u.username = userName);
if(user.Any())
{
return true;
}
else
{
return false;
}
}
You would also need to check if the password is valid. But you get the idea.
Hope this helped.

Categories

Resources