Authentication Driver

This guide will show you how to develop a new driver for OpenNebula to interact with an external authentication service.

OpenNebula comes with an internal user/password way of authentication, this is called core. To be able to use other auth methods there is a system that performs authentication with external systems. Authentication drivers are responsible for getting the user credentials from OpenNebula database and login and answer whether the authentication is correct or not.

In the OpenNebula database there are two values saved for every user, this is username and password. When the driver used for authentication is core (authenticated without an external auth driver) the password value holds the SHA256 hash of the user’s password. In case we are using another authentication method this password field can contain any other information we can use to recognize a user, for example, for x509 authentication this field contains the user’s public key.

Authentication Driver

Authentication drivers are located at /var/lib/one/remotes/auth. There is a directory for each of authentication drivers with an executable inside called authenticate. The name of the directory has to be the same as the user’s auth driver we want to authenticate. For example, if a user has as an auth driver x509 OpenNebula will execute the file /var/lib/one/remotes/auth/x509/authenticate when he performs an OpenNebula action.

The authentication driver expects parameters passed on the standard input as the XML document with following structure:

<AUTHN>
    <USERNAME>VALUE</USERNAME>
    <PASSWORD>VALUE</PASSWORD>
    <SECRET>VALUE</SECRET>
</AUTHN>

Where:

  • USERNAME: name of the user who wants to authenticate.

  • PASSWORD: value of the password field for the user that is trying to authenticate. This can be - when the user does not exist in the OpenNebula database.

  • SECRET: value provided in the password field of the authentication string.

Warning

Before OpenNebula 5.6, the parameters were passed as command line parameters. Now all the data is passed using only the standard input!

For example, we can create a new authentication method that just checks the length of the password. For this we can store in the password field the number of characters accepted, for example 5, and user name test. Here are some example calls to the driver with several passwords:

echo '<AUTHN><USERNAME>test</USERNAME><PASSWORD>5</PASSWORD><SECRET>testpassword</SECRET></AUTHN>' | \
    authenticate

echo '<AUTHN><USERNAME>test</USERNAME><PASSWORD>5</PASSWORD><SECRET>another_try</SECRET></AUTHN>' | \
    authenticate

echo '<AUTHN><USERNAME>test</USERNAME><PASSWORD>5</PASSWORD><SECRET>12345</SECRET></AUTHN>' | \
    authenticate

The script should exit with a non 0 status when the authentication is not correct and write in stderr the error. When the authentication is correct it should return:

  • Name of the driver. This is used when the user does not exist, this will be written to the user’s the auth driver field.

  • User name

  • Text to write in the user’s password field in case the user does not exist.

The code for the /var/lib/one/remotes/auth/length/authenticate executable can be:

#!/bin/bash

data=$(cat -)

username=$(echo "${data}" | xmllint --xpath '//AUTHN/USERNAME/text()' -)
password=$(echo "${data}" | xmllint --xpath '//AUTHN/PASSWORD/text()' -)
secret=$(echo "${data}" | xmllint --xpath '//AUTHN/SECRET/text()' -)

length=$(echo -n "$secret" | wc -c | tr -d ' ')

if [ $length = $password ]; then
    echo "length $username $secret"
else
    echo "Invalid password"
    exit 255
fi

Enabling the Driver

To be able to use the new driver we need to add its name to the list of enabled drivers in oned.conf:

AUTH_MAD = [
    executable = "one_auth_mad",
    authn = "ssh,x509,ldap,server_cipher,server_x509,length"
]

Managed Groups

The authentication driver may also assign user to groups, this requires that DRIVER_MANAGED_GROUPS option is to be set to YES, e.g. like for the ldap driver

AUTH_MAD_CONF = [
    NAME = "ldap",
    PASSWORD_CHANGE = "YES",
    DRIVER_MANAGED_GROUPS = "YES",
    DRIVER_MANAGED_GROUP_ADMIN = "YES",
    MAX_TOKEN_TIME = "86400"
]

Driver then needs to pass the space-separated group ids right after the username and the secret.

Such a driver response then looks like following line

ldap userx CN=userx,CN=Users,DC=opennebula,DC=org *100 101

Optionally, the group id might be marked by a preceding asterix char *. In that case, the user will be assigned to the group as an admin. See group admins for details.