Imageresizer Authentication with Owin - c#

Im using Imageresizer 4 in a MVC 5 application. We have the need to authenticate the image requests so we are using the following event:
protected void Application_Start()
{
ImageResizer.Configuration.Config.Current.Pipeline.AuthorizeAllImages = true;
ImageResizer.Configuration.Config.Current.Pipeline.AuthorizeImage += AuthorizeImage;
}
The AuthorizeImage method looks like this:
private static void AuthorizeImage(IHttpModule sender, HttpContext context, IUrlAuthorizationEventArgs e)
{
//This line throws an exception if runAllManagedModulesForAllRequests is set to false
var owinContext = context.GetOwinContext();
Authorize(context, owinContext);
}
The problem is that we are using Owin so we need the OwinContext from the HttpContext. When calling the GetOwinContext method we get the following error:
No owin.Environment item was found in the context
If I set the runAllManagedModulesForAllRequests to true in web.config, everything works like it should.
But I don't want to use runAllManagedModulesForAllRequests since it has a performance impact.
My question is: Can I somehow force the Owin middleware to execute before a specific HttpModule?
Something like this(psuedo code):
<modules runAllManagedModulesForAllRequests="false">
<add name="ImageResizingModule" type="ImageResizer.InterceptModule" modulesToRunBefore="Owin........" />
</modules>

No, you'll need runAllManagedModulesForAllRequests=true, unless you can change how the owin module is registered, and tell it to run for all requests.

Related

Allow frame from different domain with MVC5

I am trying to load google maps into an iframe using MVC5 but I am getting blocked with the error
Refused to display 'https://www.google.com/maps?cid=XXXXX' in a frame because it set 'X-Frame-Options' to 'SAMEORIGIN'.
So after much searching, I have tried the following:
Adding AntiForgeryConfig.SuppressXFrameOptionsHeader = true; to the Application_Start in global.ascx
Creating an attribute (have tried this with and without the setting in global.ascx):
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext != null)
{
filterContext.HttpContext.Response.Headers["X-Frame-Options"] = "ALLOW-FROM https://www.google.com";
base.OnActionExecuted(filterContext);
}
}
trying the attribute OnResultExecuted(ResultExecutedContext filterContext) instead of OnActionExecuted
remove it in the web.config:
<httpProtocol>
<customHeaders>
<remove name="X-Frame-Options" />
</customHeaders>
</httpProtocol>
Is there something I'm missing? how do I get rid of this http header (or at least change it to allow maps)?
Update
I have just checked the headers being sent and they are correct in that they either say
X-Frame-Options: ALLOW-FROM https://www.google.com
Or aren't there at all if I remove the attribute but keep the global.ascx update
Yet when I run the page and see these headers, it is still giving me the SAMEORIGIN error.
As it turns out I have been completely stupid and misunderstood how x-frame-options work. It is to stop your site page being shown on another site through an iframe.
So the x-frame-options http header that I was getting for SAMEORIGIN was actually coming from google. I thought that as the url was returned from their places api I could just use it, but apparently you can only link to it.
Creating a new map api key and enabling the maps embed api, I was able to use the place_id instead and call the following url into the iframe:
https://www.google.com/maps/embed/v1/place?key=YOUR_API_KEY&q=place_id:PLACE_ID
And this would show without me getting the header (or doing anything extra to my headers).
I'll leave this here just in case anyone is as daft as I am

Hangfire dashboard returns 404

