Search code examples
apachesecurityauthenticationshiro

Apache Shiro and Multi-factor Authentication


I am working on a application where I have implemented Apache Shiro based authentication. I can now get a user to log in successfully backed by my database. I know want to improve on this and allow a second long step.

So scenario would be:

User 1 does not have multi-factor authentication enabled. He logs in with credentials successfully.

User 2 does have multi-factor authentication enabled. His logs in as usual, and Apache Shiro validates username/password. Once this is done I want Apache Shiro to display another screen where User 2 can enter a one time password. And only when this is correct be fully logged in.

At point in Apache Shiro can I inject my changes? I couldn't find much documentation on it.


Solution

  • I had a similar requirement that was for OTP after authentication and i used normal filter to filter out all requests. MAke a attribute in use bean like isOTPEnabled and compare it in filter.

    My simple otpFliter Code is as follows but you can make your own according to need like jsf, etc. You have to add a login that if a user bean has a OTPenabled set true only then it filters:

    /**
     * Servlet Filter implementation class OTPFilter
     */
    @WebFilter(urlPatterns = {"/*"},initParams={@WebInitParam(name="enabled",value="0")})
    public class OTPFilter implements Filter {
    
        /**
         * Default constructor. 
         */
    
        boolean enabled=true;
    
    
        public OTPFilter() {
            // TODO Auto-generated constructor stub
        }
    
        /**
         * @see Filter#destroy()
         */
        public void destroy() {
            // TODO Auto-generated method stub
        }
    
        /**
         * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
         */
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            // TODO Auto-generated method stub
            // place your code here
    
            // pass the request along the filter chain
            //System.out.println(enabled);
                if(enabled){
                if(SecurityUtils.getSubject().getPrincipal()!=null){
                    if(request instanceof HttpServletRequest ){
                        HttpSession session = ((HttpServletRequest) request).getSession();
                        LoggedInUser user =  (LoggedInUser) session.getAttribute("userinfo");
                        String url = ((HttpServletRequest) request).getRequestURL().toString();
                        //System.out.println("url is "+ url);
    
                        if( !url.contains("public") && !user.isOTPverified() && user.isOTPEnabled()){
    
    
    
                            if(user.getOTP() == null)
                                {
                                    user.setOTP(OTPUtils.generateOTP());
                                }
                            //user.setOTPverified(true);                        
                            ((HttpServletRequest) request).getRequestDispatcher("OTP.jsp").forward(request, response);
    
                            return;
                        }
                    }
                }
    
    
                }
    
            chain.doFilter(request, response);
        }
    
        /**
         * @see Filter#init(FilterConfig)
         */
        public void init(FilterConfig fConfig) throws ServletException {
            // TODO Auto-generated method stub
            //System.out.println("fConfig.getInitParameter :" + fConfig.getInitParameter("enabled"));
             enabled = fConfig.getInitParameter("enabled").equals("1");
        }
    
    }