Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SASL doc updates #166

Merged
merged 2 commits into from
Sep 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 53 additions & 69 deletions lib/net/imap.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@
module Net

# Net::IMAP implements Internet Message Access Protocol (\IMAP) client
# functionality. The protocol is described in
# [IMAP4rev1[https://tools.ietf.org/html/rfc3501]] and
# [IMAP4rev2[https://tools.ietf.org/html/rfc9051]].
# functionality. The protocol is described
# in {IMAP4rev1 [RFC3501]}[https://tools.ietf.org/html/rfc3501]
# and {IMAP4rev2 [RFC9051]}[https://tools.ietf.org/html/rfc9051].
#
# == \IMAP Overview
#
Expand Down Expand Up @@ -768,13 +768,12 @@ def disconnected?
# cached #capabilities are used without sending a new #capability command to
# the server.
#
# <em>*NOTE:* Net::IMAP does not</em> currently <em>modify its behaviour
# according to the server's advertised capabilities.</em>
# <em>*NOTE:* Most Net::IMAP methods do not _currently_ modify their
# behaviour according to the server's advertised #capabilities.</em>
#
# See Net::IMAP@Capabilities for more about \IMAP capabilities.
#
# Related: #auth_capable?, #capabilities, #capability, #enable
#
def capable?(capability) capabilities.include? capability.to_s.upcase end
alias capability? capable?

Expand All @@ -783,12 +782,12 @@ def capable?(capability) capabilities.include? capability.to_s.upcase end
#
# To ensure a case-insensitive comparison, #capable? can be used instead.
#
# <em>*NOTE:* Net::IMAP does not</em> currently <em>modify its behaviour
# according to the server's advertised capabilities.</em>
# <em>*NOTE:* Most Net::IMAP methods do not _currently_ modify their
# behaviour according to the server's advertised #capabilities.</em>
#
# See Net::IMAP@Capabilities for more about \IMAP capabilities.
#
# Related: #capable?, #auth_capable?, #capability
# Related: #capable?, #auth_capable?, #auth_mechanisms, #capability, #enable
def capabilities
@capabilities || capability
end
Expand All @@ -812,13 +811,7 @@ def capabilities
# imap.authenticate("XOAUTH2", username, oauth2_access_token)
# imap.auth_mechanisms # => []
#
# <em>*NOTE:* Net::IMAP does not</em> currently <em>modify its behaviour
# according to the server's advertised capabilities.</em>
#
# See Net::IMAP@Capabilities for more about \IMAP capabilities.
#
# Related: #auth_capable?, #capabilities
#
# Related: #authenticate, #auth_capable?, #capabilities
def auth_mechanisms
capabilities
.grep(/\AAUTH=/i)
Expand All @@ -835,12 +828,7 @@ def auth_mechanisms
# imap.auth_capable? "PLAIN" # => true
# imap.auth_capable? "blurdybloop" # => false
#
# <em>*NOTE:* Net::IMAP does not</em> currently <em>modify its behaviour
# according to the server's advertised capabilities.</em>
#
# See Net::IMAP@Capabilities for more about \IMAP capabilities.
#
# Related: #authenticate, #capable?, #capabilities
# Related: #authenticate, #auth_mechanisms, #capable?, #capabilities
def auth_capable?(mechanism)
capable? "AUTH=#{mechanism}"
end
Expand Down Expand Up @@ -875,8 +863,8 @@ def clear_cached_capabilities
# and returns an array of capabilities that are supported by the server.
# The result is stored for use by #capable? and #capabilities.
#
# <em>*NOTE:* Net::IMAP does not</em> currently <em>modify its behaviour
# according to the server's advertised capabilities.</em>
# <em>*NOTE:* Most Net::IMAP methods do not _currently_ modify their
# behaviour according to the server's advertised #capabilities.</em>
#
# Net::IMAP automatically stores and discards capability data according to
# the requirements and recommendations in
Expand Down Expand Up @@ -992,82 +980,76 @@ def starttls(options = {}, verify = true)
end

