Dispatcher Security is one of the most ignored things in AEM implementations. I used to wonder why people still do this manually and don’t follow any best practices while configuring it. Adobe recommends using a Security Checklist, but who has got time for doing it manually when you can automate it. And it gets complex with multiple environments having different Dispatcher Configurations.
There is a tool for it Secure CQ which does something similar. But I think it can be done using Groovy quite easily and efficiently.
With this Groovy Script, you can Check Dispatcher Configurations of your website in few seconds and make corrections if anything is missing. Its free, fast, easier to use and open for modifications. Make sure to Change the protocol, domain and one valid page as per your website. None of the curl response should give a 200 status.
/* This script could be used to check the Dispatcher security by checking the <span id="mce_SELREST_start" style="overflow:hidden;line-height:0;"></span>below paths as per Security Checklist https://helpx.adobe.com/experience-manager/dispatcher/using/dispatcher-configuration.html#TestingDispatcherSecurity @author Hashim Khan */ /*Defines the protocol for th website */ def protocol="https://" /*Defines the main domain URL for the website */ def domain="www.intel.com" /*Defines a sample page in the application to check content grabbing. */ def valid_page="/content/www/us/en/homepage" /*Defines a list of security URLs which are used to verify Dispatcher Configurations. You can add more if you like. Current list is from https://helpx.adobe.com/experience-manager/dispatcher/using/dispatcher-configuration.html#TestingDispatcherSecurity */ def list = [ protocol+domain+"/admin", protocol+domain+"/system/console", protocol+domain+"/dav/crx.default", protocol+domain+"/crx", protocol+domain+"/bin/crxde/logs", protocol+domain+"/jcr:system/jcr:versionStorage.json", protocol+domain+"/_jcr_system/_jcr_versionStorage.json", protocol+domain+"/libs/wcm/core/content/siteadmin.html", protocol+domain+"/libs/collab/core/content/admin.html", protocol+domain+"/libs/cq/ui/content/dumplibs.html", protocol+domain+"/var/linkchecker.html", protocol+domain+"/etc/linkchecker.html", protocol+domain+"/home/users/a/admin/profile.json", protocol+domain+"/home/users/a/admin/profile.xml", protocol+domain+"/libs/cq/core/content/login.json", protocol+domain+"/content/../libs/foundation/components/text/text.jsp", protocol+domain+"/content/.{.}/libs/foundation/components/text/text.jsp", protocol+domain+"/apps/sling/config/org.apache.felix.webconsole.internal.servlet.OsgiManager.config/jcr%3acontent/jcr%3adata", protocol+domain+"/libs/foundation/components/primary/cq/workflow/components/participants/json.GET.servlet", protocol+domain+"/content.pages.json", protocol+domain+"/content.languages.json", protocol+domain+"/content.blueprint.json", protocol+domain+"/content.-1.json", protocol+domain+"/content.10.json", protocol+domain+"/content.infinity.json", protocol+domain+"/content.tidy.json", protocol+domain+"/content.tidy.-1.blubber.json", protocol+domain+"/content/dam.tidy.-100.json", protocol+domain+"/content/content/geometrixx.sitemap.txt", protocol+domain+valid_page+".query.json?statement=//*", protocol+domain+valid_page+".qu%65ry.js%6Fn?statement=//*", protocol+domain+valid_page+".query.json?statement=//*[@transportPassword]/(@transportPassword%20|%20@transportUri%20|%20@transportUser)", protocol+domain+valid_page+"/_jcr_content.json", protocol+domain+valid_page+"/_jcr_content.feed", protocol+domain+valid_page+"/jcr:content.feed", protocol+domain+valid_page+"._jcr_content.feed", protocol+domain+valid_page+".jcr:content.feed", protocol+domain+valid_page+".docview.xml", protocol+domain+valid_page+".docview.json", protocol+domain+valid_page+".sysview.xml", protocol+domain+"/etc.xml", protocol+domain+"/content.feed.xml", protocol+domain+"/content.rss.xml", protocol+domain+"/content.feed.html", protocol+domain+valid_page+".html?debug=layout" ] list.each { checkUrlGetStatus(it) } checkUserGeneratedPath(protocol,domain) checkDispatcherInvalidation(protocol,domain) /*Method to make a GET call for the above list. */ def checkUrlGetStatus(String path) { print path+" , " def process ="curl -s -o /dev/null -w %{http_code} ${path} ".execute().text printf("%2s", "STATUS:") process.each { text-> print "${text}" } println "" } /*Method to make a POST call for the user generated path. */ def checkUserGeneratedPath(String protocol,String domain) { print "POST:"+protocol+domain+"/content/usergenerated/mytestnode ," def process ="curl -X POST -s -o /dev/null -w %{http_code} -u anonymous:anonymous ${protocol}${domain}/content/usergenerated/mytestnode".execute().text printf("%2s", "STATUS:") process.each { text-> print "${text}" } println "" } /*Method to make a Dispatcher invalidation call. */ def checkDispatcherInvalidation(String protocol,String domain) { print "Dispatcher Invalidation: "+protocol+domain+"/dispatcher/invalidate.cache ," def process ="curl -s -o /dev/null -w %{http_code} -H \'CQ-Handle:/content\' -H \'CQ-Path:/content\' ${protocol}${domain}/dispatcher/invalidate.cache".execute().text printf("%2s", "STATUS:") process.each { text-> print "${text}" } }
By using this script you can check your Dispatcher Configurations in lower environments too. It highly advisable to use same Dispatcher Configurations in your lower and prod environments. Personally, I use Jenkins build to deploy dispatcher configurations from GIT to all the environments.
I hope this will help you to automate this task.
Follow the GITHUB page for more such interesting scripts. https://github.com/hashimkhan786