PROJET AUTOBLOG


Sam & Max: Python, Django, Git et du cul

Site original : Sam & Max: Python, Django, Git et du cul

⇐ retour index

Mise à jour

Mise à jour de la base de données, veuillez patienter...

The User is dead 9

mardi 14 juillet 2015 à 14:27

L’authentification de mémé (enfin, mémé…) n’a plus de sens, et pourtant, on continue de la montrer en exemple dans tous les tutos :

Boom, on vérifie le mot de passe (avec un peu de chance sur une version sainement hachée), on identifie l’utilisateur, et c’est plié.

C’est simple, c’est beau, ça marche.

Mais ça ne représente pas du tout la réalité.

Une des plus grosses erreurs de design de frameworks comme Django est justement la classe User.

En soit, la classe User n’est pas un problème, mais son omniprésence dans toutes les couches du framework et sa promotion au rang d’unité de référence dans les apps tierces parties ont gardé la vision de l’authentification très monolithique.

C’est que le Web n’a plus du tout la forme qu’il avait il y a 10 ans, et aujourd’hui, vous pouvez vous connecter via un service (facebook, twitter, github…), utiliser une authentification à double facteur (sms, email, yubikey…) ou avoir un compte unique qui unifie plusieurs fournisseurs (ah, le fameux compte Google qui fait gmail, youtube, calendar, play, saucisseland…).

Les gens ont plusieurs identités, plusieurs comptes, plusieurs modes d’authentification, plusieurs points d’entrées. Ce modèle ne marche plus :

USER <-- Profile 

Si vous créez un service aujourd'hui et que vous souhaitez prendre en compte cette réalité, le schéma en base de données va plutôt ressembler à un truc du genre :

                      +-------+
                      |Session|
                      +----+--+
                           |
                           |
                           |
                           |
+-----------+         +----v---+         +--------+
|  Identity | <-------+ Account| <-------+Profile |
+-----------+         +--------+         +--------+
                 +------^   ^--------+
                 |                   |
                 |                   |
                 |                   |
                 |                   |
         +-------+-----+      +------+----+
         | Credential  |      |  Service  |
         +-------------+      +-----------+

Et encore, je n'ai pas mis les permissions, les devices, les comptes multi-utilisateurs, la vérification des comptes (lien email, sms, etc), les niveaux d'offre commerciale... Ca rend le truc vraiment compliqué.

Ce qui est important ici, c'est que la notion de compte devient centrale, mais que seule l'identité est unique. Une identité peut avoir plusieurs comptes. Et un compte peut être chez votre service ou un service externe. Et l'authentification peut très bien avoir lieu ailleurs : ldap, OAuth, Mozilla Personna, Open ID...

Si votre utilisateur a un compte chez Facebook et un compte chez vous, les deux sont des comptes, avec leurs profils, reliés à la même identité, servant à vous donner des informations, permettant de se loguer... Et vous devez garder une trace de tout ça. Le fait que l'API d'un service tape sur votre serveur et l'autre non n'a en fait aucune importance pour l'utilisateur, qui utilise tout ça comme un gros blob comme si internet était un tout.

La nouvelle génération ne fait pas la différence avec un site Web et un app, ne sait pas ce qu'est une URL ou un cookie et ne veut pas rentrer trop de mots de passe, mais veut par contre utiliser 5000 services.

Ainsi on voit que les archis basées sur des microservices (hello crossbar :)) commencent à avoir la côte, faisant abstraction de la notion de "ceci est mon app, ceci est ton app" dans la structure de son projet. Bien entendu, la distinction est importante d'un point de vue humain, mais du point de vue du workflow d'authentification, non.

Par contre, forcément, ça fait beaucoup plus qu'une table User et une table Profile en base de données, et c'est pourquoi toutes les apps pluggables des frameworks actuellement ont leurs propres structures bizarres, incompatibles et torturées pour faire tenir toute cette logique. Parce qu'on code sur des frameworks qui vivent encore dans les années 2000, qui passent à votre vue un objet User en paramètre avec ses attributs username et email.

Mais ce que vous avez en face de vous, ce n'est pas un utilisateur.

C'est une session d'utilisation.

D'un service (le votre). Liée à un compte. Qui peut-être (surement) possède un profil avec un username.

Cette session s'est initiée par une authentification avec une méthode parmi 100 auprès d'un service également, lié à un compte, avec un profil. Peut-être le même service que celui qui est utilisé, peut-être pas.

Et cette authentification a pu être demandée par un utilisateur, ou encore un autre service, ou un logiciel client complètement automatiquement. Souvenez-vous : la session n'a peut-être aucun humain derrière.

Ce qui est en face de vous n'est pas un utilisateur. L'utilisateur est mort il y a des années.

