-
Notifications
You must be signed in to change notification settings - Fork 3.8k
/
Copy pathauthentication.go
83 lines (76 loc) · 3.01 KB
/
authentication.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
// Copyright 2021 The Cockroach Authors.
//
// Licensed as a CockroachDB Enterprise file under the Cockroach Community
// License (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// https://github.com/cockroachdb/cockroach/blob/master/licenses/CCL.txt
package sqlproxyccl
import (
"net"
"github.com/jackc/pgproto3/v2"
)
// Authenticate handles the startup of the pgwire protocol to the point where
// the connections is considered authenticated. If that doesn't happen, it
// returns an error.
var Authenticate = func(clientConn, crdbConn net.Conn) error {
fe := pgproto3.NewBackend(pgproto3.NewChunkReader(clientConn), clientConn)
be := pgproto3.NewFrontend(pgproto3.NewChunkReader(crdbConn), crdbConn)
// The auth step should require only a few back and forths so 20 iterations
// should be enough.
var i int
for ; i < 20; i++ {
// Read the server response and forward it to the client.
// TODO(spaskob): in verbose mode, log these messages.
backendMsg, err := be.Receive()
if err != nil {
return NewErrorf(CodeBackendReadFailed, "unable to receive message from backend: %v", err)
}
err = fe.Send(backendMsg)
if err != nil {
return NewErrorf(
CodeClientWriteFailed, "unable to send message %v to client: %v", backendMsg, err,
)
}
// Decide what to do based on the type of the server response.
switch tp := backendMsg.(type) {
case *pgproto3.ReadyForQuery:
// Server has authenticated the connection successfully and is ready to
// serve queries.
return nil
case *pgproto3.AuthenticationOk:
// Server has authenticated the connection; keep reading messages until
// `pgproto3.ReadyForQuery` is encountered which signifies that server
// is ready to serve queries.
case *pgproto3.ParameterStatus:
// Server sent status message; keep reading messages until
// `pgproto3.ReadyForQuery` is encountered.
case *pgproto3.BackendKeyData:
// Server sent backend key data; keep reading messages until
// `pgproto3.ReadyForQuery` is encountered.
case *pgproto3.ErrorResponse:
// Server has rejected the authentication response from the client and
// has closed the connection.
return NewErrorf(CodeAuthFailed, "authentication failed: %v", backendMsg)
case
*pgproto3.AuthenticationCleartextPassword,
*pgproto3.AuthenticationMD5Password,
*pgproto3.AuthenticationSASL:
// The backend is requesting the user to authenticate.
// Read the client response and forward it to server.
fntMsg, err := fe.Receive()
if err != nil {
return NewErrorf(CodeClientReadFailed, "unable to receive message from client: %v", err)
}
err = be.Send(fntMsg)
if err != nil {
return NewErrorf(
CodeBackendWriteFailed, "unable to send message %v to backend: %v", fntMsg, err,
)
}
default:
return NewErrorf(CodeBackendDisconnected, "received unexpected backend message type: %v", tp)
}
}
return NewErrorf(CodeBackendDisconnected, "authentication took more than %d iterations", i)
}