@@ -6,8 +6,6 @@ module SASL
66
77 # This API is *experimental*, and may change.
88 #
9- # TODO: catch exceptions in #process and send #cancel_response.
10- # TODO: raise an error if the command succeeds after being canceled.
119 # TODO: use with more clients, to verify the API can accommodate them.
1210 # TODO: pass ClientAdapter#service to SASL.authenticator
1311 #
@@ -80,6 +78,9 @@ def self.build(client, mechanism, *args, sasl_ir: true, **kwargs, &block)
8078
8179 attr_reader :mechanism , :authenticator
8280
81+ # An exception that has been raised by <tt>authenticator.process</tt>.
82+ attr_reader :process_error
83+
8384 def initialize ( client , mechanism , authenticator , sasl_ir : true )
8485 @client = client
8586 @mechanism = Authenticators . normalize_name ( mechanism )
@@ -92,8 +93,17 @@ def initialize(client, mechanism, authenticator, sasl_ir: true)
9293 # using #authenticator. Authentication failures will raise an
9394 # exception. Any exceptions other than AuthenticationCanceled or those
9495 # 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.
95104 def authenticate
96105 client . run_command ( mechanism , initial_response ) { process _1 }
106+ . tap { raise process_error if process_error }
97107 . tap { raise AuthenticationIncomplete , _1 unless done? }
98108 rescue AuthenticationCanceled , *client . response_errors
99109 raise # but don't drop the connection
@@ -127,9 +137,12 @@ def initial_response
127137 end
128138
129139 def process ( challenge )
130- client . encode authenticator . process client . decode challenge
131- ensure
132140 @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
133146 end
134147
135148 end
0 commit comments