Index: lams_admin/src/java/org/lamsfoundation/lams/admin/web/controller/ExtServerManagementController.java =================================================================== diff -u -r351f9417a32d396911387eeef3117fd40be35b7c -r8c86b938e95d7e4081ddcba08a23012c813d936d --- lams_admin/src/java/org/lamsfoundation/lams/admin/web/controller/ExtServerManagementController.java (.../ExtServerManagementController.java) (revision 351f9417a32d396911387eeef3117fd40be35b7c) +++ lams_admin/src/java/org/lamsfoundation/lams/admin/web/controller/ExtServerManagementController.java (.../ExtServerManagementController.java) (revision 8c86b938e95d7e4081ddcba08a23012c813d936d) @@ -78,6 +78,9 @@ ExtServer map = integrationService.getExtServer(sid); BeanUtils.copyProperties(extServerForm, map); } + + integrationService.clearLessonFinishUrlCache(); + return "integration/servermaintain"; } @@ -159,6 +162,9 @@ "integrated server name: " + map.getServerid()); } integrationService.saveExtServer(map); + + integrationService.clearLessonFinishUrlCache(); + return "forward:/extserver/serverlist.do"; } else { request.setAttribute("errorMap", errorMap); @@ -173,6 +179,8 @@ map.setDisabled(true); integrationService.saveExtServer(map); + integrationService.clearLessonFinishUrlCache(); + AuditLogFilter.log(AuditLogFilter.INTEGRATED_SERVER_DISABLE_ACTION, "integrated server name: " + map.getServerid()); @@ -186,6 +194,8 @@ map.setDisabled(false); integrationService.saveExtServer(map); + integrationService.clearLessonFinishUrlCache(); + AuditLogFilter.log(AuditLogFilter.INTEGRATED_SERVER_ENABLE_ACTION, "integrated server name: " + map.getServerid()); @@ -201,6 +211,9 @@ "integrated server name: " + extServer.getServerid()); userManagementService.delete(extServer); + + integrationService.clearLessonFinishUrlCache(); + return "redirect:/extserver/serverlist.do"; } Index: lams_admin/src/java/org/lamsfoundation/lams/admin/web/controller/LtiConsumerManagementController.java =================================================================== diff -u -r351f9417a32d396911387eeef3117fd40be35b7c -r8c86b938e95d7e4081ddcba08a23012c813d936d --- lams_admin/src/java/org/lamsfoundation/lams/admin/web/controller/LtiConsumerManagementController.java (.../LtiConsumerManagementController.java) (revision 351f9417a32d396911387eeef3117fd40be35b7c) +++ lams_admin/src/java/org/lamsfoundation/lams/admin/web/controller/LtiConsumerManagementController.java (.../LtiConsumerManagementController.java) (revision 8c86b938e95d7e4081ddcba08a23012c813d936d) @@ -112,6 +112,8 @@ request.setAttribute("timezoneDtos", timezoneDtos); } + integrationService.clearLessonFinishUrlCache(); + return "integration/ltiConsumer"; } @@ -126,6 +128,8 @@ ltiConsumer.setDisabled(disable); integrationService.saveExtServer(ltiConsumer); + integrationService.clearLessonFinishUrlCache(); + AuditLogFilter.log(AuditLogFilter.LTI_INTEGRATED_SERVER_DISABLE_ACTION, "integrated server name: " + ltiConsumer.getServerid()); @@ -139,6 +143,8 @@ ltiConsumer.setDisabled(false); integrationService.saveExtServer(ltiConsumer); + integrationService.clearLessonFinishUrlCache(); + AuditLogFilter.log(AuditLogFilter.LTI_INTEGRATED_SERVER_ENABLE_ACTION, "LTI integrated server name: " + ltiConsumer.getServerid()); @@ -158,6 +164,8 @@ userManagementService.delete(extServer); + integrationService.clearLessonFinishUrlCache(); + return start(request); } @@ -245,6 +253,9 @@ ltiConsumer.setDefaultLocale(locale); integrationService.saveExtServer(ltiConsumer); + + integrationService.clearLessonFinishUrlCache(); + return start(request); } else { Index: lams_common/src/java/org/lamsfoundation/lams/integration/service/IIntegrationService.java =================================================================== diff -u -r521b542aaaa17584d68940f23bfc880f1a2ce340 -r8c86b938e95d7e4081ddcba08a23012c813d936d --- lams_common/src/java/org/lamsfoundation/lams/integration/service/IIntegrationService.java (.../IIntegrationService.java) (revision 521b542aaaa17584d68940f23bfc880f1a2ce340) +++ lams_common/src/java/org/lamsfoundation/lams/integration/service/IIntegrationService.java (.../IIntegrationService.java) (revision 8c86b938e95d7e4081ddcba08a23012c813d936d) @@ -278,4 +278,13 @@ void updateUserRoles(User user, Organisation org, String method); + /** + * Clears cache of integrated server lesson finish urls so it can reloaded on next check + */ + void clearLessonFinishUrlCache(); + + /** + * Checks whether given lesson finish URL is whitelisted. + */ + boolean isLessonFinishUrlValid(String lessonFinishUrl); } \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/integration/service/IntegrationService.java =================================================================== diff -u -r521b542aaaa17584d68940f23bfc880f1a2ce340 -r8c86b938e95d7e4081ddcba08a23012c813d936d --- lams_common/src/java/org/lamsfoundation/lams/integration/service/IntegrationService.java (.../IntegrationService.java) (revision 521b542aaaa17584d68940f23bfc880f1a2ce340) +++ lams_common/src/java/org/lamsfoundation/lams/integration/service/IntegrationService.java (.../IntegrationService.java) (revision 8c86b938e95d7e4081ddcba08a23012c813d936d) @@ -40,6 +40,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; import org.apache.commons.lang.StringUtils; import org.apache.http.HttpRequest; @@ -102,6 +104,8 @@ public class IntegrationService implements IIntegrationService { private static Logger log = Logger.getLogger(IntegrationService.class); + private Set integratedServersLessonFinishUrls = null; + private IUserManagementService service; private ILessonService lessonService; private ILamsCoreToolService toolService; @@ -1154,6 +1158,38 @@ } } + @Override + public void clearLessonFinishUrlCache() { + integratedServersLessonFinishUrls = null; + } + + @Override + @SuppressWarnings("unchecked") + public boolean isLessonFinishUrlValid(String lessonFinishUrl) { + if (StringUtils.isBlank(lessonFinishUrl)) { + return true; + } + if (integratedServersLessonFinishUrls == null) { + integratedServersLessonFinishUrls = ((List) service.findByProperty(ExtServer.class, "disabled", + false, true)).stream().filter(s -> StringUtils.isNotBlank(s.getLessonFinishUrl())) + .collect(Collectors.mapping(s -> { + String integratedServerLssonFinishUrl = s.getLessonFinishUrl(); + int lessonFinishUrlQuerySeparator = integratedServerLssonFinishUrl.indexOf("?"); + return lessonFinishUrlQuerySeparator < 0 ? integratedServerLssonFinishUrl + : integratedServerLssonFinishUrl.substring(0, lessonFinishUrlQuerySeparator); + }, Collectors.toSet())); + } + if (integratedServersLessonFinishUrls.isEmpty()) { + return false; + } + lessonFinishUrl = lessonFinishUrl.strip(); + int lessonFinishUrlQuerySeparator = lessonFinishUrl.indexOf("?"); + lessonFinishUrl = lessonFinishUrlQuerySeparator < 0 ? lessonFinishUrl + : lessonFinishUrl.substring(0, lessonFinishUrlQuerySeparator); + + return integratedServersLessonFinishUrls.contains(lessonFinishUrl); + } + // --------------------------------------------------------------------- // Inversion of Control Methods - Method injection // --------------------------------------------------------------------- Index: lams_learning/src/java/org/lamsfoundation/lams/learning/web/controller/LoadToolActivityController.java =================================================================== diff -u -r63b60926aa4fcd1084fffc798f120c16962f9d59 -r8c86b938e95d7e4081ddcba08a23012c813d936d --- lams_learning/src/java/org/lamsfoundation/lams/learning/web/controller/LoadToolActivityController.java (.../LoadToolActivityController.java) (revision 63b60926aa4fcd1084fffc798f120c16962f9d59) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/web/controller/LoadToolActivityController.java (.../LoadToolActivityController.java) (revision 8c86b938e95d7e4081ddcba08a23012c813d936d) @@ -26,8 +26,10 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.hibernate.AssertionFailure; +import org.lamsfoundation.lams.integration.service.IIntegrationService; import org.lamsfoundation.lams.learning.service.ILearnerFullService; import org.lamsfoundation.lams.learning.web.form.ActivityForm; import org.lamsfoundation.lams.learning.web.util.ActivityMapping; @@ -55,6 +57,8 @@ private ILearnerFullService learnerService; @Autowired private ActivityMapping activityMapping; + @Autowired + private IIntegrationService integrationService; public static final String PARAM_ACTIVITY_URL = "activityURL"; public static final String PARAM_IS_BRANCHING = "isBranching"; @@ -64,9 +68,20 @@ */ @RequestMapping("/LoadToolActivity") public String execute(@ModelAttribute ActivityForm form, HttpServletRequest request, HttpServletResponse response) { + long activityId = WebUtil.readLongParam(request, AttributeNames.PARAM_ACTIVITY_ID); + String activityFinishUrl = WebUtil.readStrParam(request, "activityFinishUrl", true); + if (StringUtils.isNotBlank(activityFinishUrl)) { + boolean activityFinishUrlValid = integrationService.isLessonFinishUrlValid(activityFinishUrl); + if (activityFinishUrlValid) { + request.setAttribute("activityFinishUrl", activityFinishUrl); + } else { + log.error("Illegal activityFinishUrl parameter: " + activityFinishUrl); + // do not finish processing so we do not break flow in some special cases + } + } + LearnerProgress learnerProgress = LearningWebUtil.getLearnerProgress(request, learnerService); - long activityId = WebUtil.readLongParam(request, AttributeNames.PARAM_ACTIVITY_ID); Activity activity = learnerService.getActivity(activityId); /* Index: lams_learning/web/loadToolActivity.jsp =================================================================== diff -u -r47dddf6db4afaba99d8f3f88fc50b16df9251a76 -r8c86b938e95d7e4081ddcba08a23012c813d936d --- lams_learning/web/loadToolActivity.jsp (.../loadToolActivity.jsp) (revision 47dddf6db4afaba99d8f3f88fc50b16df9251a76) +++ lams_learning/web/loadToolActivity.jsp (.../loadToolActivity.jsp) (revision 8c86b938e95d7e4081ddcba08a23012c813d936d) @@ -82,9 +82,9 @@ $(document).ready(function(){ // submit lesson total mark to the integrated server in case request comes from an integrated server - if (${not empty param.activityFinishUrl}) { + if (${not empty activityFinishUrl}) { $.ajax({ - url: '', + url: '${activityFinishUrl}', type: "POST", dataType: 'html', cache: false,