Skip to content

Commit d4aed64

Browse files
author
Simon MacMullen
committed
Add our slightly flaky demo challenge-response mechanism.
1 parent 30c499c commit d4aed64

File tree

1 file changed

+66
-0
lines changed

1 file changed

+66
-0
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package com.rabbitmq.client.impl;
2+
3+
import com.rabbitmq.client.AMQP;
4+
import com.rabbitmq.client.AuthMechanism;
5+
import com.rabbitmq.client.ConnectionFactory;
6+
import com.rabbitmq.client.ShutdownSignalException;
7+
8+
import java.io.IOException;
9+
import java.security.MessageDigest;
10+
import java.security.NoSuchAlgorithmException;
11+
import java.util.Arrays;
12+
13+
/**
14+
START-OK: Username
15+
SECURE: {Salt1, Salt2} (where Salt1 is the salt from the db and
16+
Salt2 differs every time)
17+
SECURE-OK: md5(Salt2 ++ md5(Salt1 ++ Password))
18+
19+
The second salt is there to defend against replay attacks. The
20+
first is needed since the passwords are salted in the db.
21+
22+
This is only somewhat improved security over PLAIN (if you can
23+
break MD5 you can still replay attack) but it's better than nothing
24+
and mostly there to prove the use of SECURE / SECURE-OK frames.
25+
*/
26+
27+
public class ScramMD5Mechanism implements AuthMechanism {
28+
public AMQP.Connection.Tune doLogin(AMQChannel channel,
29+
ConnectionFactory factory) throws IOException {
30+
try {
31+
LongString resp1 = LongStringHelper.asLongString(factory.getUsername());
32+
AMQImpl.Connection.StartOk startOk =
33+
new AMQImpl.Connection.StartOk(factory.getClientProperties(), getName(),
34+
resp1, "en_US");
35+
AMQP.Connection.Secure secure =
36+
(AMQP.Connection.Secure) channel.rpc(startOk).getMethod();
37+
byte[] challenge = secure.getChallenge().getBytes();
38+
byte[] salt1 = Arrays.copyOfRange(challenge, 0, 4);
39+
byte[] salt2 = Arrays.copyOfRange(challenge, 4, 8);
40+
41+
MessageDigest digest1 = MessageDigest.getInstance("MD5");
42+
MessageDigest digest2 = MessageDigest.getInstance("MD5");
43+
byte[] d1 = digest1.digest(concat(salt1, factory.getPassword().getBytes("utf-8")));
44+
byte[] d2 = digest2.digest(concat(salt2, d1));
45+
46+
AMQImpl.Connection.SecureOk secureOk =
47+
new AMQImpl.Connection.SecureOk(LongStringHelper.asLongString(d2));
48+
49+
return (AMQP.Connection.Tune) channel.rpc(secureOk).getMethod();
50+
} catch (NoSuchAlgorithmException e) {
51+
throw new RuntimeException(e);
52+
} catch (ShutdownSignalException e) {
53+
throw AMQChannel.wrap(e, "Possibly caused by authentication failure");
54+
}
55+
}
56+
57+
public String getName() {
58+
return "RABBIT-SCRAM-MD5";
59+
}
60+
61+
private static byte[] concat(byte[] first, byte[] second) {
62+
byte[] result = Arrays.copyOf(first, first.length + second.length);
63+
System.arraycopy(second, 0, result, first.length, second.length);
64+
return result;
65+
}
66+
}

0 commit comments

Comments
 (0)