2
votes

I've created a module extension to use with Alfresco 5 Community Edition. Everything works great, I have my .get methods taken care of and they display properly.

On the page I have a button which posts back to the server to display a result (right now it's empty for testing). When I click the button I get a server error:

javax.servlet.ServletException: Possible CSRF attack noted when comparing token in session and request header. Request: POST /share/service/components/console/reset-dashboards
    at org.alfresco.web.site.servlet.CSRFFilter$AssertTokenAction.run(CSRFFilter.java:827)
    at org.alfresco.web.site.servlet.CSRFFilter.doFilter(CSRFFilter.java:312)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:504)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:421)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1074)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:611)
    at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2466)
    at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2455)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Unknown Source)

Checking the webscripts uri at http://localhost:8080/share/page/index/uri/components/console/reset-dashboards I can see everything is registered properly

Reset Dashboards
GET /share/page/components/console/reset-dashboards
Description:    Dashboard Tools - Reset All Dashboards To Default
Authentication: none
Transaction:    none
Format Style:   any
Default Format: html
Id: com/company/components/console/dashboard-tools/reset-dashboards.get
Description:    classpath:alfresco/site-webscripts/com/company/components/console/dashboard-tools/reset-dashboards.get.desc.xml

Reset Dashboards POST
POST /share/page/components/console/reset-dashboards
Description:    Dashboard Tools - Reset All Dashboards To Default POST
Authentication: user
Transaction:    required
Format Style:   any
Default Format: json
Id: com/company/components/console/dashboard-tools/reset-dashboards.post
Description:    classpath:alfresco/site-webscripts/com/company/components/console/dashboard-tools/reset-dashboards.post.desc.xml

This is the information for the GET webscript:

Script Properties
Id: com/company/components/console/dashboard-tools/reset-dashboards.get
Short Name: Reset Dashboards
Description:    Dashboard Tools - Reset All Dashboards To Default
Authentication: none
Transaction:    none
Method: GET
URL Template:   /components/console/reset-dashboards
Format Style:   any
Default Format: html
Negotiated Formats: [undefined]
Implementation: class org.springframework.extensions.webscripts.DeclarativeWebScript
Extensions: [undefined]

Store: classpath:alfresco/site-webscripts

File: com/company/components/console/dashboard-tools/reset-dashboards.get.desc.xml

<webscript>
    <shortname>Reset Dashboards</shortname>
    <description>Dashboard Tools - Reset All Dashboards To Default</description>
    <url>/components/console/reset-dashboards</url>
    <family>admin-console</family>
</webscript>

File: com/company/components/console/dashboard-tools/reset-dashboards.get.html.ftl

<@markup id="css" >
<#-- CSS Dependencies -->
    <@link href="${url.context}/res/components/console/application.css" group="console"/>
</@>

<@markup id="js">
<#-- JavaScript Dependencies -->
    <@script src="${url.context}/res/components/console/consoletool.js" group="console"/>
    <#--<@script src="${url.context}/res/components/console/application.js" group="console"/>-->
</@>

<@markup id="widgets">
    <@createWidgets group="console"/>
</@>

<@markup id="html">
    <#assign el=args.htmlid?html>
    <form id="${el}-options-form" action="${url.context}/service/components/console/reset-dashboards" method="post">
        <div class="buttons">
            <button id="${el}-apply-button" name="apply">${msg("button.reset")}</button>
        </div>
    </form>
</@>

File: com/company/components/console/dashboard-tools/reset-dashboards.get.js

function main()
{
}

main();

Store: classpath:surf/webscripts

[No implementation files]

Store: classpath:webscripts

[No implementation files]

This is the information for the POST webscript:

Script Properties
Id: com/company/components/console/dashboard-tools/reset-dashboards.post
Short Name: Reset Dashboards POST
Description:    Dashboard Tools - Reset All Dashboards To Default POST
Authentication: user
Transaction:    required
Method: POST
URL Template:   /components/console/reset-dashboards
Format Style:   any
Default Format: json
Negotiated Formats: [undefined]
Implementation: class org.springframework.extensions.webscripts.DeclarativeWebScript
Extensions: [undefined]

Store: classpath:alfresco/site-webscripts

File: com/company/components/console/dashboard-tools/reset-dashboards.post.desc.xml

<webscript>
    <shortname>Reset Dashboards POST</shortname>
    <description>Dashboard Tools - Reset All Dashboards To Default POST</description>
    <format default="json" />
    <url>/components/console/reset-dashboards</url>
    <authentication>user</authentication>
</webscript>

File: com/company/components/console/dashboard-tools/reset-dashboards.post.json.ftl

{
    "success": ${success?string},
    "message": "<#if errormsg??>${errormsg}</#if>"
}

File: com/company/components/console/dashboard-tools/reset-dashboards.post.json.js

function main()
{
    model.success = true;
}

main();

Store: classpath:surf/webscripts

[No implementation files]

Store: classpath:webscripts

[No implementation files]

Again, when I click the button on the page to post to the webscript, it gives me a Possible CSRF attack exception. How do I correct this? Is it possible to do it inside the module extension jar file?

UPDATE

I did notice that all other scripts that post as part of Alfresco contain the Alfresco-CSRFToken header and a cookie of the same name. My script only contains Alfresco-CSRFToken as a cookie and is missing as a header. I'm not sure how to make sure this exists as a header though.

1

1 Answers

2
votes

If you are calling repository webscripts in your alfresco share client side script then you need to take care of following points in order to pass CSRF filter.

Try to use standard Alfresco.util.Ajax, alfresco/core/CoreXhr or Alfresco.forms.Form while sending request.

If you are not using any of above then you need to put extra checks related to CSRF tokens as follow.

if (Alfresco.util.CSRFPolicy && Alfresco.util.CSRFPolicy.isFilterEnabled())
{
   xhrHeadersObject[Alfresco.util.CSRFPolicy.getHeader()] = Alfresco.util.CSRFPolicy.getToken();
}

In case of YUI datasource.

   if (Alfresco.util.CSRFPolicy && Alfresco.util.CSRFPolicy.isFilterEnabled())
{
   yuiDataSource.connMgr.initHeader(Alfresco.util.CSRFPolicy.getHeader(), Alfresco.util.CSRFPolicy.getToken(), false);
}

By using above methods you can get rid of CSRF attack related errors in your code.