Skip to content

Commit 1699374

Browse files
committed
authentication support for guassdb
1 parent 0947ac8 commit 1699374

File tree

7 files changed

+482
-37
lines changed

7 files changed

+482
-37
lines changed

src/main/java/io/r2dbc/postgresql/authentication/PasswordAuthenticationHandler.java

+12-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@
1919
import io.r2dbc.postgresql.message.backend.AuthenticationCleartextPassword;
2020
import io.r2dbc.postgresql.message.backend.AuthenticationMD5Password;
2121
import io.r2dbc.postgresql.message.backend.AuthenticationMessage;
22+
import io.r2dbc.postgresql.message.backend.AuthenticationSHA256Password;
2223
import io.r2dbc.postgresql.message.frontend.FrontendMessage;
2324
import io.r2dbc.postgresql.message.frontend.PasswordMessage;
25+
import io.r2dbc.postgresql.message.frontend.SHA256PasswordMessage;
2426
import io.r2dbc.postgresql.util.Assert;
2527

2628
/**
@@ -54,7 +56,9 @@ public PasswordAuthenticationHandler(CharSequence password, String username) {
5456
public static boolean supports(AuthenticationMessage message) {
5557
Assert.requireNonNull(message, "message must not be null");
5658

57-
return message instanceof AuthenticationCleartextPassword || message instanceof AuthenticationMD5Password;
59+
return message instanceof AuthenticationCleartextPassword
60+
|| message instanceof AuthenticationMD5Password
61+
|| message instanceof AuthenticationSHA256Password;
5862
}
5963

6064
@Override
@@ -65,12 +69,18 @@ public FrontendMessage handle(AuthenticationMessage message) {
6569
return handleAuthenticationClearTextPassword();
6670
} else if (message instanceof AuthenticationMD5Password) {
6771
return handleAuthenticationMD5Password((AuthenticationMD5Password) message);
72+
} else if (message instanceof AuthenticationSHA256Password) {
73+
return handleAuthenticationSHA256Password((AuthenticationSHA256Password) message);
6874
} else {
6975
throw new IllegalArgumentException(String.format("Cannot handle %s message", message.getClass().getSimpleName()));
7076
}
7177
}
7278

73-
private PasswordMessage handleAuthenticationClearTextPassword() {
79+
private FrontendMessage handleAuthenticationSHA256Password(AuthenticationSHA256Password message) {
80+
return new SHA256PasswordMessage(this.username, this.password, message);
81+
}
82+
83+
private PasswordMessage handleAuthenticationClearTextPassword() {
7484
return new PasswordMessage(this.password);
7585
}
7686

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright 2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.r2dbc.postgresql.message.backend;
18+
19+
import io.netty.buffer.ByteBuf;
20+
import io.r2dbc.postgresql.util.Assert;
21+
import io.r2dbc.postgresql.util.ByteBufferUtils;
22+
23+
import java.nio.ByteBuffer;
24+
25+
/**
26+
* The AuthenticationSHA256Password message.
27+
*/
28+
public final class AuthenticationSHA256Password implements AuthenticationMessage {
29+
public static final int PLAIN_PASSWORD = 0;
30+
31+
public static final int MD5_PASSWORD = 1;
32+
33+
public static final int SHA256_PASSWORD = 2;
34+
35+
private final int passwordStoredMethod;
36+
37+
private ByteBuffer randomCode;
38+
39+
private ByteBuffer token;
40+
41+
private ByteBuffer iteration;
42+
43+
private ByteBuffer md5Salt;
44+
45+
/**
46+
* Create a new message.
47+
*
48+
* @throws IllegalArgumentException if {@code authenticationMechanisms} is {@code null}
49+
*/
50+
public AuthenticationSHA256Password(int passwordStoredMethod, ByteBuffer randomCode, ByteBuffer token, ByteBuffer iteration) {
51+
this.passwordStoredMethod = passwordStoredMethod;
52+
this.randomCode = randomCode;
53+
this.token = token;
54+
this.iteration = iteration;
55+
}
56+
57+
public AuthenticationSHA256Password(int passwordStoredMethod, ByteBuffer md5Salt) {
58+
this.passwordStoredMethod = passwordStoredMethod;
59+
this.md5Salt = md5Salt;
60+
}
61+
62+
public ByteBuffer getRandomCode() {
63+
return this.randomCode;
64+
}
65+
66+
public ByteBuffer getToken() {
67+
return this.token;
68+
}
69+
70+
public ByteBuffer getIteration() {
71+
return iteration;
72+
}
73+
74+
public ByteBuffer getMd5Salt() {
75+
return this.md5Salt;
76+
}
77+
78+
public int getPasswordStoredMethod() {
79+
return this.passwordStoredMethod;
80+
}
81+
82+
static AuthenticationSHA256Password decode(ByteBuf in) {
83+
Assert.requireNonNull(in, "in must not be null");
84+
85+
int passwordStoredMethod = in.readInt();
86+
if (passwordStoredMethod == PLAIN_PASSWORD || passwordStoredMethod == SHA256_PASSWORD) {
87+
return new AuthenticationSHA256Password(passwordStoredMethod,
88+
ByteBufferUtils.toByteBuffer(in.readSlice(64)),
89+
ByteBufferUtils.toByteBuffer(in.readSlice(8)),
90+
ByteBufferUtils.toByteBuffer(in.readSlice(4)));
91+
} else if(passwordStoredMethod == MD5_PASSWORD) {
92+
return new AuthenticationSHA256Password(passwordStoredMethod, ByteBufferUtils.toByteBuffer(in.readSlice(4)));
93+
}
94+
throw new IllegalArgumentException(String.format("%s is not a supported password stored method.", passwordStoredMethod));
95+
}
96+
97+
}

