JCERTIFLab / jcertif-backend-2013

JCertif Back End 2013
0 stars 4 forks source link

[Design] Documentation du mécanisme Authentification + Administration #114

Open martialsomda opened 11 years ago

martialsomda commented 11 years ago

Figer les mécanismes d'authentification Appli cliente/Backend?, User/Backend? et la gestion des sessions.

Il faut documenter ce mécanisme dans le wiki

roddet commented 11 years ago

Avant la documentation, il faudrait faire un petit POC : une page web avec un bouton connecter et une gestion du jeton pour 1 service. Une fois que ça marche, on documente :)

martialsomda commented 11 years ago

ok

martialsomda commented 11 years ago

Après un peu de lecture over the internet Voila ce que je propose de POCer Le protocole OAuth prévoit 4 roles dans son processus d'authentification

Resource Owner (propriétaire de la ressource protégée) : End User (administrateur back office/Participant/Speaker etc) Authorisation Server (Intermédiaire auprès du quel le propriétaire donne son accord de délégation de droit, il authentifie le propriétaire et l'application cliente) : Backend Protected Resource Server (C'est là où se trouvent les ressources protégées) : Backend Client (Application cliente demandant délégation de droit) : Jcertif Web App, Mobile App, BackOffice App

Oauth spécifie 2 type de clients qui peuvent dialioguer avec le serveur d'authorisation: En fonction, le serveur d'authorisation adapte le niveau de sécurité

confidential : Client s'éxécutantant dans un environnement maîtrisé (Serveur dédié dont le niveau de sécurité est maîtrisé)

public : Tout type de client s'éxécutat dans un environement non maitrisé (navigateur, client loud etc.) c'est client sont plus vulnérables en terme de sécu

Si l'application possède les 2 aspects enregistrer les 2 parties au près du serveur

Il faut développer coté backend un mécanisme d'enregistrement d'appli cliente (client_id, client_secret, authorized_domain) Il faut rajouter au model d'utilisateurs d'appliation un attribut admin qui spécifiera que l'utilisateur a le droit d'accéder aux fonctions d'aministration

Authentificatiion flow :

state = HASH(session_coockie) Login BackOffice App => 302 redirect GET https://jcertif.backend.com/authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fjcertif%2Ebackoffice%2Ecom%2Finfo%2Fuser

                            the redirect-uri as to be part of authorized domains for the client_id
                            user-agent  <= Auth HTML Form user/pwd
                            user-agent  => Return form
                            Authenticate  user
                            Générate code and store generation datetime

          <= 302 redirect GET https://jcertif.backoffice.com/info/user?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz

check state param if not equal previous one then stop else extract code and request for token

          => POST https://jcertif.backend.com/token
                            body : {
                                      "response_type":"token",
                                      "client_id":"s6BhdRkqt3",
                                      "client_secret":"7Fjfp0ZBr1KtDRbnfVdmIw"
                                      "state":"xyz",
                                      "grant_type":"authorization_code",
                                      "code":"SplxlOBeZQQYbYS6WxSbIA"
                                   }
                            check if elapsed time <= 10min
                            generate access token + refresh token + scope based on user profile and store them

          <= {
               "access_token":"2YotnFZFEjr1zCsicMWpAA",
               "token_type":"bearer",
               "expires_in":3600,
               "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
               "scopes": ["user", "admin" ]
             }

access user information to show home => https://jcertif.backend.com/participant/get/:emailParticipant?access_token=2YotnFZFEjr1zCsicMWpAA&client_id=s6BhdRkqt3

          <= {
               "firstname":"Martial",
               "lastname":"SOMDA",
               "title":"M.",
               "sessions": [ "01", "02"]
             }

Do another API call => https://jcertif.backend.com/participant/update?access_token=2YotnFZFEjr1zCsicMWpAA&client_id=s6BhdRkqt3

          <= {
               "error":"access_token"
             }   

          => POST https://jcertif.backend.com/token
                            body : {
                                      "response_type":"token",
                                      "client_id":"s6BhdRkqt3",
                                      "client_secret":"7Fjfp0ZBr1KtDRbnfVdmIw"
                                      "state":"xyz",
                                      "grant_type":"refresh_token",
                                      "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA"
                                   }       

                            check if elapsed time <= 10min
                            generate access token + refresh token + scope based on user profile and store them   
          <= {
               "access_token":"3455SeeZFEjr1zCsicMWpAA",
               "token_type":"bearer",
               "expires_in":3600,
               "refresh_token":"aG455DdkF0XG5Qx234dKWIA",
               "scopes": ["user", "admin" ]
             }

Voili voilou...pour l’implémentation coté serveur je compte utiliser Spring Security for OAuth

martialsomda commented 11 years ago

