@@ -103,9 +103,9 @@ module Net
103
103
#
104
104
# == Capabilities
105
105
#
106
- # Net::IMAP does not _currently_ modify its behaviour according to the
107
- # server's advertised #capabilities. Users of this class must check that the
108
- # server is capable of extension commands or command arguments before
106
+ # Most Net::IMAP methods do not _currently_ modify their behaviour according
107
+ # to the server's advertised #capabilities. Users of this class must check
108
+ # that the server is capable of extension commands or command arguments before
109
109
# sending them. Special care should be taken to follow the #capabilities
110
110
# requirements for #starttls, #login, and #authenticate.
111
111
#
@@ -404,14 +404,14 @@ module Net
404
404
#
405
405
# Although IMAP4rev2[https://tools.ietf.org/html/rfc9051] is not supported
406
406
# yet, Net::IMAP supports several extensions that have been folded into it:
407
- # +ENABLE+, +IDLE+, +MOVE+, +NAMESPACE+, +UIDPLUS+, and +UNSELECT+. Commands
408
- # for these extensions are listed with the
409
- # {Core IMAP commands}[rdoc-ref:Net::IMAP@Core+IMAP+commands], above.
407
+ # +ENABLE+, +IDLE+, +MOVE+, +NAMESPACE+, +SASL-IR+, + UIDPLUS+, and +UNSELECT+.
408
+ # Commands for these extensions are listed with the {Core IMAP
409
+ # commands}[rdoc-ref:Net::IMAP@Core+IMAP+commands], above.
410
410
#
411
411
# >>>
412
412
# <em>The following are folded into +IMAP4rev2+ but are currently
413
413
# unsupported or incompletely supported by</em> Net::IMAP<em>: RFC4466
414
- # extensions, +ESEARCH+, +SEARCHRES+, +SASL-IR+, + LIST-EXTENDED+,
414
+ # extensions, +ESEARCH+, +SEARCHRES+, +LIST-EXTENDED+,
415
415
# +LIST-STATUS+, +LITERAL-+, +BINARY+ fetch, and +SPECIAL-USE+. The
416
416
# following extensions are implicitly supported, but will be updated with
417
417
# more direct support: RFC5530 response codes, <tt>STATUS=SIZE</tt>, and
@@ -457,6 +457,10 @@ module Net
457
457
# - Updates #append with the +APPENDUID+ ResponseCode
458
458
# - Updates #copy, #move with the +COPYUID+ ResponseCode
459
459
#
460
+ # ==== RFC4959: +SASL-IR+
461
+ # Folded into IMAP4rev2[https://tools.ietf.org/html/rfc9051].
462
+ # - Updates #authenticate with the option to send an initial response.
463
+ #
460
464
# ==== RFC5161: +ENABLE+
461
465
# Folded into IMAP4rev2[https://tools.ietf.org/html/rfc9051] and also included
462
466
# above with {Core IMAP commands}[rdoc-ref:Net::IMAP@Core+IMAP+commands].
@@ -983,19 +987,17 @@ def starttls(options = {}, verify = true)
983
987
end
984
988
985
989
# :call-seq:
986
- # authenticate(mechanism, ...) -> ok_resp
987
- # authenticate(mech, *creds, **props) {|prop, auth| val } -> ok_resp
988
- # authenticate(mechanism, authnid, credentials, authzid=nil) -> ok_resp
989
- # authenticate(mechanism, **properties) -> ok_resp
990
- # authenticate(mechanism) {|propname, authctx| prop_value } -> ok_resp
990
+ # authenticate(mechanism, ...) -> ok_resp
991
+ # authenticate(mech, *creds, sasl_ir: true, **attrs, &callback) -> ok_resp
991
992
#
992
993
# Sends an {AUTHENTICATE command [IMAP4rev1 Β§6.2.2]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.2.2]
993
994
# to authenticate the client. If successful, the connection enters the
994
995
# "_authenticated_" state.
995
996
#
996
997
# +mechanism+ is the name of the \SASL authentication mechanism to be used.
997
- # All other arguments are forwarded to the authenticator for the requested
998
- # mechanism. The listed call signatures are suggestions. <em>The
998
+ # +sasl_ir+ allows or disallows sending an "initial response" (see the
999
+ # +SASL-IR+ capability, below). All other arguments are forwarded to the
1000
+ # registered SASL authenticator for the requested mechanism. <em>The
999
1001
# documentation for each individual mechanism must be consulted for its
1000
1002
# specific parameters.</em>
1001
1003
#
@@ -1048,19 +1050,40 @@ def starttls(options = {}, verify = true)
1048
1050
# raise "No acceptable authentication mechanism is available"
1049
1051
# end
1050
1052
#
1051
- # Server capabilities may change after #starttls, #login, and #authenticate.
1052
- # Cached #capabilities will be cleared when this method completes.
1053
- # If the TaggedResponse to #authenticate includes updated capabilities, they
1054
- # will be cached.
1053
+ # The SASL exchange provides a method for server challenges and client
1054
+ # responses, but many mechanisms expect the client to "respond" first. When
1055
+ # the server's capabilities include +SASL-IR+
1056
+ # [RFC4959[https://tools.ietf.org/html/rfc4959]], this "initial response"
1057
+ # may be sent as an argument to the +AUTHENTICATE+ command, saving a
1058
+ # round-trip. The initial response will _only_ be sent when it is supported
1059
+ # by both the mechanism and the server. Set +sasl_ir+ to +false+ to prevent
1060
+ # sending an initial response, even when it is supported.
1055
1061
#
1056
- def authenticate ( mechanism , ...)
1057
- authenticator = self . class . authenticator ( mechanism , ...)
1058
- send_command ( "AUTHENTICATE" , mechanism ) do |resp |
1062
+ # Although servers _should_ advertise all supported auth mechanisms, it is
1063
+ # possible to attempt to authenticate with a +mechanism+ that isn't listed.
1064
+ # However the initial response will not be sent unless the appropriate
1065
+ # <tt>"AUTH=#{mechanism}"</tt> capability is also present.
1066
+ #
1067
+ # Server capabilities may change after #starttls, #login, and #authenticate.
1068
+ # Previously cached #capabilities will be cleared when this method
1069
+ # completes. If the TaggedResponse to #authenticate includes updated
1070
+ # capabilities, they will be cached.
1071
+ def authenticate ( mechanism , *creds , sasl_ir : true , **props , &callback )
1072
+ authenticator = self . class . authenticator ( mechanism ,
1073
+ *creds ,
1074
+ **props ,
1075
+ &callback )
1076
+ cmdargs = [ "AUTHENTICATE" , mechanism ]
1077
+ if sasl_ir && capable? ( "SASL-IR" ) && auth_capable? ( mechanism ) &&
1078
+ SASL . initial_response? ( authenticator )
1079
+ cmdargs << [ authenticator . process ( nil ) ] . pack ( "m0" )
1080
+ end
1081
+ send_command ( *cmdargs ) do |resp |
1059
1082
if resp . instance_of? ( ContinuationRequest )
1060
- data = authenticator . process ( resp . data . text . unpack ( "m" ) [ 0 ] )
1061
- s = [ data ] . pack ( "m0" )
1062
- send_string_data ( s )
1063
- put_string ( CRLF )
1083
+ challenge = resp . data . text . unpack1 ( "m" )
1084
+ response = authenticator . process ( challenge )
1085
+ response = [ response ] . pack ( "m0" )
1086
+ put_string ( response + CRLF )
1064
1087
end
1065
1088
end
1066
1089
. tap { @capabilities = capabilities_from_resp_code _1 }
0 commit comments