@@ -577,43 +577,58 @@ def starttls(options = {}, verify = true)
577577 end
578578 end
579579
580+ ##
581+ # :call-seq:
582+ # authenticate(mechanism, ...) -> ok_resp
583+ # authenticate(mechanism) -> ok_resp
584+ # authenticate(mechanism, username, password) -> ok_resp
585+ # authenticate(mechanism, authcid, secret, authzid) -> ok_resp
586+ # authenticate(mechanism, *credentials) -> ok_resp
587+ # authenticate(mechanism, **properties_and_callbacks) -> ok_resp
588+ # authenticate(mechanism) {|name, auth_ctx| prop_value } -> ok_resp
589+ # authenticate(mech, *creds, **props) {|prop, auth| val } -> ok_resp
590+ #
580591 # Sends an {AUTHENTICATE command [IMAP4rev1
581592 # §6.2.2]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.2.2]) to
582593 # authenticate the client.
583594 #
584- # The +auth_type+ parameter is a string that
585- # represents the authentication mechanism to be used. Currently Net::IMAP
586- # supports the following mechanisms:
595+ # +mechanism+ is the name of the \SASL authentication mechanism to be used.
596+ # All other arguments are forwarded to the authenticator for the requested
597+ # mechanism. The listed call signatures are suggestions. <em>The
598+ # documentation for each individual mechanism must be consulted for its
599+ # specific parameters.</em>
587600 #
588- # PLAIN:: Login using cleartext user and password. Secure with TLS.
589- # See PlainAuthenticator.
590- # CRAM-MD5:: DEPRECATED: Use PLAIN (or DIGEST-MD5) with TLS.
591- # DIGEST-MD5:: DEPRECATED by RFC6331. Must be secured using TLS.
592- # See DigestMD5Authenticator.
593- # LOGIN:: DEPRECATED: Use PLAIN.
594- #
595- # Most mechanisms require two args: authentication identity (e.g. username)
596- # and credentials (e.g. a password). But each mechanism requires and allows
597- # different arguments; please consult the documentation for the specific
598- # mechanisms you are using. <em>Several obsolete mechanisms are available
599- # for backwards compatibility. Using deprecated mechanisms will issue
600- # warnings.</em>
601- #
602- # Servers do not support all mechanisms and clients must not attempt to use
603- # a mechanism unless "AUTH=#{mechanism}" is listed as a #capability.
604- # Clients must not attempt to authenticate or #login when +LOGINDISABLED+ is
605- # listed with the capabilities. Server capabilities, especially auth
606- # mechanisms, do change after calling #starttls so they need to be checked
607- # again.
601+ # <em>In general</em>, all of a mechanism's properties can be set by keyword
602+ # argument or callback, but mechanisms may allow common properties to be set
603+ # with positional arguments. See SASL::Authenticator@Properties and
604+ # SASL::Authenticator@Callbacks for more details.
608605 #
609- # For example:
606+ # An exception Net::IMAP::NoResponseError is raised if authentication fails.
610607 #
611- # imap.authenticate('PLAIN', user, password)
608+ # ==== Supported SASL Mechanisms
612609 #
613- # A Net::IMAP::NoResponseError is raised if authentication fails.
610+ # Net::IMAP currently supports the following mechanisms:
611+ #
612+ # PLAIN:: Login using clear-text user and password. Secure with TLS.
613+ # See SASL::PlainAuthenticator.
614+ # XOAUTH2:: Login using a username and OAuth2 access token. Non-standard
615+ # and obsoleted by +OAUTHBEARER+, but still widely supported.
616+ # See SASL::XOAuth2Authenticator.
614617 #
615- # See Net::IMAP::Authenticators for more information on plugging in your
616- # own authenticator.
618+ # See Net::IMAP::Authenticators for information on plugging in
619+ # authenticators for other mechanisms. See the {SASL mechanism
620+ # registry}[https://www.iana.org/assignments/sasl-mechanisms/sasl-mechanisms.xhtml]
621+ # for information on these and other SASL mechanisms.
622+ #
623+ # ===== Deprecated mechanisms
624+ #
625+ # <em>Obsolete mechanisms are available for backwards compatibility.
626+ # Using a deprecated mechanism will print a warning.</em>
627+ #
628+ # DIGEST-MD5:: DEPRECATED by RFC6331. Must be secured using TLS.
629+ # See SASL::DigestMD5Authenticator.
630+ # CRAM-MD5:: DEPRECATED: Use +PLAIN+ (or SCRAM-*)
631+ # LOGIN:: DEPRECATED: Use +PLAIN+ with TLS.
617632 #
618633 # ==== Capabilities
619634 #
@@ -626,9 +641,35 @@ def starttls(options = {}, verify = true)
626641 # Server capabilities may change after #starttls, #login, and #authenticate.
627642 # Any cached capabilities must be invalidated when this method completes.
628643 #
629- def authenticate ( auth_type , *args )
630- authenticator = self . class . authenticator ( auth_type , *args )
631- send_command ( "AUTHENTICATE" , auth_type ) do |resp |
644+ # ==== Example
645+ # Because unhandled keyword arguments are ignored, the same config can be
646+ # used for multiple authenticator types.
647+ # password = nil # saved locally, so we don't ask more than once
648+ # creds = {
649+ # authcid: username,
650+ # password: proc { password ||= ui.prompt_for_password },
651+ # oauth2_token: proc { kms.lookup(username, :access_token) },
652+ # }
653+ # capa = imap.capability
654+ # if capa.include? "LOGINDISABLED"
655+ # raise "the server has disabled login"
656+ # elsif oauth2_token and capa.include? "AUTH=OAUTHBEARER"
657+ # imap.authenticate "OAUTHBEARER", **creds # authcid, oauth2_token
658+ # elsif oauth2_token and capa.include? "AUTH=XOAUTH2"
659+ # imap.authenticate "XOAUTH2", **creds # authcid, oauth2_token
660+ # elsif password and capa.include? "AUTH=SCRAM-SHA-256"
661+ # imap.authenticate "SCRAM-SHA-256", **creds # authcid, password
662+ # elsif password and capa.include? "AUTH=PLAIN"
663+ # imap.authenticate "PLAIN", **creds # authcid, password
664+ # elsif password and capa.include? "AUTH=DIGEST-MD5"
665+ # imap.authenticate "DIGEST-MD5", **creds # authcid, password
666+ # else
667+ # raise "no acceptable authentication mechanism is available"
668+ # end
669+ #
670+ def authenticate ( mechanism , *args , **props , &cb )
671+ authenticator = self . class . authenticator ( mechanism , *args , **props , &cb )
672+ send_command ( "AUTHENTICATE" , mechanism ) do |resp |
632673 if resp . instance_of? ( ContinuationRequest )
633674 data = authenticator . process ( resp . data . text . unpack ( "m" ) [ 0 ] )
634675 s = [ data ] . pack ( "m0" )
0 commit comments