19. Seguridad y activación push

19.1. Registro push

Hasta ahora hemos visto que cuando queremos obtener información primero debemos abrir la aplicación cliente que nos da acceso a esa información. Para recibir algo antes tenemos que solicitarlo desde nuestra aplicación, esto es lo que se conoce como una conexión pull, en la que el cliente debe "tirar" de los datos para obtenerlos.

Para determinadas aplicaciones puede ser interesante poder recibir datos sin tener que solicitarlos. Por ejemplo pensemos en una aplicación de foro, en el que varios usuarios pueden publicar mensajes. Nosotros querremos visualizar en nuestro cliente la lista de mensajes publicados en el servidor, pero no sabemos cuando llega un mensaje al servidor, ya que puede haberlo enviado cualquier otro cliente, sólo el servidor sabe cuando llegan nuevos mensajes.

Cuando el usuario abra la aplicación del foro se descargarán todos los mensajes publicados y se mostrarán. Esto sigue un modelo pull, en el que el usuario tiene que abrir la aplicación para obtener los datos deseados, debe "tirar" de los datos.

Pero imaginemos que queremos implementar una función de avisos en el foro, con la cual un usuario puede programar un aviso, de forma que cuando alguien publique una contestación a un tema que sea de su interés, el usuario reciba una notificación. De esta forma se evita tener que estar entrando en la aplicación periódicamente para ver si alguien ha contestado. Esto es un modelo push, en el que es la aplicación la que "empuja" los datos hacia nosotros en el momento en el que llegan.

Para implementar este comportamiento podríamos utilizar una técnica conocida como polling, que consiste en interrogar al servidor cada cierto periodo de tiempo para comprobar si han llegado mensajes nuevos, y en tal caso recibirlos y mostrarlos al usuario. Esto nos obligará a estar continuamente realizando peticiones al servidor, aunque no se haya recibido ningún mensaje, con lo que se estará produciendo un tráfico innecesario en la red. Además deberemos tener la aplicación continuamente en funcionamiento, aunque sea en segundo plano, para que haga las comprobaciones.

Con un modelo de tipo push podremos solucionar este problema, ya que en este caso el servidor podrá enviarnos información sin tener que pedirla nosotros previamente. De esta forma cuando el servidor haya recibido nuevos mensajes nos los enviará mediante push, sin tener que estar interrogándolo nosotros continuamente.

Es decir, push es un mecanismo que nos va a permitir recibir información de forma asíncrona, sin tenerla que solicitar nosotros previamente, y evitando el elevado consumo de recursos que producen las técnicas de polling.

En MIDP 2.0 aparece el registro push, que nos permitirá utilizar este mecanismo de recepción de información de forma asíncrona en nuestro dispositivo.

19.1.1. Aplicaciones activadas por push

El registro push nos permitirá que nuestras aplicaciones sean activadas automáticamente mediante push. Es decir, no hará falta que nosotros abramos la aplicación manualmente para que esta pueda realizar alguna función, sino que se podrá activar automáticamente cuando suceda algún evento externo.

Por ejemplo, una utilidad bastante clara de este mecanismo es la programación de alarmas. Imaginemos una agenda que deba hacer sonar una alarma cuando llegue la hora de una reunión. En MIDP 1.0 una aplicación sólo podrá programar una alarma si abrimos manualmente esa aplicación, y deberemos mantener esta aplicación abierta en segundo plano permanentemente, ya que si la cerrásemos también se cerraría la alarma programada. Esto hace que en MIDP 1.0 este tipo de aplicaciones sea poco útiles, ya que si se nos olvida abrir la aplicación cuando encendamos el móvil no sonará ninguna de las alarmas programadas.

Sin embargo, en MIDP 2.0 con el registro push podremos hacer que la aplicación se abra automáticamente cuando llegue la hora de la alarma, es decir, la aplicación se estará activando automáticamente mediante push. En este caso el evento externo que activa la aplicación será un temporizador.

19.1.1.1. Métodos de activación

La activación mediante push puede suceder por dos tipos de eventos:

Figura 5. Métodos de activación de MIDlets

19.1.1.2. Responsabilidad compartida

Deberemos tener en cuenta que el registro push sólo estará pendiente de estos eventos externos mientras nuestra aplicación esté cerrada. Cuando ejecutemos la aplicación, será responsabilidad suya escuchar las conexiones entrantes y registrar los temporizadores adecuados para que se disparen las alarmas.

