class Net::IMAP::SASL::AuthenticationExchange - net-imap: Ruby Standard Library Documentation

# class Net::IMAP::SASL::AuthenticationExchange

`AuthenticationExchange` is used internally by `Net::IMAP#authenticate`. But the API is still 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. TODO: pass `ClientAdapter#service` to `SASL.authenticator`

An `AuthenticationExchange` represents a single attempt to authenticate a `SASL` client to a `SASL` server. It is created from a client adapter, a mechanism name, and a mechanism authenticator. When `authenticate` is called, it will send the appropriate authenticate command to the server, returning the client response on success and raising an exception on failure.

In most cases, the client will not need to use `SASL::AuthenticationExchange` directly at all. Instead, use `SASL::ClientAdapter#authenticate`. If customizations are needed, the custom client adapter is probably the best place for that code.

    def authenticate(...)
      MyClient::SASLAdapter.new(self).authenticate(...)
    end

`SASL::ClientAdapter#authenticate` delegates to `::authenticate`, like so:

    def authenticate(...)
      sasl_adapter = MyClient::SASLAdapter.new(self)
      SASL::AuthenticationExchange.authenticate(sasl_adapter, ...)
    end

`::authenticate` simply delegates to `::build` and `authenticate`, like so:

    def authenticate(...)
      sasl_adapter = MyClient::SASLAdapter.new(self)
      SASL::AuthenticationExchange
        .build(sasl_adapter, ...)
        .authenticate
    end

And `::build` delegates to `SASL.authenticator` and `::new`, like so:

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

### Attributes

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

### Public Class Methods

authenticate(...) click to toggle source

Convenience method for `build(...).authenticate`

See also: `SASL::ClientAdapter#authenticate`

    # File net-imap-0.5.4/lib/net/imap/sasl/authentication_exchange.rb, line 61
    def self.authenticate(...) build(...).authenticate end

build(client, mechanism, *args, sasl_ir: true, **kwargs, &block) click to toggle source

Convenience method to combine the creation of a new authenticator and a new Authentication exchange.

`client` must be an instance of `SASL::ClientAdapter`.

`mechanism` must be a `SASL` mechanism name, as a string or symbol.

`sasl_ir` allows or disallows sending an “initial response”, depending also on whether the server capabilities, mechanism authenticator, and client adapter all support it. Defaults to `true`.

`mechanism`, `args`, `kwargs`, and `block` are all forwarded to `SASL.authenticator`. Use the `registry` kwarg to override the global `SASL::Authenticators` registry.

    # File net-imap-0.5.4/lib/net/imap/sasl/authentication_exchange.rb, line 77
    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.5.4/lib/net/imap/sasl/authentication_exchange.rb, line 84
    def initialize(client, mechanism, authenticator, sasl_ir: true)
      @client = client
      @mechanism = Authenticators.normalize_name(mechanism)
      @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.5.4/lib/net/imap/sasl/authentication_exchange.rb, line 96
    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.5.4/lib/net/imap/sasl/authentication_exchange.rb, line 117
    def done?
      authenticator.respond_to?(:done?) ? authenticator.done? : @processed
    end

send_initial_response?() click to toggle source

    # File net-imap-0.5.4/lib/net/imap/sasl/authentication_exchange.rb, line 109
    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.5.4/lib/net/imap/sasl/authentication_exchange.rb, line 125
    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.5.4/lib/net/imap/sasl/authentication_exchange.rb, line 130
    def process(challenge)
      client.encode authenticator.process client.decode challenge
    ensure
      @processed = true
    end