Class: Net::IMAP::SASL::AuthenticationExchange

Inherits:
Object
  • Object
show all
Defined in:
lib/net/imap/sasl/authentication_exchange.rb

Overview

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(...)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(client, mechanism, authenticator, sasl_ir: true) ⇒ AuthenticationExchange

Returns a new instance of AuthenticationExchange.



52
53
54
55
56
57
58
# File '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

Instance Attribute Details

#authenticatorObject (readonly)

Returns the value of attribute authenticator.



50
51
52
# File 'lib/net/imap/sasl/authentication_exchange.rb', line 50

def authenticator
  @authenticator
end

#mechanismObject (readonly)

Returns the value of attribute mechanism.



50
51
52
# File 'lib/net/imap/sasl/authentication_exchange.rb', line 50

def mechanism
  @mechanism
end

Class Method Details

.authenticateObject

Convenience method for build(...).authenticate



42
# File 'lib/net/imap/sasl/authentication_exchange.rb', line 42

def self.authenticate(...) build(...).authenticate end

.build(client, mechanism, *args, sasl_ir: true, **kwargs, &block) ⇒ Object

Use registry to override the global Authenticators registry.



45
46
47
48
# File '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

Instance Method Details

#authenticateObject

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.



64
65
66
67
68
69
70
71
72
73
74
75
# File '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?Boolean

Returns:

  • (Boolean)


85
86
87
# File 'lib/net/imap/sasl/authentication_exchange.rb', line 85

def done?
  authenticator.respond_to?(:done?) ? authenticator.done? : @processed
end

#send_initial_response?Boolean

Returns:

  • (Boolean)


77
78
79
80
81
82
83
# File '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