Skip to content

Commit 6c2e7db

Browse files
committed
[OLINGO-1640] ENUM regex fix
1 parent 20b0d7a commit 6c2e7db

2 files changed

Lines changed: 96 additions & 1 deletion

File tree

lib/client-core/src/main/java/org/apache/olingo/client/core/uri/URIUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public final class URIUtils {
7272
* Logger.
7373
*/
7474

75-
private static final Pattern ENUM_VALUE = Pattern.compile("(.+\\.)?.+'.+'");
75+
private static final Pattern ENUM_VALUE = Pattern.compile("([^']+\\.[^']+)?'[^']+'");
7676
private static final String URI_OPTIONS = "/$";
7777

7878
private URIUtils() {
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.olingo.client.core.uri;
20+
21+
import org.apache.olingo.client.api.ODataClient;
22+
import org.apache.olingo.client.core.ODataClientFactory;
23+
import org.junit.Test;
24+
25+
import static org.junit.Assert.assertEquals;
26+
27+
public class ExampleUriGeneratorTest {
28+
/**
29+
* This test demonstrates the normal behavior of encapsulating a string with single quotes
30+
* <p>
31+
* The test succeeds
32+
*/
33+
@Test
34+
public void testHappyPath() {
35+
String uri = ExampleUriGenerator.filterPersonByName("henk");
36+
37+
// Expected: https://example.com/Person?$filter=(name eq 'henk')
38+
assertEquals("https://example.com/Person?%24filter=%28name%20eq%20'henk'%29", uri);
39+
}
40+
41+
42+
/**
43+
* This test demonstrates that some String literals are not encapsulated (quoted) correctly. This happens because
44+
* {@link org.apache.olingo.client.core.uri.URIUtils#quoteString(String, boolean)} incorrectly determines the string
45+
* to be an enum using a poorly designed regex, causing it to not encapsulate the string with single quotes. This
46+
* can be abused to circumvent filters as illustrated in the example below.
47+
* <p>
48+
* The test <b>fails</b>
49+
*/
50+
@Test
51+
public void testODataInjection() {
52+
String uri = ExampleUriGenerator.filterPersonByName("' or name ne '");
53+
54+
// Expected: https://example.com/Person?$filter=(name eq ''' or name ne ''')
55+
assertEquals("https://example.com/Person?%24filter=%28name%20eq%20'''%20or%20name%20ne%20'''%29", uri);
56+
57+
// Actual: https://example.com/Person?%24filter=%28name%20eq%20''%20or%20name%20ne%20''%29
58+
// https://example.com/Person?$filter=(name eq '' or name ne '')
59+
}
60+
61+
static final class ExampleUriGenerator {
62+
private static final ODataClient client = ODataClientFactory.getClient();
63+
64+
private ExampleUriGenerator() {
65+
}
66+
67+
static String filterPersonByName(String name) {
68+
// OLingo does not escape string literals so we do it ourselves
69+
String escapedName = escape(name);
70+
71+
String filter = client.getFilterFactory() //
72+
.eq("name", escapedName) //
73+
.build();
74+
75+
return client.newURIBuilder("https://example.com/") //
76+
.appendEntitySetSegment("Person") //
77+
.filter(filter) //
78+
.build().toString();
79+
}
80+
81+
//CHECKSTYLE:OFF
82+
/**
83+
* Escapes a string literal by representing a single quote in a string literal as two consecutive single quotes,
84+
* as per the <a href="https://docs.oasis-open.org/odata/odata/v4.01/os/part2-url-conventions/odata-v4.01-os-part2-url-conventions.html#sec_URLSyntax">OData 4.01 URL Conventions</a>
85+
*
86+
* @param value the value to escape
87+
* @return the escaped value
88+
*/
89+
//CHECKSTYLE:ON
90+
private static String escape(String value) {
91+
return value.replaceAll("'", "''");
92+
}
93+
}
94+
95+
}

0 commit comments

Comments
 (0)