Page MenuHomePhorge

No OneTemporary

Size
11 KB
Referenced Files
None
Subscribers
None
diff --git a/debug_server.exs b/debug_server.exs
index 69df482..5541529 100644
--- a/debug_server.exs
+++ b/debug_server.exs
@@ -1,56 +1,66 @@
require Logger
Application.ensure_started(:cacophony)
Application.ensure_all_started(:ranch)
alias Cacophony.Message
defmodule DebugServer do
def handle_message(%Message.BindRequest{} = request) do
response = %Message.BindResponse{
id: request.id,
result_code: :success,
matched_cn: "cn=kaniini"
}
{:ok, response}
end
def handle_message(%Message.UnbindRequest{}), do: :noreply
+ def handle_message(%Message.WhoAmIRequest{} = request) do
+ response = %Message.WhoAmIResponse{
+ id: request.id,
+ result_code: :success,
+ authzid: "u:kaniini@example.com"
+ }
+
+ {:ok, response}
+ end
+
def handle_message(_message), do: {:error, :badmatch}
end
defmodule DebugListener do
def start_link(_opts) do
:ranch.start_listener(make_ref(), :ranch_tcp, [{:port, 6389}], Cacophony.Server, [mod: DebugServer])
end
def child_spec(_) do
%{id: __MODULE__, start: {__MODULE__, :start_link, [[]]}}
end
end
defmodule DebugSupervisor do
use Supervisor
def start_link(opts) do
Supervisor.start_link(__MODULE__, :ok, opts)
end
@impl true
def init(:ok) do
children = [DebugListener]
Supervisor.init(children, strategy: :one_for_one)
end
end
{:ok, pid} = DebugSupervisor.start_link([])
ref = Process.monitor(pid)
Logger.info("Debugging server started on port 6389.")
receive do
{:DOWN, ^ref, _, _, _} -> Process.exit()
end
diff --git a/lib/cacophony/message.ex b/lib/cacophony/message.ex
index 8092103..34535c9 100644
--- a/lib/cacophony/message.ex
+++ b/lib/cacophony/message.ex
@@ -1,94 +1,196 @@
defmodule Cacophony.Message do
@moduledoc """
Encoding and decoding of ASN.1 LDAP messages to high-level types.
+
+ ## Known Limitations
+
+ * Cannot interpret ExtendedResponse objects. Extended response objects
+ are encapsulated as an ExtendedResponse type. Matching up OIDs is up
+ to you.
"""
require Logger
defmodule BindRequest do
@moduledoc "A type representing a BindRequest."
defstruct [:id, :version, :cn, :credentials]
end
defmodule BindResponse do
@moduledoc "A type representing a BindResponse."
defstruct [
:id,
:result_code,
:matched_cn,
{:diagnostic_message, ""},
{:referral, :asn1_NOVALUE},
{:server_sasl_creds, :asn1_NOVALUE}
]
end
defmodule UnbindRequest do
@moduledoc "A type representing an UnbindRequest."
defstruct [:id]
end
+ @whoami_oid "1.3.6.1.4.1.4203.1.11.3"
+
+ defmodule WhoAmIRequest do
+ @moduledoc "A type representing a Who Am I request (RFC 4532)."
+
+ defstruct [:id]
+ end
+
+ defmodule WhoAmIResponse do
+ @moduledoc "A type representing a Who Am I response (RFC 4532)."
+
+ defstruct [
+ :id,
+ {:result_code, :success},
+ {:matched_dn, ""},
+ {:diag_msg, ""},
+ {:referral, :asn1_NOVALUE},
+ :authzid
+ ]
+ end
+
+ defmodule ExtendedRequest do
+ @moduledoc "A catch-all type for any extended request."
+
+ defstruct [:id, :request_name, :request_value]
+ end
+
+ defmodule ExtendedResponse do
+ @moduledoc "A catch-all type for any extended responses."
+
+ defstruct [
+ :id,
+ {:result_code, :success},
+ {:matched_dn, ""},
+ {:diag_msg, ""},
+ {:referral, :asn1_NOVALUE},
+ :response_name,
+ :response_value
+ ]
+ end
+
def interpret(:bindRequest, {:BindRequest, vsn, cn, creds}, message_id),
do: {:ok, %BindRequest{id: message_id, version: vsn, cn: cn, credentials: creds}}
def interpret(
:bindResponse,
{:BindResponse, result, matched_cn, diag_msg, referral, sasl_creds},
message_id
),
do:
{:ok,
%BindResponse{
id: message_id,
result_code: result,
matched_cn: matched_cn,
diagnostic_message: diag_msg,
referral: referral,
server_sasl_creds: sasl_creds
}}
def interpret(:unbindRequest, _, message_id), do: {:ok, %UnbindRequest{id: message_id}}
+ def interpret(:extendedReq, {:ExtendedRequest, @whoami_oid, :asn1_NOVALUE}, message_id),
+ do: {:ok, %WhoAmIRequest{id: message_id}}
+
+ def interpret(:extendedReq, {:ExtendedRequest, request_name, request_value}, message_id),
+ do:
+ {:ok,
+ %ExtendedRequest{id: message_id, request_name: request_name, request_value: request_value}}
+
+ def interpret(
+ :extendedResp,
+ {:ExtendedResponse, result, matched_dn, diag_msg, referral, response_name,
+ response_value},
+ message_id
+ ),
+ do:
+ {:ok,
+ %ExtendedResponse{
+ id: message_id,
+ result_code: result,
+ matched_dn: matched_dn,
+ diag_msg: diag_msg,
+ referral: referral,
+ response_name: response_name,
+ response_value: response_value
+ }}
+
def decode({:LDAPMessage, message_id, {type, payload}, _}),
do: interpret(type, payload, message_id)
def decode({:LDAPMessage, message_id, {type, payload}}),
do: interpret(type, payload, message_id)
def decode(message) when is_binary(message) do
with {:ok, data} <- :LDAP.decode(:LDAPMessage, message),
{:ok, struct} <- decode(data) do
{:ok, struct}
else
e -> {:error, e}
end
end
def decode(_), do: {:error, :badmatch}
def encode({:asn1, message}),
do: :LDAP.encode(:LDAPMessage, message)
def encode({:envelope, message_id, payload}),
do: encode({:asn1, {:LDAPMessage, message_id, payload, :asn1_NOVALUE}})
def encode(%BindRequest{} = msg) do
payload = {:BindRequest, msg.version, msg.cn, msg.credentials}
encode({:envelope, msg.id, {:bindRequest, payload}})
end
def encode(%BindResponse{} = msg) do
payload =
{:BindResponse, msg.result_code, msg.matched_cn, msg.diagnostic_message, msg.referral,
msg.server_sasl_creds}
encode({:envelope, msg.id, {:bindResponse, payload}})
end
def encode(%UnbindRequest{} = msg),
do: encode({:envelope, msg.id, {:unbindRequest, :asn1_NOVALUE}})
+ def encode(%WhoAmIRequest{} = msg),
+ do:
+ encode({:envelope, msg.id, {:extendedReq, {:ExtendedRequest, @whoami_oid, :asn1_NOVALUE}}})
+
+ def encode(%WhoAmIResponse{} = msg),
+ do:
+ encode(
+ {:envelope, msg.id,
+ {:extendedResp,
+ {:ExtendedResponse, msg.result_code, msg.matched_dn, msg.diag_msg, msg.referral,
+ :asn1_NOVALUE, msg.authzid}}}
+ )
+
+ def encode(%ExtendedRequest{} = msg),
+ do:
+ encode(
+ {:envelope, msg.id,
+ {:extendedReq, {:ExtendedRequest, msg.request_name, msg.request_value}}}
+ )
+
+ def encode(%ExtendedResponse{} = msg),
+ do:
+ encode(
+ {:envelope, msg.id,
+ {:extendedResp,
+ {:ExtendedResponse, msg.result_code, msg.matched_dn, msg.diag_msg, msg.referral,
+ msg.response_name, msg.response_value}}}
+ )
+
def encode(_), do: {:error, :badmatch}
end
diff --git a/test/cacophony/message_test.exs b/test/cacophony/message_test.exs
index b44a5fd..479f503 100644
--- a/test/cacophony/message_test.exs
+++ b/test/cacophony/message_test.exs
@@ -1,81 +1,136 @@
defmodule Cacophony.MessageTest do
use ExUnit.Case
+ @whoami_oid "1.3.6.1.4.1.4203.1.11.3"
+ @cirno_oid "9.99.999.9999.99999.999999"
+
describe "decode/1" do
test "successfully decodes a bindRequest" do
bindreq = {:BindRequest, 3, "cn=foo", {:simple, "bar"}}
message = {:LDAPMessage, 1, {:bindRequest, bindreq}, :asn1_NOVALUE}
{:ok, bin} = :LDAP.encode(:LDAPMessage, message)
{:ok, %Cacophony.Message.BindRequest{} = msg} = Cacophony.Message.decode(bin)
assert msg.id == 1
assert msg.cn == "cn=foo"
assert msg.credentials == {:simple, "bar"}
end
test "successfully decodes a bindResponse" do
bindresp = {:BindResponse, :success, "cn=foo", "", :asn1_NOVALUE, :asn1_NOVALUE}
message = {:LDAPMessage, 1, {:bindResponse, bindresp}, :asn1_NOVALUE}
{:ok, bin} = :LDAP.encode(:LDAPMessage, message)
{:ok, %Cacophony.Message.BindResponse{} = msg} = Cacophony.Message.decode(bin)
assert msg.id == 1
assert msg.matched_cn == "cn=foo"
assert msg.result_code == :success
end
test "successfully decodes an unbindRequest" do
message = {:LDAPMessage, 1, {:unbindRequest, :asn1_NOVALUE}, :asn1_NOVALUE}
{:ok, bin} = :LDAP.encode(:LDAPMessage, message)
{:ok, %Cacophony.Message.UnbindRequest{} = msg} = Cacophony.Message.decode(bin)
assert msg.id == 1
end
+
+ test "successfully decodes an extended whoAmIRequest" do
+ message =
+ {:LDAPMessage, 1, {:extendedReq, {:ExtendedRequest, @whoami_oid, :asn1_NOVALUE}},
+ :asn1_NOVALUE}
+
+ {:ok, bin} = :LDAP.encode(:LDAPMessage, message)
+
+ {:ok, %Cacophony.Message.WhoAmIRequest{} = msg} = Cacophony.Message.decode(bin)
+
+ assert msg.id == 1
+ end
+
+ test "successfully decodes an unknown extendedRequest" do
+ message =
+ {:LDAPMessage, 1, {:extendedReq, {:ExtendedRequest, @cirno_oid, :asn1_NOVALUE}},
+ :asn1_NOVALUE}
+
+ {:ok, bin} = :LDAP.encode(:LDAPMessage, message)
+
+ {:ok, %Cacophony.Message.ExtendedRequest{} = msg} = Cacophony.Message.decode(bin)
+
+ assert msg.id == 1
+ end
end
describe "encode/1" do
test "successfully encodes a bindRequest" do
bindreq = {:BindRequest, 3, "cn=foo", {:simple, "bar"}}
message = {:LDAPMessage, 1, {:bindRequest, bindreq}, :asn1_NOVALUE}
{:ok, bin} = :LDAP.encode(:LDAPMessage, message)
{:ok, %Cacophony.Message.BindRequest{} = msg} = Cacophony.Message.decode(bin)
{:ok, other_bin} = Cacophony.Message.encode(msg)
assert bin == other_bin
end
test "successfully encodes a bindResponse" do
bindresp = {:BindResponse, :success, "cn=foo", "", :asn1_NOVALUE, :asn1_NOVALUE}
message = {:LDAPMessage, 1, {:bindResponse, bindresp}, :asn1_NOVALUE}
{:ok, bin} = :LDAP.encode(:LDAPMessage, message)
{:ok, %Cacophony.Message.BindResponse{} = msg} = Cacophony.Message.decode(bin)
{:ok, other_bin} = Cacophony.Message.encode(msg)
assert bin == other_bin
end
test "successfully encodes an unbindRequest" do
message = {:LDAPMessage, 1, {:unbindRequest, :asn1_NOVALUE}, :asn1_NOVALUE}
{:ok, bin} = :LDAP.encode(:LDAPMessage, message)
{:ok, %Cacophony.Message.UnbindRequest{} = msg} = Cacophony.Message.decode(bin)
{:ok, other_bin} = Cacophony.Message.encode(msg)
assert bin == other_bin
end
+
+ test "successfully encodes an extended whoAmIRequest" do
+ message =
+ {:LDAPMessage, 1, {:extendedReq, {:ExtendedRequest, @whoami_oid, :asn1_NOVALUE}},
+ :asn1_NOVALUE}
+
+ {:ok, bin} = :LDAP.encode(:LDAPMessage, message)
+
+ {:ok, %Cacophony.Message.WhoAmIRequest{} = msg} = Cacophony.Message.decode(bin)
+
+ {:ok, other_bin} = Cacophony.Message.encode(msg)
+
+ assert bin == other_bin
+ end
+
+ test "successfully encodes an unknown extendedRequest" do
+ message =
+ {:LDAPMessage, 1, {:extendedReq, {:ExtendedRequest, @cirno_oid, :asn1_NOVALUE}},
+ :asn1_NOVALUE}
+
+ {:ok, bin} = :LDAP.encode(:LDAPMessage, message)
+
+ {:ok, %Cacophony.Message.ExtendedRequest{} = msg} = Cacophony.Message.decode(bin)
+
+ {:ok, other_bin} = Cacophony.Message.encode(msg)
+
+ assert bin == other_bin
+ end
end
end

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jan 21, 11:36 AM (1 d, 3 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
55710
Default Alt Text
(11 KB)

Event Timeline