Es decir, que la responsabilidad de la escucha y la gestión de los eventos push será compartida entre el MIDlet y el AMS:

La facilidad que nos proporciona el registro push es esta capacidad de ejecutar la aplicación automáticamente cuando se produzca un determinado evento externo, pero mientras nuestra aplicación se esté ejecutando este registro no realizará ninguna función.

19.1.1.3. Emulación en WTK

A partir de WTK 2.0 se puede utilizar la activación push en los emuladores. Pero para disponer de esta funcionalidad deberemos cargar la aplicación utilizando provisionamiento OTA, instalando de esta forma la aplicación utilizando el AMS del emulador.

19.1.2. Temporizadores

Vamos a ver cómo podemos registrar un temporizador push, para que la aplicación se ejecute automáticamente a una determinada hora. Para hacer esto deberemos utilizar la API de PushRegistry, que nos permitirá registrar este tipo de eventos en el registro push.

Podremos registrar una alarma push con el siguiente método:

long t = PushRegistry.registerAlarm(String midletClassName, long hora);

Deberemos proporcionar como parámetros el nombre de la clase del MIDlet que queremos que se ejecute, y el tiempo del sistema en milisegundos del instante en el que queremos que se produzca la alarma.

Hemos de tener en cuenta que sólo podemos registrar una alarma por MIDlet, de forma que si hubiésemos registrado otra alarma previamente, al invocar este método de sobrescribirá.

Si hubiese una alarma registrada previamente, la llamada a esta función nos devolverá como valor de tiempo t el instante en el que estaba programada la alarma previa que ha sido sobrescrita. En caso contrario, nos devolverá 0.

Si nuestra aplicación tuviese que programar varias alarmas, lo que deberíamos hacer es registrar mediante push la alarma que tenga la fecha más temprana, y una vez se haya producido esta alarma, se registrará la siguiente, y así consecutivamente.

19.1.2.1. Programar una alarma para una fecha absoluta

Si queremos programar una alarma para que se produzca en una determinada fecha, independientemente de la fecha actual, simplemente deberemos proporcionar al método registerAlarm el tiempo del sistema en milisegundos de la hora en la que queremos que se produzca.

Para hacer esto simplemente deberemos obtener un objeto Date que represente dicha hora. Podemos o bien solicitar que el usuario introduzca la fecha manualmente en un campo de fecha, y leer de ese campo el objeto Date con la fecha introducida, o bien generar desde nuestra aplicaciones una determinada fecha utilizando un objeto Calendar.

Una vez tengamos el objeto Date correspondiente a esta fecha, obtendremos de él el tiempo en milisegundos de dicha fecha para proporcionárselo a la función registerAlarm:

Date fecha = obtenerFecha();
long t = PushRegistry.registerAlarm(midlet.getClass().getName(), fecha.getTime());

19.1.2.2. Programar una alarma para un intervalo de tiempo

Es posible que no queramos dar una fecha absoluta a la alarma, sino que queramos establecer una alarma que suene pasado cierto tiempo desde el instante actual. Por ejemplo, podemos querer poner una alarma para que suene dentro de 5 minutos.

Para hacer esto deberemos establecer la fecha de forma relativa a la fecha actual. Primero obtendremos la fecha actual mediante un objeto Date, y a esta fecha podremos sumarle el número de milisegundos del intervalo de tiempo que queremos que tarde en sonar la alarma:

Date ahora = new Date(); // Obtiene la fecha actual
long t = PushRegistry.registerAlarm(midlet.getClass().getName(), 
                                    ahora.getTime() + intervalo);

19.1.2.3. Responsabilidad del MIDlet

Cuando el MIDlet esté en ejecución, los temporizadores registrados mediante push no tendrán efecto, estos temporizadores sólo servirán para activar la aplicación cuando esté cerrada.

Por lo tanto, normalmente durante la ejecución de la aplicación crearemos temporizadores utilizando la clase Timer de Java. Como estos temporizadores serán hilos de la aplicación, cuando ésta se cierre los temporizadores también se anularán. Entonces será este el momento en el que deberemos registrar el temporizador push.

