forked from vapor/postgres-nio
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPostgresMessage+Authentication.swift
119 lines (107 loc) · 4.94 KB
/
PostgresMessage+Authentication.swift
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import NIOCore
extension PostgresMessage {
/// Authentication request returned by the server.
@available(*, deprecated, message: "Will be removed from public API")
public enum Authentication: PostgresMessageType {
public static var identifier: PostgresMessage.Identifier {
return .authentication
}
/// Parses an instance of this message type from a byte buffer.
public static func parse(from buffer: inout ByteBuffer) throws -> Authentication {
guard let type = buffer.readInteger(as: Int32.self) else {
throw PostgresError.protocol("Could not read authentication message type")
}
switch type {
case 0: return .ok
case 3: return .plaintext
case 5:
guard let salt = buffer.readBytes(length: 4) else {
throw PostgresError.protocol("Could not parse MD5 salt from authentication message")
}
return .md5(salt)
case 10:
var mechanisms: [String] = []
while buffer.readableBytes > 0 {
guard let nextString = buffer.readNullTerminatedString() else {
throw PostgresError.protocol("Could not parse SASL mechanisms from authentication message")
}
if nextString.isEmpty {
break
}
mechanisms.append(nextString)
}
guard buffer.readableBytes == 0 else {
throw PostgresError.protocol("Trailing data at end of SASL mechanisms authentication message")
}
return .saslMechanisms(mechanisms)
case 11:
guard let challengeData = buffer.readBytes(length: buffer.readableBytes) else {
throw PostgresError.protocol("Could not parse SASL challenge from authentication message")
}
return .saslContinue(challengeData)
case 12:
guard let finalData = buffer.readBytes(length: buffer.readableBytes) else {
throw PostgresError.protocol("Could not parse SASL final data from authentication message")
}
return .saslFinal(finalData)
case 2, 7...9:
throw PostgresError.protocol("Support for KRBv5, GSSAPI, and SSPI authentication are not implemented")
case 6:
throw PostgresError.protocol("Support for SCM credential authentication is obsolete")
default:
throw PostgresError.protocol("Unknown authentication request type: \(type)")
}
}
public func serialize(into buffer: inout ByteBuffer) throws {
switch self {
case .ok:
buffer.writeInteger(0, as: Int32.self)
case .plaintext:
buffer.writeInteger(3, as: Int32.self)
case .md5(let salt):
buffer.writeInteger(5, as: Int32.self)
buffer.writeBytes(salt)
case .saslMechanisms(let mechanisms):
buffer.writeInteger(10, as: Int32.self)
mechanisms.forEach {
buffer.writeNullTerminatedString($0)
}
case .saslContinue(let challenge):
buffer.writeInteger(11, as: Int32.self)
buffer.writeBytes(challenge)
case .saslFinal(let data):
buffer.writeInteger(12, as: Int32.self)
buffer.writeBytes(data)
}
}
/// AuthenticationOk
/// Specifies that the authentication was successful.
case ok
/// AuthenticationCleartextPassword
/// Specifies that a clear-text password is required.
case plaintext
/// AuthenticationMD5Password
/// Specifies that an MD5-encrypted password is required.
case md5([UInt8])
/// AuthenticationSASL
/// Specifies the start of SASL mechanism negotiation.
case saslMechanisms([String])
/// AuthenticationSASLContinue
/// Specifies SASL mechanism-specific challenge data.
case saslContinue([UInt8])
/// AuthenticationSASLFinal
/// Specifies mechanism-specific post-authentication client data.
case saslFinal([UInt8])
/// See `CustomStringConvertible`.
public var description: String {
switch self {
case .ok: return "Ok"
case .plaintext: return "CleartextPassword"
case .md5(let salt): return "MD5Password(salt: 0x\(salt.hexdigest()))"
case .saslMechanisms(let mech): return "SASLMechanisms(\(mech))"
case .saslContinue(let data): return "SASLChallenge(\(data))"
case .saslFinal(let data): return "SASLFinal(\(data))"
}
}
}
}