Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F85826362
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Authored By
Unknown
Size
16 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/lib/cacophony/message.ex b/lib/cacophony/message.ex
index fb2b676..bd621d9 100644
--- a/lib/cacophony/message.ex
+++ b/lib/cacophony/message.ex
@@ -1,276 +1,324 @@
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, :dn, :credentials]
end
defmodule BindResponse do
@moduledoc "A type representing a BindResponse."
defstruct [
:id,
:result_code,
:matched_dn,
{: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
defmodule SearchRequest do
@moduledoc "A type representing a Search request."
defstruct [
:id,
:base,
{:scope, :baseObject},
{:deref_aliases, :neverDerefAliases},
:size_limit,
:time_limit,
:types_only,
:filter,
:attributes
]
end
defmodule SearchResultDone do
@moduledoc "A type representing the end of a set of SearchResultEntry items."
defstruct [
:id,
{:result_code, :success},
{:matched_dn, ""},
{:diag_msg, ""},
{:referral, :asn1_NOVALUE}
]
end
+ defmodule PartialAttribute do
+ @moduledoc "A type representing a PartialAttribute: key to 0 or more values."
+
+ defstruct [
+ :name,
+ {:values, []}
+ ]
+ end
+
+ defmodule SearchResultEntry do
+ @moduledoc "A type representing a SearchResultEntry: DN to 0 or more PartialAttribute items."
+
+ defstruct [
+ :id,
+ :object_name,
+ {:attributes, []}
+ ]
+ end
+
def interpret(:bindRequest, {:BindRequest, vsn, dn, creds}, message_id),
do: {:ok, %BindRequest{id: message_id, version: vsn, dn: dn, credentials: creds}}
def interpret(
:bindResponse,
{:BindResponse, result, matched_dn, diag_msg, referral, sasl_creds},
message_id
),
do:
{:ok,
%BindResponse{
id: message_id,
result_code: result,
matched_dn: matched_dn,
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 interpret(
:searchRequest,
{:SearchRequest, base, scope, deref_aliases, size_limit, time_limit, types_only, filter,
attributes},
message_id
),
do:
{:ok,
%SearchRequest{
id: message_id,
base: base,
scope: scope,
deref_aliases: deref_aliases,
size_limit: size_limit,
time_limit: time_limit,
types_only: types_only,
filter: filter,
attributes: attributes
}}
def interpret(
:searchResDone,
{:LDAPResult, result, matched_dn, diag_msg, referral},
message_id
),
do:
{:ok,
%SearchResultDone{
id: message_id,
result_code: result,
matched_dn: matched_dn,
diag_msg: diag_msg,
referral: referral
}}
+ def interpret(:searchResEntry, {:SearchResultEntry, matched_dn, attributes}, message_id),
+ do:
+ {:ok,
+ %SearchResultEntry{
+ id: message_id,
+ object_name: matched_dn,
+ attributes:
+ Enum.map(
+ attributes,
+ fn {:PartialAttribute, key, values} ->
+ %PartialAttribute{name: key, values: values}
+ end
+ )
+ }}
+
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.dn, msg.credentials}
encode({:envelope, msg.id, {:bindRequest, payload}})
end
def encode(%BindResponse{} = msg) do
payload =
{:BindResponse, msg.result_code, msg.matched_dn, 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(%SearchRequest{} = msg),
do:
encode(
{:envelope, msg.id,
{:searchRequest,
{:SearchRequest, msg.base, msg.scope, msg.deref_aliases, msg.size_limit, msg.time_limit,
msg.types_only, msg.filter, msg.attributes}}}
)
def encode(%SearchResultDone{} = msg),
do:
encode(
{:envelope, msg.id,
{:searchResDone,
{:LDAPResult, msg.result_code, msg.matched_dn, msg.diag_msg, msg.referral}}}
)
+ def encode(%SearchResultEntry{} = msg),
+ do:
+ encode(
+ {:envelope, msg.id,
+ {:searchResEntry,
+ {:SearchResultEntry, msg.object_name,
+ Enum.map(
+ msg.attributes,
+ fn %PartialAttribute{name: name, values: values} ->
+ {:PartialAttribute, name, values}
+ end
+ )}}}
+ )
+
def encode(_), do: {:error, :badmatch}
end
diff --git a/test/cacophony/message_test.exs b/test/cacophony/message_test.exs
index c5127b5..f465326 100644
--- a/test/cacophony/message_test.exs
+++ b/test/cacophony/message_test.exs
@@ -1,198 +1,224 @@
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.dn == "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_dn == "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
test "successfully decodes a searchRequest" do
searchreq =
{:SearchRequest, "", :baseObject, :neverDerefAliases, 0, 0, false,
{:present, "objectclass"}, ["supportedSASLMechanisms"]}
message = {:LDAPMessage, 1, {:searchRequest, searchreq}, :asn1_NOVALUE}
{:ok, bin} = :LDAP.encode(:LDAPMessage, message)
{:ok, %Cacophony.Message.SearchRequest{} = msg} = Cacophony.Message.decode(bin)
assert msg.id == 1
assert msg.attributes == ["supportedSASLMechanisms"]
assert msg.filter == {:present, "objectclass"}
assert msg.base == ""
assert msg.scope == :baseObject
assert msg.deref_aliases == :neverDerefAliases
assert msg.time_limit == 0
assert msg.size_limit == 0
refute msg.types_only
end
test "successfully decodes a searchResDone" do
searchresdone = {:SearchResultDone, :success, "", "", :asn1_NOVALUE}
message = {:LDAPMessage, 1, {:searchResDone, searchresdone}, :asn1_NOVALUE}
{:ok, bin} = :LDAP.encode(:LDAPMessage, message)
{:ok, %Cacophony.Message.SearchResultDone{} = msg} = Cacophony.Message.decode(bin)
assert msg.id == 1
end
+
+ test "successfully decodes a searchResEntry" do
+ searchresentry = {:SearchResultEntry, "cn=test", [{:PartialAttribute, "key", ["value1", "value2"]}]}
+ message = {:LDAPMessage, 1, {:searchResEntry, searchresentry}, :asn1_NOVALUE}
+
+ {:ok, bin} = :LDAP.encode(:LDAPMessage, message)
+
+ {:ok, %Cacophony.Message.SearchResultEntry{} = msg} = Cacophony.Message.decode(bin)
+
+ assert msg.id == 1
+ assert msg.object_name == "cn=test"
+ assert msg.attributes == [%Cacophony.Message.PartialAttribute{name: "key", values: ["value1", "value2"]}]
+ 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
test "successfully encodes a searchRequest" do
searchreq =
{:SearchRequest, "", :baseObject, :neverDerefAliases, 0, 0, false,
{:present, "objectclass"}, ["supportedSASLMechanisms"]}
message = {:LDAPMessage, 1, {:searchRequest, searchreq}, :asn1_NOVALUE}
{:ok, bin} = :LDAP.encode(:LDAPMessage, message)
{:ok, %Cacophony.Message.SearchRequest{} = msg} = Cacophony.Message.decode(bin)
{:ok, other_bin} = Cacophony.Message.encode(msg)
assert bin == other_bin
end
test "successfully encodes a searchResDone" do
searchresdone = {:SearchResultDone, :success, "", "", :asn1_NOVALUE}
message = {:LDAPMessage, 1, {:searchResDone, searchresdone}, :asn1_NOVALUE}
{:ok, bin} = :LDAP.encode(:LDAPMessage, message)
{:ok, %Cacophony.Message.SearchResultDone{} = msg} = Cacophony.Message.decode(bin)
{:ok, other_bin} = Cacophony.Message.encode(msg)
assert bin == other_bin
end
+
+ test "successfully encodes a searchResEntry" do
+ searchresentry = {:SearchResultEntry, "cn=test", [{:PartialAttribute, "key", ["value1", "value2"]}]}
+ message = {:LDAPMessage, 1, {:searchResEntry, searchresentry}, :asn1_NOVALUE}
+
+ {:ok, bin} = :LDAP.encode(:LDAPMessage, message)
+
+ {:ok, %Cacophony.Message.SearchResultEntry{} = 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
Fri, Oct 30, 6:47 AM (23 h, 25 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1799714
Default Alt Text
(16 KB)
Attached To
Mode
R11 cacophony
Attached
Detach File
Event Timeline