6. control de acceso
Transcript of 6. control de acceso
Seguridad en aplicaciones JavaEE
CONTENIDOS
Introducción. Criptografía con Java. Infraestructura con PKI con Java. Control de acceso. Aplicaciones con Java SSL. Seguridad en aplicaciones WEB. Introducción a la seguridad en los web services.
Control de acceso
Evolución del modelo de seguridad. El “Security Manager”.
Evolución del “Security Manager”.Cómo portar gestores de seguridad de la 1.1.
Ficheros de políticas de seguridad (Policy Files).Cambios en las políticas en Java 2 SDK SE 1.4.Implementación por defecto de políticas de seguridad.Localizaciones por defecto de los ficheros de políticas.Especificar un fichero de políticas adicional en tiempo de ejecución.Cambiar la implementación de Policy.
Control de acceso
Sintaxis del fichero de políticas.Ejemplos de ficheros de políticas de seguridad.Expansión de propiedades en los ficheros de políticas.
Java Authentication and Authorization Service (JAAS).
Introducción.Descripción del servicio JAAS.Autenticación JAAS.Autorización JAAS.Conclusión.
Control de acceso
Java proporciona en sus API un conjunto de clases, interfaces y herramientas que proporcionan la seguridad para las aplicaciones.
El desarrollador J2EE tiene que tener una comprensión profunda de los fundamentos de la seguridad Java.
Sin embargo, no tiene que saber cómo se implementan las medidas de seguridad.
Evolución del modelo de seguridad
JDK 1.1: las aplicaciones locales y applets firmados digitalmente de forma correcta tenían acceso total a recursos vitales del sistema, como el sistema de archivos, mientras que los applets sin firma podían acceder sólo a recursos limitados. Un “security manager” era responsable de determinar qué accesos a recursos se permitían.
Java 2 SDK: basada en políticas de seguridad (policies). La política de seguridad especifica qué permisos están disponibles para el código.
Métodos del Security Manager
La clase SecurityManager contiene varios métodos con nombres que comienzan por la palabra check:
checkReadcheckConnect…
Muchos métodos de las bibliotecas de Java llaman a un método check antes de realizar una operación sensible a la seguridad. De este modo se le da una oportunidad al security manager de prevenir la ejecución de la operación lanzando una excepción.
Métodos del Security Manager
Una rutina del gestor de seguridad simplemente retorna si la operación está permitida, pero lanza una excepción si la operación no lo está.
Existe otro tipo de métodos contenidos en la clase SecurityManager, relacionados con la existencia y profundidad del class loader:
currentClassLoader
currentLoadedClassinClassLoaderclassLoaderDepth
Security Manager en JDK 1.1
Cualquier aplicación que quería instalar un gestor de seguridad tenía que escribirlo ella misma, proporcionando implementaciones concretas apropiadas de los métodos que lanzaban excepciones por defecto, sobre todo los métodos check.
La clase java.lang.SecurityManager era abstracta.
Security Manager en JDK 1.1
Las decisiones sobre control de acceso se basaban en:
si una clase con un class loader (por ejemplo, un applet en JDK 1.1) estaba en la pila o no.la profundidad del class loader (cómo de profunda en la pila estaba la ocurrencia más reciente de un método de una clase definida usando un class loader).
Security Manager en JDK 1.1
Ejemplo de método check de un SecurityManager. No permite la llamada a Runtime.exit cuando haya en la pila una clase definida con un class loader:
public void checkExit(int status) {
if (inClassLoader()) {
throw new SecurityException(…);
}
}
Security Manager en JDK 1.1
Ejemplo de método check de un SecurityManager. No permite la creación de un class loader cuando la profundidad del propio sea 2:
public void checkCreateClassLoader() {
if (ClassLoaderDepth()==2) {
throw new SecurityException(…);
}
}
Security Manager en Java 2 SDK
Cambios en java.lang.SecurityManager:Ya no es una clase abstracta.La mayoría de los métodos check llaman a un nuevo método checkPermission, que por defecto llama al método del mismo nombre (checkPermission) en la nueva clase AccessController.
Los métodos usados en JDK 1.1 para determinar si una clase está en la pila o para calcular la profundidad del cargador de clases han sido modificados en el Java 2 SDK para ignorar los cargadores de clases del sistema y contextos de seguridad que ha sido garantizados por java.security.AllPermission.
Security Manager en Java 2 SDK
Como SecurityManager ya no es una clase abstracta, ahora se puede instanciar y usar directamente como gestor de seguridad por defecto. Esto se puede hacer:
Estableciendo la propiedad del sistema adecuada conforme se lanza la VM:java –Djava.security.manager TuAplicacion
Vía código:System.setSecurityManager(new SecurityManager());
Su comportamiento se podrá modificar mediante ficheros de políticas de seguridad (policy files).
Security Manager en Java 2 SDK
Ejemplo:
Analizar la salida.
public class PropiedadesSistema { public static void main(String[] args) { System.out.println(System.getProperty("java.version")); System.out.println(System.getProperty("java.home")); System.out.println(System.getProperty("java.vendor")); }}
Políticas de seguridad
La política de seguridad para un entorno de aplicación en lenguaje Java está asociado a un objeto Policy.
Se representa mediante una subclase de Policy, que proporciona una implementación de los métodos abstractos de la clase Policy (en el paquete java.security).
Esta implementación viene indicada en el fichero java.security .
Políticas de seguridad
Políticas de seguridad
Con la integración del servicio JAAS en el J2SDK 1.4, la API java.security.Policy maneja consultas basadas en Principal.
La implementación por defecto de las políticas de seguridad soportan entradas grant (garantías de permiso) basadas también en principales.
El control de acceso puede ahora basarse no sólo en qué código se está ejecutando, sino también en quién lo está ejecutando.
Implementación por defecto de las políticas de seguridad
Las políticas se establecen en uno o más ficheros de políticas de seguridad (Policy File), que detallan qué permisos se conceden al código en función de qué código es, de que fuente viene y quién lo está ejecutando.
Un fichero de políticas está codificado UTF-8 y se puede crear con un simple editor de texto o la herramienta gráfica Policy Tool.
Por defecto hay un único fichero global al sistema y otro opcional para el usuario.
Localización por defecto de los ficheros de políticas
El fichero de políticas de seguridad del sistema se localiza por defecto en:
java.home/lib/security/java.policy (Solaris)java.home\lib\security\java.policy (Win32)
La propiedad del sistema “java.home” especifica el directorio de instalación del SDK.
El fichero de políticas del usuario se localiza por defecto en:
user.home/.java.policy (Solaris)user.home\.java.policy (Win32)
Localización por defecto de los ficheros de políticas
Localización por defecto de los ficheros de políticas
El fichero de políticas instalado por defecto con el SDK permite a cualquier:
Escuchar en un puerto no privilegiadoPermite a cualquier código leer propiedades “estándar” que no sean sensibles a la seguridad.
Policy files
El funcionamiento del sistema de políticas de seguridad es: primero se carga el fichero de políticas del sistema y, posteriormente, se añade el/los de usuario.
Las localizaciones de los ficheros de políticas de seguridad están detalladas en el fichero de propiedades de seguridad, que se encuentra en:
java.home/lib/security/java.security (Solaris)java.home\lib\security\java.security (Win32)
Policy files
Las localizaciones de los ficheros de políticas están especificadas como valores de las propiedades que tienen la siguiente forma:
policy.url.n =URL (n es un número, que actúa como contador del número de ficheros de políticas).
Ejemplo:policy.url.1=file:${java.home}/lib/security/java.policypolicy.url.2=file:${user.home}/.java.policy
Se cargarán sólo los ficheros indicados con índices consecutivos. Si hay un hueco en los números no se cargarán los ficheros a partir del hueco.
Policy files
Policy files
Policy files
Se puede especificar un fichero de políticas adicional en tiempo de ejecución:
java –Djava.security.manager –Djava.security.policy=unaURL MiApp
Ese ejemplo cargaría el fichero especificado por unaURL además de los especificados en las propiedades de seguridad. Si se usase un ‘==‘ en lugar de un ‘=‘ entonces sólo se cargaría el fichero de políticas especificado.
Cambio de implementación
Se puede proporcionar una clase de políticas alternativa para reemplazar la implementación de referencia de la clase Policy.
Una subclase de Policy.Implementación de todos los métodos necesarios.
La implementación de referencia puede ser cambiada editando el fichero java.security cambiando la propiedad:
policy.provider = NombreClase
Sintaxis del fichero de políticas
Los ficheros de configuración de políticas de seguridad especifican qué permisos (qué tipos de accesos a recursos del sistema) se garantizan al código de una fuente concreta de código y ejecutado por un determinado principal.
Un policy file contiene:Una entrada keystore (opcional).Cero o más entradas grant.
Sintaxis del fichero de políticas
La entrada keystore: sirve para definir el keystore usado para buscar las claves públicas de los firmantes especificados en las entradas grant del fichero.
Si alguna entrada grant especifica alias de firmantes o principales entonces debe aparecer una entrada keystore.
Sólo puede haber una entrada keystore en el fichero de políticas de seguridad. Si se ponen más de una, sólo se considerará la primera.
Puede aparecer en cualquier lugar del fichero.
Sintaxis del fichero de políticas
Sintaxis de la entrada keystore:keystore "ks_url", "ks_tipo", "ks_proveedor";keystorePasswordURL "password_url";
Las URLs indicadas son relativas con respecto al directorio donde se encuentra el fichero de políticas en cuestión.
Tipo de keystore: define el formato de los datos y su almacenamiento y los algoritmos usados para protegerlo. El tipo por defecto soportado por Sun es un tipo propietario llamado “JKS”.
Sintaxis del fichero de políticas
Entradas grant: especifica qué permisos se conceden a qué código. El formato básico es:
grant signedBy "signer_names", codeBase "URL", principal principal_class_name "principal_name", principal principal_class_name "principal_name", ... {
permission permission_class_name "target_name", "action", signedBy "signer_names"; permission permission_class_name "target_name", "action", signedBy "signer_names"; ...
};
Sintaxis del fichero de políticas
Un código en ejecución siempre viene de una fuente (code source) concreta, representada por un objeto CodeSource y que se está ejecutando como un principal concreto, representado por un objeto Principal.
El code source incluye la URL donde se originó el código y, además, una referencia a los certificados que contienen las claves públicas correspondientes a las claves privadas usadas para firmar dicho código:
codeBasesignedBy
Sintaxis del fichero de políticas
Los campos signedBy, principal y codeBase son opcionales y no importa el orden entre ellos.
signedBy: referencia un alias de un certificado que está almacenado en el keystore. Una entrada con signedBy está concediendo permisos al código firmado con la clave privada correspondiente a la clave pública almacenada en la entrada del keystore indicada por el alias. Su valor puede ser una lista de múltiples alias, indicando que el código está firmado por todos ellos (operación AND).
Sintaxis del fichero de políticas
principal: especifica un par nombre de clase/nombre de principal.
Nota: si se especifica el valor del principal como una cadena de texto entre comillas (sólo se está dando el nombre de principal, en lugar del par), se trata como una alias del keystore. Si no se encuentra en el keystore el certificado correspondiente a ese alias, se ignora la entrada grant entera. Si se encuentra, se considera que el nombre de la clase es “javax.security.auth.x500.X500Principal” y la cadena el nombre distinguido del principal.
Sintaxis del fichero de políticas
Ejemplo:
Se está garantizando permisos de lectura y escritura a ficheros del directorio home del usuario “duke” y de creación de sockets a “duke.com” a cualquier código ejecutándose como “duke” o “0”.
grant
Principal com.sun.security.auth.SolarisPrincipal "duke",
Principal com.sun.security.auth.SolarisNumericUserPrincipal "0" {
permission java.io.FilePermission "/home/duke", "read, write";
permission java.net.SocketPermission "duke.com", "connect";
};
Sintaxis del fichero de políticas
Las entradas de permisos: deben empezar por la palabra permission. Los permisos corresponden a clases específicas de Java.
Para muchos permisos se requiere una acción, por ejemplo, para FilePermission, que indique que tipo de acceso a ficheros es el que se está permitiendo.
Sintaxis del fichero de políticas
Las entradas permission tienen una claúsula signedBy opcional, que indica que la clase correspondiente al permiso debe estar firmada por el alias indicado.
Ejemplo: se concede un permiso de tipo Foo si la clase Foo.class se encuentra en un JAR que has sido firmado por “FooSoft”.
grant {
permission Foo “foobar”, signedBy “FooSoft”;
};
Sintaxis del fichero de políticas
Las clases de sistema no están sujetas a las restricciones de las políticas de seguridad, por lo que si, en el ejemplo anterior, Foo.class fuera una clase de sistema, entonces ese permiso estaría implícito.
Las entradas permission termina con ‘;’. En las palabras reservadas de los ficheros de
políticas no se distinguen mayúsculas y minúsculas.
Sintaxis del fichero de políticas
Tipos de permisos incorporados por JDK (consultar las API):
java.security.AllPermission
java.security.SecurityPermission
java.security.UnresolvedPermission
java.awt.AWTPermission
java.io.FilePermission
java.io.SerializablePermission
java.lang.reflect.ReflectPermission
java.lang.RuntimePermission
java.net.NetPermission
Sintaxis del fichero de políticas
java.net.SocketPermission
java.sql.SQLPermission
java.util.PropertyPermission
java.util.logging.LoggingPermission
javax.net.ssl.SSLPermission
javax.security.auth.AuthPermission
javax.security.auth.PrivateCredentialPermission
javax.security.auth.kerberos.DelegationPermission
javax.security.auth.kerberos.ServicePermission
javax.sound.sampled.AudioPermission
Ejemplos de Policy Files
grant signedBy "Duke" { permission java.io.FilePermission "/tmp/*", "read,write";};
grant { permission java.util.PropertyPermission "java.vendor", "read";};
grant signedBy "sysadmin", codeBase "file:/home/sysadmin/*" { permission java.security.SecurityPermission "Security.insertProvider.*"; permission java.security.SecurityPermission "Security.removeProvider.*"; permission java.security.SecurityPermission "Security.setProperty.*";};
grant principal javax.security.auth.x500.X500Principal "cn=Alice" { permission java.io.FilePermission "/home/Alice", "read, write";};
grant codebase "http://www.games.com", signedBy "Duke", principal javax.security.auth.x500.X500Principal "cn=Alice" { permission java.io.FilePermission "/tmp/games", "read, write";};
Especificación de rutas de archivos en Win32
Cuando se está concediendo un FilePermission, el “target_name” es una ruta de archivo. En sistemas Win32, si se especifica directamente una ruta en una cadena, es necesario incluir dos barras (\\) por cada una que aparezca en la ruta, así:
grant {
permission java.io.FilePermission "C:\\users\\cathy\\foo.bat", "read";
};
Expansión de propiedades
La expansión de propiedades es posible tanto en los ficheros de políticas de seguridad como en los ficheros de propiedades de seguridad.
La expansión de propiedades es similar a la expansión de variables en una shell. Así, cuando una cadena como “${propiedad}” aparece en un fichero de políticas o en uno de propiedades de seguridad, será expandido al valor de la propiedad correspondiente del sistema.
Expansión de propiedades
Ejemplo:permission java.io.FilePermission "${user.home}", "read";
Si la propiedad “user.home” del sistema vale “/home/cathy” se expandirá a:
permission java.io.FilePermission "/home/cathy", "read";
Para ayudar a la creación de ficheros de políticas independientes de la plataforma, también se puede usar la notación especial “${/}”, que es una referencia corta a “${file.separator}” (propiedad del sistema que indica cuál es el separador usado en las rutas, ‘\’ en Win32, ‘/’ en Unix, por ejemplo).
Expansión de propiedades
Ejemplo:permission java.io.FilePermission "${user.home}${/}*", "read”;
Si la propiedad “user.home” del sistema vale “/home/cathy” se expandirá a:
permission java.io.FilePermission "/home/cathy/*", "read";
No se pueden anidar las propiedades para su expansión. Estaría MAL:
“${user.${foo}}”
Si una propiedad dentro de una entrada grant, permission o keystore no se puede expandir, se ignora la entrada entera.
Servicio de autenticación y autorización
Introducción. Autenticación JAAS. Ejemplo JAAS. Autorización JAAS.
47
Introducción
JAAS aumenta los controles de acceso basados en código existentes anteriormente con controles de acceso basado en el usuario y capacidades de autenticación.
Esto permite garantizar permisos basados no sólo en qué código se está ejecutando, sino también en quién lo está ejecutando.
Introducción
JAAS consiste en dos partes: la autenticación y la autorización. Esto quiere decir que se puede usar tanto para la autenticación como para la autorización:
Para la autenticación de usuarios y así determinar de forma segura quién está ejecutando código Java, sin tener en cuenta si el código es una aplicación Java independiente, un applet, un EJB o un servlet.Para la autorización de usuarios y garantizar que tienen los permisos requeridos para realizar las acciones.
Introducción
La autenticación está basada en los Pluggable Authentication Modules (PAMs) con un framework que se usará tanto para clientes como para servidores.
La realización de la autenticación usando PAMs permite a las aplicaciones Java ser independientes del mecanismo de autenticación subyacente.
Esto tiene la ventaja de que nuevos o revisados mecanismos de autenticación podrán ser incorporados sin modificar la aplicación en sí misma.
Introducción
La autorización es una extensión del mecanismo existente basado en ficheros de políticas que se usa para especificar qué se le permite a una aplicación hacer o no hacer.
Está basada en dominios de protección. Anteriormente, este mecanismo garantiza permisos en función de dónde viene el código y no en quién lo está ejecutando.
Con JAAS, los permisos y el control de acceso se pueden basar no sólo en qué código se está ejecutando sino también en quién lo está haciendo, como ya se ha visto.
Introducción
Los paquetes siguientes componen la arquitectura JAAS:
javax.security.auth: contiene clases básicas para la autenticación y autorización.javax.security.auth.callback: contiene una estructura de clases e interfaces para envío de información de autenticación a la aplicación.java.security.auth.login: contiene clases que emplean para conectarse a un dominio de seguridad.javax.security.auth.spi.
Autenticación JAAS
Sujeto: identidad en un sistema que se quiere autenticar y a la que se le quieren asignar derechos de acceso.
Un sujeto puede ser un usuario humano, un proceso o una máquina y está representado por la clase javax.security.auth.Subject.
Analizar la clase en las APIs de Java.
Autenticación JAAS
Un sujeto puede interactuar con múltiples autoridades (una clave para una web bancaria, otra para una cuenta de correo, otra para una intranet…)
Por esa razón, se usa java.security.Principal para representar la identidad en esas interacciones.
Ver APIs de Java.
Autenticación JAAS
La interfaz Principal es una noción abstracta que puede ser usada para representar una entidad, una empresa o una ID de usuario. Un Subject puede contener múltiples principales.
Contexto de conexión (LoginContext): objeto a través del que los clientes interactúan con JAAS.
Módulo de conexión (LoginModule): responsable de implementar y realizar la autenticación. Será implementado por diversos proveedores de tecnología de autenticación.
Autenticación JAAS
Los elementos que integran el sistema son:Contexto de login (LoginContext).Configuración específica.Módulos de login (LoginModule).CallBackHandler.
Autenticación JAAS
Contexto de login:Funcionamiento general: el objeto LoginContext lee la configuración e instancia el LoginModule especificado.Normalmente se usarán módulos de conexión ya desarrollados y no deberemos codificar ninguno.Sun Microsystems pone a nuestra disposición varios: JndiLoginModule KeyStoreLoginModule Krb5LoginModule NTLoginModule UNIXLoginModule
Autenticación JAAS
Contexto de login:La cadena de módulos que va a ser aplicada se indica a la hora de crear el objeto contexto mediante su constructor.public LoginContext()Ver la API de Java.
La configuración se indica mediante un fichero de configuración.
Autenticación JAAS
Configuración: Especifica la tecnología de autenticación, o LoginModule usado. Así se puede cambiar el LoginModule usado sin que sea necesario ningún cambio en el código de la aplicación.Se apoya en la clase abstracta Configuration del paquete javax.security.auth.login.
Mirar APIs de Java.
Application { ModuleClass Flag ModuleOptions; ModuleClass Flag ModuleOptions; ModuleClass Flag ModuleOptions;};
Autenticación JAAS
Configuración (cont.): ModuleClass: nombre de la clase. Flag: Required. Requisite. Sufficient. Optional.
Login { com.sun.security.auth.module.UnixLoginModule required; com.sun.security.auth.module.Krb5LoginModule optional; };
Autenticación JAAS
Configuración (cont.): Required: El módulo de conexión asociado debe ser capaz de
autenticar el sujeto en todo el proceso de autenticación para poder éxito. Independientemente de que falle o no, se continua en la cadena de módulos hasta el final.
Requisite: El módulo de conexión asociado debe tener éxito para
que se considere que todo el proceso de autenticación ha tenido éxito. Si el módulo falla, el proceso de autenticación no continua. Devuelve el control a la aplicación.
Autenticación JAAS
Configuración (cont.): Sufficient: No es requisito indispensable para la autenticación. Ahora
bien, si el módulo se supera con éxito la autenticación es automática.
Optional: no es necesaria la capacidad que tiene el módulo de conexión asociado para autenticar al sujeto. El proceso de autenticación sigue por la lista buscando otros módulos de conexión.
EJEMPLO JAAS: MyClient.java
import javax.security.auth.Subject;import javax.security.auth.login.LoginContext;import javax.security.auth.login.LoginException;
public class MyClient { public static void main(String argv[]) { LoginContext ctx = null; try { ctx = new LoginContext("WeatherLogin", new MyCallbackHandler()); } catch(LoginException le) { System.err.println("LoginContext cannot be created. "+ le.getMessage()); System.exit(-1); } catch(SecurityException se) { System.err.println("LoginContext cannot be created. "+ se.getMessage()); } try { ctx.login(); } catch(LoginException le) { System.out.println("Authentication failed. " + le.getMessage()); System.exit(-1); } System.out.println("Authentication succeeded."); System.exit(-1); }
}
Autenticación JAAS
Módulo de login:Si se implementa un LoginModule se debe dar cuerpo a los siguientes métodos (LoginContext los usará en ese orden): initialize: el propósito de este método es inicializar
este LoginModule con la información relevante. El Subject pasado a este método se usa para almacenar los principales (Principal) y credenciales (Credential) si la conexión tiene éxito. Nótese que este método recibe un CallbackHandler que puede ser usado para introducir información de la autenticación.
Autenticación JAAS
Módulo de login:login: le pide al LoginModule que autentique al Subject. Nótese que el Principal todavía no ha sido asignado.commit: se llama a este médodo si tiene éxito la autenticación total del LoginContext.abort: informa al LoginModule de que algún proveedor o módulo ha fallado al autenticar al Subject. En ese caso la conexión entera (el logado) debe fracasar.logout: desconecta al Subject borrando los principales (Principal) y credenciales (Credential) del Subject.
Ejemplo JAAS: WeatherLoginModule.javaimport java.io.*;import java.util.*;import java.security.Principal;import javax.security.auth.Subject;import javax.security.auth.callback.*;import javax.security.auth.spi.LoginModule;import javax.security.auth.login.LoginException;
public class WeatherLoginModule implements LoginModule { private Subject subject; private ExamplePrincipal entity; private CallbackHandler callbackhandler; private static final int NOT = 0; private static final int OK = 1; private static final int COMMIT = 2; private int status;
public void initialize(Subject subject, CallbackHandler// callbackhandler, Map state, Map options) { status = NOT; entity = null; this.subject = subject; this.callbackhandler = callbackhandler; }
Ejemplo JAAS: WeatherLoginModule.java
public boolean login() throws LoginException {
if(callbackhandler == null) { throw new LoginException("No callback handler is available"); } Callback callbacks[] = new Callback[1]; callbacks[0] = new NameCallback("What is the weather like today?"); String name = null; try { callbackhandler.handle(callbacks); name = ((NameCallback)callbacks[0]).getName(); } catch(java.io.IOException ioe) { throw new LoginException(ioe.toString()); } catch(UnsupportedCallbackException ce) { throw new LoginException("Error: "+ce.getCallback().toString()); } if(name.equals("Sunny")) { entity = new ExamplePrincipal("SunnyDay"); status = OK; return true; } else { return false; } }
EJEMPLO JAAS: WeatherLoginModule.java
public boolean commit() throws LoginException { if(status == NOT) { return false; } if(subject == null) { return false; } Set entities = subject.getPrincipals(); if(!entities.contains(entity)) { entities.add(entity); } status = COMMIT; return true; } public boolean abort() throws LoginException { if((subject != null) && (entity != null)) { Set entities = subject.getPrincipals(); if(entities.contains(entity)) { entities.remove(entity); } } subject = null; entity = null; status = NOT; return true; }
Ejemplo JAAS: WeatherLoginModule.java
public boolean logout() throws LoginException { subject.getPrincipals().remove(entity); status = NOT; subject = null; return true; }
}
Autenticación JAAS
CallbackHandler:Una aplicación basada en JAAS implementa la interfaz CallbackHandler de forma que pueda interactuar con los usuarios para introducir los datos específicos de autenticación, tales como usuario y clave, o mostrar mensajes de error y advertencia. Implementar la interfaz significa darle cuerpo al método handle para recuperar o mostrar la información requerida en las llamadas.
Autenticación JAAS
CallbackHandler:Diferentes tipos de respuesta: NameCallback: pasa al método handle de
CallbackHandler una respuesta al nombre de autenticación.
PasswordCallback. ChoiceCallback: muestra una lista de opciones y
captura la elegida por el usuario. ConfirmationCallback: pregunta por YES/NO, OK/
CANCEL, YES/NO/CANCEL u otras confirmaciones similares.
Autenticación JAAS
TextInputCallback: recupera información genérica de texto.TextOutputCallback: muestra información o mensajes de error o advertencia.Otras clases que implementan la interfaz Callback…
Ejemplo JAAS: MyCallbackHandler.java
import javax.security.auth.Subject;import javax.security.auth.login.LoginContext;import javax.security.auth.login.LoginException;
public class MyCallbackHandler implements CallbackHandler {
public void handle(Callback callbacks[]) throws IOException, UnsupportedCallbackException { for(int i=0;i<callbacks.length;i++) { if(callbacks[i] instanceof NameCallback) { NameCallback nc = (NameCallback) callbacks[0]; System.err.print(nc.getPrompt()); System.err.flush(); String name = (new BufferedReader( new InputStreamReader(System.in))).readLine(); nc.setName(name); } else { throw(new UnsupportedCallbackException(callbacks[i], "Callback handler not support")); } } }
}
Ejemplo JAAS: ExamplePrincipal.java
Esta clase es una implementación de Principal, a la que se ha hecho referencia en nuestro LoginModule:
import java.security.Principal;
public class ExamplePrincipal implements Principal { private final String name;
public ExamplePrincipal(String name) { if(name == null) { throw new IllegalArgumentException("Null name"); } this.name = name; }……
Ejemplo JAAS: ExamplePrincipal.java
…… public String getName() { return name; } public String toString() { return "ExamplePrincipal: "+name; } public boolean equals(Object obj) { if(obj == null) return false; if(obj == this) return true; if(!(obj instanceof ExamplePrincipal)) return false; ExamplePrincipal another = (ExamplePrincipal) obj; return name.equals(another.getName()); } public int hasCode() { return name.hashCode(); }}
Ejemplo JAAS: example.conf
Fichero de configuración. La entrada del fichero debe ser la misma que se usa en el cliente. Especifica el módulo que se va a usar para la autenticación.
WeatherLogin { WeatherLoginModule required;
};
Ejecución del ejemplo JAAS
Crear un directorio. Copiar MyClient.java, WeatherLoginModule.java, ExamplePrincipal.java y example.conf a ese directorio.
Compilar todos los fichero .java: javac *.java
Ejecutar el cliente usando el siguiente comando, que especifica el fichero de configuración de conexión:
java –Djava.security.auth.login.config=example.conf MyClient
Autorización JAAS
La autorización JAAS extiende la arquitectura de seguridad de Java centrada en el código que usa políticas de seguridad para especificar qué derechos de acceso están garantizados para un código en ejecución.
Los permisos se pueden garantizar no sólo en función de qué código se está ejecutando, sino además, quién lo está ejecutando.
Los permisos se pueden garantizar en el fichero de políticas para especificar principales.
Autorización JAAS
Importante:Para la autorización primero se debe haber procedido a la autenticación del usuario.Hay que llamar al método doAs (o doAsPrivileged) de la clase Subject, que invocará el método run que contiene el código a ser ejecutado como el sujeto especificado.
Ejemplo de Autorización JAAS
Vamos a ampliar el ejemplo usado en autenticación JAAS para que trabaje también con autorización.
Los ficheros ExamplePrincipal.java, WeatherLoginModule.java y example.conf no sufren ninguna modificación.
El objetivo del ejemplo es que el código habilite autorice a un usuario que se ha autenticado a realizar una acción.
Ejemplo de Autorización JAAS
MyClient.java: ahora, una vez que la autenticación tenga éxito, deberá realizar lo siguiente:
Se hace que el sujeto realice una acción (definida en la clase MyAction) como el sujeto autenticado.
Subject subject = ctx.getSubject(); PrivilegedAction action = new MyAction(); Subject.doAsPrivileged(subject, action, null); try { ctx.logout(); } catch(LoginException le) { System.out.println("Logout: " + le.getMessage()); }
Ejemplo de Autorización JAAS
MyAction.java:
import java.io.File;import java.security.PrivilegedAction;
public class MyAction implements PrivilegedAction { public Object run() { File file = new File("max.txt"); if(file.exists()) { System.out.println("The file exists in the current working directory"); } else { System.out.println("The file does not exist in the current working directory"); } return null; }