Réagir à un changement sur un fichier avec watchdog 14

lundi 13 juillet 2015 à 10:53

Il y a des tas de choses qu’on peut vouloir faire au moment où un fichier change :

Et ce n’est même pas dur à faire en Python grace à la lib watchdog :

pip install watchdog

D’abord, on créer un handler, une classe qui va contenir le code à lancer quand il arrive quelque chose à nos fichiers :

from watchdog.events import FileSystemEventHandler
 
class MonHandler(FileSystemEventHandler):
 
    # cette méthode sera appelée à chaque fois qu'un fichier
    # est modifié
    def on_modified(self, event):
        print("Ah, le fichier %s a été modifé" % event.src_path)
 
    # On peut aussi implémenter les méthodes suivantes :
    # - on_any_event(self, event)
    # - on_moved(self, event)
    # - on_created(self, event)
    # - on_deleted(self, event)
    # - on_modified(self, event)

Ensuite on créé un observer, qui va lancer un thread dans lequel il va… observer :

from watchdog.observers import Observer
 
observer = Observer()
# Surveiller récursivement tous les événements du dossier /tmp
# et appeler les méthodes de MonHandler quand quelque chose
# se produit
observer.schedule(MonHandler(), path='/tmp', recursive=True)

On démarre tout ça :

import time
observer.start()
 
# L'observer travaille dans un thread séparé donc on fait une 
# boucle infinie pour maintenir le thread principal
# actif dans cette démo mais dans un vrai programme,
# vous mettez votre taff ici.
try:
    while True:
        time.sleep(1)
except KeyboardInterrupt:
    # Ctrl + C arrête tout
    observer.stop()
# on attend que tous les threads se terminent proprement
observer.join()

Pour les ones shot, watchdog vient avec la commande watchmedo qui permet de lancer un commande shell en cas d’événement :

# lancer 'echo lefichier' pour chaque fichier python ou texte modifié de mon dossier utilisateur 
watchmedo shell-command --patterns="*.py;*.txt" --recursive --command='echo "${watch_src_path}"' /home/sam

Personnellement j’aime le lundi.


Télécharger le code de l’article

Today is a glorious day 15

dimanche 12 juillet 2015 à 23:29
>>> import crossbar
>>> crossbar.__version__
'0.10.4'
>>> import twisted
>>> twisted.__version__
'15.2.1'
>>> import sys
>>> print('Wait for it...')
Wait for it...
>>> sys.version
'3.4.0 (default, Apr 11 2014, 13:05:11) \n[GCC 4.8.2]'

Bougez avec la poste… 13

mercredi 8 juillet 2015 à 18:04

On a décidé de commander quelques trucs pour bidouiller un raspberry PI sur un site américain.

Grâce au Tracking chez UPS on peut savoir où se balade notre colis.
C’est assez cocasse…

Apparement le colis est arrivé dans notre ville mais a du repartir à Paris pour enfin revenir demain ou…

Heureusement que c’est pas un bon Maroilles bien vieux.

laposte

Tester Python 3.5 beta 14

mercredi 8 juillet 2015 à 08:55

Python 3.5 est en phase beta, et c’est une release très (mais alors très très très) attendue.

Si vous ne voulez pas attendre et tester le bouzin de suite, il est facile de setup la bestiole sous linux :

Un exemple possible :

cd /tmp
sudo apt-get install python-dev gcc # ou yum install python-devel gcc
wget https://www.python.org/ftp/python/3.5.0/Python-3.5.0b3.tgz
tar -xvf Python-3.5.0b3.tgz
cd Python-3.5.0b3
./configure
make
sudo make altinstall

Ne faites surtout PAS sudo make install, qui écraserait votre python principal.

Ensuite on lance :

$ python3.5
$ python3.5
Python 3.5.0b3 (default, Jul  5 2015, 23:52:07) 
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.
Traceback (most recent call last):
  File "/home/sam/Scripts/pythonstartup.py", line 119, in 
    store = Store(os.path.join(TEMP_DIR, 'store.%s.db') % python_version)
  File "/home/sam/Scripts/pythonstartup.py", line 93, in __init__
    object.__setattr__(self, 'DICT', shelve.DbfilenameShelf(filename))
  File "/usr/local/lib/python3.5/shelve.py", line 227, in __init__
    Shelf.__init__(self, dbm.open(filename, flag), protocol, writeback)
  File "/usr/local/lib/python3.5/dbm/__init__.py", line 91, in open
    "available".format(result))
dbm.error: db type is dbm.gnu, but the module is not available
&gt;&gt;&gt; import types
&gt;&gt;&gt; print(':)')
:)
&gt;&gt;&gt;

En dehors du vomi d’intro, tout marche chez moi.