src/main/java/io/r2dbc/postgresql/message/backend/BackendMessageDecoder.java

+3-7
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,8 @@ private static BackendMessage decodeAuthentication(ByteBuf in) {
110110
return AuthenticationMD5Password.decode(in);
111111
case SCMC_CREDENTIAL:
112112
return AuthenticationSCMCredential.INSTANCE;
113-
case SASL:
114-
return AuthenticationSASL.decode(in);
115-
case SASL_CONTINUE:
116-
return AuthenticationSASLContinue.decode(in);
117-
case SASL_FINAL:
118-
return AuthenticationSASLFinal.decode(in);
113+
case SHA256_PASSWORD:
114+
return AuthenticationSHA256Password.decode(in);
119115
case SSPI:
120116
return AuthenticationSSPI.INSTANCE;
121117
default:
@@ -132,7 +128,7 @@ private enum AuthenticationType {
132128
GSS_CONTINUE(8),
133129
MD5_PASSWORD(5),
134130
SCMC_CREDENTIAL(6),
135-
SASL(10),
131+
SHA256_PASSWORD(10),
136132
SASL_CONTINUE(11),
137133
SASL_FINAL(12),
138134
SSPI(9);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Copyright 2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.r2dbc.postgresql.message.frontend;
18+
19+
import io.netty.buffer.ByteBuf;
20+
import io.netty.buffer.ByteBufAllocator;
21+
import io.r2dbc.postgresql.message.backend.AuthenticationSHA256Password;
22+
import io.r2dbc.postgresql.util.Assert;
23+
import io.r2dbc.postgresql.util.MD5Digest;
24+
import org.reactivestreams.Publisher;
25+
import reactor.core.publisher.Mono;
26+
27+
import java.nio.ByteBuffer;
28+
import java.nio.charset.StandardCharsets;
29+
30+
import static io.r2dbc.postgresql.message.frontend.FrontendMessageUtils.writeByte;
31+
import static io.r2dbc.postgresql.message.frontend.FrontendMessageUtils.writeBytes;
32+
import static io.r2dbc.postgresql.message.frontend.FrontendMessageUtils.writeInt;
33+
34+
/**
35+
* The SHA256PasswordMessage message.
36+
*/
37+
public final class SHA256PasswordMessage implements FrontendMessage {
38+
39+
private final CharSequence password;
40+
41+
private final String username;
42+
43+
private final AuthenticationSHA256Password authentication;
44+
45+
/**
46+
* Create a new message.
47+
*
48+
* @param password the password (encrypted, if requested)
49+
* @throws IllegalArgumentException if {@code password} is {@code null}
50+
*/
51+
public SHA256PasswordMessage(String username, CharSequence password, AuthenticationSHA256Password authentication) {
52+
this.username = Assert.requireNonNull(username, "username must not be null");
53+
this.password = Assert.requireNonNull(password, "password must not be null");
54+
this.authentication = Assert.requireNonNull(authentication, "authentication must not be null");
55+
}
56+
57+
@Override
58+
public Publisher<ByteBuf> encode(ByteBufAllocator byteBufAllocator) {
59+
Assert.requireNonNull(byteBufAllocator, "byteBufAllocator must not be null");
60+
61+
return Mono.fromSupplier(() -> {
62+
ByteBuf out = byteBufAllocator.ioBuffer();
63+
byte[] result;
64+
if (AuthenticationSHA256Password.SHA256_PASSWORD == authentication.getPasswordStoredMethod() ||
65+
AuthenticationSHA256Password.PLAIN_PASSWORD == authentication.getPasswordStoredMethod()) {
66+
String randomCode = new String(authentication.getRandomCode().array(), StandardCharsets.UTF_8);
67+
String token = new String(authentication.getToken().array(), StandardCharsets.UTF_8);
68+
int iteration = authentication.getIteration().getInt();
69+
result = MD5Digest.RFC5802Algorithm(String.valueOf(this.password), randomCode, token, iteration);
70+
} else {
71+
byte[] salt = authentication.getMd5Salt().array();
72+
result = MD5Digest.SHA256_MD5encode(username.getBytes(StandardCharsets.UTF_8),
73+
String.valueOf(this.password).getBytes(StandardCharsets.UTF_8), salt);
74+
}
75+
writeByte(out, 'p');
76+
writeInt(out, 4 + result.length + 1);
77+
writeBytes(out, ByteBuffer.wrap(result));
78+
return writeByte(out, 0);
79+
});
80+
}
81+
}

src/main/java/io/r2dbc/postgresql/message/frontend/StartupMessage.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ public Publisher<ByteBuf> encode(ByteBufAllocator byteBufAllocator) {
8787
ByteBuf out = byteBufAllocator.ioBuffer();
8888

8989
writeLengthPlaceholder(out);
90-
writeShort(out, 3, 0);
90+
writeShort(out, 3, 51);
9191
writeParameter(out, USER, this.username);
9292

9393
if (this.database != null) {

0 commit comments

Comments
 (0)