-
Notifications
You must be signed in to change notification settings - Fork 0
/
sasl.py
107 lines (89 loc) · 3.35 KB
/
sasl.py
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
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
from dispatcher import Dispatcher
from framing import SASL_FRAME
from protocol import *
class SASL(Dispatcher):
type_decoder = PROTOCOL_DECODER
type_encoder = PROTOCOL_ENCODER
def __init__(self, connection):
Dispatcher.__init__(self, 3, SASL_FRAME)
self.connection = connection
self.mechanisms = None
self.mechanism = None
self.username = None
self.password = None
self.output_redirect = False
self.outcome = None
def client(self, mechanism="ANONYMOUS", username=None, password=None):
self.mechanism = mechanism
self.username = username
self.password = password
self.post_frame(0, SaslInit(mechanism = self.mechanism,
initial_response = str("\0%s\0%s" % (self.username or "",
self.password or ""))))
def server(self, mechanisms=("ANONYMOUS", "PLAIN"), passwords={}):
self.mechanisms = mechanisms
self.passwords = passwords
self.post_frame(0, SaslMechanisms(sasl_server_mechanisms = self.mechanisms))
def do_sasl_mechanisms(self, channel, mechs):
if self.mechanism not in [m.name for m in mechs.sasl_server_mechanisms]:
# we're pretending negotiation failure is an outcome
self.outcome = 2
def do_sasl_init(self, channel, init):
mech = init.mechanism.name
if mech in self.mechanisms:
return getattr(self, "mech_%s" % mech.lower())(init.initial_response)
else:
return self.post_outcome(2)
def mech_anonymous(self, resp):
return self.post_outcome(0)
def mech_plain(self, resp):
_, username, password = resp.split("\x00")
if username in self.passwords and password == self.passwords[username]:
return self.post_outcome(0)
else:
return self.post_outcome(1)
def post_outcome(self, code):
self.outcome = code
self.post_frame(0, SaslOutcome(code=code))
if code == 0:
self.output_redirect = True
return self.__tunnel
else:
# XXX: how do we close things down?
pass
def do_sasl_outcome(self, channel, outcome):
self.outcome = outcome.code
if self.outcome == 0:
self.output_redirect = True
return self.__tunnel
def unhandled(self, channel, body):
raise ValueError("unknown boyd: %s" % body);
def tick(self):
if self.output_redirect:
self.output.write(self.connection.read())
def __tunnel(self):
self.connection.write(self.input.read())
def error(self, exc):
if self.output_redirect:
self.connection.error(exc)
def closed(self):
if self.output_redirect:
self.connection.closed()