public void Test(string original, string expected, string defaults, string overrides )
        {
            Config c = new Config();
            var defs = new Dictionary<string, ResizeSettings>();
            defs.Add("p", new ResizeSettings(defaults));
            var sets = new Dictionary<string, ResizeSettings>();
            sets.Add("p", new ResizeSettings(overrides));
            new Presets(defs,sets,false).Install(c);

            var e = new UrlEventArgs("/image.jpg",new ResizeSettings(original));
            c.Pipeline.FireRewritingEvents(null, null, e);
            Dictionary<string,string> expectedDict = new Dictionary<string,string>(StringComparer.OrdinalIgnoreCase);
            var ex = new ResizeSettings(expected);
            foreach(string k in ex.Keys)
                expectedDict[k] = ex[k];
            Dictionary<string,string> dict = new Dictionary<string,string>(StringComparer.OrdinalIgnoreCase);
            foreach(string k in e.QueryString.Keys)
                dict[k] = e.QueryString[k];

            Assert.AreElementsEqualIgnoringOrder<KeyValuePair<string, string>>(expectedDict,dict);
        }
Example #2
0
        /// <summary>
        /// This is where we filter requests and intercept those that want resizing performed.
        /// We first strip FakeExtension, then verify the remaining file extension is supported for decoding.
        /// We fire URL rewriting events. If the result includes any supported querystring params afterwards, we process the request. Otherwise we let it fall back to IIS/ASP.NET.
        /// If the file doesn't exist, we also ignore the request. They're going to cause a 404 anyway.
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected virtual void CheckRequest_PostAuthorizeRequest(object sender, EventArgs e)
        {
            //Skip requests if the Request object isn't populated
            HttpApplication app = sender as HttpApplication;
            if (app == null) return;
            if (app.Context == null) return;
            if (app.Context.Request == null) return;

            conf.FirePostAuthorizeRequest(this, app.Context);

            //Allow handlers of the above event to change filePath/pathinfo so we can successfull test the extension
            string originalPath = conf.PreRewritePath;

            //Trim fake extensions so IsAcceptedImageType will work properly
            string filePath = conf.TrimFakeExtensions(originalPath);

            //Is this an image request? Checks the file extension for .jpg, .png, .tiff, etc.
            if (conf.SkipFileTypeCheck || conf.IsAcceptedImageType(filePath)) {
                //Copy the querystring so we can mod it to death without messing up other stuff.
                NameValueCollection q = conf.ModifiedQueryString;

                //Call URL rewriting events
                UrlEventArgs ue = new UrlEventArgs(filePath, q);
                conf.FireRewritingEvents(this, app.Context,ue);

                //Pull data back out of event object, resolving app-relative paths
                string virtualPath = PathUtils.ResolveAppRelativeAssumeAppRelative(ue.VirtualPath);
                q = ue.QueryString;

                //Store the modified querystring in request for use by VirtualPathProviders
                conf.ModifiedQueryString = q; // app.Context.Items["modifiedQueryString"] = q;

                //See if resizing is wanted (i.e. one of the querystring commands is present).
                //Called after processPath so processPath can add them if needed.
                //Checks for thumnail, format, width, height, maxwidth, maxheight and a lot more
                if (conf.HasPipelineDirective(q)) {
                    //Who's the user
                    IPrincipal user = app.Context.User as IPrincipal;

                    // no user (must be anonymous...).. Or authentication doesn't work for this suffix. Whatever, just avoid a nullref in the UrlAuthorizationModule
                    if (user == null)
                        user = new GenericPrincipal(new GenericIdentity(string.Empty, string.Empty), new string[0]);

                    //Do we have permission to call UrlAuthorizationModule.CheckUrlAccessForPrincipal?
                    bool canCheckUrl = System.Security.SecurityManager.IsGranted(new System.Security.Permissions.SecurityPermission(System.Security.Permissions.PermissionState.Unrestricted));

                    //Run the rewritten path past the auth system again, using the result as the default "AllowAccess" value
                    bool isAllowed = true;
                    if (canCheckUrl && !app.Context.SkipAuthorization) try {
                            isAllowed = UrlAuthorizationModule.CheckUrlAccessForPrincipal(virtualPath, user, "GET");
                        } catch (NotImplementedException) { } //For MONO support

                    IUrlAuthorizationEventArgs authEvent = new UrlAuthorizationEventArgs(virtualPath, new NameValueCollection(q), isAllowed);

                    //Allow user code to deny access, but not modify the url or querystring.
                    conf.FireAuthorizeImage(this, app.Context, authEvent);

                    if (!authEvent.AllowAccess) throw new ImageProcessingException(403, "Access denied", "Access denied");

                    //Does the file exist physically? (false if VppUsage=always or file is missing)
                    bool existsPhysically = (conf.VppUsage != VppUsageOption.Always) && System.IO.File.Exists(HostingEnvironment.MapPath(virtualPath));

                    //If not present physically (and VppUsage!=never), try to get the virtual file. Null indicates a missing file
                    IVirtualFile vf = (conf.VppUsage != VppUsageOption.Never && !existsPhysically) ? conf.GetFile(virtualPath, q) : null;

                    //Only process files that exist
                    if (existsPhysically || vf != null) {
                        try{
                            HandleRequest(app.Context, virtualPath, q, vf);
                            //Catch not found exceptions
                        } catch (System.IO.FileNotFoundException notFound) { //Some VPPs are optimisitic , or could be a race condition
                            FileMissing(app.Context, virtualPath, q);
                            throw new ImageMissingException("The specified resource could not be located", "File not found", notFound);
                        } catch (System.IO.DirectoryNotFoundException notFound) {
                            FileMissing(app.Context, virtualPath, q);
                            throw new ImageMissingException("The specified resource could not be located", "File not found", notFound);
                        }
                    } else
                        FileMissing(app.Context, virtualPath, q);

                }
            }
        }
        public PostAuthorizeResult PostAuthorize()
        {
            conf.FirePostAuthorizeRequest(sender as IHttpModule, context);

            conf.FireHeartbeat();

            //Allow handlers of the above event to change filePath/pathinfo so we can successfully test the extension
            string originalPath = conf.PreRewritePath;

            //Trim fake extensions so IsAcceptedImageType will work properly
            string filePath = conf.TrimFakeExtensions(originalPath);

            //Is this an image request? Checks the file extension for .jpg, .png, .tiff, etc.
            if (!(conf.SkipFileTypeCheck || conf.IsAcceptedImageType(filePath)))
            {
                return(PostAuthorizeResult.UnrelatedFileType);
            }

            //Copy the querystring so we can mod it to death without messing up other stuff.
            NameValueCollection queryCopy = new NameValueCollection(conf.ModifiedQueryString);

            Performance.GlobalPerf.Singleton.PreRewriteQuery(queryCopy);

            //Call URL rewriting events
            UrlEventArgs ue = new UrlEventArgs(filePath, queryCopy);

            conf.FireRewritingEvents(sender, context, ue);

            //Pull data back out of event object, resolving app-relative paths
            RewrittenVirtualPath  = PathUtils.ResolveAppRelativeAssumeAppRelative(ue.VirtualPath);
            RewrittenQuery        = ue.QueryString;
            RewrittenInstructions = new Instructions(RewrittenQuery);

            //Store the modified querystring in request for use by VirtualPathProviders during URL Authorization
            conf.ModifiedQueryString = RewrittenQuery;

            RewrittenVirtualPathIsAcceptedImageType = conf.IsAcceptedImageType(RewrittenVirtualPath);
            RewrittenQueryHasDirective = conf.HasPipelineDirective(RewrittenQuery);
            RewrittenMappedPath        = HostingEnvironment.MapPath(RewrittenVirtualPath);

            ProcessingIndicated = false;
            CachingIndicated    = false;

            if (RewrittenQueryHasDirective)
            {
                //By default, we process it if is both (a) a recognized image extension, and (b) has a resizing directive (not just 'cache').
                //Check for resize directive by removing ('non-resizing' items from the current querystring)
                ProcessingIndicated = RewrittenInstructions.Process == ProcessWhen.Always ||
                                      ((RewrittenInstructions.Process == ProcessWhen.Default || RewrittenInstructions.Process == null) &&
                                       RewrittenVirtualPathIsAcceptedImageType &&
                                       conf.HasPipelineDirective(RewrittenInstructions.Exclude("cache", "process", "useresizingpipeline", "404", "404.filterMode", "404.except")));

                CachingIndicated = RewrittenInstructions.Cache == ServerCacheMode.Always ||
                                   ((RewrittenInstructions.Cache == ServerCacheMode.Default || RewrittenInstructions.Cache == null) && ProcessingIndicated);

                //Resolve the 'cache' setting to 'no' unless we want it cache. TODO: Understand this better
                if (!CachingIndicated)
                {
                    RewrittenInstructions.Cache = ServerCacheMode.No;
                }

                Performance.GlobalPerf.Singleton.QueryRewrittenWithDirective(RewrittenVirtualPath);
            }


            if (RewrittenQueryHasDirective || conf.AuthorizeAllImages)
            {
                var authEvent = new UrlAuthorizationEventArgs(RewrittenVirtualPath, new NameValueCollection(RewrittenQuery), true);

                //Allow user code to deny access, but not modify the URL or querystring.
                conf.FireAuthorizeImage(sender, context, authEvent);

                if (!authEvent.AllowAccess)
                {
                    return(PostAuthorizeResult.AccessDenied403);
                }
            }
            return(PostAuthorizeResult.Complete);
        }