When trying to access the hangfire dashboard on my local IIS at domain/hangfire/ I get a 404 response. This is in a webforms project targeting .Net 4.5.1, Hangfire is version 1.5.3. My startup and authorisationoverride classes are as follows:
[assembly: OwinStartup(typeof(MyNamespace.Startup))]
namespace MyNamespace
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
GlobalConfiguration.Configuration.UseSqlServerStorage("MyConnString");
DashboardOptions opts = new DashboardOptions
{
AuthorizationFilters = new[] { new AuthorisationOverride() }
};
app.UseHangfireServer();
app.UseHangfireDashboard("/hangfire", opts);
}
}
}
public class AuthorisationOverride : Hangfire.Dashboard.IAuthorizationFilter
{
public bool Authorize(IDictionary<string, object> owinEnvironment)
{
return true;
}
}
Jobs are running successfully, but I've run out of ideas for getting the Dashboard to work.
I had something similar but I managed to get it resolved by reading through this post.
Hope you will have a better luck following through that if you haven't yet. The main problem for me was the missing DLL, and then the removing site data from the TemporaryASP.NET folder.
Edit: Someone down voted this answer because I used a link for the solution.
Since I did find a solution to this specific problem, I thought I will give it another try to share. :)
Here are the steps that I have taken to come to a solution.
Confirm you have the Microsoft.Owin.Host.SystemWeb.dll in your bin directory of this project. (In my case, the dll was missing)
Stop your app pool
Navigate to your TemporaryASP.NET folder : C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files and delete the folder inside of your site/application's folder.
Restart you app pool
Navigate to "/admin" or whatever you set your dashboard url to be "/hangfire" by default.
Struggled with this for a few hours today and just fixed it in my project.
Try moving your Hangfire configuration code higher up in your Startup class's Configuration method.
I had my Hangfire configuration code at the very bottom of Startup.Configuration and just happened to discover that the dashboard works again when I move it before some of the other OWIN stuff I was configuring.
Specifically, I moved it above the following code in my project:
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR();
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
RouteConfig.RegisterRoutes(RouteTable.Routes);
// my AutoMapper configuration
// some async/await code that was calling .Wait() here.
I didn't take time to figure out exactly which line of code was breaking the Hangfire dashboard, but I hope that helps someone.
Also for the record, the old code was working under IIS Express at https://localhost:44342/hangfire. I was getting the 404 in full IIS at https://localhost/appname/hangfire.
Add this line in your web.config file:
<system.webServer>
<handlers>
<add name="hangfireDashboard" path="hangfire" type="System.Web.DefaultHttpHandler" verb="*" />
</handlers>
</system.webServer>
Since there is no solution so far, I would like to share something that I rectified to get this issue resolved.
If you're facing this issue only in production then, your web.config file is not properly configured.
Firstly, assuming you have already created the Startup class, add the following to the web.config under :
<add key="owin:AutomaticAppStartup" value="true" />
Next, make sure that you have referenced the OWIN assemblies as the below following:
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
Although, when you install OWIN via nuget, the setup will automatically update the web.config for you, but just in case it doesn't, you can always add this. Further make sure this above OWIN version matches with the one yo have installed via nuget.
Hope this helps somebody!
Edit: Answering the OP's original question, Hangfire returns 404 error when it is not started. Apart from adding the Startup OWIN class, we need to mention automaticstartup=true in the web config also. The next issue IIS will look for is reference to Hangfire, where is we kick in the assembly details.
application Startup
[assembly: OwinStartupAttribute(typeof(yournamespace.Startup))]
namespace yournamespace
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
var storage = new SqlServerStorage("connectionstring");
......
......
app.UseHangfireDashboard("/Scheduler", new DashboardOptions() { AuthorizationFilters = new[] { new HangFireAuthorizationFilter() } }, storage);
}
Authorization Filter
public class HangFireAuthorizationFilter:IAuthorizationFilter
{
public bool Authorize(IDictionary<string, object> owinEnvironment)
{
// In case you need an OWIN context, use the next line.
// `OwinContext` class is defined in the `Microsoft.Owin` package.
var context = new OwinContext(owinEnvironment);
return context.Authentication.User.Identity.IsAuthenticated &&
context.Authentication.User.IsInRole("xyz");
}
}
You Can Ignore the HangFireAuthorizationFilter if you want to.
The problem for me was missing ASP.NET installation on the server

Registering a custom PageHandlerFactory through code

Using the Microsoft.Web.Infrastructure assembly we can register modules during the pre-application start phase, as follows:
DynamicModuleUtility.RegisterModule(typeof(MyHttpModule));
Is it possible to register a custom PageHandlerFactory in ASP.NET web forms in code instead just like the example above with the module?
I currently wire this through code like this, but I find it too verbose (and it makes it much harder to create a quick start NuGet package, since I have to alter the web.config):
<?xml version="1.0"?>
<configuration>
<system.webServer>
<handlers>
<add name="CustomFactory" verb="*" path="*.aspx"
type="Shared.CustomPageHandlerFactory, Shared"/>
</handlers>
</system.webServer>
</configuration>
As far as I know, there is no way to do this in code. In my particular situation however, the solution really was to register a HTTP module.
The HTTP module can upon initialization hook onto the HttpApplication.PreRequestHandlerExecute event which is executed after the page handler factory created the Page, but before ASP.NET starts executing that page (and other handlers).
Here is an example of such a HTTP Module:
public class MyHttpModule : IHttpModule
{
void IHttpModule.Dispose() {
}
void IHttpModule.Init(HttpApplication context) {
context.PreRequestHandlerExecute +=
this.PreRequestHandlerExecute;
}
private void PreRequestHandlerExecute(object s, EventArgs e) {
IHttpHandler handler =
this.application.Context.CurrentHandler;
// CurrentHandler can be null
if (handler != null) {
// TODO: Initialization here.
}
}
}

