Paddle (penguin_paddle v0.1.6) 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 :penguin_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"),
filter_passwords: true
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 . | [] |
:filter_passwords | Filter passwords from appearing in the logs | true |
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.
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.
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 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
Specs
add_ldap_error() :: :undefinedAttributeType | :objectClassViolation | :invalidAttributeSyntax | :noSuchObject | :insufficientAccessRights | :entryAlreadyExists
Specs
Specs
auth_status() :: :ok | {:error, atom()}
Specs
authenticate_ldap_error() :: :operationsError | :protocolError | :authMethodNotSupported | :strongAuthRequired | :referral | :saslBindInProgress | :inappropriateAuthentication | :invalidCredentials | :unavailable | :anonymous_auth
Specs
delete_ldap_error() :: :noSuchObject | :notAllowedOnNonLeaf | :insufficientAccessRights
Specs
Specs
Specs
Specs
modify_ldap_error() :: :noSuchObject | :undefinedAttributeType | :namingViolation | :attributeOrValueExists | :invalidAttributeSyntax | :notAllowedOnRDN | :objectClassViolation | :objectClassModsProhibited | :insufficientAccessRights
Specs
Specs
search_ldap_error() :: :noSuchObject | :sizeLimitExceeded | :timeLimitExceeded | :undefinedAttributeType | :insufficientAccessRights
Link to this section Functions
Specs
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"})
Specs
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']
Specs
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
.
Specs
config() :: keyword()
Get the whole configuration of the Paddle application.
Specs
Get the environment configuration of the Paddle application under a certain key.
Specs
Same as config/1
but allows you to specify a default value.
Specs
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).
Specs
get(dn()) :: {:ok, [ldap_entry()]} | {:error, search_ldap_error()}
get(Paddle.Class.t()) :: {:ok, [Paddle.Class.t()]} | {: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"]}]}
Specs
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}]}
Specs
get!(dn()) :: [ldap_entry()]
get!(Paddle.Class.t()) :: [Paddle.Class.t()]
Same as get/1
but throws in case of an error.
Specs
get!(Paddle.Class.t(), Paddle.Filters.t()) :: [Paddle.Class.t()]
Same as get/2
but throws in case of an error.
Specs
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"}
Specs
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}
Specs
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}