class Net::IMAP::SASL::AuthenticationExchange

This API is experimental, and may change.

TODO: catch exceptions in process and send cancel_response. TODO: raise an error if the command succeeds after being canceled. TODO: use with more clients, to verify the API can accommodate them.

Create an AuthenticationExchange from a client adapter and a mechanism authenticator:

def authenticate(mechanism, ...)
  authenticator = SASL.authenticator(mechanism, ...)
  SASL::AuthenticationExchange.new(
    sasl_adapter, mechanism, authenticator
  ).authenticate
end

private

def sasl_adapter = MyClientAdapter.new(self, &method(:send_command))

Or delegate creation of the authenticator to ::build:

def authenticate(...)
  SASL::AuthenticationExchange.build(sasl_adapter, ...)
    .authenticate
end

As a convenience, ::authenticate combines ::build and authenticate:

def authenticate(...)
  SASL::AuthenticationExchange.authenticate(sasl_adapter, ...)
end

Likewise, ClientAdapter#authenticate delegates to authenticate:

def authenticate(...) = sasl_adapter.authenticate(...)

Attributes

authenticator[R]
client[R]
mechanism[R]

Public Class Methods

authenticate(...) click to toggle source

Convenience method for build(...).authenticate

# File net-imap-0.4.11/lib/net/imap/sasl/authentication_exchange.rb, line 42
def self.authenticate(...) build(...).authenticate end
build(client, mechanism, *args, sasl_ir: true, **kwargs, &block) click to toggle source

Use registry to override the global Authenticators registry.

# File net-imap-0.4.11/lib/net/imap/sasl/authentication_exchange.rb, line 45
def self.build(client, mechanism, *args, sasl_ir: true, **kwargs, &block)
  authenticator = SASL.authenticator(mechanism, *args, **kwargs, &block)
  new(client, mechanism, authenticator, sasl_ir: sasl_ir)
end
new(client, mechanism, authenticator, sasl_ir: true) click to toggle source
# File net-imap-0.4.11/lib/net/imap/sasl/authentication_exchange.rb, line 52
def initialize(client, mechanism, authenticator, sasl_ir: true)
  @client = client
  @mechanism = -mechanism.to_s.upcase.tr(?_, ?-)
  @authenticator = authenticator
  @sasl_ir = sasl_ir
  @processed = false
end

Public Instance Methods

authenticate() click to toggle source

Call authenticate to execute an authentication exchange for client using authenticator. Authentication failures will raise an exception. Any exceptions other than those in RESPONSE_ERRORS will drop the connection.

# File net-imap-0.4.11/lib/net/imap/sasl/authentication_exchange.rb, line 64
def authenticate
  client.run_command(mechanism, initial_response) { process _1 }
    .tap { raise AuthenticationIncomplete, _1 unless done? }
rescue *client.response_errors
  raise # but don't drop the connection
rescue
  client.drop_connection
  raise
rescue Exception # rubocop:disable Lint/RescueException
  client.drop_connection!
  raise
end
done?() click to toggle source
# File net-imap-0.4.11/lib/net/imap/sasl/authentication_exchange.rb, line 85
def done?
  authenticator.respond_to?(:done?) ? authenticator.done? : @processed
end
send_initial_response?() click to toggle source
# File net-imap-0.4.11/lib/net/imap/sasl/authentication_exchange.rb, line 77
def send_initial_response?
  @sasl_ir &&
    authenticator.respond_to?(:initial_response?) &&
    authenticator.initial_response? &&
    client.sasl_ir_capable? &&
    client.auth_capable?(mechanism)
end

Private Instance Methods

initial_response() click to toggle source
# File net-imap-0.4.11/lib/net/imap/sasl/authentication_exchange.rb, line 93
def initial_response
  return unless send_initial_response?
  client.encode_ir authenticator.process nil
end
process(challenge) click to toggle source
# File net-imap-0.4.11/lib/net/imap/sasl/authentication_exchange.rb, line 98
def process(challenge)
  client.encode authenticator.process client.decode challenge
ensure
  @processed = true
end