Re: context root with relative path
On 5/9/2016 11:34 AM, Dimitar Valov wrote: Hi, Have you decided if the proposed fix make since? If the corner case is :/, then it can be handled as well, not to remove the slash in case the previous char is :. IMO, the correct result for this case would most likely be to INCLUDE the trailing "/" if the previous character is a ":". Generally you are going to want to end up with "the root of ", not "the default directory on ". Best Regards, Dimitar On Thu, Apr 21, 2016 at 7:12 PM, Leo Donahue wrote: On Apr 21, 2016 10:38 AM, "David kerber" wrote: On 4/21/2016 11:33 AM, Leo Donahue wrote: Chris, On Apr 21, 2016 9:15 AM, "Christopher Schultz" < ch...@christopherschultz.net> wrote: I don't have a Windows machine handy right this minute, but from my previous experience, "C:" means "the current working directory on the C drive, from this process's perspective. For instance: D:\> DIR C:\ ... Program Files Windows ... D:\> DIR C: ... Program Files Windows ... D:\> CD C:\Windows D:\> DIR C: ... System System32 ... So I would think that using "C:" (with no trailing path) from Java would behave the same way: the current working directory *on that drive* would be the one used. I would expect it to work just like "." on *NIX. -chris -- On Windows 7 from a command prompt: C:\downloads dir c: Shows contents of downloads C:\downloads dir c:\ Shows contents of c drive Yes, that's all well-known on windows. The question was, how does the Java File object handle it? Does it give the correct result as above? And going back to the original question, how should these paths be normalized? Let's hope this looks right, pasting code from Android device... *import* java.io.File; *import* java.net.URI; *import* java.net.URISyntaxException; *import* java.util.ArrayList; *import* java.util.List; *public* *class* Demo { *public* *static* *void* main(String[] args) { List paths = *new* ArrayList(2); paths.add("file:/c:"); paths.add("file:/c:/"); *for* (String x : paths) { *try* { URI uri = *new* URI(x); File f = *new* File(uri); System.*out*.println(f.getAbsolutePath()); } *catch* (URISyntaxException e) { e.printStackTrace(); } } } } - To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org
Re: context root with relative path
Hi, Have you decided if the proposed fix make since? If the corner case is :/, then it can be handled as well, not to remove the slash in case the previous char is :. Best Regards, Dimitar On Thu, Apr 21, 2016 at 7:12 PM, Leo Donahue wrote: > On Apr 21, 2016 10:38 AM, "David kerber" wrote: > > > > On 4/21/2016 11:33 AM, Leo Donahue wrote: > >> > >> Chris, > >> > >> On Apr 21, 2016 9:15 AM, "Christopher Schultz" < > ch...@christopherschultz.net> > >> wrote: > >>> > >>> > >>> I don't have a Windows machine handy right this minute, but from my > >>> previous experience, "C:" means "the current working directory on the C > >>> drive, from this process's perspective. > >>> > >>> For instance: > >>> > >>> D:\> DIR C:\ > >>> ... > >>> Program Files > >>> Windows > >>> ... > >>> > >>> D:\> DIR C: > >>> ... > >>> Program Files > >>> Windows > >>> ... > >>> > >>> D:\> CD C:\Windows > >>> D:\> DIR C: > >>> ... > >>> System > >>> System32 > >>> ... > >>> > >>> So I would think that using "C:" (with no trailing path) from Java > would > >>> behave the same way: the current working directory *on that drive* > would > >>> be the one used. > >>> > >>> I would expect it to work just like "." on *NIX. > >>> > >>> -chris > >>> > >>> -- > >> > >> > >> On Windows 7 from a command prompt: > >> > >>> C:\downloads dir c: > >> > >> Shows contents of downloads > >> > >>> C:\downloads dir c:\ > >> > >> Shows contents of c drive > > > > > > Yes, that's all well-known on windows. The question was, how does the > Java File object handle it? Does it give the correct result as above? > And going back to the original question, how should these paths be > normalized? > > Let's hope this looks right, pasting code from Android device... > > *import* java.io.File; > > *import* java.net.URI; > > *import* java.net.URISyntaxException; > > *import* java.util.ArrayList; > > *import* java.util.List; > > > > *public* *class* Demo > > { > > *public* *static* *void* main(String[] args) > > { > > List paths = *new* ArrayList(2); > > paths.add("file:/c:"); > > paths.add("file:/c:/"); > > > > *for* (String x : paths) > > { > > *try* > > { > > URI uri = *new* URI(x); > > File f = *new* File(uri); > > System.*out*.println(f.getAbsolutePath()); > > } > > *catch* (URISyntaxException e) > > { > > e.printStackTrace(); > > } > >} > > } > > } >
Re: context root with relative path
On Apr 21, 2016 10:38 AM, "David kerber" wrote: > > On 4/21/2016 11:33 AM, Leo Donahue wrote: >> >> Chris, >> >> On Apr 21, 2016 9:15 AM, "Christopher Schultz" < ch...@christopherschultz.net> >> wrote: >>> >>> >>> I don't have a Windows machine handy right this minute, but from my >>> previous experience, "C:" means "the current working directory on the C >>> drive, from this process's perspective. >>> >>> For instance: >>> >>> D:\> DIR C:\ >>> ... >>> Program Files >>> Windows >>> ... >>> >>> D:\> DIR C: >>> ... >>> Program Files >>> Windows >>> ... >>> >>> D:\> CD C:\Windows >>> D:\> DIR C: >>> ... >>> System >>> System32 >>> ... >>> >>> So I would think that using "C:" (with no trailing path) from Java would >>> behave the same way: the current working directory *on that drive* would >>> be the one used. >>> >>> I would expect it to work just like "." on *NIX. >>> >>> -chris >>> >>> -- >> >> >> On Windows 7 from a command prompt: >> >>> C:\downloads dir c: >> >> Shows contents of downloads >> >>> C:\downloads dir c:\ >> >> Shows contents of c drive > > > Yes, that's all well-known on windows. The question was, how does the Java File object handle it? Does it give the correct result as above? And going back to the original question, how should these paths be normalized? Let's hope this looks right, pasting code from Android device... *import* java.io.File; *import* java.net.URI; *import* java.net.URISyntaxException; *import* java.util.ArrayList; *import* java.util.List; *public* *class* Demo { *public* *static* *void* main(String[] args) { List paths = *new* ArrayList(2); paths.add("file:/c:"); paths.add("file:/c:/"); *for* (String x : paths) { *try* { URI uri = *new* URI(x); File f = *new* File(uri); System.*out*.println(f.getAbsolutePath()); } *catch* (URISyntaxException e) { e.printStackTrace(); } } } }
Re: context root with relative path
On 4/21/2016 11:33 AM, Leo Donahue wrote: Chris, On Apr 21, 2016 9:15 AM, "Christopher Schultz" wrote: I don't have a Windows machine handy right this minute, but from my previous experience, "C:" means "the current working directory on the C drive, from this process's perspective. For instance: D:\> DIR C:\ ... Program Files Windows ... D:\> DIR C: ... Program Files Windows ... D:\> CD C:\Windows D:\> DIR C: ... System System32 ... So I would think that using "C:" (with no trailing path) from Java would behave the same way: the current working directory *on that drive* would be the one used. I would expect it to work just like "." on *NIX. -chris -- On Windows 7 from a command prompt: C:\downloads dir c: Shows contents of downloads C:\downloads dir c:\ Shows contents of c drive Yes, that's all well-known on windows. The question was, how does the Java File object handle it? Does it give the correct result as above? And going back to the original question, how should these paths be normalized? - To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org
Re: context root with relative path
Chris, On Apr 21, 2016 9:15 AM, "Christopher Schultz" wrote: > > I don't have a Windows machine handy right this minute, but from my > previous experience, "C:" means "the current working directory on the C > drive, from this process's perspective. > > For instance: > > D:\> DIR C:\ > ... > Program Files > Windows > ... > > D:\> DIR C: > ... > Program Files > Windows > ... > > D:\> CD C:\Windows > D:\> DIR C: > ... > System > System32 > ... > > So I would think that using "C:" (with no trailing path) from Java would > behave the same way: the current working directory *on that drive* would > be the one used. > > I would expect it to work just like "." on *NIX. > > -chris > > -- On Windows 7 from a command prompt: >C:\downloads dir c: Shows contents of downloads >C:\downloads dir c:\ Shows contents of c drive Leo
Re: context root with relative path
Konstantin, On 4/20/16 8:31 AM, Konstantin Kolinko wrote: > 2016-04-19 22:42 GMT+03:00 Mark Thomas : >> On 19/04/2016 19:38, Dimitar Valov wrote: >>> All static resources such as index.html will not be found when application >>> is added with , for example tomcat >>> is put inside the application's META-INF. >>> >>> I've drilled down that the AbstractFileResourceSet class is responsible for >>> this behaviour, inside the protected final File file(String name, boolean >>> mustExist) method. There absoluteBase and canonicalBase (absolute, unique >>> with resolved symlinks) are used to determine if the file should be >>> accessed based on a case sensitivity check. >>> >>> Everything works fine if the docBase is not just path like ../../.././../ >>> but has an actual directory at the end, like ../../../web-app. However in >>> this edgy case the difference appears since the behaviour of >>> the org.apache.tomcat.util.http.RequestUtil.normalize method has slightly >>> different behavior than the File.getCanonicalPath. >>> >>> System.out.println(RequestUtil.normalize("/base/1/2/3/../../../")); >>> /base/ >>> >>> System.out.println(RequestUtil.normalize("/base/1/2/3/../../..")); >>> /base/1/.. >>> System.out.println(new File("/base/1/2/3/../../../").getCanonicalPath()); >>> /base >>> >>> The added /from RequestUtil breakes the logic inside the file method, since >>> when doing the substring operation inside AbstractFileResourceSet.file >>> method it may or may not have a trailing /. In such situation >> path>/index.html substring with the absoluteBase becomes ndex.html. At the >>> end the file method returns from here: >>> >>> if (!canPath.equals(absPath)) // !"index.html".equals("ndex.html") >>> => true >>> return null; >>> >>> The RequestUtil comes from the http packages and follows their conventions >>> when normalizing the path, so an obvious way to fix this is to add and if >>> statement after the normalization >>> inside AbstractFileResourceSet.initInternal. >>> >>> this.absoluteBase = normalize(absolutePath); >>> if (this.absoluteBase.endsWith("/")) { >>> this.absoluteBase = this.absoluteBase.substring(0, >>> this.absoluteBase.length() - 1); >>> } >>> >>> With Java 7 instead of using the RequestUtil for normalization, Path >>> java.nio.file.Path.normalize() can accomplish the correct thing. >>> >>> Do you think that is something that can be fixed? Maybe the above is not >>> the best approach, however it's the least invasive. >> >> We need to be very careful here since this is security sensitive. >> >> Given that normalize handles URIs, there is an argument for slightly >> different handling of trailing '/'. I'm currently of the view (subject >> to the results of some local tests I am running) that if the input ends >> in '/', so should the output. If the input doesn't end in '/' neither >> should the output unless the output is the string "/". >> >> The end result is likely to be that docBase values should not end in "/". >> > > (I have not looked at the context. Just a general comment / review of > r1740134) > > There is a risk of normalizing Windows path of "C:\foo\.." into "C:" > which denotes the current directory on drive C: while the expected > value is the root of the drive, "C:\". > > I have not tested how java.io.File("C:") actually works. I don't have a Windows machine handy right this minute, but from my previous experience, "C:" means "the current working directory on the C drive, from this process's perspective. For instance: D:\> DIR C:\ ... Program Files Windows ... D:\> DIR C: ... Program Files Windows ... D:\> CD C:\Windows D:\> DIR C: ... System System32 ... So I would think that using "C:" (with no trailing path) from Java would behave the same way: the current working directory *on that drive* would be the one used. I would expect it to work just like "." on *NIX. -chris - To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org
Re: context root with relative path
On 4/20/2016 12:07 PM, Dimitar Valov wrote: System.out.println(new File("C:").exists()); prints true, so I guess it works okay. All that means is that it does something. That doesn't means it's doing the correct thing. That *should* be checking the existence of the "current" directory, which is always going to succeed. The question is, is it actually checking for the existence of the root directory? And what does new File("C:\").exists() give you? And is it different? On Wed, Apr 20, 2016 at 3:31 PM, Konstantin Kolinko wrote: 2016-04-19 22:42 GMT+03:00 Mark Thomas : On 19/04/2016 19:38, Dimitar Valov wrote: All static resources such as index.html will not be found when application is added with , for example tomcat is put inside the application's META-INF. I've drilled down that the AbstractFileResourceSet class is responsible for this behaviour, inside the protected final File file(String name, boolean mustExist) method. There absoluteBase and canonicalBase (absolute, unique with resolved symlinks) are used to determine if the file should be accessed based on a case sensitivity check. Everything works fine if the docBase is not just path like ../../.././../ but has an actual directory at the end, like ../../../web-app. However in this edgy case the difference appears since the behaviour of the org.apache.tomcat.util.http.RequestUtil.normalize method has slightly different behavior than the File.getCanonicalPath. System.out.println(RequestUtil.normalize("/base/1/2/3/../../../")); /base/ System.out.println(RequestUtil.normalize("/base/1/2/3/../../..")); /base/1/.. System.out.println(new File("/base/1/2/3/../../../").getCanonicalPath()); /base The added /from RequestUtil breakes the logic inside the file method, since when doing the substring operation inside AbstractFileResourceSet.file method it may or may not have a trailing /. In such situation /index.html substring with the absoluteBase becomes ndex.html. At the end the file method returns from here: if (!canPath.equals(absPath)) // !"index.html".equals("ndex.html") => true return null; The RequestUtil comes from the http packages and follows their conventions when normalizing the path, so an obvious way to fix this is to add and if statement after the normalization inside AbstractFileResourceSet.initInternal. this.absoluteBase = normalize(absolutePath); if (this.absoluteBase.endsWith("/")) { this.absoluteBase = this.absoluteBase.substring(0, this.absoluteBase.length() - 1); } With Java 7 instead of using the RequestUtil for normalization, Path java.nio.file.Path.normalize() can accomplish the correct thing. Do you think that is something that can be fixed? Maybe the above is not the best approach, however it's the least invasive. We need to be very careful here since this is security sensitive. Given that normalize handles URIs, there is an argument for slightly different handling of trailing '/'. I'm currently of the view (subject to the results of some local tests I am running) that if the input ends in '/', so should the output. If the input doesn't end in '/' neither should the output unless the output is the string "/". The end result is likely to be that docBase values should not end in "/". (I have not looked at the context. Just a general comment / review of r1740134) There is a risk of normalizing Windows path of "C:\foo\.." into "C:" which denotes the current directory on drive C: while the expected value is the root of the drive, "C:\". I have not tested how java.io.File("C:") actually works. Best regards, Konstantin Kolinko - To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org - To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org
RE: context root with relative path
> From: Dimitar Valov [mailto:dimitar.va...@gmail.com] > Subject: Re: context root with relative path > System.out.println(new File("C:").exists()); prints true, so I guess it > works okay. Depends on the definition of "okay"; that only tells us that the C drive's current directory is present. As Konstantin pointed out, the normalization should have produced "C:\" - which will also pass the exists() test. - Chuck THIS COMMUNICATION MAY CONTAIN CONFIDENTIAL AND/OR OTHERWISE PROPRIETARY MATERIAL and is thus for use only by the intended recipient. If you received this in error, please contact the sender and delete the e-mail and its attachments from all computers. - To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org
Re: context root with relative path
System.out.println(new File("C:").exists()); prints true, so I guess it works okay. On Wed, Apr 20, 2016 at 3:31 PM, Konstantin Kolinko wrote: > 2016-04-19 22:42 GMT+03:00 Mark Thomas : > > On 19/04/2016 19:38, Dimitar Valov wrote: > >> All static resources such as index.html will not be found when > application > >> is added with , for example > tomcat > >> is put inside the application's META-INF. > >> > >> I've drilled down that the AbstractFileResourceSet class is responsible > for > >> this behaviour, inside the protected final File file(String name, > boolean > >> mustExist) method. There absoluteBase and canonicalBase (absolute, > unique > >> with resolved symlinks) are used to determine if the file should be > >> accessed based on a case sensitivity check. > >> > >> Everything works fine if the docBase is not just path like > ../../.././../ > >> but has an actual directory at the end, like ../../../web-app. However > in > >> this edgy case the difference appears since the behaviour of > >> the org.apache.tomcat.util.http.RequestUtil.normalize method has > slightly > >> different behavior than the File.getCanonicalPath. > >> > >> System.out.println(RequestUtil.normalize("/base/1/2/3/../../../")); > >> /base/ > >> > >> System.out.println(RequestUtil.normalize("/base/1/2/3/../../..")); > >> /base/1/.. > >> System.out.println(new > File("/base/1/2/3/../../../").getCanonicalPath()); > >> /base > >> > >> The added /from RequestUtil breakes the logic inside the file method, > since > >> when doing the substring operation inside AbstractFileResourceSet.file > >> method it may or may not have a trailing /. In such situation >> path>/index.html substring with the absoluteBase becomes ndex.html. At > the > >> end the file method returns from here: > >> > >> if (!canPath.equals(absPath)) // > !"index.html".equals("ndex.html") > >> => true > >> return null; > >> > >> The RequestUtil comes from the http packages and follows their > conventions > >> when normalizing the path, so an obvious way to fix this is to add and > if > >> statement after the normalization > >> inside AbstractFileResourceSet.initInternal. > >> > >> this.absoluteBase = normalize(absolutePath); > >> if (this.absoluteBase.endsWith("/")) { > >> this.absoluteBase = this.absoluteBase.substring(0, > >> this.absoluteBase.length() - 1); > >> } > >> > >> With Java 7 instead of using the RequestUtil for normalization, Path > >> java.nio.file.Path.normalize() can accomplish the correct thing. > >> > >> Do you think that is something that can be fixed? Maybe the above is not > >> the best approach, however it's the least invasive. > > > > We need to be very careful here since this is security sensitive. > > > > Given that normalize handles URIs, there is an argument for slightly > > different handling of trailing '/'. I'm currently of the view (subject > > to the results of some local tests I am running) that if the input ends > > in '/', so should the output. If the input doesn't end in '/' neither > > should the output unless the output is the string "/". > > > > The end result is likely to be that docBase values should not end in "/". > > > > (I have not looked at the context. Just a general comment / review of > r1740134) > > There is a risk of normalizing Windows path of "C:\foo\.." into "C:" > which denotes the current directory on drive C: while the expected > value is the root of the drive, "C:\". > > I have not tested how java.io.File("C:") actually works. > > Best regards, > Konstantin Kolinko > > - > To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org > For additional commands, e-mail: users-h...@tomcat.apache.org > >
Re: context root with relative path
2016-04-19 22:42 GMT+03:00 Mark Thomas : > On 19/04/2016 19:38, Dimitar Valov wrote: >> All static resources such as index.html will not be found when application >> is added with , for example tomcat >> is put inside the application's META-INF. >> >> I've drilled down that the AbstractFileResourceSet class is responsible for >> this behaviour, inside the protected final File file(String name, boolean >> mustExist) method. There absoluteBase and canonicalBase (absolute, unique >> with resolved symlinks) are used to determine if the file should be >> accessed based on a case sensitivity check. >> >> Everything works fine if the docBase is not just path like ../../.././../ >> but has an actual directory at the end, like ../../../web-app. However in >> this edgy case the difference appears since the behaviour of >> the org.apache.tomcat.util.http.RequestUtil.normalize method has slightly >> different behavior than the File.getCanonicalPath. >> >> System.out.println(RequestUtil.normalize("/base/1/2/3/../../../")); >> /base/ >> >> System.out.println(RequestUtil.normalize("/base/1/2/3/../../..")); >> /base/1/.. >> System.out.println(new File("/base/1/2/3/../../../").getCanonicalPath()); >> /base >> >> The added /from RequestUtil breakes the logic inside the file method, since >> when doing the substring operation inside AbstractFileResourceSet.file >> method it may or may not have a trailing /. In such situation > path>/index.html substring with the absoluteBase becomes ndex.html. At the >> end the file method returns from here: >> >> if (!canPath.equals(absPath)) // !"index.html".equals("ndex.html") >> => true >> return null; >> >> The RequestUtil comes from the http packages and follows their conventions >> when normalizing the path, so an obvious way to fix this is to add and if >> statement after the normalization >> inside AbstractFileResourceSet.initInternal. >> >> this.absoluteBase = normalize(absolutePath); >> if (this.absoluteBase.endsWith("/")) { >> this.absoluteBase = this.absoluteBase.substring(0, >> this.absoluteBase.length() - 1); >> } >> >> With Java 7 instead of using the RequestUtil for normalization, Path >> java.nio.file.Path.normalize() can accomplish the correct thing. >> >> Do you think that is something that can be fixed? Maybe the above is not >> the best approach, however it's the least invasive. > > We need to be very careful here since this is security sensitive. > > Given that normalize handles URIs, there is an argument for slightly > different handling of trailing '/'. I'm currently of the view (subject > to the results of some local tests I am running) that if the input ends > in '/', so should the output. If the input doesn't end in '/' neither > should the output unless the output is the string "/". > > The end result is likely to be that docBase values should not end in "/". > (I have not looked at the context. Just a general comment / review of r1740134) There is a risk of normalizing Windows path of "C:\foo\.." into "C:" which denotes the current directory on drive C: while the expected value is the root of the drive, "C:\". I have not tested how java.io.File("C:") actually works. Best regards, Konstantin Kolinko - To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org
RE: context root with relative path
> From: Mark Thomas [mailto:ma...@apache.org] > Subject: Re: context root with relative path On 19/04/2016 19:38, Dimitar Valov wrote: > All static resources such as index.html will not be found when application > is added with , for example tomcat > is put inside the application's META-INF. Not that it's pertinent to the resource retrieval problem, but a path attribute of "/" is never correct ("" might be what is wanted). But since path attributes on elements located in META-INF/context.xml are not allowed, it doesn't really matter for this particular issue. - Chuck THIS COMMUNICATION MAY CONTAIN CONFIDENTIAL AND/OR OTHERWISE PROPRIETARY MATERIAL and is thus for use only by the intended recipient. If you received this in error, please contact the sender and delete the e-mail and its attachments from all computers. - To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org
Re: context root with relative path
On 4/19/2016 4:13 PM, Dimitar Valov wrote: Hi Mark, Yes, it is sensitive, that's why I'm suggesting such simple solution. For me the issues comes because of AbstractFileResourceSet::file -> absPath = absPath.substring(absoluteBase.length() + 1); and if (!canPath.equals(absPath)). This + 1 should account for the /. However we cannot count on not having the / at the end of absPath. Why not explicitly check for the existence of the trailing "\", rather than assuming it's (non)existence and just checking the string length? I think Mark is saying that you have found an inconsistency, and pending further testing thinks that there should be changes made so that you get back what you supplied to those functions. I.E., if you gave it a trailing "\" as an argument, you'll get one back, and if not, you won't. I've played with specifying paths that end with / and without, and I think that there's no way that the current implementation can be configured correctly: * if path like ../../ is used it is normalized to path ending with / => the substring will consume the first character of the filename. * if path like ../.. is used it is normalized to path ending .. (which is even worse), but this can be documented out, otherwise a method like Path.normalize should be used or implemented. * if path like ../../app or ../../app/ is used everything works correctly, but this is bacause StandardContext::fixDocBase takes care to delete the last /. I think that if fixDocBase does something to strings like ../../../ it will break the results returned from RequestUtil.normalize, i.e. deleting the last / and the normalizing it will produce path ending with /.. which will once again not work. The behaviour of org.apache.tomcat.util.http.RequestUtil is quite similar but different from the one getting unique file path (Path.normalize). And then if (!canPath.equals(absPath)) is comparing two quite similar things ,but not the same "things". I think that with java.io.File APIs there's nothing that can give the needed behaviour (the getCanonicalPath will resolve symlinks) Best Regards, Dimitar Valov On Tue, Apr 19, 2016 at 10:42 PM, Mark Thomas wrote: On 19/04/2016 19:38, Dimitar Valov wrote: All static resources such as index.html will not be found when application is added with , for example tomcat is put inside the application's META-INF. I've drilled down that the AbstractFileResourceSet class is responsible for this behaviour, inside the protected final File file(String name, boolean mustExist) method. There absoluteBase and canonicalBase (absolute, unique with resolved symlinks) are used to determine if the file should be accessed based on a case sensitivity check. Everything works fine if the docBase is not just path like ../../.././../ but has an actual directory at the end, like ../../../web-app. However in this edgy case the difference appears since the behaviour of the org.apache.tomcat.util.http.RequestUtil.normalize method has slightly different behavior than the File.getCanonicalPath. System.out.println(RequestUtil.normalize("/base/1/2/3/../../../")); /base/ System.out.println(RequestUtil.normalize("/base/1/2/3/../../..")); /base/1/.. System.out.println(new File("/base/1/2/3/../../../").getCanonicalPath()); /base The added /from RequestUtil breakes the logic inside the file method, since when doing the substring operation inside AbstractFileResourceSet.file method it may or may not have a trailing /. In such situation /index.html substring with the absoluteBase becomes ndex.html. At the end the file method returns from here: if (!canPath.equals(absPath)) // !"index.html".equals("ndex.html") => true return null; The RequestUtil comes from the http packages and follows their conventions when normalizing the path, so an obvious way to fix this is to add and if statement after the normalization inside AbstractFileResourceSet.initInternal. this.absoluteBase = normalize(absolutePath); if (this.absoluteBase.endsWith("/")) { this.absoluteBase = this.absoluteBase.substring(0, this.absoluteBase.length() - 1); } With Java 7 instead of using the RequestUtil for normalization, Path java.nio.file.Path.normalize() can accomplish the correct thing. Do you think that is something that can be fixed? Maybe the above is not the best approach, however it's the least invasive. We need to be very careful here since this is security sensitive. Given that normalize handles URIs, there is an argument for slightly different handling of trailing '/'. I'm currently of the view (subject to the results of some local tests I am running) that if the input ends in '/', so should the output. If the input doesn't end in '/' neither should the output unless the output is the string "/". The end result is likely to be that docBase values should not end in "/". Mark - To
Re: context root with relative path
Hi Mark, Yes, it is sensitive, that's why I'm suggesting such simple solution. For me the issues comes because of AbstractFileResourceSet::file -> absPath = absPath.substring(absoluteBase.length() + 1); and if (!canPath.equals(absPath)). This + 1 should account for the /. However we cannot count on not having the / at the end of absPath. I've played with specifying paths that end with / and without, and I think that there's no way that the current implementation can be configured correctly: * if path like ../../ is used it is normalized to path ending with / => the substring will consume the first character of the filename. * if path like ../.. is used it is normalized to path ending .. (which is even worse), but this can be documented out, otherwise a method like Path.normalize should be used or implemented. * if path like ../../app or ../../app/ is used everything works correctly, but this is bacause StandardContext::fixDocBase takes care to delete the last /. I think that if fixDocBase does something to strings like ../../../ it will break the results returned from RequestUtil.normalize, i.e. deleting the last / and the normalizing it will produce path ending with /.. which will once again not work. The behaviour of org.apache.tomcat.util.http.RequestUtil is quite similar but different from the one getting unique file path (Path.normalize). And then if (!canPath.equals(absPath)) is comparing two quite similar things ,but not the same "things". I think that with java.io.File APIs there's nothing that can give the needed behaviour (the getCanonicalPath will resolve symlinks) Best Regards, Dimitar Valov On Tue, Apr 19, 2016 at 10:42 PM, Mark Thomas wrote: > On 19/04/2016 19:38, Dimitar Valov wrote: > > All static resources such as index.html will not be found when > application > > is added with , for example tomcat > > is put inside the application's META-INF. > > > > I've drilled down that the AbstractFileResourceSet class is responsible > for > > this behaviour, inside the protected final File file(String name, boolean > > mustExist) method. There absoluteBase and canonicalBase (absolute, unique > > with resolved symlinks) are used to determine if the file should be > > accessed based on a case sensitivity check. > > > > Everything works fine if the docBase is not just path like ../../.././../ > > but has an actual directory at the end, like ../../../web-app. However in > > this edgy case the difference appears since the behaviour of > > the org.apache.tomcat.util.http.RequestUtil.normalize method has slightly > > different behavior than the File.getCanonicalPath. > > > > System.out.println(RequestUtil.normalize("/base/1/2/3/../../../")); > > /base/ > > > > System.out.println(RequestUtil.normalize("/base/1/2/3/../../..")); > > /base/1/.. > > System.out.println(new File("/base/1/2/3/../../../").getCanonicalPath()); > > /base > > > > The added /from RequestUtil breakes the logic inside the file method, > since > > when doing the substring operation inside AbstractFileResourceSet.file > > method it may or may not have a trailing /. In such situation > path>/index.html substring with the absoluteBase becomes ndex.html. At > the > > end the file method returns from here: > > > > if (!canPath.equals(absPath)) // > !"index.html".equals("ndex.html") > > => true > > return null; > > > > The RequestUtil comes from the http packages and follows their > conventions > > when normalizing the path, so an obvious way to fix this is to add and if > > statement after the normalization > > inside AbstractFileResourceSet.initInternal. > > > > this.absoluteBase = normalize(absolutePath); > > if (this.absoluteBase.endsWith("/")) { > > this.absoluteBase = this.absoluteBase.substring(0, > > this.absoluteBase.length() - 1); > > } > > > > With Java 7 instead of using the RequestUtil for normalization, Path > > java.nio.file.Path.normalize() can accomplish the correct thing. > > > > Do you think that is something that can be fixed? Maybe the above is not > > the best approach, however it's the least invasive. > > We need to be very careful here since this is security sensitive. > > Given that normalize handles URIs, there is an argument for slightly > different handling of trailing '/'. I'm currently of the view (subject > to the results of some local tests I am running) that if the input ends > in '/', so should the output. If the input doesn't end in '/' neither > should the output unless the output is the string "/". > > The end result is likely to be that docBase values should not end in "/". > > Mark > > > - > To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org > For additional commands, e-mail: users-h...@tomcat.apache.org > >
Re: context root with relative path
On 19/04/2016 19:38, Dimitar Valov wrote: > All static resources such as index.html will not be found when application > is added with , for example tomcat > is put inside the application's META-INF. > > I've drilled down that the AbstractFileResourceSet class is responsible for > this behaviour, inside the protected final File file(String name, boolean > mustExist) method. There absoluteBase and canonicalBase (absolute, unique > with resolved symlinks) are used to determine if the file should be > accessed based on a case sensitivity check. > > Everything works fine if the docBase is not just path like ../../.././../ > but has an actual directory at the end, like ../../../web-app. However in > this edgy case the difference appears since the behaviour of > the org.apache.tomcat.util.http.RequestUtil.normalize method has slightly > different behavior than the File.getCanonicalPath. > > System.out.println(RequestUtil.normalize("/base/1/2/3/../../../")); > /base/ > > System.out.println(RequestUtil.normalize("/base/1/2/3/../../..")); > /base/1/.. > System.out.println(new File("/base/1/2/3/../../../").getCanonicalPath()); > /base > > The added /from RequestUtil breakes the logic inside the file method, since > when doing the substring operation inside AbstractFileResourceSet.file > method it may or may not have a trailing /. In such situation path>/index.html substring with the absoluteBase becomes ndex.html. At the > end the file method returns from here: > > if (!canPath.equals(absPath)) // !"index.html".equals("ndex.html") > => true > return null; > > The RequestUtil comes from the http packages and follows their conventions > when normalizing the path, so an obvious way to fix this is to add and if > statement after the normalization > inside AbstractFileResourceSet.initInternal. > > this.absoluteBase = normalize(absolutePath); > if (this.absoluteBase.endsWith("/")) { > this.absoluteBase = this.absoluteBase.substring(0, > this.absoluteBase.length() - 1); > } > > With Java 7 instead of using the RequestUtil for normalization, Path > java.nio.file.Path.normalize() can accomplish the correct thing. > > Do you think that is something that can be fixed? Maybe the above is not > the best approach, however it's the least invasive. We need to be very careful here since this is security sensitive. Given that normalize handles URIs, there is an argument for slightly different handling of trailing '/'. I'm currently of the view (subject to the results of some local tests I am running) that if the input ends in '/', so should the output. If the input doesn't end in '/' neither should the output unless the output is the string "/". The end result is likely to be that docBase values should not end in "/". Mark - To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org
context root with relative path
All static resources such as index.html will not be found when application is added with , for example tomcat is put inside the application's META-INF. I've drilled down that the AbstractFileResourceSet class is responsible for this behaviour, inside the protected final File file(String name, boolean mustExist) method. There absoluteBase and canonicalBase (absolute, unique with resolved symlinks) are used to determine if the file should be accessed based on a case sensitivity check. Everything works fine if the docBase is not just path like ../../.././../ but has an actual directory at the end, like ../../../web-app. However in this edgy case the difference appears since the behaviour of the org.apache.tomcat.util.http.RequestUtil.normalize method has slightly different behavior than the File.getCanonicalPath. System.out.println(RequestUtil.normalize("/base/1/2/3/../../../")); /base/ System.out.println(RequestUtil.normalize("/base/1/2/3/../../..")); /base/1/.. System.out.println(new File("/base/1/2/3/../../../").getCanonicalPath()); /base The added /from RequestUtil breakes the logic inside the file method, since when doing the substring operation inside AbstractFileResourceSet.file method it may or may not have a trailing /. In such situation /index.html substring with the absoluteBase becomes ndex.html. At the end the file method returns from here: if (!canPath.equals(absPath)) // !"index.html".equals("ndex.html") => true return null; The RequestUtil comes from the http packages and follows their conventions when normalizing the path, so an obvious way to fix this is to add and if statement after the normalization inside AbstractFileResourceSet.initInternal. this.absoluteBase = normalize(absolutePath); if (this.absoluteBase.endsWith("/")) { this.absoluteBase = this.absoluteBase.substring(0, this.absoluteBase.length() - 1); } With Java 7 instead of using the RequestUtil for normalization, Path java.nio.file.Path.normalize() can accomplish the correct thing. Do you think that is something that can be fixed? Maybe the above is not the best approach, however it's the least invasive. Best Regards Dimitar Valov