Tipos de usuarios - UltraTesla/UTesla GitHub Wiki

Hay dos tipos de usuarios a tener en cuenta para crear una infraestructura correcta:

  • Usuario administrativo: Es el usuario encargado del servidor y creador de toda la infraestructura.
  • Usuario invitado: Es aquel que necesita de un token de acceso generado por un usuario administrativo para poder hacer uso de los servicios de la red.

Algunos servicios se comportarán de manera diferente cuando un usuario es un invitado o no, como generate_token, que no permite su uso cuando sé es un usuario invitado.

generate_token se comporta de esa menera porque así obliga al usuario a usar un token de acceso que solo el usuario administrativo ha generado.

¿Con qué fin?

¡Un negocio! o tal vez simplemente separar roles o lo que sea que desee el usuario, pero para una mejor explicación usemos el gráfico.

Como se puede observar en la imagen anteriormente mostrada, la Empresa A contiene los servicios: Servicio 1, Servicio 2 y Servicio 3; la Empresa A desea compartirlos a las demás empresas (Empresa B y Empresa C) pero para que esto puedo ser posible, esas empresas deben pagar por un token de acceso y cada servicio puede sumarle más al valor de él.

Entonces el token de acceso puede permitir acceder sólo a ciertos servicios que el administrador del servidor decida, y ese token será compartido a los usuarios invitados que podrán usar determinados servicios.

Es por eso que no se puede usar el servicio generate_token siendo usuario invitado, aunque esta característica no es de Ultra Tesla en sí, más bien es de ese servicio exclusivamente.

Lo que sí es parte de UTesla es que un usuario administrativo no tiene restricción sobre qué servicios usar; un usuario administrativo tiene permiso de usar absolutamente todos.

Volviendo la ficción en realidad

Vamos a recrear el gráfico usando Ultra Tesla. Primero vamos a crear un usuario administrador y dos usuarios invitados.

Primero creamos el usuario administrador:

# Generamos el par de claves Ed25519
python3.8 ./UTeslaCLI generate_keys -out-public-key /tmp/pubkey -out-private-key /tmp/privkey
# Ahora lo agregamos
python3.8 ./UTeslaCLI add -u administrador -p password123@ -i /tmp/pubkey -l 0

Los usuarios deben generar sus propios pares de claves y luego compartir la clave pública con el usuario administrador.

# Las empresas primero deben generar sus par de claves.
#
# Primero la empresa A
python3.8 ./UTeslaCLI generate_keys -out-public-key /tmp/empresa.1.pub -out-private-key /tmp/empresa.1.priv
# Ahora la empresa B
python3.8 ./UTeslaCLI generate_keys -out-public-key /tmp/empresa.2.pub -out-private-key /tmp/empresa.2.priv

Ahora el administrador agrega a los usuarios como invitados.

# Empresa A
python3.8 ./UTeslaCLI add -u empresa_A -p password123@ -i /tmp/empresa.1.pub -g
# Empresa B
python3.8 ./UTeslaCLI add -u empresa_B -p password123@ -i /tmp/empresa.2.pub -g

En este punto, el usuario administrador debe generar un token de acceso con una cantidad limitada de servicios; para este ejemplo el servicio Servicio 1 y el Servicio 3 que se mostraron en la imagen, serán index y hello_world.

python3.8 ./UTeslaCLI generate_token -s keys/ed25519.pub -i /tmp/pubkey -I /tmp/privkey -u administrador -p password123@ localhost -S '(index|hello_world)'

Nota: El valor del parámetro -S es una expresión regular con un máximo según lo que esté configurado en el archivo config/database.sql (255, de forma pre-determinada)

La salida sería:

Token: a8f55ecd592234b7cf2603db88b92b34d7f39861979e0c6a58c1188e2f84220d

Ese token es el que le daremos a las empresas y como se indicó en la generación del token, solo se podrán usar el servicio index y hello_world.

Ahora un cliente puede requerir un servicio determinado (como index):

import asyncio
import pprint

from modules.Infrastructure import client

async def main():
    (host, port) = "localhost", 17000
    user = "empresa_A"
    server_key = "keys/ed25519.pub"
    public_key, private_key = "/tmp/empresa.1.pub", "/tmp/empresa.1.priv"

    with open(server_key, "rb") as fd:
        server_key = fd.read()

    with open(public_key, "rb") as fd:
        public_key = fd.read()

    with open(private_key, "rb") as fd:
        private_key = fd.read()

    (UControl, _, stream) = await client.simple_client(
        host,
        port,
        user,
        server_key,
        public_key = public_key,
        private_key = private_key,

    )

    UControl.set_token("a8f55ecd592234b7cf2603db88b92b34d7f39861979e0c6a58c1188e2f84220d")
    UControl.set_path("/index", "get")

    await UControl.write(None)
    print("Respuesta:", await UControl.read())

    print()
    print("Encabezados del servidor:")
    pprint.pprint(UControl.request.headers)
    
    print()
    print("Encabezados del cliente:")
    pprint.pprint(UControl.headers)

    stream.close()

if __name__ == "__main__":
    asyncio.run(main())

Y obtendría:

python3.8 client.py
Respuesta: ¡Hola Mundo!

Encabezados del servidor:
{'action': 'get',
 'force': False,
 'init_params': {},
 'is_packed': True,
 'limit': 104857600,
 'node': (),
 'params': {},
 'path': '/index',
 'status': '',
 'status_code': 0,
 'token': '',
 'version': '2.0.1'}

Encabezados del cliente:
{'action': 'get',
 'init_params': {},
 'params': {},
 'path': '/index',
 'status': '',
 'status_code': 0,
 'token': 'a8f55ecd592234b7cf2603db88b92b34d7f39861979e0c6a58c1188e2f84220d'}

Sin embargo cuando el cliente intenta acceder a un servicio que no tiene permisos, la respuesta sería diferente:

Respuesta: None

Encabezados del servidor:
{'action': 'get',
 'force': False,
 'init_params': {},
 'is_packed': True,
 'limit': 104857600,
 'node': (),
 'params': {},
 'path': '/get_services',
 'status': 'Permiso denegado',
 'status_code': 1,
 'token': '',
 'version': '2.0.1'}

Encabezados del cliente:
{'action': 'get',
 'init_params': {},
 'params': {},
 'path': '/get_services',
 'status': '',
 'status_code': 0,
 'token': 'a8f55ecd592234b7cf2603db88b92b34d7f39861979e0c6a58c1188e2f84220d'}