android - manager - retrofit oauth2
¿No debería Android AccountManager almacenar tokens OAuth en una base por aplicación/UID? (4)
¿Es esto una preocupación de seguridad válida / práctica?
Para el cliente A oficial, mi proveedor OAuth2 puede emitir un token de tipo / alcance "súper" que otorga acceso a piezas públicas y privadas de mi API
En el caso general, nunca podría confiar en un token de autenticación otorgado a un usuario que permanezca secreto de ese usuario . Por ejemplo, el usuario podría estar ejecutando un teléfono rooteado y leer el token, obteniendo acceso a su API privada. Lo mismo si el sistema del usuario estaba comprometido (el atacante podría leer el token en este caso).
Dicho de otra manera, no existe una API "privada" que sea accesible para cualquier usuario autenticado, por lo que es razonable que Android ignore este objetivo de seguridad por oscuridad en su diseño.
una aplicación maliciosa ... podría obtener acceso a la ficha OAuth2 almacenada de mi aplicación
Para el caso de la aplicación maliciosa, comienza a parecer más razonable que una aplicación maliciosa no pueda usar el token del cliente, ya que esperamos que el sistema de permisos de Android proporcione aislamiento de las aplicaciones maliciosas (siempre que el usuario lea / se preocupe por los permisos que aceptado cuando lo instalaron). Sin embargo, como dices, el usuario debe aceptar una solicitud de acceso (proporcionada por el sistema Android) para que la aplicación use tu token.
Dado que la solución de Android parece estar bien, las aplicaciones no pueden usar silenciosamente la autenticación de un usuario sin preguntar, pero el usuario puede permitir explícitamente que las aplicaciones reutilicen una autenticación previa a un servicio, lo cual es conveniente para el usuario.
Posible revisión de las soluciones
"Secreto" authTokenType ... no parece muy seguro
De acuerdo, es solo otra capa de seguridad a través de la oscuridad; Parece que cualquier aplicación que desee compartir su autenticación debería haber buscado lo que authTokenType era de todos modos, por lo que adoptar este enfoque simplemente lo hace un poco más incómodo para este hipotético desarrollador de aplicaciones.
Enviar ID / secreto del cliente con token OAuth2 ... [para] verificar que la aplicación sea el cliente autorizado del lado del servidor
Esto no es posible en el caso general (todo lo que el servidor obtiene es una serie de mensajes en un protocolo; no se puede determinar el código que generó esos mensajes). En esta instancia específica, podría proteger contra la amenaza más limitada de una aplicación cliente / malintencionada alternativa (no raíz): no estoy lo suficientemente familiarizado con el AccountManager para comentar (lo mismo para sus soluciones personalizadas de autenticación de tokens).
Sugerencia
Describió dos amenazas: aplicaciones maliciosas que un usuario no desea tener acceso a su cuenta, y clientes alternativos que usted (el desarrollador) no desea utilizar con partes de la API.
Aplicaciones maliciosas: considere qué tan sensible es el servicio que está brindando, y si no es más confidencial que, por ejemplo, las cuentas de Google / Twitter, solo confíe en las protecciones de Android (permisos en la instalación, pantalla de Solicitud de acceso). Si es más sensible, considere si su restricción de utilizar el AccountManager de Android es apropiada. Para proteger fuertemente al usuario contra el uso malicioso de su cuenta, pruebe la autenticación de dos factores para acciones peligrosas (por ejemplo, agregar los detalles de una cuenta de un nuevo destinatario en la banca en línea).
Clientes alternativos: no tienen una API secreta que intente solo ser accesible para un cliente oficial; la gente lo sostendrá. Asegúrese de que todas sus API públicas sean seguras sin importar qué cliente (futuro) esté usando el usuario.
El Administrador de cuentas de Android parece recuperar el mismo token de autenticación en caché para las aplicaciones con diferentes UID: ¿esto es seguro? No parece compatible con OAuth2, ya que no se supone que los tokens de acceso se compartan entre diferentes clientes.
Fondo / Contexto
Estoy creando una aplicación de Android que usa OAuth2 para la autenticación / autorización de solicitudes de la API REST a mi servidor, que es un proveedor OAuth2. Como la aplicación es la aplicación "oficial" (a diferencia de una aplicación de terceros), se considera un cliente OAuth2 de confianza, por lo que estoy usando el flujo de contraseñas del propietario del recurso para obtener un token OAuth2: el usuario (el propietario del recurso) ingresa su nombre de usuario / contraseña en la aplicación, que luego envía su ID de cliente y secreto de cliente junto con las credenciales de usuario al punto extremo del token OAuth2 de mi servidor a cambio de un token de acceso que se puede usar para hacer llamadas API, así como token de actualización vivido utilizado para obtener nuevos tokens de acceso cuando caducan. El razonamiento es que es más seguro almacenar el token de actualización en el dispositivo que la contraseña del usuario.
Estoy utilizando AccountManager para administrar la cuenta y el token de acceso asociado en el dispositivo. Como proporciono mi propio proveedor de OAuth2, he creado mi propio tipo de cuenta personalizada extendiendo AbstractAccountAuthenticator y otros componentes necesarios, como se explica en esta Guía de desarrollo de Android y demostrado en el proyecto de ejemplo SampleSyncAdapter. Puedo agregar con éxito cuentas de mi tipo personalizado desde mi aplicación y administrarlas desde la pantalla de configuración de "Cuentas y sincronización" de Android.
La cuestión
Sin embargo, me preocupa la forma en que el AccountManager almacena en caché y emite auth tokens, específicamente, que el mismo token de autenticación para un tipo de token y tipo de cuenta dado parece ser accesible por cualquier aplicación a la que el usuario haya otorgado acceso.
Para obtener un token de autenticación a través del AccountManager, se debe invocar AccountManager.getAuthToken() , pasando, entre otras cosas, la instancia Account para la cual se obtiene el token auth y el authTokenType
deseado. Si existe un token de autenticación para la cuenta especificada y authTokenType, y si el usuario otorga acceso (a través de la pantalla de "Solicitud de acceso" ) a la aplicación que ha realizado la solicitud de token de autenticación (en los casos en que el UID de la aplicación solicitante no coincida el UID del autenticador), luego se devuelve el token. En caso de que mi explicación sea deficiente, esta útil entrada al blog lo explica muy claramente. Basado en esa publicación, y después de examinar el origen de AccountManager y AccountManagerService (una clase interna que hace el trabajo pesado para AccountManager) para mí, parece que solo 1 token de autenticación se almacena por authTokenType / account combo.
Por lo tanto, parece factible que si una aplicación maliciosa conociera el tipo de cuenta y authTokenType (s) utilizados por mi autenticador, podría invocar AccountManager.getAuthToken () para obtener acceso al token OAuth2 almacenado de mi aplicación, suponiendo que el usuario otorgue acceso a la herramienta maliciosa. aplicación
Para mí, el problema es que la implementación de almacenamiento en caché predeterminada de AccountManager se basa en un paradigma en el que, si tuviéramos que aplicar capas a un contexto de autenticación / autorización OAuth2, el teléfono / dispositivo sería un único cliente OAuth2 para un proveedor de servicios / recursos . Mientras que, el paradigma que tiene sentido para mí es que cada aplicación / UID debe considerarse como su propio cliente OAuth2. Cuando mi proveedor de OAuth2 emite un token de acceso, emite un token de acceso para esa aplicación en particular que ha enviado el ID de cliente y el secreto de cliente correctos, no todas las aplicaciones en el dispositivo. Por ejemplo, el usuario puede tener tanto mi aplicación oficial (llámela aplicación Cliente A) como una aplicación de terceros "autorizada" que use mi API (llámela aplicación Cliente B) instalada. Para el Cliente A oficial, mi proveedor OAuth2 puede emitir un token de tipo / alcance "súper" que otorga acceso a elementos públicos y privados de mi API, mientras que para el Cliente B de terceros, mi proveedor puede emitir un tipo "restringido" token de / scope que solo concede acceso a las llamadas API públicas. No es posible que la aplicación Cliente B obtenga el token de acceso de la aplicación del Cliente A, que la implementación actual de AccountManager / AccountManagerService parece permitir. Porque, incluso si el usuario otorga autorización al Cliente B para el token super del Cliente A, el hecho es que mi proveedor OAuth2 solo pretendía otorgar ese token al Cliente A.
¿Estoy pasando por alto algo aquí? ¿Mi creencia de que los tokens de autenticación se deben emitir por aplicación / UID (cada aplicación es un cliente distinto) racional / práctico, o son auth-tokens-por-dispositivo (cada dispositivo es un cliente) el estándar / aceptado ¿práctica?
¿O hay algún error en mi comprensión del código / restricciones de seguridad en torno a AccountManager
/ AccountManagerService
, de modo que esta vulnerabilidad no existe en realidad? AccountManager
el escenario anterior Cliente A / Cliente B con AccountManager
y mi autenticador personalizado, y mi aplicación cliente de prueba B, que tiene un alcance de paquete y UID diferente, pude obtener el token de autenticación que mi servidor había emitido para mi probar la aplicación de cliente A authTokenType
el mismo authTokenType
(durante el cual se me authTokenType
pantalla de concesión de "Solicitud de acceso", que authTokenType
porque soy un usuario y, por lo tanto, no tengo ni idea) ...
Soluciones posibles
a. "Secreto" authTokenType
Para obtener el token de autenticación, se debe conocer authTokenType
; ¿Debería el authTokenType
ser tratado como un tipo de secreto de cliente, de modo que un token emitido para un tipo de token secreto determinado pueda ser obtenido solo por aquellas aplicaciones cliente "autorizadas" que conocen el tipo de token secreto? Esto no parece muy seguro; en un dispositivo rooteado, sería posible examinar la columna authtokens
tabla authtokens
en la base de datos de accounts
del sistema y examinar los valores de authTokenType que están almacenados con mis tokens. Por lo tanto, los tipos de tokens de autenticación "secretos" utilizados en todas las instalaciones de mi aplicación (y cualquier aplicación de terceros autorizada utilizada en el dispositivo) se habrán expuesto en una ubicación central. Al menos con las identificaciones / secretos de los clientes de OAuth2, incluso si deben estar empaquetados con la aplicación, se distribuyen entre diferentes aplicaciones de clientes, y se puede intentar ofuscarlos (lo cual es mejor que nada) para ayudar a desanimar a aquellos que lo harían. desempaquetar / descompilar la aplicación.
segundo. Tokens de autenticación personalizados
De acuerdo con los documentos para AccountManager.KEY_CALLER_UID y AuthenticatorDescription.customTokens , y el código fuente de AccountManagerService
que hice referencia anteriormente, debería poder especificar que mi tipo de cuenta personalizada use "tokens personalizados" y gire mi propia implementación de memoria caché / almacenamiento de tokens dentro de mi costumbre autenticador, en el que puedo obtener el UID de la aplicación que realiza la llamada para ordenar / recuperar los toques de autenticación en función de UID. Básicamente, tendría una tabla de authtokens
como la implementación predeterminada, excepto que habría una columna de uid
añadida para que los tokens se indexen de forma exclusiva en UID, cuenta y tipo de token de autenticación (a diferencia de solo la cuenta y el tipo de token de autenticación). Esto parece una solución más segura que el uso de AuthTokenTypes "secretos", ya que eso implicaría el uso de los mismos authTokenTypes
en todas las instalaciones de mi aplicación / autenticador, mientras que los UID varían de sistema a sistema y no se pueden falsificar fácilmente. Aparte de la alegre sobrecarga de escribir y administrar mi propio mecanismo de caché de tokens, ¿qué desventajas hay para este enfoque en términos de seguridad? ¿Es excesivo? ¿Estoy realmente protegiendo algo, o me estoy perdiendo algo de tal manera que incluso con una implementación así, todavía sería bastante fácil para un cliente de aplicación maliciosa obtener el token de autenticación de otro cliente de aplicación utilizando el AccountManager
y authTokenType
(s) que no son se garantiza que es secreto (suponiendo que dicha aplicación maliciosa no conoce el secreto del cliente OAuth2, y por lo tanto no puede obtener directamente un token nuevo, pero solo podría esperar obtener uno que ya estaba almacenado en caché en el AccountManager
en nombre del cliente de aplicación autorizado).
do. Enviar ID de cliente / secreto con Token OAuth2
Podría seguir con la implementación del almacenamiento de tokens predeterminado de AccountManagerService
y aceptar la posibilidad de acceso no autorizado al token de autenticación de mi aplicación, pero podría forzar a las solicitudes de API a incluir siempre el ID del cliente OAuth2 y el secreto del cliente, además del token de acceso, y verificar en el lado del servidor que la aplicación es el cliente autorizado para el que se emitió el token en primer lugar. Sin embargo, me gustaría evitar esto porque A) AFAIK, la especificación OAuth2 no requiere autenticación de cliente para solicitudes de recursos protegidos; solo se requiere el token de acceso, y B) Me gustaría evitar la sobrecarga adicional de autenticar al cliente en cada una solicitud.
Esto no es posible en el caso general (todo lo que el servidor obtiene es una serie de mensajes en un protocolo; no se puede determinar el código que generó esos mensajes). - Michael
Pero lo mismo podría decirse de la autenticación inicial del cliente en el flujo OAuth2 durante el cual el cliente recibe el token de acceso por primera vez. La única diferencia es que en lugar de autenticarse solo en la solicitud de token, las solicitudes de recursos protegidos también se autenticarían de la misma manera. (Tenga en cuenta que la aplicación cliente podría pasar su identificación de cliente y secreto de cliente a través del parámetro AccountManager.getAuthToken()
de AccountManager.getAuthToken()
, que mi autenticador personalizado pasaría a mi proveedor de recursos, según el protocolo OAuth2).
Preguntas clave
- ¿Es posible que una aplicación obtenga authToken de otra aplicación para una cuenta invocando AccountManager.getAuthToken () con el mismo authTokenType?
Si esto es posible, ¿ es esto una preocupación de seguridad válida / práctica dentro de un contexto OAuth2?
Nunca se puede confiar en un token de autenticación dado a un usuario que permanezca secreto de ese usuario ... por lo que es razonable que Android ignore esta seguridad por su objetivo de oscuridad en su diseño - Michael
PERO - No me preocupa que el usuario (el propietario del recurso) obtenga el token de autenticación sin mi consentimiento; Me preocupan los clientes no autorizados (aplicaciones). Si el usuario quiere ser un atacante de sus propios recursos protegidos, entonces él puede quedarse inconsciente. Estoy diciendo que no debería ser posible que un usuario instale mi aplicación cliente y, sin saberlo, una aplicación de cliente "impostora" que pueda obtener acceso al token de autenticación de mi aplicación simplemente porque se transfirió el authTokenType correcto y el usuario estaba demasiado vago / inconsciente / apresurado para examinar la pantalla de solicitud de acceso. Esta analogía puede ser un poco simplificada, pero no considero "seguridad por oscuridad" que mi aplicación de Facebook instalada no pueda leer los correos electrónicos almacenados en caché por mi aplicación de Gmail, que es diferente de mí (el usuario) rooteando mi teléfono y examinando el caché contenido yo mismo.
El usuario debe aceptar una solicitud de acceso (proporcionada por el sistema Android) para que la aplicación use su token ... Dado que la solución de Android parece estar bien, las aplicaciones no pueden usar silenciosamente la autenticación de un usuario sin preguntarlo. Michael
PERO - Esto también es un problema de autorización : el token de autenticación emitido para mi cliente "oficial" es la clave para un conjunto de recursos protegidos para los cuales ese cliente y solo ese cliente están autorizados. Supongo que se podría argumentar que, dado que el usuario es el propietario de esos recursos protegidos, si acepta la solicitud de acceso de un cliente externo (ya sea una aplicación asociada "sagrada" o algún phisher), entonces está autorizando efectivamente a la tercera parte. cliente de la fiesta que hizo la solicitud para acceder a esos recursos. Pero tengo problemas con esto:
- El usuario promedio no es lo suficientemente consciente de la seguridad como para poder tomar esta decisión de manera competente. No creo que debamos depender únicamente del juicio del usuario para tocar "Denegar" en la pantalla de solicitud de acceso de Android para evitar incluso un intento de phishing. Cuando al usuario se le presenta la solicitud de acceso, mi autenticador puede ser súper detallado y enumerar todos los tipos de recursos protegidos confidenciales (que solo mi cliente debería poder acceder) que el usuario otorgará si acepta la solicitud, y en la mayoría de los casos, el usuario aún no estará al tanto y aceptará. Y en otros intentos de phishing más sofisticados, la aplicación "impostora" simplemente se verá demasiado "oficial" para que el usuario levante una ceja en la pantalla de solicitud de acceso. O, un ejemplo más contundente: en la pantalla de solicitud de acceso, mi autenticador podría decir simplemente: "¡No acepte esta solicitud! Si está viendo esta pantalla, ¡una aplicación maliciosa está intentando obtener acceso a su cuenta!" Con suerte, en tal caso, la mayoría de los usuarios rechazarían la solicitud. Pero, ¿por qué debería llegar tan lejos? Si Android simplemente mantiene los tokens de autenticación aislados para el alcance de cada aplicación / UID para el que se emitieron, entonces esto no sería un problema. Simplifiquemos, incluso en el caso en que solo tengo una aplicación de cliente "oficial" y, por lo tanto, mi proveedor de recursos ni siquiera se preocupa por emitir tokens a otros clientes de terceros, como desarrollador debería tener la opción de decirle al AccountManager, "No! Bloquea este token de autenticación para que solo mi aplicación tenga acceso". Puedo hacer esto si sigo la ruta de "tokens personalizados", pero incluso en ese caso, no podría evitar que al usuario se le presente primero la pantalla de solicitud de acceso. Como mínimo, se debe documentar mejor que la implementación predeterminada de AccountManager.getAuthToken () devolverá el mismo token de autenticación para todas las aplicaciones / UID que lo soliciten.
- Incluso los documentos de Android reconocen OAuth2 como el " estándar de la industria " para la autenticación (y presumiblemente la autorización). La especificación OAuth2 establece claramente que los tokens de acceso no se deben compartir entre los clientes ni divulgarse de ninguna manera. ¿Por qué, entonces, la implementación / configuración de AccountManager predeterminada hace que sea tan fácil para un cliente obtener el mismo token de autenticación en caché que otro cliente obtuvo originalmente del servicio? Una solución simple dentro del AccountManager sería solo reutilizar tokens en caché para la misma aplicación / UID bajo la cual se obtuvieron originalmente del servicio. Si no hay un token de autenticación en caché local disponible para un UID determinado, entonces debe obtenerse del servicio. O al menos hacer de esto una opción configurable para el desarrollador.
- En el flujo OAuth de 3 patas (que implica que el usuario otorgue acceso al cliente), ¿no se supone que es el proveedor de servicios / recursos (y no, por ejemplo, el SO) que llega a A) autentica al cliente y B ) si el cliente es válido, presente al usuario la solicitud de acceso de concesión? Parece que Android está (incorrectamente) usurpando este rol en el flujo.
Pero el usuario puede permitir explícitamente que las aplicaciones reutilicen una autenticación previa a un servicio, lo cual es conveniente para el usuario .-- Michael
PERO - No creo que el retorno de la inversión en la conveniencia justifique el riesgo de seguridad. En los casos en que la contraseña del usuario se almacena en la cuenta del usuario, realmente, la única comodidad que se adquiere para el usuario es que en lugar de enviar una solicitud web a mi servicio para obtener un token nuevo y distinto que esté autorizado para el cliente solicitante, se devuelve un token almacenado localmente que no está autorizado para el cliente. Por lo tanto, el usuario obtiene la leve conveniencia de ver un diálogo de progreso de "Iniciar sesión ..." unos segundos menos, a riesgo de que el usuario sufra grandes inconvenientes por el robo / uso indebido de sus recursos.
Teniendo en cuenta que estoy comprometido con A) utilizando el protocolo OAuth2 para asegurar mis solicitudes de API, B) proporcionando mi propio proveedor de autenticación / recursos OAuth2 (en lugar de autenticar con, digamos, Google o Facebook), y C) utilizando el AccountManager de Android para Administrar mi tipo de cuenta personalizada y su (s) token (s), ¿son válidas alguna de las soluciones propuestas? ¿Qué tiene más sentido? ¿Estoy pasando por alto alguno de los pros / contras? ¿Existen alternativas que valgan la pena que no haya pensado?
[Uso] Clientes alternativos No tiene una API secreta que intente solo ser accesible para un cliente oficial; la gente lo sostendrá. Asegúrese de que todas sus API públicas sean seguras sin importar qué cliente (futuro) esté usando el usuario: Michael
PERO - ¿Esto no derrota uno de los propósitos principales de usar OAuth2 en primer lugar? ¿De qué sirve la autorización si todos los potenciales autorizados estuvieran autorizados al mismo alcance de los recursos protegidos?
¿Alguien más sintió que esto era un problema, y cómo funcionó? He hecho algunas búsquedas exhaustivas en Google para tratar de descubrir si otros han sentido que se trata de un problema / preocupación de seguridad, pero parece que la mayoría de las publicaciones / preguntas relacionadas con el AccountManager y los tokens de autenticación de Android tratan sobre cómo autenticarse con una cuenta de Google y no con un tipo de cuenta personalizado y el proveedor OAuth2. Además, no pude encontrar a nadie que estuviera preocupado por la posibilidad de que las diferentes aplicaciones usen el mismo token de autenticación, lo que me hace preguntarme si esta es realmente una posibilidad / digna de preocupación en primer lugar (ver mis primeras 2 "Preguntas clave" " listados arriba).
¡Agradezco su aporte / orientación!
En respuesta a...
Michael : Creo que las principales dificultades que tengo con tu respuesta son:
Todavía me inclino a pensar en las aplicaciones como clientes separados y distintos de un servicio, en lugar de que el usuario / teléfono / dispositivo sea un cliente "grande", y por lo tanto un token que ha sido autorizado para una aplicación no debería, por predeterminado, ser transferible a uno que no tiene. Parece que puede estar insinuando que es discutible considerar cada aplicación como un cliente distinto debido a la posibilidad de que,
el usuario podría estar ejecutando un teléfono rooteado y leer el token, obtener acceso a su API privada ... [o] si el sistema del usuario estaba en peligro (el atacante podría leer el token en este caso)
y que, por lo tanto, en el gran esquema de cosas, debemos considerar que el dispositivo es un cliente del servicio, ya que no podemos garantizar la seguridad entre las aplicaciones en el dispositivo mismo. Es cierto si el sistema en sí se ha visto comprometido, entonces no puede haber ninguna garantía de autenticar / autorizar las solicitudes que se envían desde ese dispositivo a un servicio. Pero lo mismo podría decirse, por ejemplo, TLS; la seguridad del transporte es irrelevante si los puntos finales no pueden ser asegurados. Y para la gran mayoría de los dispositivos Android, que no están comprometidos, creo que es más seguro considerar cada cliente de aplicación como un punto final distinto, en lugar de agruparlos en uno compartiendo el mismo token de autenticación.
- Cuando se presenta la pantalla de "solicitud de acceso" (similar al contrato de licencia de usuario de software que siempre leemos a fondo antes de consentir e instalar), no confío en la opinión del usuario para distinguir una aplicación de cliente maliciosa / no autorizada de una que no lo es.
Creo que @Michael respondió la pregunta perfectamente; sin embargo, para hacer la respuesta más sensata y corta para aquellos que buscan una respuesta rápida, escribo esto.
Su preocupación acerca de la seguridad de Android AccountManager
es correcta, pero esto es lo que OAuth debe ser, de lo que depende Android AccountManager
.
En otras palabras, si está buscando un mecanismo de autenticación muy seguro, esta no sería una buena opción para usted. No debe confiar en los tokens almacenados en caché para la autenticación, ya que pueden revelarse fácilmente al intruso en caso de que exista alguna vulnerabilidad de seguridad en el dispositivo del usuario, como otorgar inadvertidamente permiso de acceso al intruso, ejecutar un dispositivo rooteado, etc.
La mejor alternativa a OAuth en sistemas de autenticación más seguros, por ejemplo, aplicaciones de banca en línea, es el uso de encriptación asimétrica utilizando claves públicas y privadas, en las que el usuario debe ingresar su contraseña cada vez que utiliza los servicios. La contraseña se cifra luego usando la clave pública en el dispositivo y se envía al servidor. Aquí, incluso si el intruso se entera de la contraseña encriptada, no puede hacer nada con eso porque no puede descifrarla con esa clave pública y solo necesita la clave privada del servidor.
De todos modos, si uno quiere hacer uso del sistema AccountManager
del Android y mantener un alto nivel de seguridad, sería posible al no guardar ningún token en el dispositivo. El método getAuthToken
de AbstractAccountAuthenticator
puede ser reemplazado así:
@Override
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String
authTokenType, Bundle options) throws NetworkErrorException {
AuthenticatorManager authenticatorManager = AuthenticatorManager.authenticatorManager;
Bundle result;
AccountManager accountManager = AccountManager.get(context);
// case 1: access token is available
result = authenticatorManager.getAccessTokenFromCache(account, authTokenType,
accountManager);
if (result != null) {
return result;
}
final String refreshToken = accountManager.getPassword(account);
// case 2: access token is not available but refresh token is
if (refreshToken != null) {
result = authenticatorManager.makeResultBundle(account, refreshToken, null);
return result;
}
// case 3: neither tokens is available but the account exists
if (isAccountAvailable(account, accountManager)) {
result = authenticatorManager.makeResultBundle(account, null, null);
return result;
}
// case 4: account does not exist
return new Bundle();
}
En este método, ni el caso 1, el caso 2 ni el caso 4 son verdaderos porque no hay un token guardado, aunque la account
esté allí. Por lo tanto, solo se devolverá el caso 3, que luego se puede configurar en la devolución de llamada correspondiente para abrir una Activity
en la que el usuario ingresa el nombre de usuario y la contraseña para la autenticación.
No estoy seguro de estar en el camino correcto al describir esto aquí, pero las publicaciones de mi sitio web en AccountManager
pueden ayudar por si acaso.
Estoy enfrentando el mismo problema arquitectónico para una aplicación.
La solución que obtuve es asociar / hash el token oauth, con el token del proveedor de la aplicación (por ejemplo, el token que Facebook le da a una aplicación), y al id del dispositivo ( android_id
). Solo se autoriza la aplicación, ya que el dispositivo puede usar el token del administrador de la cuenta.
Por supuesto, es solo una nueva capa de seguridad, pero no a prueba de balas.
Tu observación es correcta Authenticator se ejecutará con el mismo UID que la aplicación de instalación. Cuando otra aplicación se conecte al administrador de cuentas y obtenga un token para este autenticador, se vinculará a su servicio de autenticador provisto. Se ejecutará como su UID, por lo que las cuentas nuevas estarán relacionadas con este Autenticador. Cuando la aplicación solicite getAuthToken, se producirá la vinculación y Authenticator seguirá ejecutándose en la misma UId. Los permisos incorporados predeterminados comprueban el UID de la cuenta, de modo que el Authenticator diferente no pueda acceder a otra cuenta desde el Authenticator diferente.
Puede resolver este problema con el uso de "Llamando a UID" para addAccount y GetAuthToken, ya que el servicio del administrador de cuentas lo agrega al paquete. La implementación de tu autenticador puede verificar eso.
@Override
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account,
String authTokenType, Bundle loginOptions) throws NetworkErrorException {
Log.v(
TAG,
"getAuthToken() for accountType:" + authTokenType + " package:"
+ mContext.getPackageName() + "running pid:" + Binder.getCallingPid()
+ " running uid:" + Binder.getCallingUid() + " caller uid:"
+ loginOptions.getInt(AccountManager.KEY_CALLER_UID));
...
}
Sugiero seguir el flujo de autorización en lugar de almacenar el secreto del cliente en su aplicación nativa, porque otros desarrolladores pueden extraer ese secreto. Tu aplicación no es una aplicación web y no debe tener secretos.
Cuando está agregando una cuenta, puede consultar también a la callingUId. Debe establecer UserData en su actividad relacionada addAccount que se ejecutará como el UID de su aplicación, para que pueda llamar a setUserData .
getUserData y setUserData utiliza una base de datos sqllite incorporada, por lo que no es necesario que construyas el caché tú solo. Solo puede almacenar el tipo de cadena, pero puede analizar json y almacenar información adicional por cuenta.
Cuando diferentes aplicaciones de terceros consultan cuentas y llaman a getAuthtoken con su cuenta, puede verificar el UID en los datos de usuario de la cuenta. Si el UID de llamada no está en la lista, puede hacer el aviso u otras cosas para obtener el permiso. Si está permitido, puede agregar un nuevo UID a la cuenta.
Compartir tokens entre aplicaciones : cada aplicación normalmente se registra con diferentes clientid y no deben compartir token. Token es para una aplicación de cliente.
Almacenamiento : AccountManager no está encriptando sus datos. Si necesita una solución más segura, debe encriptar los tokens y luego almacenarlos.