Merge pull-request: Github authentication #162

This commit is contained in:
Frédéric Guillot
2014-06-30 21:52:02 -03:00
parent f70ac7d65f
commit 06d0b7048e
23 changed files with 488 additions and 57 deletions

View File

@@ -20,6 +20,7 @@ use Model\LastLogin;
* @property \Model\Config $config
* @property \Model\File $file
* @property \Model\Google $google
* @property \Model\GitHub $gitHub
* @property \Model\LastLogin $lastLogin
* @property \Model\Ldap $ldap
* @property \Model\Project $project

View File

@@ -299,4 +299,68 @@ class User extends Base
$this->response->redirect('?controller=user');
}
/**
* GitHub authentication
*
* @access public
*/
public function gitHub()
{
$code = $this->request->getStringParam('code');
if ($code) {
$profile = $this->gitHub->getGitHubProfile($code);
if (is_array($profile)) {
// If the user is already logged, link the account otherwise authenticate
if ($this->acl->isLogged()) {
if ($this->gitHub->updateUser($this->acl->getUserId(), $profile)) {
$this->session->flash(t('Your GitHub account was successfully linked to your profile.'));
}
else {
$this->session->flashError(t('Unable to link your GitHub Account.'));
}
$this->response->redirect('?controller=user');
}
else if ($this->gitHub->authenticate($profile['id'])) {
$this->response->redirect('?controller=app');
}
else {
$this->response->html($this->template->layout('user_login', array(
'errors' => array('login' => t('GitHub authentication failed')),
'values' => array(),
'no_layout' => true,
'title' => t('Login')
)));
}
}
}
$this->response->redirect($this->gitHub->getAuthorizationUrl());
}
/**
* Unlink a GitHub account
*
* @access public
*/
public function unlinkGitHub()
{
$this->checkCSRFParam();
$this->gitHub->revokeGitHubAccess();
if ($this->gitHub->unlink($this->acl->getUserId())) {
$this->session->flash(t('Your GitHub account is no longer linked to your profile.'));
}
else {
$this->session->flashError(t('Unable to unlink your GitHub Account.'));
}
$this->response->redirect('?controller=user');
}
}

View File

