teichmann@5861: /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde teichmann@5861: * Software engineering by Intevation GmbH teichmann@5861: * teichmann@5993: * This file is Free Software under the GNU AGPL (>=v3) teichmann@5861: * and comes with ABSOLUTELY NO WARRANTY! Check out the teichmann@5993: * documentation coming with Dive4Elements River for details. teichmann@5861: */ teichmann@5861: teichmann@5835: package org.dive4elements.river.client.server.filter; felix@4436: teichmann@5835: import org.dive4elements.river.client.server.auth.Authentication; teichmann@5835: import org.dive4elements.river.client.server.auth.AuthenticationException; teichmann@5835: import org.dive4elements.river.client.server.auth.AuthenticationFactory; teichmann@5835: import org.dive4elements.river.client.server.auth.User; teichmann@5835: import org.dive4elements.river.client.server.features.Features; felix@4436: felix@4436: import java.io.IOException; bjoern@4549: import java.net.InetAddress; bjoern@4549: import java.net.UnknownHostException; felix@4436: import java.util.Enumeration; felix@4436: felix@4436: import javax.servlet.Filter; felix@4436: import javax.servlet.FilterChain; felix@4436: import javax.servlet.FilterConfig; felix@4436: import javax.servlet.ServletContext; felix@4436: import javax.servlet.ServletException; felix@4436: import javax.servlet.ServletRequest; felix@4436: import javax.servlet.ServletResponse; felix@4436: import javax.servlet.http.HttpServletRequest; felix@4436: import javax.servlet.http.HttpServletResponse; felix@4436: import javax.servlet.http.HttpSession; felix@4436: felix@4436: import org.apache.log4j.Logger; felix@4436: felix@4436: felix@4436: /** ServletFilter used for GGInA authentification and certain authorisation. */ felix@4436: public class GGInAFilter implements Filter { felix@4436: teichmann@8203: /** Private log. */ teichmann@8203: private static Logger log = Logger.getLogger(GGInAFilter.class); felix@4436: felix@4436: private boolean deactivate = false; felix@4436: private String authmethod; felix@4436: private String redirecturl; felix@4436: private ServletContext sc; felix@4436: bjoern@4549: private static final String LOGIN_JSP = "/login.jsp"; bjoern@4549: private static final String LOGIN_SERVLET = "/flys/login"; bh@5952: private static final String SAML_SERVLET = "/flys/saml"; bjoern@4549: private static final String FLYS_CSS = "/FLYS.css"; felix@4436: felix@4436: felix@4436: /** felix@4436: * Initialize. felix@4436: * felix@4436: * Read FilterConfig parameter deactivate felix@4436: */ felix@4436: @Override felix@4436: public void init(FilterConfig config) felix@4436: throws ServletException felix@4436: { felix@4436: String deactivate = config.getInitParameter("deactivate"); felix@4436: this.sc = config.getServletContext(); teichmann@8203: log.debug("GGInAFilter context " + this.sc.getContextPath()); felix@4436: this.authmethod = sc.getInitParameter("authentication"); felix@4436: this.redirecturl = sc.getInitParameter("redirect-url"); felix@4436: if (deactivate != null && deactivate.equalsIgnoreCase("true")) { felix@4436: this.deactivate = true; felix@4436: } felix@4436: felix@4436: } felix@4436: felix@4436: felix@4436: /** felix@4436: * Called when filter in chain invoked. felix@4436: * @param req request to servlet felix@4436: * @param resp response of servlet felix@4436: * @param chain the filter chain felix@4436: */ felix@4436: @Override felix@4436: public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) felix@4436: throws IOException, ServletException felix@4436: { felix@4436: if (this.deactivate) { teichmann@8203: log.debug("GGinAFilter is deactivated"); felix@4436: chain.doFilter(req, resp); felix@4436: return; felix@4436: } felix@4436: felix@4436: HttpServletRequest sreq = (HttpServletRequest) req; felix@4436: felix@4436: String requesturi = sreq.getRequestURI(); teichmann@8203: if (log.isDebugEnabled()) { teichmann@4651: for (Enumeration e = req.getAttributeNames() ; e.hasMoreElements() ;) { teichmann@8203: log.debug(e.nextElement()); teichmann@4651: } felix@4436: } felix@4436: teichmann@8203: log.debug("Request for: " + requesturi); felix@4436: christian@4965: // Allow access to localhost teichmann@6894: if (isLocalAddress(req)) { teichmann@6978: String noAuth = sreq.getHeader("X_NO_GGINA_AUTH"); teichmann@6978: if (noAuth != null && noAuth.equals("TRUE")) { teichmann@8203: log.debug("Request to localhost"); teichmann@6978: chain.doFilter(req, resp); teichmann@6978: return; teichmann@6978: } teichmann@6894: } bjoern@4549: felix@4436: // Allow access to login pages felix@4436: String path = this.sc.getContextPath(); felix@4436: if (requesturi.equals(path + LOGIN_JSP) felix@4436: || requesturi.equals(path + LOGIN_SERVLET) bh@5952: || requesturi.equals(path + SAML_SERVLET) bjoern@4549: || requesturi.equals(path + FLYS_CSS)) { teichmann@8203: log.debug("Request for login " + requesturi); felix@4436: chain.doFilter(req, resp); felix@4436: return; felix@4436: } felix@4436: felix@4436: boolean redirect = false; felix@4436: felix@4436: HttpSession session = sreq.getSession(); felix@4436: felix@4436: String uri = path + "/" + this.redirecturl; felix@4436: felix@4436: /* Redirect if uri is root or redirecturl */ felix@4436: if (requesturi.equals(uri) || requesturi.equals(path + "/")) { felix@4436: redirect = true; felix@4436: } felix@4436: teichmann@4651: String queryString = sreq.getQueryString(); teichmann@4651: teichmann@4651: if (queryString != null) { teichmann@4651: uri += "?" + queryString; felix@4436: } felix@4436: session.setAttribute("requesturi", uri); felix@4436: felix@4436: User user = (User)session.getAttribute("user"); felix@4436: if (user == null) { teichmann@8203: log.debug("No user in session: " + requesturi); felix@4436: this.handleResponse(resp, redirect); felix@4436: return; felix@4436: } felix@4436: if (user.hasExpired()) { felix@4436: // try to re-authenticate the user teichmann@8203: log.debug("User ticket has expired: " + requesturi); felix@4436: String encoding = sreq.getCharacterEncoding(); felix@4436: try { felix@4436: Authentication auth = this.auth(user, encoding); felix@4436: if (auth == null || !auth.isSuccess()) { teichmann@8203: log.debug("Re-athentication not successful"); felix@4436: this.handleResponse(resp, redirect); felix@4436: } felix@4436: } felix@4436: catch(AuthenticationException e) { teichmann@8203: log.error("Failure during re-authentication", e); felix@4436: this.handleResponse(resp, redirect); felix@4436: return; felix@4436: } felix@4436: } felix@4436: felix@4436: chain.doFilter(req, resp); felix@4436: return; felix@4436: } felix@4436: felix@4436: private void redirect(ServletResponse resp) throws IOException { teichmann@8203: log.debug("Redirect to login"); felix@4436: ((HttpServletResponse) resp).sendRedirect(this.sc.getContextPath() + felix@4436: "/login.jsp"); felix@4436: } felix@4436: felix@4436: private void sendNotAuthenticated(ServletResponse resp) throws IOException { teichmann@8203: log.debug("Send not authenticated"); felix@4436: ((HttpServletResponse)resp).sendError(HttpServletResponse.SC_FORBIDDEN, "User not authenticated"); felix@4436: } felix@4436: felix@4436: private void handleResponse(ServletResponse resp, boolean redirect) throws IOException { felix@4436: if (redirect) { felix@4436: this.redirect(resp); felix@4436: } felix@4436: else { felix@4436: this.sendNotAuthenticated(resp); felix@4436: } felix@4436: } felix@4436: felix@4436: felix@4436: /** felix@4436: * Do nothing at destruction. felix@4436: */ felix@4436: @Override felix@4436: public void destroy() { felix@4436: } felix@4436: felix@4436: private Authentication auth(User user, String encoding) felix@4436: throws AuthenticationException, IOException { felix@4436: Features features = (Features)sc.getAttribute(Features.CONTEXT_ATTRIBUTE); felix@4436: return AuthenticationFactory.getInstance(this.authmethod).auth( bh@5933: user.getName(), user.getPassword(), encoding, features, sc); felix@4436: } bjoern@4549: bjoern@4549: /** bjoern@4549: * Returns true if the request is from our machine bjoern@4549: * @param req The ServletRequest bjoern@4549: * @return true if the request is from a loopback interface or from one of bjoern@4549: * the interface addresses of the machine bjoern@4549: */ bjoern@4549: private boolean isLocalAddress(ServletRequest req) { bjoern@4549: try { bjoern@4549: InetAddress addr = InetAddress.getByName(req.getRemoteAddr()); bjoern@4549: return addr.isAnyLocalAddress() || addr.isLoopbackAddress(); bjoern@4549: } catch (UnknownHostException e) { teichmann@8203: log.error(e, e); bjoern@4549: return false; bjoern@4549: } bjoern@4549: } felix@4436: } felix@4436: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :