View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.server.handler;
20  
21  import java.io.File;
22  import java.net.URI;
23  import java.nio.file.Files;
24  import java.nio.file.Path;
25  
26  import org.eclipse.jetty.server.handler.ContextHandler.AliasCheck;
27  import org.eclipse.jetty.util.log.Log;
28  import org.eclipse.jetty.util.log.Logger;
29  import org.eclipse.jetty.util.resource.Resource;
30  
31  
32  /* ------------------------------------------------------------ */
33  /** Symbolic Link AliasChecker.
34   * <p>An instance of this class can be registered with {@link ContextHandler#addAliasCheck(AliasCheck)}
35   * to check resources that are aliased to other locations.   The checker uses the 
36   * Java {@link Files#readSymbolicLink(Path)} and {@link Path#toRealPath(java.nio.file.LinkOption...)}
37   * APIs to check if a file is aliased with symbolic links.</p>
38   */
39  public class AllowSymLinkAliasChecker implements AliasCheck
40  {
41      private static final Logger LOG = Log.getLogger(AllowSymLinkAliasChecker.class);
42      
43      @Override
44      public boolean check(String path, Resource resource)
45      {
46          try
47          {
48              File file =resource.getFile();
49              if (file==null)
50                  return false;
51              
52              // If the file exists
53              if (file.exists())
54              {
55                  // we can use the real path method to check the symlinks resolve to the alias
56                  URI real = file.toPath().toRealPath().toUri();
57                  if (real.equals(resource.getAlias()))
58                  {
59                      if (LOG.isDebugEnabled())
60                          LOG.debug("Allow symlink {} --> {}",resource,real);
61                      return true;
62                  }
63              }
64              else
65              {
66                  // file does not exists, so we have to walk the path and links ourselves.
67                  Path p = file.toPath().toAbsolutePath();
68                  File d = p.getRoot().toFile();
69                  for (Path e:p)
70                  {
71                      d=new File(d,e.toString());
72                      
73                      while (d.exists() && Files.isSymbolicLink(d.toPath()))
74                      {
75                          Path link=Files.readSymbolicLink(d.toPath());
76                          if (!link.isAbsolute())
77                              link=link.resolve(d.toPath());
78                          d=link.toFile().getAbsoluteFile().getCanonicalFile();
79                      }
80                  }
81                  if (resource.getAlias().equals(d.toURI()))
82                  {
83                      if (LOG.isDebugEnabled())
84                          LOG.debug("Allow symlink {} --> {}",resource,d);
85                      return true;
86                  }
87              }
88          }
89          catch(Exception e)
90          {
91              e.printStackTrace();
92              LOG.ignore(e);
93          }
94          return false;
95      }
96  
97  }