7

I am getting a 403 forbidden-error every time I try GET a user's information from the database. Relating to my code below, every time I try request by pressing the Ajax Test button, It fails to run and gives me an alert, but also in the console gives me a 403 Forbidden-error. I am not sure whether it has something to do with Spring security?

Users JSP page:

<table>
    <tr>
        <td>User Id</td>
        <td>Full Name</td>
        <td>Username</td>
        <td>Email</td>
        <td>Date of Birth</td>
        <td>User Authority</td>
        <td>Update </td>
        <td>Delete</td>
    </tr>
    <c:forEach var="user" items="${users}">
        <tr>
            <td><c:out value="${user.id}" /></td>
            <td><c:out value="${user.name}"/></td>
            <td><c:out value="${user.username}"/></td>
            <td><c:out value="${user.email}"/></td>
            <td><c:out value="${user.dob}"/></td>
            <td><c:out value="${user.authority}"/></td>
            <td>
                <a id="update" href="<c:url value="/viewUser"><c:param name="id" value="${user.id}"/></c:url>"><button>Update</button></a>
            </td>
            <td>
                <a id="delete" href="<c:url value="/deleteUser"><c:param name="id" value="${user.id}"/></c:url>"><button>Delete</button></a>
            </td>
            <td>
                <button class="loadUser" name="id" value="${user.id}">Ajax test</button>
            </td>
        </tr>
    </c:forEach>
</table>
 <div id="personIdResponse"> </div>
<script type="text/javascript">
    $(document).ready(function(){
        $(".loadUser").click(function(e) {
            e.preventDefault();
            var personId = +$(this).val();
            $.get('${pageContext.request.contextPath}/SDP/ajaxTest/' + personId, function(user) {
                  $('#personIdResponse').text(user.name + ', = username ' + user.username);
                })
            .fail(function(user){
                alert('Could not load user');
            });
        });
    });
</script>

User Controller class:

    @RequestMapping("/viewUser")
public String updateUser(Model model, @RequestParam(value = "id", required = false) Integer id) {

    User user = usersService.getUser(id);

    model.addAttribute("user", user);

    return "settings";
}

@RequestMapping("/ajaxTest")
@ResponseBody
public User ajaxTest(@RequestParam(value = "id", required = false) Integer id) {

    User user = usersService.getUser(id); 
    return user;
}
Ouissal
  • 1,519
  • 2
  • 18
  • 36
Maff
  • 1,032
  • 4
  • 25
  • 42
  • like this http://stackoverflow.com/questions/11185285/ajax-jquery-call-getting-networkerror-403-forbidden-error-in-response – Sitansu Sep 30 '13 at 09:56
  • How would I implement this JSONP with my already existing code? – Maff Sep 30 '13 at 10:03
  • 403 forbidden error can come if request is broken or there arre cross domain issues. Please check your request. – Vineet Kasat Sep 30 '13 at 11:55

5 Answers5

28

It is usually caused by Spring default CSRF protection.

If you use for example DELETE HTTP request from your JS code, it is required to send also CSRF protection headers.

It is not necessary to disable CSRF protection! Please, do not do that if not necessary.

You can easily add CSRF AJAX/REST protection by:

1.Adding meta headers to every page (use @layout.html or something):

<head>
  <meta name="_csrf" th:content="${_csrf.token}"/>
  <meta name="_csrf_header" th:content="${_csrf.headerName}"/>
</head>

2.Customizing your ajax requests to sent these headers for every request:

$(function () {
  var token = $("meta[name='_csrf']").attr("content");
  var header = $("meta[name='_csrf_header']").attr("content");
  $(document).ajaxSend(function(e, xhr, options) {
    xhr.setRequestHeader(header, token);
  });
});

Notice that i use thymeleaf, so i use th:content instead of content attribute.

lukyer
  • 7,595
  • 3
  • 37
  • 31
5