El lugar adecuado para registrar los temporizadores push será el método destroyApp del MIDlet. De esta forma, si al destruirse la aplicación todavía tuviésemos algún temporizador pendiente, los registraremos mediante push para que siga siendo efectivo.

19.1.2.4. Activación del MIDlet

Cuando el MIDlet se active vía push, debido a un temporizador, simplemente se pondrá en marcha la aplicación como si la hubiésemos abierto manualmente, y no tendrá constancia en ningún momento de que se ha abierto debido a un temporizador.

Si queremos que cuando se abra automáticamente se ejecute la alarma, deberemos implementar este comportamiento manualmente. Para hacer esto deberemos registrar las alarmas pendientes utilizando RMS.

Cuando queramos programar una alarma, los datos de esta alarma se registrarán de forma persistente utilizando RMS, y se programará un Timer para ella.

Si salimos de la aplicación, en el método destroyApp se buscará la siguiente alarma pendiente, si hay alguna, y la registrará mediante push.

Cuando la aplicación se active la próxima vez, podrá leer las alarmas pendientes en RMS y programar un Timer para la siguiente. De esta forma, si la aplicación se hubiese abierto de forma manual y no correspondiese activar ninguna alarma, como en RMS no hay ninguna alarma programada para este momento no sucederá nada. Si por el contrario, se hubiese abierto debido al temporizador push, como tendremos en RMS una alarma programada justo para el momento actual, se activará la alarma. Así, aunque la aplicación no sepa cual ha sido la forma de activarse, mediante la información almacenada en RMS podremos saber cuándo debemos disparar las alarmas y cuando no.

19.1.3. Conexiones push

Podemos hacer que las aplicaciones se activen mediante conexiones de red entrantes. Utilizando protocolo HTTP no tenemos este tipo de conexiones, ya que éste es un protocolo síncrono en el que debemos realizar una petición para obtener una respuesta.

Sin embargo, en MIDP 2.0 se definen otros tipos de conexiones a bajo nivel que si que soportan conexiones entrantes. Estas son las conexiones de sockets y datagramas. Podremos hacer que el dispositivo escuche en un determinado puerto conexiones entrantes mediante sockets o datagramas.

El problema de estos tipos de conexiones es que en la mayoría de los casos los operadores de telefonía móvil actuales utilizan IPs dinámicas, por lo que cada vez que se establezca una nueva conexión (por ejemplo mediante GPRS) se obtendrá una IP distinta. Esto complica la tarea de registrar nuestro móvil para recibir avisos, ya que si la IP cambia frecuentemente no se sabrá a qué dirección se debe enviar la información.

Otro tipo de conexión que tenemos disponible en un gran número de dispositivos y que nos resultará más útil es la conexión de mensajes que aporta la API WMA. Los mensajes de texto se envían a un número de teléfono que sabemos que no va a cambiar. De esta manera podremos tener identificado claramente el dispositivo en el cual queremos recibir notificaciones.

Tenemos dos formas de registrar conexiones push entrantes:

19.1.3.1. Registro estático

Podremos utilizar registro estático cuando las direcciones de nuestras conexiones entrantes sean estáticas. Este será el caso de las conexiones de mensajes (SMS) en cualquier dispositivo, o de las conexiones de sockets y datagramas en aquellos dispositivos que tengan asignada una IP estática y su puerto se configure también de forma estática.

Para registrar una conexión push entrante añadiremos un atributo como el siguiente en el fichero JAD:

MIDlet-Push-<n>: <URL>, <NombreClaseMIDlet>, <RemitentesPermitidos>

Debemos especificar para cada conexión push que queramos permitir la URL de la conexión entrante y el MIDlet que se ejecutará cuando recibamos datos. Además como tercer elemento podemos indicar los remitentes a los que les permitimos enviarnos datos. Con * indicamos que aceptamos datos de cualquier remitente.

Estas conexiones se registrarán en el momento en que se instale la aplicación, y se eliminarán cuando se desinstale.

Este tipo de registro no es posible cuando tengamos asignación dinámica de IPs, ya que en tiempo de despliegue no podremos conocer cual será la IP que tenga el dispositivo cuando se utilice la aplicación. En este caso deberemos utilizar registro dinámico, como veremos más adelante.

Para configurar conexiones entrantes de sockets, datagramas y mensajes podremos utilizar URLs de los siguientes tipos:

