javascriptjqueryajaxrestxwiki

xwiki REST ajax call error


Hi all i have an istance of xwiki on my localhost, for a test purpose i wanted to test the RESTful api by writing some simple jquery script:

<script type="text/javascript">

var username = "Admin";
var password ="admin";  

function make_base_auth(user, password) 
  {

    var tok = user + ':' + password;
    var hash = btoa(tok);
    alert(hash);
    return "Basic " + hash;

  }

var url = "http://localhost:8080/xwiki/rest/wikis/query?q=object:XWiki.XWikiUsers";
var returnData = "";
$.ajax({
    type: "GET",
    dataType: "xml",
    crossDomain: true,
    async: true,
    url: url,
     headers: {"authorization":  make_base_auth(username, password), "Access-Control-Allow-Origin": "*" },

    error: function(request, status, error) 
    {   
        alert(error) 
    },
    success: function(data) 
    {
       alert("success");

    }

       });    
</script>

the error i get is:

XMLHttpRequest cannot load http://localhost:8080/xwiki/rest/wikis/query?q=object:XWiki.XWikiUsers. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.

but trying with postman i get the correct result...i'm missing something? thanks


Solution

  • In the default configuration XWiki does not allow CORS; you need to enable it in the web.xml

    To allow sending authentication data with the authentication header, edit the file web.xml and add a new filter among the section with the filters:

    <filter>
      <filter-name>Set CORS headers very lenitent</filter-name>
      <filter-class>org.xwiki.container.servlet.filters.internal.SetHTTPHeaderFilter</filter-class>
      <init-param>
        <param-name>name</param-name>
        <param-value>Access-Control-Allow-Headers</param-value>
      </init-param>
      <init-param>
        <param-name>value</param-name>
        <param-value>authorization</param-value>
      </init-param>
    </filter>
    

    Now you need to activate the filter; further down among the filter-mappings add your own:

    <filter-mapping>
      <filter-name>Set CORS headers very lenitent</filter-name>
      <servlet-name>RestletServlet</servlet-name>
    </filter-mapping>
    

    (and yes, if you do not like the filter name, use a different name, just use the same name in both places.)

    As you figured out in the comments, allowing several HTTP headers works like:

    <filter>
      <filter-name>Set CORS headers very lenitent</filter-name>
      <filter-class>org.xwiki.container.servlet.filters.internal.SetHTTPHeaderFilter</filter-class>
      <init-param>
        <param-name>name</param-name>
        <param-value>Access-Control-Allow-Headers</param-value>
      </init-param>
      <init-param>
        <param-name>value</param-name>
        <param-value>authorization, content-type</param-value>
      </init-param>
    </filter>
    

    (in this case allowing both the authorization header and a "non-standard" Content-Type header) (side note: headers are case-nsensitive: Are HTTP headers case-sensitive?)

    Also you need to allow CORS in general for REST-request; for this search for:

    <!-- We set the CORS policy globally for webjars.
       ... longer comment ....
      -->
    <filter-mapping>
      <filter-name>Set CORS policy for fonts</filter-name>
      <servlet-name>resourceReferenceHandler</servlet-name>
      <url-pattern>/webjars/*</url-pattern>
      <url-pattern>*.woff</url-pattern>
      <url-pattern>*.eot</url-pattern>
      <url-pattern>*.ttf</url-pattern>
      <dispatcher>REQUEST</dispatcher>
      <dispatcher>FORWARD</dispatcher>
    </filter-mapping>
    

    edit the filter-mapping and add a line <servlet-name>RestletServlet</servlet-name> to activate this filter for the rest servlet, too:

    <filter-mapping>
      <filter-name>Set CORS policy for fonts</filter-name>
      <servlet-name>resourceReferenceHandler</servlet-name>
      <servlet-name>RestletServlet</servlet-name>
      <url-pattern>/webjars/*</url-pattern>
      [...]
    

    After a restart of the servlet container the AJAX request should now work.