ASP.NET Override a webmethod - c#

I have several WebMethods in a C# ASP.NET web app. I'd like to change the behavior of all of them to validate each request. Imagine the code below:
[WebMethod]
public static void DoSomething()
{
if (ValidateRequest())
{
HttpContext.Current.Response.StatusCode = 400;
// do some other stuff
return;
}
// rest of method
}
I've noticed of course that the ValidateRequest() method call is common to a large portion of my WebMethods. Is there anyway I can wire this up so that all WebMethods automatically have this same behavior? Could I add a second attribute to the method to accomplish this?

Add the validate request in the Begin Request of your Global.asax file.
Now, you need some sort of code to check if the request should be validated.
I'm unsure how to do this in webforms... But, what I'd do is:
use the RequestPath property (and get the method and class name if they match your service URL)
HttpContext.Current.Request.Path;
Then I would create a method attribute and perhaps use reflection to see if the request should be validated. (see link below)
http://msdn.microsoft.com/en-us/library/z919e8tw.aspx
This way from this point on you just need to tag your method with your "[Validate]" attribute and it all should just work.
public class Global : HttpApplication
{
protected void Application_BeginRequest(object sender, EventArgs e)
{
if(ShouldValidate() && !IsValidRequest()){
//add your custom error status here perhaps
Response.StatusCode = 400
Response.StatusDescription = "Something Bad happened"
HttpContext.Current.Response.End()
}
}

Related

ASP.NET C# ApiController and Static Config Class

I have an issue with an ASP.NET C# API application.
It uses the AuthApiAttribute class to check authorization, using 2 HTTP header to authenticate the query.
Once I have validated the credentials, I put some configuration linked to those credentials in a class with static attributes. That class is named ApiKeyConfig. That parts works correctly.
My problem is when the ApiController handles the response, the value of the attributes of ApiKeyConfig are the values of the previous API call.
So if I call the API 4 time with userA, userB, userC and userA again, the result will be:
Call for userA: Has no info if server is fresh, last call if not
Call for userB: Will have info of userA
Call for userC: Will have info of userB
Call for userA: Will have info of userC
I was expecting the static values of the ApiKeyConfig class not to survive from one query to another. I thought it would be static for the query API call only.
And from that behaviour, I suppose that the AuthApiAttribute class call is done AFTER the controller method has executed ?
In my controller, I have defined [AuthApi] above my public class CustomerController : ApiController.
So what would be the best way to pass to my controller configuration that are specific to the API-key for the current call ?
Also, is there a way to prevent values to be kept from API call to API call ? Like in this case, what would I do to make sure ApiKeyConfig don't have the value of the previous request?
Edit:
My AuthApiAttribute class:
public class AuthApiAttribute : Attribute, IAuthorizationFilter
{
public bool AllowMultiple => true;
public Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
// I have the logic to check if user is valid
// [...]
List<ApiKey> keys; // Is assigned the valid API keys, skip that code below to avoid long comment
// I have some logic here to stock the valid keys in "keys"
// [...]
foreach (ApiKey apikey in keys)
{
if (key == apikey.key && auth == apikey.auth)
{
// FIXME: Would need to do somehting here to assign that key to something for me to be able to use that value once I'm in the controller's method
return response;
}
}
response.Result.StatusCode = System.Net.HttpStatusCode.Forbidden;
response.Result.Content = new StringContent("Access forbidden. Make sure your credentials are valid.");
return response;
}
}
The class ApiKeyConfig is just a class with attributes representing the settings of the API key in use (somewhat like a user's profile)
Here, an example of a Controller in which I want to refer to the ApiKey for the current request.
[AuthApi]
public class CustomerController : ApiController
{
public Models.Response Get(string id)
{
// FIXME: Here, I want to access the value of ApiKey for the current session.
try
{
// I have some logic here to get the Customer requested
// [...]
return new Models.Response
{
Status = "Success",
Data = Customer
};
}
catch (Exception e)
{
return new Models.Response
{
Status = "Error",
Message = e.Message,
Stack = e.StackTrace
};
}
}
}
Solution:
Based on Athanasios Kataras answer, in AuthApiAttribute:
actionContext.ControllerContext.Configuration.Properties.TryAdd("apikey", apikey);
And then, in my Controller's Method accessing this value with:
Configuration.Properties.TryGetValue("apikey", out object config);
ApiKeyConfig keyConfig = (ApiKeyConfig)config;
if (keyConfig.value.Equals(""))
{
// Handle session undefined
}
You should not use static variables for these types of communication.
When you have multiple concurrent users, the static variable might change in your authorization, before the request is handled by the controller. This will lead to bugs that can't be easily identified.
Maybe you could use something like this to share data between filters and controllers. WebApi: how to pass state from filter to controller?
Also make sure that you extend the https://learn.microsoft.com/en-us/aspnet/web-api/overview/security/authentication-and-authorization-in-aspnet-web-api authorization attribute for your authorization action, as this will certainly run before your controller.

C# AntiForgeryToken attribute causes StackOverflowException in mvc application

I have created a antiforgery attribute class to decorate my GenericBaseController class:
[AttributeUsage(AttributeTargets.Class)]
public class ValidateAntiForgeryTokenAttribute : AuthorizeAttribute
{
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())
{
var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];
var cookieValue = antiForgeryCookie != null
? antiForgeryCookie.Value
: null;
AntiForgery.Validate(cookieValue, request.Headers["__RequestVerificationToken"]);
}
else
{
new ValidateAntiForgeryTokenAttribute()
.OnAuthorization(filterContext);
}
}
}
}
(reference link http://richiban.uk/2013/02/06/validating-net-mvc-4-anti-forgery-tokens-in-ajax-requests/ )
once a normal POST call in application is done (not ajax), I always get a StackOverflowException.
Application without ValidateAntiForgeryTokenAttribute works fine.
If I debug the code inside this class, after a post request, flow keeps going trough the line
new ValidateAntiForgeryTokenAttribute()
.OnAuthorization(filterContext);
infinitely.
People in linked article assure that this implementation works, so I'm wondering why I'm getting this problem.
Is it really supposed to create a new ValidateAntiForgeryTokenAttribute when the request is not ajax ?
Boiled down to the problem, your code is:
public class ValidateAntiForgeryTokenAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
if ( evaluateCondition() )
{}
else
{
new ValidateAntiForgeryTokenAttribute()
.OnAuthorization(filterContext);
}
}
}
The problem
Your call is recursive in the else block:
The class you are calling the method on is ValidateAntiForgeryTokenAttribute.
In your else block you have
new ValidateAntiForgeryTokenAttribute()
.OnAuthorization(filterContext);
which, given that the calling method is
public override void OnAuthorization(AuthorizationContext filterContext)
means that you will keep calling OnAuthorization (i.e. the same method) on new instances of a ValidateAntiForgeryTokenAttribute.
Solution
In the example you posted, the situation was slightly different - the name of the class is ValidateAntiForgeryTokenOnAllPosts whereas yours is ValidateAntiForgeryTokenAttribute, so the call is not recursive since the method is not calling itself with the same arguments.
You have three options - I'm not sure which is best for your situation (I'm thinking the first one):
Change your Attribute name to ValidateAntiForgeryTokenOnAllPosts to match the name in the example you posted.
Explicitly state that you want System.Web.Mvc.ValidateAntiForgeryTokenAttribute by changing the block to say
new System.Web.Mvc.ValidateAntiForgeryTokenAttribute()
.OnAuthorization(filterContext);
Since you are overriding ValidateAntiForgeryTokenAttribute, you can call the base method, i.e.
else
{
base.OnAuthorization(filterContext);
}