Example #4
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        /// <param name="virtualPath"></param>
        /// <param name="settings"></param>
        public void ExecuteVirtualPathResult(ControllerContext context, string virtualPath, NameValueCollection settings)
        {
            var app = (HttpApplication) context.HttpContext.GetService(typeof(HttpApplication));

            NameValueCollection q = settings;

            //Call URL rewriting events
            UrlEventArgs ue = new UrlEventArgs(virtualPath, q);
            conf.FireRewritingEvents(null, app.Context,ue);

            //Pull data back out of event object, resolving app-relative paths
            virtualPath = PathUtils.ResolveAppRelativeAssumeAppRelative(ue.VirtualPath);
            q = ue.QueryString;

            //Store the modified querystring in request for use by VirtualPathProviders
            conf.ModifiedQueryString = q;

            bool isAllowed = true;
            if (this.ReauthorizeFinalPath){
                //Who's the user
                IPrincipal user = app.Context.User as IPrincipal;
                // no user (must be anonymous...).. Or authentication doesn't work for this suffix. Whatever, just avoid a nullref in the UrlAuthorizationModule
                if (user == null)  user = new GenericPrincipal(new GenericIdentity(string.Empty, string.Empty), new string[0]);
                //Do we have permission to call UrlAuthorizationModule.CheckUrlAccessForPrincipal?
                bool canCheckUrl = System.Security.SecurityManager.IsGranted(new System.Security.Permissions.SecurityPermission(System.Security.Permissions.PermissionState.Unrestricted));
                //Run the rewritten path past the auth system again, using the result as the default "AllowAccess" value
                if (canCheckUrl) try {
                            isAllowed = UrlAuthorizationModule.CheckUrlAccessForPrincipal(virtualPath, user, "GET");
                        } catch (NotImplementedException) { } //For MONO support

            }

            //Allow user code to deny access, but not modify the url or querystring.
            IUrlAuthorizationEventArgs authEvent = new UrlAuthorizationEventArgs(virtualPath, new NameValueCollection(q), isAllowed);
            conf.FireAuthorizeImage(null, app.Context, authEvent);

            if (!authEvent.AllowAccess) throw new ImageProcessingException(403, "Access denied", "Access denied");

            //Does the file exist physically? (false if VppUsage=always or file is missing)
            bool existsPhysically = (conf.VppUsage != VppUsageOption.Always) && System.IO.File.Exists(HostingEnvironment.MapPath(virtualPath));

            //If not present physically (and VppUsage!=never), try to get the virtual file. Null indicates a missing file
            IVirtualFile vf = (conf.VppUsage != VppUsageOption.Never && !existsPhysically) ? conf.GetFile(virtualPath, q) : null;

            //Only process files that exist
            if (existsPhysically || vf != null) {
                try{
                    ExecuteVirtualFileResult(app.Context, virtualPath, q, vf);
                    //Catch not found exceptions
                } catch (System.IO.FileNotFoundException notFound) { //Some VPPs are optimisitic , or could be a race condition
                    FileMissing(app.Context, virtualPath, q);
                    throw new ImageMissingException("The specified resource could not be located", "File not found", notFound);
                }
            } else
                FileMissing(app.Context, virtualPath, q);
        }