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