How to avoid a HttpException when calling HttpContext.Request?

So HttpContext.Request throws if called within a global start
public HttpRequest get_Request()
{
if (this.HideRequestResponse)
{
throw new HttpException(SR.GetString("Request_not_available"));
}
return this._request;
}
This is actually documented
ASP.NET will throw an exception if you try to use this property when the HttpRequest object is not available. For example, this would be true in the Application_Start method of the Global.asax file, or in a method that is called from the Application_Start method. At that time no HTTP request has been created yet.
Is there a way of checking if a HttpContext.Request is in a state that it can be retrieved without throwing the exception? Effectively I want to write a TryGetRequest helper method.
Reflection is not an option. It needs to be a public API.
I dont have access to the application context. this is generic logging code. So setting some flag when startup has finished is not an option
As deostroll observed, it is reasonable and may in fact be necessary to rely on the ASP.NET application lifecycle to determine when the current HttpRequest has become available. The generic logging code is presumably dependent at the very least on HttpContext.Current or some other reference to the current HttpContext instance. If that assumption holds true, then an HttpModule can be implemented that stores a flag in the HttpContext.Items collection when the BeginRequest event fires. The static TryGetRequest helper method can test for the presence of that flag to determine whether it is safe to use HttpContext.Request.
Perhaps like this:
public class HttpRequestHelper : IHttpModule
{
private const string HttpRequestIsAvailable = "HttpRequestIsAvailable";
public static bool TryGetRequest(HttpContext context, out HttpRequest request)
{
request = null;
if (context != null)
{
if (context.Items.Contains(HttpRequestIsAvailable))
request = context.Request;
}
return (request != null);
}
#region IHttpModule
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.BeginRequest += context_BeginRequest;
}
private void context_BeginRequest(object sender, EventArgs e)
{
((HttpApplication)sender).Context.Items.Add(HttpRequestIsAvailable, true);
}
#endregion
}
The module must be registered in web.config (assuming IIS 7.0 integrated pipeline):
<system.webServer>
<modules>
<add name="HttpRequestHelper" type="Utility.HttpRequestHelper" />
</modules>
</system.webServer>
The logging code would use the helper method like this:
HttpRequest request;
if (HttpRequestHelper.TryGetRequest(HttpContext.Current, out request))
LogWithRequest(request, message);
else
LogWithoutRequest(message);
The implementation does not rely on private API's or reflection. It relies on a flag, but the state information remains with the HttpContext instance and is well encapsulated.
Why not wrap the call to HttpContext.Request with a try, catch block then you can catch the exception and modify your behaviour accordingly.
It is not possible without using reflection

