Index: lams_central/conf/language/lams/ApplicationResources_en_AU.properties =================================================================== diff -u -r51fb2a37254f24bb2a805d4ffd54482c779f43fa -r9eaeb8328024c0c652dd7d17372dc4caf3a5852c --- lams_central/conf/language/lams/ApplicationResources_en_AU.properties (.../ApplicationResources_en_AU.properties) (revision 51fb2a37254f24bb2a805d4ffd54482c779f43fa) +++ lams_central/conf/language/lams/ApplicationResources_en_AU.properties (.../ApplicationResources_en_AU.properties) (revision 9eaeb8328024c0c652dd7d17372dc4caf3a5852c) @@ -1,9 +1,6 @@ appName = lams_central #language code: en -#locale code: AU - - - +#locale code: AU #=================== labels for LAMS Central =================# label.username =Username @@ -672,4 +669,9 @@ label.private.notifications.read.hint =Mark notification as read label.private.notifications.read.all.hint =Mark all notifications as read +label.verification.code =Verification code +error.verification.code =Sorry, entered verification code is incorrect. Please try again. +label.your.new.shared.secret =Your new shared secret: {0} +label.2FA.shared.secret =Two-factor authorization shared secret + #======= End labels: Exported 439 labels for en AU ===== \ No newline at end of file Index: lams_central/src/java/org/lamsfoundation/lams/web/IndexAction.java =================================================================== diff -u -r5773f84ed608838de3521ecde87c52f3c72d478c -r9eaeb8328024c0c652dd7d17372dc4caf3a5852c --- lams_central/src/java/org/lamsfoundation/lams/web/IndexAction.java (.../IndexAction.java) (revision 5773f84ed608838de3521ecde87c52f3c72d478c) +++ lams_central/src/java/org/lamsfoundation/lams/web/IndexAction.java (.../IndexAction.java) (revision 9eaeb8328024c0c652dd7d17372dc4caf3a5852c) @@ -53,40 +53,16 @@ import org.springframework.web.context.support.WebApplicationContextUtils; /** - * @version * - *

- * View Source - *