Querystring without argument name

I am trying to get this to work. I have a DNN module in which I read from a querystring and perform a few steps. All of that is working fine. Now I am trying to clean up the URL while reading the querystring
Right now, the URL looks something like this:
http://mysite.website.com/?pid=1234
I would like it to look like:
http://mysite.website.com/1234
Is something like this even possible?
You are much better to use a proper rewriting solution for DotNetNuke (e.g. iFinity UrlMaster and there are others...).
You can then write a custom url provider for your module.
That's what I've done on my site to rewrite parts of my articles module (e.g. www.ventrian.com/blog/
You can find more information about urlmaster here:
http://www.ifinity.com.au/Products/Url_Master_DNN_SEO_Urls
look at using a URL Rewriter module. There are several third party ones for IIS6, but Microsoft provides one for IIS7 and IIS7.5. You basically configure it with a regular expression and change the output.
Microsoft's rewrite module for IIS7 is available at: http://www.iis.net/downloads/microsoft/url-rewrite
You've got a couple of choices:
Explore the rewrite capabilities available in DNN and how to use them. They can be found in Host Settings > Advanced Settings > Friendly URL Settings. Or use the 2nd option based on which version of IIS you're working on.
2a. URL Rewrite Module for IIS 7 & above
2b. "ISAPI_Rewrite 3" by HeliconTech (has free version too, that does the job pretty well)
You can accomplish what you are looking for without interacting with DNN at all by using an HttpModule. Kind of like this:
public class PidRewriteModule : System.Web.IHttpModule
{
public void Dispose()
{
}
public void Init(System.Web.HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
}
void context_BeginRequest(object sender, EventArgs e)
{
HttpApplication app = sender as HttpApplication;
if (app != null)
{
Match mPidCheck = new Regex(#"^/(?<pid>[0-9]+)/?$").Match(app.Context.Request.Url.AbsolutePath);
if (mPidCheck.Success)
{
app.Context.RewritePath("~/default.aspx", String.Empty, String.Concat("pid=", mPidCheck.Groups["pid"].Value));
}
}
else
return;
}
}
Then you can add this to your Web.config:
<modules runAllManagedModulesForAllRequests="true">
<add name="PidRewriteModule" type="Assembly.Namespace.PidRewriteModule, Assembly"/>
</modules>
Put that in the system.webServer node. Substitute Assembly and Namespace respectively.
All of this info is for IIS7. It's not entirely different for IIS 6, but previous implementations you have to go the route of ISAPI filters.

Sharepoint 2010 does not invoke ProcessRequest of my custom HttpHandler

Well, I know it's IIS which is supposed to invoke it. Anyway; I have a Sharepoint solution which is supposed to return a special string when files with particular extensions are clicked on document libraries.
In the corresponding web.config file I have following to run this HTTP Handler:
<system.webServer>
<handlers>
...
<add name="MyFileHandler" path="*.bar" verb="*" type="Foo.Example.MyHandler, Foo.Example, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3b53a24010893ac2" resourceType="File" />
...
</handlers>
</system.webServer>
And the HttpHandler class is something like this:
namespace Foo.Example
{
public class MyHandler : IHttpHandler
{
public MyHandler(){} //For breakpoint
public void ProcessRequest(HttpContext context)
{
//Do stuff and write to response.
}
public bool IsReusable
{
get { return false; }
}
}
}
When I try to open a file with '.bar' extension on Sharepoint, it returns 404. What I do in ProcessRequest is not relevant because when I debug the handler, I can see that the handler's constructor is invoked but not the 'ProcessRequest'. Besides the debugger I have also put debug lines(File.AppendAll), again only the constructor gets invoked according to the debug output.
IIS 7.5.7600
Sharepoint 2010 Foundation
Turns out
resourceType="File"
on handler tag in web.config was the problem. Either remove it or set it as "Unspecified".
That is already mentioned here which, unfortunately, I failed to spot before.
The only thing I can think of is to try moving your handler to be really the first one.
Otherwise it could be better to actually integrate with SharePoint instead of trying to override its behavior. In this case you probably should post separate question for what you want to achieve.

Categories

Resources