# frozen_string_literal: true module Net class IMAP # Pluggable authentication mechanisms for protocols which support SASL # (Simple Authentication and Security Layer), such as IMAP4, SMTP, LDAP, and # XMPP. {RFC-4422}[https://tools.ietf.org/html/rfc4422] specifies the # common \SASL framework: # >>> # SASL is conceptually a framework that provides an abstraction layer # between protocols and mechanisms as illustrated in the following # diagram. # # SMTP LDAP XMPP Other protocols ... # \ | | / # \ | | / # SASL abstraction layer # / | | \ # / | | \ # EXTERNAL GSSAPI PLAIN Other mechanisms ... # # Net::IMAP uses SASL via the Net::IMAP#authenticate method. # # == Mechanisms # # Each mechanism has different properties and requirements. Please consult # the documentation for the specific mechanisms you are using: # # +ANONYMOUS+:: # See AnonymousAuthenticator. # # Allows the user to gain access to public services or resources without # authenticating or disclosing an identity. # # +EXTERNAL+:: # See ExternalAuthenticator. # # Authenticates using already established credentials, such as a TLS # certificate or IPSec. # # +OAUTHBEARER+:: # See OAuthBearerAuthenticator. # # Login using an OAuth2 Bearer token. This is the standard mechanism # for using OAuth2 with \SASL, but it is not yet deployed as widely as # +XOAUTH2+. # # +PLAIN+:: # See PlainAuthenticator. # # Login using clear-text username and password. # # +SCRAM-SHA-1+:: # +SCRAM-SHA-256+:: # See ScramAuthenticator. # # Login by username and password. The password is not sent to the # server but is used in a salted challenge/response exchange. # +SCRAM-SHA-1+ and +SCRAM-SHA-256+ are directly supported by # Net::IMAP::SASL. New authenticators can easily be added for any other # SCRAM-* mechanism if the digest algorithm is supported by # OpenSSL::Digest. # # +XOAUTH2+:: # See XOAuth2Authenticator. # # Login using a username and an OAuth2 access token. Non-standard and # obsoleted by +OAUTHBEARER+, but widely supported. # # See the {SASL mechanism # registry}[https://www.iana.org/assignments/sasl-mechanisms/sasl-mechanisms.xhtml] # for a list of all SASL mechanisms and their specifications. To register # new authenticators, see Authenticators. # # === Deprecated mechanisms # # Obsolete mechanisms should be avoided, but are still available for # backwards compatibility. # # >>> # For +DIGEST-MD5+ see DigestMD5Authenticator. # # For +LOGIN+, see LoginAuthenticator. # # For +CRAM-MD5+, see CramMD5Authenticator. # # Using a deprecated mechanism will print a warning. # module SASL # Exception class for any client error detected during the authentication # exchange. # # When the _server_ reports an authentication failure, it will respond # with a protocol specific error instead, e.g: +BAD+ or +NO+ in IMAP. # # When the client encounters any error, it *must* consider the # authentication exchange to be unsuccessful and it might need to drop the # connection. For example, if the server reports that the authentication # exchange was successful or the protocol does not allow additional # authentication attempts. Error = Class.new(StandardError) # Indicates an authentication exchange that will be or has been canceled # by the client, not due to any error or failure during processing. AuthenticationCanceled = Class.new(Error) # Indicates an error when processing a server challenge, e.g: an invalid # or unparsable challenge. An underlying exception may be available as # the exception's #cause. AuthenticationError = Class.new(Error) # Indicates that authentication cannot proceed because one of the server's # messages has not passed integrity checks. AuthenticationFailed = Class.new(Error) # Indicates that authentication cannot proceed because one of the server's # ended authentication prematurely. class AuthenticationIncomplete < AuthenticationFailed # The success response from the server attr_reader :response def initialize(response, message = "authentication ended prematurely") super(message) @response = response end end # autoloading to avoid loading all of the regexps when they aren't used. sasl_stringprep_rb = File.expand_path("sasl/stringprep", __dir__) autoload :StringPrep, sasl_stringprep_rb autoload :SASLprep, sasl_stringprep_rb autoload :StringPrepError, sasl_stringprep_rb autoload :ProhibitedCodepoint, sasl_stringprep_rb autoload :BidiStringError, sasl_stringprep_rb sasl_dir = File.expand_path("sasl", __dir__) autoload :AuthenticationExchange, "#{sasl_dir}/authentication_exchange" autoload :ClientAdapter, "#{sasl_dir}/client_adapter" autoload :ProtocolAdapters, "#{sasl_dir}/protocol_adapters" autoload :Authenticators, "#{sasl_dir}/authenticators" autoload :GS2Header, "#{sasl_dir}/gs2_header" autoload :ScramAlgorithm, "#{sasl_dir}/scram_algorithm" autoload :AnonymousAuthenticator, "#{sasl_dir}/anonymous_authenticator" autoload :ExternalAuthenticator, "#{sasl_dir}/external_authenticator" autoload :OAuthBearerAuthenticator, "#{sasl_dir}/oauthbearer_authenticator" autoload :PlainAuthenticator, "#{sasl_dir}/plain_authenticator" autoload :ScramAuthenticator, "#{sasl_dir}/scram_authenticator" autoload :ScramSHA1Authenticator, "#{sasl_dir}/scram_authenticator" autoload :ScramSHA256Authenticator, "#{sasl_dir}/scram_authenticator" autoload :XOAuth2Authenticator, "#{sasl_dir}/xoauth2_authenticator" autoload :CramMD5Authenticator, "#{sasl_dir}/cram_md5_authenticator" autoload :DigestMD5Authenticator, "#{sasl_dir}/digest_md5_authenticator" autoload :LoginAuthenticator, "#{sasl_dir}/login_authenticator" # Returns the default global SASL::Authenticators instance. def self.authenticators; @authenticators ||= Authenticators.new end # Delegates to registry.new See Authenticators#new. def self.authenticator(*args, registry: authenticators, **kwargs, &block) registry.new(*args, **kwargs, &block) end # Delegates to ::authenticators. See Authenticators#add_authenticator. def self.add_authenticator(...) authenticators.add_authenticator(...) end module_function # See Net::IMAP::StringPrep::SASLprep#saslprep. def saslprep(string, **opts) Net::IMAP::StringPrep::SASLprep.saslprep(string, **opts) end end end end