Skip to content

DATAMONGO-1257 - mongo:mongo-client namespace does not support usernames with a comma. #310

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.8.0.BUILD-SNAPSHOT</version>
<version>1.8.0.DATAMONGO-1257-SNAPSHOT</version>
<packaging>pom</packaging>

<name>Spring Data MongoDB</name>
Expand Down
4 changes: 2 additions & 2 deletions spring-data-mongodb-cross-store/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.8.0.BUILD-SNAPSHOT</version>
<version>1.8.0.DATAMONGO-1257-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down Expand Up @@ -48,7 +48,7 @@
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>1.8.0.BUILD-SNAPSHOT</version>
<version>1.8.0.DATAMONGO-1257-SNAPSHOT</version>
</dependency>

<dependency>
Expand Down
2 changes: 1 addition & 1 deletion spring-data-mongodb-distribution/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.8.0.BUILD-SNAPSHOT</version>
<version>1.8.0.DATAMONGO-1257-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion spring-data-mongodb-log4j/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.8.0.BUILD-SNAPSHOT</version>
<version>1.8.0.DATAMONGO-1257-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion spring-data-mongodb/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>1.8.0.BUILD-SNAPSHOT</version>
<version>1.8.0.DATAMONGO-1257-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@

import java.beans.PropertyEditorSupport;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.springframework.util.StringUtils;

