View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2015 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.nio.file.Files;
22  import java.nio.file.Path;
23  
24  import org.eclipse.jetty.server.handler.ContextHandler.AliasCheck;
25  import org.eclipse.jetty.util.log.Log;
26  import org.eclipse.jetty.util.log.Logger;
27  import org.eclipse.jetty.util.resource.PathResource;
28  import org.eclipse.jetty.util.resource.Resource;
29  
30  
31  /* ------------------------------------------------------------ */
32  /** Symbolic Link AliasChecker.
33   * <p>An instance of this class can be registered with {@link ContextHandler#addAliasCheck(AliasCheck)}
34   * to check resources that are aliased to other locations.   The checker uses the 
35   * Java {@link Files#readSymbolicLink(Path)} and {@link Path#toRealPath(java.nio.file.LinkOption...)}
36   * APIs to check if a file is aliased with symbolic links.</p>
37   */
38  public class AllowSymLinkAliasChecker implements AliasCheck
39  {
40      private static final Logger LOG = Log.getLogger(AllowSymLinkAliasChecker.class);
41      
42      @Override
43      public boolean check(String uri, Resource resource)
44      {
45          // Only support PathResource alias checking
46          if (!(resource instanceof PathResource))
47              return false;
48          
49          PathResource pathResource = (PathResource)resource;
50  
51          try
52          {
53              Path path = pathResource.getPath();
54              Path alias = pathResource.getAliasPath();
55              
56              // is the file itself a symlink?
57              if (Files.isSymbolicLink(path))
58              {        
59                  alias = path.getParent().resolve(alias);
60                  if (LOG.isDebugEnabled())
61                  {
62                      LOG.debug("path ={}",path);
63                      LOG.debug("alias={}",alias);
64                  }
65                  if (Files.isSameFile(path,alias))
66                  {
67                      if (LOG.isDebugEnabled())
68                          LOG.debug("Allow symlink {} --> {}",resource,pathResource.getAliasPath());
69                      return true;
70                  }
71              }
72              
73              // No, so let's check each element ourselves
74              Path d = path.getRoot();
75              for (Path e:path)
76              {
77                  d=d.resolve(e);
78                  
79                  while (Files.exists(d) && Files.isSymbolicLink(d))
80                  {
81                      Path link=Files.readSymbolicLink(d);                    
82                      if (!link.isAbsolute())
83                          link=d.resolve(link);
84                      d=link;
85                  }
86              }
87              if (pathResource.getAliasPath().equals(d))
88              {
89                  if (LOG.isDebugEnabled())
90                      LOG.debug("Allow path symlink {} --> {}",resource,d);
91                  return true;
92              }
93          }
94          catch(Exception e)
95          {
96              LOG.ignore(e);
97          }
98          
99          return false;
100     }
101 
102 }