viernes, 25 de abril de 2025

Simplificando la gestión de cambio de contraseñas en ambientes de base de datos Oracle 19c o superior arquitectura CDB

Han hecho un registro de las horas que dedican constantemente a brindar soporte en el cambio de contraseñas de usuarios, a los cuáles se les ha vencido su vigencia o que olvidaron la clave y hay que cambiar o bien que simplemente, por el tema de complejidad que tengamos implementada en la base de datos, los usuarios finales tomen la opción de dejar que pase el período de gracia y solicitar una nueva contraseña, por "pereza" a pensar en la complejidad que debe llevar la contraseña.?

Si es cierto, es una pregunta muy grande la que he hecho. Tienen toda la razón.

Pero han pensando tan sólo un segundo, realmente cuanto tiempo han dedicado a este tipo de tareas que son "cajoneras".?

A ver, cuando tienes decenas de bases de datos y cientos de usuarios y no confías la autenticación a un servicio LDAP para que otros sean los que sufran con el mantenimiento de vencimiento de contraseñas, la verdad es que uno busca como simplificar ciertas tareas.

Incluso, muchas veces, las acciones más comúnes tiene que ver con los vencimientos de los propios compañeros del área de TI en los ambientes de UAT o DEV.

Una manera de mitigar esta sobrecarga de trabajo es "semi-automatizando" la tarea.

Veamos a ver como lo podemos hacer.

Primero que todo, vamos a crear una PROFILE en la raiz de contenedor de base de datos, para que este disponible para todos los PDBs que tengamos que gestionar.

No vamos a ser tan rigurosos con los tiempos de vigencia y tiempo ocioso.

Nuestro PERFIL a crear, tendrá como parámetros 30 minutos de tiempo ocioso antes de ser desconectado, soporta hasta 5 fallas en el ingreso de la contraseña antes de bloquear la cuenta, va a tener un período de vida de 45 días y un período de gracia de 5. El usuario no podrá reutilizar la contraseña hasta que no se hayan cumplido 365 días y máximo podrá reutilizarla 10 veces.


CREATE PROFILE "C##PERFIL_USUARIOS_TI" LIMIT
COMPOSITE_LIMIT DEFAULT SESSIONS_PER_USER DEFAULT
CPU_PER_SESSION DEFAULT
CPU_PER_CALL DEFAULT
LOGICAL_READS_PER_SESSION DEFAULT
LOGICAL_READS_PER_CALL DEFAULT
IDLE_TIME 30
CONNECT_TIME DEFAULT
PRIVATE_SGA DEFAULT
FAILED_LOGIN_ATTEMPTS 5
PASSWORD_LIFE_TIME 45
PASSWORD_REUSE_TIME 365
PASSWORD_REUSE_MAX 10
PASSWORD_VERIFY_FUNCTION ora12c_strong_verify_function
PASSWORD_LOCK_TIME UNLIMITED 
PASSWORD_GRACE_TIME 5;

Una vez creado el perfil en la raíz de contenedor de base de datos, vamos a crear una función y un procedimiento en cada PDB que exista en el CDB, cambiando unicamente unos cuantos datos.

La función será la misma para todas las bases de datos acopladas. Esta función se encargará de crear por nosotros las contraseñas asignadas durante el cambio de la misma. Complijidad completa con caracteres en mayúscula, minúscula, números y caracteres especiales.

create or replace NONEDITIONABLE function generate_password(
no_of_digits in number,
no_of_special_characters in number,
no_of_lower in number,
no_of_upper in number
) return varchar2
AS

password VARCHAR2(40);
password_redefine VARCHAR2(40);
password_final VARCHAR2(40);
digits CONSTANT VARCHAR2(10) := '123456789';
lower CONSTANT VARCHAR2(26) := 'abcdefghijklmnpqrstuvwxyz';
upper CONSTANT VARCHAR2(26) := 'ABCDEFGHIJKLMNPQRSTUVWXYZ';
special CONSTANT VARCHAR2(32) := '!$+{}[]?#';

