Gestión de usuarios

Para la gestión de los usuarios se han creado una serie subrutinas que se encuentran en el paquete Cactus::Users. A continuación se explica su funcionamiento.

Log de usuarios

Estas funciones utilizarán syslog para añadir a los log del sistema información sobre los accesos que se produzcan.

Con este fin se utilizará el paquete Sys::Syslog. Para hacer esto más sencillo hemos creado el paquete Cactus::Utils en el que se incluyen funciones que facilitan las acciones de log. En concreto en el caso de los usuarios se utilizará la rutina authlog.

sub authlog($$$$)
{
    my ($action, $user, $ip, $result) = @_;

    Sys::Syslog::openlog("Cactus", "", "LOG_AUTH");
    Sys::Syslog::syslog("LOG_INFO", "Action :$action, User: $user, IP: $ip, Result: $result");
    Sys::Syslog::closelog();
}

authlog acepta la acción (por ejemplo, nuevo usuario) sobre la que se almacenará información en el log, el usuario para el que se produce, la ip desde la que se ha hecho la petición y el resultado de la misma.

Estas entradas se harán en el log de autenticaciones de usuario (/var/log/auth.log) y serán de información. Posteriormente veremos como tener archivos de log propios para cactus.

Registro

Para permitir el registro se utilizará el script Cactus::Users::adduser que aceptará como argumentos el usuario y la contraseña y creará un usuario en el sistema.

sub adduser($$$)
{
my ($user, $pass, $ip) = @_;

if (!($user =~ /^[a-zA-Z_][a-zA-Z_0-9\-]*$/)) {
    Cactus::Utils::authlog("New User", $user, $ip, "User exists");
    return 402; # Invalid username
}

my $pu = Passwd::Unix->new();


if (! $pu->user($user) ) {

    my $hashed = Crypt::Password::password( $pass, undef, "sha512");
    my $home = '/home/'.$user;
    mkdir $home;

    my $gid = getgrnam('cactus-users');

    $pu->user($user, $hashed, $pu->maxuid + 1, $gid,
                        ' ', $home, '/bin/nologin');
    my $useruid = getpwnam($user);
    my $rootuser = getpwnam("root");
    mkdir "$home/mail";
    chown($rootuser, $gid, "$home");
    chmod 0755, "$home:";
    chown($useruid, $gid, "$home/mail");
    chmod 0755, "$home/mail:";

    setquota($user);

    Cactus::Utils::authlog("New User", $user, $ip, "OK");

    return 200;
} else {
    Cactus::Utils::authlog("New User", $user, $ip, "User exists");
    return 401; # User exists
}

}

En primer lugar se comprobará que el nombre de usuario es válido, es decir, que solo contenga letras, números, el guión (-) y que comience por una letra.

En caso de que sea correcto se utilizará el paquete Passwd::Unix que nos permite crear un objeto para interactuar con los archivos /etc/passwd, /etc/shadow y /etc/group.

Con este objeto comprobamos que no existe el usuario en el sistema. Si está disponible se cifrará la contraseña por medio de la función password del paquete Crypt::Password utilizando SHA de 512 bits y se creará el usuario con $pu->user().

También se asignan las cuotas de usuario, pero esto lo explicaremos más adelante.

adduser() devolverá:

  • 200 si se ha creado correctamente
  • 402 si el nombre de usuario no es válido
  • 401 si el usuario ya existe

En la creación del usuario, además se incluye la creación de una carpeta de usuario mediante mkdir y se le asigna la shell /bin/nologin. De este modo no se permitirá que los usuarios accedan directamente al sistema Debian. Tendrán que interactuar con todos los servicios desde otros clientes, ya sea mediante el servidor web, con un cliente de email o mediante sftp.

En la función anterior se ve el uso de authlog para guardar entradas de log, en los casos siguientes se omiten estas lineas para mayor claridad.

Una vez está lista esta función, mediante el mecanismo explicado en el apartado del servidor local Tronco, se podrá realizar el registro de un usuario mediante el siguiente formulario web.

Tras el registro recibiremos la correspondiente bienvenida.

formulario de registro

Además recibiremos un correo informandonos del registro.

email de registro

Login

Para autenticar a un usuario contra /etc/shadows se utilizará la función check_password que nos indica si la contraseña es correcta o no. Se obtiene el hash del usuario mediante Passwd::Unix y la función passwd() y se compara con la contraseña de la petición tras haberla cifrado.

