Search code examples
restxmlhttprequesthttp-status-code-403dspace

DSpace Rest API - Creating a new Top level Communtity - 403 preflight response invalid status code


I just want to create a new community and within that i plan to add subcommunities, Collections, Items and Bitstreams but, When I use post http request it says unauthorized. Then I managed to use the url for login to become authorized. But now I have a different problem.

My code is:

<html>
<head>
<title>Welcome To Dspace REST</title>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
</head>
<body>
<div ng-app="myApp" ng-controller="myCtrl" >

    <input type="button" value="login"ng-click="login()"/></br></br>

<h1>{{data1}}</h1>
    <input type="button" value="status"ng-click="status()"/></br></br>
<h1>{{status}}</h1>

<input type="button" value="create a new customer"ng-click="createCustomer()"/></br></br>

<h1>{{show}}</h1>
<input type="button" value="logout"ng-click="logout()"/></br></br>

<h1>{{logout}}</h1>

<!--<div ng-init="myVar = 'http://www.w3schools.com'">
<h1>Tutorials</h1>
<p>Go to <a ng-href="{{myVar}}">{{myVar}}</a> to learn!</p>
</div>-->


</div>

<script>
var app = angular.module('myApp', []);

    app.config(function ($httpProvider) {
        $httpProvider.defaults.headers.common = {};

        $httpProvider.defaults.headers.put = {};
        $httpProvider.defaults.headers.patch = {};
    });

app.controller('myCtrl', function($scope, $http, $sce) {
//start showItem
$scope.createCustomer=function(){
var url = 'https://localhost:8443/rest/communities'//+document.getElementById("1").value;

var json={
    "id":"1",
    "name":"A test community",
    "shortDescription":"Community created with JSON"
}
//start http      



$http.post(url,json).success(function(data) {

                        $scope.show=data;
                        });
//end http
}
//end showItem
$scope.login=function(){

    $http.post("https://localhost:8443/rest/login",{email:"mohan",password:"mohan"}).success(function(data){$scope.data1=data;});   //login

}

$scope.status=function(){
    console.log($scope.data1);
    $http.get("https://localhost:8443/rest/status",{"rest-dspace-token":$scope.data1}).success(function(resp){$scope.status=resp});

}

$scope.logout=function(){

    var req = {
        method: 'POST',
        url: 'https://localhost:8443/rest/logout',
        headers: {
            'rest-dspace-token': $scope.data1
        }

    }


    $http(req).success(function(data){$scope.logout=data;});   //login

}

//start changeDlink()
$scope.changeDlink=function(){
//$scope.url=  $sce.trustAsUrl('https://localhost:8443/rest/bitstreams/'+document.getElementById("1").value+'/retrieve');
$scope.url= $sce.trustAsResourceUrl('https://localhost:8443/rest/bitstreams/'+document.getElementById("1").value+'/retrieve');
$scope.furl= $sce.trustAsResourceUrl('https://localhost:8443/rest/bitstreams/'+document.getElementById("1").value+'/retrieve?');
}
});


</script>
</body>
</html>

But I keep getting this error...

XMLHttpRequest cannot load https://localhost:8443/rest/logout. Response for preflight has invalid HTTP status code 403

But, When I login the response is 200 OK and I get a login token as response. But when i try to logout this error comes outta console.

The following is my web.xml for Dspace REST:

<?xml version="1.0" encoding="UTF-8"?>
<!--

    The contents of this file are subject to the license and copyright
    detailed in the LICENSE and NOTICE files at the root of the source
    tree and available online at

    http://www.dspace.org/license/