Expand All @@ -32,6 +35,8 @@
*/
public class MongoCredentialPropertyEditor extends PropertyEditorSupport {

private static final Pattern GROUP_PATTERN = Pattern.compile("(\\\\?')(.*?)\\1");

private static final String AUTH_MECHANISM_KEY = "uri.authMechanism";
private static final String USERNAME_PASSWORD_DELIMINATOR = ":";
private static final String DATABASE_DELIMINATOR = "@";
Expand All @@ -51,11 +56,7 @@ public void setAsText(String text) throws IllegalArgumentException {

List<MongoCredential> credentials = new ArrayList<MongoCredential>();

for (String credentialString : text.split(",")) {

if (!text.contains(USERNAME_PASSWORD_DELIMINATOR) || !text.contains(DATABASE_DELIMINATOR)) {
throw new IllegalArgumentException("Credentials need to be in format 'username:password@database'!");
}
for (String credentialString : extractCredentialsString(text)) {

String[] userNameAndPassword = extractUserNameAndPassword(credentialString);
String database = extractDB(credentialString);
Expand All @@ -68,16 +69,29 @@ public void setAsText(String text) throws IllegalArgumentException {
String authMechanism = options.getProperty(AUTH_MECHANISM_KEY);

if (MongoCredential.GSSAPI_MECHANISM.equals(authMechanism)) {

verifyUserNamePresent(userNameAndPassword);
credentials.add(MongoCredential.createGSSAPICredential(userNameAndPassword[0]));
} else if (MongoCredential.MONGODB_CR_MECHANISM.equals(authMechanism)) {

verifyUsernameAndPasswordPresent(userNameAndPassword);
verifyDatabasePresent(database);
credentials.add(MongoCredential.createMongoCRCredential(userNameAndPassword[0], database,
userNameAndPassword[1].toCharArray()));
} else if (MongoCredential.MONGODB_X509_MECHANISM.equals(authMechanism)) {

verifyUserNamePresent(userNameAndPassword);
credentials.add(MongoCredential.createMongoX509Credential(userNameAndPassword[0]));
} else if (MongoCredential.PLAIN_MECHANISM.equals(authMechanism)) {

verifyUsernameAndPasswordPresent(userNameAndPassword);
verifyDatabasePresent(database);
credentials.add(MongoCredential.createPlainCredential(userNameAndPassword[0], database,
userNameAndPassword[1].toCharArray()));
} else if (MongoCredential.SCRAM_SHA_1_MECHANISM.equals(authMechanism)) {

verifyUsernameAndPasswordPresent(userNameAndPassword);
verifyDatabasePresent(database);
credentials.add(MongoCredential.createScramSha1Credential(userNameAndPassword[0], database,
userNameAndPassword[1].toCharArray()));
} else {
Expand All @@ -86,6 +100,9 @@ public void setAsText(String text) throws IllegalArgumentException {
}
}
} else {

verifyUsernameAndPasswordPresent(userNameAndPassword);
verifyDatabasePresent(database);
credentials.add(MongoCredential.createCredential(userNameAndPassword[0], database,
userNameAndPassword[1].toCharArray()));
}
Expand All @@ -94,17 +111,45 @@ public void setAsText(String text) throws IllegalArgumentException {
setValue(credentials);
}

private List<String> extractCredentialsString(String source) {

Matcher matcher = GROUP_PATTERN.matcher(source);

List<String> list = new ArrayList<String>();
while (matcher.find()) {

String value = StringUtils.trimLeadingCharacter(matcher.group(), '\'');
list.add(StringUtils.trimTrailingCharacter(value, '\''));
}

if (!list.isEmpty()) {
return list;
}
return Arrays.asList(source.split(","));
}

private static String[] extractUserNameAndPassword(String text) {

int dbSeperationIndex = text.lastIndexOf(DATABASE_DELIMINATOR);
String userNameAndPassword = text.substring(0, dbSeperationIndex);
int index = text.lastIndexOf(DATABASE_DELIMINATOR);

if (index == -1) {
index = text.lastIndexOf(OPTIONS_DELIMINATOR);
}
if (index == -1) {
return new String[] {};
}
String userNameAndPassword = text.substring(0, index);
return userNameAndPassword.split(USERNAME_PASSWORD_DELIMINATOR);
}

private static String extractDB(String text) {

int dbSeperationIndex = text.lastIndexOf(DATABASE_DELIMINATOR);

if (dbSeperationIndex == -1) {
return "";
}

String tmp = text.substring(dbSeperationIndex + 1);
int optionsSeperationIndex = tmp.lastIndexOf(OPTIONS_DELIMINATOR);

Expand All @@ -129,4 +174,27 @@ private static Properties extractOptions(String text) {

return properties;
}

private void verifyUserNamePresent(String[] source) {

if (source.length == 0 || !StringUtils.hasText(source[0])) {
throw new IllegalArgumentException("Credentials need to specify username!");
}
}

private void verifyUsernameAndPasswordPresent(String[] source) {

verifyUserNamePresent(source);
if (source.length != 2) {
throw new IllegalArgumentException(
"Credentials need to specify username and password like in 'username:password@database'!");
}
}

private void verifyDatabasePresent(String source) {

if (!StringUtils.hasText(source)) {
throw new IllegalArgumentException("Credentials need to specify database like in 'username:password@database'!");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,19 @@ public class MongoCredentialPropertyEditorUnitTests {
static final String USER_2_PWD = "warg";
static final String USER_2_DB = "snow";

static final String USER_3_NAME = "CN=myName,OU=myOrgUnit,O=myOrg,L=myLocality,ST=myState,C=myCountry";
static final String USER_3_DB = "stark";

static final String USER_1_AUTH_STRING = USER_1_NAME + ":" + USER_1_PWD + "@" + USER_1_DB;
static final String USER_1_AUTH_STRING_WITH_PLAIN_AUTH_MECHANISM = USER_1_AUTH_STRING + "?uri.authMechanism=PLAIN";

static final String USER_2_AUTH_STRING = USER_2_NAME + ":" + USER_2_PWD + "@" + USER_2_DB;
static final String USER_2_AUTH_STRING_WITH_MONGODB_CR_AUTH_MECHANISM = USER_2_AUTH_STRING
+ "?uri.authMechanism=MONGODB-CR";

static final String USER_3_AUTH_STRING_WITH_X509_AUTH_MECHANISM = "'" + USER_3_NAME + "@" + USER_3_DB
+ "?uri.authMechanism=MONGODB-X509'";

static final MongoCredential USER_1_CREDENTIALS = MongoCredential.createCredential(USER_1_NAME, USER_1_DB,
USER_1_PWD.toCharArray());
static final MongoCredential USER_1_CREDENTIALS_PLAIN_AUTH = MongoCredential.createPlainCredential(USER_1_NAME,
Expand All @@ -60,6 +66,8 @@ public class MongoCredentialPropertyEditorUnitTests {
static final MongoCredential USER_2_CREDENTIALS_CR_AUTH = MongoCredential.createMongoCRCredential(USER_2_NAME,
USER_2_DB, USER_2_PWD.toCharArray());

static final MongoCredential USER_3_CREDENTIALS_X509_AUTH = MongoCredential.createMongoX509Credential(USER_3_NAME);

MongoCredentialPropertyEditor editor;

@Before
Expand Down Expand Up @@ -168,4 +176,75 @@ public void shouldReturnCredentialsValueCorrectlyWhenGivenMultipleUserNamePasswo

assertThat((List<MongoCredential>) editor.getValue(), contains(USER_1_CREDENTIALS_PLAIN_AUTH, USER_2_CREDENTIALS));
}

/**
* @see DATAMONGO-1257
*/
@Test
@SuppressWarnings("unchecked")
public void shouldReturnCredentialsValueCorrectlyWhenGivenMultipleQuotedUserNamePasswordStringWithDatabaseAndNoOptions() {

editor.setAsText(StringUtils.collectionToCommaDelimitedString(Arrays.asList("'" + USER_1_AUTH_STRING + "'", "'"
+ USER_2_AUTH_STRING + "'")));

assertThat((List<MongoCredential>) editor.getValue(), contains(USER_1_CREDENTIALS, USER_2_CREDENTIALS));
}

/**
* @see DATAMONGO-1257
*/
@Test
@SuppressWarnings("unchecked")
public void shouldReturnCredentialsValueCorrectlyWhenGivenSingleQuotedUserNamePasswordStringWithDatabaseAndNoOptions() {

editor.setAsText("'" + USER_1_AUTH_STRING + "'");

assertThat((List<MongoCredential>) editor.getValue(), contains(USER_1_CREDENTIALS));
}

/**
* @see DATAMONGO-1257
*/
@Test
@SuppressWarnings("unchecked")
public void shouldReturnX509CredentialsCorrectly() {

editor.setAsText(USER_3_AUTH_STRING_WITH_X509_AUTH_MECHANISM);

assertThat((List<MongoCredential>) editor.getValue(), contains(USER_3_CREDENTIALS_X509_AUTH));
}

/**
* @see DATAMONGO-1257
*/
@Test
@SuppressWarnings("unchecked")
public void shouldReturnX509CredentialsCorrectlyWhenNoDbSpecified() {

editor.setAsText("tyrion?uri.authMechanism=MONGODB-X509");

assertThat((List<MongoCredential>) editor.getValue(), contains(MongoCredential.createMongoX509Credential("tyrion")));
}

/**
* @see DATAMONGO-1257
*/
@Test(expected = IllegalArgumentException.class)
public void shouldThrowExceptionWhenNoDbSpecifiedForMongodbCR() {

editor.setAsText("tyrion?uri.authMechanism=MONGODB-CR");

editor.getValue();
}

/**
* @see DATAMONGO-1257
*/
@Test(expected = IllegalArgumentException.class)
public void shouldThrowExceptionWhenDbIsEmptyForMongodbCR() {

editor.setAsText("tyrion@?uri.authMechanism=MONGODB-CR");

editor.getValue();
}
}