paddle v0.1.1 Paddle
Module handling ldap requests and translate them to the :eldap
syntax.
Configuration
The configuration should be in the dev.secret.exs or prod.secret.exs depending on the environment you’re working on. Here’s an example config:
config :paddle, Paddle,
host: "ldap.my-organisation.org",
base: "dc=myorganisation,dc=org",
ssl: true,
port: 636,
account_subdn: "ou=People",
group_subdn: "ou=Group",
account_class: "inetOrgPerson",
group_class: "posixGroup"
:host
- The host of the LDAP server. Mandatory:base
- The base DN.:ssl
- When set totrue
, use SSL to connect to the LDAP server. Defaults tofalse
.:port
- The port the LDAP server listen to. Defaults to389
.:account_subdn
- The DN (without the base) where the accounts are located. Defaults to"ou=People"
.:group_subdn
- The DN (without the base) where the groups are located. Defaults to"ou=Group"
.:account_class
- The class (objectClass) of all your user entries. Defaults to"posixAccount"
:group_class
- The class (objectClass) of all your group entries. Defaults to"posixGroup"
Usage
To check a user’s credentials and/or authenticate the connection, simply do:
Paddle.authenticate("username", "password")
You can also specify the partial DN like so:
Paddle.authenticate([cn: "admin"], "adminpassword")
Many functions support passing both a base and a filter via a keyword list like so:
Paddle.get(filter: [uid: "testuser"], base: [ou: "People"])
But you can also use structs which implements the Paddle.Class
protocol
(called class objects). Some are already defined:
Paddle.get %Paddle.PosixAccount{uid: "user"}
The previous example will return every accounts which are in a given subDN
(defined in the Paddle.Class
protocol), which have the right objectClass
(also defined in the same protocol), and have an uid of “user”.
You can also specify an additional filter as second argument.
You are also provided with some “user” functions that will automatically get the information from the right subDN and check that the entry have the right objectClass, see Configuration.
Example:
Paddle.users(filter: [givenName: "User"])
Class objects
A class object is simply a struct implementing the Paddle.Class
protocol.
Some “classes” are already defined and implemented (see
Paddle.PosixAccount
, and Paddle.PosixGroup
)
For more informations, see the Paddle.Class
module documentation.
Filters
A filter in Paddle is a Keyword list and the atom corresponding to the key must have a value strictly equal to, well the given value. When multiple keywords are provided, the result must match all criteria.
Example:
[uid: "user", cn: "User", homeDirectory: "/home/user"]
If you are missing some filtering capabilities, you can always pass as
argument an :eldap
filter like so:
Paddle.get(filter: :eldap.substrings('uid', initial: 'b'))
For more informations and examples, see Paddle.Filters.construct_filter/1
Bases
A base in Paddle can be a Keyword list that will be converted to a charlist
to be passed on to the :eldap
module. A direct string can also be passed.
For more informations and examples, see Paddle.Filters.construct_dn/2
Summary
Functions
Add an entry to the LDAP given a class object
Add an entry to the LDAP given a DN and a list of attributes
Check the given credentials
Get the environment whole configuration of the Paddle application
Get the environment configuration of the Paddle application under a certain key
Same as config/1
but allows you to specify a default value
Delete a LDAP entry given a DN or a class object
Get one or more LDAP entries given a keyword list
Get an entry in the LDAP given a class object. You can specify an optional additional filter as second argument
Same as get/1
but throws in case of an error
Same as get/2
but throws in case of an error
Get the DN of an entry
Get a single LDAP entry given a keyword list
Init the LDAP connection
Modify an LDAP entry given a DN or a class object and a list of modifications
Start the LDAP process
Terminate the LDAP connection
Types
add_ldap_error :: :undefinedAttributeType | :objectClassViolation | :invalidAttributeSyntax | :noSuchObject | :insufficientAccessRights | :entryAlreadyExists
delete_ldap_error :: :noSuchObject | :notAllowedOnNonLeaf | :insufficientAccessRights
mod :: {:add, {binary | atom, binary | [binary]}} | {:delete, binary} | {:replace, {binary | atom, binary | [binary]}}
modify_ldap_error :: :noSuchObject | :undefinedAttributeType | :namingViolation | :attributeOrValueExists | :invalidAttributeSyntax | :notAllowedOnRDN | :objectClassViolation | :objectClassModsProhibited | :insufficientAccessRights
search_ldap_error :: :noSuchObject | :sizeLimitExceeded | :timeLimitExceeded | :undefinedAttributeType | :insufficientAccessRights
Functions
add(Paddle.Class.t) :: :ok | {:error, :missing_unique_identifier} | {:error, :missing_req_attributes, [atom]} | {:error, add_ldap_error}
Add an entry to the LDAP given a class object.
Example:
Paddle.add(%Paddle.PosixAccount{uid: "myUser", cn: "My User", gidNumber: "501", homeDirectory: "/home/myUser"})
Add an entry to the LDAP given a DN and a list of attributes.
The first argument is the DN given as a string or keyword list as usual. The second argument is the list of attributes in the new entry as a keyword list like so:
[objectClass: ["account", "posixAccount"],
cn: "User",
loginShell: "/bin/bash",
homeDirectory: "/home/user",
uidNumber: 501,
gidNumber: 100]
Please note that due to the limitation of char lists you cannot pass directly
a char list as an attribute value. But, you can wrap it in an array like
this: homeDirectory: ['/home/user']
Check the given credentials.
The user id can be given through a binary, which will expand to
uid=<id>,<group subdn>,<base>
, or through a keyword list if you want to
specify the whole DN (still without the base).
Example:
iex> Paddle.authenticate("testuser", "test")
:ok
iex> Paddle.authenticate("testuser", "wrong password")
{:error, :invalidCredentials}
iex> Paddle.authenticate([cn: "admin"], "test")
:ok
Get the environment configuration of the Paddle application under a certain key.
Same as config/1
but allows you to specify a default value.
Delete a LDAP entry given a DN or a class object.
Examples:
Paddle.delete("uid=testuser,ou=People")
Paddle.delete([uid: "testuser", ou: "People"])
Paddle.delete(%Paddle.PosixAccount{uid: "testuser"})
The three examples above do exactly the same thing (provided that the
Paddle.PosixAccount
is configured appropriately).
Get one or more LDAP entries given a keyword list.
Example:
iex> Paddle.get(base: [uid: "testuser", ou: "People"])
{:ok,
[%{"cn" => ["Test User"],
"dn" => "uid=testuser,ou=People,dc=test,dc=com",
"gecos" => ["Test User,,,,"], "gidNumber" => ["120"],
"homeDirectory" => ["/home/testuser"],
"loginShell" => ["/bin/bash"],
"objectClass" => ["account", "posixAccount", "top"],
"uid" => ["testuser"], "uidNumber" => ["500"],
"userPassword" => ["{SSHA}AIzygLSXlArhAMzddUriXQxf7UlkqopP"]}]}
iex> Paddle.get(base: "uid=testuser,ou=People")
{:ok,
[%{"cn" => ["Test User"],
"dn" => "uid=testuser,ou=People,dc=test,dc=com",
"gecos" => ["Test User,,,,"], "gidNumber" => ["120"],
"homeDirectory" => ["/home/testuser"],
"loginShell" => ["/bin/bash"],
"objectClass" => ["account", "posixAccount", "top"],
"uid" => ["testuser"], "uidNumber" => ["500"],
"userPassword" => ["{SSHA}AIzygLSXlArhAMzddUriXQxf7UlkqopP"]}]}
iex> Paddle.get(base: [uid: "nothing"])
{:error, :noSuchObject}
iex> Paddle.get(filter: [uid: "testuser"], base: [ou: "People"])
{:ok,
[%{"cn" => ["Test User"],
"dn" => "uid=testuser,ou=People,dc=test,dc=com",
"gecos" => ["Test User,,,,"], "gidNumber" => ["120"],
"homeDirectory" => ["/home/testuser"],
"loginShell" => ["/bin/bash"],
"objectClass" => ["account", "posixAccount", "top"],
"uid" => ["testuser"], "uidNumber" => ["500"],
"userPassword" => ["{SSHA}AIzygLSXlArhAMzddUriXQxf7UlkqopP"]}]}
get(Paddle.Class.t, [tuple]) :: {:ok, [Paddle.Class.t]} | {:error, search_ldap_error}
Get an entry in the LDAP given a class object. You can specify an optional additional filter as second argument.
Example:
iex> Paddle.get(%Paddle.PosixAccount{})
{:ok,
[%Paddle.PosixAccount{cn: ["Test User"], description: nil,
gecos: ["Test User,,,,"], gidNumber: ["120"],
homeDirectory: ["/home/testuser"], host: nil, l: nil,
loginShell: ["/bin/bash"], o: nil,
ou: nil, seeAlso: nil, uid: ["testuser"],
uidNumber: ["500"],
userPassword: ["{SSHA}AIzygLSXlArhAMzddUriXQxf7UlkqopP"]}]}
iex> Paddle.get(%Paddle.PosixGroup{cn: "users"})
{:ok,
[%Paddle.PosixGroup{cn: ["users"], description: nil, gidNumber: ["2"],
memberUid: ["testuser"], userPassword: nil}]}
iex> Paddle.get(%Paddle.PosixGroup{}, :eldap.substrings('cn', initial: 'a'))
{:ok,
[%Paddle.PosixGroup{cn: ["adm"], description: nil, gidNumber: ["3"],
memberUid: nil, userPassword: nil}]}
Same as get/1
but throws in case of an error.
Same as get/2
but throws in case of an error.
Get the DN of an entry.
Example:
iex> Paddle.get_dn(%Paddle.PosixAccount{uid: "testuser"})
{:ok, "uid=testuser,ou=People"}
Get a single LDAP entry given a keyword list.
Example:
iex> Paddle.get_single(base: [ou: "People"])
{:ok,
%{"dn" => "ou=People,dc=test,dc=com",
"objectClass" => ["top", "organizationalUnit"], "ou" => ["People"]}}
iex> Paddle.get_single(filter: [uid: "nothing"])
{:error, :noSuchObject}
Init the LDAP connection.
This is called by the GenServer.start_link/3
function. GenServer will then
handle and keep the state, which is in this case the ldap connection, and
pass it we we need it.
Modify an LDAP entry given a DN or a class object and a list of modifications.
A modification is specified like so:
{action, {parameters...}}
Available modifications:
{:add, {field, value}}
{:delete, field}
{:replace, {field, value}}
For example, adding a “description” field:
{:add, {"description", "This is a description"}}
This allows you to do things like this:
Paddle.modify([uid: "testuser", ou: "People"],
add: {"description", "This is a description"},
delete: "gecos",
replace: {"o", ["Club *Nix", "Linux Foundation"]})
Start the LDAP process.
This function is called by the supervisor handled by the main application
in MyApplication.start/2
.