1616
1717package com .mongodb .connection ;
1818
19+ import com .mongodb .AuthenticationMechanism ;
1920import com .mongodb .MongoCredential ;
2021import com .mongodb .ServerAddress ;
22+ import com .mongodb .internal .authentication .SaslPrep ;
2123import org .bson .internal .Base64 ;
2224
2325import javax .crypto .Mac ;
2931import java .security .MessageDigest ;
3032import java .security .NoSuchAlgorithmException ;
3133import java .security .SecureRandom ;
34+ import java .util .Collections ;
3235import java .util .HashMap ;
36+ import java .util .LinkedHashMap ;
37+ import java .util .Map ;
3338import java .util .Random ;
3439
40+ import static com .mongodb .AuthenticationMechanism .SCRAM_SHA_1 ;
41+ import static com .mongodb .AuthenticationMechanism .SCRAM_SHA_256 ;
3542import static com .mongodb .internal .authentication .NativeAuthenticationHelper .createAuthenticationHash ;
3643import static java .lang .String .format ;
3744
3845class ScramShaAuthenticator extends SaslAuthenticator {
3946 private final RandomStringGenerator randomStringGenerator ;
4047 private final AuthenticationHashGenerator authenticationHashGenerator ;
48+
4149 private static final int MINIMUM_ITERATION_COUNT = 4096 ;
4250
4351 ScramShaAuthenticator (final MongoCredential credential ) {
44- this (credential , new DefaultRandomStringGenerator (), AUTHENTICATION_HASH_GENERATOR );
52+ this (credential , new DefaultRandomStringGenerator (), getAuthenicationHashGenerator ( credential . getAuthenticationMechanism ()) );
4553 }
4654
4755 ScramShaAuthenticator (final MongoCredential credential , final RandomStringGenerator randomStringGenerator ) {
48- this (credential , randomStringGenerator , AUTHENTICATION_HASH_GENERATOR );
56+ this (credential , randomStringGenerator , getAuthenicationHashGenerator ( credential . getAuthenticationMechanism ()) );
4957 }
5058
5159 ScramShaAuthenticator (final MongoCredential credential , final RandomStringGenerator randomStringGenerator ,
@@ -87,8 +95,13 @@ static class ScramShaSaslClient implements SaslClient {
8795 this .credential = credential ;
8896 this .randomStringGenerator = randomStringGenerator ;
8997 this .authenticationHashGenerator = authenticationHashGenerator ;
90- hAlgorithm = "SHA-1" ;
91- hmacAlgorithm = "HmacSHA1" ;
98+ if (credential .getAuthenticationMechanism ().equals (SCRAM_SHA_1 )) {
99+ hAlgorithm = "SHA-1" ;
100+ hmacAlgorithm = "HmacSHA1" ;
101+ } else {
102+ hAlgorithm = "SHA-256" ;
103+ hmacAlgorithm = "HmacSHA256" ;
104+ }
92105 }
93106
94107 public String getMechanismName () {
@@ -122,7 +135,7 @@ private byte[] validateServerSignature(final byte[] challenge) throws SaslExcept
122135 }
123136
124137 public boolean isComplete () {
125- return step == 3 ;
138+ return step == 2 ;
126139 }
127140
128141 public byte [] unwrap (final byte [] incoming , final int offset , final int len ) {
@@ -280,11 +293,19 @@ private HashMap<String, String> parseServerResponse(final String response) {
280293 }
281294
282295 private String getUserName () {
283- return credential .getUserName ().replace ("=" , "=3D" ).replace ("," , "=2C" );
296+ String userName = credential .getUserName ().replace ("=" , "=3D" ).replace ("," , "=2C" );
297+ if (credential .getAuthenticationMechanism () == SCRAM_SHA_256 ) {
298+ userName = SaslPrep .saslPrepStored (userName );
299+ }
300+ return userName ;
284301 }
285302
286303 private String getAuthenicationHash () {
287- return authenticationHashGenerator .generate (credential );
304+ String password = authenticationHashGenerator .generate (credential );
305+ if (credential .getAuthenticationMechanism () == SCRAM_SHA_256 ) {
306+ password = SaslPrep .saslPrepStored (password );
307+ }
308+ return password ;
288309 }
289310
290311 private byte [] xorInPlace (final byte [] a , final byte [] b ) {
@@ -330,7 +351,16 @@ public String generate(final int length) {
330351 }
331352 }
332353
333- private static final AuthenticationHashGenerator AUTHENTICATION_HASH_GENERATOR = new AuthenticationHashGenerator () {
354+ private static final AuthenticationHashGenerator DEFAULT_AUTHENTICATION_HASH_GENERATOR = new AuthenticationHashGenerator () {
355+ // Suppress warning of MongoCredential#getAuthenicationHash possibly returning null
356+ @ SuppressWarnings ("ConstantConditions" )
357+ @ Override
358+ public String generate (final MongoCredential credential ) {
359+ return new String (credential .getPassword ());
360+ }
361+ };
362+
363+ private static final AuthenticationHashGenerator LEGACY_AUTHENTICATION_HASH_GENERATOR = new AuthenticationHashGenerator () {
334364 // Suppress warning of MongoCredential#getAuthenicationHash possibly returning null
335365 @ SuppressWarnings ("ConstantConditions" )
336366 @ Override
@@ -339,4 +369,8 @@ public String generate(final MongoCredential credential) {
339369 return createAuthenticationHash (credential .getUserName (), credential .getPassword ());
340370 }
341371 };
372+
373+ private static AuthenticationHashGenerator getAuthenicationHashGenerator (final AuthenticationMechanism authenticationMechanism ) {
374+ return authenticationMechanism == SCRAM_SHA_1 ? LEGACY_AUTHENTICATION_HASH_GENERATOR : DEFAULT_AUTHENTICATION_HASH_GENERATOR ;
375+ }
342376}
0 commit comments