Autenticación personalizada con Couchbase Mobile
Couchbase Mobile extiende Couchbase a la periferia, gestionando y sincronizando datos de forma segura desde cualquier nube a cualquier dispositivo móvil. Couchbase Mobile cuenta con una base de datos integrada -Couchbase Lite- con SQL y búsqueda de texto completo para JSON, sincronización peer-to-peer integrada y seguridad end-to-end desde la nube hasta el extremo.
Couchbase Mobile también cuenta con una pasarela web segura -Sync Gateway- que permite el acceso y la sincronización de datos a través de la web y admite múltiples métodos de autenticación. Uno de estos métodos es la autenticación personalizada en la que un App Server gestiona la autenticación con un sistema externo.
Esta entrada del blog le guiará a través del flujo de autenticación personalizada con ejemplos de cómo implementar el código del servidor de aplicaciones y el código de la aplicación móvil. Un OpenLDAP pero el flujo se aplica a cualquier proveedor de autenticación externo.
El servidor de aplicaciones de ejemplo es una aplicación node.js sencilla y los ejemplos de código de la aplicación móvil utilizan el módulo SDK para Android de Couchbase Lite.
Requisitos previos
Este blog asume familiaridad con Couchbase Server, Sync Gateway, y Couchbase Lite.
Necesitarás una instalación operativa de Sync Gateway 2.5 y Couchbase Server EE 6.x. Si es necesario, los siguientes enlaces pueden ponerte en marcha rápidamente:
Todo el código de este blog está disponible en el siguiente repositorio Git: https://github.com/dugbonsai/sg-custom-auth
Flujo de autenticación personalizado
El siguiente diagrama muestra un ejemplo de autenticación personalizada.
- El usuario de la aplicación móvil intenta iniciar sesión con sus credenciales a través de una interfaz REST expuesta por el App Server.
- El App Server autentica al usuario contra un servidor OpenLDAP.
- Si el usuario no está autenticado, se le devuelve a la interfaz de inicio de sesión.
- Si el usuario está autenticado, App Server obtiene la información del usuario de Sync Gateway a través de una interfaz REST.
- Si el usuario existe en Sync Gateway, vaya al paso 8.
- Si el usuario no existe en Sync Gateway, el App Server crea un nuevo usuario en Sync Gateway a través de una interfaz REST.
- Si el usuario no se creó en Sync Gateway, App Server devuelve un error y el usuario regresa a la interfaz de usuario de inicio de sesión.
- Si el usuario se creó en Sync Gateway, App Server crea una nueva sesión para el usuario en Sync Gateway a través de una interfaz REST.
- Si la sesión no se creó en Sync Gateway, App Server devuelve un error y el usuario regresa a la interfaz de usuario de inicio de sesión.
- Si la sesión se creó en Sync Gateway, App Server devuelve el ID de sesión.
- La aplicación móvil almacena el ID de sesión y crea un replicador de Couchbase Lite utilizando el ID de sesión.
- Si la replicación falla debido a una sesión caducada en Sync Gateway, el usuario vuelve a la interfaz de inicio de sesión.
Configuración de OpenLDAP
Si ya tiene configurado un servidor LDAP puede saltarse esta sección. Si no tiene un servidor LDAP configurado, estas instrucciones le guiarán a través de la configuración de OpenLDAP en Ubuntu 18.04.
- Crear un fichero LDIF (ldap_data.ldif) con información para rellenar la base de datos LDAP (pulse aquí para obtener más información sobre los archivos LDIF). Las instrucciones anteriores para configurar OpenLDAP también contienen instrucciones para crear el archivo LDIF para rellenar la base de datos LDAP. En este ejemplo, el usuario mobileuser (a partir de la línea 13) se utilizará cuando se autentique desde la aplicación móvil.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
dn: ou=Personas,dc=ejemplo,dc=com objetoClase: unidad organizativa ou: Personas dn: ou=Grupos,dc=ejemplo,dc=com objetoClase: unidad organizativa ou: Grupos dn: cn=departamento,ou=Grupos,dc=ejemplo,dc=com objetoClase: posixGroup cn: subgrupo gidNumber: 5000 dn: uid=usuario móvil,ou=Personas,dc=ejemplo,dc=com objetoClase: inetOrgPerson objetoClase: posixAccount objetoClase: shadowAccount uid: usuario móvil sn: Usuario givenName: Móvil cn: Móvil Usuario displayName: usuario móvil uidNumber: 10000 gidNumber: 5000 userPassword: contraseña gecos: Móvil Usuario loginShell: /papelera/bash inicioDirectorio: /Inicio/usuario móvil |
- Añade los datos iniciales a la base de datos OpenLDAP:
1 |
$ ldapadd -x -D cn=admin,dc=ejemplo,dc=com -W -f ldap_datos.ldif |
- Pruebe la configuración buscando mobileuser en el directorio OpenLDAP:
1 |
$ ldapsearch -x -LLL -b dc=ejemplo,dc=com uid=usuario móvil |
Verás la información para mobileuser:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
dn: uid=usuario móvil,ou=Personas,dc=ejemplo,dc=com objetoClase: inetOrgPerson objetoClase: posixAccount objetoClase: shadowAccount uid: usuario móvil sn: Usuario givenName: Móvil cn: Móvil Usuario displayName: usuario móvil uidNumber: 10000 gidNumber: 5000 gecos: Móvil Usuario loginShell: /papelera/bash inicioDirectorio: /Inicio/usuario móvil |
Implementación de App Server
El App Server se implementa como una aplicación node.js. El código completo del App Server está disponible en auth.js en el siguiente repositorio Git: sg-custom-auth. El App Server utiliza el paquete passport-ldapauth para la autenticación LDAP. Los siguientes fragmentos de código destacan la llamada para autenticar contra el servidor OpenLDAP y las llamadas a la API REST de Sync Gateway.
El App Server debe gestionar las llamadas a POST /login. Este endpoint se llama desde la aplicación móvil con las credenciales de usuario almacenadas en el cuerpo de la solicitud en nombre de usuario y contraseña. El App Server utiliza estas credenciales para autenticarse en el servidor OpenLDAP.
El valor de searchBase debe coincidir con los componentes de dominio definidos en su servidor LDAP. dc=example,dc=com se utilizó anteriormente, por lo que aquí se utilizan los mismos valores (línea 12).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
var express = requiere(exprés), pasaporte = requiere(pasaporte), bodyParser = requiere('body-parser'), LdapStrategy = requiere(pasaporte-ldapauth), rizo = requiere('curl-request'); var syncGatewayEndpoint = 'http://:4985/'; var aplicación = express(); var OPTS = { servidor: { url: 'ldap://:389', searchBase: 'dc=ejemplo,dc=com', // DEBE coincidir con el directorio LDAP filtro de búsqueda: '(uid={{nombredeusuario}})' } }; pasaporte.utilice(nuevo LdapStrategy(OPTS)); aplicación.utilice(bodyParser.json()); aplicación.utilice(bodyParser.urlencoded({ampliado: falso})); aplicación.utilice(pasaporte.inicializar()); aplicación.Correo electrónico:(Inicio de sesión, pasaporte.autentifique(ldapauth, {sesión: falso}), función(consulte, res) { // usuario autenticado con éxito en LDAP } |
Los siguientes pasos se ejecutarán si el usuario está autenticado.
Obtener información de usuario de Sync Gateway
Obtener información de usuario de Sync Gateway llamando a GET /{db}/_usuario/{nombre}. Si el usuario existe en Sync Gateway, el código de respuesta es 200. Si el usuario no existe en Sync Gateway, el código de respuesta es 404.
1 2 3 4 5 6 7 8 9 10 |
getUser = nuevo(rizo); getUser.setHeaders([Content-Type: application/json']) .consiga(syncGatewayEndpoint + "/_usuario/ + consulte.cuerpo.nombre de usuario) .entonces(({statusCode, cuerpo, cabeceras}) => { si (statusCode == 404) { // status == 404: el usuario no existe } si no si (statusCode == 200) { // status == 200: el usuario existe } }) |
Si el usuario no existe en Sync Gateway, cree un nuevo usuario
Cree un nuevo usuario en Sync Gateway llamando a POST /{db}/_user/. Si el usuario se ha creado correctamente en la puerta de enlace Sync, el código de respuesta es 201.
1 2 3 4 5 6 7 8 9 10 11 |
postUsuario = nuevo(rizo); postUsuario.setHeaders([Content-Type: application/json']) .setBody('{"name": "' + consulte.cuerpo.nombre de usuario + '", "contraseña": "' + consulte.cuerpo.contraseña + '"}') .Correo electrónico:(syncGatewayEndpoint + "/_usuario/) .entonces(({statusCode, cuerpo, cabeceras}) => { si (statusCode == 201) { // status == 201: éxito } si no { // no se ha podido crear el usuario } }) |
Crear una sesión para el usuario en Sync Gateway
Cree una sesión para el usuario en Sync Gateway llamando a POST /{db}/sesión. En este ejemplo, la sesión expirará transcurridos 30 minutos. Si la sesión se ha creado correctamente en Sync Gateway, el código de respuesta es 200. La respuesta JSON contiene los siguientes valores:
session_idel ID de la nueva sesión. La aplicación móvil lo utilizará para la autenticación con Sync Gateway.
caduca en: marca de tiempo cuando expira la sesión. No se utiliza en la aplicación móvil.
nombre_de_la_galleta: nombre de la cookie de sesión. No se utiliza en la aplicación móvil.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
resBody = {statusCode: 200}; postSession = nuevo(rizo); postSession.setHeaders([Content-Type: application/json']) .setBody('{"name": "' + solicitar.cuerpo.nombre de usuario + '", "ttl": 1800}') .Correo electrónico:(syncGatewayEndpoint + /_sesión) .entonces(({statusCode, cuerpo, cabeceras}) => { si (statusCode == 200) { // status == 200: éxito resBody.session_id = cuerpo.session_id; resBody.caduca en = cuerpo.caduca en; resBody.nombre_de_la_galleta = cuerpo.nombre_de_la_galleta; // enviar respuesta de éxito al cliente respuesta.enviar(JSON.stringify(resBody)); } si no { // no se ha podido crear la sesión } }) |
Pruebas de autenticación
Para probar la autenticación desde el App Server, inícielo utilizando el siguiente comando:
1 |
$ nodo auth.js |
Cuando se inicie, verás lo siguiente:
1 |
Escuchar en puerto 8080 |
Puede probar el servidor de aplicaciones utilizando un simple comando curl como el siguiente (o Postman, etc.):
1 |
$ rizo -d "nombreusuario=usuariomóvil&contraseña=contraseña" -X POST http://:8080/login |
Verá un resultado similar al siguiente:
1 |
{"statusCode":200,"session_id":"c149012eaa8d0cf15b1b4110cf0a2fec259ef726","caduca":"2019-08-01T13:47:56.311076773Z","nombre_galleta":"SyncGatewaySession"} |
Si el usuario no existe en LDAP, la respuesta será:
1 |
Sin autorización |
La salida del App Server tendrá este aspecto:
1 2 3 4 5 |
usuario móvil tiene ha sido autentificado con LDAP crear usuario usuario móvil en Sincroniza Pasarela usuario usuario móvil creado en Sincroniza Pasarela crear sesión para usuario usuario móvil creado sesión para usuario móvil |
Implantación de aplicaciones móviles
Todo lo que queda por hacer es realizar las llamadas apropiadas desde la aplicación móvil al servidor de aplicaciones y a la pasarela de sincronización. La aplicación móvil utiliza el Marco de volea para realizar la llamada REST al App Server. Los siguientes fragmentos de código destacan la llamada al App Server y el código de Couchbase Lite para autenticar usando el session_id.
Autenticar al usuario móvil
Autenticar usuario con App Server llamando POST /login/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
JSONObject reqBody = nuevo JSONObject(); reqBody.poner("nombre de usuario", <usuario suministrado nombre de usuario>); reqBody.poner("contraseña", <usuario suministrado contraseña>); Cadena url = <Aplicación Servidor host>:8080/inicio de sesión; RequestQueue cola = Volea.newRequestQueue(<contexto>); JsonRequest<JSONObject> jsonRequest = nuevo JsonObjectRequest( Solicitar.Método.POST, url, reqBody, nuevo Respuesta.Oyente<JSONObject>() { @Anular público void onResponse(JSONObject respuesta) { // obtener session_id de la respuesta pruebe { Cadena sessionID = respuesta.getString("session_id"); // Almacenar session_id } captura (JSONException je) { // Manejar excepción } } }, nuevo Respuesta.ErrorListener() { @Anular público void onErrorResponse(VolleyError error) { // autenticación fallida } }); cola.añada(jsonRequest); |
Crear una réplica única
Cree una replicación única utilizando el identificador de sesión guardado (línea 13) y vuelva a autenticarse si la sesión de Sync Gateway ha caducado.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
Cadena syncGatewayEndpoint = "ws://:4984/{db}"; URI url = null; pruebe { url = nuevo URI(mSyncGatewayEndpoint); } captura (URISyntaxException e) { e.printStackTrace(); devolver; } ReplicatorConfiguration config = nuevo ReplicatorConfiguration(base de datos, nuevo URLEndpoint(url)); config.setReplicatorType(ReplicatorConfiguration.ReplicatorType.PUSH_AND_PULL); config.setContinuous(falso); config.setAuthenticator(nuevo Autenticador de sesión(sessionID)); Replicador replicador = nuevo Replicador(config); replicador.addChangeListener(nuevo ReplicatorChangeListener() { @Anular público void cambiado(ReplicatorChange cambiar) { CouchbaseLiteException error = cambiar.getStatus().getError(); si (error != null) { si (error.getCode() == 10401) { // sesión caducada; volver a autenticar } } ... } }); replicador.iniciar(); |
El futuro
Si no conoce Couchbase, aproveche nuestra formación gratuita en línea disponible en https://learn.couchbase.com para saber más.
Más tutoriales para móviles en la página Página web de tutoriales de Couchbase.