From 0ca11e0e2c83c7f59be91b866d39de57abf98758 Mon Sep 17 00:00:00 2001 From: srosse <stephane.rosse@frentix.com> Date: Mon, 3 Feb 2020 14:04:22 +0100 Subject: [PATCH] OO-4517: implements an exclusion list of WebDAV client per user agent --- .../commons/services/webdav/WebDAVModule.java | 19 ++- .../webdav/servlets/WebDAVDispatcherImpl.java | 19 ++- .../webdav/ui/WebDAVAdminController.java | 116 ++++++++++-------- .../ui/_i18n/LocalStrings_de.properties | 2 + .../ui/_i18n/LocalStrings_en.properties | 2 + .../resources/serviceconfig/olat.properties | 2 + 6 files changed, 104 insertions(+), 56 deletions(-) diff --git a/src/main/java/org/olat/core/commons/services/webdav/WebDAVModule.java b/src/main/java/org/olat/core/commons/services/webdav/WebDAVModule.java index a80d382a4df..8d206583153 100644 --- a/src/main/java/org/olat/core/commons/services/webdav/WebDAVModule.java +++ b/src/main/java/org/olat/core/commons/services/webdav/WebDAVModule.java @@ -70,7 +70,9 @@ public class WebDAVModule extends AbstractSpringModule implements ConfigOnOff { private boolean prependCourseReferenceToTitle; @Value("${webdav.basic.authentication.black.list}") private String basicAuthenticationBlackList; - + @Value("${webdav.user.agent.black.list}") + private String userAgentBlackList; + @Value("${webdav.learners.bookmarks.enabled:true}") private boolean enableLearnersBookmarksCourse; /** @@ -233,6 +235,21 @@ public class WebDAVModule extends AbstractSpringModule implements ConfigOnOff { this.basicAuthenticationBlackList = basicAuthenticationBlackList; } + public String[] getUserAgentBlackListArray() { + if(StringHelper.containsNonWhitespace(userAgentBlackList)) { + return userAgentBlackList.split("[,]"); + } + return new String[0]; + } + + public String getUserAgentBlackList() { + return userAgentBlackList; + } + + public void setUserAgentBlackList(String userAgentBlackList) { + this.userAgentBlackList = userAgentBlackList; + } + /** * Return an unmodifiable map * @return diff --git a/src/main/java/org/olat/core/commons/services/webdav/servlets/WebDAVDispatcherImpl.java b/src/main/java/org/olat/core/commons/services/webdav/servlets/WebDAVDispatcherImpl.java index 03a7820cee2..cad3154c7b2 100644 --- a/src/main/java/org/olat/core/commons/services/webdav/servlets/WebDAVDispatcherImpl.java +++ b/src/main/java/org/olat/core/commons/services/webdav/servlets/WebDAVDispatcherImpl.java @@ -54,9 +54,11 @@ import org.olat.core.commons.services.webdav.WebDAVDispatcher; import org.olat.core.commons.services.webdav.WebDAVManager; import org.olat.core.commons.services.webdav.WebDAVModule; import org.olat.core.dispatcher.Dispatcher; +import org.olat.core.gui.media.ServletUtil; import org.olat.core.helpers.Settings; import org.apache.logging.log4j.Logger; import org.olat.core.logging.Tracing; +import org.olat.core.util.StringHelper; import org.olat.core.util.UserSession; import org.olat.core.util.vfs.QuotaExceededException; import org.olat.core.util.vfs.VFSItem; @@ -273,7 +275,7 @@ public class WebDAVDispatcherImpl throws ServletException, IOException { if (webDAVManager == null) { resp.setStatus(WebdavStatus.SC_INTERNAL_SERVER_ERROR); - } else if(webDAVModule == null || !webDAVModule.isEnabled()) { + } else if(webDAVModule == null || !webDAVModule.isEnabled() || isUserAgentExcluded(req)) { resp.setStatus(WebdavStatus.SC_FORBIDDEN); } else if (webDAVManager.handleAuthentication(req, resp)) { webdavService(req, resp); @@ -281,6 +283,21 @@ public class WebDAVDispatcherImpl //the method handleAuthentication will send the challenges for authentication } } + + private boolean isUserAgentExcluded(HttpServletRequest req) { + String userAgent = ServletUtil.getUserAgent(req); + if(!StringHelper.containsNonWhitespace(userAgent)) { + userAgent = ""; + } + String[] blackList = webDAVModule.getUserAgentBlackListArray(); + for(String blackListedAgent:blackList) { + if((blackListedAgent.length() < 2 && userAgent.equalsIgnoreCase(blackListedAgent)) + || (blackListedAgent.length() >= 2 && userAgent.contains(blackListedAgent))) { + return true; + } + } + return false; + } /** * Handles the special WebDAV methods. diff --git a/src/main/java/org/olat/core/commons/services/webdav/ui/WebDAVAdminController.java b/src/main/java/org/olat/core/commons/services/webdav/ui/WebDAVAdminController.java index 457f814f107..37ad1d594ce 100644 --- a/src/main/java/org/olat/core/commons/services/webdav/ui/WebDAVAdminController.java +++ b/src/main/java/org/olat/core/commons/services/webdav/ui/WebDAVAdminController.java @@ -19,16 +19,20 @@ */ package org.olat.core.commons.services.webdav.ui; -import org.olat.core.CoreSpringFactory; import org.olat.core.commons.services.webdav.WebDAVModule; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; +import org.olat.core.gui.components.form.flexible.elements.SpacerElement; +import org.olat.core.gui.components.form.flexible.elements.TextElement; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormEvent; +import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; +import org.olat.core.util.StringHelper; +import org.springframework.beans.factory.annotation.Autowired; /** * @@ -39,6 +43,8 @@ public class WebDAVAdminController extends FormBasicController { private static final String[] onKeys = new String[]{"xx"}; + private TextElement excludeUserAgentsClientsEl; + private MultipleSelectionElement excludeClientsEl; private MultipleSelectionElement enableModuleEl; private MultipleSelectionElement enableLinkEl; private MultipleSelectionElement enableDigestEl; @@ -48,13 +54,17 @@ public class WebDAVAdminController extends FormBasicController { private MultipleSelectionElement learnersAsParticipantEl; private MultipleSelectionElement learnersBookmarkEl; private MultipleSelectionElement prependReferenceEl; + private SpacerElement spacer1; + private SpacerElement spacer2; - private final WebDAVModule webDAVModule; + + @Autowired + private WebDAVModule webDAVModule; public WebDAVAdminController(UserRequest ureq, WindowControl wControl) { super(ureq, wControl); - webDAVModule = CoreSpringFactory.getImpl(WebDAVModule.class); initForm(ureq); + updateEnabledDisabled(); } @Override @@ -64,56 +74,51 @@ public class WebDAVAdminController extends FormBasicController { setFormDescription("admin.webdav.description"); setFormContextHelp("WebDAV"); - boolean enabled = webDAVModule.isEnabled(); String[] values = new String[] { getTranslator().translate("webdav.on") }; enableModuleEl = uifactory.addCheckboxesHorizontal("webdavModule", "webdav.module", formLayout, onKeys, values); - enableModuleEl.select("xx", enabled); enableModuleEl.addActionListener(FormEvent.ONCHANGE); + enableModuleEl.select("xx", enabled); enableLinkEl = uifactory.addCheckboxesHorizontal("webdavLink", "webdav.link", formLayout, onKeys, values); enableLinkEl.select("xx", webDAVModule.isLinkEnabled()); - enableLinkEl.addActionListener(FormEvent.ONCHANGE); - enableLinkEl.setEnabled(enabled); enableDigestEl = uifactory.addCheckboxesHorizontal("webdavDigest", "webdav.digest", formLayout, onKeys, values); enableDigestEl.select("xx", webDAVModule.isDigestAuthenticationEnabled()); - enableDigestEl.addActionListener(FormEvent.ONCHANGE); - enableDigestEl.setEnabled(enabled); + + String excludedUserAgents = webDAVModule.getUserAgentBlackList(); + excludeClientsEl = uifactory.addCheckboxesHorizontal("webdavExclusion", "webdav.client.exclusion", formLayout, onKeys, values); + excludeClientsEl.select("xx", StringHelper.containsNonWhitespace(excludedUserAgents)); + excludeClientsEl.addActionListener(FormEvent.ONCHANGE); + + excludeUserAgentsClientsEl = uifactory.addTextElement("webdav.user.agent.exclusion", 4096, excludedUserAgents, formLayout); + excludeUserAgentsClientsEl.setVisible(excludeClientsEl.isAtLeastSelected(1)); - uifactory.addSpacerElement("spacer1", formLayout, false); + spacer1 = uifactory.addSpacerElement("spacer1", formLayout, false); enableTermsFoldersEl = uifactory.addCheckboxesHorizontal("webdavTermsFolders", "webdav.termsfolders", formLayout, onKeys, values); enableTermsFoldersEl.select("xx", webDAVModule.isTermsFoldersEnabled()); - enableTermsFoldersEl.addActionListener(FormEvent.ONCHANGE); - enableTermsFoldersEl.setEnabled(enabled); enableCurriculumElementFoldersEl = uifactory.addCheckboxesHorizontal("webdavCurriculumsElementsFolders", "webdav.curriculumelementsfolders", formLayout, onKeys, values); enableCurriculumElementFoldersEl.select("xx", webDAVModule.isCurriculumElementFoldersEnabled()); - enableCurriculumElementFoldersEl.addActionListener(FormEvent.ONCHANGE); - enableCurriculumElementFoldersEl.setEnabled(enabled); enableManagedFoldersEl = uifactory.addCheckboxesHorizontal("webdavManagedFolders", "webdav.managedfolders", formLayout, onKeys, values); enableManagedFoldersEl.select("xx", webDAVModule.isManagedFoldersEnabled()); - enableManagedFoldersEl.addActionListener(FormEvent.ONCHANGE); - enableManagedFoldersEl.setEnabled(enabled); prependReferenceEl = uifactory.addCheckboxesHorizontal("webdavPrepend", "webdav.prepend.reference", formLayout, onKeys, values); prependReferenceEl.select("xx", webDAVModule.isPrependCourseReferenceToTitle()); - prependReferenceEl.addActionListener(FormEvent.ONCHANGE); - prependReferenceEl.setEnabled(enabled); - - uifactory.addSpacerElement("spacer2", formLayout, false); + + spacer2 = uifactory.addSpacerElement("spacer2", formLayout, false); learnersAsParticipantEl = uifactory.addCheckboxesHorizontal("learnersParticipants", "webdav.for.learners.participants", formLayout, onKeys, values); learnersAsParticipantEl.select("xx", webDAVModule.isEnableLearnersParticipatingCourses()); - learnersAsParticipantEl.addActionListener(FormEvent.ONCHANGE); - learnersAsParticipantEl.setEnabled(enabled); learnersBookmarkEl = uifactory.addCheckboxesHorizontal("learnerBookmarks", "webdav.for.learners.bookmarks", formLayout, onKeys, values); learnersBookmarkEl.select("xx", webDAVModule.isEnableLearnersBookmarksCourse()); - learnersBookmarkEl.addActionListener(FormEvent.ONCHANGE); - learnersBookmarkEl.setEnabled(enabled); + + FormLayoutContainer buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); + formLayout.add(buttonsCont); + uifactory.addFormSubmitButton("save", buttonsCont); } @Override @@ -126,41 +131,44 @@ public class WebDAVAdminController extends FormBasicController { if(source == enableModuleEl) { boolean enabled = enableModuleEl.isAtLeastSelected(1); webDAVModule.setEnabled(enabled); - enableLinkEl.setEnabled(enabled); - enableDigestEl.setEnabled(enabled); - enableTermsFoldersEl.setEnabled(enabled); - learnersAsParticipantEl.setEnabled(enabled); - learnersBookmarkEl.setEnabled(enabled); - } else if(source == enableLinkEl) { - boolean enabled = enableLinkEl.isAtLeastSelected(1); - webDAVModule.setLinkEnabled(enabled); - } else if(source == enableDigestEl) { - boolean enabled = enableDigestEl.isAtLeastSelected(1); - webDAVModule.setDigestAuthenticationEnabled(enabled); - } else if(source == enableTermsFoldersEl) { - boolean enabled = enableTermsFoldersEl.isAtLeastSelected(1); - webDAVModule.setTermsFoldersEnabled(enabled); - } else if(source == enableCurriculumElementFoldersEl) { - boolean enabled = enableCurriculumElementFoldersEl.isAtLeastSelected(1); - webDAVModule.setCurriculumElementFoldersEnabled(enabled); - } else if(source == learnersAsParticipantEl) { - boolean enabled = learnersAsParticipantEl.isAtLeastSelected(1); - webDAVModule.setEnableLearnersParticipatingCourses(enabled); - } else if(source == learnersBookmarkEl) { - boolean enabled = learnersBookmarkEl.isAtLeastSelected(1); - webDAVModule.setEnableLearnersBookmarksCourse(enabled); - } else if(source == prependReferenceEl) { - boolean enabled = prependReferenceEl.isAtLeastSelected(1); - webDAVModule.setPrependCourseReferenceToTitle(enabled); - } else if(source == enableManagedFoldersEl) { - boolean enabled = enableManagedFoldersEl.isAtLeastSelected(1); - webDAVModule.setManagedFoldersEnabled(enabled); + updateEnabledDisabled(); + } else if(source == excludeClientsEl) { + excludeUserAgentsClientsEl.setVisible(excludeClientsEl.isAtLeastSelected(1)); } super.formInnerEvent(ureq, source, event); } + + private void updateEnabledDisabled() { + boolean enabled = enableModuleEl.isAtLeastSelected(1); + + enableLinkEl.setVisible(enabled); + enableDigestEl.setVisible(enabled); + enableTermsFoldersEl.setVisible(enabled); + learnersAsParticipantEl.setVisible(enabled); + learnersBookmarkEl.setVisible(enabled); + enableCurriculumElementFoldersEl.setVisible(enabled); + enableManagedFoldersEl.setVisible(enabled); + prependReferenceEl.setVisible(enabled); + excludeClientsEl.setVisible(enabled); + excludeUserAgentsClientsEl.setVisible(enabled && excludeClientsEl.isAtLeastSelected(1)); + spacer1.setVisible(enabled); + spacer2.setVisible(enabled); + } @Override protected void formOK(UserRequest ureq) { - // + webDAVModule.setLinkEnabled(enableLinkEl.isAtLeastSelected(1)); + webDAVModule.setDigestAuthenticationEnabled(enableDigestEl.isAtLeastSelected(1)); + webDAVModule.setTermsFoldersEnabled(enableTermsFoldersEl.isAtLeastSelected(1)); + webDAVModule.setCurriculumElementFoldersEnabled(enableCurriculumElementFoldersEl.isAtLeastSelected(1)); + webDAVModule.setEnableLearnersParticipatingCourses(learnersAsParticipantEl.isAtLeastSelected(1)); + webDAVModule.setEnableLearnersBookmarksCourse(learnersBookmarkEl.isAtLeastSelected(1)); + webDAVModule.setPrependCourseReferenceToTitle(prependReferenceEl.isAtLeastSelected(1)); + webDAVModule.setManagedFoldersEnabled(enableManagedFoldersEl.isAtLeastSelected(1)); + if(excludeClientsEl.isAtLeastSelected(1)) { + webDAVModule.setUserAgentBlackList(excludeUserAgentsClientsEl.getValue()); + } else { + webDAVModule.setUserAgentBlackList(null); + } } } diff --git a/src/main/java/org/olat/core/commons/services/webdav/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/core/commons/services/webdav/ui/_i18n/LocalStrings_de.properties index e081425ac73..97cd86527ad 100644 --- a/src/main/java/org/olat/core/commons/services/webdav/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/core/commons/services/webdav/ui/_i18n/LocalStrings_de.properties @@ -3,6 +3,7 @@ admin.menu.title=WebDAV admin.menu.title.alt=WebDAV Zugang admin.webdav.description=Mit Hilfe von WebDAV k\u00F6nnen Sie OpenOlat Ordner auf Ihrem lokalen Desktop wie lokale Ordner anzeigen und verwenden. Konfigurieren Sie ob diese Funktion allen Benutzern Systemweit zur Verf\u00FCgung stehen soll. Bitte lesen sie die Kontexthilfe. core.webdav=WebDAV +webdav.client.exclusion=WebDAV Client Verbot webdav.curriculumelementsfolders=Kurse nach Curriculumelementen gruppieren webdav.digest=Digest Authentication bei HTTP Zugang verwenden webdav.for.learners.bookmarks=Zugriff f\u00FCr Studenten / Betreuer Favoriten @@ -13,3 +14,4 @@ webdav.module=WebDAV Zugang webdav.on=ein webdav.prepend.reference=Kennzeichen dem Titel voranstellen webdav.termsfolders=Kurse nach Semesterdaten gruppieren +webdav.user.agent.exclusion=Liste von User-Agent (Komma als Trenzeichen) diff --git a/src/main/java/org/olat/core/commons/services/webdav/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/core/commons/services/webdav/ui/_i18n/LocalStrings_en.properties index a4a726fe021..28fe7f470a7 100644 --- a/src/main/java/org/olat/core/commons/services/webdav/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/core/commons/services/webdav/ui/_i18n/LocalStrings_en.properties @@ -3,6 +3,7 @@ admin.menu.title=WebDAV admin.menu.title.alt=WebDAV access admin.webdav.description=Using WebDAV you can mount and use OpenOlat folders on your local desktop as if they were local folders. Enable this feature to make it accessable to all users of your platform. Please read the context help. core.webdav=WebDAV +webdav.client.exclusion=WebDAV Client exclusion webdav.curriculumelementsfolders=Group courses by curriculum elements webdav.digest=Digest Authentication for HTTP access webdav.for.learners.bookmarks=Enable access for courses that users marked as favorite @@ -13,3 +14,4 @@ webdav.module=WebDAV access webdav.on=enabled webdav.prepend.reference=Prepend external course reference to title webdav.termsfolders=Group courses by semester terms +webdav.user.agent.exclusion=List of User-Agents (comma as separator) diff --git a/src/main/resources/serviceconfig/olat.properties b/src/main/resources/serviceconfig/olat.properties index 7b34f89ff55..7a27ea40234 100644 --- a/src/main/resources/serviceconfig/olat.properties +++ b/src/main/resources/serviceconfig/olat.properties @@ -563,6 +563,8 @@ auth.digest.enabled=true webdav.termsfolders.enabled=true # User agents for which the basic authentication should never be proposed webdav.basic.authentication.black.list=Microsoft Office Excel,Microsoft Excel,Microsoft-WebDAV-MiniRedir +# User agents which don't play nice +webdav.user.agent.black.list=- ######################################################################## # Image and PDF scale/thumbnail options -- GitLab