Question

I am trying to use apache shiro into my project as I have to create a role based mechanism into my project. I created a demo project with following configurations...

I created following files into my project -

index.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Shiro Web Test</title>
</head>
<body>
<h1>This is a test for Shiro Web Framework</h1>

<a href = "success.jsp">Click Here!</a>
</body>
</html>

login.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Shiro Web Test : Login Page</title>
</head>
<body>
<%! String errorMessage = null; %>
<% 
errorMessage = (String) request.getAttribute("shiroLoginFailure");
if (errorMessage != null) { %>
<font color="red">Invalid Login: ${errorMessage}</font><br/>
<font color="black"><h3>Enter login information...</h3></font>
<% } else { %>
<font color="black"><h3>Enter login information...</h3></font>
<% } %>

<form action="loginTest.do" method="POST">
<table>
<tr>
<td>Username:</td>
<td><input type="text" name="username" placeholder="username" /></td>
</tr>
<tr>
<td>Password:</td>
<td><input type="password" name="password" placeholder="password" /></td>
</tr>
</table>
<input type="checkbox" value="true" name="rememberMe" />Remember Me?<br />
<input type="submit" value="Sign In" />
</form>
</body>
</html>

success.jsp
denied.jsp
logout.jsp
showUser.jsp

My shiro.ini configuration is as follows -

# =======================
# Shiro INI configuration
# =======================

[main]
authc = org.apache.shiro.web.filter.authc.FormAuthenticationFilter
roles = org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
authc.loginUrl = /login.jsp
authc.failureKeyAttribute = shiroLoginFailure
roles.unauthorizedUrl = /denied.jsp

[users]
admin = password, ROLE_ADMIN
member = password, ROLE_MEMBER

[roles]
ROLE_ADMIN = *

[urls]
/success.jsp = authc, roles[ROLE_MEMBER]
/secret.jsp = roles[ROLE_ADMIN]

I am using a servlet LoginTestServlet.java to dispatch to login.jsp page or success.jsp after authentication is successful/unsuccessful -

public class LoginTestServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        generateResponse(request, response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        generateResponse(request, response);
    }

    protected void generateResponse(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        UserCredentials user = new UserCredentials();
        user.setUserName(request.getParameter("username"));
        user.setPassword(request.getParameter("password"));

        if (user.getUserName() != null && user.getPassword() != null) {
            Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
            SecurityManager securityManager = factory.getInstance();
            SecurityUtils.setSecurityManager(securityManager);
            Subject currentUser = SecurityUtils.getSubject();

            UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(), user.getPassword());

            try {
                currentUser.login(token);
                Session session = currentUser.getSession();
                session.setAttribute("user", user.getUserName());
            } catch (UnknownAccountException uae) {
                request.setAttribute("shiroLoginFailure", uae.getMessage());
                System.err.println("Exception type: " + uae.getClass().getName());
                System.err.println("Error due to: " + uae.getMessage());
            } catch (IncorrectCredentialsException iae) {
                request.setAttribute("shiroLoginFailure", iae.getMessage());
                System.err.println("Exception type: " + iae.getClass().getName());
                System.err.println("Error due to: " + iae.getMessage());
            } catch (LockedAccountException lae) {
                request.setAttribute("shiroLoginFailure", lae.getMessage());
                System.err.println("Exception type: " + lae.getClass().getName());
                System.err.println("Error due to: " + lae.getMessage());
            } catch (AuthenticationException ae) {
                request.setAttribute("shiroLoginFailure", ae.getMessage());
                System.err.println("Exception type: " + ae.getClass().getName());
                System.err.println("Error due to: " + ae.getMessage());
            } catch (Exception e) {
                request.setAttribute("shiroLoginFailure", e.getMessage());
                System.err.println("Exception type: " + e.getClass().getName());
                System.err.println("Error due to: " + e.getMessage());
            }

            RequestDispatcher view = null;

            if (currentUser.isAuthenticated() && currentUser.hasRole("ROLE_MEMBER")) {
                view = request.getRequestDispatcher("success.jsp");
                view.forward(request, response);
            } else if (currentUser.isAuthenticated() && currentUser.hasRole("ROLE_ADMIN")) {
                view = request.getRequestDispatcher("secret.jsp");
                view.forward(request, response);
            } else {
                view = request.getRequestDispatcher("login.jsp");
                view.forward(request, response);
            }
        }
    }//end of generateResponse()

}//end of class

I am using TOMCAT 6.0.

My problem is -

  1. Whenever I am trying to enter credentials at login.jsp page, its automatically taking me to the respective page for the credentials I enter. Ex., if I try to enter ROLE_MEMBER credentials after clicking for success.jsp, its taking me to success.jsp page. But if I try to enter ROLE_ADMIN after clicking for same success.jsp, its automatically taking me to secret.jsp as per the servlet code written instead of going to denied.jsp.
  2. How to make a generic code without writing a separate servlet for each resource to show login success or denied page?

Also, is there any way to create custom permissions in shiro for every resource? If yes, then how. If there is any link to this, I would be grateful to you.

Thanks all.

Was it helpful?

Solution

I'm wondering why you've decided to handle the authentication inside a servlet rather than using the pre-built filter as is already defined in the guide (among other things, you seem to be reloading the configuration and creating a new SecurityManager on every request...). The filter should handle the details in #1 for you.

If you insist on using a servlet, you need to add a value either to the session or as a parameter to the request to login.jsp which tells it where it should redirect the user after successful authentication and read that parameter once the user is authenticated.

Regarding #2, you are simply forwarding success.jsp after successful authentication. You aren't either 1) explicitly checking the user's roles or allowing the framework to do so for you. Again, switching to the filter should resolve this for you.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top