- * * @author Fei Yang - * - * Created at 16:59:28 on 13/06/2006 */ -/** - * struts doclet - * - * - * - * - * - * - * - * - * - * - * - */ public class IndexAction extends Action { private static final String PATH_PEDAGOGICAL_PLANNER = "pedagogical_planner"; private static final String PATH_LAMS_CENTRAL = "lams-central.war"; private static Logger log = Logger.getLogger(IndexAction.class); private static IUserManagementService userManagementService; - private static IExportToolContentService exportService; - private static IAuthoringService authoringService; - private static Configuration configurationService; @Override @SuppressWarnings("unchecked") @@ -110,11 +86,14 @@ // check if user is flagged as needing to change their password User loggedInUser = getUserManagementService().getUserByLogin(request.getRemoteUser()); - if (loggedInUser.getChangePassword() != null) { - if (loggedInUser.getChangePassword()) { - return mapping.findForward("password"); - } + if (loggedInUser.getChangePassword() != null && loggedInUser.getChangePassword()) { + return mapping.findForward("password"); } + + // check if user needs to get his shared two-factor authorization secret + if (loggedInUser.isTwoFactorAuthenticationEnabled() && loggedInUser.getTwoFactorAuthenticationSecret() == null) { + return mapping.findForward("twoFactorAuthentication"); + } User user = getUserManagementService().getUserByLogin(userDTO.getLogin()); request.setAttribute("portraitUuid", user.getPortraitUuid()); Index: lams_central/src/java/org/lamsfoundation/lams/web/PasswordAction.java =================================================================== diff -u -r51fb2a37254f24bb2a805d4ffd54482c779f43fa -r9eaeb8328024c0c652dd7d17372dc4caf3a5852c --- lams_central/src/java/org/lamsfoundation/lams/web/PasswordAction.java (.../PasswordAction.java) (revision 51fb2a37254f24bb2a805d4ffd54482c779f43fa) +++ lams_central/src/java/org/lamsfoundation/lams/web/PasswordAction.java (.../PasswordAction.java) (revision 9eaeb8328024c0c652dd7d17372dc4caf3a5852c) @@ -21,7 +21,6 @@ * **************************************************************** */ - package org.lamsfoundation.lams.web; import javax.servlet.http.HttpServletRequest; @@ -34,13 +33,6 @@ /** * @author jliew - * - * - * - * - * - * - * */ public class PasswordAction extends Action { Index: lams_central/src/java/org/lamsfoundation/lams/web/ProfileAction.java =================================================================== diff -u -r5773f84ed608838de3521ecde87c52f3c72d478c -r9eaeb8328024c0c652dd7d17372dc4caf3a5852c --- lams_central/src/java/org/lamsfoundation/lams/web/ProfileAction.java (.../ProfileAction.java) (revision 5773f84ed608838de3521ecde87c52f3c72d478c) +++ lams_central/src/java/org/lamsfoundation/lams/web/ProfileAction.java (.../ProfileAction.java) (revision 9eaeb8328024c0c652dd7d17372dc4caf3a5852c) @@ -66,24 +66,9 @@ import org.springframework.web.context.support.WebApplicationContextUtils; /** - * @version * - *

- * View Source - *

- * * @author Fei Yang - * - * Created at 14:21:53 on 28/06/2006 */ - -/** - * - * - * - * - * - */ public class ProfileAction extends LamsDispatchAction { private static Logger log = Logger.getLogger(ProfileAction.class); @@ -229,6 +214,9 @@ } userForm.set("localeId", locale.getLocaleId()); request.setAttribute("locales", locales); + if (requestor.isTwoFactorAuthenticationEnabled()) { + request.setAttribute("sharedSecret", requestor.getTwoFactorAuthenticationSecret()); + } request.setAttribute("tab", "profile"); boolean hasLamsCommunityToken = requestor.getLamsCommunityToken() != null; Index: lams_central/src/java/org/lamsfoundation/lams/web/action/TwoFactorAuthenticationAction.java =================================================================== diff -u --- lams_central/src/java/org/lamsfoundation/lams/web/action/TwoFactorAuthenticationAction.java (revision 0) +++ lams_central/src/java/org/lamsfoundation/lams/web/action/TwoFactorAuthenticationAction.java (revision 9eaeb8328024c0c652dd7d17372dc4caf3a5852c) @@ -0,0 +1,74 @@ +/**************************************************************** + * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ + +package org.lamsfoundation.lams.web.action; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.struts.action.Action; +import org.apache.struts.action.ActionForm; +import org.apache.struts.action.ActionForward; +import org.apache.struts.action.ActionMapping; +import org.lamsfoundation.lams.usermanagement.User; +import org.lamsfoundation.lams.usermanagement.service.UserManagementService; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.WebApplicationContextUtils; + +import com.warrenstrange.googleauth.GoogleAuthenticator; +import com.warrenstrange.googleauth.GoogleAuthenticatorKey; +import com.warrenstrange.googleauth.GoogleAuthenticatorQRGenerator; + +/** + * @author Andrey Balan + */ +public class TwoFactorAuthenticationAction extends Action { + + @Override + public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws Exception { + + WebApplicationContext ctx = WebApplicationContextUtils + .getWebApplicationContext(getServlet().getServletContext()); + UserManagementService userManagementService = (UserManagementService) ctx.getBean("userManagementService"); + + // check if user needs to get his shared two-factor authorization secret + User loggedInUser = userManagementService.getUserByLogin(request.getRemoteUser()); + if (loggedInUser.isTwoFactorAuthenticationEnabled() && loggedInUser.getTwoFactorAuthenticationSecret() == null) { + + GoogleAuthenticator gAuth = new GoogleAuthenticator(); + final GoogleAuthenticatorKey key = gAuth.createCredentials(); + String sharedSecret = key.getKey(); + + loggedInUser.setTwoFactorAuthenticationSecret(sharedSecret); + userManagementService.save(loggedInUser); + + request.setAttribute("sharedSecret", sharedSecret); + String QRCode = GoogleAuthenticatorQRGenerator.getOtpAuthURL(null, "LAMS account: " + loggedInUser.getLogin(), key); + request.setAttribute("QRCode", QRCode); + } + + request.setAttribute("tab", "profile"); + return mapping.findForward("secret"); + } +} Index: lams_central/web/WEB-INF/struts-config.xml =================================================================== diff -u -r65efb0abb529cafc1977e284e2c9a4ed33722334 -r9eaeb8328024c0c652dd7d17372dc4caf3a5852c --- lams_central/web/WEB-INF/struts-config.xml (.../struts-config.xml) (revision 65efb0abb529cafc1977e284e2c9a4ed33722334) +++ lams_central/web/WEB-INF/struts-config.xml (.../struts-config.xml) (revision 9eaeb8328024c0c652dd7d17372dc4caf3a5852c) @@ -149,6 +149,11 @@ redirect="false" /> + + + + + + + + + Index: lams_central/web/WEB-INF/web.xml =================================================================== diff -u -rab7fcc93ccae4b3d2525a80b1613c42dd4bce12f -r9eaeb8328024c0c652dd7d17372dc4caf3a5852c --- lams_central/web/WEB-INF/web.xml (.../web.xml) (revision ab7fcc93ccae4b3d2525a80b1613c42dd4bce12f) +++ lams_central/web/WEB-INF/web.xml (.../web.xml) (revision 9eaeb8328024c0c652dd7d17372dc4caf3a5852c) @@ -665,6 +665,7 @@ /forgotPassword.jsp /forgotPasswordChange.jsp /forgotPasswordProc.jsp + /loginTwoFactorAuth.jsp /signup/* /rest/* /runtimeStats Index: lams_central/web/editprofile.jsp =================================================================== diff -u -r3dbf966d900adefc34cdad501d3c392118451cd9 -r9eaeb8328024c0c652dd7d17372dc4caf3a5852c --- lams_central/web/editprofile.jsp (.../editprofile.jsp) (revision 3dbf966d900adefc34cdad501d3c392118451cd9) +++ lams_central/web/editprofile.jsp (.../editprofile.jsp) (revision 9eaeb8328024c0c652dd7d17372dc4caf3a5852c) @@ -157,6 +157,15 @@ + + + : + + ${sharedSecret} + + + + Index: lams_central/web/loginTwoFactorAuth.jsp =================================================================== diff -u --- lams_central/web/loginTwoFactorAuth.jsp (revision 0) +++ lams_central/web/loginTwoFactorAuth.jsp (revision 9eaeb8328024c0c652dd7d17372dc4caf3a5852c) @@ -0,0 +1,125 @@ +<%@page import="org.springframework.web.context.request.SessionScope"%> +<%@ page language="java" pageEncoding="UTF-8" contentType="text/html;charset=utf-8"%> +<%@ taglib uri="tags-fmt" prefix="fmt"%> +<%@ taglib uri="tags-core" prefix="c"%> +<%@ taglib uri="tags-lams" prefix="lams"%> +<%@ page import="org.lamsfoundation.lams.util.Configuration"%> +<%@ page import="org.lamsfoundation.lams.util.ConfigurationKeys"%> +<%@ page import="org.lamsfoundation.lams.web.session.SessionManager"%> +<%@ page import="org.lamsfoundation.lams.usermanagement.dto.UserDTO"%> + + + + + + + + + + <fmt:message key="title.login.window" /> + + + + + + + + + +
+ +

 

+ +
+ + +
+ +
+

+ LAMS - Learning Activity Management System +

+ +
+ + +
+

+ + <%=Configuration.get(ConfigurationKeys.VERSION)%> +

+ +

+ +

+ +
+ + + + + + + + +

+ + : +

+ + +
+
+ + +
+ +
+ + + + +
+ + + <% + // remove login and password attributes from the session as they are no longer needed + HttpSession hs = SessionManager.getSession(); + if (hs != null) { + hs.removeAttribute("login"); + hs.removeAttribute("password"); + } + %> + + +
\ No newline at end of file Index: lams_central/web/twoFactorAuthSecret.jsp =================================================================== diff -u --- lams_central/web/twoFactorAuthSecret.jsp (revision 0) +++ lams_central/web/twoFactorAuthSecret.jsp (revision 9eaeb8328024c0c652dd7d17372dc4caf3a5852c) @@ -0,0 +1,14 @@ +<%@ taglib uri="tags-fmt" prefix="fmt" %> + +

+ + ${sharedSecret} + +

+

+ +

+

+ +

Index: lams_common/conf/hibernate/mappings/org/lamsfoundation/lams/usermanagement/User.hbm.xml =================================================================== diff -u -rc3c499fa8b7a5487229a59411af3710fa878b93c -r9eaeb8328024c0c652dd7d17372dc4caf3a5852c --- lams_common/conf/hibernate/mappings/org/lamsfoundation/lams/usermanagement/User.hbm.xml (.../User.hbm.xml) (revision c3c499fa8b7a5487229a59411af3710fa878b93c) +++ lams_common/conf/hibernate/mappings/org/lamsfoundation/lams/usermanagement/User.hbm.xml (.../User.hbm.xml) (revision 9eaeb8328024c0c652dd7d17372dc4caf3a5852c) @@ -58,6 +58,24 @@ not-null="false" + + + @hibernate.property + column="two_factor_auth_enabled" + length="1" + not-null="true" + + + + + @hibernate.property + column="two_factor_auth_secret" + length="64" + not-null="true" + + Index: lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch2040067.sql =================================================================== diff -u --- lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch2040067.sql (revision 0) +++ lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch2040067.sql (revision 9eaeb8328024c0c652dd7d17372dc4caf3a5852c) @@ -0,0 +1,13 @@ +-- Turn off autocommit, so nothing is committed if there is an error + +SET AUTOCOMMIT = 0; +SET FOREIGN_KEY_CHECKS=0; + +-- LDEV-3965 Ability to enable two-factor authentication for selected users +ALTER TABLE lams_user ADD COLUMN two_factor_auth_enabled TINYINT(1) DEFAULT 0 AFTER salt; +ALTER TABLE lams_user ADD COLUMN two_factor_auth_secret CHAR(64) AFTER two_factor_auth_enabled; + +-- If there were no errors, commit and restore autocommit to on +SET FOREIGN_KEY_CHECKS=0; +COMMIT; +SET AUTOCOMMIT = 1; Index: lams_common/src/java/org/lamsfoundation/lams/integration/security/SsoHandler.java =================================================================== diff -u -rac1774a2e7f4b8ce9b79e6447b1b4748f719bc32 -r9eaeb8328024c0c652dd7d17372dc4caf3a5852c --- lams_common/src/java/org/lamsfoundation/lams/integration/security/SsoHandler.java (.../SsoHandler.java) (revision ac1774a2e7f4b8ce9b79e6447b1b4748f719bc32) +++ lams_common/src/java/org/lamsfoundation/lams/integration/security/SsoHandler.java (.../SsoHandler.java) (revision 9eaeb8328024c0c652dd7d17372dc4caf3a5852c) @@ -25,9 +25,11 @@ import javax.servlet.ServletContext; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.math.NumberUtils; import org.lamsfoundation.lams.usermanagement.User; import org.lamsfoundation.lams.usermanagement.dto.UserDTO; import org.lamsfoundation.lams.usermanagement.service.IUserManagementService; @@ -37,6 +39,8 @@ import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; +import com.warrenstrange.googleauth.GoogleAuthenticator; + import io.undertow.Handlers; import io.undertow.server.session.Session; import io.undertow.servlet.ServletExtension; @@ -96,6 +100,35 @@ User user = getUserManagementService(session.getServletContext()).getUserByLogin(login); if (user != null) { userDTO = user.getUserDTO(); + + // if user is not yet authorized and has 2FA shared secret set up - redirect him to + // loginTwoFactorAuth.jsp to prompt user to enter his verification code (Time-based One-time Password) + if (request.getRemoteUser() == null && user.isTwoFactorAuthenticationEnabled() + && user.getTwoFactorAuthenticationSecret() != null) { + String verificationCodeStr = request.getParameter("verificationCode"); + int verificationCode = NumberUtils.toInt(verificationCodeStr); + GoogleAuthenticator gAuth = new GoogleAuthenticator(); + boolean isCodeValid = gAuth.authorize(user.getTwoFactorAuthenticationSecret(), + verificationCode); + + //user entered correct TOTP password + if (isCodeValid) { + //do nothing and let regular login to happen + + //user hasn't yet entered TOTP password (request came from login.jsp) or entered the wrong one + } else { + session.setAttribute("login", login); + String password = request.getParameter("j_password"); + session.setAttribute("password", password); + + //verificationCodeStr equals null in case request came from login.jsp + String redirectUrl = "/lams/loginTwoFactorAuth.jsp" + ((verificationCodeStr == null) ? "" : "?failed=true" ); + HttpServletResponse response = (HttpServletResponse) context.getServletResponse(); + response.sendRedirect(redirectUrl); + return; + } + + } } } Index: lams_common/src/java/org/lamsfoundation/lams/usermanagement/User.java =================================================================== diff -u -r51fb2a37254f24bb2a805d4ffd54482c779f43fa -r9eaeb8328024c0c652dd7d17372dc4caf3a5852c --- lams_common/src/java/org/lamsfoundation/lams/usermanagement/User.java (.../User.java) (revision 51fb2a37254f24bb2a805d4ffd54482c779f43fa) +++ lams_common/src/java/org/lamsfoundation/lams/usermanagement/User.java (.../User.java) (revision 9eaeb8328024c0c652dd7d17372dc4caf3a5852c) @@ -53,6 +53,10 @@ * persistent field */ private String password; + + private Boolean twoFactorAuthenticationEnabled; + + private String twoFactorAuthenticationSecret; /** * persistent field @@ -172,6 +176,7 @@ /** default constructor */ public User() { changePassword = false; + twoFactorAuthenticationEnabled = false; } public Integer getUserId() { @@ -205,7 +210,23 @@ public void setSalt(String salt) { this.salt = salt; } + + public Boolean isTwoFactorAuthenticationEnabled() { + return twoFactorAuthenticationEnabled; + } + public void setTwoFactorAuthenticationEnabled(Boolean twoFactorAuthenticationEnabled) { + this.twoFactorAuthenticationEnabled = twoFactorAuthenticationEnabled; + } + + public String getTwoFactorAuthenticationSecret() { + return twoFactorAuthenticationSecret; + } + + public void setTwoFactorAuthenticationSecret(String twoFactorAuthenticationSecret) { + this.twoFactorAuthenticationSecret = twoFactorAuthenticationSecret; + } + public String getTitle() { return title; }