Dis moi...a t-on la main sur les serveurs BackOffice/Backend pour mettre en place du SSL? par ce que la sécurité sous OAuth v2 repose beaucoup sur une sécurité au niveau transport..beaucoup de mot de passe sont véhiculés en pseudo claire..après on peux jouer sur la configuration de révocation automatique des tokens d'accès pour mitiger le risque mais bon...sinon dans un seconde phase (après la finalisation de la solution OAuth v2) je vais peut-être rétrograder à OAuth v1..:-)...je vais pas retrouver de ci tôt mes belles nuits de sommeil si ça continu comme ça :-)

roddet commented 11 years ago

En théorie, l'utilisateur ne saisira son mot de passe que sur le site partenaire. Le backend ne recevrait pas dans ce cas les mots de passe en clair. Pour répondre à ta question, on a la main sur la partie backend on peut mettre du SSL si besoin, côté front, l'idéal serait de l'héberger en tant que Github Pages comme il ne s'agira que de fichiers statiques. Et là, il me semble que le SSL n'est pas supporté, je vais vérifier.

Je suis un peu surpris que nous allions du côté de Spring Sécurity. As-tu regarder du côté de "SecureSocial" (http://securesocial.ws/) ? Il me semble qu'il serait plus adapté, qu'en penses-tu ?

Concernant tes nuits, bienvenu dans l'emprise de la communauté. Tu partages un doigt et la communauté prend tout le bras puis tout le corps :) Et ce n'est pas fini, le temps de l'intégration approche à grand pas, je travaille en ce moment sur le chantier web et j'arrive, j'arrive :)

martialsomda commented 11 years ago

Huuum...moi j'ai modéliser dans ma tête le problème dans l'autre sens. Pour moi le Backend contient les informations sensibles d'un utilisateur, du coup c'est les appli partenaire qui demande une délégation de droits pour accéder à ces infos sur le backend.

La cinématique est la suivante :

1) Les appli clientes s'enregistrent au près du backend.elles se voient remettre par le backend un clientId et un clientSecret. 2) Lors de la connexion d'un utilisateur, l'appli cliente redirige l'utilisateur vers une page de login du backend en s'identifiant elle même avec son couple clientId/clientSecret (encodé en base64 et véhiculé dans le header HTTP). 3) le client s'authentifie au près du backend puis est redirigé vers l'appli client par le backend.Au passage le backend transmet à l'appli cliente un code temporaire vallable 10min. 4) L'appli cliente recontacte le backend pour échanger ce code contre un token de validité 1h. la backend stocke le fait que ce jeton a été généré pour ce client et cet utilisateur. 5) L'appli client peut invoquer tous les services qu'elle veut au nom de l'utilisateur en présentant ce jeton. 6) le jeton est automatiquement révoqué au bout de d'une 1h et l'appli client doit redemander un jeton

Oui j'avais regardé du coté de securesocial et play authenticate (http://joscha.github.io/play-authenticate/). Ces 2 plugins propose de s'interfacer directement avec les grand du web implémentant OAuth (Google, Facebook etc..) ou de mettre en place son propre provider OAuth sous la forme d'une authentification username/password de l'utilisateur final. Ce qui me dérangeait en soit c'était que la partie authentification de l'appli client est absente. Hors je veux pouvoir définir un certains nombre d'appli authorisées utiliser les services, en pouvant même réduire les périmètres d'utilisation de chaque appli (scope).

Voila pourquoi je suis parti sur un truc un peu plus à la mano en utilisant spring security pour oauth. Après il est possible que j'ai loupé un truc en faisant mon analyse..je vais regarder d'un peu plus près et je te fais un retour sur securesocial

martialsomda commented 11 years ago

mdr, concernant la communauté j'ai l'impression d'avoir fait fuir les certains...ça codait tranquil avant que je n'arrive puis j'ai mis mon grain de sel et j'ai l'impression qu'ils se sont tous barrés...moi je serait jcertif je stopperai tout de suite la collaboration avec les éléments perturbateurs comme moi :-)

roddet commented 11 years ago

Je comprends ton point et la sélection que tu veux faire pour faire un mapping client <> services authorisés. Cela te conduit à construire un serveur OAuth côté Backend. On peut effectivement le faire pour le fun et comme tu aimes la difficultés, pourquoi pas :) Par contre, la fonctionnalité que nous recherchons ici, au delà du plaisir technique, est de simplifier la connexion d'un utilisateur. Que le participant qui s'inscrit à l'événement n'ai pas besoin de stocker un user/password côté JCertif mais qu'il utilise son compte Google, Twitter, Github ou Facebook. Cela nous évite de stocker une information sensible comme le mot de passe par exemple. Effectivement nous n'avons pas compris la même chose :(

Ok je te laisse poursuivre l'analyse pour déterminer quelle est la solution la mieux adaptée.

En ce qui concerne la "fuite", ne t'inquiètes pas, c'est cyclique dans les projets comme celui là. Il y a souvent une rotation des personnes suivant les disponibilités. Africa Android Challenge ne nous a pas non plus aidé, quelques uns de nos contributeurs y participent activement en ce moment, donc moins de dispos pour le projet. Je pense que lorsque nous aurons les premiers travaux du site web cela recréera la dynamique qui te manque :) Donc très très bientôt et ce que tu fais sur l'authentification est CAPITAL !

