mirror of
https://github.com/evennia/evennia.git
synced 2026-03-22 07:46:30 +01:00
Added ability to login directly using SSH auth; based on patch by hagna.
This commit is contained in:
parent
218ae61836
commit
1d93d8295f
4 changed files with 125 additions and 92 deletions
|
|
@ -60,83 +60,17 @@ class CmdConnect(MuxCommand):
|
|||
session.msg("Incorrect password.")
|
||||
return
|
||||
|
||||
# We are logging in, get/setup the player object controlled by player
|
||||
|
||||
# Check if this is the first time the
|
||||
# *player* connects
|
||||
if player.db.FIRST_LOGIN:
|
||||
player.at_first_login()
|
||||
del player.db.FIRST_LOGIN
|
||||
player.at_pre_login()
|
||||
|
||||
character = player.character
|
||||
if character:
|
||||
# this player has a character. Check if it's the
|
||||
# first time *this character* logs in
|
||||
if character.db.FIRST_LOGIN:
|
||||
character.at_first_login()
|
||||
del character.db.FIRST_LOGIN
|
||||
# run character login hook
|
||||
character.at_pre_login()
|
||||
|
||||
# actually do the login
|
||||
# actually do the login. This will call all hooks.
|
||||
session.session_login(player)
|
||||
|
||||
# post-login hooks
|
||||
player.at_post_login()
|
||||
|
||||
# we are logged in. Look around.
|
||||
character = player.character
|
||||
if character:
|
||||
character.at_post_login()
|
||||
character.execute_cmd('look')
|
||||
character.execute_cmd("look")
|
||||
else:
|
||||
player.execute_cmd('look')
|
||||
# we have no character yet; use player's look, if it exists
|
||||
player.execute_cmd("look")
|
||||
|
||||
# run look
|
||||
#print "character:", character, character.scripts.all(), character.cmdset.current
|
||||
|
||||
#
|
||||
# character = player.character
|
||||
# if not character:
|
||||
# # Create a new character object to tie the player to. This should
|
||||
# # usually not be needed unless the old character object was manually
|
||||
# # deleted.
|
||||
# default_home_id = ServerConfig.objects.conf("default_home")
|
||||
# default_home = ObjectDB.objects.get_id(default_home_id)
|
||||
# typeclass = settings.BASE_CHARACTER_TYPECLASS
|
||||
# character = create.create_object(typeclass=typeclass,
|
||||
# key=player.name,
|
||||
# location=default_home,
|
||||
# home=default_home,
|
||||
# player=player)
|
||||
|
||||
# character.db.FIRST_LOGIN = "True"
|
||||
|
||||
# # Getting ready to log the player in.
|
||||
|
||||
# # Check if this is the first time the
|
||||
# # *player* connects
|
||||
# if player.db.FIRST_LOGIN:
|
||||
# player.at_first_login()
|
||||
# del player.db.FIRST_LOGIN
|
||||
|
||||
# # check if this is the first time the *character*
|
||||
# # character (needs not be the first time the player
|
||||
# # does so, e.g. if the player has several characters)
|
||||
# if character.db.FIRST_LOGIN:
|
||||
# character.at_first_login()
|
||||
# del character.db.FIRST_LOGIN
|
||||
|
||||
# # actually do the login, calling
|
||||
# # customization hooks before and after.
|
||||
# player.at_pre_login()
|
||||
# character.at_pre_login()
|
||||
|
||||
# session.session_login(player)
|
||||
|
||||
# player.at_post_login()
|
||||
# character.at_post_login()
|
||||
# # run look
|
||||
# #print "character:", character, character.scripts.all(), character.cmdset.current
|
||||
# character.execute_cmd('look')
|
||||
|
||||
class CmdCreate(MuxCommand):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -58,6 +58,43 @@ class IOdata(object):
|
|||
self.__dict__.update(**kwargs)
|
||||
|
||||
|
||||
def _login(session, player):
|
||||
"""
|
||||
For logging a player in. Removed this from CmdConnect because ssh
|
||||
wanted to call it for autologin.
|
||||
"""
|
||||
# We are logging in, get/setup the player object controlled by player
|
||||
|
||||
# Check if this is the first time the
|
||||
# *player* connects (should be set by the
|
||||
if player.db.FIRST_LOGIN:
|
||||
player.at_first_login()
|
||||
del player.db.FIRST_LOGIN
|
||||
player.at_pre_login()
|
||||
|
||||
character = player.character
|
||||
if character:
|
||||
# this player has a character. Check if it's the
|
||||
# first time *this character* logs in (this should be
|
||||
# set by the initial create command)
|
||||
if character.db.FIRST_LOGIN:
|
||||
character.at_first_login()
|
||||
del character.db.FIRST_LOGIN
|
||||
# run character login hook
|
||||
character.at_pre_login()
|
||||
|
||||
# actually do the login
|
||||
session.session_login(player)
|
||||
|
||||
# post-login hooks
|
||||
player.at_post_login()
|
||||
if character:
|
||||
character.at_post_login()
|
||||
character.execute_cmd('look')
|
||||
else:
|
||||
player.execute_cmd('look')
|
||||
|
||||
|
||||
#------------------------------------------------------------
|
||||
# SessionBase class
|
||||
#------------------------------------------------------------
|
||||
|
|
@ -110,10 +147,28 @@ class SessionBase(object):
|
|||
|
||||
def session_login(self, player):
|
||||
"""
|
||||
Private startup mechanisms that need to run at login
|
||||
Startup mechanisms that need to run at login
|
||||
|
||||
player - the connected player
|
||||
"""
|
||||
# Check if this is the first time the *player* logs in
|
||||
if player.db.FIRST_LOGIN:
|
||||
player.at_first_login()
|
||||
del player.db.FIRST_LOGIN
|
||||
player.at_pre_login()
|
||||
|
||||
character = player.character
|
||||
if character:
|
||||
# this player has a character. Check if it's the
|
||||
# first time *this character* logs in
|
||||
if character.db.FIRST_LOGIN:
|
||||
character.at_first_login()
|
||||
del character.db.FIRST_LOGIN
|
||||
# run character login hook
|
||||
character.at_pre_login()
|
||||
|
||||
# actually do the login by assigning session data
|
||||
|
||||
self.player = player
|
||||
self.user = player.user
|
||||
self.uid = self.user.id
|
||||
|
|
@ -132,9 +187,14 @@ class SessionBase(object):
|
|||
#add session to connected list
|
||||
SESSIONS.add_loggedin_session(self)
|
||||
|
||||
#call hook
|
||||
#call login hook
|
||||
self.at_login(player)
|
||||
|
||||
# post-login hooks
|
||||
player.at_post_login()
|
||||
if character:
|
||||
character.at_post_login()
|
||||
|
||||
def session_disconnect(self):
|
||||
"""
|
||||
Clean up the session, removing it from the game and doing some
|
||||
|
|
|
|||
|
|
@ -19,10 +19,13 @@ from twisted.conch.insults import insults
|
|||
from twisted.conch.manhole_ssh import TerminalRealm, _Glue, ConchFactory
|
||||
from twisted.conch.manhole import Manhole, recvline
|
||||
from twisted.internet import defer
|
||||
from twisted.conch import interfaces as iconch
|
||||
from twisted.python import components
|
||||
from django.conf import settings
|
||||
from src.server import session
|
||||
from src.players.models import PlayerDB
|
||||
from src.utils import ansi, utils, logger
|
||||
|
||||
#from src.commands.default.unloggedin import _login
|
||||
|
||||
ENCODINGS = settings.ENCODINGS
|
||||
|
||||
|
|
@ -37,6 +40,13 @@ class SshProtocol(Manhole, session.Session):
|
|||
them. All communication between game and player goes through
|
||||
here.
|
||||
"""
|
||||
def __init__(self, player):
|
||||
"""
|
||||
For setting up the player. If player is not None then we'll
|
||||
login automatically.
|
||||
"""
|
||||
self.player = player
|
||||
|
||||
|
||||
def terminalSize(self, width, height):
|
||||
"""
|
||||
|
|
@ -48,9 +58,12 @@ class SshProtocol(Manhole, session.Session):
|
|||
self.terminal.cursorHome()
|
||||
self.width = width
|
||||
self.height = height
|
||||
|
||||
# initialize the session
|
||||
self.session_connect(self.getClientAddress())
|
||||
|
||||
if self.player is not None:
|
||||
self.session_login(self.player)
|
||||
self.execute_cmd('look')
|
||||
|
||||
def connectionMade(self):
|
||||
"""
|
||||
|
|
@ -161,7 +174,6 @@ class SshProtocol(Manhole, session.Session):
|
|||
"""
|
||||
self.telnet_markup = True
|
||||
# show connection screen
|
||||
self.execute_cmd('look')
|
||||
|
||||
def at_login(self, player):
|
||||
"""
|
||||
|
|
@ -184,7 +196,7 @@ class SshProtocol(Manhole, session.Session):
|
|||
|
||||
def at_data_out(self, string, data=None):
|
||||
"""
|
||||
Data Evennia -> Player access hook. 'data' argument is ignored.
|
||||
Data Evennia -> Player access hook. 'data' argument is a dict parsed for string settings.
|
||||
"""
|
||||
try:
|
||||
string = utils.to_str(string, encoding=self.encoding)
|
||||
|
|
@ -216,6 +228,7 @@ class SshProtocol(Manhole, session.Session):
|
|||
logger.log_errmsg(str(e))
|
||||
|
||||
|
||||
|
||||
class ExtraInfoAuthServer(SSHUserAuthServer):
|
||||
def auth_password(self, packet):
|
||||
"""
|
||||
|
|
@ -230,10 +243,11 @@ class ExtraInfoAuthServer(SSHUserAuthServer):
|
|||
return self.portal.login(c, None, IConchUser).addErrback(
|
||||
self._ebPassword)
|
||||
|
||||
|
||||
class AnyAuth(object):
|
||||
class PlayerDBPasswordChecker(object):
|
||||
"""
|
||||
Special auth method that accepts any credentials.
|
||||
Checks the django db for the correct credentials for
|
||||
username/password otherwise it returns the player or None which is
|
||||
useful for the Realm.
|
||||
"""
|
||||
credentialInterfaces = (credentials.IUsernamePassword,)
|
||||
|
||||
|
|
@ -242,8 +256,31 @@ class AnyAuth(object):
|
|||
up = credentials.IUsernamePassword(c, None)
|
||||
username = up.username
|
||||
password = up.password
|
||||
src_ip = str(up.transport.transport.getPeer().host)
|
||||
return defer.succeed(username)
|
||||
player = PlayerDB.objects.get_player_from_name(username)
|
||||
res = None
|
||||
if player and player.user.check_password(password):
|
||||
res = player
|
||||
return defer.succeed(res)
|
||||
|
||||
class PassAvatarIdTerminalRealm(TerminalRealm):
|
||||
"""
|
||||
Returns an avatar that passes the avatarId through to the
|
||||
protocol. This is probably not the best way to do it.
|
||||
"""
|
||||
|
||||
def _getAvatar(self, avatarId):
|
||||
comp = components.Componentized()
|
||||
user = self.userFactory(comp, avatarId)
|
||||
sess = self.sessionFactory(comp)
|
||||
|
||||
sess.transportFactory = self.transportFactory
|
||||
sess.chainedProtocolFactory = lambda : self.chainedProtocolFactory(avatarId)
|
||||
|
||||
comp.setComponent(iconch.IConchUser, user)
|
||||
comp.setComponent(iconch.ISession, sess)
|
||||
|
||||
return user
|
||||
|
||||
|
||||
|
||||
class TerminalSessionTransport_getPeer:
|
||||
|
|
@ -276,6 +313,7 @@ class TerminalSessionTransport_getPeer:
|
|||
|
||||
self.chainedProtocol.terminalProtocol.terminalSize(width, height)
|
||||
|
||||
|
||||
def getKeyPair(pubkeyfile, privkeyfile):
|
||||
"""
|
||||
This function looks for RSA keypair files in the current directory. If they
|
||||
|
|
@ -302,6 +340,7 @@ def getKeyPair(pubkeyfile, privkeyfile):
|
|||
|
||||
return Key.fromString(publicKeyString), Key.fromString(privateKeyString)
|
||||
|
||||
|
||||
def makeFactory(configdict):
|
||||
"""
|
||||
Creates the ssh server factory.
|
||||
|
|
@ -310,21 +349,21 @@ def makeFactory(configdict):
|
|||
pubkeyfile = "ssh-public.key"
|
||||
privkeyfile = "ssh-private.key"
|
||||
|
||||
def chainProtocolFactory():
|
||||
def chainProtocolFactory(username=None):
|
||||
return insults.ServerProtocol(
|
||||
configdict['protocolFactory'],
|
||||
*configdict.get('protocolConfigdict', ()),
|
||||
*configdict.get('protocolConfigdict', (username,)),
|
||||
**configdict.get('protocolKwArgs', {}))
|
||||
|
||||
rlm = TerminalRealm()
|
||||
rlm = PassAvatarIdTerminalRealm()
|
||||
rlm.transportFactory = TerminalSessionTransport_getPeer
|
||||
rlm.chainedProtocolFactory = chainProtocolFactory
|
||||
factory = ConchFactory(Portal(rlm))
|
||||
|
||||
|
||||
try:
|
||||
# create/get RSA keypair
|
||||
# create/get RSA keypair
|
||||
publicKey, privateKey = getKeyPair(pubkeyfile, privkeyfile)
|
||||
factory.publicKeys = {'ssh-rsa': publicKey}
|
||||
factory.publicKeys = {'ssh-rsa': publicKey}
|
||||
factory.privateKeys = {'ssh-rsa': privateKey}
|
||||
except Exception, e:
|
||||
print " getKeyPair error: %s\n WARNING: Evennia could not auto-generate SSH keypair. Using conch default keys instead." % e
|
||||
|
|
@ -333,6 +372,6 @@ def makeFactory(configdict):
|
|||
factory.services = factory.services.copy()
|
||||
factory.services['ssh-userauth'] = ExtraInfoAuthServer
|
||||
|
||||
factory.portal.registerChecker(AnyAuth())
|
||||
factory.portal.registerChecker(PlayerDBPasswordChecker())
|
||||
|
||||
return factory
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ class TelnetProtocol(StatefulTelnetProtocol, session.Session):
|
|||
|
||||
def at_data_out(self, string, data=None):
|
||||
"""
|
||||
Data Evennia -> Player access hook. 'data' argument is ignored.
|
||||
Data Evennia -> Player access hook. 'data' argument is a dict parsed for string settings.
|
||||
"""
|
||||
try:
|
||||
string = utils.to_str(string, encoding=self.encoding)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue