Hey Jason, That would solve the selector problem, but it wouldn't really solve the suffix problem though. But that one can be fixed in the same way although I would expect the whitelisting to be a bit tougher in that one ;), seeing as suffix is used as a dynamic variable most of the times. For my specific needs I did solve it now by actually looking at the request and seeing if the modification date equals the actual asset modification date. Thanks for all the help!
Resource resource = request.getResource(); if(resource instanceof NonExistingResource) { LOG.info("Asset resource {} using the cdn selector does not exist", resource.getPath()); response.sendError(404); } else if(!"last-modified".equals(getSuffixSegment(request, 0))) { LOG.info("Asset resource {} is not using the last modified suffix", resource.getPath()); response.sendError(404); } else if(resource.adaptTo(Asset.class) == null) { LOG.info("Resource {} is not an asset", resource.getPath()); response.sendError(404); } else if(!String.valueOf(((Asset)resource.adaptTo(Asset.class)).getLastModified()).equals(getSuffixSegment(request, 1))) { LOG.info("Asset resource {} does not have the same last modified date as request: {}", resource.getPath(), getSuffixSegment(request, 1)); response.sendError(404); } else { RequestDispatcherOptions opts = new RequestDispatcherOptions(); opts.setReplaceSelectors(""); RequestDispatcher dispatcher = request.getRequestDispatcher(resource, opts); if(dispatcher != null) { dispatcher.forward(request, response); } else { LOG.error("Could not get request dispatcher for asset resource {}", resource.getPath()); } } Greets Roy > On 1 Aug 2016, at 16:26, Jason Bailey <jason.bai...@sas.com> wrote: > > If we're talking dispatcher, then yes, this is the wrong list :) However if > we focus on the general concern, which is that as a by-product of its design. > There is an inherent exploit which can result in DOS attack when using a > cache. > > One solution might be a generic selector filter, one that can accept a list > of patterns to whitelist or blacklist. > > -----Original Message----- > From: Roy Teeuwen [mailto:r...@teeuwen.be] > Sent: Saturday, July 30, 2016 6:58 AM > To: users@sling.apache.org > Subject: Re: Getting the actual resource from a request > > Hey Jason, > > Just come back to the dispatcher caching problem you saw. I think this is > actually a global problem that happens anywhere, is there any rule in the > dispatcher to be able stop this? Just to look at a fun real life example: > > http://wwwimages.adobe.com/content/dam/Adobe/images/shared/product_mnemonics/48x48/dreamweaver-no-shadow-48x48.png > > <http://wwwimages.adobe.com/content/dam/Adobe/images/shared/product_mnemonics/48x48/dreamweaver-no-shadow-48x48.png> > http://wwwimages.adobe.com/content/dam/Adobe/images/shared/product_mnemonics/48x48/dreamweaver-no-shadow-48x48.png./test.jpg > > <http://wwwimages.adobe.com/content/dam/Adobe/images/shared/product_mnemonics/48x48/dreamweaver-no-shadow-48x48.png./test.jpg> > http://wwwimages.adobe.com/content/dam/Adobe/images/shared/product_mnemonics/48x48/dreamweaver-no-shadow-48x48.png./test/another.jpg > > <http://wwwimages.adobe.com/content/dam/Adobe/images/shared/product_mnemonics/48x48/dreamweaver-no-shadow-48x48.png./test/another.jpg> > > It seems to make a new image in the dispatcher cache for every request. But I > guess we would be on the wrong list to discuss something like this ;) > > Greets > Roy > > >> On 29 Jul 2016, at 15:04, Roy Teeuwen <r...@teeuwen.be> wrote: >> >> Hey Jason, >> >> You are absolutely right, damn :)! It’s because I didn’t realise that the >> .jpg didn’t count as extension. I’m going to keep it with a suffix though: >> /content/dam/nice-image.jpg.cdn./mod-date/20160815/nice-image.jpg just so >> that in the browser it still looks like the image is called nice-image.jpg >> ;). >> >> And you are also right about the second part, sadly enough :P. So maybe it >> would be safe to make the servlet after all, so that I can check the >> mod-date suffix part and see if that asset actually exists with that last >> modified date and only return it then, and else return a 404. This would >> solve the caching possibility of infinite image issue! >> >> Thanks >> Roy >> >> >>> On 29 Jul 2016, at 14:31, Jason Bailey <jason.bai...@sas.com> wrote: >>> >>> Roy, >>> >>> I think you may slap your forehead on this one :) You had to >>> implement a service because when you added the cdn between the image >>> name and the jpeg. It broke the resource resolution. That's why you >>> had problems with the request.getResource() >>> >>> Once you fixed it by moving the selector, the resource is identified. That >>> means, it's found the image. You don't need to have a service. The Sling >>> application will take your URL, identify the resource and return that >>> resource. >>> >>> So if all you did was just append .%timestamp$. to the end of your >>> assets it will do what you want it do >>> >>> content/dam/nice-image.jpg.20160815. >>> >>> This is a nice idea for cdn's but you need to be aware of a potential >>> issue. I know, from a dispatcher point of view that the ability to add >>> selectors to any resource and return the original resource is a potential >>> attack vector. An example would be if that url you gave was behind a >>> dispatcher that does caching. I could sit there and call that asset with a >>> millisecond time stamp and each time I did it, it would be cached, and the >>> cache would get larger. Until some point I have consumed all of your disk >>> space. >>> >>> I'm assuming a similar type issue with cdn's >>> >>> -Jason >>> >>> -----Original Message----- >>> From: Roy Teeuwen [mailto:r...@teeuwen.be] >>> Sent: Friday, July 29, 2016 8:14 AM >>> To: users@sling.apache.org >>> Subject: Re: Getting the actual resource from a request >>> >>> Hey all, >>> >>> Ok so I fixed it finally by doing the following: >>> >>> @SlingServlet( >>> resourceTypes = "sling/servlet/default", >>> selectors = "cdn" >>> ) >>> @Service({Servlet.class}) >>> public class CDNAssetServlet extends SlingSafeMethodsServlet { >>> >>> private static final Logger LOG = >>> LoggerFactory.getLogger(CDNAssetServlet.class); >>> >>> @Override >>> protected void doGet(SlingHttpServletRequest request, >>> SlingHttpServletResponse response) throws ServletException, IOException { >>> Resource resource = request.getResource(); >>> if (resource instanceof NonExistingResource) { >>> LOG.info("Asset resource {} using the cdn selector does not >>> exist", resource.getPath()); >>> response.sendError(HttpServletResponse.SC_NOT_FOUND); >>> } else { >>> RequestDispatcherOptions opts = new RequestDispatcherOptions(); >>> opts.setReplaceSelectors(""); >>> RequestDispatcher dispatcher = >>> request.getRequestDispatcher(resource, opts); >>> if (dispatcher != null) { >>> dispatcher.forward(request, response); >>> } else { >>> LOG.error("Could not get request dispatcher for asset resource >>> {}", resource.getPath()); >>> } >>> } >>> } >>> } >>> >>> And then using the url provided by Jason :) thanks! >>> @Olivier >>> Still don’t know what you meant by just serving the resource instead of >>> forwarding it, if you have an example you can still give it for when it >>> would be more performant/better. >>> Thanks all, >>> Greets >>> Roy >>> >>> >>> >>>> On 29 Jul 2016, at 00:01, Roy Teeuwen <r...@teeuwen.be> wrote: >>>> >>>> Also lastly to combine with my previous mail, it doesn’t have to be >>>> only images. It could also be pdf’s, zips,… So the approach I am >>>> using now won’t work in all the cases I want :) >>>> >>>> >>>>> On 28 Jul 2016, at 23:44, Roy Teeuwen <r...@teeuwen.be> wrote: >>>>> >>>>> Hey Jason, Olivier, >>>>> >>>>> @Jason: >>>>> Damn, I feel so stupid now :D indeed, using >>>>> /content/dam/nice-image.jpg.cdn./modification-date/20160815/nice-image.jpg >>>>> fixes everything. I don’t have to implement the nonexistingservlet >>>>> anymore ;), I was indeed thinking that jpg was the extension and so that >>>>> the cdn HAD to be before the jpg because else the cdn would be the >>>>> extension, but your explanation makes sense! >>>>> >>>>> @Olivier: >>>>> "What's the reason for forwarding instead of reading/serving the resource >>>>> from the repository in your current servlet?” Currently I am doing it >>>>> like that, but I find the implementation a bit nasty… See how I did it: >>>>> >>>>> @Override >>>>> protected void doGet(SlingHttpServletRequest request, >>>>> SlingHttpServletResponse response) throws ServletException, IOException { >>>>> Resource resource = request.getResource(); >>>>> final Image image = new Image(resource); >>>>> image.set(Image.PN_REFERENCE, resource.getPath()); >>>>> try { >>>>> final String mimeType = image.getMimeType(); >>>>> final Layer layer = image.getLayer(false, false, false); >>>>> double quality = mimeType.equals(MIME_TYPE_GIF) ? 255 : 1.0; >>>>> response.setContentType(mimeType); >>>>> layer.write(mimeType, quality, response.getOutputStream()); >>>>> response.getOutputStream().flush(); >>>>> } catch (RepositoryException e) { >>>>> LOG.error("could not get layer", e); >>>>> } >>>>> } >>>>> >>>>> Thats why I would think it would be easier / nicer to just forward it to >>>>> the normal jpg handling servlet so that I don’t actually have to manually >>>>> write it to the servlet response output. If there is a better way in >>>>> serving the image resource from the repo, do tell :D. >>>>> >>>>> (For when you might be curious on why I am doing all of this, I am >>>>> adding the latest modification date to all the image urls because >>>>> the image urls actually get served by a cdn in front that proxies >>>>> to the >>>>> dam: >>>>> https://some.azureedge.net/content/dam/nice-image.jpg.cdn./modifica >>>>> ti on-date/20160815/nice-image.jpg , this way when the same image >>>>> gets replaced in the dam by a new image with the same name on a >>>>> page, I don’t have to invalidate the azure cdn cache because the >>>>> modification date changing in the url takes care of that, and >>>>> because I am not using a query string I also don’t have to care >>>>> about nullifying the browser client-side caching) >>>>> >>>>> Thanks so far! >>>>> Greets, >>>>> Roy >>>>> >>>>> >>>>>> On 28 Jul 2016, at 23:02, Jason Bailey <jason.bai...@sas.com> wrote: >>>>>> >>>>>> I was going to say that you shouldn't need to implement >>>>>> NonExistingResource interface because a selector wouldn't impact >>>>>> resolution then I had one of those blinding aha moments. >>>>>> >>>>>> In the case of the url you posted you aren't adding a selector, you are >>>>>> modifying the resource name. '/content/dam/nice-image.jpg' does not >>>>>> have an extension in the traditional sense, in the traditional sling >>>>>> sense the resource would actually be '/content/dam/nice-image' and jpg >>>>>> would be a handler that would return the asset as a jpeg. >>>>>> >>>>>> So when you are adding a selector to it it's not matching anything >>>>>> because there is no '/content/dam/nice-image' resource to match against. >>>>>> >>>>>> So first make your request find the resource without the servlet in the >>>>>> way. If you switch around the .cdn to the end and add a period at the >>>>>> end of cdn like this... >>>>>> >>>>>> content/dam/nice-image.jpg.cdn./modification-date/20160815/nice-im >>>>>> ag >>>>>> e.jpg >>>>>> >>>>>> This should work to return the original nice-image.jpg at that point it >>>>>> should be easier to create a servlet that will have the resource as part >>>>>> of the request. >>>>>> >>>>>> Or optionally you could try adding a sling:resourceType to the image and >>>>>> have a selector within that resource type that does what you need it do. >>>>>> >>>>>> -Jason >>>>>> >>>>>> >>>>>> >>>>>> -----Original Message----- >>>>>> From: Roy Teeuwen [mailto:r...@teeuwen.be] >>>>>> Sent: Thursday, July 28, 2016 3:17 PM >>>>>> To: users@sling.apache.org >>>>>> Subject: Re: Getting the actual resource from a request >>>>>> >>>>>> Hmm Sorry Jason, >>>>>> >>>>>> I might have had to notice that I am extending SlingSafeMethodServlet >>>>>> but also implementing the following servlet: >>>>>> https://docs.adobe.com/docs/en/cq/5-6-1/javadoc/com/day/cq/commons >>>>>> /s ervlets/NonExistingResourceServlet.html >>>>>> >>>>>> And as it states in the docs itself, it also says: >>>>>> public boolean accepts(SlingHttpServletRequest request) { >>>>>> // get non-existing path (incl. selectors and extension!) >>>>>> String path = request.getResource().getPath(); >>>>>> // return true if this servlet can handle this path >>>>>> return true; >>>>>> } >>>>>> >>>>>> So probably it’s not possible to do it through this interface in without >>>>>> manually parseing :) It also says in the docs: Please note: This is a >>>>>> temporary solution until Sling provides a built-in mechanism for this >>>>>> use case. Not to be used by client implementations! >>>>>> >>>>>> Any clue if it is possible yet to do it with standard sling, the thing I >>>>>> try to achieve is a servlet that also catches resources with a selector >>>>>> AND suffix (as stated in my example of course) ? >>>>>> >>>>>> Thanks! >>>>>> Roy >>>>>> >>>>>> >>>>>>> On 28 Jul 2016, at 18:35, Jason Bailey <jason.bai...@sas.com> wrote: >>>>>>> >>>>>>> I'm under the understanding that it is; >>>>>>> >>>>>>> request.getResource().getPath() >>>>>>> >>>>>>> -----Original Message----- >>>>>>> From: Roy Teeuwen [mailto:r...@teeuwen.be] >>>>>>> Sent: Thursday, July 28, 2016 12:31 PM >>>>>>> To: users@sling.apache.org >>>>>>> Subject: Getting the actual resource from a request >>>>>>> >>>>>>> Hey all, >>>>>>> >>>>>>> I am creating a SlingServlet that will work by both using a >>>>>>> selector and a suffix. The resource is for example >>>>>>> /content/dam/image.jpg and the actual url will be >>>>>>> /content/dam/nice-image.cdn.jpg/modification-date/20160815/nice-image. >>>>>>> jpg >>>>>>> >>>>>>> What is the most easy way to get the actual resource path again from >>>>>>> the SlingHttpServletRequest? Currently I am doing the following but I >>>>>>> find it a bit cumbersome: >>>>>>> >>>>>>> private String getResourcePath(SlingHttpServletRequest request) { >>>>>>> String requestUrl = >>>>>>> request.getRequestPathInfo().getResourcePath(); >>>>>>> int endIndex = >>>>>>> requestUrl.lastIndexOf(request.getRequestPathInfo().getSuffix()); >>>>>>> String resourcePathWithSelector = requestUrl.substring(0, >>>>>>> endIndex); endIndex = >>>>>>> resourcePathWithSelector.lastIndexOf(request.getRequestPathInfo() >>>>>>> .getSelectorString() + "." + >>>>>>> request.getRequestPathInfo().getExtension()); >>>>>>> return resourcePathWithSelector.substring(0, endIndex) + >>>>>>> request.getRequestPathInfo().getExtension(); >>>>>>> } >>>>>>> >>>>>>> Is there an easier way or is parsing it like this the only way? >>>>>>> >>>>>>> Also after I got the actual resourcePath, I tried doing the following, >>>>>>> but this doesn’t seem to work, any clue on why? >>>>>>> >>>>>>> @Override >>>>>>> protected void doGet(SlingHttpServletRequest request, >>>>>>> SlingHttpServletResponse response) throws ServletException, IOException >>>>>>> { >>>>>>> RequestDispatcherOptions opts = new RequestDispatcherOptions(); >>>>>>> opts.setReplaceSelectors(""); >>>>>>> String resourcePath = getResourcePath(request); >>>>>>> RequestDispatcher dispatcher = >>>>>>> request.getRequestDispatcher(resourcePath, opts); >>>>>>> if (dispatcher != null) { >>>>>>> dispatcher.forward(request, response); >>>>>>> } >>>>>>> } >>>>>>> >>>>>>> I would expect that the previous would actually just forward it >>>>>>> to the actual image being fetched from the getResourcePath but it >>>>>>> just gives me a 404 not found (I checked the getResourcePath and >>>>>>> it does return >>>>>>> /content/dam/nice-image.jpg) >>>>>>> >>>>>>> Thanks! >>>>>>> Roy >>>>>> >>>>> >>>> >>> >> >