JCertif Lab ne vit que de commits ! Donc les éléments perturbateurs comme toi sont les meilleurs amis de JCertif Lab et on raffole des amis comme toi :)

martialsomda commented 11 years ago

:-) ça marche..Effectivement je n'avais pas compris que le besoin était de permettre à l'utilisateur final ne s'authentifier via son compte facebook twitter ou autre...Pour ce besoin effectivement je préférerai m'orienter sur securesocial.

Je vois alors 2 cas de figures possibles : 1) Les appli clientes gèrent elle même l'authentification de leurs membres via Google facebook etc..(intégration de modules comme securesocial dans les appli clientes). elles gèrent aussi la session de ces membres à l'aide d'un coockie signé. Elles invoquent les services du backend en s'authentifiant elles aussi avec user/mdp. chaque appli a un profile sotcké coté backend, le couple user/mdp de l'appli permettra de savoir si l'appli a accès aux fonctions admin. pas de cookie coté backend, à chaque appel l'appli s'authentifie

2) Les appli clientes affichent l'écrant de login avec choix du provider. une fois le provider choisi, le backend est sollicité en tant qu'intermédiaire. il va rediriger l'utilisateur vers l'url du provider, stoker le couple jeton/user d'authentification coté bakend avant de le transmettre à l'appli.Tous les appels au backend devront avoir ce jeton d'authentification pour être considérés comme authentifiés. Les fonction admin seront disponibles pour les utilisateurs de type admin

roddet commented 11 years ago

1) Cette option ne me séduit pas parce qu'on se retrouve à envoyer un mot de passe à chaque requête.

2) C'est une solution qui a son charme, j'ai failli être séduit :) La seule chose qui me dérange c'est de placer le backend en tant qu'intermédiaire. Vu que les authentifications se font du côté du site partenaire (Google, Facebook, etc...), cela nécessite de faire une redirection de l'utilisateur au sens navigateur et donc le backend doit héberger la page d'authentification. Et c'est sur ce point que nous aurons quelques soucis :) En effet, on ne pourra pas par exemple se permettre de rediriger l'utilisateur de l'application Android sur notre page. Si nous avons une application cliente avec 2 look and feel différents, le fait de rediriger vers le backend va briser la chaine de l'élégance :)

Je te propose l'option 3)

3) Les applications clientes se "débrouillent" pour authentifier les utilisateurs de Google, Facebook etc... et récupèrent le jetton provenant de ces sites. A chaque appel au backend ce jeton est transmis ainsi que sa provenance (Google, Twitter, etc...). Le backend en recevant ce jeton vérifie s'il l'a en cache (données en cache avec une durée limitée), s'il ne l'a pas il intérroge le site partenaire pour savoir si le jeton est toujours valide, si c'est le cas, il met à jour le cache. Cela permettra de ne pas avoir d'IHM côté Backend. Pour distinguer s'il sagit d'un compte admin ou pas, on pourra juste alimenter une liste d'email dans le fichier de configuration ou en base, peu importe.

Je n'y avais pas pensé avant, mais il faudra aussi gérer le cas où l'utilisateur ne veut pas utiliser un compte partenaire. Dans ce cas, l'utilisateur saisie 1 fois 1 user/mdp et on lui transmet pareil un jeton qu'il va utiliser à chaque requête.

Qu'en penses-tu ?

martialsomda commented 11 years ago

OK ça marche pour l'option 3), en fait dans l'option 2) le backend n'avait pas besoin d'avoir un page d'authentification, le but c'était que l'utilisateur soit redirigé sur le site partenaire (Google, Facebook etc..) en passant par le backend (seule application enregistrée au près des différents providers) afin que une fois authentifié, le jeton soit transmit au backend dans un premier tps qui pourrait le garder en cache avant de le retourner à l'appli cliente.

Dans l'option 3) toutes les appli doivent s'enregistrer indépendamment au près des différents providers et en plus de stoker le jeton il faut que le backend stocke le client_id/client_secret de chaque appli cliente afin de pouvoir contacter le site partenaire dans le cas où le jeton ne serait pas en cache.