socket://:<puerto>
datagram://:<puerto>
sms://:<puerto>

Al utilizar registro estático siempre deberemos indicar explícitamente el puerto, ya que si dejamos que el puerto se asigne dinámicamente no sabremos a qué puerto del móvil hay que conectarse para activar la aplicación.

Por ejemplo, podemos registrar una conexión de mensajes entrantes de la siguiente forma:

MIDlet-Push-1: sms://:4444, es.ua.jtech.sms.MIDletRecibirSMS, *

De esta forma se escuchará la llegada de SMSs en el puerto 4444, y en el momento que llegue uno se ejecutará el MIDlet MIDletRecibirSMS, permitiendo que lleguen desde cualquier remitente.

19.1.3.2. Registro dinámico

Cuando utilicemos registro dinámico podremos configurar, además de las conexiones anteriores, las conexiones de sockets y datagramas para las que se asigne el puerto de forma dinámica:

socket://
datagram://

Utilizaremos este tipo de registro cuando estemos utilizando direcciones dinámicas, o bien cuando utilizando direcciones estáticas queramos registrar la conexión sólo si se cumplen ciertas condiciones.

En este caso el registro lo realizaremos en tiempo de ejecución, utilizando la API de PushRegistry. Podemos registrar una conexión entrante dinámicamente de la siguiente forma:

PushRegistry.registerConnection(url, 
    nombreClaseMIDlet, remitentesPermitidos);

Si estamos utilizando una conexión entrante asignada dinámicamente, encontramos el problema de que el sistema externo no sabrá a qué dirección debe enviar la información para contactar con nuestra aplicación. Para solucionar este problema deberemos comunicar a este sistema externo la dirección en la que estamos escuchando. Esto podemos hacerlo de la siguiente forma:

// Creamos socket servidor asignando el puerto dinámicamente
ServerSocketConnection ssc = (ServerSocketConnection)Connector.open("socket://");
// Obtenemos el puerto que ha asignado el sistema
String url = "socket://:" + ssc.getLocalPort();
// Registramos en push una conexion entrante con este mismo puerto
PushRegistry.registerConnection(url, midletClassName, filter);
// Obtenemos la URL completa de nuestra aplicación
url = "socket://" + ssc.getLocalAddress() + ":" + ssc.getLocalPort();

// Publicamos la URL en el sistema externo
publicarURL(url);

De esta forma cada vez que el sistema asigne un nuevo puerto a nuestra aplicación deberemos publicar la nueva URL en el sistema externo.

Hemos visto que publicando la dirección en el sistema externo podemos utilizar direcciones en las que el puerto de asigna de forma dinámica por el sistema. Sin embargo, el caso en el que nuestro operador de telefonía asigne al dispositivo la IP de forma dinámica será más complicado, ya que cualquier pérdida de la conexión hará que la IP cambie y el sistema externo será incapaz de comunicarse con nuestra aplicación.

En este caso los cambios de dirección pueden ser muy frecuentes, y si la aplicación Java está cerrada no tendremos constancia del momento en el que esto ocurra, por lo que estos tipos de conexión push no serán de utilidad. En ese caso la solución será utilizar conexiones de mensajes, para las que si que tenemos una dirección (número de teléfono) asignada de forma estática.

19.1.3.3. Eliminar conexión entrante

Las conexiones entrantes push que registremos de forma dinámica podrán ser eliminadas. Para eliminar una conexión utilizaremos el siguiente método:

try {
  boolean estado = PushRegistry.unregisterConnection(url);
} catch(SecurityException e) {
  // Error de seguridad
}

El método unregisterConnection nos devolverá true si ha podido eliminar la conexión push correctamente, y false en caso contrario.

19.1.3.4. Activación de la aplicación

Cuando la aplicación haya sido activada mediante una conexión entrante push, a diferencia de la activación mediante temporizador, si que tendremos constancia de la forma en la que se ha activado.

Para esto utilizaremos el método listConnections, que nos devuelve la lista de conexiones push registradas para el MIDlet. Si a este método le pasamos true como parámetro, nos devolverá sólo aquellas conexiones en las que tengamos datos disponibles para ser leidos.

De esta forma, si al ejecutarse la aplicación existe alguna conexión push con datos disponibles sabremos que la aplicación se ha activado mediante push debido a la recepción de datos en dichas conexiones.