-->
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         id="WebApp_ID" version="2.5">
    <servlet>
        <servlet-name>DSpace REST API</servlet-name>
        <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
        <init-param>
            <!--
             The jersey ServletContainer will look for our Root Resource Class
             (i.e. our HelloWorld class) in the foo.bar package
             There are other ways to register this; see the jersey documentation for
             more details
            -->
            <param-name>com.sun.jersey.config.property.packages</param-name>
            <param-value>org.dspace.rest</param-value>
        </init-param>
        <init-param>
            <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
            <param-value>true</param-value>
        </init-param>
        <!--
        Load the ServletContainer at startup.  A value of 1 indicates the ServletContainer
        is a high priority servlet to load
         -->
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>DSpace REST API</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

    <!-- Security settings and mapping -->
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>DSpace REST API</web-resource-name>
            <url-pattern>/*</url-pattern>
        </web-resource-collection>
        <user-data-constraint>
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </user-data-constraint>
    </security-constraint>

    <!-- DSpace Configuration Information -->
    <context-param>
        <param-name>dspace-config</param-name>
        <param-value>/dspace/config/dspace.cfg</param-value>
    </context-param>

    <!-- new ConfigurationService initialization for dspace.dir -->
    <context-param>
        <description>
            The location of the main DSpace configuration file
        </description>
        <param-name>dspace.dir</param-name>
        <param-value>/dspace</param-value>
    </context-param>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/applicationContext.xml
        </param-value>
        <!--
            Add this context if using Spring Security
            /WEB-INF/applicationContext-security.xml
        -->
    </context-param>

    <!-- 
       DSpace Kernel startup listener. This listener is in charge of initializing/starting the
       DSpace Kernel. It MUST be listed BEFORE any other DSpace listeners, as DSpace services
       will not function until the Kernel is initialized.
    -->
    <listener>
        <listener-class>org.dspace.servicemanager.servlet.DSpaceKernelServletContextListener</listener-class>
    </listener>

    <listener>
        <listener-class>org.dspace.app.util.DSpaceContextListener</listener-class>
    </listener>

    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>
<!--cors request filter-->
<filter>
  <filter-name>CorsFilter</filter-name>
  <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
  <init-param>
    <param-name>cors.allowed.origins</param-name>
    <param-value>*</param-value>
  </init-param>
  <init-param>
    <param-name>cors.allowed.methods</param-name>
    <param-value>GET,POST,HEAD,OPTIONS,PUT</param-value>
  </init-param>
  <init-param>
    <param-name>cors.allowed.headers</param-name>
    <param-value>Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers</param-value>
  </init-param>
  <init-param>
    <param-name>cors.exposed.headers</param-name>
    <param-value>Access-Control-Allow-Origin,Access-Control-Allow-Credentials</param-value>
  </init-param>
  <init-param>
    <param-name>cors.support.credentials</param-name>
    <param-value>true</param-value>
  </init-param>
  <init-param>
    <param-name>cors.preflight.maxage</param-name>
    <param-value>10</param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>CorsFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

</web-app>

The Reason why I have added this is I have already included the cors filter. I am not getting any error when retreiving data.

And the code through which i could access the metadata and all information is

<html>
<head>
<title>Welcome To Dspace REST</title>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
</head>
<body>
<div ng-app="myApp" ng-controller="myCtrl" >

<p>Today's welcome message is:</p>

<input type="button" value="Show Items"ng-click="showItems()"/></br></br>
<h1>{{showALL}}</h1>
<input id="1" type="text" placeholder="Enter the id here" ng-keyup="changeDlink()"/>
<input type="button" value="Show Item"ng-click="showItem()"/>


<input type="button" value="Store Item"ng-click="storeItems()" ng-hide="true"/>
<input type="button" value="Show Item MetaData" ng-click="showItemMeta()"/>

<h1>{{show}}</h1>
<ul ng-repeat="item in show">
    <li>            
      {{item.key}}: {{item.value}}
    </li>
  </ul> 

<form method="get" action="{{url}}">
<button type="submit">Retreive Items</button>
</form>
<a download="bitstreams/8/retrieve.txt" ng-href="{{url}}">Download</a>

<!--<div ng-init="myVar = 'http://www.w3schools.com'">
<h1>Tutorials</h1>
<p>Go to <a ng-href="{{myVar}}">{{myVar}}</a> to learn!</p>
</div>-->


</div>


<iframe ng-src="{{furl}}" width="1000px" height= "1200px"> </iframe>
<script>
var app = angular.module('myApp', []);

app.controller('myCtrl', function($scope, $http, $sce) {
//start showItem
$scope.showItem=function(){
var url = 'https://localhost:8443/rest/items/'+document.getElementById("1").value;

//start http      

$http.get(url).success(function(data) {

                        $scope.show=data;
                        });
//end http
}
//end showItem

$scope.showItems=function(){
var url = 'https://localhost:8443/rest/items';

//start http      

$http.get(url).success(function(data) {

                        $scope.showALL=data;
                        });
//end http
}

$scope.showItemMeta=function(){
var url = 'https://localhost:8443/rest/items/'+document.getElementById("1").value+"/metadata";

//start http      

$http.get(url).success(function(data) {

                        $scope.show=data;
                        });
//end http
}


//start changeDlink()
$scope.changeDlink=function(){
//$scope.url=  $sce.trustAsUrl('https://localhost:8443/rest/bitstreams/'+document.getElementById("1").value+'/retrieve');
$scope.url= $sce.trustAsResourceUrl('https://localhost:8443/rest/bitstreams/'+document.getElementById("1").value+'/retrieve');
$scope.furl= $sce.trustAsResourceUrl('https://localhost:8443/rest/bitstreams/'+document.getElementById("1").value+'/retrieve?');
}
});


</script>
</body>
</html>

I already gone through searching for a day in both google and stackoverflow and try most of the things.

But, Nothing did work!

Is there anyone to help me!


Solution

  • Finally, I have got the correct method for doing this.

    I had to maintain the login session using a token named "rest-dspace-token".

    But, I didn't add it on my cor-allowed-headers list(web.xml).

    Now, I changed my web.xml and everything works fine.

    Here's what i have changed!

    <filter>
      <filter-name>CorsFilter</filter-name>
      <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
      <init-param>
        <param-name>cors.allowed.origins</param-name>
        <param-value>*</param-value>
      </init-param>
      <init-param>
        <param-name>cors.allowed.methods</param-name>
        <param-value>GET,POST,HEAD,OPTIONS,PUT</param-value>
      </init-param>
      <init-param>
        <param-name>cors.allowed.headers</param-name>
        <param-value>Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,rest-dspace-token</param-value>
      </init-param>
      <init-param>
        <param-name>cors.exposed.headers</param-name>
        <param-value>Access-Control-Allow-Origin,Access-Control-Allow-Credentials</param-value>
      </init-param>
      <init-param>
        <param-name>cors.support.credentials</param-name>
        <param-value>true</param-value>
      </init-param>
    
    </filter>
    <filter-mapping>
      <filter-name>CorsFilter</filter-name>
      <url-pattern>/*</url-pattern>
    </filter-mapping>