Pergunta

My web application at the moment accepts REST requests and handled via some controllers, which calls corresponding services to perform the logic.

Now I want to add in some security logic before calling the services. This includes checking if a service can be accessed ALSO amend the request body if necessary. I am having trouble on deciding where and how this security layer should be added.

Solution 1 is to create secured versions for each of the services, wrapping the original service and replace them in each of the controllers. Expose the secured services only and make the original services private/package protected. This way all my services remain separated in their own modules and security is enforced. But I may as well just update the services, without having an extra layer?

Solution 2 is to create one single Security service and takes in service requests from controllers, does the security checks, amends the request body, then dispatch the updated requests to corresponding services. This way I can have just one security module and security is enforced but this module has to know each of the services in order to dispatch to correct services.

Solution 3 is to create one single Security service and let the corresponding controllers to use it at will. In other words, individual controller handles some of the security logic. e.g. a controller calls security check, then passes in request body to get the amended request before calling the service. This way I can have just one security module and this module does not need to know each of the services, but it is not protecting any services and acting just like an utility class. i.e. there is no enforcing that new controller must go through this security logic.

Is there a solution that can enforce security, remain in its own module and no dependency to existing services?

Foi útil?

Solução

Use a filter (interceptor pattern) and add a SecurityFilter class to your Servlet... There are a ton of examples out there... I'll give you one of mine:

    import java.io.IOException;
    import java.util.Map;

    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;

    import com.turnmarker.next.models.DistributedSessionModel;
    import com.turnmarker.next.models.PayloadModel;

    @Component
    @Order(0)
    public class AuthenticationFilterBean extends AbstractBean implements Filter {

        /**
         * 
         */
        private static final long serialVersionUID = 8592924875474194043L;

        @SuppressWarnings("unused")
        private FilterConfig fc;

        // TODO: CHANGE THIS SO THAT SESSION's ARE STORED/RETRIEVED FROM A DISTRIBUTED-SESSION-MAP:
        @Autowired
        private DistributedSessionModel dsm; // = DistributedSessionModel.getInstance();

        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

            // CAST INTO SOMETHING WE CAN MANIPULATE:
            HttpServletRequest req = (HttpServletRequest) request;
            Map<String, String[]> params = request.getParameterMap();

            // SESSION's ARE STORED/RETRIEVED FROM THE DISTRIBUTED-SESSION-MAP:
            HttpSession session = req.getSession(false);

            if ((null != session) && (dsm.contains(session.getId()))) {

                getLogger().warn("I found your session: " + session.getId());

                if (params.get("TURN") == null) {

                    trace("AuthenticationFilterBean::doFilter() --> HttpServletRequest is missing a required parameter.");

                    // JUST GO-AWAY:
                    response.reset();
                    // response.getOutputStream().close();

                    // INSTANTIATE:
                    HttpServletResponse res = (HttpServletResponse) response;

                    // CONFIGURE:
                    // res.setContentType("application/json");
                    res.sendError(HttpServletResponse.SC_BAD_REQUEST, "Required headers not specified in the request");

                    // GOODBYE, CRUEL WORLD:
                    res.getOutputStream().flush();

                    // AND CLOSE:
                    res.getOutputStream().close();

                    // AND RETURN:
                    return;

                } else {

                    trace("AuthenticationFilterBean::doFilter() --> Required parameter located on HttpServletRequest.");

                }

            }

            // OTHERWISE:
            chain.doFilter(request, response);

        }

        @Override
        public void destroy() {

            trace("AuthenticationFilterBean::destroy() --> Method called");

        }

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

            trace("AuthenticationFilterBean::init() --> Method called");

            // STORE:
            this.fc = conf;

        }

        // LOGGER IMPLEMENTATION:
        protected Logger logger = LoggerFactory.getLogger(PayloadModel.class);

        protected Logger getLogger() {

            return logger;

        }

        protected void setLogger(Logger logger) {

            this.logger = logger;

        }

    }
Licenciado em: CC-BY-SA com atribuição
scroll top