23

I would like to control the access after the user log in my system.

For example:

administrator : can add, delete and give rights to employee
employee : fill forms only
...

So after knowing which right the user has, checking in database, I would like to restrict what this user can see and do. There's a simple way to do that ?

EDIT

@WebFilter("/integra/user/*")
public class LoginFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {    
        HttpServletRequest req = (HttpServletRequest) request;
        Authorization authorization = (Authorization) req.getSession().getAttribute("authorization");

        if (authorization != null && authorization.isLoggedIn()) {
            // User is logged in, so just continue request.
            chain.doFilter(request, response);
        } else {
            // User is not logged in, so redirect to index.
            HttpServletResponse res = (HttpServletResponse) response;
            res.sendRedirect(req.getContextPath() + "/integra/login.xhtml");
        }
    }

    // You need to override init() and destroy() as well, but they can be kept empty.


    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void destroy() {
    }
}
Kukeltje
  • 12,223
  • 4
  • 24
  • 47
Valter Silva
  • 16,446
  • 52
  • 137
  • 218
  • 2
    How are you authenticating the users? By container managed authentication (`j_security_check` or `request.login()`) or by a homebrewed servlet filter on a session attribute? – BalusC Sep 20 '12 at 16:31
  • @BalusC,Hello my friend! Long time no talk with you. I'm using a servlet filter that you teach me a long time ago, which I'm gonna post it here. – Valter Silva Sep 20 '12 at 17:17
  • 1
    You could check out http://jguard.sourceforge.net/mvnsite/docbook/en_jGuard_reference.html#d108e3815 We had to create a custom EL function to check if a user has a certain role though (to use in rendered attributes for example) – Jasper de Vries Sep 20 '12 at 18:18
  • 1
    I'm quite curious about this myself. Can't really recall the scope of seam 3 security nor similar concepts in codi but they may be useful. Deltaspike will add this for v 0.4 (the next one) iirc. I have also peeked at apache shiro but decided against it. I have decided to halt my auth logic for now and wait for v.04 of deltaspike – Karl Kildén Sep 20 '12 at 19:56

1 Answers1

35

Well, this is a pretty broad subject. As you're starting off with homebrewed authentication, I'll target the answer on homebrewed authorization.


Role checking in Java/JSF is at its own relatively simple if the model is sensibly designed. Assuming that a single user can have multiple roles (as is often the case in real world applications), you'd ultimately like to end up having something like:

public class User {

    private List<Role> roles;

    // ...

    public boolean hasRole(Role role) {
        return roles.contains(role);
    }

}
public enum Role {

    EMPLOYEE, MANAGER, ADMIN;

}

so that you can check it as follows in your JSF views:

<h:selectManyCheckbox value="#{user.roles}" disabled="#{not user.hasRole('ADMIN')}">
    <f:selectItems value="#{Role}" />
</h:selectManyCheckbox>
<h:commandButton value="Delete" rendered="#{user.hasRole('ADMIN')}" />

and in your filter:

String path = req.getRequestURI().substring(req.getContextPath().length());

if (path.startsWith("/integra/user/admin/") && !user.hasRole(Role.ADMIN)) {
    res.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}

The hardest part is translating this Java model to a sane DB model. There are several different ways depending on the concrete business requirements, each with its own (dis)advantages. Or perhaps you already have a DB model on which you have to base your Java model (thus, you need to design bottom-up)?

Anyway, assuming that you're using JPA 2.0 (your question history at least confirms this) and that you can design top-down, one of the easiest ways would be to map the roles property as an @ElementCollection against an user_roles table. As we're using a Role enum, a second role table isn't necessary. Again, that depends on the concrete functional and business requirements.

In generic SQL terms, the user_roles table can look like this:

CREATE TABLE user_roles (
    user_id BIGINT REFERENCES user(id),
    role VARCHAR(16) NOT NULL,
    PRIMARY KEY(user_id, role)
)

Which is then to be mapped as follows:

@ElementCollection(targetClass=Role.class, fetch=FetchType.EAGER)
@Enumerated(EnumType.STRING)
@CollectionTable(name="user_roles", joinColumns={@JoinColumn(name="user_id")})
@Column(name="role")
private List<Role> roles;

That's basically all you'd need to change in your User entity.


Next to homebrewed authentication (login/logout) and authorization (role checking), there is also Java EE provided container managed authentication with which you can login by j_security_check or HttpServletRequest#login(), filter HTTP requests by <security-constraint> in web.xml, check the logged-in user by #{request.remoteUser} and its roles by #{request.isUserInRole('ADMIN')}, etc.

Then there are several 3rd party frameworks such as PicketLink, Spring Security, Apache Shiro, etc. But this is all out of the question :)

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555