1. Usando JWT en Python. Normas generales
2. Manejo de sesiones en Python
3. Pasar el openrety a TSL (ssh)
Informática de andar por casa.
1. Usando JWT en Python. Normas generales
2. Manejo de sesiones en Python
3. Pasar el openrety a TSL (ssh)
Tenemos que creare un programa para que verifique las credenciales de usuario y contraseña sobre el servidor LDAP
También debemos ponerlo en un servidor http para recibir dichos parámetros y devolver la autorización
Veamos el código fuente:
La primera línea es de (Shebang #!) que indica el ejecutor del programa. Si en una ventana de comandos ejecutamos xmldap.py, ya sabe que python lo deber ejecutar, que es el de la ruda indicada en el shebang, que es la del entorno virtual que tiene todos los módulos necesarios instalados. (Pero en este caso no lo vamos a ehjecutar con el shebang, sino el fichero python del siguiente apartado)
El módulo que nos da toda la gracia de acceso a LDAP es ldap3 que hay que instalarlo con "pip install ldap3" desde el entorno virtual
La función getProps se encarga de leer el fichero de propiedades para aceder al fichero de parámetros del servidor LDAP
La función autheticateByLogin se encarga de acceder al servidor LDAP y autenticar el usuario con su contraseña.
Las demás funciones son para obtener información del sistem LDAP
#!/home/eduard/MyPython/05.fasthtml/venv_fasthtml/bin/python3 import pprint from ldap3 import Server, Connection, ALL, ALL_ATTRIBUTES ,SAFE_SYNC, NTLM, ALL_ATTRIBUTES import sys import os #------Imprescindible para poder importar de otras carpetas (de basicutils) import sys from pathlib import Path #from ox import xmoxfrmdict2fasthtml as xmoxfrmdict2fasthtml path_root1 = Path(__file__).parents[1] # Damos un salto de directorio hacia arriba-> ximoutilsmod sys.path.append(str(path_root1)) path_root0 = Path(__file__).parents[0] # El mismo directorio sys.path.append(str(path_root0)) from basicutils import xmcrypto, xmfile # ------Fin imprescindible def getProps(): logs=[] logs.append('env='+str(os.environ)) logs.append('os.getenv("CONF_PYTHON")='+str(os.getenv("CONF_PYTHON"))) xmfile.addLinesToFile('/home/eduard/kk.log', logs) confFile=os.getenv("CONF_PYTHON")+'ldap.encrypted.yml' config= xmcrypto.getPropertiesFromFile(confFile) return config['ldapWindows'] '''Autheticate by login name and password''' def autheticateByLogin(usename: str, password: str)->bool: config=getProps() try: server = Server(config['serverName'], get_info=ALL) myUser=config['userPrefix']+usename conn = Connection(server, user=myUser, password=password) if conn.bind(): return True else: return False except Exception as e: print(f"LDAP error: {e}", file=sys.stderr) if 'conn' in locals(): conn.unbind() return False def getConn()->Connection: conn=None; config=None; baseDN=None try: config=getProps() baseDN=config['dn'][config['dn'].find("DC="):] server = Server(config['serverName'], get_info=ALL) conn = Connection(server, user=config['dn'], password=config['password'], auto_bind=True) return conn, config, baseDN except Exception as e: print(f"LDAP error: {e}", file=sys.stderr) if 'conn' in locals(): conn.unbind() return conn, config, baseDN '''Get all login names from LDAP''' def getAllLogins()->list: try: conn, config, baseDN=getConn() #conn.search(baseDN, '(&(objectclass=user) (sAMAccountName=*))',attributes=ALL_ATTRIBUTES) conn.search(baseDN, '(&(objectclass=person) (sAMAccountName=*))',attributes=['sAMAccountName']) entries=conn.entries return [str(e['sAMAccountName']) for e in entries] except Exception as e: print(f"LDAP error: {e}", file=sys.stderr) if 'conn' in locals(): conn.unbind() return [] '''Get all DNs from LDAP''' def getAllDNs()->list: try: conn, config, baseDN=getConn() conn.search(baseDN, '(&(objectclass=user) (sAMAccountName=*))',attributes=[]) #conn.search(baseDN, '(&(objectclass=person) (sAMAccountName=*))',attributes=['DN']) entries=conn.entries #pprint.pprint(entries) print(str(entries[0])) return [str(e)[:str(e).find(" - STATUS:")].replace('DN: ','')for e in entries] except Exception as e: print(f"LDAP error: {e}", file=sys.stderr) if 'conn' in locals(): conn.unbind() return [] if __name__ == "__main__": if len(sys.argv) != 3: print("Usage: authenticate.py <username> <password>") sys.exit(1) username = sys.argv[1] password = sys.argv[2] #print(f"username: {username}, password: {password}") ''' print(getAllDNs()) print (getAllLogins()) print(autheticateByLogin(username, password)) print(autheticateByLogin(username, password+'a')) print(autheticateByLogin(username+'a', password)) ''' if autheticateByLogin(username, password): print("OK") else: print("FAIL")
Cabe destacar :
Veamos el código:
#!/home/eduard/MyPython/05.fasthtml/venv_fasthtml/bin/python3 # auth_service.py from fastapi import FastAPI, HTTPException from pydantic import BaseModel import uvicorn import os import sys import base64 #------Imprescindible para poder importar de otras carpetas (de basicutils) import sys from pathlib import Path #from ox import xmoxfrmdict2fasthtml as xmoxfrmdict2fasthtml path_root1 = Path(__file__).parents[1] # Damos un salto de directorio hacia arriba-> ximoutilsmod sys.path.append(str(path_root1)) path_root0 = Path(__file__).parents[0] # El mismo directorio sys.path.append(str(path_root0)) from basicutils import xmldap # ------Fin imprescindible app = FastAPI() class AuthRequest(BaseModel): username: str password: str class AuthResponse(BaseModel): authenticated: bool def authenticate(username: str, password: str) -> bool: """ Your existing authentication function. Replace this implementation with your actual authentication logic. """ # Example implementation #if username == "admin" and password == "secret": # return True #return False return xmldap.autheticateByLogin(username, password) @app.post("/auth", response_model=AuthResponse) async def auth(request: AuthRequest): is_valid = authenticate(request.username, request.password) return AuthResponse(authenticated=is_valid) if __name__ == "__main__": uvicorn.run(app, host="127.0.0.1", port=5000)
Para ejecutarlo, hay que ir a un ventana de comandos y introducir
cd ruta-mdulos-python
./xmopenresty.py
Pues como está el shebang, ya sabe que python utilizará para su ejecución
Existen tres formas principales de configurar variables de entorno en Ubuntu:
#1. Bloquear nginx
sudo systemctl disable nginxsudo systemctl stop nginx
#2. Instalar prerequisitos
sudo apt-get -y install --no-install-recommends wget gnupg ca-certificates lsb-release#3. Importar la clave GPG de descarga (para Ubuntu 22 +)
wget -O - https://openresty.org/package/pubkey.gpg | sudo gpg --dearmor -o /usr/share/keyrings/openresty.gpg#4. Añadir el repositorio en sistemas x86_64 or amd64 para Ubuntu 22 +
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/openresty.gpg] http://openresty.org/package/ubuntu $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/openresty.list > /dev/null#5. Actualizar el índice APT
sudo apt-get update#6. Instalar el paquete
sudo apt-get -y install openresty#7. Verificar la instalación que debe devolver: nginx version: openresty/X.Y.Z
openresty -v#8. Arrancar/rearrancar/ pararel servicio
sudo systemctl start openrestysudo systemctl restart openrestysudo systemctl stop openresty#9. Permitir el servicio al arrancar (boot)
sudo systemctl enable openresty#10. Ver el estado del servicio
sudo systemctl status openresty
Y los logs están en:
# 1.Prerequisitos sudo apt install build-essential libreadline-dev unzip # 2. Descargar curl -R -O http://www.lua.org/ftp/lua-5.3.5.tar.gz # 3. Descomprimir tar -zxf lua-5.3.5.tar.gz # 4. Compilar cd lua-5.3.5 make linux test sudo make install
# 1.Instalar paquetes. # En este caso instala el paquete lua-python para poder ejecutar modulos python sudo luarocks install lua-python --check-lua-versions sudo luarocks install lua-resty-http sudo luarocks install lua-resty-openssl # 2. Ver los módulos instalados luarocks list # Devuelve #Rocks installed for Lua 5.1 #--------------------------- # #lua-resty-http # 0.17.2-0 (installed) - /usr/local/lib/#luarocks/rocks-5.1 # #lua-resty-lrucache # 0.09-2 (installed) - /usr/local/lib/#luarocks/rocks-5.1 # #lua-resty-openssl # 1.5.1-1 (installed) - /usr/local/lib/#luarocks/rocks-5.1 #
server { listen 8080;
#1. Creación de contenido.
# Cuando se accede a http://localhost:8080/hello:
# devuelve "Hello Word"
location /hello {
content_by_lua_block {
ngx.say("Hello, World!")
}
}
#2. Redirección dinámica en base al navegador (si es "curl" u otro)
# Cuando se accede a http://localhost:8080/route:
# te envía a http://localhost:8080/for-curl si operas en "curl"
# y sinó te envia a http://localhost:8080/for-browser
location /route { content_by_lua_block { local user_agent = ngx.var.http_user_agent if user_agent and user_agent:find("curl") then ngx.redirect("/for-curl", 302) else ngx.redirect("/for-browser", 302) end } } }
server { listen 8080; location /protected { access_by_lua_block {
-- Importamos el módulo lua-resty-jwt que debe estar previamente instalado local jwt = require "resty.jwt" local auth_header = ngx.var.http_Authorization if not auth_header or not auth_header:find("Bearer ") then ngx.status = ngx.HTTP_UNAUTHORIZED ngx.say("Missing or invalid Authorization header") return ngx.exit(ngx.HTTP_UNAUTHORIZED) end local token = auth_header:sub(8) -- Remove "Bearer "
--- "your_jwt_secret" es la clave secreta para verificar la firma del token
local jwt_obj = jwt:verify("your_jwt_secret", token)
if not jwt_obj.verified then
ngx.status = ngx.HTTP_UNAUTHORIZED
ngx.say("Unauthorized: " .. (jwt_obj.reason or "unknown reason"))
return ngx.exit(ngx.HTTP_UNAUTHORIZED)
end
}
content_by_lua_block {
ngx.say("Access Granted!")
}
}
}
curl http://localhost:8080/protected -H "Authorization: Bearer <your-jwt-token>"
Se puede utilizar el módulo adicional ngx_http_auth_request_module, pero se necesita una versión de nginx precompilada con este módulo adicional. Para Ubuntu se podría instalar nginx-extras. Pero da muchos problemas. Para ello se ha optado por configurar nginx para que uilizando fastCGI consulte un script python para autenticar usuarios sobre LDAP.
Supongamos que ya tenemos instalado python y un entorno virtual. Instalaremos pues nginx y fcgiwrap
# 1. Instalar paquetes requeridos
sudo apt update
sudo apt install nginx fcgiwrap
# 2. Verificar la versión de nginx instalada (en este caso 1.24.0 (Ubuntu)
nginx -v
# 3. Como curisidad si queremos mostra los módulos instalados en nginx
nginx -V 2>&1|xargs -n1|grep module
# 1. Arrancar el sercicio
sudo systemctl enable fcgiwrap
sudo systemctl start fcgiwrap
# 2. Verificar el servicio
systemctl status fcgiwrap
#!/home/edu/MyPython/05.fasthtml/env05/bin/python3
import os
import cgi
print("Content-Type: text/plain\n")
# Simulated authentication logic
form = cgi.FieldStorage()
username = form.getvalue("username")
password = form.getvalue("password")
if username == "admin" and password == "secret":
print("Authentication successful")
else:
print("Authentication failed")
sudo chmod +x /home/edu/MyPython/05.fasthtml/basicutils/xmlogin.py
http {
server {
listen 8001;
server_name localhost;
location /auth {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /home/edu/MyPython/05.fasthtml/basicutils/xmlogin.py;
fastcgi_pass unix:/var/run/fcgiwrap.socket;
}
}
}
Y aclara:
ldap_server my_ldap_server
:
url
: Especifica la URL del servidor LDAP. En este caso, ldap://municipio-dc-03.edificio.municipio:389
.dc=edificio,dc=municipio
: Indica la base de búsqueda en el árbol LDAP.
?uid
: Especifica el atributo de búsqueda del usuario (generalmente uid
o cn
).?sub
: Define el alcance de la búsqueda (sub
para buscar recursivamente en subárboles).(objectClass=person)
: Filtro para encontrar objetos LDAP que representan usuarios.binddn
y binddn_passwd
:
auth_ldap
y auth_ldap_servers
:
En este ejemplo, solo las solicitudes al directorio /protected
requieren autenticación LDAP. Si la autenticación es exitosa, el usuario puede acceder; de lo contrario, se muestra un desafío de autenticación.
Revisar los logs:
/var/log/nginx/access.log
/var/log/nginx/error.log
Asegurar conectividad con el servidor LDAP:
ldapsearch -H
ldap://municipio-dc-03.edificio.municipio
-D "cn=Ximo Dante,ou=SISTEMAS,ou=USUARIOS IMPORTANTES,dc=edificio,dc=municipio"
-w "mi_contraseña"
-b "dc=edificio,dc=municipio"
Supongamos que
Depurar errores comunes:
binddn
sobre todo no dejarse ningún OU ni DC ni por supuesto el CN. Para ello hemos ejecutado en Windows : dsquery user -name "Ximo Dante"binddn_passwd
.Usar LDAP con Nginx es posible con el módulo adecuado, como ngx_http_auth_ldap_module
o la solución comercial de Nginx Plus. Este enfoque permite autenticar usuarios centralmente mediante un servidor LDAP, lo cual es útil en entornos empresariales.
Se puede utilizar el módulo adicional ngx_http_auth_request_module, pero se necesita una versión de nginx precompilada con este módulo adicional. Para Ubuntu se podría instalar nginx-extras pero da problemas. Para ello utilizamos una ruta alternativa, compilando el módulo
sudo apt install nginx-extras #DA PROBLEMAS PUES NO RECONOCE EL SERVICIO LDAP
sudo apt update
sudo apt upgrade
# Install requiered packages
sudo apt install build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev libssl-dev git
# Download nginx versison 1.27.3
wget http://nginx.org/download/nginx-1.27.3.tar.gz
tar -xzvf nginx-1.27.3.tar.gz
cd nginx-1.27.3
# Clone LDAP Module
git clone https://github.com/kvspb/nginx-auth-ldap.git
# Configure Nginx with the LDAP Module
./configure --add-module=./nginx-auth-ldap --with-http_ssl_module --with-http_v2_module
# Compile and Install Nginx:
make
sudo make install
# Verify Installation: Check the installed Nginx binary for the LDAP module:
/usr/local/nginx/sbin/nginx -V
1. Introducción
Esto es un resumen de Saquib Khan
Nginx es:
# 1. Instalar Ubuntu en un contenedor docker usando el puerto 8080 de la máquina local y el puerto 80 del contenedor docker run -it -p 8080:80 ubuntu # 2. Instalar nginx apt-get update apt-get install nginx # 3. Verificar la instalación nginx -v
# 1. Instalar nginx en Ubuntu sudo apt update sudo apt install nginx # 2. Arrancar nginx sudo systemctl start nginx # 3. Verificar sudo systemctl status nginx
worker_processes auto; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 80; server_name localhost; location / { root /usr/share/nginx/html; index index.html index.htm; } } }
server { listen 80; server_name localhost; location / { root /usr/share/nginx/html; index index.html index.htm; } }
events { } http { server { listen 80; server_name _; # This means it will respond to any server name location / { return 200 "Hello from Nginx Conf File"; } } }
mkdir -p /www/data echo "<h1>Welcome to Nginx</h1>" > /www/data/index.html
server { listen 80; server_name localhost; root /www/data; location / { try_files $uri $uri/ =404; } }
location /images/ { root /var/www/images; }
upstream backend { server backend1.example.com; server backend2.example.com; }
server { listen 80; server_name example.com; location / { proxy_pass http://backend_server; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
upstream backend { server backend1.example.com; server backend2.example.com; } server { listen 80; server_name example.com; location / { proxy_pass http://backend; } }
server { listen 443 ssl; server_name example.com; ssl_certificate /etc/nginx/ssl/example.com.crt; ssl_certificate_key /etc/nginx/ssl/example.com.key; location / { root /var/www/html; index index.html; } } server { listen 80; server_name example.com; return 301 https://$host$request_uri; }
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=1g inactive=60m;
log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main;
192.168.1.1 - - [03/Jan/2025:12:34:56 +0000] "GET /index.html HTTP/1.1" 200 1024 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" "-"