@@ -6,8 +6,6 @@ module SASL
6
6
7
7
# This API is *experimental*, and may change.
8
8
#
9
- # TODO: catch exceptions in #process and send #cancel_response.
10
- # TODO: raise an error if the command succeeds after being canceled.
11
9
# TODO: use with more clients, to verify the API can accommodate them.
12
10
#
13
11
# An AuthenticationExchange represents a single attempt to authenticate
@@ -79,6 +77,9 @@ def self.build(client, mechanism, *args, sasl_ir: true, **kwargs, &block)
79
77
80
78
attr_reader :mechanism , :authenticator
81
79
80
+ # An exception that has been raised by <tt>authenticator.process</tt>.
81
+ attr_reader :process_error
82
+
82
83
def initialize ( client , mechanism , authenticator , sasl_ir : true )
83
84
client => SASL ::ClientAdapter
84
85
@client = client
@@ -92,8 +93,17 @@ def initialize(client, mechanism, authenticator, sasl_ir: true)
92
93
# using #authenticator. Authentication failures will raise an
93
94
# exception. Any exceptions other than AuthenticationCanceled or those
94
95
# in <tt>client.response_errors</tt> will drop the connection.
96
+ #
97
+ # When <tt>authenticator.process</tt> raises any StandardError
98
+ # (including AuthenticationCanceled), the authentication exchange will
99
+ # be canceled before re-raising the exception. The server will usually
100
+ # respond with an error response, and the client will most likely raise
101
+ # that error. This client error will supercede the original error.
102
+ # Unfortunately, the original error will not be the +#cause+ for the
103
+ # client error. But it will be available on #process_error.
95
104
def authenticate
96
105
client . run_command ( mechanism , initial_response ) { process _1 }
106
+ . tap { raise process_error if process_error }
97
107
. tap { raise AuthenticationIncomplete , _1 unless done? }
98
108
rescue AuthenticationCanceled , *client . response_errors
99
109
raise # but don't drop the connection
@@ -127,9 +137,12 @@ def initial_response
127
137
end
128
138
129
139
def process ( challenge )
130
- client . encode authenticator . process client . decode challenge
131
- ensure
132
140
@processed = true
141
+ return client . cancel_response if process_error
142
+ client . encode authenticator . process client . decode challenge
143
+ rescue => process_error
144
+ @process_error = process_error
145
+ client . cancel_response
133
146
end
134
147
135
148
end
0 commit comments