PlayerPreLoginEvent: New, more elegant way to control authentication requirement

Previously the only way to deal with this was to cancel the PlayerKickEvent generated by lack of authentication. Now, plugins can decide whether auth should be required for a specific player. The default is whatever xbox-auth is set to in server.properties.

cc @Johnmacrocraft
This commit is contained in:
Dylan K. Taylor 2018-12-23 18:24:33 +00:00
parent f313d06070
commit 02efa93e3a
3 changed files with 30 additions and 8 deletions

View File

@ -1732,7 +1732,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$this->setSkin($packet->skin); $this->setSkin($packet->skin);
$ev = new PlayerPreLoginEvent($this, "Plugin reason"); $ev = new PlayerPreLoginEvent($this, "Plugin reason", $this->server->requiresAuthentication());
$ev->call(); $ev->call();
if($ev->isCancelled()){ if($ev->isCancelled()){
$this->close("", $ev->getKickMessage()); $this->close("", $ev->getKickMessage());
@ -1756,16 +1756,16 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
} }
if(!$packet->skipVerification){ if(!$packet->skipVerification){
$this->server->getAsyncPool()->submitTask(new ProcessLoginTask($this, $packet, NetworkCipher::$ENABLED)); $this->server->getAsyncPool()->submitTask(new ProcessLoginTask($this, $packet, $ev->isAuthRequired(), NetworkCipher::$ENABLED));
}else{ }else{
$this->setAuthenticationStatus(true, null); $this->setAuthenticationStatus(false, false, null);
$this->networkSession->onLoginSuccess(); $this->networkSession->onLoginSuccess();
} }
return true; return true;
} }
public function setAuthenticationStatus(bool $authenticated, ?string $error) : bool{ public function setAuthenticationStatus(bool $authenticated, bool $authRequired, ?string $error) : bool{
if($this->networkSession === null){ if($this->networkSession === null){
return false; return false;
} }
@ -1783,7 +1783,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$this->authenticated = $authenticated; $this->authenticated = $authenticated;
if(!$this->authenticated){ if(!$this->authenticated){
if($this->server->requiresAuthentication() and $this->kick("disconnectionScreen.notAuthenticated", false)){ //use kick to allow plugins to cancel this if($authRequired){
$this->close("", "disconnectionScreen.notAuthenticated");
return false; return false;
} }

View File

@ -42,14 +42,18 @@ use pocketmine\Player;
class PlayerPreLoginEvent extends PlayerEvent implements Cancellable{ class PlayerPreLoginEvent extends PlayerEvent implements Cancellable{
/** @var string */ /** @var string */
protected $kickMessage; protected $kickMessage;
/** @var bool */
protected $authRequired;
/** /**
* @param Player $player * @param Player $player
* @param string $kickMessage * @param string $kickMessage
* @param bool $authRequired
*/ */
public function __construct(Player $player, string $kickMessage){ public function __construct(Player $player, string $kickMessage, bool $authRequired){
$this->player = $player; $this->player = $player;
$this->kickMessage = $kickMessage; $this->kickMessage = $kickMessage;
$this->authRequired = $authRequired;
} }
/** /**
@ -65,4 +69,18 @@ class PlayerPreLoginEvent extends PlayerEvent implements Cancellable{
public function getKickMessage() : string{ public function getKickMessage() : string{
return $this->kickMessage; return $this->kickMessage;
} }
/**
* @return bool
*/
public function isAuthRequired() : bool{
return $this->authRequired;
}
/**
* @param bool $v
*/
public function setAuthRequired(bool $v) : void{
$this->authRequired = $v;
}
} }

View File

@ -59,6 +59,8 @@ class ProcessLoginTask extends AsyncTask{
* root public key. * root public key.
*/ */
private $authenticated = false; private $authenticated = false;
/** @var bool */
private $authRequired;
/** /**
* @var bool * @var bool
@ -74,9 +76,10 @@ class ProcessLoginTask extends AsyncTask{
/** @var string|null */ /** @var string|null */
private $handshakeJwt = null; private $handshakeJwt = null;
public function __construct(Player $player, LoginPacket $packet, bool $useEncryption = true){ public function __construct(Player $player, LoginPacket $packet, bool $authRequired, bool $useEncryption = true){
$this->storeLocal($player); $this->storeLocal($player);
$this->packet = $packet; $this->packet = $packet;
$this->authRequired = $authRequired;
$this->useEncryption = $useEncryption; $this->useEncryption = $useEncryption;
if($useEncryption){ if($useEncryption){
if(self::$SERVER_PRIVATE_KEY === null){ if(self::$SERVER_PRIVATE_KEY === null){
@ -220,7 +223,7 @@ class ProcessLoginTask extends AsyncTask{
$player = $this->fetchLocal(); $player = $this->fetchLocal();
if(!$player->isConnected()){ if(!$player->isConnected()){
$this->worker->getLogger()->error("Player " . $player->getName() . " was disconnected before their login could be verified"); $this->worker->getLogger()->error("Player " . $player->getName() . " was disconnected before their login could be verified");
}elseif($player->setAuthenticationStatus($this->authenticated, $this->error)){ }elseif($player->setAuthenticationStatus($this->authenticated, $this->authRequired, $this->error)){
if(!$this->useEncryption){ if(!$this->useEncryption){
$player->getNetworkSession()->onLoginSuccess(); $player->getNetworkSession()->onLoginSuccess();
}else{ }else{