public boolean isPushActivated() {

String [] conexiones = PushRegistry.listConnections(true);
if (conexiones != null && conexiones.length > 0) { for (int i=0; i < conexiones.length; i++) { leerDatos(conexiones[i]);
} return true ;
} else {
return false;
} }

Cuando hayamos recibido datos en una de estas conexiones será responsabilidad de nuestro MIDlet abrir esta conexión y leer los datos.

Hemos de tener en cuenta que en conexiones como los sockets el AMS no creará ningún buffer con los datos, sino que será el MIDlet activado el que los lea directamente de la red. Por lo tanto, deberemos leerlos lo más rápidamente posible, ya que si demorásemos la lectura de datos se podría producir un timeout.

19.2. Seguridad

Vamos a estudiar la seguridad de las aplicaciones MIDP. Nos referiremos a seguridad en cuanto a que las aplicaciones que se instale el usuario en el móvil no puedan realizar actividades dañinas para él. Otros tipos de seguridad dependientes de la aplicación, como son la autentificación y la confidencialidad de la información transmitida por la red los estudiaremos en el tema de aplicaciones corporativas.

El usuario navegando por la red puede encontrar aplicaciones MIDP que para utilizarlas deberán ser instaladas de forma local en su móvil. Si permitiésemos que estas aplicaciones, una vez instaladas, pudiesen realizar cualquier acción, sería bastante peligroso utilizar este tipo de aplicaciones. El usuario debería estar muy seguro que la aplicación que se instala es de su confianza, porque de no serlo la aplicación podría realizar tareas como por ejemplo:

Por lo tanto, es importante garantizar que las aplicaciones MIDP son seguras y no pueden realizar ninguna acción dañina, para que de esta forma los usuarios puedan confiar en ellas y descargárselas sin ningún temor. A continuación veremos cómo se garantiza esta seguridad en las aplicaciones MIDP.

19.2.1. Sandbox

La seguridad de las aplicaciones MIDP se debe a que estás aplicaciones se debe a que éstas se ejecutan en un entorno restringido y controlado. Al ejecutarse sobre una máquina virtual, y no directamente sobre el dispositivo, se puede limitar el número de acciones que estas aplicaciones pueden realizar, evitando de esta forma que se realicen acciones que puedan resultar dañinas.

Las aplicaciones se ejecutan dentro de lo que se conoce como un cajón de arena (sandbox), como los que existen en los parques para que los niños jueguen de forma segura. Este cajón de arena es un entorno limitado y cerrado en el que podrá trabajar la aplicación, y en el que no se tendrá acceso a nada que pudiera resultar dañino.

En el caso de las aplicaciones MIDP, este sandbox será la suite de MIDlets. Es decir, ninguna aplicación podrá acceder a nada externo a su suite:

Como las aplicaciones MIDP no permiten acceder al sistema de ficheros del dispositivo, ni tampoco permiten utilizar su API nativa, no tendremos problemas de seguridad en este aspecto.

La única funcionalidad que podría resultar peligrosa es la capacidad que tienen estas aplicaciones de establecer conexiones de red. Una aplicación podría estar intercambiando información por la red, lo cual le costará dinero al usuario, sin que éste se diese cuenta. Sin embargo, esta es una funcionalidad imprescindible de las aplicaciones MIDP, por lo que no podemos privar a estas aplicaciones de su API de red. Por esta razón, a partir de MIDP 2.0 surge un modelo de seguridad que limitará la utilización de estas funciones a las aplicaciones que obtengan permiso para hacerlo.

19.2.2. Solicitud de permisos

En la API de MIDP 2.0 existen diferentes permisos para cada tipo de conexión que pueda realizar el dispositivo. Estos permisos son los siguientes:

javax.microedition.io.Connector.http
javax.microedition.io.Connector.socket
javax.microedition.io.Connector.https
javax.microedition.io.Connector.ssl
javax.microedition.io.Connector.datagram
javax.microedition.io.Connector.serversocket
javax.microedition.io.Connector.datagramreceiver
javax.microedition.io.Connector.comm
javax.microedition.io.PushRegistry

Cuando en nuestra aplicación necesitemos utilizar alguna conexión de cualquiera de estos tipos, deberemos solicitar el permiso para poder hacerlo. Solicitaremos los permisos en el fichero JAD, mediante las propiedades MIDlet-Permissions y MIDlet-Permissions-Opt, en las que especificaremos todos los permisos solicitados separados por comas:

