Code-Repository
Bitbucket
Build new version
- Change version number in manifest.xml
Add changes in readme
Tag version – example:
git tag -a v0.3 -m 'v0.3' f4e1e90
git push origin v0.3 |
git tag -a v0.3 -m 'v0.3' f4e1e90
git push origin v0.3
The checksum of the commit is optional.
- Zip files without the git files – example:
cd ../
zip -r google2fa_v0.3.zip google2fa/config_default.php google2fa/js google2fa/languages google2fa/manifest.xml google2fa/php google2fa/readme google2fa/resources |
cd ../
zip -r google2fa_v0.3.zip google2fa/config_default.php google2fa/js google2fa/languages google2fa/manifest.xml google2fa/php google2fa/readme google2fa/resources
- Download the file and upload it to with WordPress Download Plugin.
Idea: Use the Zarafa build with js optimizing
Update from repository (f.e. after merging pull request)
Commit changes to the repository
git diff
git status
git add {file}
git commit -m "{comment}"
git push origin master
git log |
git diff
git status
git add {file}
git commit -m "{comment}"
git push origin master
git log
Create or update language files
Export texts from files
xgettext --no-wrap php/plugin.google2fa.php js/settings/SettingsGoogle2FAWidget.js js/settings/SettingsGoogle2FACategory.js -o languages/messages.pot |
xgettext --no-wrap php/plugin.google2fa.php js/settings/SettingsGoogle2FAWidget.js js/settings/SettingsGoogle2FACategory.js -o languages/messages.pot
Don’t forget to edit header (CHARSET -> UTF-8)
Take english texts from ids
msgen --no-wrap languages/messages.pot -o languages/en_US.UTF-8/LC_MESSAGES/plugin_google2fa.po |
msgen --no-wrap languages/messages.pot -o languages/en_US.UTF-8/LC_MESSAGES/plugin_google2fa.po
Merge german translation
msgmerge --no-wrap languages/de_DE.UTF-8/LC_MESSAGES/plugin_google2fa.po languages/messages.pot -o languages/de_DE.UTF-8/LC_MESSAGES/plugin_google2fa.po |
msgmerge --no-wrap languages/de_DE.UTF-8/LC_MESSAGES/plugin_google2fa.po languages/messages.pot -o languages/de_DE.UTF-8/LC_MESSAGES/plugin_google2fa.po
Search for fuzzy, correct translation, delete fuzzy
Merge french translation
msgmerge --no-wrap languages/fr_FR.UTF-8/LC_MESSAGES/plugin_google2fa.po languages/messages.pot -o languages/fr_FR.UTF-8/LC_MESSAGES/plugin_google2fa.po |
msgmerge --no-wrap languages/fr_FR.UTF-8/LC_MESSAGES/plugin_google2fa.po languages/messages.pot -o languages/fr_FR.UTF-8/LC_MESSAGES/plugin_google2fa.po
Search for fuzzy, correct translation, delete fuzzy
Create binaries
msgfmt languages/de_DE.UTF-8/LC_MESSAGES/plugin_google2fa.po -o languages/de_DE.UTF-8/LC_MESSAGES/plugin_google2fa.mo
msgfmt languages/en_US.UTF-8/LC_MESSAGES/plugin_google2fa.po -o languages/en_US.UTF-8/LC_MESSAGES/plugin_google2fa.mo
msgfmt languages/fr_FR.UTF-8/LC_MESSAGES/plugin_google2fa.po -o languages/fr_FR.UTF-8/LC_MESSAGES/plugin_google2fa.mo |
msgfmt languages/de_DE.UTF-8/LC_MESSAGES/plugin_google2fa.po -o languages/de_DE.UTF-8/LC_MESSAGES/plugin_google2fa.mo
msgfmt languages/en_US.UTF-8/LC_MESSAGES/plugin_google2fa.po -o languages/en_US.UTF-8/LC_MESSAGES/plugin_google2fa.mo
msgfmt languages/fr_FR.UTF-8/LC_MESSAGES/plugin_google2fa.po -o languages/fr_FR.UTF-8/LC_MESSAGES/plugin_google2fa.mo
Integration des Plugins in die WebApp
Integration in den Login-Prozess
Grundsätzlich ist das Plugin so entwickelt, dass es sich an die dokumentierten Standards der WebApp-Entwicklung hält – so zum Beispiel die Anwender-Konfiguration in den WebApp-Einstellungen inkl. Speicherung. Das Besondere an dem Plugin ist allerdings, dass es sich in den WebApp-Login-Mechanismus einhängen muss, um die 2-Faktor-Authentifizierung erreichen zu können.
Ziel bei der Entwicklung war es, hierbei den WebApp-Quellcode nicht zu verändern. Hierzu wird zum einen ein in der WebApp definierter Hook verwendet. Zum anderen wird bei Bedarf mit Hilfe einer zweiten Login-Seite der Token erfragt.
WebApp-Integration und Bedarfsprüfung Token-Abfrage
Verwendet wird der in der index.php definierte Hook “server.index.load.main.before”. Nach der Angabe von Benutzername und Passwort und deren Prüfung wird das Plugin für die Bedarfprüfung bzgl. einer Token-Prüfung aufgerufen. Der Logon-Hook kann nicht verwendet werden, da zu diesem Zeitpunkt die Settings noch nicht geladen wurden.
Die Hook-Registierung befindet sich in der Datei php/plugin.google2fa.php in der Methode init().
$this->registerHook('server.index.load.main.before');
In selbiger Datei in der Methode execute() findet dann die Bedarfsprüfung zur Eingabe eines Tokens statt.
case 'server.index.load.main.before' :
Hier ist der Ablauf wie folgt:
- Wenn laut Plugin-Konfiguration das Plugin immer “enabled” sein soll, dann wird das Plugin aktiviert.
if (PLUGIN_GOOGLE2FA_ALWAYS_ENABLED) {
$GLOBALS["settings"]->set('zarafa/v1/plugins/google2fa/enable', true);
$GLOBALS["settings"]->saveSettings();
}
- Wenn laut Plugin-Konfiguration die Zwei-Faktor-Authentifizierung “activated” sein soll, dann wird diese aktiviert.
if (PLUGIN_GOOGLE2FA_ALWAYS_ACTIVATED)
Google2FAData::setActivate(true);
- Wenn das Plugin nicht “enabled” oder die Zwei-Faktor-Authentifizierung nicht “activated” ist, dann wird aus der Methode gesprungen, um den normalen Login-Vorgang fortzusetzen. Eine Token-Abfrage findet nicht statt.
if (!$GLOBALS["settings"]->get('zarafa/v1/plugins/google2fa/enable')
|| !Google2FAData::isActivated())
break;
- Es wird geprüft, ob die IP-Adresse des Anwenders in der in der Plugin-Konfiguration definierten Whitelist steht. Ist dies der Fall, wird aus der Methode gesprungen, um ebenfalls den normalen Login-Vorgang fortzusetzen.
if (PLUGIN_GOOGLE2FA_WHITELIST !== "") {
foreach (explode (",", PLUGIN_GOOGLE2FA_WHITELIST) as $range) {
if (self::ip_in_range($_SERVER['REMOTE_ADDR'], $range))
break 2;
}
}
- Es wird geprüft, ob die Token-Authorisierung schon stattgefunden hat. Das ist der Fall, wenn der Token gerade abgefragt und erfolgreich geprüft wurde oder wenn die WebApp neu geladen wird. Im ersten Fall wird der verwendete Token gespeichert oder aus der Liste der zeitunabhängigen Codes gelöscht, damit er nicht erneut verwendet werden kann.
/normanth/google2fa/src/master/php/plugin.google2fa.phpif (array_key_exists('google2FALoggedOn', $_SESSION) && $_SESSION['google2FALoggedOn']) {
// Login successful - save or remove code
if (isset($_SESSION['google2FACode'])) {
if (isset($_SESSION['google2FACodeTimeless'])) {
Google2FAData::rmTimelessCode($_SESSION['google2FACode']);
unset($_SESSION['google2FACodeTimeless']);
} else {
Google2FAData::addUsedCode($_SESSION['google2FACode']);
}
unset($_SESSION['google2FACode']);
}
break;
} |
if (array_key_exists('google2FALoggedOn', $_SESSION) && $_SESSION['google2FALoggedOn']) {
// Login successful - save or remove code
if (isset($_SESSION['google2FACode'])) {
if (isset($_SESSION['google2FACodeTimeless'])) {
Google2FAData::rmTimelessCode($_SESSION['google2FACode']);
unset($_SESSION['google2FACodeTimeless']);
} else {
Google2FAData::addUsedCode($_SESSION['google2FACode']);
}
unset($_SESSION['google2FACode']);
}
break;
}
- Die Session wird gelöscht – also der Login rückgängig gemacht. Die für einen späteren Login und die Token-Abfrage benötigten Informationen werden in einer neuen Session gespeichert.
/normanth/google2fa/src/master/php/plugin.google2fa.php$encryptionStore = EncryptionStore::getInstance();
$username = $encryptionStore->get('username');
$password = $encryptionStore->get('password');
$encryptionStore->add('username', '');
$encryptionStore->add('password', '');
...
$_SESSION = array(); // clear session to logoff and don't loose session
$_SESSION['google2FAUsername'] = $username; // or from $_POST/$GLOBALS
$_SESSION['google2FAPassword'] = $password;
[...] |
$encryptionStore = EncryptionStore::getInstance();
$username = $encryptionStore->get('username');
$password = $encryptionStore->get('password');
$encryptionStore->add('username', '');
$encryptionStore->add('password', '');
...
$_SESSION = array(); // clear session to logoff and don't loose session
$_SESSION['google2FAUsername'] = $username; // or from $_POST/$GLOBALS
$_SESSION['google2FAPassword'] = $password;
[...]
- Zusätzlich müssen die beiden Fingerprints für Frontend und Backend zwischengespeichert werden.
$_SESSION['google2FAFingerprint'] = $_SESSION['fingerprint'];
$_SESSION['google2FAFrontendFingerprint'] = $_SESSION['frontend-fingerprint'];
- Eine Umleitung auf die zweite Login-Seite mit der Token-Abfrage php/login.php findet statt und die weitere Ausführung der index.php wird abgebrochen.
header('Location: plugins/google2fa/php/login.php', true, 303); // delete GLOBALS, go to token page
exit; // don't execute header-function in index.php
Token-Abfrage und -Prüfung
Da der WebApp-Quellcode der WebApp nicht verändert werden sollte, wurde eine zweite Login-Seite zur Token-Abfrage php/login.php auf Basis der Login-Seite entwickelt. Ab hier befindet wir uns außerhalb des offiziellen Plugin-Mechanismus.
Klickt der Anwender auf den Login-Button der zweiten Login-Seite, so findet die Token-Prüfung in der Datei php/logon.php statt.
form action="logon.php" method="post"
Bei einer erfolgreichen Token-Authentifizierung wird die Session mit den benötigten Anmeldeinformationen wiederhergestellt und die index.php der WebApp aufgerufen. Der Startprozess wird erneut durchlaufen. Da die Token-Authentifizierung erfolgt ist, ruft das Plugin diesmal nicht die zweite Login-Seite auf.
/normanth/google2fa/src/master/php/logon.php$_SESSION['username'] = $_SESSION['google2FAUsername'];
$_SESSION['password'] = $_SESSION['google2FAPassword'];
$_SESSION['google2FACode'] = $code; // to disable code
$_SESSION['google2FALoggedOn'] = TRUE; // 2FA successful
$_SESSION['fingerprint'] = $_SESSION['google2FAFingerprint'];
$_SESSION['frontend-fingerprint'] = $_SESSION['google2FAFrontendFingerprint'];
header('Location: ../../../index.php', true, 303); |
$_SESSION['username'] = $_SESSION['google2FAUsername'];
$_SESSION['password'] = $_SESSION['google2FAPassword'];
$_SESSION['google2FACode'] = $code; // to disable code
$_SESSION['google2FALoggedOn'] = TRUE; // 2FA successful
$_SESSION['fingerprint'] = $_SESSION['google2FAFingerprint'];
$_SESSION['frontend-fingerprint'] = $_SESSION['google2FAFrontendFingerprint'];
header('Location: ../../../index.php', true, 303);
Ist die Token-Authentifizierung nicht erfolgreich, wird die zweite Login-Seite zur Token-Abfrage erneut aufgerufen.
$_SESSION['google2FALoggedOn'] = FALSE; // login not successful
header('Location: login.php', true, 303);