port hubzillas OpenWebAuth - remote authentification

This commit is contained in:
rabuzarus 2018-06-18 23:05:44 +02:00
parent 5fb8c758fd
commit 1c7f4e3c63
16 changed files with 1151 additions and 41 deletions

View file

@ -17,7 +17,9 @@ use Friendica\Core\System;
use Friendica\Core\Worker;
use Friendica\Database\DBM;
use Friendica\Model\Contact;
use Friendica\Model\Verify;
use Friendica\Protocol\Diaspora;
use Friendica\Network\Probe;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Network;
use Friendica\Util\Temporal;
@ -978,27 +980,137 @@ class Profile
return null;
}
/**
* Process the 'zrl' parameter and initiate the remote authentication.
*
* This method checks if the visitor has a public contact entry and
* redirects the visitor to his/her instance to start the magic auth (Authentication)
* process.
*
* @param App $a Application instance.
*/
public static function zrlInit(App $a)
{
$my_url = self::getMyURL();
$my_url = Network::isUrlValid($my_url);
if ($my_url) {
// Is it a DDoS attempt?
// The check fetches the cached value from gprobe to reduce the load for this system
$urlparts = parse_url($my_url);
if (!local_user()) {
// Is it a DDoS attempt?
// The check fetches the cached value from gprobe to reduce the load for this system
$urlparts = parse_url($my_url);
$result = Cache::get('gprobe:' . $urlparts['host']);
if ((!is_null($result)) && (in_array($result['network'], [NETWORK_FEED, NETWORK_PHANTOM]))) {
logger('DDoS attempt detected for ' . $urlparts['host'] . ' by ' . $_SERVER['REMOTE_ADDR'] . '. server data: ' . print_r($_SERVER, true), LOGGER_DEBUG);
return;
$result = Cache::get('gprobe:' . $urlparts['host']);
if ((!is_null($result)) && (in_array($result['network'], [NETWORK_FEED, NETWORK_PHANTOM]))) {
logger('DDoS attempt detected for ' . $urlparts['host'] . ' by ' . $_SERVER['REMOTE_ADDR'] . '. server data: ' . print_r($_SERVER, true), LOGGER_DEBUG);
return;
}
Worker::add(PRIORITY_LOW, 'GProbe', $my_url);
$arr = ['zrl' => $my_url, 'url' => $a->cmd];
Addon::callHooks('zrl_init', $arr);
// Try to find the public contact entry of the visitor.
$fields = ["id", "url"];
$condition = ['uid' => 0, 'nurl' => normalise_link($my_url)];
$contact = dba::selectFirst('contact',$fields, $condition);
// Not found? Try to probe the visitor.
if (!DBM::is_result($contact)) {
Probe::uri($my_url, '', -1, true, true);
$contact = dba::selectFirst('contact',$fields, $condition);
}
if (!DBM::is_result($contact)) {
logger('No contact record found for ' . $my_url, LOGGER_DEBUG);
return;
}
if (DBM::is_result($contact) && remote_user() && remote_user() === $contact['id']) {
// The visitor is already authenticated.
return;
}
logger('Not authenticated. Invoking reverse magic-auth for ' . $my_url, LOGGER_DEBUG);
// Try to avoid recursion - but send them home to do a proper magic auth.
$query = str_replace(array('?zrl=', '&zid='), array('?rzrl=', '&rzrl='), $a->query_string);
// The other instance needs to know where to redirect.
$dest = urlencode(System::baseUrl() . "/" . $query);
// We need to extract the basebath from the profile url
// to redirect the visitors '/magic' module.
// Note: We should have the basepath of a contact also in the contact table.
$urlarr = explode("/profile/", $contact['url']);
$basepath = $urlarr[0];
if ($basepath != System::baseUrl() && !strstr($dest, '/magic') && !strstr($dest, '/rmagic')) {
goaway($basepath . '/magic' . '?f=&owa=1&dest=' . $dest);
}
}
Worker::add(PRIORITY_LOW, 'GProbe', $my_url);
$arr = ['zrl' => $my_url, 'url' => $a->cmd];
Addon::callHooks('zrl_init', $arr);
}
}
/**
* OpenWebAuth authentication.
*
* @param string $token
*/
public static function owtInit($token)
{
$a = get_app();
// Clean old verify entries.
Verify::purge('owt', '3 MINUTE');
// Check if the token we got is the same one
// we have stored in the database.
$visitor_handle = Verify::getMeta('owt', 0, $token);
if($visitor_handle === false) {
return;
}
// Try to find the public contact entry of the visitor.
$condition = ["uid" => 0, "addr" => $visitor_handle];
$visitor = dba::selectFirst("contact", [], $condition);
if (!DBM::is_result($visitor)) {
Probe::uri($visitor_handle, '', -1, true, true);
$visitor = dba::selectFirst("contact", [], $condition);
}
if(!DBM::is_result($visitor)) {
logger('owt: unable to finger ' . $visitor_handle, LOGGER_DEBUG);
return;
}
// Authenticate the visitor.
$_SESSION['authenticated'] = 1;
$_SESSION['visitor_id'] = $visitor['id'];
$_SESSION['visitor_handle'] = $visitor['addr'];
$_SESSION['visitor_home'] = $visitor['url'];
$arr = [
'visitor' => $visitor,
'url' => $a->query_string,
'session' => $_SESSION
];
/**
* @hooks magic_auth_success
* Called when a magic-auth was successful.
* * \e array \b visitor
* * \e string \b url
* * \e array \b session
*/
Addon::callHooks('magic_auth_success', $arr);
$a->contact = $visitor;
info(L10n::t('OpenWebAuth: %1$s welcomes %2$s', $a->get_hostname(), $visitor['name']));
logger('OpenWebAuth: auth success from ' . $visitor['addr'], LOGGER_DEBUG);
}
public static function zrl($s, $force = false)
{
if (!strlen($s)) {
@ -1042,4 +1154,26 @@ class Profile
return $uid;
}
/**
* Stip zrl parameter from a string.
*
* @param string $s The input string.
* @return string The zrl.
*/
public static function stripZrls($s)
{
return preg_replace('/[\?&]zrl=(.*?)([\?&]|$)/is', '', $s);
}
/**
* Stip query parameter from a string.
*
* @param string $s The input string.
* @return string The query parameter.
*/
public static function stripQueryParam($s, $param)
{
return preg_replace('/[\?&]' . $param . '=(.*?)(&|$)/ism', '$2', $s);
}
}

73
src/Model/Verify.php Normal file
View file

@ -0,0 +1,73 @@
<?php
/**
* @file src/Model/Verify.php
*/
namespace Friendica\Model;
use Friendica\Database\DBM;
use Friendica\Util\DateTimeFormat;
use dba;
/**
* Methods to deal with entries of the 'verify' table.
*/
class Verify
{
/**
* Create an entry in the 'verify' table.
*
* @param string $type Verify type.
* @param int $uid The user ID.
* @param string $token
* @param string $meta
*
* @return boolean
*/
public static function create($type, $uid, $token, $meta)
{
$fields = [
"type" => $type,
"uid" => $uid,
"token" => $token,
"meta" => $meta,
"created" => DateTimeFormat::utcNow()
];
return dba::insert("verify", $fields);
}
/**
* Get the "meta" field of an entry in the verify table.
*
* @param string $type Verify type.
* @param int $uid The user ID.
* @param string $token
*
* @return string|boolean The meta enry or false if not found.
*/
public static function getMeta($type, $uid, $token)
{
$condition = ["type" => $type, "uid" => $uid, "token" => $token];
$entry = dba::selectFirst("verify", ["id", "meta"], $condition);
if (DBM::is_result($entry)) {
dba::delete("verify", ["id" => $entry["id"]]);
return $entry["meta"];
}
return false;
}
/**
* Purge entries of a verify-type older than interval.
*
* @param string $type Verify type.
* @param string $interval SQL compatible time interval
*/
public static function purge($type, $interval)
{
$condition = ["`type` = ? AND `created` < ?", $type, DateTimeFormat::utcNow() . " - INTERVAL " . $interval];
dba::delete("verify", $condition);
}
}