MIDlet-Permissions: javax.microedition.io.Connector.http,javax.microedition.io.PushRegistry
MIDlet-Permissions-Opt: javax.microedition.io.Connector.https

El atributo MIDlet-Permissions indicará aquellos permisos que son esenciales para que nuestra aplicación pueda funcionar. Si el dispositivo en el que se va a instalar la aplicación no pudiese conceder estos permisos a nuestra aplicación, debido a que no confía en ella, se producirá un error en la instalación ya que la aplicación no funcionará sin estos permisos.

En el caso de MIDlet-Permissions-Opt, especificamos permisos que solicitamos, pero que son opcionales. Si no se pudiesen obtener estos permisos la aplicación podría funcionar.

En WTK podremos introducir esta información en la pestaña Permissions de la ventana Settings... de nuestra aplicación:

Desde esta ventana, pulsando sobre Add podremos añadir permisos de forma visual:

Aquí podremos seleccionar los permisos deseados entre todos los permisos proporcionados por la API que estemos utilizando.

19.2.3. Dominios

Los permisos que se le otorguen a cada aplicación MIDP dependerán del dominio en el que se encuentre dicha aplicación. Un dominio comprende:

Podemos distinguir distintos tipos de dominios según lo restrictivos que sean:

Hemos visto tres casos de dominios extremos como ejemplo, pero podemos tener muchos más tipos de dominios distintos. Un dominio se definirá otorgando a cada operación sensible un determinado tipo de permiso. En un dominio se pueden conceder permisos de dos formas distintas:

Esta definición de los dominios será responsabilidad del fabricante del dispositivo, por lo que no deberemos ocuparnos de ello. Nuestras aplicaciones simplemente serán asignadas a uno de los dominios disponibles en el dispositivo que las instalemos.

19.2.3.1. Dominios en dispositivos reales

Normalmente, los dispositivos reales incluyen a las aplicaciones por defecto en un dominio como el último. Es decir, cualquier aplicación que instalemos se considera que no es de confianza, y se le preguntará al usuario cada vez que la aplicación vaya a realizar una operación restringida.

Además, en el caso de los dispositivos reales, también se suele poder cambiar la configuración de este dominio por defecto en la pantalla de configuración del AMS de nuestro móvil. Por ejemplo, en el caso del Nokia 6600, podremos cambiar los permisos que se le otorgan a cada aplicación manualmente. Para cada operación restringida nos dará 4 posibilidades:

Deberemos tener cuidado de no asignarle permisos a una aplicación que no sea de nuestra confianza.

La forma en la que el dispositivo decide en qué dominio se debe incluir la aplicación no está especificada en MIDP, sin embargo se recomienda la utilización de firmas criptográficas y certificados.

De esta forma, si la aplicación instalada no lleva una firma de confianza, la aplicación se incluirá en el dominio definido por defecto de aplicaciones que no son de confianza. Si por el contrario, contiene una firma reconocida por el dispositivo, la aplicación se añadirá a un dominio de confianza correspondiente a dicha firma, que nos otorgará un determinado conjunto de permisos para los cuales no será necesaria la confirmación del usuario.

Según la firma se puede añadir la aplicación a diferentes dominios, y en cada uno de ellos se pueden conceder o denegar distintas operaciones. De esta forma, puede ocurrir que una aplicación firmada por A tenga sólo permiso para utilizar conexiones HTTP, una aplicación firmada por B tenga sólo permiso para utilizar sockets, y una firmada por C tenga permiso para utilizar cualquier tipo de conexión. Los distintos tipos de dominios definidos y la asignación de permisos a cada uno de ellos dependerá del fabricante del dispositivo.

19.2.3.2. Dominios en los emuladores

Los emuladores incluidos en WTK definen un conjunto de 4 dominios en los que se podrán incluir las aplicaciones. Estos dominios son:

Podemos indicar en la configuración de WTK cual será el dominio por defecto en el que se ejecutarán las aplicaciones cuando las carguemos directamente en el emulador (sin utilizar OTA). Podemos cambiar este dominio por defecto en la ventana de preferencias (Preferences...) del WTK.