If you are using Spring Security 3.2R1 and above try using this solution http://spring.io/blog/2013/08/21/spring-security-3-2-0-rc1-highlights-csrf-protection

chege
  • 323
  • 5
  • 16
2

As of Spring Security 4.0, CSRF protection is enabled by default with XML configuration. If you would like to disable CSRF protection, the corresponding XML configuration can be seen below.

<security:http use-expressions="true">
           ...
   <security:csrf disabled="true" />
</security:http>
Pradip Kharbuja
  • 3,442
  • 6
  • 29
  • 50
1

Check files permissions. 403 is server error, not Ajax. Try to check requested file (by file i mean url) directly.

Choinek
  • 313
  • 2
  • 13
0

In Spring Rest or other REST implementations (like Jersey) if there is no matching resources at server side then 403 Forbidden is thrown by REST containers.

You need to re-validate req-response annotations.

For example, for ajaxTest request try this change:

@RequestMapping("/ajaxTest/{personid}", method=RequestMethod.GET)
@ResponseBody
public User ajaxTest(@PathVariable Integer personid) { .. }

Basically person-id doesn't look like a request parameter (which we set in GET URL), try changing to to PathVariable and if you are not sure on default method in Spring REST, explicitly define for which HTTP-Method this method should get invoked.

On 403, it implies that operation not allowed or many similar reasons apart from auth failure. Take a look at http://en.wikipedia.org/wiki/HTTP_403 for various possibilities.

harsh
  • 7,502
  • 3
  • 31
  • 32
  • I just tried implementing this, but I got the exact same problem. – Maff Sep 30 '13 at 10:17
  • @RequestMapping(value="/ajaxTest/{personId}", method=RequestMethod.GET) @ResponseBody public User ajaxTest(@PathVariable Integer personId) { User user = usersService.getUser(personId); return user; } That is my update code in the controller. – Maff Sep 30 '13 at 10:20
  • Can you post your `rest-servlet.xml` as well? looks like by `@ResponseBody` you are expecting `json` conversion, do you have have `jackson` jar in classpath? not sure if this might be the case for `403` for `Spring REST`, but better to check.. – harsh Sep 30 '13 at 10:27
  • Also, what's your controller's `RequestMapping` url? – harsh Sep 30 '13 at 10:31
  • I havn't got a rest-servlet.xml config file. I do have the jackson jar in the class path though. – Maff Sep 30 '13 at 10:34
  • Without proper json conversion your req wouldn't succeed. Check json mapping configuration http://www.ibm.com/developerworks/library/wa-restful/ (listing-1), this should help. – harsh Sep 30 '13 at 10:40
  • @Harsh If there is no matching resource at server side in Spring then 404 error is thrown, not 403. Also error codes have nothing to do with framework, it is tomcat dependent. – Vineet Kasat Sep 30 '13 at 11:53
  • It is not `tomcat` dependent at least in this case, `404` is a sure case of not having matching resource (based on `url`) but `403` can come if operation is not allowed (e.g. accept-type in request is `txt` but at resource it is configured as `json`, this is one of a `403` case and surely not `404`) – harsh Sep 30 '13 at 11:58
  • @VineetKasat My above comment is purely based on `REST` spec (`jsr-311`) and implementation (in this case `Spring REST`) which has nothing to do with tomcat or any other web-server. – harsh Sep 30 '13 at 12:00
  • @Harsh 403 can come if request is broken. 403 means request has not reached server. – Vineet Kasat Sep 30 '13 at 12:04
  • Not true (in some cases it may be), 403 in case is always sent either by `REST` container (i.e. `Jersey`, `Spring REST`) or by application code (i.e. apps authentication filter where on auth failure `Response.FORBIDDEN` is thrown, http://stackoverflow.com/a/6527453/878732). `ResponseCode` javadoc https://jersey.java.net/nonav/apidocs/1.5/jersey/javax/ws/rs/core/Response.Status.html which is heavily used by application code to return specific status. – harsh Sep 30 '13 at 12:16