Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
DATAMONGO-1257 - <mongo:mongo-client /> element now supports username…
…s with a comma.

We now allow grouping credentials by enclosing them in single quotes like this:

credentials='CN=myName,OU=myOrgUnit,O=myOrg,L=myLocality,ST=myState,C=myCountry?uri.authMechanism=MONGODB-X509'

We also changed the required argument checks to be more authentication mechanism specific which means the pattern is now username[:password@database][?options].

Original pull request: #310.
  • Loading branch information
christophstrobl authored and odrotbohm committed Jul 24, 2015
1 parent 594e907 commit bebd0fa
Show file tree
Hide file tree
Showing 2 changed files with 154 additions and 7 deletions.
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'!");
}
}
}
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();
}
}

0 comments on commit bebd0fa

Please sign in to comment.