Joven hacker sonriendo

Hackeamos su software

cero falsos positivos

Inteligencia experta + automatización eficaz

Implementar Módulos Personalizados de Autenticación

Nuestros ethical hackers explican cómo implementar o desarrollar módulos de autenticación personalizados de manera segura, de tal forma que estos puedan cumplir con los requerimientos y políticas implementadas dentro de una organización. En esta oportunidad se utiliza la clase LoginModule.

Necesidad

Desarrollar un módulo de autenticación personalizado.

Contexto

A continuación se describen las circunstancias bajo las cuales la siguiente solución tiene sentido:

  1. Se está desarrollando en Java.

Solución

En algunas situaciones es importante desarrollar un módulo de autenticación que se ajuste a los requerimientos y políticas de seguridad de la organización. Estos módulos personalizados pueden utilizarse en el esquema de autenticación conectable de Java.

  1. La clase LoginModule describe una interfaz para poder realizar esto.

  2. Cada LoginModule se instancia con un Subject, un CallbackHandler, un entorno y unas opciones específicas del módulo en cuestión.

  3. El Subject representa el sujeto que se está autenticando y contiene las credenciales relevantes.

  4. El CallbackHandler se usa para comunicar el LoginModule con los usuarios. Es un espacio adecuado para preguntar nombres de usuario y contraseñas.

  5. Las opciones del LoginModule representan opciones establecidas por un administrador en el archivo de configuración. Estas opciones son definidas por el LoginModule. Las opciones se definen usando una sintaxis de tipo llave=valor.

  6. El siguiente archivo de configuración muestra como se define la opción de depuración.

    conf.java
    1
    2
    3
    CountFiles {
      SimpleLoginModule required debug=true;
    };
    
  7. El archivo de configuración Se puede especificar en tiempo de ejecución con el argumento.

    ejecucion.java
    1
    Djava.security.auth.login.config=login.conf
    
  8. El archivo de configuración está dividido en diferentes entradas donde se define un nombre de aplicación. Al interior de cada uno de estos nombres están definidos los módulos de autenticación.

  9. Cada módulo se define por su nombre de clase totalmente definido. Además se debe especificar que tipo de comportamiento se desea para cada módulo, es decir, definir el campo Flag.

  10. Las siguientes son las opciones que se pueden definir:

    • Required: El LoginModule debe tener éxito.

    • Requisite: Se requiere que este LoginModule tenga éxito. Si es exitosa la autenticación, esta continúa al siguiente módulo. En otro caso, se retorna el control a la aplicación y se genera una excepción.

    • Sufficient: El LoginModule no está obligado a tener éxito. Pero si es exitoso, se retorna exitosamente la autenticación.

    • Optional: No es requerido que tenga éxito, si lo tiene o falla el proceso de autenticación, este continúa.

  11. Finalmente, en el ModuleOptions se pueden especificar opciones relativas a cada módulo de autenticación.

    options.java
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    Application {
      ModuleClass Flag ModuleOptions;
      ModuleClass Flag ModuleOptions;
      ModuleClass Flag ModuleOptions;
    };
    Application {
      ModuleClass Flag ModuleOptions;
      ModuleClass Flag ModuleOptions;
    };
    other {
      ModuleClass Flag ModuleOptions;
      ModuleClass Flag ModuleOptions;
    };
    
  12. El LoginModule almacena las opciones como un mapa de manera que los valores se pueden recuperar usando la llave, como se muestra en el siguiente código.

    loginmodule.java
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    public void initialize(Subject s, CallbackHandler cb, Map sharedMap, Map options)
    {
      if (debug)
      {
        System.err.println("SimpleLoginModule: initialize");
      }
      subject = s;
      callbackHandler = cb;
      debug = "true".equalsIgnoreCase((String) options.get("debug"));
    }
    
  13. Aunque la aplicación que invoca el proceso de autenticación ve una sola operación, en realidad el proceso ocurre en dos etapas. En la primera etapa, el método login es invocado por el método login de LoginContext. Este método realiza la autenticación y guarda su estado de autenticación en la variable privada succeeded. Una vez finalizado, el método ha de retornar true si tuvo éxito, false si esto debe ignorarse, o lanza una excepción de tipo LoginException para marcar el fallo. En este caso, el módulo no debe realizar reintentos o retardos. Esta responsabilidad pertenece a la aplicación.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    public boolean login() throws LoginException
    {
      if (debug)
      {
         System.err.println("SimpleLoginModule: login");
      }
      userName = "defaultUser";
      succeeded = true;
      return true;
    }
    
  14. En la segunda fase puede pasar dos cosas:

  15. Si la autenticación general de LoginContext fue exitosa, el método commit de LoginModule se invoca. Este método ha de validar si la autenticación propia del módulo fue exitosa. En caso de serlo, este método debe asociar la identidad y credenciales al Subject.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public boolean commit() throws LoginException
    {
      if (debug)
      {
        System.err.println("SimpleLoginModule: commit");
      }
      if (!succeeded) {
        userName = null;
        return false;
      }
      principal = new SimplePrincipal(userName);
      if (!subject.getPrincipals().contains(principal)) {
        subject.getPrincipals().add(principal);
      }
      userName = null;
      commitSucceeded = true;
      return true;
    }
    
  16. Si la autenticación general de LoginContext no tuvo éxito, el método abort es invocado para destruir o remover cualquier estado de autenticación previamente almacenado.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    public boolean abort() throws LoginException {
      if (debug)
        System.err.println("SimpleLoginModule: abort");
      if (succeeded == false)
        return false;
      else if (succeeded == true && commitSucceeded == true) {
        logout();
      }
      else {
        succeeded = false;
      }
      return true;
    }
    
  17. Finalmente, se invoca el método logout que es el responsable de realizar el proceso de salida de la autenticación.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public boolean logout() throws LoginException {
      if (debug)
        System.err.println("SimpleLoginModule: logout");
      subject.getPrincipals().remove(principal);
      principal = null;
      userName = null;
      succeeded = commitSucceeded = false;
      return true;
    }
    

Descargas

Puedes descargar el código fuente pulsando en los siguientes enlaces:

SimpleLoginModule.java Clase SimpleLoginModule.

SimplePrincipal.java Clase SimplePrincipal.

CountFiles.java Clase CountFiles.

CountFilesAction.java Clase CountFilesAction.




Haz un comentario

Estado de los servicios - Términos de Uso