[Hack] Privatiser une instance de ghost

[Hack] Privatiser une instance de ghost

Juste un petit post pour montrer un petit hack permettant de protéger l'intégralité d'un blog Ghost par UserName & Password depuis le changement d'API de ghost-core. Cette méthode fonctionne avec Ghost version >= 0.6 executé sous NodeJS.

Un peu d'installation d'abord

Pour commencer créer un nouveau dossier contenant le projet, histoire d'être sûr. Pour les systèmes UNIX-like, ouvrir un terminal et go.

$ mkdir ghost+basic-auth
$ cd ghost+basic-auth

Facultatif : pour éviter des pertes éventuelles de dépendances, il est possible de créer un package.json avec $ npm init. Après cette commande, il convient d'ajouter ghost et basic-auth dans les "dependencies":{} de package.json. Ensuite il suffit juste de faire un petit $ npm install pour télécharger automatiquement toutes les dépendances nécessaires.


Ce petit hack à deux petits prérequis:

  • Utiliser ghost comme un module de NodeJS
  • Installer le module basic-auth par npm

Si vous n'êtes pas passés par un package.json, il suffit d'installer les deux dépendances manuellement.

$ npm install ghost
$ npm install basic-auth

Installé de cette manière, ghost n'est qu'un "simple" module de NodeJS.

Attention : le module basic-auth utilisé des méthodes simplistes pour l'identification qui ne présente qu'une sécurité relative :

  • Pas de chiffrement de mot de passe
  • Authentification considérée comme "en dur"

Une fois les dépendances installées, il reste à coder l'authentification.

Codons un peu

Nous allons commencer par créer un fichier mon_fichier_a_lancer.js avec le nom désiré. Ici, j'ai choisi arbitrairement de l'appeler app.js.

Dans ce fichier, nous allons bien sur écrire le code nécessaire au lancement de ghost, ce code peut être trouvé sur le site contenant la documentation de ghost.

app.js
var express,
	ghost,
	parentApp,
	errors;

// Make sure dependencies are installed and file system permissions are correct.
require('./core/server/utils/startup-check').check();

// Proceed with startup
express = require('express');
ghost = require('./core');
errors = require('./core/server/errors');
// Create our parent express app instance.
parentApp = express();


ghost().then(function (ghostServer) {
	// Mount our ghost instance on our desired subdirectory path if it exists.
	parentApp.use(ghostServer.config.paths.subdir, ghostServer.rootApp);

	// Let ghost handle starting our server instance.
	ghostServer.start(parentApp);
}).catch(function (err) {
	errors.logErrorAndExit(err, err.context, err.help);
});

Ceci est le code minimal nécessaire pour lancer une instance de ghost.

Nous allons lui rajouter l'authentification.

auth=require('basic-auth');

Juste en dessous des déclarations de variables globales. Ce qui nous fait un début de fichier de cette forme :

var express,
	ghost,
	parentApp,
	errors,
    auth;

require('./core/server/utils/startup-check').check();

// Proceed with startup
express = require('express');
ghost = require('./core');
errors = require('./core/server/errors');
auth=require('basic-auth');

Notre serveur commence à prendre forme. Nous allons maintenant ajouter la route express permettant de "hooké" l'authentification. Nous l'ajoutons directement à parentApp.

parentApp.use(function(req, res, next) {
	if(req.url.indexOf("ghost") == -1 && req.url.indexOf("shared") == -1){
	
        var user = auth(req);
        if (user === undefined || user['name'] !== 'username' || user['pass'] !== 'password') {
			res.statusCode = 401;
         	res.setHeader('WWW-Authenticate', 'Basic realm="Mon Super Blog"');
          	res.end('Unauthorized');
   		} else {
			next();
		}
	}else{
		next();
	}
});

Le hack réside dans le premier test. Il est impératif de filtrer les url de requêtes pour s'émanciper des nombreuses redirections effectuées par ghost. Pour éviter des interférences entre les authentifications globales et pour accèder à l'interface permettant de créer des posts, il est nécessaire d'ignorer les url qui contiennent ghost et shared pour atteindre l'authentification de l'admin et permettrent de charger les images dans celle-ci (d'où le shared).

Il n'y a rien besoin de plus. Après libre au développeur de créer un système plus complexe de gestion d'utilisateurs, au minimum une liste des utilisateurs autorisés etc. Il est aussi possible d'imaginer l'intégration dans des applications web plus complètes et plus complexes.

Conclusion

Voici comment ajouter une feature qui peut être interessante pour restreindre l'accès à tout ou partie d'un blog ghost.

Il convient de ne pas oublier qu'il s'agit ici d'un hack et qu'il faut rester prudent dans la mise en place de mécanismes de ce type qui, bien que stables, ne présentent pas un degré suffisament élevé de sécurité pour être directement utilisés en production.

Cheers!