Auth module (Enterprise)
Memgraph supports authentication and (optional) authorization using a custom built external auth module. The two supported operation modes are:
- authentication only (username/password verification)
- authentication and authorization (username/password verification and user to role mapping)
When a user connects to Memgraph the database will forward the user's supplied username and password to the external auth module and wait for it to deliver the authentication and/or authorization verdict back to the database. Based on the returned verdict, Memgraph will either close the connection to the connected user or it will allow the connection and set-up the user and/or role accordingly.
When Memgraph is switched to use the external auth module for authentication its internal users are automatically disabled. All users are authenticated only using the module, existing local users are ignored (unless they can be authenticated using the module).
As this is an Enterprise feature, once the Memgraph Enterprise license expires, newly created users will be granted all privileges. The existing users' privileges will still apply but you won't be able to manage them.
Authentication mode
In this mode, Memgraph will only perform authentication (verification of username and password) using the external auth module. All user-to-role mappings, as well as user and role permissions are managed through Memgraph.
When a user that has never logged into the database passes authentication using the external auth module, a user object is created for that user. The user can then be seen using the following query:
SHOW USERS;
This behavior can be changed to disable login for users that don't have an explicitly created user account.
Authorization mode
In this mode, Memgraph will perform both the authentication and authorization using the external auth module. The external module is used to determine user-to-role mappings, but user and role permissions are still managed through Memgraph.
When a user with a non-existing role within Memgraph logs into the database, that role object is created and assigned to the user.
The role can then be seen using the following query:
SHOW ROLES;
This behavior can be changed to disable login to users that don't have an explicitly created role.
Configuration flags
Use the following configuration flags to configure the external auth module authentication and authorization mechanisms used by Memgraph.
Flag | Description |
---|---|
--auth_module_executable | Path to the executable that should be used for user authentication/authorization. |
--auth_module-create_user | Controls whether users should be implicitly created on first login or they should be explicitly created manually. |
--auth_module-create_role | Controls whether roles should be implicitly created on first appearance or they should be explicitly created manually. |
--auth_module-manage_roles | Specifies whether the module is used only for authentication (value is false ), or it should be used for both authentication and authorization. |
--auth_module_timeout | Specifies the maximum time that Memgraph will wait for a response from the external auth module. |
--auth_password-permit_null | Can be set to false to disable null passwords. |
--auth_password-strength_regex | The regular expression that should be used to match the entire entered password to ensure its strength. |
Communication
Memgraph uses inter-process pipes to communicate with the module. The module
will receive auth requests on file descriptor 1000
and has to return auth
responses to file descriptor 1001
. The standard streams (stdin
and stdout
)
aren't used because external libraries often tend to write something to stdout
which is difficult to disable. By using separate file descriptors, stdout
is
left intact and can be used freely for debugging purposes (along with stderr
).
The protocol used between Memgraph and the module is as follows:
- Each auth request is sent as a JSON encoded object in a single line that is
terminated by a
\n
. - Each auth response must be sent as a JSON encoded object in a single line
that is terminated by a
\n
. - Auth requests are objects that contain the following keys:
username
- the user's usernamepassword
- the user's password
- Auth responses must be objects that contain the following keys:
authenticated
- abool
indicating whether the user is allowed to log in to the databaserole
- astring
indicating which role the user should have (must be supplied even when the module is used for authentication only)
If the external auth module crashes during the processing of an auth request,
Memgraph won't allow the user to log in to the database and will automatically
restart the auth module for the next auth request. All crash logs will be seen
in Memgraph's output (typically in systemd
logs using journalctl
).
Example
This very simple example auth module is written in Python, but any programming language can be used.
#!/usr/bin/python3
import json
import io
def authenticate(username, password):
return {"authenticated": True, "role": ""}
if __name__ == "__main__":
input_stream = io.FileIO(1000, mode="r")
output_stream = io.FileIO(1001, mode="w")
while True:
params = json.loads(input_stream.readline().decode("ascii"))
ret = authenticate(**params)
output_stream.write((json.dumps(ret) + "\n").encode("ascii"))
In the example you can see how the communication protocol works and you can see
the function that is used for authentication (and authorization). When writing
your own modules you have to reimplement the authenticate
function according
to your needs.
Because the authentication (and authorization) function has a simple signature, it is easy (and recommended) to write unit (or integration) tests in separate files. For example:
#!/usr/bin/python3
import module
assert module.authenticate("sponge", "bob") == {"authenticated": True, "role": ""}
assert module.authenticate("CHUCK", "NORRIS") == {"authenticated": True, "role": ""}
LDAP
Memgraph also supports authentication and authorization using LDAP with a built-in auth module that is packaged with Memgraph Enterprise.
The module supports two operation modes:
- authentication only (LDAP bind request)
- authentication and authorization (LDAP bind and search requests)
Authentication mode
When using LDAP authentication the module builds the DN used for authentication using the user specified username and the following formula:
DN = prefix + username + suffix
In most common situations the prefix
will be cn=
and the suffix
will be
,dc=example,dc=com
. With an example username alice
that would yield a DN
equal to cn=alice,dc=example,dc=com
which will then be used for the LDAP bind
operation with the user specified password.
Authorization mode
Authentication is performed in the same way as described above. After the user is
authenticated, the module searches through the role mapping root DN object that
contains role mappings. A role mapping object that has the current bound user
as its member
attribute is used as the user's role. The role that is mapped
to the user is the CN
attribute of the role mapping object. The attribute
that contains the user DN in the mapping object, as well as the attribute that
contains the role name, can be changed in the module configuration file to
accommodate your LDAP schema.
When searching for a role in directories that have thousands of roles, the search process could take some time, causing long login times.
Module requirements
The module is written in Python 3 and it must be installed on the server. The
Python version should be at least 3.5
. Also, you must have the following
Python 3 libraries installed:
ldap3
- used to communicate with the LDAP server.PyYAML
- used to parse the configuration file.
Module configuration
The module configuration file is located at
/etc/memgraph/auth_module/ldap.yaml
. An initial example configuration file
that has all settings documented and explained is located at
/etc/memgraph/auth_module/ldap.example.yaml
. For quick setup, you can copy the example
configuration file into the module configuration file.
Database configuration
In order to enable the use of the LDAP authentication and authorization module
you have to set the flag --auth-module-executable
to use
/usr/lib/memgraph/auth_module/ldap.py
.
Other flags that change the behavior of the database to module integration can be specified according to your needs.
Example
Organizations typically use an LDAP server to hold and manage the permissions. Because LDAP servers are already set-up in most large organizations, it is convenient for the organization to allow all staff members to have access to the database using the already available centralized user management system.
For this guide let's assume that we have an LDAP server that is serving the following data:
# Users root entry
dn: ou=people,dc=memgraph,dc=com
objectclass: organizationalUnit
objectclass: top
ou: people
# User dba
dn: cn=dba,ou=people,dc=memgraph,dc=com
cn: dba
objectclass: person
objectclass: top
sn: user
userpassword: dba
# User alice
dn: cn=alice,ou=people,dc=memgraph,dc=com
cn: alice
objectclass: person
objectclass: top
sn: user
userpassword: alice
# User bob
dn: cn=bob,ou=people,dc=memgraph,dc=com
cn: bob
objectclass: person
objectclass: top
sn: user
userpassword: bob
# User carol
dn: cn=carol,ou=people,dc=memgraph,dc=com
cn: carol
objectclass: person
objectclass: top
sn: user
userpassword: carol
# User dave
dn: cn=dave,ou=people,dc=memgraph,dc=com
cn: dave
objectclass: person
objectclass: top
sn: user
userpassword: dave
# Roles root entry
dn: ou=roles,dc=memgraph,dc=com
objectclass: organizationalUnit
objectclass: top
ou: roles
# Role moderator
dn: cn=moderator,ou=roles,dc=memgraph,dc=com
cn: moderator
member: cn=alice,ou=people,dc=memgraph,dc=com
objectclass: groupOfNames
objectclass: top
# Role admin
dn: cn=admin,ou=roles,dc=memgraph,dc=com
cn: admin
member: cn=carol,ou=people,dc=memgraph,dc=com
member: cn=dave,ou=people,dc=memgraph,dc=com
objectclass: groupOfNames
objectclass: top
To summarize, the dataset contains the following data:
ou=people,dc=memgraph,dc=com
- entry that holds all users.cn=dba,ou=people,dc=memgraph,dc=com
- userdba
that will be used as the database administrator.cn=alice,ou=people,dc=memgraph,dc=com
- regular useralice
.cn=bob,ou=people,dc=memgraph,dc=com
- regular userbob
.cn=carol,ou=people,dc=memgraph,dc=com
- regular usercarol
.cn=dave,ou=people,dc=memgraph,dc=com
- regular userdave
.
ou=roles,dc=memgraph,dc=com
- entry that holds all roles.cn=moderator,ou=roles,dc=memgraph,dc=com
- rolemoderator
that hasalice
as its member.cn=admin,ou=roles,dc=memgraph,dc=com
- roleadmin
that hascarol
anddave
as its members.
Authentication
Run Memgraph
Firs, prepare Memgraph for the integration with LDAP. Run a Memgraph instance without any users in its local authentication storage. For more details on how the native authentication storage works in Memgraph check user privileges.
Create an administrator
The first user in the database should be the database administrator. The username you are about to create must exist in the LDAP directory. Connect to the database and issue the following queries:
CREATE USER dba;
GRANT ALL PRIVILEGES TO dba;
Once the user is created and all privileges have been granted, it's safe to disconnect from the database and proceed with the LDAP integration.
Enable LDAP integration
To enable LDAP integration specify the following flag:
--auth-module-executable=/usr/lib/memgraph/auth_module/ldap.py
Also, add the following LDAP module configuration to
/etc/memgraph/auth_module/ldap.yaml
:
server:
host: "<LDAP_SERVER_HOSTNAME>"
port: <LDAP_SERVER_PORT>
encryption: "disabled"
cert_file: ""
key_file: ""
ca_file: ""
validate_cert: false
users:
prefix: "cn="
suffix: ",ou=people,dc=memgraph,dc=com"
roles:
root_dn: ""
root_objectclass: ""
user_attribute: ""
role_attribute: ""
Adjust the security settings according to your LDAP server security settings.
Once all the configuration options are set, restart the Memgraph database instance.
Check the integration
Verify that you can log into the database using the username dba
and password
dba
. It will confirm that the LDAP authentication is succesfully enabled.
Run the SHOW USERS;
query which should list only one user, dba
. It means no
other users have yet logged in.
Log in other users
User alice
should be able to log in with password alice
. Upon the first log
in, a new user is created for Alice in the database without any privileges.
The administrator dba
should modify Alice's privileges to include the MATCH
privilege using the following query:
GRANT MATCH TO alice;
Once Alice logs in the second time, she should be able to execute the following query:
MATCH (n) RETURN n;
If the dba
runs the SHOW USERS;
query, it should return both dba
and
alice
users.
Users Bob, Carol and Dave will also be able to log in to the database using their LDAP password, and their users will be created withou any privileges.
Disable log-in without a user
If you want to disable users to log in if they don't have a manually created user in the database, set the following configuration flag:
--auth-ldap-create-user=false
The database administrator (user dba
) will first have to explicitly create the
users so they'll be able to log in. If only dba
exists in the database at this
moment, they should run the following queries to create users:
CREATE USER alice;
CREATE USER bob;
Alice and Bob will can log in to the database because they have existing user accounts, but users Carol and Dave can't.
Authorization
This example shows how to set-up the LDAP auth module to deduce the user's role using LDAP search queries.
Verify user authentication
First, enable and verify user authentication like in the example above.
Enable role mapping
To enable role mapping for the described LDAP schema, modify the LDAP auth
module configuration file, specifically the section roles
, by adding the
following content:
roles:
root_dn: "ou=roles,dc=memgraph,dc=com"
root_objectclass: "groupOfNames"
user_attribute: "member"
role_attribute: "cn"
This configuration tells the LDAP module that all role mapping entries are
children of the ou=roles,dc=memgraph,dc=com
entry, that the children have
user DNs specified in their member
attribute and that the cn
attribute
should be used to determine the role name.
When a user logs in to the database, the LDAP auth module will go through all role mapping entries and will try to find out which role mapping entry has the user as its member.
So now when Alice logs in, the LDAP auth module will go through the following
entries: cn=admin,ou=roles,dc=memgraph,dc=com
and
cn=moderator,ou=roles,dc=memgraph,dc=com
. Because Alice is a member of the
moderator
role mapping, the LDAP auth module will assign role moderator to
Alice.
If the user dba
runs the SHOW ROLE FOR alice;
query, they will see that
Alice now has the role of a moderator
.
Adjust permissions
Permissions for users and roles are still managed through Memgraph, they can't be managed through the LDAP server.
Disable automatic role creation
You can disable automatic role creation by using using the following flag:
--auth-ldap-create-role=false
The database administrator (user dba
) now has to explicitly create the role
the users have so they will be able to log into the database:
CREATE ROLE moderator;
In this scenario Alice and Bob will be able to log in. Alice will be allowed to log in because her role (moderator) already exists. Bob will be allowed to log in because he doesn't have any role. Carol and Dave won't be allowed to log in because their role (administrator) doesn't exist.
If both automatic role creation and automatic user creation
(--auth-ldap-create-user=false
) are disabled, then both the user and the role
must exist for a user to successfully log in to the database.