Skip to content

Commit

Permalink
fix username validation for internal user api (#2331)
Browse files Browse the repository at this point in the history
Signed-off-by: Rutuja Surve <[email protected]>
Co-authored-by: Peter Nied <[email protected]>
  • Loading branch information
rutuja-amazon and peternied authored Mar 22, 2023
1 parent d725b9e commit 691cd67
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,17 @@
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
import java.util.stream.Collectors;
import com.google.common.collect.ImmutableList;

import static org.opensearch.security.dlic.rest.support.Utils.hash;
import static org.opensearch.security.dlic.rest.support.Utils.addRoutesPrefix;

public class InternalUsersApiAction extends PatchableResourceApiAction {
static final List<String> RESTRICTED_FROM_USERNAME = ImmutableList.of(
":" // Not allowed in basic auth, see https://stackoverflow.com/a/33391003/533057
);

private static final List<Route> routes = addRoutesPrefix(ImmutableList.of(
new Route(Method.GET, "/user/{name}"),
new Route(Method.GET, "/user/"),
Expand Down Expand Up @@ -96,6 +101,13 @@ protected void handlePut(RestChannel channel, final RestRequest request, final C
return;
}

final List<String> foundRestrictedContents = RESTRICTED_FROM_USERNAME.stream().filter(username::contains).collect(Collectors.toList());
if (!foundRestrictedContents.isEmpty()) {
final String restrictedContents = foundRestrictedContents.stream().map(s -> "'" + s + "'").collect(Collectors.joining(","));
badRequestResponse(channel, "Username has restricted characters " + restrictedContents + " that are not permitted.");
return;
}

// TODO it might be sensible to consolidate this with the overridden method in
// order to minimize duplicated logic

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@
import java.util.List;

import static org.opensearch.security.OpenSearchSecurityPlugin.LEGACY_OPENDISTRO_PREFIX;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.opensearch.security.OpenSearchSecurityPlugin.PLUGINS_PREFIX;
import static org.opensearch.security.dlic.rest.api.InternalUsersApiAction.RESTRICTED_FROM_USERNAME;

@RunWith(Parameterized.class)
public class UserApiTest extends AbstractRestApiUnitTest {
Expand Down Expand Up @@ -482,7 +486,7 @@ public void testPasswordRules() throws Exception {
addUserWithPassword("$1aAAAAAAAac", "$1aAAAAAAAAC", HttpStatus.SC_BAD_REQUEST);
addUserWithPassword(URLEncoder.encode("$1aAAAAAAAac%", "UTF-8"), "$1aAAAAAAAAC%", HttpStatus.SC_BAD_REQUEST);
addUserWithPassword(URLEncoder.encode("$1aAAAAAAAac%!=\"/\\;:test&~@^", "UTF-8").replace("+", "%2B"), "$1aAAAAAAAac%!=\\\"/\\\\;:test&~@^", HttpStatus.SC_BAD_REQUEST);
addUserWithPassword(URLEncoder.encode("$1aAAAAAAAac%!=\"/\\;: test&", "UTF-8"), "$1aAAAAAAAac%!=\\\"/\\\\;: test&123", HttpStatus.SC_CREATED);
addUserWithPassword(URLEncoder.encode("$1aAAAAAAAac%!=\"/\\;: test&", "UTF-8"), "$1aAAAAAAAac%!=\\\"/\\\\;: test&123", HttpStatus.SC_BAD_REQUEST);

response = rh.executeGetRequest(PLUGINS_PREFIX + "/api/internalusers/nothinghthere?pretty", new Header[0]);
Assert.assertEquals(HttpStatus.SC_NOT_FOUND, response.getStatusCode());
Expand Down Expand Up @@ -641,6 +645,29 @@ public void testUserApiForNonSuperAdmin() throws Exception {

}

@Test
public void restrictedUsernameContents() throws Exception {
setup();

rh.keystore = "restapi/kirk-keystore.jks";
rh.sendAdminCertificate = true;

RESTRICTED_FROM_USERNAME.stream().forEach(restrictedTerm -> {
final String username = "nag" + restrictedTerm + "ilum";
final String url = ENDPOINT + "/internalusers/" + username;
final String bodyWithDefaultPasswordHash = "{\"hash\": \"456\"}";
HttpResponse response = null;
try {
response = rh.executePutRequest(url, bodyWithDefaultPasswordHash);
} catch (final Exception e) {
Assert.fail("Unexpected exception " + e);
}
Assert.assertNotNull("Should have a non-null response object", response);
assertThat("Expected " + username + " to be rejected", response.getStatusCode(), equalTo(HttpStatus.SC_BAD_REQUEST));
assertThat(response.getBody(), containsString(restrictedTerm));
});
}

@Test
public void checkNullElementsInArray() throws Exception{
setup();
Expand Down

0 comments on commit 691cd67

Please sign in to comment.