I am attempting to upload large files in WebApi 2. I was following this tutorial (which is the same recipe used in the webapi 2 cookbook) where you register a host policy
public class NoBufferPolicySelector : WebHostBufferPolicySelector
{
public override bool UseBufferedInputStream(object hostContext)
{
var context = hostContext as HttpContextBase;
if (context != null)
{
if (string.Equals(context.Request.RequestContext.RouteData.Values["controller"].ToString(), "uploading", StringComparison.InvariantCultureIgnoreCase))
return false;
}
return true;
}
}
However context.Request.RequestContext.RouteData is basically a dummy object with no route data set.
Is there another method for finding the RouteData in webapi 2 from an HttpBaseContext, or possible another method to get deal with bufferless uploads?
Your post is already a bit old, but recently went through the same problem.
Projects with Owin Host (my case and maybe yours) use OwinBufferedPolicySelector class that already does the job, so do not need to overwrite the class.
OwinContext not exposes RouteData as HttpContextBase.
https://books.google.com.br/books?id=7aE8BAAAQBAJ&pg=PA123&lpg=PA123&dq=override+WebHostBufferPolicySelector&source=bl&ots=fvV5SWVsJG&sig=I5t4MBOXdPbgFV4mBCI_kWLWkRw&hl=pt-BR&sa=X&ei=oheIVev2N-TgsASS2IDgCQ&ved=0CD0Q6AEwAw#v=onepage&q=override%20WebHostBufferPolicySelector&f=false
Since you are using Owin, you are already using bufferless input so you don't need to make any changes.
By default without Owin, the WebHostBufferPolicySelector is used, which has buffering set to true for input streams:
http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Http.WebHost/WebHostBufferPolicySelector.cs
public virtual bool UseBufferedInputStream(object hostContext) {
if(hostContext == null) {
throw Error.ArgumentNull("hostContext");
}
return true;
}
When you use the Owin middleware layer, OwinBufferPolicySelector is used instead of WebHostBufferPolicySelector, which has buffering set to false for all input streams:
http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Http.Owin/OwinBufferPolicySelector.cs
public bool UseBufferedInputStream(object hostContext) {
return false;
}
I also encountered same issue and solved it by commenting out the call to "MapHttpAttributeRoutes" method on HttpConfiguration instance. I do not know why it interfere with RouteData.
public static void Register(HttpConfiguration config)
{
// Web API routes
//Enabling of below cause empty RoutData in NoBufferPolicySelector class.
//config.MapHttpAttributeRoutes();
}
Related
I'm using ABP (aspnetboilerplate) 7.0 thru ASP.NET Zero 11 and I'm trying to get OData working. I've followed the article over at ABP and I've taken inspiration from their sample.
The response of OData routes (/odata and /odata/$metadata) should not be wrapped. ABP does provide an attribute to prevent wrapping called DontWrapResult. However, since these routes are not on controllers that I have direct access to, I can't set the attribute.
The same question has been asked here: Disable Wrapping of Controller Results
However, they wanted to disable wrapping altogether, which is not what I want to do.
The answer to that question is to use a ResultFilter to set the attribute's value. I have, however, found that setting the value thru the attribute also sets the value that comes from the injected IAbpAspNetCoreConfiguration.
For example:
public class ODataResultFilter : IResultFilter, ITransientDependency
{
private readonly IAbpAspNetCoreConfiguration _configuration;
public ODataResultFilter(IAbpAspNetCoreConfiguration configuration)
{
_configuration = configuration;
}
public void OnResultExecuting(ResultExecutingContext context)
{
var methodInfo = context.ActionDescriptor.GetMethodInfo();
var wrapResultAttribute =
GetSingleAttributeOfMemberOrDeclaringTypeOrDefault(
methodInfo,
_configuration.DefaultWrapResultAttribute,
false
);
if (context.HttpContext.Request.Path.Value.Equals("/odata/$metadata") ||
context.HttpContext.Request.Path.Value.Equals("/odata"))
{
wrapResultAttribute.WrapOnSuccess = false;
}
}
public void OnResultExecuted(ResultExecutedContext context)
{
// No action
}
private TAttribute GetSingleAttributeOfMemberOrDeclaringTypeOrDefault<TAttribute>(MemberInfo memberInfo, TAttribute defaultValue = default(TAttribute), bool inherit = true)
where TAttribute : class
{
return memberInfo.GetCustomAttributes(true).OfType<TAttribute>().FirstOrDefault()
?? memberInfo.DeclaringType?.GetTypeInfo().GetCustomAttributes(true).OfType<TAttribute>().FirstOrDefault()
?? defaultValue;
}
}
As soon as I hit wrapResultAttribute.WrapOnSuccess = false;, _configuration.DefaultWrapResultAttribute becomes false and every other request ends up not being wrapped. My front-end expects wrapped responses and thus the front-end stops working as soon as I hit an OData route once.
How can I manipulate this attribute and prevent wrapping for OData routes but leave the default + attribute-configured wrapping behavior for the other routes?
GetSingleAttributeOfMemberOrDeclaringTypeOrDefault method should work fine, except right now, since _configuration.DefaultWrapResultAttribute gets modified, a controller that doesn't explicitly set a WrapResult attribute will get the default, overridden by the last value set.
Implement IWrapResultFilter, which was introduced in ABP v6.5:
using Abp.Web.Results.Filters;
using System;
namespace AbpODataDemo.Web.Host.ResultWrapping
{
public class ODataWrapResultFilter : IWrapResultFilter
{
public bool HasFilterForWrapOnError(string url, out bool wrapOnError)
{
wrapOnError = false;
return new Uri(url).AbsolutePath.StartsWith("/odata", StringComparison.InvariantCultureIgnoreCase);
}
public bool HasFilterForWrapOnSuccess(string url, out bool wrapOnSuccess)
{
wrapOnSuccess = false;
return new Uri(url).AbsolutePath.StartsWith("/odata", StringComparison.InvariantCultureIgnoreCase);
}
}
}
Add it to WrapResultFilters in the PreInitialize method of your module:
Configuration.Modules.AbpWebCommon().WrapResultFilters.Add(new ODataWrapResultFilter());
Reference:
https://aspnetboilerplate.com/Pages/Documents/AspNet-Core#wrapresultfilters
https://github.com/aspnetboilerplate/sample-odata/pull/20
OData with ABP v7.1 and later
Abp.AspNetCore.OData implements AbpODataDontWrapResultFilter to disable result wrapping for paths that start with "/odata".
Add it to WrapResultFilters in the PreInitialize method of your module:
Configuration.Modules.AbpWebCommon().WrapResultFilters.Add(new AbpODataDontWrapResultFilter());
The rationale of letting library users configure this explicitly is to highlight this interaction between the default result wrapping and OData use case.
References:
https://aspnetboilerplate.com/Pages/Documents/OData-AspNetCore-Integration#result-wrapping
https://github.com/aspnetboilerplate/aspnetboilerplate/pull/6375
Please see this StackOverflow question.
I am porting an application from .Net Framework to .Net Core 3.1. The solution in the above SO question was used in the .Net Framework solution to make sure that the controller could only be used by other applications on the same server.
I have found a similar AuthorizeAttribute, but is does not have the same method to override.
I also think I know how to add filters:
services.AddControllers(options =>
{
options.Filters.Add(*some_filter_here*);
});
But I don't know how to create the filter.
How do I do this in .Net Core 3.1? Or is there a different way to do what I want?
You can create a custom Authorization filter:
public class LocalAuthorizationFilter : IAuthorizationFilter
{
public LocalAuthorizationFilter()
{
}
public void OnAuthorization(AuthorizationFilterContext context)
{
var isLocal = context.Request.IsLocal();
if (!isLocal)
{
context.Result = new ForbidResult();
}
}
public static bool IsLocal(this HttpRequest req)
{
var connection = req.HttpContext.Connection;
if (connection.RemoteIpAddress != null)
{
if (connection.LocalIpAddress != null)
{
return connection.RemoteIpAddress.Equals(connection.LocalIpAddress);
}
else
{
return IPAddress.IsLoopback(connection.RemoteIpAddress);
}
}
// for in memory TestServer or when dealing with default connection info
if (connection.RemoteIpAddress == null && connection.LocalIpAddress == null)
{
return true;
}
return false;
}
}
There is not an IsLocal property anymore (HttpRequest documentation), so I added one in your class. You can extract it and add it in an extentions class to be used everywhere. Kudos to this guy here
I am building a ASP.NET Core MVC application and am trying to create a global action filter that logs how much time is spent executing an action (it should only log if spent time is above some threshold). I have succesfully done this but now I want to be able to say that a single action or a single controller should have a different threshold. When I try this, my action filter is applied twice(which is not what I want) but with the correct two different thresholds.
I have tried quite a few things and searched around. In an MVC 3 and an MVC 4 project I have successfully done this using RegisterGlobalFilters() in Global.asax and it automatically overrides the global one when I used the attribute on a controller/action. I have also tried the approach listed in this post, without luck:
Override global authorize filter in ASP.NET Core MVC 1.0
My code for my ActionFilterAttribute:
public class PerformanceLoggingAttribute : ActionFilterAttribute
{
public int ExpectedMax = -1; // Log everything unless this is explicitly set
private Stopwatch sw;
public override void OnActionExecuting(ActionExecutingContext context)
{
sw = Stopwatch.StartNew();
}
public override void OnActionExecuted(ActionExecutedContext context)
{
sw.Stop();
if (sw.ElapsedMilliseconds >= ExpectedMax)
{
// Log here
}
}
//public override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
//{
// // If there is another performance filter, do nothing
// if (context.Filters.Any(item => item is PerformanceLoggingAttribute && item != this))
// {
// return Task.FromResult(0);
// }
// return base.OnActionExecutionAsync(context, next);
//}
}
I am applying this global filter in my Startup.cs:
services.AddMvc(options =>
{
if (_env.IsProduction()) options.Filters.Add(new RequireHttpsAttribute());
//options.Filters.Add(new PerformanceLoggingFilter() { ExpectedMax = 1 }); // Add Performance Logging filter
options.Filters.Add(new PerformanceLoggingAttribute() { ExpectedMax = 1 }); // Add Performance Logging filter
});
And in my controller I am applying the attribute:
//[TypeFilter(typeof(PerformanceLoggingFilter))]
[PerformanceLogging(ExpectedMax = 2)]
public IActionResult Index()
{
var vm = _performanceBuilder.BuildPerformanceViewModel();
return View(vm);
}
As you can tell from the code snippets above I have tried the OnActionExecutionAsync approach and I have also tried a IActionFilter instead and using [TypeFilter(typeof(PerformanceLoggingFilter))] on actions, but no luck.
Can anyone help me out?
May suggest you a bit different implementation of what you try to achieve by using one action filter and additional custom attribute:
create a new simple attribute (let's name it ExpectedMaxAttribute), that just holds the ExpectedMax value. Apply this attribute to controller's actions with different values.
keep your PerformanceLogging action filter as global, but modify implementation. On OnActionExecuted method check if controller's action has ExpectedMaxAttribute. If yes, then read ExpectedMax value from attribute, otherwise use the default value from the action filter.
Also, I recommend you to rename action filter accordingly to convention naming something like PerformanceLoggingActionFilter.
I got it working thanks to #Set's answer above in combination with this answer:
https://stackoverflow.com/a/36932793/5762645
I ended up with a global action that is applied to all actions and then having a simple ExpectedMaxAttribute that I put on actions where the threshold should be different. In the OnActionExecuted of my global action filter, I then check if the action in question has the ExpectedMaxAttribute attached to it and then read the ExpectedMax from that. Below is my attribute:
public class PerformanceLoggingExpectedMaxAttribute : ActionFilterAttribute
{
public int ExpectedMax = -1;
}
And the OnActionExecuted part that I added to my ActionFilter:
public override void OnActionExecuted(ActionExecutedContext context)
{
sw.Stop();
foreach (var filterDescriptor in context.ActionDescriptor.FilterDescriptors)
{
if (filterDescriptor.Filter is PerformanceLoggingExpectedMaxAttribute)
{
var expectedMaxAttribute = filterDescriptor.Filter as PerformanceLoggingExpectedMaxAttribute;
if (expectedMaxAttribute != null) ExpectedMax = expectedMaxAttribute.ExpectedMax;
break;
}
}
if (sw.ElapsedMilliseconds >= ExpectedMax)
{
_logger.LogInformation("Test log from PerformanceLoggingActionFilter");
}
}
I have been trying to recreate an Ajax version of the ValidateAntiForgeryToken - there are many blog posts on how to do this for previous versions of MVC, but with the latest MVC 6, none of the code is relevant. The core principle that I am going after, though, is to have the validation look at the Cookie and the Header for the __RequestVerificationToken, instead of comparing the Cookie to a form value. I am using MVC 6.0.0-rc1-final, dnx451 framework, and all of the Microsoft.Extensions libraries are 1.0.0-rc1-final.
My initial thought was to just inherit ValidateAntiForgeryTokenAttribute, but looking at the source code, I would need to return my own implementation of an an Authorization Filter to get it to look at the header.
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class ValidateAjaxAntiForgeryTokenAttribute : Attribute, IFilterFactory, IFilterMetadata, IOrderedFilter
{
public int Order { get; set; }
public bool IsReusable => true;
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
return serviceProvider.GetRequiredService<ValidateAjaxAntiforgeryTokenAuthorizationFilter>();
}
}
As such, I then made my own version of ValidateAntiforgeryTokenAuthorizationFilter
public class ValidateAjaxAntiforgeryTokenAuthorizationFilter : IAsyncAuthorizationFilter, IAntiforgeryPolicy
{
private readonly IAntiforgery _antiforgery;
private readonly ILogger _logger;
public ValidateAjaxAntiforgeryTokenAuthorizationFilter(IAntiforgery antiforgery, ILoggerFactory loggerFactory)
{
if (antiforgery == null)
{
throw new ArgumentNullException(nameof(antiforgery));
}
_antiforgery = antiforgery;
_logger = loggerFactory.CreateLogger<ValidateAjaxAntiforgeryTokenAuthorizationFilter>();
}
public async Task OnAuthorizationAsync(AuthorizationContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (IsClosestAntiforgeryPolicy(context.Filters) && ShouldValidate(context))
{
try
{
await _antiforgery.ValidateRequestAsync(context.HttpContext);
}
catch (AjaxAntiforgeryValidationException exception)
{
_logger.LogInformation(1, string.Concat("Ajax Antiforgery token validation failed. ", exception.Message));
context.Result = new BadRequestResult();
}
}
}
protected virtual bool ShouldValidate(AuthorizationContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
return true;
}
private bool IsClosestAntiforgeryPolicy(IList<IFilterMetadata> filters)
{
// Determine if this instance is the 'effective' antiforgery policy.
for (var i = filters.Count - 1; i >= 0; i--)
{
var filter = filters[i];
if (filter is IAntiforgeryPolicy)
{
return object.ReferenceEquals(this, filter);
}
}
Debug.Fail("The current instance should be in the list of filters.");
return false;
}
}
However, I cannot find the proper Nuget package and namespace that contains IAntiforgeryPolicy. While I found the interface on GitHub - what package do I find it in?
My next attempt was to instead go after the IAntiforgery injection, and replace the DefaultAntiforgery with my own AjaxAntiforgery.
public class AjaxAntiforgery : DefaultAntiforgery
{
private readonly AntiforgeryOptions _options;
private readonly IAntiforgeryTokenGenerator _tokenGenerator;
private readonly IAntiforgeryTokenSerializer _tokenSerializer;
private readonly IAntiforgeryTokenStore _tokenStore;
private readonly ILogger<AjaxAntiforgery> _logger;
public AjaxAntiforgery(
IOptions<AntiforgeryOptions> antiforgeryOptionsAccessor,
IAntiforgeryTokenGenerator tokenGenerator,
IAntiforgeryTokenSerializer tokenSerializer,
IAntiforgeryTokenStore tokenStore,
ILoggerFactory loggerFactory)
{
_options = antiforgeryOptionsAccessor.Value;
_tokenGenerator = tokenGenerator;
_tokenSerializer = tokenSerializer;
_tokenStore = tokenStore;
_logger = loggerFactory.CreateLogger<AjaxAntiforgery>();
}
}
I got this far before I stalled out because there is no generic method on ILoggerFactory for CreateLogger<T>(). The source code for DefaultAntiforgery has Microsoft.Extensions.Options, but I cannot find that namespace in any Nuget package. Microsoft.Extensions.OptionsModel exists, but that just brings in the IOptions<out TOptions> interface.
To follow all of this up, once I do get the Authorization Filter to work, or I get a new implementation of IAntiforgery, where or how do I register it with the dependency injection to use it - and only for the actions that I will be accepting Ajax requests?
I had similar issue. I don't know if any changes are coming regarding this in .NET but, at the time, I added the following lines to ConfigureServices method in Startup.cs, before the line services.AddMvc(), in order to validate the AntiForgeryToken sent via Ajax:
services.AddAntiforgery(options =>
{
options.CookieName = "yourChosenCookieName";
options.HeaderName = "RequestVerificationToken";
});
The AJAX call would be something like the following:
var token = $('input[type=hidden][name=__RequestVerificationToken]', document).val();
var request = $.ajax({
data: { 'yourField': 'yourValue' },
...
headers: { 'RequestVerificationToken': token }
});
Then, just use the native attribute [ValidadeAntiForgeryToken] in your Actions.
I've been wrestling with a similar situation, interfacing angular POSTs with MVC6, and came up with the following.
There are two problems that need to be addressed: getting the security token into MVC's antiforgery validation subsystem, and translating angular's JSON-formatted postback data into an MVC model.
I handle the first step via some custom middleware inserted in Startup.Configure(). The middleware class is pretty simple:
public static class UseAngularXSRFExtension
{
public const string XSRFFieldName = "X-XSRF-TOKEN";
public static IApplicationBuilder UseAngularXSRF( this IApplicationBuilder builder )
{
return builder.Use( next => context =>
{
switch( context.Request.Method.ToLower() )
{
case "post":
case "put":
case "delete":
if( context.Request.Headers.ContainsKey( XSRFFieldName ) )
{
var formFields = new Dictionary<string, StringValues>()
{
{ XSRFFieldName, context.Request.Headers[XSRFFieldName] }
};
// this assumes that any POST, PUT or DELETE having a header
// which includes XSRFFieldName is coming from angular, so
// overwriting context.Request.Form is okay (since it's not
// being parsed by MVC's internals anyway)
context.Request.Form = new FormCollection( formFields );
}
break;
}
return next( context );
} );
}
}
You insert this into the pipeline with the following line inside the Startup.Configure() method:
app.UseAngularXSRF();
I did this right before the call to app.UseMVC().
Note that this extension transfers the XSRF header on any POST, PUT or DELETE where it exists, and it does so by overwriting the existing form field collection. That fits my design pattern -- the only time the XSRF header will be in a request is if it's coming from some angular code I've written -- but it may not fit yours.
I also think you need to configure the antiforgery subsystem to use the correct name for the XSRF field name (I'm not sure what the default is). You can do this by inserting the following line into Startup.ConfigureServices():
services.ConfigureAntiforgery( options => options.FormFieldName = UseAngularXSRFExtension.XSRFFieldName );
I inserted this right before the line services.AddAntiforgery().
There are several ways of getting the XSRF token into the request stream. What I do is add the following to the view:
...top of view...
#inject Microsoft.AspNet.Antiforgery.IAntiforgery af
...rest of view...
...inside the angular function...
var postHeaders = {
'X-XSRF-TOKEN': '#(af.GetTokens(this.Context).FormToken)',
'Content-Type': 'application/json; charset=utf-8',
};
$http.post( '/Dataset/DeleteDataset', JSON.stringify({ 'siteID': siteID }),
{
headers: postHeaders,
})
...rest of view...
The second part -- translating the JSON data -- is handled by decorating the model class on your action method with [FromBody]:
// the [FromBody] attribute on the model -- and a class model, rather than a
// single integer model -- are necessary so that MVC can parse the JSON-formatted
// text POSTed by angular
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult DeleteDataset( [FromBody] DeleteSiteViewModel model )
{
}
[FromBody] only works on class instances. Even though in my case all I'm interested in is a single integer, I still had to dummy up a class, which only contains a single integer property.
Hope this helps.
Using a anti forgery token in a Ajax call is possible but if you are trying to secure a Api I really would suggest using a Access Token instead.
If you are relying on a identity token stored in a cookie as authentication for your Api, you will need to write code to compensate for when your cookie authentication times out, and your Ajax post is getting redirected to a login screen. This is especially important for SPAs and Angular apps.
Using a Access Token implementation instead, will allow you to refresh you access token (using a refresh token), to have long running sessions and also stop cookie thiefs from accessing your Apis.. and it will also stop XSRF :)
A access token purpose is to secure resources, like Web Apis.
So I've found bits and pieces that have enlightened me some on the [Authorize] tag, but nothing that solves my problem.
My scenario is that I have Web Api methods that I want to hit with integration tests using RestSharp. However RestSharp is getting my login page, instead of the results of the call.
[Authorize]
public Item GetItem([FromBody] int id)
{
return service.GetItem(id);
}
The product uses a custom login system, and what I would REALLY like would be a way to disable the [Authorize] badge only for integration tests. However I read that you can allow anonymous users and it would 'disable' the badge, so in the solution, I have an integration tests project, and in that project I have an App.config file. In that file I put:
<location>
<system.web>
<authorization>
<allow users="?"/>
</authorization>
</system.web>
</location>
But this doesn't appear to be working either. Any explanation as to what's going on, why it's not working and what can be done to get this working would be greatly appreciated.
I have attempted to set a Thread.CurrentPrincipal but that didn't work (maybe I did it wrong - can you set "anything" to be authorized in the code?). Authentication is handled in an httpmodule if that helps at all.
I realise that this question is about firing 'real' requests from RestSharp at the webapi endpoints so this suggestion is not immediately applicable to the OPs scenario.. BUT:
I'm using in-memory Web Api tests using HttpConfiguration, HttpServer and HttpMessageInvoker (much like Badri's suggestion I believe). In this way, I don't need listeners or ports open since I can test the full stack (end to end test) in memory - really handy on a build server, Heroku instance, etc.
Using in-memory tests, here is how you could set the Thread.CurrentPrincipal.. I have a helper on my test base class like this:
protected void AuthentateRequest()
{
Thread.CurrentPrincipal = new AuthenticatedPrincipal(Thread.CurrentPrincipal);
}
Which uses this:
public class AuthenticatedPrincipal : IPrincipal
{
private readonly IPrincipal _principalToWrap;
private readonly IIdentity _identityToWrap;
public AuthenticatedPrincipal(IPrincipal principalToWrap)
{
_principalToWrap = principalToWrap;
_identityToWrap = new AuthenticatedIdentity(principalToWrap.Identity);
}
public bool IsInRole(string role)
{ return _principalToWrap.IsInRole(role); }
public IIdentity Identity
{
get { return _identityToWrap; }
private set { throw new NotSupportedException(); }
}
}
public class AuthenticatedIdentity : IIdentity
{
private readonly IIdentity _identityToWrap;
public AuthenticatedIdentity(IIdentity identityToWrap)
{
_identityToWrap = identityToWrap;
}
public string Name
{
get { return _identityToWrap.Name; }
private set { throw new NotSupportedException(); }
}
public string AuthenticationType
{
get { return _identityToWrap.AuthenticationType; }
private set { throw new NotSupportedException(); }
}
public bool IsAuthenticated
{
get { return true; }
private set { throw new NotSupportedException(); }
}
}
It may seem like overkill to stub the IPrincipal manually but I tried with my mocking framework and it blew up in some of my test runners (Resharper and TeamCity, but not NCrunch - something about serialising over AppDomains I think).
This will set Thread.CurrentPrincipal inside the ApiController action method and therefore fool the AuthorizeAttribute into believing you are authenticated.
Here is how you should set the Thread.CurrentPrincipal. Add a message handler like this to your Web API project and add the handler in the Register method of WebApiConfig.cs like so: config.MessageHandlers.Add(new MyTestHandler());.
public class MyTestHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
var local = request.Properties["MS_IsLocal"] as Lazy<bool>;
bool isLocal = local != null && local.Value;
if (isLocal)
{
if (request.Headers.GetValues("X-Testing").First().Equals("true"))
{
var dummyPrincipal = new GenericPrincipal(
new GenericIdentity("dummy", "dummy"),
new[] { "myrole1" });
Thread.CurrentPrincipal = dummyPrincipal;
if (HttpContext.Current != null)
HttpContext.Current.User = dummyPrincipal;
}
}
return await base.SendAsync(request, cancellationToken);
}
}
This handler sets an authenticated principal to make all your [Authorize] happy. There is an element of risk with this approach. Only for testing, you should plug this handler into the Web API pipeline. If you plug this handler in to the pipeline (intentional or otherwise) in your production code, it basically defeats your authentication mechanism. To mitigate the risk to some extent (hoping API is not accessed locally), I check to ensure the access is local and that there is a header X-Testing with a value of true.
From RestSharp, add the custom header.
var request = new RestRequest(...);
request.AddHeader("X-Testing", "true");
BTW, for integration testing, I'd much rather use in-memory hosting, instead of web-hosting. That way, Web API runs in the same testing project and you can do whatever you want with it, without the fear of breaking something in production. For more info on in-memory hosting, see this and this.
Set the authenticator for your RestClient:
RestClient.Authenticator = new HttpBasicAuthenticator(username, password);
Using the authenticator that your custom login system actually accepts ... Basic, NTLM, OAuth, Simple ...
It is kind of documented in the second line of the example at http://restsharp.org/