views:

497

answers:

4

I'm trying to make a simple forum just to get the hang of the Spring Security and MVC frameworks.

For simplicity's sake, let's I have a JSP to view a forum post, which looks like the following:

<body>
    ...

    Title: ${forumPost.title} <br>
    Author: ${forumPost.author.name} <br>
    Message: {forumPost.message} <br>

    <security:authorize ifAnyGranted="ROLE_ADMIN">
        Edit: <a href="/edit">Edit</a>
    </security:authorize>

    ...
</body>

My problem is: not only should an Administrator be able to edit this post, but the original author should be able to as well. Therefore, I only want ROLE_ADMIN and the original author to be able to see the Edit link. However I'm not sure how to filter by user with the security:authorize tag, or if I'll need to go about this a different way.

Any suggestions would be much appreciated. Thanks!

A: 

Does your Author object implement equals in such a way that each author is unique?

If so, you could simply check if the Author is the same as the current user (You'd have two sets of tags).

TM
This would work, but ideally I'd like to find a way to do this within the confines of the Spring Security framework.
Alex Beardsley
+3  A: 

Assuming that you have a controller that sits behind this page, I would simply add a canEditPost field to the ModelAndView that looks something like (semi-pseudocode):

private boolean isAdmin() {
    Authentication currentAuthObj = SecurityContextHolder.getContext().getAuthentication();
    List<GrantedAuthority> authorities = Arrays.asList(currentAuthObj.getAuthorites());
    for (GrantedAuthority auth : authorities) {
        if ("ROLE_ADMIN".equals(auth.getAuthority())) {
            return true;
        }
    }
    return false;
}

boolean currentUserIsAuthor = ...;

modelAndView.addObject("canEditPost", 
    Boolean.valueOf(currentUserIsAuthor || isAdmin());

And then in your view just reference $canEditPost.

It's generally better for the view to just reference a simple flag in the model than have the view/template doing the actual logic.

matt b
A: 

@matt b's answer is a great way to do it and is probably what I'll end up doing. But I found another way that is a bit more complicated but will achieve what I put in this post.

I did a bit of reading and found out that you can handle security at the domain object level and essentially give read/write/delete privileges to a role or to an arbitrary object, for example, the current user ID. In this example, I would give the current user id access to a domain object, in this case a ForumPost object that has its own unique id from the database.

The current user id would then be granted read and write access, which can (via the XML configuration) be defined as a custom role of sorts (I believe the correct term is actually Voter). I could then name this voter *MESSAGE__EDIT*.

So, in my JSP I could then use the following:

*security:authorize ifAnyGranted="MESSAGE_EDIT"*

And it would (again, through XML configuration) get the current user id and give access based on the current domain object, in this case, a ForumPost object.

It is a fair bit more work than it sounds, but it can definitely be done.

Some documentation on all this can be found in the Domain Object Security section in the Spring Security Reference Documentation (http://static.springframework.org/spring-security/site/reference/html/springsecurity.html (for some reason the link to the Domain object Security section is broken for now)).

Alex Beardsley
A: 

you can have conditions

<% if(mycondition.isTrue()){ %>
<security:authorize ifAnyGranted="ROLE_ADMIN">
    Edit: <a href="/edit">Edit</a>
</security:author
<% }%>
Milhous
Yes I know. As I mentioned to @TM, I'd like to find a way to do this within the confines of the Spring Security framework, preferably without using scriptlets (i.e. the <% %>)
Alex Beardsley