benperiton
Using Active Directory GUID with Ecto UUID field
I’m attempting to integrate some AD stuff with my app, but I’m stuck on how to use the GUID that is returned with Ecto.
From exldap, I get this back:
'objectGUID' => [
[219, 12, 193, 79, 151, 81, 153, 75, 128, 88, 23, 96, 59, 10, 33, 175]
]
which is fine, except if I try and load it with Ecto I get the wrong UUID back:
[219, 12, 193, 79, 151, 81, 153, 75, 128, 88, 23, 96, 59, 10, 33, 175]
|> :binary.list_to_bin
|> Ecto.UUID.load
{:ok, "db0cc14f-9751-994b-8058-17603b0a21af"}
Expected: 4FC10CDB-5197-4B99-8058-17603B0A21AF
Actual: DB0CC14F-9751-994B-8058-17603B0A21AF
I’m sure there’ something obvious that I’m overlooking!
Marked As Solved
axelson
This was a cool little problem!
First step, find the “correct” format of the expected UUID “4FC10CDB-5197-4B99-8058-17603B0A21AF”
iex(50)> Ecto.UUID.dump("4FC10CDB-5197-4B99-8058-17603B0A21AF")
{:ok, <<79, 193, 12, 219, 81, 151, 75, 153, 128, 88, 23, 96, 59, 10, 33, 175>>}
Hmmm, some of those numbers look similar. Let’s look at them side by side (aligned by comma):
[79, 193, 12, 219, 81, 151, 75, 153, 128, 88, 23, 96, 59, 10, 33, 175]
[219, 12, 193, 79, 151, 81, 153, 75, 128, 88, 23, 96, 59, 10, 33, 175]
In chunks:
[79, 193, 12, 219, | 81, 151, | 75, 153, | 128, 88, 23, 96, 59, 10, 33, 175]
[219, 12, 193, 79, | 151, 81, | 153, 75, | 128, 88, 23, 96, 59, 10, 33, 175]
So for some reason (someone else may understand the reason) the first 4 numbers are reversed, then the next two, and the next two again, but all the rest after that match (which is why “8058-17603B0A21AF” is decoded correctly).
So you can write a function to convert as follows:
defmodule Test do
def convert(list) do
{first4, rest} = Enum.split(list, 4)
{second2, rest} = Enum.split(rest, 2)
{third2, rest} = Enum.split(rest, 2)
Enum.reverse(first4)
|> Enum.concat(Enum.reverse(second2))
|> Enum.concat(Enum.reverse(third2))
|> Enum.concat(rest)
end
end
Which can then be used for the desired output:
iex(55)> list = [219, 12, 193, 79, 151, 81, 153, 75, 128, 88, 23, 96, 59, 10, 33, 175]
[219, 12, 193, 79, 151, 81, 153, 75, 128, 88, 23, 96, 59, 10, 33, 175]
iex(56)> Test.convert(list) |> :binary.list_to_bin() |> Ecto.UUID.load()
{:ok, "4fc10cdb-5197-4b99-8058-17603b0a21af"}
Also Liked
benperiton
So that has now lead me to this: (Thanks to this post on mixed endian binaries - Pete Corey - Building Mixed Endian Binaries with Elixir)
iex(65)> << a::32, b::16, c::16, d::16, e::48 >> = [219, 12, 193, 79, 151, 81, 153, 75, 128, 88, 23, 96, 59, 10, 33, 175] |> :binary.list_to_bin
<<219, 12, 193, 79, 151, 81, 153, 75, 128, 88, 23, 96, 59, 10, 33, 175>>
iex(66)> << a::32-little, b::16-little, c::16-little, d::16-big, e::48-big >>
<<79, 193, 12, 219, 81, 151, 75, 153, 128, 88, 23, 96, 59, 10, 33, 175>>
iex(67)> << a::32-little, b::16-little, c::16-little, d::16-big, e::48-big >> |> Base.encode16
"4FC10CDB51974B99805817603B0A21AF"
And then a nice little function to swap:
def swap_endians(<< a::32, b::16, c::16, d::16, e::48 >>) do
<< a::32-little, b::16-little, c::16-little, d::16-big, e::48-big >>
end
[219, 12, 193, 79, 151, 81, 153, 75, 128, 88, 23, 96, 59, 10, 33, 175]
|> :binary.list_to_bin()
|> swap_endians()
|> Base.encode16()
"4FC10CDB2D51974B99805817603B0A21AF"
benperiton
Thank you!!
I spent so long looking at it, I couldn’t see that the first 3 parts were reversed! ![]()
Which with some googling leads to:
Variant bits aside, the two variants are the same except that when reduced to a binary form for storage or transmission, variant 1 UUIDs use “network” (big-endian) byte order, while variant 2 GUIDs use “native” (little-endian) byte order. In their textual representations, variants 1 and 2 are the same except for the variant bits.
When byte swapping is required to convert between the big-endian byte order of variant 1 and the little-endian byte order of variant 2, the fields above define the swapping. The first three fields are unsigned 32- and 16-bit integers and are subject to swapping, while the last two fields consist of uninterpreted bytes, not subject to swapping. This byte swapping applies even for version 3, 4, and 5 UUID’s where the canonical fields do not correspond to the content of the UUID
So I think that explains the ordering of the first 3 parts.
Thankyou again! ![]()
axelson
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #hex









