/** * OLAT - Online Learning and Training<br> * http://www.olat.org * <p> * Licensed under the Apache License, Version 2.0 (the "License"); <br> * you may not use this file except in compliance with the License.<br> * You may obtain a copy of the License at * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * Unless required by applicable law or agreed to in writing,<br> * software distributed under the License is distributed on an "AS IS" BASIS, <br> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> * See the License for the specific language governing permissions and <br> * limitations under the License. * <p> * Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> * University of Zurich, Switzerland. * <hr> * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * This file has been modified by the OpenOLAT community. Changes are licensed * under the Apache 2.0 license as the original file. */ package org.olat.core.commons.services.webdav.manager; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Map; import java.util.StringTokenizer; import java.util.UUID; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.olat.admin.user.delete.service.UserDeletionManager; import org.olat.basesecurity.BaseSecurityManager; import org.olat.basesecurity.BaseSecurityModule; import org.olat.core.commons.services.webdav.WebDAVManager; import org.olat.core.commons.services.webdav.WebDAVModule; import org.olat.core.commons.services.webdav.WebDAVProvider; import org.olat.core.commons.services.webdav.servlets.WebResourceRoot; import org.olat.core.helpers.Settings; import org.olat.core.id.Identity; import org.olat.core.id.IdentityEnvironment; import org.olat.core.id.Roles; import org.olat.core.id.User; import org.olat.core.id.UserConstants; import org.olat.core.util.SessionInfo; import org.olat.core.util.StringHelper; import org.olat.core.util.UserSession; import org.olat.core.util.cache.CacheWrapper; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.session.UserSessionManager; import org.olat.core.util.vfs.MergeSource; import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VirtualContainer; import org.olat.core.util.vfs.callbacks.ReadOnlyCallback; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * Initial Date: 16.04.2003 * * @author Mike Stock * @author guido * * Comment: * */ @Service("webDAVManager") public class WebDAVManagerImpl implements WebDAVManager, InitializingBean { private static boolean enabled = true; public static final String BASIC_AUTH_REALM = "OLAT WebDAV Access"; private CoordinatorManager coordinatorManager; private CacheWrapper<CacheKey,UserSession> timedSessionCache; @Autowired private UserSessionManager sessionManager; @Autowired private WebDAVAuthManager webDAVAuthManager; @Autowired private WebDAVModule webdavModule; @Autowired public WebDAVManagerImpl(CoordinatorManager coordinatorManager) { this.coordinatorManager = coordinatorManager; } @Override public void afterPropertiesSet() throws Exception { timedSessionCache = coordinatorManager.getCoordinator().getCacher().getCache(WebDAVManager.class.getSimpleName(), "webdav"); } @Override public WebResourceRoot getWebDAVRoot(HttpServletRequest req) { UserSession usess = getUserSession(req); if (usess == null || usess.getIdentity() == null) { return createEmptyRoot(usess); } usess.getSessionInfo().setLastClickTime(); VFSResourceRoot fdc = (VFSResourceRoot)usess.getEntry("_DIRCTX"); if (fdc != null) { return fdc; } IdentityEnvironment identityEnv = usess.getIdentityEnvironment(); VFSContainer webdavContainer = getMountableRoot(identityEnv); //create the / folder VirtualContainer rootContainer = new VirtualContainer(""); rootContainer.addItem(webdavContainer); rootContainer.setLocalSecurityCallback(new ReadOnlyCallback()); fdc = new VFSResourceRoot(identityEnv.getIdentity(), rootContainer); usess.putEntry("_DIRCTX", fdc); return fdc; } /** * Returns a mountable root containing all entries which will be exposed to the webdav mount. * @return */ private VFSContainer getMountableRoot(IdentityEnvironment identityEnv) { MergeSource vfsRoot = new MergeSource(null, "webdav"); for (Map.Entry<String, WebDAVProvider> entry : webdavModule.getWebDAVProviders().entrySet()) { WebDAVProvider provider = entry.getValue(); if(provider.hasAccess(identityEnv)) { vfsRoot.addContainer(new WebDAVProviderNamedContainer(identityEnv, provider)); } } return vfsRoot; } private WebResourceRoot createEmptyRoot(UserSession usess) { //create the / folder VirtualContainer rootContainer = new VirtualContainer(""); rootContainer.setLocalSecurityCallback(new ReadOnlyCallback()); return new VFSResourceRoot(usess.getIdentity(), rootContainer); } /** * @see org.olat.core.commons.services.webdav.WebDAVManager#handleAuthentication(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override public boolean handleAuthentication(HttpServletRequest req, HttpServletResponse resp) { //manger not started if(timedSessionCache == null) { return false; } UserSession usess = sessionManager.getUserSession(req); if(usess != null && usess.isAuthenticated()) { req.setAttribute(REQUEST_USERSESSION_KEY, usess); return true; } usess = doAuthentication(req, resp); if (usess == null) { return false; } // register usersession in REQUEST, not session !! // see SecureWebDAVServlet.setAuthor() and checkQuota() req.setAttribute(REQUEST_USERSESSION_KEY, usess); return true; } /** * @see org.olat.core.commons.services.webdav.WebDAVManager#getUserSession(javax.servlet.http.HttpServletRequest) */ @Override public UserSession getUserSession(HttpServletRequest req) { return (UserSession)req.getAttribute(REQUEST_USERSESSION_KEY); } private UserSession doAuthentication(HttpServletRequest request, HttpServletResponse response) { // Get the Authorization header, if one was supplied String authHeader = request.getHeader("Authorization"); if (authHeader != null) { // fetch user session from a previous authentication String cacheKey = null; UserSession usess = null; String remoteAddr = request.getRemoteAddr(); StringTokenizer st = new StringTokenizer(authHeader); if (st.hasMoreTokens()) { String basic = st.nextToken(); // We only handle HTTP Basic authentication if (basic.equalsIgnoreCase("Basic")) { cacheKey = authHeader; usess = timedSessionCache.get(new CacheKey(remoteAddr, authHeader)); if (usess == null || !usess.isAuthenticated()) { String credentials = st.nextToken(); usess = handleBasicAuthentication(credentials, request); } } else if (basic.equalsIgnoreCase("Digest")) { DigestAuthentication digestAuth = DigestAuthentication.parse(authHeader); cacheKey = digestAuth.getUsername(); usess = timedSessionCache.get(new CacheKey(remoteAddr, digestAuth.getUsername())); if (usess == null || !usess.isAuthenticated()) { usess = handleDigestAuthentication(digestAuth, request); } } } if(usess != null && cacheKey != null) { timedSessionCache.put(new CacheKey(remoteAddr, cacheKey), usess); return usess; } } // If the user was not validated or the browser does not know about the realm yet, fail with a // 401 status code (UNAUTHORIZED) and // pass back a WWW-Authenticate header for // this servlet. // // Note that this is the normal situation the // first time you access the page. The client // web browser will prompt for userID and password // and cache them so that it doesn't have to // prompt you again. if(request.isSecure() || Settings.isJUnitTest()) { response.addHeader("WWW-Authenticate", "Basic realm=\"" + BASIC_AUTH_REALM + "\""); } if(webdavModule.isDigestAuthenticationEnabled()) { String nonce = UUID.randomUUID().toString().replace("-", ""); response.addHeader("WWW-Authenticate", "Digest realm=\"" + BASIC_AUTH_REALM + "\", qop=\"auth\", nonce=\"" + nonce + "\""); } response.setStatus(401); return null; } protected UserSession handleDigestAuthentication(DigestAuthentication digestAuth, HttpServletRequest request) { Identity identity = webDAVAuthManager.digestAuthentication(request.getMethod(), digestAuth); if(identity != null) { return afterAuthorization(identity, request); } return null; } protected UserSession handleBasicAuthentication(String credentials, HttpServletRequest request) { // This example uses sun.misc.* classes. // You will need to provide your own // if you are not comfortable with that. String userPass = StringHelper.decodeBase64(credentials); // The decoded string is in the form // "userID:password". int p = userPass.indexOf(":"); if (p != -1) { String userID = userPass.substring(0, p); String password = userPass.substring(p + 1); // Validate user ID and password // and set valid true if valid. // In this example, we simply check // that neither field is blank Identity identity = webDAVAuthManager.authenticate(null, userID, password); if (identity != null) { return afterAuthorization(identity, request); } } return null; } private UserSession afterAuthorization(Identity identity, HttpServletRequest request) { UserSession usess = sessionManager.getUserSession(request); synchronized(usess) { //double check to prevent severals concurrent login if(usess.isAuthenticated()) { return usess; } sessionManager.signOffAndClear(usess); usess.setIdentity(identity); UserDeletionManager.getInstance().setIdentityAsActiv(identity); // set the roles (admin, author, guest) Roles roles = BaseSecurityManager.getInstance().getRoles(identity); usess.setRoles(roles); // set session info SessionInfo sinfo = new SessionInfo(identity.getKey(), identity.getName(), request.getSession()); User usr = identity.getUser(); sinfo.setFirstname(usr.getProperty(UserConstants.FIRSTNAME, null)); sinfo.setLastname(usr.getProperty(UserConstants.LASTNAME, null)); String remoteAddr = request.getRemoteAddr(); sinfo.setFromIP(remoteAddr); sinfo.setFromFQN(remoteAddr); try { InetAddress[] iaddr = InetAddress.getAllByName(request.getRemoteAddr()); if (iaddr.length > 0) sinfo.setFromFQN(iaddr[0].getHostName()); } catch (UnknownHostException e) { // ok, already set IP as FQDN } sinfo.setAuthProvider(BaseSecurityModule.getDefaultAuthProviderIdentifier()); sinfo.setUserAgent(request.getHeader("User-Agent")); sinfo.setSecure(request.isSecure()); sinfo.setWebDAV(true); sinfo.setWebModeFromUreq(null); // set session info for this session usess.setSessionInfo(sinfo); // sessionManager.signOn(usess); return usess; } } /** * @see org.olat.core.commons.services.webdav.WebDAVManager#isEnabled() */ public boolean isEnabled() { return enabled; } /** * Spring setter method to enable/disable the webDAV module * @param enabled */ public void setEnabled(boolean enabled) { WebDAVManagerImpl.enabled = enabled; } }