BEGIN
SELECT LISTAGG(letter, NULL) WITHIN GROUP (ORDER BY DBMS_RANDOM.VALUE)
INTO password
FROM (
SELECT SUBSTR(
digits,
FLOOR(DBMS_RANDOM.VALUE(1, LENGTH(digits) + 1)),
1
) AS letter
FROM DUAL
CONNECT BY LEVEL <= no_of_digits
UNION ALL
SELECT SUBSTR(
lower,
FLOOR(DBMS_RANDOM.VALUE(1, LENGTH(lower) + 1)),
1
) AS letter
FROM DUAL
CONNECT BY LEVEL <= no_of_lower
UNION ALL
SELECT SUBSTR(
upper,
FLOOR(DBMS_RANDOM.VALUE(1, LENGTH(upper) + 1)),
1
) AS letter
FROM DUAL
CONNECT BY LEVEL <= no_of_upper
UNION ALL
SELECT SUBSTR(
special,
FLOOR(DBMS_RANDOM.VALUE(1, LENGTH(special) + 1)),
1
) AS letter
FROM DUAL
CONNECT BY LEVEL <= no_of_special_characters
);
password_redefine :=dbms_random.string('U',2)||password;
RETURN password_redefine;
END;

Esta función estaría generando contraseñas parecidas a esta: MH46$1g+6p5dCr7ClZB5bQ5C3

Ahora bien, cada vez que cambiamos una contraseña a un usuario, a través del método de solicitud que tengamos en nuestra organización, debemos notificar personalmente al dueño de la contraseña por correo electrónico, con la información de la nueva contraseña.

Dentro de una buena gestión de contraseñas, es importante, que solo el custodio del usuario a nivel de la base de datos, sea conocedor de dicha contraseña, independientemente si es un ambiente de desarrollo o UAT. Muchas veces estos ambientes cuentan con información proveniente del ambiente de producción y aún cuando sea información desactualizada, puede generar una brecha de seguridad.

Mi recomendación, utilizar siempre el correo electrónico, como método informativo, para suministrar la nueva información de conexión.

Este es el procedimiento que vamos a utilizar para cambiar la contraseña al usuario, aceptando como parámetro el nombre del usuario y teniendo como salida, la nueva contraseña y la información básica de conexión al servicio en donde fue modificada la misma.

create or replace NONEDITIONABLE procedure cambiar_contrasena_user(p_usuario varchar2)
as

pwd varchar2(30);
uname varchar2(20) := p_usuario;
v_user dba_users.username%TYPE;
v_estado dba_users.account_status%TYPE;

begin
pwd := generate_password(9,2,6,6);
execute immediate 'alter user '||uname||' identified by "'||pwd||'"';
dbms_output.put_line('done=> user: '||uname||' | new password: '||pwd);
select username, account_status into v_user, v_estado from dba_users
where username=uname;
dbms_output.put_line('Ambiente=> BD:LABORATORIO_PDB1');
dbms_output.put_line('User=> user: '||uname||' estado: '|| v_estado);
dbms_output.put_line('jdbc:oracle:thin:@//127.0.0.1:1521/pdb1.sub12180050100.vcnlab1.oraclevcn.com');
end;

Lo único que debemos cambiar con cada PDB en donde vayamos a implementar esta opción, es el mensaje de salida en el "DBMS_OUTPUT" donde se indique el ambiente correspondiente y la conexión JDBC a la base de datos.

Veamos como quedaría implementado a nivel de un PDB.


SQL> alter session set container=pdb1;

Session altered.

SQL> create user test identified by oracle;

SQL> alter user test profile C##PERFIL_USUARIOS_TI;

User altered.

SQL>

Ahora si, cuando tengamos que cambiar la contraseña, vamos a utilizar el procedimiento para facilitar nuestra tarea y hacer un "COPY PASTE" de la información necesaria para enviar al dueño de la cuenta.


set serveroutput on
execute cambiar_contrasena_user('TEST');

A la hora de ejecutar el proceso, obtendremos la siguiente salida, que podemos cortar y pegar en el correo enviado al interesado.

done=> user: TEST | new password: MH46$1g+6p5dCr7ClZB5bQ5C3
Ambiente=> BD:LABORATORIO_PDB1
User=> user: TEST estado: OPEN
jdbc:oracle:thin:@//127.0.0.1:1521/pdb1.sub12180050100.vcnlab1.oraclevcn.com

Procedimiento PL/SQL terminado correctamente.

Te aseguro que te estarás ahorrando una buena cantidad de tiempo.


No hay comentarios:

Publicar un comentario

Te agradezco tus comentarios. Te esperamos de vuelta.

Todos los Sábados a las 8:00PM