diff --git a/pom.xml b/pom.xml index 4bd5228..8702caf 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.github.zxbu webdav-aliyundriver - 2.1.0 + 2.2.0 webdav Demo project for Spring Boot diff --git a/src/main/java/com/github/zxbu/webdavteambition/WebdavTeambitionApplication.java b/src/main/java/com/github/zxbu/webdavteambition/WebdavTeambitionApplication.java index 758ccee..0f8a0cd 100644 --- a/src/main/java/com/github/zxbu/webdavteambition/WebdavTeambitionApplication.java +++ b/src/main/java/com/github/zxbu/webdavteambition/WebdavTeambitionApplication.java @@ -40,4 +40,5 @@ public class WebdavTeambitionApplication { return filterRegistrationBean; } + } diff --git a/src/main/java/com/github/zxbu/webdavteambition/config/AliYunDriveProperties.java b/src/main/java/com/github/zxbu/webdavteambition/config/AliYunDriveProperties.java index 311e0bd..410a1a8 100644 --- a/src/main/java/com/github/zxbu/webdavteambition/config/AliYunDriveProperties.java +++ b/src/main/java/com/github/zxbu/webdavteambition/config/AliYunDriveProperties.java @@ -10,6 +10,7 @@ public class AliYunDriveProperties { private String workDir = "/etc/aliyun-driver/"; private String agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_0_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"; private String driveId; + private Auth auth; public String getUrl() { return url; @@ -58,4 +59,42 @@ public class AliYunDriveProperties { public void setDriveId(String driveId) { this.driveId = driveId; } + + public Auth getAuth() { + return auth; + } + + public void setAuth(Auth auth) { + this.auth = auth; + } + + public static class Auth { + private Boolean enable = true; + private String userName; + private String password; + + public Boolean getEnable() { + return enable; + } + + public void setEnable(Boolean enable) { + this.enable = enable; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + } } diff --git a/src/main/java/com/github/zxbu/webdavteambition/config/EmbeddedTomcatConfig.java b/src/main/java/com/github/zxbu/webdavteambition/config/EmbeddedTomcatConfig.java new file mode 100644 index 0000000..56adee2 --- /dev/null +++ b/src/main/java/com/github/zxbu/webdavteambition/config/EmbeddedTomcatConfig.java @@ -0,0 +1,70 @@ +package com.github.zxbu.webdavteambition.config; + +import org.apache.catalina.authenticator.DigestAuthenticator; +import org.apache.catalina.realm.GenericPrincipal; +import org.apache.catalina.realm.MessageDigestCredentialHandler; +import org.apache.catalina.realm.RealmBase; +import org.apache.tomcat.util.descriptor.web.SecurityCollection; +import org.apache.tomcat.util.descriptor.web.SecurityConstraint; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; +import org.springframework.boot.web.server.WebServerFactoryCustomizer; +import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; +import org.springframework.core.Ordered; +import org.springframework.stereotype.Component; + +import java.security.Principal; +import java.util.Collections; + +@Component +@ConditionalOnProperty(prefix = "aliyundrive.auth", name = "enable", matchIfMissing = true) +public class EmbeddedTomcatConfig implements WebServerFactoryCustomizer, Ordered { + + @Autowired + private AliYunDriveProperties aliYunDriveProperties; + + @Override + public void customize(ConfigurableServletWebServerFactory factory) { + + TomcatServletWebServerFactory tomcatServletWebServerFactory = (TomcatServletWebServerFactory) factory; + + tomcatServletWebServerFactory.addContextCustomizers(context -> { + + RealmBase realm = new RealmBase() { + @Override + protected String getPassword(String username) { + if (aliYunDriveProperties.getAuth().getUserName().equals(username)) { + return aliYunDriveProperties.getAuth().getPassword(); + } + return ""; + } + + @Override + protected Principal getPrincipal(String username) { + return new GenericPrincipal(username, aliYunDriveProperties.getAuth().getPassword(), Collections.singletonList("**")); + } + }; + + MessageDigestCredentialHandler credentialHandler = new MessageDigestCredentialHandler(); + realm.setCredentialHandler(credentialHandler); + context.setRealm(realm); + + DigestAuthenticator digestAuthenticator = new DigestAuthenticator(); + SecurityConstraint securityConstraint = new SecurityConstraint(); + securityConstraint.setAuthConstraint(true); + securityConstraint.addAuthRole("**"); + SecurityCollection collection = new SecurityCollection(); + collection.addPattern("/*"); + securityConstraint.addCollection(collection); + context.addConstraint(securityConstraint); + context.getPipeline().addValve(digestAuthenticator); + }); + + } + + @Override + public int getOrder() { + return Ordered.LOWEST_PRECEDENCE; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/zxbu/webdavteambition/filter/ErrorFilter.java b/src/main/java/com/github/zxbu/webdavteambition/filter/ErrorFilter.java index 9ed6132..ef9259a 100644 --- a/src/main/java/com/github/zxbu/webdavteambition/filter/ErrorFilter.java +++ b/src/main/java/com/github/zxbu/webdavteambition/filter/ErrorFilter.java @@ -1,5 +1,8 @@ package com.github.zxbu.webdavteambition.filter; +import net.sf.webdav.WebdavStatus; +import org.apache.tomcat.util.http.fileupload.IOUtils; +import org.springframework.core.io.ClassPathResource; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; @@ -9,10 +12,24 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; import java.io.IOException; +import java.io.InputStream; import java.io.PrintWriter; +import java.nio.charset.StandardCharsets; public class ErrorFilter extends OncePerRequestFilter { + private static final String errorPage = readErrorPage(); + private static String readErrorPage() { + try { + ClassPathResource classPathResource = new ClassPathResource("error.xml"); + InputStream inputStream = classPathResource.getInputStream(); + byte[] buffer = new byte[(int) classPathResource.contentLength()]; + IOUtils.readFully(inputStream, buffer); + return new String(buffer, StandardCharsets.UTF_8); + } catch (IOException e) { + return ""; + } + } @Override protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { @@ -21,10 +38,19 @@ public class ErrorFilter extends OncePerRequestFilter { try { filterChain.doFilter(httpServletRequest, wrapperResponse); if (wrapperResponse.hasErrorToSend()) { - httpServletResponse.setStatus(wrapperResponse.getStatus()); - if (wrapperResponse.getMessage() != null) { - httpServletResponse.getWriter().write(wrapperResponse.getMessage()); + int status = wrapperResponse.getStatus(); + if (status == 401) { +// httpServletResponse.addHeader("WWW-Authenticate", "Digest realm=\"iptel.org\", qop=\"auth,auth-int\",\n" + +// "nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\", opaque=\"\", algorithm=MD5"); +// } + httpServletResponse.setStatus(status); + String message = wrapperResponse.getMessage(); + if (message == null) { + message = WebdavStatus.getStatusText(status); + } + String errorXml = errorPage.replace("{{code}}", status + "").replace("{{message}}", message); + httpServletResponse.getWriter().write(errorXml); } httpServletResponse.flushBuffer(); } catch (Throwable t) { diff --git a/src/main/java/com/github/zxbu/webdavteambition/store/AliYunDriverFileSystemStore.java b/src/main/java/com/github/zxbu/webdavteambition/store/AliYunDriverFileSystemStore.java index 6d8c113..ed3f5a2 100644 --- a/src/main/java/com/github/zxbu/webdavteambition/store/AliYunDriverFileSystemStore.java +++ b/src/main/java/com/github/zxbu/webdavteambition/store/AliYunDriverFileSystemStore.java @@ -3,10 +3,8 @@ package com.github.zxbu.webdavteambition.store; import com.github.zxbu.webdavteambition.model.FileType; import com.github.zxbu.webdavteambition.model.PathInfo; import com.github.zxbu.webdavteambition.model.result.TFile; -import net.sf.webdav.ITransaction; -import net.sf.webdav.IWebdavStore; -import net.sf.webdav.StoredObject; -import net.sf.webdav.Transaction; +import net.sf.webdav.*; +import net.sf.webdav.exceptions.UnauthenticatedException; import net.sf.webdav.exceptions.WebdavException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -17,6 +15,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.security.Principal; +import java.util.Enumeration; import java.util.Set; public class AliYunDriverFileSystemStore implements IWebdavStore { @@ -43,7 +42,6 @@ public class AliYunDriverFileSystemStore implements IWebdavStore { @Override public ITransaction begin(Principal principal, HttpServletRequest req, HttpServletResponse resp) { LOGGER.debug("begin"); - aliYunDriverClientService.clearCache(); return new Transaction(principal, req, resp); } @@ -51,9 +49,9 @@ public class AliYunDriverFileSystemStore implements IWebdavStore { @Override public void checkAuthentication(ITransaction transaction) { LOGGER.debug("checkAuthentication"); -// if (transaction.getPrincipal() == null) { -// throw new UnauthenticatedException(WebdavStatus.SC_UNAUTHORIZED); -// } + if (transaction.getPrincipal() == null) { + throw new UnauthenticatedException(WebdavStatus.SC_UNAUTHORIZED); + } } @Override diff --git a/src/main/java/net/sf/webdav/WebDavServletBean.java b/src/main/java/net/sf/webdav/WebDavServletBean.java index dacfaaa..a92ed75 100644 --- a/src/main/java/net/sf/webdav/WebDavServletBean.java +++ b/src/main/java/net/sf/webdav/WebDavServletBean.java @@ -109,6 +109,10 @@ public class WebDavServletBean extends HttpServlet { if (LOG.isTraceEnabled()) debugRequest(methodName, req); + if (returnError(req, resp)) { + return; + } + try { Principal userPrincipal = getUserPrincipal(req); transaction = _store.begin(userPrincipal, req, resp); @@ -171,15 +175,31 @@ public class WebDavServletBean extends HttpServlet { } /** - * Method that permit to customize the way + * Method that permit to customize the way * user information are extracted from the request, default use JAAS * @param req * @return */ protected Principal getUserPrincipal(HttpServletRequest req) { - return req.getUserPrincipal(); + return req.getUserPrincipal(); } - + + private boolean returnError(HttpServletRequest req, HttpServletResponse resp) throws IOException { + if (req.getRequestURI().equals("/error")) { + Object codeObject = req.getAttribute("javax.servlet.error.status_code"); + if (codeObject != null) { + int code = Integer.parseInt(codeObject.toString()); + if (code > 400) { + resp.setStatus(code); + resp.flushBuffer(); + return true; + } + } + } + return false; + } + + private void debugRequest(String methodName, HttpServletRequest req) { LOG.trace("-----------"); LOG.trace("WebdavServlet\n request: methodName = " + methodName); diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index cf6f6e3..ccfd3fe 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,3 +1,7 @@ #logging.level.net.sf.webdav=trace logging.file.path=/var/log/ -logging.file.name=webdav.log \ No newline at end of file +logging.file.name=webdav.log + +aliyundrive.auth.enable=true +aliyundrive.auth.user-name=admin +aliyundrive.auth.password=admin diff --git a/src/main/resources/error.xml b/src/main/resources/error.xml new file mode 100644 index 0000000..1e53462 --- /dev/null +++ b/src/main/resources/error.xml @@ -0,0 +1,9 @@ + + + + + + HTTP/1.1 {{code}} {{message}} + + + \ No newline at end of file