Class: Protocol::ZMTP::Mechanism::Plain

Inherits:
Object
  • Object
show all
Defined in:
lib/protocol/zmtp/mechanism/plain.rb

Overview

PLAIN security mechanism — username/password authentication, no encryption.

Implements the ZMTP PLAIN handshake (RFC 24):

client → server:  HELLO    (username + password)
server → client:  WELCOME  (empty, credentials accepted)
client → server:  INITIATE (socket metadata)
server → client:  READY    (socket metadata)

Constant Summary collapse

MECHANISM_NAME =
"PLAIN"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(username: "", password: "", authenticator: nil) ⇒ Plain

Returns a new instance of Plain.

Parameters:

  • username (String) (defaults to: "")

    client username (max 255 bytes)

  • password (String) (defaults to: "")

    client password (max 255 bytes)

  • authenticator (#call, nil) (defaults to: nil)

    server-side credential verifier; called as authenticator.call(username, password) and must return truthy to accept the connection. When nil, all credentials pass.



30
31
32
33
34
35
# File 'lib/protocol/zmtp/mechanism/plain.rb', line 30

def initialize(username: "", password: "", authenticator: nil)
  @username         = username
  @password         = password
  @authenticator    = authenticator
  @metadata = nil
end

Instance Attribute Details

#metadataHash{String => String}

Extra READY/INITIATE properties an upper layer wants this side to advertise. Mutated before #handshake!.

Returns:

  • (Hash{String => String})


22
23
24
# File 'lib/protocol/zmtp/mechanism/plain.rb', line 22

def 
  @metadata
end

Instance Method Details

#encrypted?Boolean

Returns false — PLAIN does not encrypt frames.

Returns:

  • (Boolean)

    false — PLAIN does not encrypt frames



68
69
70
# File 'lib/protocol/zmtp/mechanism/plain.rb', line 68

def encrypted?
  false
end

#handshake!(io, as_server:, socket_type:, identity:, qos: 0, qos_hash: "") ⇒ Hash

Performs the full PLAIN handshake over io.

Parameters:

  • io (#read_exactly, #write, #flush)

    transport IO

  • as_server (Boolean)
  • socket_type (String)
  • identity (String)

Returns:

  • (Hash)

    { peer_socket_type:, peer_identity: }

Raises:



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/protocol/zmtp/mechanism/plain.rb', line 46

def handshake!(io, as_server:, socket_type:, identity:, qos: 0, qos_hash: "")
  io.write(Codec::Greeting.encode(mechanism: MECHANISM_NAME, as_server: as_server))
  io.flush

  greeting_data = io.read_exactly(Codec::Greeting::SIZE)
  peer_greeting = Codec::Greeting.decode(greeting_data)

  unless peer_greeting[:mechanism] == MECHANISM_NAME
    raise Error, "unsupported mechanism: #{peer_greeting[:mechanism]}"
  end

  if as_server
    server_handshake! io, socket_type: socket_type, identity: identity,
      qos: qos, qos_hash: qos_hash
  else
    client_handshake! io, socket_type: socket_type, identity: identity,
      qos: qos, qos_hash: qos_hash
  end
end