OnActionExecuting equivalent in standard asp.NET?

Is there an equivalent for MVC.NET's OnActionExecuting in standard asp.NET? ?
I thought it would be Page_Load since OnActionExecuting would be called each time an action is executed (or the page loads). But I'm running into inheritance issues when I try to use Page_Load instead.
Since it is very difficult to make my solution work with a Page_Load I'm thinking I might not have the best ... solution.
Any thoughts on whether they are equivalent or close enough?
Background:
I'm converting a piece of an MVC3 application into a standard .NET to wrap in a SharePoint Web Part.
Here's the MVC code I'm trying to translate, as you can see its the user security bits I'm translating:
protected override void OnActionExecuting(ActionExecutingContext filterContext) {
if (!SiteCacheProvider.ItemCached(enmCacheKey.SiteSetting)) {
if (filterContext.IsImplementedGeneralPrincipal()) {
IUserProfile userProfile = ((IGeneralPrincipal)filterContext.HttpContext.User).UserProfile;
SiteCacheProvider.ChangeSiteSetting(userProfile.SiteID);
}
}
base.OnActionExecuting(filterContext);
}
First, take on account that no Actions are in ASP.NET because the model is different (Event-Based) - There're no methods(actions) which you can decorate with Action Filters, it's all about the Page-Cycle events.
Second, In ASP.NET, you may use HTTP modules (HttpApplication.BeginRequest particularly) in order to intercept incoming requests to your application pages by adding your required logic.
From MSDN:
HTTP Modules use to intercept HTTP requests for modifying or utilize
HTTP based requests according to needs like authentication,
authorization, session/state management, logging, modifying Response,
URL rewriting, Error handling, Caching....
For example:
using System;
using System.Web;
using System.Collections;
public class HelloWorldModule : IHttpModule
{
public string ModuleName
{
get { return "HelloWorldModule"; }
}
public void Init(HttpApplication application)
{
application.BeginRequest += (new EventHandler(this.Application_BeginRequest));
application.EndRequest += (new EventHandler(this.Application_EndRequest));
}
private void Application_BeginRequest(Object source, EventArgs e)
{
HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;
context.Response.Write("<h1>HelloWorldModule: Beginning of Request</h1><hr>");
}
private void Application_EndRequest(Object source, EventArgs e)
{
HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;
context.Response.Write("<hr><h1>HelloWorldModule: End of Request</h1>");
}
public void Dispose()
{
}
}

How to write a custom MVC ActionFilterAttribute that redirects a Facebook application

I need an attribute that handles authorization for my controllers. This is for a Facebook application and there are a few hurdles surrounding the problem.
What I really need is the equivalent to a server.transfer but of course that is not an option in ASP.NET MVC. A redirect will not work because of the way Facebook consumes the application.
Is there an a way I can re-route from within an ActionFilterAttribute?
public class FbAuthorize : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!Service.SignedIn())
RouteToAction("Account", "Index"); // Fictional method (I wish it existed)
}
}
If you're using the facebook developer's toolkit you can implement the basepagehelper's LoadFBMLPage method in an ActionFiler's OnActionExecuting method. (otherwise you'll have to emit the fb:redirect tag yourself). Here's a brief writeup: http://onishimura.com/2009/04/13/facebook-and-aspnet-mvc/
Here is your "Server.Transfer()" or kind of:
public static class ServerHelper {
public static void Transfer(ActionExecutingContext filterContext, string url) {
// Rewrite path
HttpContext.Current.RewritePath(GetPath(filterContext, url), false);
IHttpHandler httpHandler = new System.Web.Mvc.MvcHttpHandler();
// Process request
httpHandler.ProcessRequest(HttpContext.Current);
filterContext.HttpContext.Response.End();
}
private static string GetPath(ActionExecutingContext filterContext, string url) {
HttpRequestBase request = filterContext.HttpContext.Request;
UriBuilder uriBuilder = new UriBuilder(request.Url.Scheme, request.Url.Host, request.Url.Port, request.ApplicationPath);
uriBuilder.Path += url;
return filterContext.HttpContext.Server.UrlDecode(uriBuilder.Uri.PathAndQuery);
}
}
Now, in your filter, just call:
ServerHelper.Transfer(filterContext, "Account/Index");
Cheers
You could just render the sam view with the same data that the action you want to route to would have rendered. Abstract the code to generate the data back into the model and both methods could use it from there so you reduce the duplication. This won't give you the same URL, but it will give you the view that you want.

Categories

Resources