Cuando se utilice provisionamiento OTA, el emulador se comportará como un dispositivo real, asignando a la aplicación un dominio según su firma.

19.2.4. Firmar MIDlets

En la especificación de MIDP no se establece ningún método para decidir a qué dominio corresponde cada MIDlet, pero se recomienda que para tomar esta decisión se utilicen firmas y certificados.

Cada dispositivo contendrá una serie de certificados de confianza. Cada uno de estos certificados estará asociado a un determinado dominio. Es responsabilidad del fabricante decidir qué certificados se incluyen en el dispositivo y a qué dominio se asocia cada uno.

19.2.4.1. Certificados en los dispositivos

Para que a un MIDlet se le otorguen ciertos permisos, deberá estar firmado por un certificado que sea conocido por el dispositivo donde se instala. Al instalar el MIDlet en el dispositivo, si está firmado se comprobará si el dispositivo contiene el certificado que se ha utilizado para firmarlo. De ser así, se comprobará la autenticidad de la aplicación descargada mediante este certificado, y de ser correcta se instalará la aplicación en el dominio que el dispositivo tuviese asociado a dicho certificado.

Si el certificado con el que se ha firmado la aplicación no fuese conocido por el dispositivo, simplemente instalará la aplicación en el dominio de aplicaciones que no son de confianza. Normalmente en este dominio se preguntará al usuario cada vez que se va a realizar una operación restringida.

Por lo tanto, para conseguir que a nuestro MIDlet se le otorguen permisos deberemos firmarlo por un certificado que esté incluido en el dispositivo.

La especificación de MIDP 2.0 recomienda que se incluyan 3 tipos de certificados:

Si el certificado con el que hemos firmado nuestra aplicación no está entre los anteriores, o bien no hemos firmado la aplicación, ésta se instalará en el dominio de aplicaciones no fiables que existirá en cualquier dispositivo.

19.2.4.2. Certificados en WTK

Para que nuestra aplicación obtenga permisos en un dispositivo móvil real deberíamos tenerla firmada por un certificado incorporado en el dispositivo en el que la instalamos. Sin embargo, cuando la probemos en emuladores podremos crear nuestros propios certificados y añadirlos al emulador, sin necesidad de obtenerlos a partir de una Autoridad Certificadora. De esta forma en el emulador las aplicaciones firmadas por nosotros podrán obtener los permisos que solicitemos.

Vamos a ver como firmar aplicaciones MIDP utilizando WTK. Para firmar una aplicación, lo primero que deberemos hacer es crear el paquete con la aplicación, ya que es necesario contar con el fichero JAR para obtener su digest. Una vez creado el paquete utilizaremos la opción Project > Sign para firmar la aplicación. Aparecerá la siguiente ventana:

Aquí podremos utilizar alguna de las claves disponibles para firmar nuestra aplicación, o bien crear un nuevo par de claves. Pulsaremos sobre New Key Pair... para crear nuestras propias claves:

Aquí introducimos información sobre nuestra compañía, para crear un certificado correspondiente a esta compañía. Cuando pulsemos sobre Create se creará este certificado asignándole su correspondiente par de claves, y nos mostrará la siguiente ventana para indicar a qué dominio se asignarán las aplicaciones firmadas por nosotros:

De esta forma, nuestro certificado será instalado en el emulador. Cuando instalemos una aplicación firmada por nosotros en el emulador, esta aplicación se instalará en el dominio que hayamos indicado aquí. Si elegimos trusted, nuestras aplicaciones dispondrán de todos los permisos sin tener que pedir la confirmación del usuario.

El último paso que debemos realizar es firmar nuestra aplicación utilizando el certificado que acabamos de crear. Para esto simplemente seleccionaremos en la ventana Sign MIDlet Suite el certificado que queremos utilizar, y pulsaremos sobre el botón Sign MIDlet Suite...

Una vez firmada, podremos probarla en el emulador para comprobar que se le otorgan los permisos correspondientes. Para que esto sea así, deberemos probarla utilizando provisionamiento OTA, ya que si lo hacemos de otra forma la firma no se tendría en cuenta.

Recordemos que si ejecutamos la aplicación directamente se tiene en cuenta el dominio que se haya configurado por defecto para los emuladores. Cuando utilizamos OTA se comportará como un dispositivo real, utilizando los certificados de los que dispone para asignar un dominio a nuestra aplicación.