paddle v0.1.4 Paddle View Source
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,
ipv6: true,
tcpopts: [],
sslopts: [certfile: '/path/to/certificate.crt'],
timeout: 3000,
account_subdn: "ou=People",
schema_files: Path.wildcard("/etc/openldap/schema/*.schema")
Option | Description | Default |
---|---|---|
:host | The host(s) containing the LDAP server(s). Can be a bitstring for a single host, or a list of bitstrings, which will make Paddle try to connect to each host in the specified order. See also the :timeout option. | Mandatory |
:base | The base DN. | "" |
:ssl | When set to true , use SSL to connect to the LDAP server. | false |
:port | The port the LDAP server listen to. | 389 |
:ipv6 | When set to true , connect to the LDAP server using IPv6. | false |
:tcpopts | Additionnal :gen_tcp.connect/4 / :ssl.connect/4 options. Must not have the :active , :binary , :deliver , :list , :mode or :packet options. See :gen_tcp ’s option documentation. | [] |
:sslopts | Additionnal :ssl.connect/4 options. Ineffective if the :ssl option is set to false . See :ssl ’s option documentation. | [] |
:timeout | The timeout in milliseconds, or nil for the default TCP stack timeout value (which may be very long), for each request to the LDAP server. | nil |
:account_subdn | The DN (without the base) where the accounts are located. Used by the Paddle.authenticate/2 function. | "ou=People" |
:account_identifier | The identifier by which users are identified. Used by the Paddle.authenticate/2 function. | :uid |
:schema_files | Files which are to be parsed to help generate classes using Paddle.Class.Helper . | [] |
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 or a map 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). If we take as example the
classes defined in test/support/classes.ex
, we could do:
Paddle.get %MyApp.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.
Class objects
A class object is simply a struct implementing the Paddle.Class
protocol.
If you’re in need of some examples, you can see the test/support/classes.ex
file which defines MyApp.PosixAccount
, and MyApp.PosixGroup
(but only
in test mode, so you would have to define your own).
For more informations, see the Paddle.Class
module documentation.
Filters
A filter in Paddle is a keyword list or a map.
This is equivalent to a filter where each attribute name (key from the map / keyword list) must have a corresponding value (value from the map / keyword list).
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
Link to this section 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 and authenticate the current connection
Returns a specification to start this module under a supervisor
Get the 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
Same as get/1
but throws in case of an error
Same as get/2
but throws in case of an error
Get one or more LDAP entries given a partial DN and a filter
Get an entry in the LDAP given a class object. You can specify an optional additional filter as second argument
Get the DN of an entry
Get a single LDAP entry given an optional partial DN and an optional filter
Modify an LDAP entry given a DN or a class object and a list of modifications
Closes the current connection and opens a new one
Link to this section Types
add_ldap_error() :: :undefinedAttributeType | :objectClassViolation | :invalidAttributeSyntax | :noSuchObject | :insufficientAccessRights | :entryAlreadyExists
authenticate_ldap_error() :: :operationsError | :protocolError | :authMethodNotSupported | :strongAuthRequired | :referral | :saslBindInProgress | :inappropriateAuthentication | :invalidCredentials | :unavailable | :anonymous_auth
delete_ldap_error() :: :noSuchObject | :notAllowedOnNonLeaf | :insufficientAccessRights
modify_ldap_error() :: :noSuchObject | :undefinedAttributeType | :namingViolation | :attributeOrValueExists | :invalidAttributeSyntax | :notAllowedOnRDN | :objectClassViolation | :objectClassModsProhibited | :insufficientAccessRights
search_ldap_error() :: :noSuchObject | :sizeLimitExceeded | :timeLimitExceeded | :undefinedAttributeType | :insufficientAccessRights
Link to this section 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(%MyApp.PosixAccount{uid: "myUser", cn: "My User", gidNumber: "501", homeDirectory: "/home/myUser"})
add(dn(), attributes()) :: :ok | {:error, add_ldap_error()}
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. 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']
authenticate(dn(), binary()) :: :ok | {:error, authenticate_ldap_error()}
Check the given credentials and authenticate the current connection.
When given the wrong credentials, returns {:error, :invalidCredentials}
The user id can be passed as a binary, which will expand to
<account_identifier>=<id>,<account subdn>,<base>
, or with a keyword list if
you want to specify the whole DN (but still without the base DN).
Example:
iex> Paddle.authenticate("testuser", "test")
:ok
iex> Paddle.authenticate("testuser", "wrong password")
{:error, :invalidCredentials}
iex> Paddle.authenticate([cn: "admin"], "test")
:ok
Returns a specification to start this module under a supervisor.
See Supervisor
.
Get the 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(Paddle.Class.t() | dn()) :: :ok | {:error, delete_ldap_error()}
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(%MyApp.PosixAccount{uid: "testuser"})
The three examples above do exactly the same thing (provided that the
MyApp.PosixAccount
is configured appropriately).
Same as get/1
but throws in case of an error.
get!(Paddle.Class.t(), Paddle.Filters.t()) :: [Paddle.Class.t()]
Same as get/2
but throws in case of an error.
get(dn()) :: {:ok, [ldap_entry()]} | {:error, search_ldap_error()}
Get one or more LDAP entries given a partial DN and a filter.
Example:
iex> Paddle.get(base: [uid: "testuser", ou: "People"])
{:ok,
[%{"cn" => ["Test User"],
"dn" => "uid=testuser,ou=People",
"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",
"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",
"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(), Paddle.Filters.t()) :: {: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(%MyApp.PosixAccount{})
{:ok,
[%MyApp.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(%MyApp.PosixGroup{cn: "users"})
{:ok,
[%MyApp.PosixGroup{cn: ["users"], description: nil, gidNumber: ["2"],
memberUid: ["testuser"], userPassword: nil}]}
iex> Paddle.get(%MyApp.PosixGroup{}, :eldap.substrings('cn', initial: 'a'))
{:ok,
[%MyApp.PosixGroup{cn: ["adm"], description: nil, gidNumber: ["3"],
memberUid: nil, userPassword: nil}]}
get_dn(Paddle.Class.t()) :: {:ok, binary()} | {:error, :missing_unique_identifier}
Get the DN of an entry.
Example:
iex> Paddle.get_dn(%MyApp.PosixAccount{uid: "testuser"})
{:ok, "uid=testuser,ou=People"}
get_single(dn()) :: {:ok, ldap_entry()} | {:error, search_ldap_error()}
Get a single LDAP entry given an optional partial DN and an optional filter.
Example:
iex> Paddle.get_single(base: [ou: "People"])
{:ok,
%{"dn" => "ou=People",
"objectClass" => ["top", "organizationalUnit"], "ou" => ["People"]}}
iex> Paddle.get_single(filter: [uid: "nothing"])
{:error, :noSuchObject}
modify(Paddle.Class.t() | dn(), [mod()]) :: :ok | {:error, modify_ldap_error()}
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"]})
Or, using class objects:
Paddle.modify(%MyApp.PosixAccount{uid: "testuser"},
add: {"description", "This is a description"},
delete: "gecos",
replace: {"o", ["Club *Nix", "Linux Foundation"]})
Closes the current connection and opens a new one.
Accepts connection information as arguments. Not specified values will be fetched from the config.
Example:
iex> Paddle.reconnect(host: ['example.com'])
{:error, {:not_connected, "connect failed"}}
iex> Paddle.reconnect()
{:ok, :connected}