Skip to content

Commit 0cac416

Browse files
committed
JAVA-497: authenticate/getnonce commands always use ReadPreference.primaryPreferred, so that authentication doesn't fail if connected to a replica set with no primary available
1 parent 74307b6 commit 0cac416

File tree

3 files changed

+64
-29
lines changed

3 files changed

+64
-29
lines changed

src/main/com/mongodb/DB.java

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -69,20 +69,33 @@ public DB( Mongo mongo , String name ){
6969
* @return true if the command is obedient
7070
* @see com.mongodb.ReadPreference
7171
*/
72-
boolean obeyReadPreference(DBObject command){
72+
ReadPreference getCommandReadPreference(DBObject command, ReadPreference requestedPreference){
7373
String comString = command.keySet().iterator().next();
7474

75+
if (comString.equals("getnonce") || comString.equals("authenticate")) {
76+
return ReadPreference.primaryPreferred();
77+
}
78+
79+
boolean primaryRequired;
80+
7581
// explicitly check mapreduce commands are inline
7682
if(comString.equals("mapreduce")) {
7783
Object out = command.get("out");
7884
if (out instanceof BSONObject ){
7985
BSONObject outMap = (BSONObject) out;
80-
return outMap.get("inline") != null;
86+
primaryRequired = outMap.get("inline") == null;
8187
}
8288
else
83-
return false;
89+
primaryRequired = true;
90+
} else {
91+
primaryRequired = !_obedientCommands.contains(comString);
92+
}
93+
94+
if (primaryRequired) {
95+
return ReadPreference.primary();
96+
} else {
97+
return requestedPreference;
8498
}
85-
return (_obedientCommands.contains(comString));
8699
}
87100

88101
/**
@@ -241,8 +254,7 @@ public CommandResult command( DBObject cmd , int options, ReadPreference readPre
241254
*/
242255
public CommandResult command( DBObject cmd , int options, ReadPreference readPrefs, DBEncoder encoder ){
243256

244-
if ( !obeyReadPreference(cmd) )
245-
readPrefs = ReadPreference.primary();
257+
readPrefs = getCommandReadPreference(cmd, readPrefs);
246258

247259
Iterator<DBObject> i =
248260
getCollection("$cmd").__find(cmd, new BasicDBObject(), 0, -1, 0, options, readPrefs ,
@@ -535,7 +547,7 @@ public void dropDatabase(){
535547
* @dochub authenticate
536548
*/
537549
public boolean isAuthenticated() {
538-
return authorizationCredentialsReference.get() != null;
550+
return authenticationCredentialsReference.get() != null;
539551
}
540552

541553
/**
@@ -549,16 +561,16 @@ public boolean isAuthenticated() {
549561
*/
550562
public boolean authenticate(String username, char[] password ){
551563

552-
if (authorizationCredentialsReference.get() != null) {
564+
if (authenticationCredentialsReference.get() != null) {
553565
throw new IllegalStateException("can't authenticate twice on the same database");
554566
}
555567

556-
AuthorizationCredentials newCredentials = new AuthorizationCredentials(username, password);
557-
CommandResult res = newCredentials.authorize();
568+
AuthenticationCredentials newCredentials = new AuthenticationCredentials(username, password);
569+
CommandResult res = newCredentials.authenticate();
558570
if (!res.ok())
559571
return false;
560572

561-
boolean wasNull = authorizationCredentialsReference.compareAndSet(null, newCredentials);
573+
boolean wasNull = authenticationCredentialsReference.compareAndSet(null, newCredentials);
562574
if (!wasNull) {
563575
throw new IllegalStateException("can't authenticate twice on the same database");
564576
}
@@ -576,14 +588,14 @@ public boolean authenticate(String username, char[] password ){
576588
*/
577589
public synchronized CommandResult authenticateCommand(String username, char[] password ){
578590

579-
if (authorizationCredentialsReference.get() != null) {
591+
if (authenticationCredentialsReference.get() != null) {
580592
throw new IllegalStateException( "can't authenticate twice on the same database" );
581593
}
582594

583-
AuthorizationCredentials newCredentials = new AuthorizationCredentials(username, password);
584-
CommandResult res = newCredentials.authorize();
595+
AuthenticationCredentials newCredentials = new AuthenticationCredentials(username, password);
596+
CommandResult res = newCredentials.authenticate();
585597
res.throwOnError();
586-
boolean wasNull = authorizationCredentialsReference.compareAndSet(null, newCredentials);
598+
boolean wasNull = authenticationCredentialsReference.compareAndSet(null, newCredentials);
587599
if (!wasNull) {
588600
throw new IllegalStateException("can't authenticate twice on the same database");
589601
}
@@ -745,8 +757,8 @@ public int getOptions(){
745757

746758
public abstract void cleanCursors( boolean force );
747759

748-
AuthorizationCredentials getAuthorizationCredentials() {
749-
return authorizationCredentialsReference.get();
760+
AuthenticationCredentials getAuthenticationCredentials() {
761+
return authenticationCredentialsReference.get();
750762
}
751763

752764
final Mongo _mongo;
@@ -757,17 +769,17 @@ AuthorizationCredentials getAuthorizationCredentials() {
757769
private com.mongodb.ReadPreference _readPref;
758770
final Bytes.OptionHolder _options;
759771

760-
private AtomicReference<AuthorizationCredentials> authorizationCredentialsReference =
761-
new AtomicReference<AuthorizationCredentials>();
772+
private AtomicReference<AuthenticationCredentials> authenticationCredentialsReference =
773+
new AtomicReference<AuthenticationCredentials>();
762774

763775
/**
764776
* Encapsulate everything relating to authorization of a user on a database
765777
*/
766-
class AuthorizationCredentials {
778+
class AuthenticationCredentials {
767779
private final String userName;
768780
private final byte[] authHash;
769781

770-
private AuthorizationCredentials(final String userName, final char[] password) {
782+
private AuthenticationCredentials(final String userName, final char[] password) {
771783
if (userName == null) {
772784
throw new IllegalArgumentException("userName can not be null");
773785
}
@@ -778,11 +790,16 @@ private AuthorizationCredentials(final String userName, final char[] password) {
778790
this.authHash = createHash(userName, password);
779791
}
780792

781-
CommandResult authorize() {
782-
CommandResult res = command(getNonceCommand());
783-
res.throwOnError();
793+
CommandResult authenticate() {
794+
requestStart();
795+
try {
796+
CommandResult res = command(getNonceCommand());
797+
res.throwOnError();
784798

785-
return command(getAuthCommand(res.getString("nonce")));
799+
return command(getAuthCommand(res.getString("nonce")));
800+
} finally {
801+
requestDone();
802+
}
786803
}
787804

788805
DBObject getAuthCommand( String nonce ){

src/main/com/mongodb/DBPort.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ protected void close(){
294294
}
295295

296296
void checkAuth( DB db ) throws IOException {
297-
DB.AuthorizationCredentials credentials = db.getAuthorizationCredentials();
297+
DB.AuthenticationCredentials credentials = db.getAuthenticationCredentials();
298298
if ( credentials == null ){
299299
if ( db._name.equals( "admin" ) )
300300
return;

src/test/com/mongodb/DBTest.java

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,31 @@ public void testForCollectionExistence()
9292
@Test(groups = {"basic"})
9393
public void testReadPreferenceObedience() {
9494
DBObject obj = new BasicDBObject("mapreduce", 1).append("out", "myColl");
95-
assertFalse(_db.obeyReadPreference(obj));
95+
assertEquals(ReadPreference.primary(), _db.getCommandReadPreference(obj, ReadPreference.secondary()));
9696

9797
obj = new BasicDBObject("mapreduce", 1).append("out", new BasicDBObject("replace", "myColl"));
98-
assertFalse(_db.obeyReadPreference(obj));
98+
assertEquals(ReadPreference.primary(), _db.getCommandReadPreference(obj, ReadPreference.secondary()));
9999

100100
obj = new BasicDBObject("mapreduce", 1).append("out", new BasicDBObject("inline", 1));
101-
assertTrue(_db.obeyReadPreference(obj));
101+
assertEquals(ReadPreference.secondary(), _db.getCommandReadPreference(obj, ReadPreference.secondary()));
102+
103+
obj = new BasicDBObject("mapreduce", 1).append("out", new BasicDBObject("inline", null));
104+
assertEquals(ReadPreference.primary(), _db.getCommandReadPreference(obj, ReadPreference.secondary()));
105+
106+
obj = new BasicDBObject("getnonce", 1);
107+
assertEquals(ReadPreference.primaryPreferred(), _db.getCommandReadPreference(obj, ReadPreference.secondary()));
108+
109+
obj = new BasicDBObject("authenticate", 1);
110+
assertEquals(ReadPreference.primaryPreferred(), _db.getCommandReadPreference(obj, ReadPreference.secondary()));
111+
112+
obj = new BasicDBObject("count", 1);
113+
assertEquals(ReadPreference.secondary(), _db.getCommandReadPreference(obj, ReadPreference.secondary()));
114+
115+
obj = new BasicDBObject("count", 1);
116+
assertEquals(ReadPreference.secondary(), _db.getCommandReadPreference(obj, ReadPreference.secondary()));
117+
118+
obj = new BasicDBObject("serverStatus", 1);
119+
assertEquals(ReadPreference.primary(), _db.getCommandReadPreference(obj, ReadPreference.secondary()));
102120
}
103121

104122
/*public static class Person extends DBObject {

0 commit comments

Comments
 (0)