Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F140764
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
11 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
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)
Attached To
Mode
R11 cacophony
Attached
Detach File
Event Timeline
Log In to Comment