Skip to content

Commit bebd0fa

Browse files
christophstroblodrotbohm
authored andcommitted
DATAMONGO-1257 - <mongo:mongo-client /> element now supports usernames 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: spring-projects#310.
1 parent 594e907 commit bebd0fa

File tree

2 files changed

+154
-7
lines changed

2 files changed

+154
-7
lines changed

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MongoCredentialPropertyEditor.java

Lines changed: 75 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,11 @@
1717

1818
import java.beans.PropertyEditorSupport;
1919
import java.util.ArrayList;
20+
import java.util.Arrays;
2021
import java.util.List;
2122
import java.util.Properties;
23+
import java.util.regex.Matcher;
24+
import java.util.regex.Pattern;
2225

2326
import org.springframework.util.StringUtils;
2427

@@ -32,6 +35,8 @@
3235
*/
3336
public class MongoCredentialPropertyEditor extends PropertyEditorSupport {
3437

38+
private static final Pattern GROUP_PATTERN = Pattern.compile("(\\\\?')(.*?)\\1");
39+
3540
private static final String AUTH_MECHANISM_KEY = "uri.authMechanism";
3641
private static final String USERNAME_PASSWORD_DELIMINATOR = ":";
3742
private static final String DATABASE_DELIMINATOR = "@";
@@ -51,11 +56,7 @@ public void setAsText(String text) throws IllegalArgumentException {
5156

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

54-
for (String credentialString : text.split(",")) {
55-
56-
if (!text.contains(USERNAME_PASSWORD_DELIMINATOR) || !text.contains(DATABASE_DELIMINATOR)) {
57-
throw new IllegalArgumentException("Credentials need to be in format 'username:password@database'!");
58-
}
59+
for (String credentialString : extractCredentialsString(text)) {
5960

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

7071
if (MongoCredential.GSSAPI_MECHANISM.equals(authMechanism)) {
72+
73+
verifyUserNamePresent(userNameAndPassword);
7174
credentials.add(MongoCredential.createGSSAPICredential(userNameAndPassword[0]));
7275
} else if (MongoCredential.MONGODB_CR_MECHANISM.equals(authMechanism)) {
76+
77+
verifyUsernameAndPasswordPresent(userNameAndPassword);
78+
verifyDatabasePresent(database);
7379
credentials.add(MongoCredential.createMongoCRCredential(userNameAndPassword[0], database,
7480
userNameAndPassword[1].toCharArray()));
7581
} else if (MongoCredential.MONGODB_X509_MECHANISM.equals(authMechanism)) {
82+
83+
verifyUserNamePresent(userNameAndPassword);
7684
credentials.add(MongoCredential.createMongoX509Credential(userNameAndPassword[0]));
7785
} else if (MongoCredential.PLAIN_MECHANISM.equals(authMechanism)) {
86+
87+
verifyUsernameAndPasswordPresent(userNameAndPassword);
88+
verifyDatabasePresent(database);
7889
credentials.add(MongoCredential.createPlainCredential(userNameAndPassword[0], database,
7990
userNameAndPassword[1].toCharArray()));
8091
} else if (MongoCredential.SCRAM_SHA_1_MECHANISM.equals(authMechanism)) {
92+
93+
verifyUsernameAndPasswordPresent(userNameAndPassword);
94+
verifyDatabasePresent(database);
8195
credentials.add(MongoCredential.createScramSha1Credential(userNameAndPassword[0], database,
8296
userNameAndPassword[1].toCharArray()));
8397
} else {
@@ -86,6 +100,9 @@ public void setAsText(String text) throws IllegalArgumentException {
86100
}
87101
}
88102
} else {
103+
104+
verifyUsernameAndPasswordPresent(userNameAndPassword);
105+
verifyDatabasePresent(database);
89106
credentials.add(MongoCredential.createCredential(userNameAndPassword[0], database,
90107
userNameAndPassword[1].toCharArray()));
91108
}
@@ -94,17 +111,45 @@ public void setAsText(String text) throws IllegalArgumentException {
94111
setValue(credentials);
95112
}
96113

114+
private List<String> extractCredentialsString(String source) {
115+
116+
Matcher matcher = GROUP_PATTERN.matcher(source);
117+
118+
List<String> list = new ArrayList<String>();
119+
while (matcher.find()) {
120+
121+
String value = StringUtils.trimLeadingCharacter(matcher.group(), '\'');
122+
list.add(StringUtils.trimTrailingCharacter(value, '\''));
123+
}
124+
125+
if (!list.isEmpty()) {
126+
return list;
127+
}
128+
return Arrays.asList(source.split(","));
129+
}
130+
97131
private static String[] extractUserNameAndPassword(String text) {
98132

99-
int dbSeperationIndex = text.lastIndexOf(DATABASE_DELIMINATOR);
100-
String userNameAndPassword = text.substring(0, dbSeperationIndex);
133+
int index = text.lastIndexOf(DATABASE_DELIMINATOR);
134+
135+
if (index == -1) {
136+
index = text.lastIndexOf(OPTIONS_DELIMINATOR);
137+
}
138+
if (index == -1) {
139+
return new String[] {};
140+
}
141+
String userNameAndPassword = text.substring(0, index);
101142
return userNameAndPassword.split(USERNAME_PASSWORD_DELIMINATOR);
102143
}
103144

104145
private static String extractDB(String text) {
105146

106147
int dbSeperationIndex = text.lastIndexOf(DATABASE_DELIMINATOR);
107148

149+
if (dbSeperationIndex == -1) {
150+
return "";
151+
}
152+
108153
String tmp = text.substring(dbSeperationIndex + 1);
109154
int optionsSeperationIndex = tmp.lastIndexOf(OPTIONS_DELIMINATOR);
110155

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

130175
return properties;
131176
}
177+
178+
private void verifyUserNamePresent(String[] source) {
179+
180+
if (source.length == 0 || !StringUtils.hasText(source[0])) {
181+
throw new IllegalArgumentException("Credentials need to specify username!");
182+
}
183+
}
184+
185+
private void verifyUsernameAndPasswordPresent(String[] source) {
186+
187+
verifyUserNamePresent(source);
188+
if (source.length != 2) {
189+
throw new IllegalArgumentException(
190+
"Credentials need to specify username and password like in 'username:password@database'!");
191+
}
192+
}
193+
194+
private void verifyDatabasePresent(String source) {
195+
196+
if (!StringUtils.hasText(source)) {
197+
throw new IllegalArgumentException("Credentials need to specify database like in 'username:password@database'!");
198+
}
199+
}
132200
}

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/config/MongoCredentialPropertyEditorUnitTests.java

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,19 @@ public class MongoCredentialPropertyEditorUnitTests {
4343
static final String USER_2_PWD = "warg";
4444
static final String USER_2_DB = "snow";
4545

46+
static final String USER_3_NAME = "CN=myName,OU=myOrgUnit,O=myOrg,L=myLocality,ST=myState,C=myCountry";
47+
static final String USER_3_DB = "stark";
48+
4649
static final String USER_1_AUTH_STRING = USER_1_NAME + ":" + USER_1_PWD + "@" + USER_1_DB;
4750
static final String USER_1_AUTH_STRING_WITH_PLAIN_AUTH_MECHANISM = USER_1_AUTH_STRING + "?uri.authMechanism=PLAIN";
4851

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

56+
static final String USER_3_AUTH_STRING_WITH_X509_AUTH_MECHANISM = "'" + USER_3_NAME + "@" + USER_3_DB
57+
+ "?uri.authMechanism=MONGODB-X509'";
58+
5359
static final MongoCredential USER_1_CREDENTIALS = MongoCredential.createCredential(USER_1_NAME, USER_1_DB,
5460
USER_1_PWD.toCharArray());
5561
static final MongoCredential USER_1_CREDENTIALS_PLAIN_AUTH = MongoCredential.createPlainCredential(USER_1_NAME,
@@ -60,6 +66,8 @@ public class MongoCredentialPropertyEditorUnitTests {
6066
static final MongoCredential USER_2_CREDENTIALS_CR_AUTH = MongoCredential.createMongoCRCredential(USER_2_NAME,
6167
USER_2_DB, USER_2_PWD.toCharArray());
6268

69+
static final MongoCredential USER_3_CREDENTIALS_X509_AUTH = MongoCredential.createMongoX509Credential(USER_3_NAME);
70+
6371
MongoCredentialPropertyEditor editor;
6472

6573
@Before
@@ -168,4 +176,75 @@ public void shouldReturnCredentialsValueCorrectlyWhenGivenMultipleUserNamePasswo
168176

169177
assertThat((List<MongoCredential>) editor.getValue(), contains(USER_1_CREDENTIALS_PLAIN_AUTH, USER_2_CREDENTIALS));
170178
}
179+
180+
/**
181+
* @see DATAMONGO-1257
182+
*/
183+
@Test
184+
@SuppressWarnings("unchecked")
185+
public void shouldReturnCredentialsValueCorrectlyWhenGivenMultipleQuotedUserNamePasswordStringWithDatabaseAndNoOptions() {
186+
187+
editor.setAsText(StringUtils.collectionToCommaDelimitedString(Arrays.asList("'" + USER_1_AUTH_STRING + "'", "'"
188+
+ USER_2_AUTH_STRING + "'")));
189+
190+
assertThat((List<MongoCredential>) editor.getValue(), contains(USER_1_CREDENTIALS, USER_2_CREDENTIALS));
191+
}
192+
193+
/**
194+
* @see DATAMONGO-1257
195+
*/
196+
@Test
197+
@SuppressWarnings("unchecked")
198+
public void shouldReturnCredentialsValueCorrectlyWhenGivenSingleQuotedUserNamePasswordStringWithDatabaseAndNoOptions() {
199+
200+
editor.setAsText("'" + USER_1_AUTH_STRING + "'");
201+
202+
assertThat((List<MongoCredential>) editor.getValue(), contains(USER_1_CREDENTIALS));
203+
}
204+
205+
/**
206+
* @see DATAMONGO-1257
207+
*/
208+
@Test
209+
@SuppressWarnings("unchecked")
210+
public void shouldReturnX509CredentialsCorrectly() {
211+
212+
editor.setAsText(USER_3_AUTH_STRING_WITH_X509_AUTH_MECHANISM);
213+
214+
assertThat((List<MongoCredential>) editor.getValue(), contains(USER_3_CREDENTIALS_X509_AUTH));
215+
}
216+
217+
/**
218+
* @see DATAMONGO-1257
219+
*/
220+
@Test
221+
@SuppressWarnings("unchecked")
222+
public void shouldReturnX509CredentialsCorrectlyWhenNoDbSpecified() {
223+
224+
editor.setAsText("tyrion?uri.authMechanism=MONGODB-X509");
225+
226+
assertThat((List<MongoCredential>) editor.getValue(), contains(MongoCredential.createMongoX509Credential("tyrion")));
227+
}
228+
229+
/**
230+
* @see DATAMONGO-1257
231+
*/
232+
@Test(expected = IllegalArgumentException.class)
233+
public void shouldThrowExceptionWhenNoDbSpecifiedForMongodbCR() {
234+
235+
editor.setAsText("tyrion?uri.authMechanism=MONGODB-CR");
236+
237+
editor.getValue();
238+
}
239+
240+
/**
241+
* @see DATAMONGO-1257
242+
*/
243+
@Test(expected = IllegalArgumentException.class)
244+
public void shouldThrowExceptionWhenDbIsEmptyForMongodbCR() {
245+
246+
editor.setAsText("tyrion@?uri.authMechanism=MONGODB-CR");
247+
248+
editor.getValue();
249+
}
171250
}

0 commit comments

Comments
 (0)