sub check_user($$)
{

    my ($user, $pass) = @_;

    if (!($user =~ /^[a-zA-Z_][a-zA-Z_0-9\-]*$/))
    {
        return 402; # Invalid username
    }

    my $pu = Passwd::Unix->new();

    if ($pu->user($user))
    {
        my $encrypt = $pu->passwd($user);
        if(Crypt::Password::check_password($encrypt, $pass))
        {
            return 200;
        }else
        {
            return 401;
        }
    } else {
        return 402; # User doesn't exists
    }

check_password() devolverá:

  • 200 si se ha autenticado correctamente
  • 402 si el usuario no existe
  • 401 si la contraseña es incorrecta.

El formulario para acceder a la cuenta personal es el siguiente.

formulario de login

En caso de que la autenticación sea correcta, se accederá a los registros log de usuarios y se recopilarán los accesos inválidos desde la última autenticación correcta.

Esta lista de accesos se mostrarán al usuario al inciar su sesión. El código para acceder al log es el siguiente.

my $parser = Parse::Syslog->new("/var/log/auth.log", allow_future => 1);


while(my $sl = $parser->next) {
    if ($sl->{program} eq "Cactus")
    {
        if($sl->{text} =~ /^Action: Login, User: $user,/)
        {
            if($sl->{text} =~ /OK$/)
            {
                @wrong_access = ();
                my $date = scalar(localtime(($sl->{timestamp})));
                @last_access = [$date, $sl->{text}];

            }
            else
            {
                my $date = scalar(localtime(($sl->{timestamp})));
                push (@wrong_access, [$date, $sl->{text}]);
            }
        }
    }
}

Se hace uso de Parse::Syslog, que nos permite un fácil acceso a los campos de cada entrada del registro.

Para probarlo intentaremos acceder a nuestra cuenta recién creada con una contraseña inválida antes de introducirla correctamente. Comprobamos que, en efecto, nos avisa del intento de acceso a nuestra cuenta la primera vez que entramos.

formulario de login

Modificar Datos

La modificación de los datos se hará mediante el formulario siguiente. Dado que se ha instalado una base de datos en la que se almacenan estos datos, se hará uso de la misma para almacenar esta información desde el servidor web.

formulario de modificación de perfil

Si se actualizan nos mostrará la confirmación.

formulario de modificación de perfil

Modificar Contraseña

En caso de querer modificar la contraseña se deberá proporcionar la contraseña anterior y la nueva. Es necesario introducir ambas para evitar que alguien que tenga acceso temporal a un equipo conectado pueda realizar el cambio.

El código en perl hace uso de los mismos paquetes que en casos anteriores y su funcionamiento es similar.

sub changepass($$$$)
{

    my ($user, $newpass, $oldpass, $ip) = @_;

    if (!($user =~ /^[a-zA-Z_][a-zA-Z_0-9\-]*$/))
    {
        return 402; # Invalid username
    }

    my $pu = Passwd::Unix->new();

    if ($pu->user($user))
    {
        my $result = check_user($user, $oldpass);
        if($result==200)
        {
            my $newencpass = Crypt::Password::password( $newpass, undef, "sha512");
            $pu->passwd($user, $newencpass);
            return 200;
        }else
        {
            return 401;
        }
    } else {
        return 402; # User doesn't exists
    }
}

changepass() devolverá:

  • 200 si se ha autenticado correctamente
  • 402 si el usuario no existe
  • 401 si la contraseña es incorrecta.

A continuación se puede ver la ventana que se muestra al usuario para introducir las contraseñas y la de confirmación.

formulario de cambio de contraseña confirmación de cambio de contraseña

Recuperar Contraseña

En caso de querer recuperar la contraseña se podrá solicitar desde la página de login. En este caso se nos pedirá el email con el que nos registramos y se enviará un enlace temporal desde el que modificar la contraseña.

El código es similar al de cambiar la contraseña pero se suprime la necesidad de introducir la contraseña anterior ya que esta opción solo será accesible desde el correo personal del usuario.

sub forcechangepass($$$)
{

    my ($user, $newpass, $ip) = @_;

    if (!($user =~ /^[a-zA-Z_][a-zA-Z_0-9\-]*$/))
    {
        return 402; # Invalid username
    }
    my $pu = Passwd::Unix->new();

    if ($pu->user($user))
    {
        my $newencpass = Crypt::Password::password( $newpass, undef, "sha512");
        $pu->passwd($user, $newencpass);
        return 200;
    } else {
        return 402; # User doesn't exists
    }

}

forcechangepass() devolverá:

  • 200 si se ha autenticado correctamente
  • 402 si el usuario no existe
formulario de recuperar contraseña confirmación de envío de mail para recuperar contraseña formulario para introducir nueva contraseña

Eliminar Cuenta

En caso de que el usuario quiera eliminar su cuenta, igual que para el caso del cambio de contraseña, se deberá introducir la contraseña anterior.

De nuevo se hace uso del paquete Passwd::Unix, que esta vez nos permite eliminar el usuario.

sub deluser($$$)
{
    my ($user, $pass, $ip) = @_;

    if (!($user =~ /^[a-zA-Z_][a-zA-Z_0-9\-]*$/)) {
        return 402; # Invalid username
    }

    my $pu = Passwd::Unix->new();

    if ($pu->user($user) ) {
        if(200 == check_user($user, $pass))
        {
            $pu->del_user($user);
            return 200;
        }
        else
        {
            return 401;
        }
    } else {
        return 402; # User doesn't exists
    }
}

deluser() devolverá:

  • 200 si se ha autenticado correctamente
  • 402 si el usuario no existe
  • 401 si la contraseña es incorrecta.
formulario para eliminar usuario confirmación de usuario eliminado

Contenidos

Tema anterior

Integración de Postfix con Cactus web

Próximo tema

Cuotas de usuario

Esta página