# :call-seq:
# authenticate(mechanism, ...) -> ok_resp
# authenticate(mech, *creds, sasl_ir: true, **attrs, &callback) -> ok_resp
# authenticate(mechanism, *, sasl_ir: true, **, &) -> ok_resp
#
# Sends an {AUTHENTICATE command [IMAP4rev1 §6.2.2]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.2.2]
# to authenticate the client. If successful, the connection enters the
# "_authenticated_" state.
#
# +mechanism+ is the name of the \SASL authentication mechanism to be used.
#
# +sasl_ir+ allows or disallows sending an "initial response" (see the
# +SASL-IR+ capability, below). All other arguments are forwarded to the
# registered SASL authenticator for the requested mechanism. <em>The
# documentation for each individual mechanism must be consulted for its
# specific parameters.</em>
# +SASL-IR+ capability, below).
#
# An exception Net::IMAP::NoResponseError is raised if authentication fails.
# All other arguments are forwarded to the registered SASL authenticator for
# the requested mechanism. <em>The documentation for each individual
# mechanism must be consulted for its specific parameters.</em>
#
# Related: #login, #starttls, #auth_capable?, #auth_mechanisms
#
# ==== Supported SASL Mechanisms
# ==== Mechanisms
#
# +PLAIN+:: See PlainAuthenticator.
# Login using clear-text username and password.
# Each mechanism has different properties and requirements. Please consult
# the documentation for the specific mechanisms you are using:
#
# +XOAUTH2+:: See XOAuth2Authenticator.
# Login using a username and OAuth2 access token.
# Non-standard and obsoleted by +OAUTHBEARER+, but widely
# supported.
# +PLAIN+::
# See PlainAuthenticator[Net::IMAP::SASL::PlainAuthenticator].
#
# >>>
# *Deprecated:* <em>Obsolete mechanisms are available for backwards
# compatibility.</em>
# Login using clear-text username and password.
#
# For +DIGEST-MD5+ see DigestMD5Authenticator.
# +XOAUTH2+::
# See XOAuth2Authenticator[Net::IMAP::SASL::XOAuth2Authenticator].
#
# For +LOGIN+, see LoginAuthenticator.
# Login using a username and an OAuth2 access token. Non-standard and
# obsoleted by +OAUTHBEARER+, but widely supported.
#
# For +CRAM-MD5+, see CramMD5Authenticator.
# 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.
#
# <em>Using a deprecated mechanism will print a warning.</em>
# ===== Deprecated mechanisms
#
# See Net::IMAP::Authenticators for information on plugging in
# authenticators for other mechanisms. See the {SASL mechanism
# registry}[https://www.iana.org/assignments/sasl-mechanisms/sasl-mechanisms.xhtml]
# for information on these and other SASL mechanisms.
# <em>Obsolete mechanisms should be avoided, but are still available for
# backwards compatibility. See</em> Net::IMAP::SASL@Deprecated+mechanisms.
# <em>Using a deprecated mechanism will print a warning.</em>
#
# ===== Capabilities
# ==== Capabilities
#
# The server should list <tt>"AUTH=#{mechanism}"</tt> capabilities for
# supported mechanisms. Check #auth_capable? or #auth_mechanisms before
# using a particular mechanism.
# <tt>"AUTH=#{mechanism}"</tt> capabilities indicate server support for
# mechanisms. Use #auth_capable? or #auth_mechanisms to check for support
# before using a particular mechanism.
#
# if imap.auth_capable? "XOAUTH2"
# imap.authenticate "XOAUTH2", username, oauth2_access_token
# elsif imap.auth_capable? "PLAIN"
# imap.authenticate "PLAIN", username, password
# elsif imap.auth_capable? "DIGEST-MD5"
# imap.authenticate "DIGEST-MD5", username, password
# elsif !imap.capability? "LOGINDISABLED"
# imap.login username, password
# else
# raise "No acceptable authentication mechanism is available"
# end
#
# The SASL exchange provides a method for server challenges and client
# responses, but many mechanisms expect the client to "respond" first. When
# the server's capabilities include +SASL-IR+
# [RFC4959[https://tools.ietf.org/html/rfc4959]], this "initial response"
# may be sent as an argument to the +AUTHENTICATE+ command, saving a
# round-trip. The initial response will _only_ be sent when it is supported
# by both the mechanism and the server. Set +sasl_ir+ to +false+ to prevent
# sending an initial response, even when it is supported.
# Although servers should list all supported \SASL mechanisms, they may
# allow authentication with an unlisted +mechanism+.
#
# Although servers _should_ advertise all supported auth mechanisms, it is
# possible to attempt to authenticate with a +mechanism+ that isn't listed.
# However the initial response will not be sent unless the appropriate
# <tt>"AUTH=#{mechanism}"</tt> capability is also present.
# If [SASL-IR[https://www.rfc-editor.org/rfc/rfc4959.html]] is supported
# and the appropriate <tt>"AUTH=#{mechanism}"</tt> capability is present,
# an "initial response" may be sent as an argument to the +AUTHENTICATE+
# command, saving a round-trip. The SASL exchange allows for server
# challenges and client responses, but many mechanisms expect the client to
# "respond" first. The initial response will only be sent for
# "client-first" mechanisms.
#
# Server capabilities may change after #starttls, #login, and #authenticate.
# Previously cached #capabilities will be cleared when this method
Expand Down Expand Up @@ -1098,8 +1080,10 @@ def authenticate(mechanism, *creds, sasl_ir: true, **props, &callback)
# this +user+. If successful, the connection enters the "_authenticated_"
# state.
#
# Using #authenticate is generally preferred over #login. The LOGIN command
# is not the same as #authenticate with the "LOGIN" +mechanism+.
# Using #authenticate {should be
# preferred}[https://www.rfc-editor.org/rfc/rfc9051.html#name-login-command]
# over #login. The LOGIN command is not the same as #authenticate with the
# "LOGIN" +mechanism+.
#
# A Net::IMAP::NoResponseError is raised if authentication fails.
#
Expand Down
57 changes: 47 additions & 10 deletions lib/net/imap/sasl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@ 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 and the +EXTERNAL+ mechanism, and the
# {SASL mechanism registry}[https://www.iana.org/assignments/sasl-mechanisms/sasl-mechanisms.xhtml]
# lists the specification for others.
#
# "SASL is conceptually a framework that provides an abstraction layer
# between protocols and mechanisms as illustrated in the following diagram."
# 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 ...
# \ | | /
Expand All @@ -21,10 +20,46 @@ class IMAP
# / | | \
# 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:
#
# +PLAIN+::
# See PlainAuthenticator[Net::IMAP::SASL::PlainAuthenticator].
#
# Login using clear-text username and password.
#
# +XOAUTH2+::
# See XOAuth2Authenticator[Net::IMAP::SASL::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
#
# <em>Obsolete mechanisms should be avoided, but are still available for
# backwards compatibility.</em>
#
# >>>
# For +DIGEST-MD5+ see DigestMD5Authenticator.
#
# For +LOGIN+, see LoginAuthenticator.
#
# For +CRAM-MD5+, see CramMD5Authenticator.
#
# <em>Using a deprecated mechanism will print a warning.</em>
#
module SASL

# 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
Expand Down Expand Up @@ -60,11 +95,13 @@ def saslprep(string, **opts)
Net::IMAP::StringPrep::SASLprep.saslprep(string, **opts)
end

def initial_response?(mechanism)
mechanism.respond_to?(:initial_response?) && mechanism.initial_response?
# Returns whether the authenticator is client-first and supports sending
# an "initial response".
def initial_response?(authenticator)
authenticator.respond_to?(:initial_response?) &&
authenticator.initial_response?
end

end
end

end
2 changes: 1 addition & 1 deletion lib/net/imap/sasl/stringprep.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

module Net::IMAP::SASL

# Alias for Net::IMAP::StringPrep::SASLPrep.
# Alias for Net::IMAP::StringPrep::SASLprep.
SASLprep = Net::IMAP::StringPrep::SASLprep
StringPrep = Net::IMAP::StringPrep # :nodoc:
BidiStringError = Net::IMAP::StringPrep::BidiStringError # :nodoc:
Expand Down