https://bz.apache.org/bugzilla/show_bug.cgi?id=57937
Bug ID: 57937 Summary: Request for a form based two factor authentication support in Tomcat Product: Tomcat 7 Version: 7.0.55 Hardware: PC OS: Linux Status: NEW Severity: enhancement Priority: P2 Component: Catalina Assignee: dev@tomcat.apache.org Reporter: bella...@denic.de Created attachment 32744 --> https://bz.apache.org/bugzilla/attachment.cgi?id=32744&action=edit Result of a diff -u operated on the original code and the pseudo-code containing a 2fa workaround Hi there, for an application to be deployed on a TomEE we need the support for two factor authentication. Are there planned development efforts going into that direction? As temporary workaround we patched the class FormAuthenticator, so that a second factor (a 2fa token) is additionlly evaluated. This patch is in the style of AuthenticRoast, an solution available for Tomcat 1.6. Here the code patch in pseudo code: package org.apache.catalina.authenticator; [original code omitted with imports] /** * An <b>Authenticator</b> and <b>Valve</b> implementation of FORM BASED Authentication, as * described in the Servlet API Specification, Version 2.2. */ public class FormAuthenticator extends AuthenticatorBase { [original code omitted] // --------------------------------------------------------- Public Methods /** * Authenticate the user making this request, based on the specified login configuration. Return * <code>true</code> if any specified constraint has been satisfied, or <code>false</code> if we * have created a response challenge already. * * @param request Request we are processing * @param response Response we are creating * @param config Login configuration describing how authentication should be performed * * @exception IOException if an input/output error occurs */ @Override public boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException { // References to objects we will need later Session session = null; // Have we already authenticated someone? Principal principal = request.getUserPrincipal(); String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); [original code omitted] // Yes -- Acknowledge the request, validate the specified credentials // and redirect to the error page if they are not correct request.getResponse().sendAcknowledgement(); Realm realm = context.getRealm(); if (characterEncoding != null) { request.setCharacterEncoding(characterEncoding); } String username = request.getParameter(Constants.FORM_USERNAME); String password = request.getParameter(Constants.FORM_PASSWORD); if (log.isDebugEnabled()) { log.debug("Authenticating username '" + username + "'"); } // BEGIN --- Customized code for two factor authentication Part I --- BEGIN String password2factor = request.getParameter("j_2fa"); // A customized Realm Class which implements a second factor authentication final TwoFactorRealm twoFactorRealm = new TwoFactorRealm(...); boolean twoFactorSuccessful = twoFactorRealm.authenticate(username, password2factor); if (log.isWarnEnabled() && !twoFactorSuccessful) { log.warn("Authentication 2FA failed for user " + username); } // END --- Customized code for two factor authentication Part I --- END principal = realm.authenticate(username, password); // BEGIN --- Customized code for two factor authentication Part II --- BEGIN if (principal == null || !twoFactorSuccessful) { log.warn("Authentication of '" + username + "' failed: [principal=" + principal + "], [twoFactorSuccessful=" + twoFactorSuccessful + "]"); forwardToErrorPage(request, response, config); return (false); } // END --- Customized code for two factor authentication Part II --- END if (log.isDebugEnabled()) { log.debug("Authentication of '" + username + "' was successful"); } if (session == null) { session = request.getSessionInternal(false); } if (session == null) { if (containerLog.isDebugEnabled()) { containerLog.debug("User took so long to log on the session expired"); } if (landingPage == null) { response.sendError(HttpServletResponse.SC_REQUEST_TIMEOUT, sm.getString("authenticator.sessionExpired")); } else { // Make the authenticator think the user originally requested // the landing page String uri = request.getContextPath() + landingPage; SavedRequest saved = new SavedRequest(); saved.setMethod("GET"); saved.setRequestURI(uri); saved.setDecodedRequestURI(uri); request.getSessionInternal(true).setNote(Constants.FORM_REQUEST_NOTE, saved); response.sendRedirect(response.encodeRedirectURL(uri)); } return (false); } // Save the authenticated Principal in our session session.setNote(Constants.FORM_PRINCIPAL_NOTE, principal); // Save the username and password as well session.setNote(Constants.SESS_USERNAME_NOTE, username); session.setNote(Constants.SESS_PASSWORD_NOTE, password); // Redirect the user to the original request URI (which will cause // the original request to be restored) requestURI = savedRequestURL(session); if (log.isDebugEnabled()) { log.debug("Redirecting to original '" + requestURI + "'"); } if (requestURI == null) { if (landingPage == null) { response.sendError(HttpServletResponse.SC_BAD_REQUEST,sm.getString("authenticator.formlogin")); } else { // Make the authenticator think the user originally requested // the landing page String uri = request.getContextPath() + landingPage; SavedRequest saved = new SavedRequest(); saved.setMethod("GET"); saved.setRequestURI(uri); saved.setDecodedRequestURI(uri); session.setNote(Constants.FORM_REQUEST_NOTE, saved); response.sendRedirect(response.encodeRedirectURL(uri)); } } else { response.sendRedirect(response.encodeRedirectURL(requestURI)); } return (false); } [original code omitted] } Best regards, Marco -- Dipl.-Inf. Marco Bellavia Software Engineering DENIC eG Kaiserstraße 75-77 60329 Frankfurt am Main GERMANY Angaben nach § 25a Absatz 1 GenG: DENIC eG (Sitz: Frankfurt am Main) Vorstand: Helga Krüger, Andreas Musielak, Carsten Schiefner, Dr. Jörg Schweiger Vorsitzender des Aufsichtsrats: Thomas Keller Eingetragen unter Nr. 770 im Genossenschaftsregister, Amtsgericht Frankfurt am Main -- You are receiving this mail because: You are the assignee for the bug. --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org