Index: lams_bb_integration/src/org/lamsfoundation/bb/integration/servlet/GradebookServlet.java =================================================================== diff -u -r54843a5ae3288a977cdfa75fd43afc9c67831624 -ra4cac24066ba39701ad51a8dd4c512b6e4100873 --- lams_bb_integration/src/org/lamsfoundation/bb/integration/servlet/GradebookServlet.java (.../GradebookServlet.java) (revision 54843a5ae3288a977cdfa75fd43afc9c67831624) +++ lams_bb_integration/src/org/lamsfoundation/bb/integration/servlet/GradebookServlet.java (.../GradebookServlet.java) (revision a4cac24066ba39701ad51a8dd4c512b6e4100873) @@ -76,12 +76,14 @@ private static Logger logger = LoggerFactory.getLogger(GradebookServlet.class); /** - * Receives call from Lams ab lesson completion. After that get the latest marks for this user in this lesson and stores it in DB. + * Receives call from Lams ab lesson completion. After that get the latest marks for this user in this lesson and + * stores it in DB. */ + @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ContextManager ctxMgr = null; - + try { // get Blackboard context ctxMgr = (ContextManager) BbServiceManager.lookupService(ContextManager.class); @@ -104,9 +106,16 @@ //check user rights String secretKey = LamsPluginUtil.getServerSecretKey(); String serverId = LamsPluginUtil.getServerId(); - if (!LamsSecurityUtil.sha1( - timeStamp.toLowerCase() + userName.toLowerCase() + serverId.toLowerCase() - + secretKey.toLowerCase()).equals(hash)) { + String plaintext = timeStamp.toLowerCase() + userName.toLowerCase() + serverId.toLowerCase() + + secretKey.toLowerCase(); + String parametersHash = null; + if (hash.length() == LamsSecurityUtil.SHA1_HEX_LENGTH) { + // for some time support SHA-1 for authentication + parametersHash = LamsSecurityUtil.sha1(plaintext); + } else { + parametersHash = LamsSecurityUtil.sha256(plaintext); + } + if (!hash.equals(parametersHash)) { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "authentication failed"); return; } @@ -117,7 +126,7 @@ throw new ServletException("User not found with userName:" + userName); } Id userId = user.getId(); - + //allow lessonComplete.jsp on LAMS side to make an Ajax call to this servlet String serverUrlWithLamsWord = LamsPluginUtil.getServerUrl(); URI uri = new URI(serverUrlWithLamsWord); @@ -139,10 +148,8 @@ + " scores."); String getLamsMarkURL = LamsPluginUtil.getServerUrl() + "/services/xml/LessonManager?" - + LamsSecurityUtil.generateAuthenticateParameters(userName) - + "&method=gradebookMarksUser" - + "&lsId=" + lamsLessonIdParam - + "&outputsUser=" + URLEncoder.encode(userName, "UTF8"); + + LamsSecurityUtil.generateAuthenticateParameters(userName) + "&method=gradebookMarksUser" + + "&lsId=" + lamsLessonIdParam + "&outputsUser=" + URLEncoder.encode(userName, "UTF8"); URL url = new URL(getLamsMarkURL); URLConnection conn = url.openConnection(); if (!(conn instanceof HttpURLConnection)) { @@ -163,7 +170,7 @@ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document document = db.parse(is); - + Node lesson = document.getDocumentElement().getFirstChild(); Node learnerResult = lesson.getFirstChild(); @@ -179,44 +186,44 @@ currentScore.setLineitemId(lineitem.getId()); currentScore.setCourseMembershipId(courseMembership.getId()); } - + //updates and persists currentScore in the DB LineitemUtil.updateScoreBasedOnLamsResponse(lesson, learnerResult, currentScore); - + //notifying LAMS that score has been stored successfully response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.write("OK"); - + //the following paragraph is kept due to the Ernie's request to keep it for potential usage in the future // NodeList activities = document.getDocumentElement().getFirstChild().getChildNodes(); // // float maxResult = 0; // float userResult = 0; // for (int i = 0; i < activities.getLength(); i++) { // Node activity = activities.item(i); -// +// // for (int j = 0; j < activity.getChildNodes().getLength(); j++) { -// +// // Node toolOutput = activity.getChildNodes().item(j); // String toolOutputName = toolOutput.getAttributes().getNamedItem("name").getNodeValue(); // // The only numeric outputs we get from LAMS are for the MCQ and Assessment activities -// // learner.total.score = Assessment +// // learner.total.score = Assessment // // learner.mark = MCQ // if ("learner.mark".equals(toolOutputName) || "learner.total.score".equals(toolOutputName)) { // String userResultStr = toolOutput.getAttributes().getNamedItem("output").getNodeValue(); // String maxResultStr = toolOutput.getAttributes().getNamedItem("marksPossible").getNodeValue(); -// +// // userResult += Float.parseFloat(userResultStr); // maxResult += Float.parseFloat(maxResultStr); // } // } -// +// // } - + } catch (MalformedURLException e) { - throw new ServletException("Unable to get LAMS learning designs, bad URL: " - + ", please check lams.properties", e); + throw new ServletException( + "Unable to get LAMS learning designs, bad URL: " + ", please check lams.properties", e); } catch (IllegalStateException e) { throw new ServletException( "LAMS Server timeout, did not get a response from the LAMS server. Please contact your systems administrator", @@ -251,7 +258,7 @@ } } - + @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); Index: lams_bb_integration/src/org/lamsfoundation/bb/integration/servlet/UserDataServlet.java =================================================================== diff -u -ree84f34847defe313ee0570b67a75c41a22091c2 -ra4cac24066ba39701ad51a8dd4c512b6e4100873 --- lams_bb_integration/src/org/lamsfoundation/bb/integration/servlet/UserDataServlet.java (.../UserDataServlet.java) (revision ee84f34847defe313ee0570b67a75c41a22091c2) +++ lams_bb_integration/src/org/lamsfoundation/bb/integration/servlet/UserDataServlet.java (.../UserDataServlet.java) (revision a4cac24066ba39701ad51a8dd4c512b6e4100873) @@ -49,9 +49,9 @@ /** * The doGet method of the servlet.
- * + * * This method is called when a form has its tag value method equals to get. - * + * * @param request * the request send by the client to the server * @param response @@ -61,25 +61,33 @@ * @throws IOException * if an error occurred */ + @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // get Parameter values String usernameParam = request.getParameter(Constants.PARAM_USER_ID); String tsParam = request.getParameter(Constants.PARAM_TIMESTAMP); - String hashParam = request.getParameter(Constants.PARAM_HASH); + String hash = request.getParameter(Constants.PARAM_HASH); // check paramaeters - if (usernameParam == null || tsParam == null || hashParam == null) { + if (usernameParam == null || tsParam == null || hash == null) { response.sendError(HttpServletResponse.SC_BAD_REQUEST, "missing expected parameters"); return; } String secretKey = LamsPluginUtil.getServerSecretKey(); String serverId = LamsPluginUtil.getServerId(); + String plaintext = tsParam.toLowerCase() + usernameParam.toLowerCase() + serverId.toLowerCase() + + secretKey.toLowerCase(); + String parametersHash = null; + if (hash.length() == LamsSecurityUtil.SHA1_HEX_LENGTH) { + // for some time support SHA-1 for authentication + parametersHash = LamsSecurityUtil.sha1(plaintext); + } else { + parametersHash = LamsSecurityUtil.sha256(plaintext); + } - if (!LamsSecurityUtil.sha1( - tsParam.toLowerCase() + usernameParam.toLowerCase() + serverId.toLowerCase() + secretKey.toLowerCase()) - .equals(hashParam)) { + if (!hash.equals(parametersHash)) { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "authentication failed"); return; } @@ -112,10 +120,10 @@ // ,,,, // ,, String[] valList = { user.getTitle(), user.getGivenName(), user.getFamilyName(), - user.getStreet1() + user.getStreet2(), user.getCity(), user.getState(), user.getZipCode(), - countryCode, user.getHomePhone1(), user.getMobilePhone(), user.getBusinessFax(), - user.getEmailAddress(), user.getLocale() }; - + user.getStreet1() + user.getStreet2(), user.getCity(), user.getState(), user.getZipCode(), countryCode, + user.getHomePhone1(), user.getMobilePhone(), user.getBusinessFax(), user.getEmailAddress(), + user.getLocale() }; + PrintWriter out = response.getWriter(); out.println(CSVUtil.write(valList)); } Index: lams_bb_integration/src/org/lamsfoundation/bb/integration/util/LamsSecurityUtil.java =================================================================== diff -u -r37fbc0e992fae0577ca56376b3263a7a50709260 -ra4cac24066ba39701ad51a8dd4c512b6e4100873 --- lams_bb_integration/src/org/lamsfoundation/bb/integration/util/LamsSecurityUtil.java (.../LamsSecurityUtil.java) (revision 37fbc0e992fae0577ca56376b3263a7a50709260) +++ lams_bb_integration/src/org/lamsfoundation/bb/integration/util/LamsSecurityUtil.java (.../LamsSecurityUtil.java) (revision a4cac24066ba39701ad51a8dd4c512b6e4100873) @@ -2,21 +2,21 @@ * Copyright (C) 2007 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 + * 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 * **************************************************************** */ @@ -70,30 +70,34 @@ /** * This class creates URLs, servlet calls and webservice calls for communication with LAMS - * + * * @author Luke Foxton */ public class LamsSecurityUtil { private static Logger logger = LoggerFactory.getLogger(LamsSecurityUtil.class); - private static final String DUMMY_COURSE = "Previews"; + private static final String DUMMY_COURSE = "Previews"; private static final String EXPORT_FOLDER_LAMS_SERVER = "/tmp/lams/"; + public static final int SHA1_HEX_LENGTH = 40; + public static final int SHA256_HEX_LENGTH = 64; + /** * Generates login requests to LAMS for author, monitor and learner - * + * * @param ctx * the blackboard contect, contains session data * @param method * the mehtod to request of LAMS "author", "monitor", "learnerStrictAuth" * @param lsid * lesson id. It is expected to be present in case of "monitor" and "learnerStrictAuth" * @return a url pointing to the LAMS lesson, monitor, author session - * @throws IOException - * @throws PersistenceException + * @throws IOException + * @throws PersistenceException * @throws Exception */ - public static String generateRequestURL(Context ctx, String method, String lsid) throws PersistenceException, IOException { + public static String generateRequestURL(Context ctx, String method, String lsid) + throws PersistenceException, IOException { String serverAddr = LamsPluginUtil.getServerUrl(); String serverId = LamsPluginUtil.getServerId(); @@ -102,17 +106,17 @@ throw new RuntimeException("Configuration Exception " + serverAddr + ", " + serverId); } - String timestamp = getServerTime(); + String timestamp = LamsSecurityUtil.getServerTime(); String username = ctx.getUser().getUserName(); String firstName = ctx.getUser().getGivenName(); - String lastName = ctx.getUser().getFamilyName(); + String lastName = ctx.getUser().getFamilyName(); String email = ctx.getUser().getEmailAddress(); String locale = ctx.getUser().getLocale(); - String country = getCountryCode(ctx.getUser().getCountry()); + String country = LamsSecurityUtil.getCountryCode(ctx.getUser().getCountry()); // Even for authoring calls we still need a 'course' the user, role & organisation are all bound up together // do to be authorised to use authoring you must be in an organisation. - String courseId = setupCourseId(ctx, null, true); + String courseId = LamsSecurityUtil.setupCourseId(ctx, null, true); String serverSecretKey = LamsPluginUtil.getServerSecretKey(); @@ -121,9 +125,9 @@ // regular case: [ts + uid + method + serverID + serverSecretKey] String plaintext = timestamp.toLowerCase().trim() + username.toLowerCase().trim() + method.toLowerCase().trim() + ("learnerStrictAuth".equals(method) ? lsid.toLowerCase().trim() : "") + serverId.toLowerCase().trim() - + serverSecretKey.toLowerCase().trim(); + + serverSecretKey.toLowerCase().trim(); // generate authentication hash code to validate parameters - String hash = sha1(plaintext); + String hash = LamsSecurityUtil.sha1(plaintext); String url; try { @@ -132,11 +136,11 @@ + "&ts=" + timestamp + "&sid=" + serverId + "&hash=" + hash + course + "&country=" + country + "&lang=" + locale + "&firstName=" + URLEncoder.encode(firstName, "UTF-8") + "&lastName=" + URLEncoder.encode(lastName, "UTF-8") + "&email=" + URLEncoder.encode(email, "UTF-8"); - + if ("learnerStrictAuth".equals(method) || "monitor".equals(method)) { - url += "&lsid=" + lsid; + url += "&lsid=" + lsid; } - + } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } @@ -146,10 +150,11 @@ return url; } - + /** * Generates default - * @throws UnsupportedEncodingException + * + * @throws UnsupportedEncodingException */ public static String generateAuthenticateParameters(String username) throws UnsupportedEncodingException { String serverAddr = LamsPluginUtil.getServerUrl(); @@ -161,149 +166,162 @@ } String timestamp = new Long(System.currentTimeMillis()).toString(); - String hash = generateAuthenticationHash(timestamp, username, serverId); + String hash = LamsSecurityUtil.generateAuthenticationHash(timestamp, username, serverId); String authenticateParameters = "&serverId=" + serverId + "&datetime=" + timestamp + "&hashValue=" + hash + "&username=" + URLEncoder.encode(username, "UTF8"); return authenticateParameters; } - + /** * Generates url request to LAMS for LearningDesignImage. - * + * * @param ctx * the blackboard contect, contains session data * @return a url pointing to the LAMS lesson, monitor, author session - * @throws UnsupportedEncodingException + * @throws UnsupportedEncodingException */ public static String generateRequestLearningDesignImage(String username) throws UnsupportedEncodingException { String serverAddr = LamsPluginUtil.getServerUrl(); - - //$request = "$CFG->lamslesson_serverurl/services/LearningDesignSVG?serverId=" . $CFG->lamslesson_serverid . "&datetime=" . $datetime_encoded . "&hashValue=" . - //$hashvalue . "&username=" . $username . "&courseId=" . $courseid . "&courseName=" . urlencode($coursename) . "&mode=2&country=" . $country . "&lang=" . $lang . - //"&ldId=" . $ldid; - String url = serverAddr + "/services/LearningDesignSVG?" + generateAuthenticateParameters(username); + //$request = "$CFG->lamslesson_serverurl/services/LearningDesignSVG?serverId=" . $CFG->lamslesson_serverid . "&datetime=" . $datetime_encoded . "&hashValue=" . + //$hashvalue . "&username=" . $username . "&courseId=" . $courseid . "&courseName=" . urlencode($coursename) . "&mode=2&country=" . $country . "&lang=" . $lang . + //"&ldId=" . $ldid; + String url = serverAddr + "/services/LearningDesignSVG?" + + LamsSecurityUtil.generateAuthenticateParameters(username); + logger.info("LAMS Req: " + url); return url; } /** - * Gets a list of learning designs & workspace folders for the current user from LAMS. - * + * Gets a list of learning designs & workspace folders for the current user from LAMS. + * * @param ctx * the blackboard context, contains session data * @param courseId * blackboard courseid. We pass it as a parameter as ctx.getCourse().getCourseId() is null when called * from LamsLearningDesignServlet. - * @param folderId folderId. It can be null and then LAMS returns default workspace folders. - * + * @param folderId + * folderId. It can be null and then LAMS returns default workspace folders. + * * @return a string containing the LAMS workspace tree in tigra format */ public static String getLearningDesigns(Context ctx, String courseId, String folderId) { - return getLearningDesigns(ctx, null, courseId, folderId,"getLearningDesignsJSON",null,null,null,null,null,null); + return LamsSecurityUtil.getLearningDesigns(ctx, null, courseId, folderId, "getLearningDesignsJSON", null, null, + null, null, null, null); } - + /** - * Gets a list of learning designs & workspace folders for the current user from LAMS or the user "usernameFromParam" - * - * @param ctx the blackboard context, contains session data - * @param usernameFromParam only used if there isn't a user in the context, due to how the servlet is called - * @param courseId blackboard course id. We pass it as a parameter as ctx.getCourse().getCourseId() is null when called + * Gets a list of learning designs & workspace folders for the current user from LAMS or the user + * "usernameFromParam" + * + * @param ctx + * the blackboard context, contains session data + * @param usernameFromParam + * only used if there isn't a user in the context, due to how the servlet is called + * @param courseId + * blackboard course id. We pass it as a parameter as ctx.getCourse().getCourseId() is null when called * from LamsLearningDesignServlet. - * @param folderId folderID in LAMS. It can be null and then LAMS returns default workspace folders. - * @param method which method to call on the LAMS end - * @param type used onlu for method = getLearningDesignsJSON, restricts by type - * @param page used only for method = getPagedHomeLearningDesignsJSON - * @param size used only for method = getPagedHomeLearningDesignsJSON - * @return a string containing the LAMS workspace tree in tigra format (method = getLearningDesignsJSON) or - * a string containing the learning designs in JSON (method = getPagedHomeLearningDesignsJSON) + * @param folderId + * folderID in LAMS. It can be null and then LAMS returns default workspace folders. + * @param method + * which method to call on the LAMS end + * @param type + * used onlu for method = getLearningDesignsJSON, restricts by type + * @param page + * used only for method = getPagedHomeLearningDesignsJSON + * @param size + * used only for method = getPagedHomeLearningDesignsJSON + * @return a string containing the LAMS workspace tree in tigra format (method = getLearningDesignsJSON) or + * a string containing the learning designs in JSON (method = getPagedHomeLearningDesignsJSON) */ - public static String getLearningDesigns(Context ctx, String usernameFromParam, String urlCourseId, String folderId, String method, String type, - String search, String page, String size, String sortName, String sortDate) { - + public static String getLearningDesigns(Context ctx, String usernameFromParam, String urlCourseId, String folderId, + String method, String type, String search, String page, String size, String sortName, String sortDate) { + String serverAddr = LamsPluginUtil.getServerUrl(); - - String courseId = setupCourseId(ctx, urlCourseId, true); + + String courseId = LamsSecurityUtil.setupCourseId(ctx, urlCourseId, true); String serverId = LamsPluginUtil.getServerId(); // If lams.properties could not be read, throw exception if (serverAddr == null || serverId == null) { - throw new RuntimeException("lams.properties file could not be read. serverAddr:" + serverAddr + ", serverId:" + serverId); + throw new RuntimeException( + "lams.properties file could not be read. serverAddr:" + serverAddr + ", serverId:" + serverId); } String timestamp = new Long(System.currentTimeMillis()).toString(); User user = ctx.getUser(); - if ( user == null ) + if (user == null) { user = BlackboardUtil.loadUserFromDB(usernameFromParam); - + } + String username = user.getUserName(); String firstName = user.getGivenName(); String lastName = user.getFamilyName(); String email = user.getEmailAddress(); - String hash = generateAuthenticationHash(timestamp, username, serverId); + String hash = LamsSecurityUtil.generateAuthenticationHash(timestamp, username, serverId); String locale = ctx.getUser().getLocale(); - String country = getCountryCode(ctx.getUser().getCountry()); + String country = LamsSecurityUtil.getCountryCode(ctx.getUser().getCountry()); // the mode to call upon learning designs - final Integer MODE = 2; + final int MODE = 2; // TODO: Make locale settings work - String learningDesigns = ""; // empty + String learningDesigns = ""; // empty try { - - String serviceURL = serverAddr - + "/services/xml/LearningDesignRepository?method="+method+"&datetime=" + String serviceURL = serverAddr + "/services/xml/LearningDesignRepository?method=" + method + "&datetime=" + timestamp + "&username=" + URLEncoder.encode(username, "utf8") + "&serverId=" + URLEncoder.encode(serverId, "utf8") + "&hashValue=" + hash + "&courseId=" + URLEncoder.encode(courseId, "UTF8") + "&country=" + country + "&lang=" + locale + "&mode=" + MODE + "&firstName=" + URLEncoder.encode(firstName, "UTF-8") + "&lastName=" + URLEncoder.encode(lastName, "UTF-8") + "&email=" + URLEncoder.encode(email, "UTF-8"); - - if (folderId != null ) { - serviceURL += "&folderID=" + ( folderId.equalsIgnoreCase("home") ? "-1" : folderId); + + if (folderId != null) { + serviceURL += "&folderID=" + (folderId.equalsIgnoreCase("home") ? "-1" : folderId); } // The following parameter is only used for getLearningDesignsJSON - if ( type != null && type.length() > 0 ) { - serviceURL += "&type=" +type; + if (type != null && type.length() > 0) { + serviceURL += "&type=" + type; } - + // The following parameters are only used for getPagedLearningDesignsJSON - if (page != null ) { + if (page != null) { serviceURL += "&page=" + page; } - if (size != null ) { + if (size != null) { serviceURL += "&size=" + size; } // sort by name, ascending = 1, descending = 0 - if (sortName != null ) { + if (sortName != null) { serviceURL += "&sortName=" + sortName; } // sort by date, ascending = 1, descending = 0 - if (sortDate != null ) { + if (sortDate != null) { serviceURL += "&sortDate=" + sortDate; } // get all the designs that contain this string - if (search != null ) { + if (search != null) { serviceURL += "&search=" + search; } InputStream is = LamsSecurityUtil.callLamsServerPost(serviceURL); - // Read/convert response to a String + // Read/convert response to a String StringWriter writer = new StringWriter(); IOUtils.copy(is, writer, "UTF-8"); learningDesigns = writer.toString(); } catch (MalformedURLException e) { - throw new RuntimeException("Unable to get LAMS learning designs, bad URL: '" + serverAddr - + "', please check lams.properties", e); + throw new RuntimeException( + "Unable to get LAMS learning designs, bad URL: '" + serverAddr + "', please check lams.properties", + e); } catch (IllegalStateException e) { throw new RuntimeException( "LAMS Server timeout, did not get a response from the LAMS server. Please contact your systems administrator", @@ -317,62 +335,66 @@ } catch (IOException e) { throw new RuntimeException(e); } - + return learningDesigns; } /** - * Gets a list of learning designs & workspace folders for the current user from LAMS. - * - * @param ctx the blackboard context, contains session data - * @param courseId blackboard courseid. We pass it as a parameter as ctx.getCourse().getCourseId() is null when called + * Gets a list of learning designs & workspace folders for the current user from LAMS. + * + * @param ctx + * the blackboard context, contains session data + * @param courseId + * blackboard courseid. We pass it as a parameter as ctx.getCourse().getCourseId() is null when called * from LamsLearningDesignServlet. - * @param ldId learning design to delete + * @param ldId + * learning design to delete * @return JSON response from server */ public static String deleteLearningDesigns(Context ctx, String urlCourseId, Long ldId) { - - String courseId = setupCourseId(ctx, urlCourseId, false); + String courseId = LamsSecurityUtil.setupCourseId(ctx, urlCourseId, false); + String serverAddr = LamsPluginUtil.getServerUrl(); String serverId = LamsPluginUtil.getServerId(); // If lams.properties could not be read, throw exception if (serverAddr == null || serverId == null) { - throw new RuntimeException("lams.properties file could not be read. serverAddr:" + serverAddr + ", serverId:" + serverId); + throw new RuntimeException( + "lams.properties file could not be read. serverAddr:" + serverAddr + ", serverId:" + serverId); } - + String timestamp = new Long(System.currentTimeMillis()).toString(); String username = ctx.getUser().getUserName(); String firstName = ctx.getUser().getGivenName(); String lastName = ctx.getUser().getFamilyName(); String email = ctx.getUser().getEmailAddress(); - String hash = generateAuthenticationHash(timestamp, username, serverId); + String hash = LamsSecurityUtil.generateAuthenticationHash(timestamp, username, serverId); String locale = ctx.getUser().getLocale(); - String country = getCountryCode(ctx.getUser().getCountry()); + String country = LamsSecurityUtil.getCountryCode(ctx.getUser().getCountry()); try { String serviceURL = serverAddr - + "/services/xml/LearningDesignRepository?method=deleteLearningDesignJSON&datetime=" - + timestamp + "&username=" + URLEncoder.encode(username, "utf8") + "&serverId=" + + "/services/xml/LearningDesignRepository?method=deleteLearningDesignJSON&datetime=" + timestamp + + "&username=" + URLEncoder.encode(username, "utf8") + "&serverId=" + URLEncoder.encode(serverId, "utf8") + "&hashValue=" + hash + "&courseId=" - + URLEncoder.encode(courseId, "UTF8") + "&country=" + country + "&lang=" + locale - + "&firstName=" + URLEncoder.encode(firstName, "UTF-8") + "&lastName=" - + URLEncoder.encode(lastName, "UTF-8") + "&email=" + URLEncoder.encode(email, "UTF-8") - + "&learningDesignID="+ldId; - + + URLEncoder.encode(courseId, "UTF8") + "&country=" + country + "&lang=" + locale + "&firstName=" + + URLEncoder.encode(firstName, "UTF-8") + "&lastName=" + URLEncoder.encode(lastName, "UTF-8") + + "&email=" + URLEncoder.encode(email, "UTF-8") + "&learningDesignID=" + ldId; + InputStream is = LamsSecurityUtil.callLamsServerPost(serviceURL); - // Read/convert response to a String + // Read/convert response to a String StringWriter writer = new StringWriter(); IOUtils.copy(is, writer, "UTF-8"); return writer.toString(); } catch (MalformedURLException e) { - throw new RuntimeException("Unable to get LAMS learning designs, bad URL: '" + serverAddr - + "', please check lams.properties", e); + throw new RuntimeException( + "Unable to get LAMS learning designs, bad URL: '" + serverAddr + "', please check lams.properties", + e); } catch (IllegalStateException e) { throw new RuntimeException( "LAMS Server timeout, did not get a response from the LAMS server. Please contact your systems administrator", @@ -405,7 +427,7 @@ /** * Starts lessons in lams through a LAMS webservice. - * + * * @param ctx * the blackboard contect, contains session data * @param usernameFromParam @@ -423,7 +445,7 @@ * according default setting * @param isPreview * whether LAMS should start it as a preview or not - * + * * @return the learning session id */ public static Long startLesson(User user, String courseId, long ldId, String title, String desc, @@ -435,26 +457,28 @@ String username = user.getUserName(); String locale = user.getLocale(); - String country = getCountryCode(user.getCountry()); + String country = LamsSecurityUtil.getCountryCode(user.getCountry()); String method = (isPreview) ? "preview" : "start"; - + if (courseId == null || serverId == null || serverAddr == null || serverSecretKey == null) { logger.info("Unable to start lesson, one or more lams configuration properties or the course id is null"); - throw new RuntimeException("Unable to start lesson, one or more lams configuration properties or the course id is null. courseId="+courseId); + throw new RuntimeException( + "Unable to start lesson, one or more lams configuration properties or the course id is null. courseId=" + + courseId); } try { String timestamp = new Long(System.currentTimeMillis()).toString(); - String hash = generateAuthenticationHash(timestamp, username, serverId); + String hash = LamsSecurityUtil.generateAuthenticationHash(timestamp, username, serverId); String course = courseId != null ? "&courseId=" + URLEncoder.encode(courseId, "UTF8") : ""; String serviceURL = serverAddr + "/services/xml/LessonManager?" + "serverId=" + URLEncoder.encode(serverId, "utf8") + "&datetime=" + timestamp + "&username=" + URLEncoder.encode(username, "utf8") + "&hashValue=" + hash + course + "&ldId=" + new Long(ldId).toString() + "&country=" + country + "&lang=" + locale + "&method=" + method + "&title=" + URLEncoder.encode(title, "utf8").trim() + "&desc=" - + URLEncoder.encode(desc, "utf8").trim() + "&enableNotifications=true" - + "&allowLearnerRestart=" + enforceAllowLearnerRestart; + + URLEncoder.encode(desc, "utf8").trim() + "&enableNotifications=true" + "&allowLearnerRestart=" + + enforceAllowLearnerRestart; logger.info("LAMS START LESSON Req: " + serviceURL); @@ -465,10 +489,10 @@ Document document = db.parse(is); return Long.parseLong(document.getElementsByTagName("Lesson").item(0).getAttributes() .getNamedItem("lessonId").getNodeValue()); - + } catch (MalformedURLException e) { - throw new RuntimeException("Unable to start LAMS lesson, bad URL: '" + serverAddr - + "', please check lams.properties", e); + throw new RuntimeException( + "Unable to start LAMS lesson, bad URL: '" + serverAddr + "', please check lams.properties", e); } catch (IllegalStateException e) { throw new RuntimeException( "LAMS Server timeout, did not get a response from the LAMS server. Please contact your systems administrator", @@ -482,8 +506,8 @@ "LAMS Server timeout, did not get a response from the LAMS server. Please contact your systems administrator", e); } catch (IOException e) { - throw new RuntimeException("Unable to start LAMS lesson. " + e.getMessage() - + " Please contact your system administrator.", e); + throw new RuntimeException( + "Unable to start LAMS lesson. " + e.getMessage() + " Please contact your system administrator.", e); } catch (ParserConfigurationException e) { throw new RuntimeException("Unable to start LAMS lesson. Please contact your system administrator.", e); } catch (SAXException e) { @@ -494,20 +518,21 @@ /** * Deletes lesson on LAMS server through a LAMS webservice. - * + * * @param ctx * the blackboard contect, contains session data * @param usernameFromParam * current user's username * @param lsId * the lesson id to be deleted - * + * * @return boolean whether lesson was successfully deleted - * @throws IOException - * @throws ParserConfigurationException - * @throws SAXException + * @throws IOException + * @throws ParserConfigurationException + * @throws SAXException */ - public static Boolean deleteLesson(String userName, String lsId) throws IOException, ParserConfigurationException, SAXException { + public static Boolean deleteLesson(String userName, String lsId) + throws IOException, ParserConfigurationException, SAXException { String serverId = LamsPluginUtil.getServerId(); String serverAddr = LamsPluginUtil.getServerUrl(); @@ -518,7 +543,7 @@ } String timestamp = new Long(System.currentTimeMillis()).toString(); - String hash = generateAuthenticationHash(timestamp, userName, serverId); + String hash = LamsSecurityUtil.generateAuthenticationHash(timestamp, userName, serverId); String serviceURL = serverAddr + "/services/xml/LessonManager?" + "serverId=" + URLEncoder.encode(serverId, "utf8") + "&datetime=" + timestamp + "&username=" @@ -534,15 +559,15 @@ return Boolean.parseBoolean( document.getElementsByTagName("Lesson").item(0).getAttributes().getNamedItem("deleted").getNodeValue()); } - + /** * Clones lessons in lams through a LAMS webservice using the lsID & courseId parameter. - * + * * @param courseId - * courseId as a request parameter + * courseId as a request parameter * @param ldId * the learning design id for which you wish to start a lesson - * + * * @return lesson id of a cloned lesson */ public static Long cloneLesson(User teacher, String courseId, String lsId) { @@ -552,36 +577,38 @@ String serverSecretKey = LamsPluginUtil.getServerSecretKey(); String username = teacher.getUserName(); String locale = teacher.getLocale(); - String country = getCountryCode(teacher.getCountry()); - + String country = LamsSecurityUtil.getCountryCode(teacher.getCountry()); + if (courseId == null || serverId == null || serverAddr == null || serverSecretKey == null) { logger.info("Unable to clone lesson, one or more lams configuration properties or the course id is null"); - throw new RuntimeException("Unable to clone lesson, one or more lams configuration properties or the course id is null. courseId="+courseId); + throw new RuntimeException( + "Unable to clone lesson, one or more lams configuration properties or the course id is null. courseId=" + + courseId); } try { String method = "clone"; String timestamp = new Long(System.currentTimeMillis()).toString(); - String hash = generateAuthenticationHash(timestamp, username, serverId); + String hash = LamsSecurityUtil.generateAuthenticationHash(timestamp, username, serverId); String serviceURL = serverAddr + "/services/xml/LessonManager?" + "serverId=" + URLEncoder.encode(serverId, "utf8") + "&datetime=" + timestamp + "&username=" + URLEncoder.encode(username, "utf8") + "&hashValue=" + hash + "&courseId=" - + URLEncoder.encode(courseId, "UTF8") + "&country=" - + country + "&lang=" + locale + "&lsId=" + lsId + "&method=" + method; + + URLEncoder.encode(courseId, "UTF8") + "&country=" + country + "&lang=" + locale + "&lsId=" + lsId + + "&method=" + method; logger.info("LAMS clone lesson request: " + serviceURL); - - // parse xml response and get the lesson id + + // parse xml response and get the lesson id InputStream is = LamsSecurityUtil.callLamsServerPost(serviceURL); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document document = db.parse(is); return Long.parseLong(document.getElementsByTagName("Lesson").item(0).getAttributes() .getNamedItem("lessonId").getNodeValue()); - + } catch (MalformedURLException e) { - throw new RuntimeException("Unable to clone LAMS lesson, bad URL: '" + serverAddr - + "', please check lams.properties", e); + throw new RuntimeException( + "Unable to clone LAMS lesson, bad URL: '" + serverAddr + "', please check lams.properties", e); } catch (IllegalStateException e) { throw new RuntimeException( "LAMS Server timeout, did not get a response from the LAMS server. Please contact your systems administrator", @@ -601,44 +628,47 @@ throw new RuntimeException( "Unable to clone LAMS lesson. " + e.getMessage() + " Can't instantiate DocumentBuilder.", e); } catch (SAXException e) { - throw new RuntimeException( - "Unable to clone LAMS lesson. " + e.getMessage() + " Can't parse LAMS results.", e); + throw new RuntimeException("Unable to clone LAMS lesson. " + e.getMessage() + " Can't parse LAMS results.", + e); } } - + /** * Import learning design in LAMS from its temp folder. Then starting a lesson using this learning design. - * + * * @param courseId - * courseId as a request parameter + * courseId as a request parameter * @param ldId * the learning design id for which you wish to start a lesson - * + * * @return lesson id of a cloned lesson - * @throws LamsServerException + * @throws LamsServerException */ - public static Long importLearningDesign(User teacher, String courseId, String lsId, String ldId) throws LamsServerException { + public static Long importLearningDesign(User teacher, String courseId, String lsId, String ldId) + throws LamsServerException { String serverId = LamsPluginUtil.getServerId(); String serverAddr = LamsPluginUtil.getServerUrl(); String serverSecretKey = LamsPluginUtil.getServerSecretKey(); String username = teacher.getUserName(); String locale = teacher.getLocale(); - String country = getCountryCode(teacher.getCountry()); - + String country = LamsSecurityUtil.getCountryCode(teacher.getCountry()); + if (courseId == null || serverId == null || serverAddr == null || serverSecretKey == null) { logger.info("Unable to import lesson, one or more lams configuration properties or the course id is null"); - throw new RuntimeException("Unable to import lesson, one or more lams configuration properties or the course id is null. courseId="+courseId); + throw new RuntimeException( + "Unable to import lesson, one or more lams configuration properties or the course id is null. courseId=" + + courseId); } - //import a learning design + //import a learning design String filePath = EXPORT_FOLDER_LAMS_SERVER + lsId + "_" + ldId + ".zip"; - + try { - String filePathParam = URLEncoder.encode(filePath, "UTF-8"); + String filePathParam = URLEncoder.encode(filePath, "UTF-8"); String timestamp = new Long(System.currentTimeMillis()).toString(); - String hash = generateAuthenticationHash(timestamp, username, serverId); + String hash = LamsSecurityUtil.generateAuthenticationHash(timestamp, username, serverId); String serviceURL = serverAddr + "/services/xml/LessonManager?" + "serverId=" + URLEncoder.encode(serverId, "utf8") + "&datetime=" + timestamp + "&username=" + URLEncoder.encode(username, "utf8") + "&hashValue=" + hash + "&courseId=" @@ -652,9 +682,9 @@ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document document = db.parse(is); - return Long.parseLong(document.getElementsByTagName("Lesson").item(0).getAttributes() - .getNamedItem("ldId").getNodeValue()); - + return Long.parseLong(document.getElementsByTagName("Lesson").item(0).getAttributes().getNamedItem("ldId") + .getNodeValue()); + } catch (MalformedURLException e) { throw new LamsServerException("Unable to import LAMS lesson, bad URL: '" + serverAddr + "', please check lams.properties. Tried to import file " + filePath, e); @@ -687,10 +717,10 @@ } } - + /** * Pre-adding students and monitors to a lesson - * + * * @param ctx * the blackboard contect, contains session data * @param lessonId @@ -702,7 +732,7 @@ String serverSecretKey = LamsPluginUtil.getServerSecretKey(); String username = user.getUserName(); String locale = user.getLocale(); - String country = getCountryCode(user.getCountry()); + String country = LamsSecurityUtil.getCountryCode(user.getCountry()); if (serverId == null || serverAddr == null || serverSecretKey == null) { throw new RuntimeException("Unable to start lesson, one or more lams configuration properties is null"); @@ -727,16 +757,16 @@ List studentCourseMemberships = courseMemLoader.loadByCourseIdAndRole(courseId, CourseMembership.Role.STUDENT, null, true); for (CourseMembership courseMembership : studentCourseMemberships) { - String learnerId = escapeValue(courseMembership.getUser().getUserName()); + String learnerId = LamsSecurityUtil.escapeValue(courseMembership.getUser().getUserName()); learnerIds += learnerId + ","; - - String firstName = escapeValue(courseMembership.getUser().getGivenName()); + + String firstName = LamsSecurityUtil.escapeValue(courseMembership.getUser().getGivenName()); firstNames += firstName + ","; - - String lastName = escapeValue(courseMembership.getUser().getFamilyName()); + + String lastName = LamsSecurityUtil.escapeValue(courseMembership.getUser().getFamilyName()); lastNames += lastName + ","; - - String email = escapeValue(courseMembership.getUser().getEmailAddress()); + + String email = LamsSecurityUtil.escapeValue(courseMembership.getUser().getEmailAddress()); emails += email + ","; } @@ -749,16 +779,16 @@ CourseMembership.Role.COURSE_BUILDER, null, true); monitorCourseMemberships.addAll(courseBuilderCourseMemberships); for (CourseMembership courseMembership : monitorCourseMemberships) { - String monitorId = escapeValue(courseMembership.getUser().getUserName()); + String monitorId = LamsSecurityUtil.escapeValue(courseMembership.getUser().getUserName()); monitorIds += monitorId + ","; - String firstName = escapeValue(courseMembership.getUser().getGivenName()); + String firstName = LamsSecurityUtil.escapeValue(courseMembership.getUser().getGivenName()); firstNames += firstName + ","; - String lastName = escapeValue(courseMembership.getUser().getFamilyName()); + String lastName = LamsSecurityUtil.escapeValue(courseMembership.getUser().getFamilyName()); lastNames += lastName + ","; - String email = escapeValue(courseMembership.getUser().getEmailAddress()); + String email = LamsSecurityUtil.escapeValue(courseMembership.getUser().getEmailAddress()); emails += email + ","; } @@ -775,7 +805,7 @@ monitorIds = monitorIds.isEmpty() ? "" : monitorIds.substring(0, monitorIds.length() - 1); String timestamp = new Long(System.currentTimeMillis()).toString(); - String hash = generateAuthenticationHash(timestamp, username, serverId); + String hash = LamsSecurityUtil.generateAuthenticationHash(timestamp, username, serverId); String serviceURL = serverAddr + "/services/xml/LessonManager?" + "&serverId=" + URLEncoder.encode(serverId, "utf8") + "&datetime=" + timestamp + "&username=" @@ -794,10 +824,11 @@ System.out.println("LAMS Preadd users Req: " + serviceURL); InputStream is = LamsSecurityUtil.callLamsServerPost(serviceURL); - + } catch (MalformedURLException e) { - throw new RuntimeException("Unable to preadd users to the lesson, bad URL: '" + serverAddr - + "', please check lams.properties", e); + throw new RuntimeException( + "Unable to preadd users to the lesson, bad URL: '" + serverAddr + "', please check lams.properties", + e); } catch (IllegalStateException e) { throw new RuntimeException( "LAMS Server timeout, did not get a response from the LAMS server. Please contact your systems administrator", @@ -815,17 +846,18 @@ + " Please contact your system administrator.", e); } catch (KeyNotFoundException e) { throw new RuntimeException("Unable to preadd users to the lesson. " + e.getMessage() - + " Please contact your system administrator.", e); + + " Please contact your system administrator.", e); } catch (PersistenceException e) { throw new RuntimeException("Unable to preadd users to the lesson. " + e.getMessage() - + " Please contact your system administrator.", e); + + " Please contact your system administrator.", e); } } - + /** - * Takes care about blank values. Besides, escapes CSV sensitive symbols (commas, quotes, etc) and then encodes it to be sent as a URL parameter. - * + * Takes care about blank values. Besides, escapes CSV sensitive symbols (commas, quotes, etc) and then encodes it + * to be sent as a URL parameter. + * * @param value * @param CSV * @return @@ -840,29 +872,29 @@ return encodedValue; } - + /** * getLearnerProgress in current lesson through a LAMS webservice - * + * * @param ctx * the blackboard contect, contains session data * @param lsId * the lesson id for which you wish to retrieve progress - * + * * @return the learning session id */ public static LearnerProgressDTO getLearnerProgress(Context ctx, long lsId) { String serverId = LamsPluginUtil.getServerId(); String serverAddr = LamsPluginUtil.getServerUrl(); String serverSecretKey = LamsPluginUtil.getServerSecretKey(); String courseId = ctx.getCourse().getCourseId(); - + String username = ctx.getUser().getUserName(); String firstName = ctx.getUser().getGivenName(); String lastName = ctx.getUser().getFamilyName(); String email = ctx.getUser().getEmailAddress(); String locale = ctx.getUser().getLocale(); - String country = getCountryCode(ctx.getUser().getCountry()); + String country = LamsSecurityUtil.getCountryCode(ctx.getUser().getCountry()); if (serverId == null || serverAddr == null || serverSecretKey == null) { throw new RuntimeException("Unable to start lesson, one or more lams configuration properties is null"); @@ -871,7 +903,7 @@ try { String timestamp = new Long(System.currentTimeMillis()).toString(); - String hash = generateAuthenticationHash(timestamp, username, serverId); + String hash = LamsSecurityUtil.generateAuthenticationHash(timestamp, username, serverId); String serviceURL = serverAddr + "/services/xml/LessonManager?method=singleStudentProgress" + "&serverId=" + URLEncoder.encode(serverId, "utf8") + "&datetime=" + timestamp + "&username=" @@ -892,19 +924,22 @@ // get the lesson id from the response NamedNodeMap learnerProgress = document.getElementsByTagName("LearnerProgress").item(0).getAttributes(); - boolean lessonComplete = Boolean.parseBoolean(learnerProgress.getNamedItem("lessonComplete").getNodeValue()); - int activitiesCompleted = Integer.parseInt(learnerProgress.getNamedItem("activitiesCompleted").getNodeValue()); - int attemptedActivities = Integer.parseInt(learnerProgress.getNamedItem("attemptedActivities").getNodeValue()); + boolean lessonComplete = Boolean + .parseBoolean(learnerProgress.getNamedItem("lessonComplete").getNodeValue()); + int activitiesCompleted = Integer + .parseInt(learnerProgress.getNamedItem("activitiesCompleted").getNodeValue()); + int attemptedActivities = Integer + .parseInt(learnerProgress.getNamedItem("attemptedActivities").getNodeValue()); int activityCount = Integer.parseInt(learnerProgress.getNamedItem("activityCount").getNodeValue()); LearnerProgressDTO learnerProgressDto = new LearnerProgressDTO(activityCount, attemptedActivities, activitiesCompleted, lessonComplete); - + return learnerProgressDto; } catch (MalformedURLException e) { - throw new RuntimeException("Unable to get LearnerProgress, bad URL: '" + serverAddr - + "', please check lams.properties", e); + throw new RuntimeException( + "Unable to get LearnerProgress, bad URL: '" + serverAddr + "', please check lams.properties", e); } catch (IllegalStateException e) { throw new RuntimeException( "LAMS Server timeout, did not get a response from the LAMS server. Please contact your systems administrator", @@ -918,8 +953,9 @@ "LAMS Server timeout, did not get a response from the LAMS server. Please contact your systems administrator", e); } catch (IOException e) { - throw new RuntimeException("Unable to get LearnerProgress. " + e.getMessage() - + " Please contact your system administrator.", e); + throw new RuntimeException( + "Unable to get LearnerProgress. " + e.getMessage() + " Please contact your system administrator.", + e); } catch (ParserConfigurationException e) { throw new RuntimeException( "Unable to get LearnerProgress. " + e.getMessage() + " Please contact your system administrator.", @@ -931,10 +967,10 @@ } } - + /** * Make a call to LAMS server. - * + * * @param serviceURL * @return resulted InputStream * @throws IOException @@ -958,11 +994,10 @@ return is; } - - + /** * Make a call to LAMS server. - * + * * @param serviceURL * @return resulted InputStream * @throws IOException @@ -971,18 +1006,18 @@ String path; String body; - + int bodyStart = serviceURL.indexOf('?'); - if ( bodyStart < 0 ) { + if (bodyStart < 0) { path = serviceURL; body = ""; } else { - path = serviceURL.substring(0,bodyStart); - body = serviceURL.substring(bodyStart+1); + path = serviceURL.substring(0, bodyStart); + body = serviceURL.substring(bodyStart + 1); } - byte[] postData = body.getBytes("UTF-8"); - int postDataLength = postData.length; + byte[] postData = body.getBytes("UTF-8"); + int postDataLength = postData.length; URL url = new URL(path); URLConnection conn = url.openConnection(); @@ -991,15 +1026,15 @@ } HttpURLConnection httpConn = (HttpURLConnection) conn; - conn.setDoOutput( true ); + conn.setDoOutput(true); httpConn.setRequestMethod("POST"); - conn.setRequestProperty( "Content-Type", "application/x-www-form-urlencoded"); - conn.setRequestProperty( "charset", "utf-8"); - conn.setRequestProperty( "Content-Length", Integer.toString( postDataLength )); - conn.setUseCaches( false ); + conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + conn.setRequestProperty("charset", "utf-8"); + conn.setRequestProperty("Content-Length", Integer.toString(postDataLength)); + conn.setUseCaches(false); - conn.getOutputStream().write(postData); - + conn.getOutputStream().write(postData); + if (httpConn.getResponseCode() != HttpURLConnection.HTTP_OK) { throw new IOException("LAMS server responded with HTTP response code: " + httpConn.getResponseCode() + ", HTTP response message: " + httpConn.getResponseMessage()); @@ -1011,22 +1046,22 @@ public static String getServerTime() throws IOException, PersistenceException { long now = (new Date()).getTime(); - + // get LamsServerTime from the storage PortalExtraInfo pei = PortalUtil.loadPortalExtraInfo(null, null, "LamsServerTimeStorage"); ExtraInfo ei = pei.getExtraInfo(); - + String lamsServerTimeDeltaStr = ei.getValue("LAMSServerTimeDelta"); long lamsServerTimeDelta = (lamsServerTimeDeltaStr == null) ? -1 : Long.parseLong(lamsServerTimeDeltaStr); - + //check if it's time to update String lastUpdateTimeStr = ei.getValue("lastUpdateTime"); long lastUpdateTime = (lastUpdateTimeStr == null) ? -1 : Long.parseLong(lastUpdateTimeStr); long lamsServerTime; - long lamsServerTimeRefreshInterval = getLamsServerTimeRefreshInterval() * 60 * 60 * 1000; + long lamsServerTimeRefreshInterval = LamsSecurityUtil.getLamsServerTimeRefreshInterval() * 60 * 60 * 1000; if ((lamsServerTimeDeltaStr == null) || (lastUpdateTime + lamsServerTimeRefreshInterval < now)) { - + // refresh time from LAMS server String serverAddr = LamsPluginUtil.getServerUrl(); String serviceURL = serverAddr + "/services/getServerTime"; @@ -1035,7 +1070,7 @@ StringWriter writer = new StringWriter(); IOUtils.copy(is, writer, "UTF-8"); - + try { lamsServerTime = Long.parseLong(writer.toString().trim()); } catch (NumberFormatException e) { @@ -1049,29 +1084,29 @@ ei.setValue("lastUpdateTime", "" + now); PortalUtil.savePortalExtraInfo(pei); } else { - + //no need to refresh - use stored value lamsServerTime = now - lamsServerTimeDelta; } - + return "" + lamsServerTime; } - + /** - * + * * @return the LAMS server time refresh interval from lams.properties */ private static long getLamsServerTimeRefreshInterval() { //set default value long lamsServerTimeRefreshInterval = 24; - + try { String lamsServerTimeRefreshIntervalStr = LamsPluginUtil.getLamsServerTimeRefreshInterval(); lamsServerTimeRefreshInterval = Long.parseLong(lamsServerTimeRefreshIntervalStr); } catch (NumberFormatException e) { logger.warn("Wrong format of PROP_LAMS_SERVER_TIME_REFRESH_INTERVAL from lams.properties"); } - + return lamsServerTimeRefreshInterval; } @@ -1082,15 +1117,15 @@ String plaintext = datetime.toLowerCase().trim() + login.toLowerCase().trim() + serverId.toLowerCase().trim() + serverSecretKey.toLowerCase().trim(); - String hash = sha1(plaintext); + String hash = LamsSecurityUtil.sha1(plaintext); return hash; } /** * The parameters are: uid - the username on the external system method - either author, monitor or learner ts - * timestamp sid - serverID str is [ts + uid + method + serverID + serverSecretKey] (Note: all lower case) - * + * * @param str * The string to be hashed * @return The hased string @@ -1103,12 +1138,21 @@ throw new RuntimeException(e); } } - + + public static String sha256(String plaintext) { + try { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + return new String(Hex.encodeHex(md.digest(plaintext.getBytes()))); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + /** * Returns country code based on country name. If it can't find according code - returns "XX". */ public static String getCountryCode(String countryName) { - + if (StringUtils.isNotBlank(countryName)) { Locale[] locales = Locale.getAvailableLocales(); for (Locale locale : locales) { @@ -1120,7 +1164,7 @@ } } } - + return "XX"; } Index: lams_central/src/java/org/lamsfoundation/lams/web/LoginRequestLtiServlet.java =================================================================== diff -u -r058adba867d104c2148e289a3dacda7f22f6ac60 -ra4cac24066ba39701ad51a8dd4c512b6e4100873 --- lams_central/src/java/org/lamsfoundation/lams/web/LoginRequestLtiServlet.java (.../LoginRequestLtiServlet.java) (revision 058adba867d104c2148e289a3dacda7f22f6ac60) +++ lams_central/src/java/org/lamsfoundation/lams/web/LoginRequestLtiServlet.java (.../LoginRequestLtiServlet.java) (revision a4cac24066ba39701ad51a8dd4c512b6e4100873) @@ -202,7 +202,7 @@ + method.toLowerCase().trim() + (IntegrationConstants.METHOD_LEARNER_STRICT_AUTHENTICATION.equals(method) ? lessonId : "") + consumerKey.toLowerCase().trim() + secret.toLowerCase().trim(); - String hash = HashUtil.sha1(plaintext); + String hash = HashUtil.sha256(plaintext); // constructing redirectUrl by getting request.getQueryString() for POST requests String redirectUrl = "lti.do"; Index: lams_central/src/java/org/lamsfoundation/lams/webservice/UserRoleServlet.java =================================================================== diff -u -r33829c670fd8c90447d62ea3300498a103905e7a -ra4cac24066ba39701ad51a8dd4c512b6e4100873 --- lams_central/src/java/org/lamsfoundation/lams/webservice/UserRoleServlet.java (.../UserRoleServlet.java) (revision 33829c670fd8c90447d62ea3300498a103905e7a) +++ lams_central/src/java/org/lamsfoundation/lams/webservice/UserRoleServlet.java (.../UserRoleServlet.java) (revision a4cac24066ba39701ad51a8dd4c512b6e4100873) @@ -56,20 +56,25 @@ String plaintext = datetime.toLowerCase().trim() + username.toLowerCase().trim() + targetUsername.toLowerCase().trim() + method.toLowerCase().trim() + role.toLowerCase().trim() + extServer.getServerid().toLowerCase().trim() + extServer.getServerkey().toLowerCase().trim(); - if (!hashValue.equals(HashUtil.sha1(plaintext))) { + String parametersHash = null; + if (hashValue.length() == HashUtil.SHA1_HEX_LENGTH) { + // for some time support SHA-1 for authentication + parametersHash = HashUtil.sha1(plaintext); + } else { + parametersHash = HashUtil.sha256(plaintext); + } + if (!hashValue.equals(parametersHash)) { log.error("Hash check failed while trying to set role for user: " + targetUsername); response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication failed, invalid hash"); return; } - ExtUserUseridMap sysadminUserMap = integrationService.getExtUserUseridMap(extServer, - username); + ExtUserUseridMap sysadminUserMap = integrationService.getExtUserUseridMap(extServer, username); if (!securityService.isSysadmin(sysadminUserMap.getUser().getUserId(), "set user role", false)) { log.error("Sysadmin role check failed while trying to set role for user: " + targetUsername); response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication failed, user is not sysadmin"); return; } - ExtUserUseridMap userMap = integrationService.getExtUserUseridMap(extServer, - targetUsername); + ExtUserUseridMap userMap = integrationService.getExtUserUseridMap(extServer, targetUsername); User targetUser = userMap.getUser(); if ("grant".equalsIgnoreCase(method)) { grant(targetUser, role); @@ -107,7 +112,7 @@ switch (role) { case Role.SYSADMIN: Organisation rootOrganisation = userManagementService.getRootOrganisation(); - List roles = new ArrayList(Arrays.asList(Role.ROLE_SYSADMIN.toString())); + List roles = new ArrayList<>(Arrays.asList(Role.ROLE_SYSADMIN.toString())); userManagementService.setRolesForUserOrganisation(user, rootOrganisation.getOrganisationId(), roles); break; default: @@ -122,7 +127,7 @@ switch (role) { case Role.SYSADMIN: Organisation rootOrganisation = userManagementService.getRootOrganisation(); - List roles = new ArrayList(); + List roles = new ArrayList<>(); userManagementService.setRolesForUserOrganisation(user, rootOrganisation.getOrganisationId(), roles); break; default: Index: lams_common/src/java/org/lamsfoundation/lams/integration/security/Authenticator.java =================================================================== diff -u -reed8c9ab647229fb34fdadf6465dac729cf3dd87 -ra4cac24066ba39701ad51a8dd4c512b6e4100873 --- lams_common/src/java/org/lamsfoundation/lams/integration/security/Authenticator.java (.../Authenticator.java) (revision eed8c9ab647229fb34fdadf6465dac729cf3dd87) +++ lams_common/src/java/org/lamsfoundation/lams/integration/security/Authenticator.java (.../Authenticator.java) (revision a4cac24066ba39701ad51a8dd4c512b6e4100873) @@ -144,7 +144,14 @@ } public static void checkHash(String plaintext, String hashValue) throws AuthenticationException { - if (!hashValue.equals(HashUtil.sha1(plaintext))) { + String parametersHash = null; + if (hashValue.length() == HashUtil.SHA1_HEX_LENGTH) { + // for some time support SHA-1 for authentication + parametersHash = HashUtil.sha1(plaintext); + } else { + parametersHash = HashUtil.sha256(plaintext); + } + if (!hashValue.equals(parametersHash)) { throw new AuthenticationException("Authentication failed!"); } } Index: lams_common/src/java/org/lamsfoundation/lams/integration/service/IntegrationService.java =================================================================== diff -u -rca67d3227c5ace010da9afa104645a86c50a004f -ra4cac24066ba39701ad51a8dd4c512b6e4100873 --- lams_common/src/java/org/lamsfoundation/lams/integration/service/IntegrationService.java (.../IntegrationService.java) (revision ca67d3227c5ace010da9afa104645a86c50a004f) +++ lams_common/src/java/org/lamsfoundation/lams/integration/service/IntegrationService.java (.../IntegrationService.java) (revision a4cac24066ba39701ad51a8dd4c512b6e4100873) @@ -567,7 +567,7 @@ String serverKey = extServer.getServerkey(); String plaintext = timestamp.trim().toLowerCase() + extUsername.trim().toLowerCase() + serverId.trim().toLowerCase() + serverKey.trim().toLowerCase(); - return HashUtil.sha1(plaintext); + return HashUtil.sha256(plaintext); } private String buildName(String prefix, String name) { @@ -865,7 +865,7 @@ userData[k - 1] = userProperty; } String salt = HashUtil.salt(); - String password = HashUtil.sha1(RandomPasswordGenerator.nextPassword(10)); + String password = HashUtil.sha256(RandomPasswordGenerator.nextPassword(10), salt); extUserUseridMap = createExtUserUseridMap(extServer, extUsername, password, salt, userData, true); } Index: lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/web/controller/LearningWebsocketServer.java =================================================================== diff -u -rcd4af70336301a4c551cf28afbfc5534e3e6e7c9 -ra4cac24066ba39701ad51a8dd4c512b6e4100873 --- lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/web/controller/LearningWebsocketServer.java (.../LearningWebsocketServer.java) (revision cd4af70336301a4c551cf28afbfc5534e3e6e7c9) +++ lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/web/controller/LearningWebsocketServer.java (.../LearningWebsocketServer.java) (revision a4cac24066ba39701ad51a8dd4c512b6e4100873) @@ -155,7 +155,7 @@ String userName = websocket.userName; ArrayNode messagesJSON = LearningWebsocketServer.getMessages(chatSession, messages, userName); // if hash of roster and messages is the same as before, do not send the message, save the bandwidth - String hash = HashUtil.sha1(rosterString + messagesJSON.toString()); + String hash = HashUtil.sha256(rosterString + messagesJSON.toString()); if ((websocket.hash == null) || !websocket.hash.equals(hash)) { websocket.hash = hash; @@ -327,10 +327,7 @@ */ @OnMessage public void receiveMessage(String input, Session session) throws JsonProcessingException, IOException { - if (StringUtils.isBlank(input)) { - return; - } - if (input.equalsIgnoreCase("ping")) { + if (StringUtils.isBlank(input) || input.equalsIgnoreCase("ping")) { // just a ping every few minutes return; }