@@ -5,9 +5,9 @@ return array(
'German' => 'Deutsch',
'French' => 'Französisch',
'Polish' => 'Polnisch',
'Portuguese (Brazilian)' => 'Portugisisch (Brasilien)',
'Portuguese (Brazilian)' => 'Portugiesisch (Brasilien)',
'Spanish' => 'Spanisch',
'Chinese (Simplified)' => 'Chinesisch',
'Chinese (Simplified)' => 'Chinesisch (vereinfacht)',
'None' => 'Kein',
'edit' => 'bearbeiten',
'Edit' => 'Bearbeiten',
@@ -27,16 +27,16 @@ return array(
'Grey' => 'Grau',
'Save' => 'Speichern',
'Login' => 'Anmelden',
'Official website:' => 'Offizielle Website :',
'Official website:' => 'Offizielle Website:',
'Unassigned' => 'Nicht zugeordnet',
'View this task' => 'Aufgabe ansehen',
'Remove user' => 'Benutzer löschen',
'Do you really want to remove this user: "%s"?' => 'Willst Du diesen Benutzer wirklich löschen : « %s » ?',
'Do you really want to remove this user: "%s"?' => 'Willst Du diesen Benutzer wirklich löschen: «%s»?',
'New user' => 'Neuer Benutzer',
'All users' => 'Alle Benutzer',
'Username' => 'Benutzername',
'Password' => 'Passwort',
'Default Project' => 'Standard Projekt',
'Default Project' => 'Standardprojekt',
'Administrator' => 'Administrator',
'Sign in' => 'Anmelden',
'Users' => 'Benutzer',
@@ -70,37 +70,37 @@ return array(
'Disable' => 'Deaktivieren',
'Enable' => 'Aktivieren',
'New project' => 'Neues Projekt',
'Do you really want to remove this project: "%s"?' => 'Möchtest Du dieses Projekt wirklich löschen : « %s » ?',
'Do you really want to remove this project: "%s"?' => 'Möchtest Du dieses Projekt wirklich löschen: «%s»?',
'Remove project' => 'Projekt löschen',
'Boards' => 'Tafel',
'Edit the board for "%s"' => 'Modifier le tableau pour « %s »',
'Edit the board for "%s"' => 'Tafel für «%s» bearbeiten',
'All projects' => 'Alle Projekte',
'Change columns' => 'Spalten ändern',
'Add a new column' => 'Neue Spalte hinzufügen',
'Title' => 'Titel',
'Add Column' => 'Neue Spalte',
'Project "%s"' => 'Projekt « %s »',
'Project "%s"' => 'Projekt «%s»',
'Nobody assigned' => 'Kein Zuständiger zugeordnet',
'Assigned to %s' => 'Zuständiger: %s',
'Remove a column' => 'Spalte löschen',
'Remove a column from a board' => 'Eine Spalte von einer Tafel löschen',
'Unable to remove this column.' => 'Löschen dieser Spalte nicht möglich.',
'Do you really want to remove this column: "%s"?' => 'Willst Du diese Spalte wirklich löschen : « %s » ?',
'This action will REMOVE ALL TASKS associated to this column!' => 'Diese Aktion wird ALLE AUFGABEN löschen !',
'Do you really want to remove this column: "%s"?' => 'Willst Du diese Spalte wirklich löschen: «%s»?',
'This action will REMOVE ALL TASKS associated to this column!' => 'Diese Aktion wird ALLE AUFGABEN löschen!',
'Settings' => 'Einstellungen',
'Application settings' => 'Applikationseinstellungen',
'Language' => 'Sprache',
'Webhooks token:' => 'Webhooks token:',
'More information' => 'Mehr Informationen',
'Database size:' => 'Datenbank Größe :',
'Database size:' => 'Datenbankgröße:',
'Download the database' => 'Download der Datenbank',
'Optimize the database' => 'Optimieren der Datenbank',
'(VACUUM command)' => '(VACUUM command)',
'(Gzip compressed Sqlite file)' => '(Gzip komprimierte sqlite Datei)',
'User settings' => 'Benutzer Eintellungen',
'My default project:' => 'Mein Standard Projekt : ',
'User settings' => 'Benutzereinstellungen',
'My default project:' => 'Mein Standardprojekt:',
'Close a task' => 'Aufgabe schließen',
'Do you really want to close this task: "%s"?' => 'Willst Du diese Aufgabe wirklich schließen : « %s » ?',
'Do you really want to close this task: "%s"?' => 'Willst Du diese Aufgabe wirklich schließen: «%s»?',
'Edit a task' => 'Aufgabe bearbeiten',
'Column' => 'Spalte',
'Color' => 'Farbe',
@@ -108,18 +108,18 @@ return array(
'Create another task' => 'Neue Aufgabe erstellen',
'New task' => 'Neue Aufgabe',
'Open a task' => 'Öffne eine Aufgabe',
'Do you really want to open this task: "%s"?' => 'Willst Du diese Aufgabe wirklich öffnen : « %s » ?',
'Do you really want to open this task: "%s"?' => 'Willst Du diese Aufgabe wirklich öffnen: «%s»?',
'Back to the board' => 'Zurück zur Tafel',
'Created on %B %e, %G at %k:%M %p' => 'Erstellt am %d.%m.%Y um %H:%M',
'There is nobody assigned' => 'Ein gibt keinen Zuständigen',
'Column on the board:' => 'Spalten auf diesem Tafel : ',
'Column on the board:' => 'Spalten auf diesem Tafel:',
'Status is open' => 'Status ist geöffnet',
'Status is closed' => 'Status ist geschlossen',
'close this task' => 'Aufgabe schließen',
'open this task' => 'Aufgabe öffnen',
'There is no description.' => 'Es gibt keine Erklärung.',
'There is no description.' => 'Es gibt keine Beschreibung.',
'Add a new task' => 'Eine neue Aufgabe hinzufügen',
'The username is required' => 'Der Butzutzername wird benötigt',
'The username is required' => 'Der Benutzername wird benötigt',
'The maximum length is %d characters' => 'Die maximale Länge sind %d Zeichen',
'The minimum length is %d characters' => 'Die minimale Länge sind %d Zeichen',
'The password is required' => 'Das Passwort wird benötigt',
@@ -133,12 +133,12 @@ return array(
'The project is required' => 'Das Projekt wird benötigt',
'The color is required' => 'Die Farbe wird benötigt',
'The id is required' => 'Die ID wird benötigt',
'The project id is required' => 'Die Projekt ID wird benötogt',
'The project name is required' => 'Der Projekt Name wird benötigt',
'This project must be unique' => 'Der Projekt Name muss eindeutig sein',
'The project id is required' => 'Die Projekt ID wird benötigt',
'The project name is required' => 'Der Projektname wird benötigt',
'This project must be unique' => 'Der Projektname muss eindeutig sein',
'The title is required' => 'Der Titel wird benötigt',
'The language is required' => 'Die Sprache wird benötigt',
'There is no active project, the first step is to create a new project.' => 'Es gibt kein aktives Projekt. Der erste Schritt ist ein Projekt erstellen.',
'There is no active project, the first step is to create a new project.' => 'Es gibt kein aktives Projekt. Der erste Schritt ist ein Projekt zu erstellen.',
'Settings saved successfully.' => 'Die Einstellungen wurden erfolgreich gespeichert.',
'Unable to save your settings.' => 'Speicher der Einstellungen nicht möglich.',
'Database optimization done.' => 'Optimieren der Datenbank abgeschlossen.',
@@ -148,7 +148,7 @@ return array(
'Unable to update this project.' => 'Ändern des Projekts nicht möglich.',
'Unable to remove this project.' => 'Löschen des Projekts nicht möglich.',
'Project removed successfully.' => 'Löschen des Projekts erfolgreich.',
'Project activated successfully.' => 'Aktivieren des Projekts erolgreich.',
'Project activated successfully.' => 'Aktivieren des Projekts erfolgreich.',
'Unable to activate this project.' => 'Aktivieren des Projekts nicht möglich.',
'Project disabled successfully.' => 'Deaktivieren des Projekts erfolgreich.',
'Unable to disable this project.' => 'Deaktivieren des Projekts nicht möglich.',
@@ -171,24 +171,24 @@ return array(
'Backlog' => 'Ideen',
'Work in progress' => 'In Arbeit',
'Done' => 'Erledigt',
'Application version:' => 'Programmversion :',
'Completed on %B %e, %G at %k:%M %p' => 'Erledigt am %d.%m.%Y à %H:%M',
'Application version:' => 'Programmversion:',
'Completed on %B %e, %G at %k:%M %p' => 'Erledigt am %d.%m.%Y um %H:%M',
'%B %e, %G at %k:%M %p' => '%d.%m.%Y um %H:%M',
'Date created' => 'Erstellung am',
'Date created' => 'Erstellt am',
'Date completed' => 'Erledigt am',
'Id' => 'ID',
'No task' => 'Keine Aufgabe',
'Completed tasks' => 'Erledigte Aufgaben',
'List of projects' => 'Liste der Projekte',
'Completed tasks for "%s"' => 'Erledigte Aufaben für « %s »',
'%d closed tasks' => '%d erledigte Augaben',
'Completed tasks for "%s"' => 'Erledigte Aufgaben für «%s»',
'%d closed tasks' => '%d erledigte Aufgaben',
'no task for this project' => 'Keine Aufgaben in diesem Projekt',
'Public link' => 'Öffentlicher Link',
'There is no column in your project!' => 'Es gibt keine Spalte in Deinem Projekt!',
'There is no column in your project!' => 'Es gibt keine Spalte in deinem Projekt!',
'Change assignee' => 'Zuständigkeit ändern',
'Change assignee for the task "%s"' => 'Zuständigkeit für diese Aufgabe ändern: « %s »',
'Change assignee for the task "%s"' => 'Zuständigkeit für diese Aufgabe ändern: «%s»',
'Timezone' => 'Zeitzone',
'Sorry, I didn\'t found this information in my database!' => 'Diese Information wurde in der Datenbank nicht gefunden !',
'Sorry, I didn\'t found this information in my database!' => 'Diese Information wurde in der Datenbank nicht gefunden!',
'Page not found' => 'Seite nicht gefunden',
'Story Points' => 'Umfang',
'limit' => 'Limit',
@@ -197,17 +197,17 @@ return array(
'Edit project access list' => 'Projekt Zugangsberechtigungen bearbeiten',
'Edit users access' => 'Benutzerzugang bearbeiten',
'Allow this user' => 'Diesen Benutzer authorisieren',
'Project access list for "%s"' => 'Projekt Zugangsliste für « %s »',
'Only those users have access to this project:' => 'Nur diese Benutzer haben Zugang zum Projekt :',
'Project access list for "%s"' => 'Projekt Zugangsliste für «%s»',
'Only those users have access to this project:' => 'Nur diese Benutzer haben Zugang zum Projekt:',
'Don\'t forget that administrators have access to everything.' => 'Vergiss nicht, dass Administratoren überall Zugang haben.',
'revoke' => 'verbieten',
'List of authorized users' => 'Liste der authorisieren Benutzer',
'List of authorized users' => 'Liste der authorisierten Benutzer',
'User' => 'Benutzer',
'Everybody have access to this project.' => 'Jedem hat Zugang zu diesem Projekt.',
'Everybody have access to this project.' => 'Jeder hat Zugang zu diesem Projekt.',
'You are not allowed to access to this project.' => 'Du hast keinen Zugang zu diesem Projekt.',
'Comments' => 'Kommentare',
'Post comment' => 'kommentieren',
'Write your text in Markdown' => 'Schreibe Deinen Text in Markdown',
'Write your text in Markdown' => 'Schreibe deinen Text in Markdown',
'Leave a comment' => 'Kommentar abgeben',
'Comment is required' => 'Ein Kommentar wird benötigt',
'Leave a description' => 'Beschreibung',
@@ -226,8 +226,8 @@ return array(
'Unable to create your automatic action.' => 'Deine automatische Aktion konnte nicht erstellt werden.',
'Remove an action' => 'Aktion löschen',
'Unable to remove this action.' => 'Aktion konnte nicht gelöscht werden',
'Action removed successfully.' => 'Action wurde erfolgreich gelöscht.',
'Automatic actions for the project "%s"' => 'Automatische Aktionen für dieses Projekt « %s »',
'Action removed successfully.' => 'Aktion wurde erfolgreich gelöscht.',
'Automatic actions for the project "%s"' => 'Automatische Aktionen für das Projekt «%s»',
'Defined actions' => 'Definierte Aktionen',
'Add an action' => 'Aktion hinzufügen',
'Event name' => 'Ereignis',
@@ -235,15 +235,15 @@ return array(
'Action parameters' => 'Aktionsparameter',
'Action' => 'Aktion',
'Event' => 'Ereignis',
'When the selected event occurs execute the corresponding action.' => 'Wenn des gewählte Ereignis eintritt, führe die passende Aktion aus.',
'When the selected event occurs execute the corresponding action.' => 'Wenn des gewählte Ereignis eintritt, führe die zugehörige Aktion aus.',
'Next step' => 'Nächster Schritt',
'Define action parameters' => 'Aktionsparameter definieren',
'Save this action' => 'Aktion speichern',
'Do you really want to remove this action: "%s"?' => 'Willst Du diese Aktion wirklich löschen « %s » ?',
'Do you really want to remove this action: "%s"?' => 'Willst Du diese Aktion wirklich löschen «%s»?',
'Remove an automatic action' => 'Löschen einer automatischen Aktion',
'Close the task' => 'Aufgabe schießen',
'Close the task' => 'Aufgabe schließen',
'Assign the task to a specific user' => 'Aufgabe einem Benutzer zuordnen',
'Assign the task to the person who does the action' => 'Aufgabe dem Benutzer zuordnen der die Aktion aufgeführt hat',
'Assign the task to the person who does the action' => 'Aufgabe dem Benutzer zuordnen der die Aktion ausgeführt hat',
'Duplicate the task to another project' => 'Aufgabe in ein anderes Projekt kopieren',
'Move a task to another column' => 'Aufgabe in eine andere Spalte verschieben',
'Move a task to another position in the same column' => 'Aufgabe an eine andere Position in der gleichen Spalte verschieben',
@@ -268,7 +268,7 @@ return array(
'Do you really want to remove this comment?' => 'Willst Du diesen Kommentar wirklich löschen?',
'Only administrators or the creator of the comment can access to this page.' => 'Nur Administratoren und der Ersteller des Kommentars könne diese Seite verwenden.',
'Details' => 'Details',
'Current password for the user "%s"' => 'Aktuelles Passwort für den Benutzer « %s »',
'Current password for the user "%s"' => 'Aktuelles Passwort für den Benutzer «%s»',
'The current password is required' => 'Das aktuelle Passwort wird benötigt',
'Wrong password' => 'Falsches Passwort',
'Reset all tokens' => 'Alle Tokens zurücksetzten',
@@ -278,8 +278,8 @@ return array(
'Login date' => 'Anmeldedatum',
'Authentication method' => 'Anmeldemethode',
'IP address' => 'IP Adresse',
'User agent' => 'Benutzer Agent',
'Persistent connections' => 'Bestende Verbindungen',
'User agent' => 'User Agent',
'Persistent connections' => 'Bestehende Verbindungen',
'No session' => 'Keine Session',
'Expiration date' => 'Ablaufdatum',
'Remember Me' => 'Angemeldet bleiben',
@@ -291,23 +291,31 @@ return array(
'Closed' => 'Geschlossen',
'Search' => 'Suchen',
'Nothing found.' => 'Nichts gefunden.',
'Search in the project "%s"' => 'Suche im Projekt « %s »',
'Search in the project "%s"' => 'Suche im Projekt «%s»',
'Due date' => 'Fälligkeitsdatum',
'Others formats accepted: %s and %s' => 'Andere akzepierte Formate : %s und %s',
'Description' => 'Beschreibung',
'%d comments' => '%d Kommentare',
'%d comment' => '%d Kommentar',
'Email address invalid' => 'EMail Adresse ungültig',
'Your Google Account is not linked anymore to your profile.' => 'Dein Google Accout ist nicht mit den Profil verbunden.',
'Unable to unlink your Google Account.' => 'Trennung der Verbindung mit dem Google Accout nicht möglich.',
'Your Google Account is not linked anymore to your profile.' => 'Dein Google Account ist nicht mehr mit deinem Profil verbunden.',
'Unable to unlink your Google Account.' => 'Trennung der Verbindung mit deinem Google Account nicht möglich.',
'Google authentication failed' => 'Zugang mit Google nicht möglich',
'Unable to link your Google Account.' => 'Verbindung mit dem Google Accout nicht möglich.',
'Your Google Account is linked to your profile successfully.' => 'Der Google Account wurde erfolgreich verbunden.',
'Unable to link your Google Account.' => 'Verbindung mit deinem Google Account nicht möglich.',
'Your Google Account is linked to your profile successfully.' => 'Dein Google Account wurde erfolgreich verbunden.',
'Email' => 'Email',
'Link my Google Account' => 'Verbinde meinen Google Account',
'Unlink my Google Account' => 'Verbindung mit meinem Google Account trennen',
'Login with my Google Account' => 'Anmelden mit meinem Google Account',
'Project not found.' => 'Das Projekt wurde nicht gefunden.',
'Your GitHub account was successfully linked to your profile.' => 'Dein GitHub Account wurde erfolgreich mit deinem Profil verbunden.',
'Unable to link your GitHub Account.' => 'Verbindung mit deinem GitHub Account nicht möglich.',
'GitHub authentication failed' => 'Zugang mit GitHub nicht möglich',
'Your GitHub account is no longer linked to your profile.' => 'Dein GitHub Account ist nicht mehr mit deinem Profil verbunden.',
'Unable to unlink your GitHub Account.' => 'Trennung der Verbindung mit deinem GitHub Account nicht möglich.',
'Login with my GitHub Account' => 'Anmelden mit meinem GitHub Account',
'Link my GitHub Account' => 'Mit meinem GitHub Account verbinden',
'Unlink my GitHub Account' => 'Verbindung mit meinem GitHub Account trennen',
// 'Task #%d' => '',
// 'Task removed successfully.' => '',
// 'Unable to remove this task.' => '',

View File

@@ -376,4 +376,12 @@ return array(
'Unable to upload the file.' => 'No pude cargar el fichero.',
'Actions' => 'Acciones',
// 'Display another project' => '',
// 'Your GitHub account was successfully linked to your profile.' => '',
// 'Unable to link your GitHub Account.' => '',
// 'GitHub authentication failed' => '',
// 'Your GitHub account is no longer linked to your profile.' => '',
// 'Unable to unlink your GitHub Account.' => '',
// 'Login with my GitHub Account' => '',
// 'Link my GitHub Account' => '',
// 'Unlink my GitHub Account' => '',
);

View File

@@ -374,4 +374,12 @@ return array(
'Maximum size: ' => 'Taille maximum : ',
'Unable to upload the file.' => 'Impossible de transférer le fichier.',
'Display another project' => 'Afficher un autre projet',
'Your GitHub account was successfully linked to your profile.' => 'Votre compte Github est désormais lié avec votre profile.',
'Unable to link your GitHub Account.' => 'Impossible de lier votre compte Github.',
'GitHub authentication failed' => 'L\'authentification avec Github à échouée',
'Your GitHub account is no longer linked to your profile.' => 'Votre compte Github n\'est plus relié avec votre profile.',
'Unable to unlink your GitHub Account.' => 'Impossible de déconnecter votre compte Github.',
'Login with my GitHub Account' => 'Se connecter avec mon compte Github',
'Link my GitHub Account' => 'Lier mon compte Github',
'Unlink my GitHub Account' => 'Ne plus utiliser mon compte Github',
);

View File

@@ -377,4 +377,12 @@ return array(
// 'Maximum size: ' => '',
// 'Unable to upload the file.' => '',
// 'Display another project' => '',
// 'Your GitHub account was successfully linked to your profile.' => '',
// 'Unable to link your GitHub Account.' => '',
// 'GitHub authentication failed' => '',
// 'Your GitHub account is no longer linked to your profile.' => '',
// 'Unable to unlink your GitHub Account.' => '',
// 'Login with my GitHub Account' => '',
// 'Link my GitHub Account' => '',
// 'Unlink my GitHub Account' => '',
);

View File

@@ -374,4 +374,12 @@ return array(
// 'Maximum size: ' => '',
// 'Unable to upload the file.' => '',
// 'Display another project' => '',
// 'Your GitHub account was successfully linked to your profile.' => '',
// 'Unable to link your GitHub Account.' => '',
// 'GitHub authentication failed' => '',
// 'Your GitHub account is no longer linked to your profile.' => '',
// 'Unable to unlink your GitHub Account.' => '',
// 'Login with my GitHub Account' => '',
// 'Link my GitHub Account' => '',
// 'Unlink my GitHub Account' => '',
);

View File

@@ -376,4 +376,12 @@ return array(
'Maximum size: ' => 'Maxstorlek: ',
'Unable to upload the file.' => 'Kunde inte ladda upp filen.',
// 'Display another project' => '',
// 'Your GitHub account was successfully linked to your profile.' => '',
// 'Unable to link your GitHub Account.' => '',
// 'GitHub authentication failed' => '',
// 'Your GitHub account is no longer linked to your profile.' => '',
// 'Unable to unlink your GitHub Account.' => '',
// 'Login with my GitHub Account' => '',
// 'Link my GitHub Account' => '',
// 'Unlink my GitHub Account' => '',
);

View File

@@ -382,4 +382,12 @@ return array(
// 'Maximum size: ' => '',
// 'Unable to upload the file.' => '',
// 'Display another project' => '',
// 'Your GitHub account was successfully linked to your profile.' => '',
// 'Unable to link your GitHub Account.' => '',
// 'GitHub authentication failed' => '',
// 'Your GitHub account is no longer linked to your profile.' => '',
// 'Unable to unlink your GitHub Account.' => '',
// 'Login with my GitHub Account' => '',
// 'Link my GitHub Account' => '',
// 'Unlink my GitHub Account' => '',
);

View File

@@ -17,7 +17,7 @@ class Acl extends Base
* @var array
*/
private $public_actions = array(
'user' => array('login', 'check', 'google'),
'user' => array('login', 'check', 'google', 'github'),
'task' => array('add'),
'board' => array('readonly'),
);
@@ -32,7 +32,7 @@ class Acl extends Base
'app' => array('index'),
'board' => array('index', 'show', 'assign', 'assigntask', 'save', 'check'),
'project' => array('tasks', 'index', 'forbidden', 'search'),
'user' => array('index', 'edit', 'update', 'forbidden', 'logout', 'index', 'unlinkgoogle'),
'user' => array('index', 'edit', 'update', 'forbidden', 'logout', 'index', 'unlinkgoogle', 'unlinkgithub'),
'config' => array('index', 'removeremembermetoken'),
'comment' => array('create', 'save', 'confirm', 'remove', 'update', 'edit', 'forbidden'),
'file' => array('create', 'save', 'download', 'confirm', 'remove', 'open', 'image'),

178
app/Model/GitHub.php Normal file
View File

@@ -0,0 +1,178 @@
<?php
namespace Model;
require __DIR__.'/../../vendor/OAuth/bootstrap.php';
use OAuth\Common\Storage\Session;
use OAuth\Common\Consumer\Credentials;
use OAuth\Common\Http\Uri\UriFactory;
use OAuth\ServiceFactory;
use OAuth\Common\Http\Exception\TokenResponseException;
/**
* GitHub model
*
* @package model
*/
class GitHub extends Base
{
/**
* Authenticate a GitHub user
*
* @access public
* @param string $github_id GitHub user id
* @return boolean
*/
public function authenticate($github_id)
{
$userModel = new User($this->db, $this->event);
$user = $userModel->getByGitHubId($github_id);
if ($user) {
// Create the user session
$userModel->updateSession($user);
// Update login history
$lastLogin = new LastLogin($this->db, $this->event);
$lastLogin->create(
LastLogin::AUTH_GITHUB,
$user['id'],
$userModel->getIpAddress(),
$userModel->getUserAgent()
);
return true;
}
return false;
}
/**
* Unlink a GitHub account for a given user
*
* @access public
* @param integer $user_id User id
* @return boolean
*/
public function unlink($user_id)
{
$userModel = new User($this->db, $this->event);
return $userModel->update(array(
'id' => $user_id,
'github_id' => '',
));
}
/**
* Update the user table based on the GitHub profile information
*
* @access public
* @param integer $user_id User id
* @param array $profile GitHub profile
* @return boolean
* @todo Don't overwrite existing email/name with empty GitHub data
*/
public function updateUser($user_id, array $profile)
{
$userModel = new User($this->db, $this->event);
return $userModel->update(array(
'id' => $user_id,
'github_id' => $profile['id'],
'email' => $profile['email'],
'name' => $profile['name'],
));
}
/**
* Get the GitHub service instance
*
* @access public
* @return \OAuth\OAuth2\Service\GitHub
*/
public function getService()
{
$uriFactory = new UriFactory();
$currentUri = $uriFactory->createFromSuperGlobalArray($_SERVER);
$currentUri->setQuery('controller=user&action=gitHub');
$storage = new Session(false);
$credentials = new Credentials(
GITHUB_CLIENT_ID,
GITHUB_CLIENT_SECRET,
$currentUri->getAbsoluteUri()
);
$serviceFactory = new ServiceFactory();
return $serviceFactory->createService(
'gitHub',
$credentials,
$storage,
array('')
);
}
/**
* Get the authorization URL
*
* @access public
* @return \OAuth\Common\Http\Uri\Uri
*/
public function getAuthorizationUrl()
{
return $this->getService()->getAuthorizationUri();
}
/**
* Get GitHub profile information from the API
*
* @access public
* @param string $code GitHub authorization code
* @return bool|array
*/
public function getGitHubProfile($code)
{
try {
$gitHubService = $this->getService();
$gitHubService->requestAccessToken($code);
return json_decode($gitHubService->request('user'), true);
}
catch (TokenResponseException $e) {
return false;
}
return false;
}
/**
* Revokes this user's GitHub tokens for Kanboard
*
* @access public
* @return bool|array
* @todo Currently this simply removes all our tokens for this user, ideally it should
* restrict itself to the one in question
*/
public function revokeGitHubAccess()
{
try {
$gitHubService = $this->getService();
$basicAuthHeader = array('Authorization' => 'Basic ' .
base64_encode(GITHUB_CLIENT_ID.':'.GITHUB_CLIENT_SECRET));
return json_decode($gitHubService->request('/applications/'.GITHUB_CLIENT_ID.'/tokens', 'DELETE', null, $basicAuthHeader), true);
}
catch (TokenResponseException $e) {
return false;
}
return false;
}
}

View File

@@ -33,6 +33,7 @@ class LastLogin extends Base
const AUTH_REMEMBER_ME = 'remember_me';
const AUTH_LDAP = 'ldap';
const AUTH_GOOGLE = 'google';
const AUTH_GITHUB = 'github';
/**
* Create a new record

View File

@@ -51,6 +51,18 @@ class User extends Base
return $this->db->table(self::TABLE)->eq('google_id', $google_id)->findOne();
}
/**
* Get a specific user by the GitHub id
*
* @access public
* @param string $github_id GitHub user id
* @return array
*/
public function getByGitHubId($github_id)
{
return $this->db->table(self::TABLE)->eq('github_id', $github_id)->findOne();
}
/**
* Get a specific user by the username
*

View File

@@ -3,7 +3,12 @@
namespace Schema;
use Core\Security;
const VERSION = 19;
const VERSION = 20;
function version_20($pdo)
{
$pdo->exec("ALTER TABLE users ADD COLUMN github_id VARCHAR(30)");
}
function version_19($pdo)
{

View File

@@ -3,7 +3,12 @@
namespace Schema;
use Core\Security;
const VERSION = 19;
const VERSION = 20;
function version_20($pdo)
{
$pdo->exec("ALTER TABLE users ADD COLUMN github_id TEXT");
}
function version_19($pdo)
{

View File

@@ -48,14 +48,27 @@
<?= Helper\form_checkbox('is_admin', t('Administrator'), 1, isset($values['is_admin']) && $values['is_admin'] == 1 ? true : false) ?><br/>
<?php endif ?>
<ul>
<?php if (GOOGLE_AUTH && Helper\is_current_user($values['id'])): ?>
<li>
<?php if (empty($values['google_id'])): ?>
<a href="?controller=user&amp;action=google<?= Helper\param_csrf() ?>"><?= t('Link my Google Account') ?></a>
<?php else: ?>
<a href="?controller=user&amp;action=unlinkGoogle<?= Helper\param_csrf() ?>"><?= t('Unlink my Google Account') ?></a>
<?php endif ?>
</li>
<?php endif ?>
<?php if (GITHUB_AUTH && Helper\is_current_user($values['id'])): ?>
<li>
<?php if (empty($values['github_id'])): ?>
<a href="?controller=user&amp;action=gitHub<?= Helper\param_csrf() ?>"><?= t('Link my GitHub Account') ?></a>
<?php else: ?>
<a href="?controller=user&amp;action=unlinkGitHub<?= Helper\param_csrf() ?>"><?= t('Unlink my GitHub Account') ?></a>
<?php endif ?>
</li>
<?php endif ?>
</ul>
</div>
<div class="form-actions">

View File

@@ -18,12 +18,20 @@
<?= Helper\form_checkbox('remember_me', t('Remember Me'), 1) ?><br/>
<ul>
<?php if (GOOGLE_AUTH): ?>
<p>
<li>
<a href="?controller=user&amp;action=google"><?= t('Login with my Google Account') ?></a>
</p>
</li>
<?php endif ?>
<?php if (GITHUB_AUTH): ?>
<li>
<a href="?controller=user&amp;action=gitHub"><?= t('Login with my GitHub Account') ?></a>
</li>
<?php endif ?>
</ul>
<div class="form-actions">
<input type="submit" value="<?= t('Sign in') ?>" class="btn btn-blue"/>
</div>

View File

@@ -51,6 +51,11 @@ defined('GOOGLE_AUTH') or define('GOOGLE_AUTH', false);
defined('GOOGLE_CLIENT_ID') or define('GOOGLE_CLIENT_ID', '');
defined('GOOGLE_CLIENT_SECRET') or define('GOOGLE_CLIENT_SECRET', '');
// GitHub authentication
defined('GITHUB_AUTH') or define('GITHUB_AUTH', false);
defined('GITHUB_CLIENT_ID') or define('GITHUB_CLIENT_ID', '');
defined('GITHUB_CLIENT_SECRET') or define('GITHUB_CLIENT_SECRET', '');
$loader = new Loader;
$loader->execute();