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.")
|
session.msg("Incorrect password.")
|
||||||
return
|
return
|
||||||
|
|
||||||
# We are logging in, get/setup the player object controlled by player
|
# actually do the login. This will call all hooks.
|
||||||
|
|
||||||
# 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
|
|
||||||
session.session_login(player)
|
session.session_login(player)
|
||||||
|
|
||||||
# post-login hooks
|
# we are logged in. Look around.
|
||||||
player.at_post_login()
|
character = player.character
|
||||||
if character:
|
if character:
|
||||||
character.at_post_login()
|
character.execute_cmd("look")
|
||||||
character.execute_cmd('look')
|
|
||||||
else:
|
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):
|
class CmdCreate(MuxCommand):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,43 @@ class IOdata(object):
|
||||||
self.__dict__.update(**kwargs)
|
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
|
# SessionBase class
|
||||||
#------------------------------------------------------------
|
#------------------------------------------------------------
|
||||||
|
|
@ -110,10 +147,28 @@ class SessionBase(object):
|
||||||
|
|
||||||
def session_login(self, player):
|
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
|
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.player = player
|
||||||
self.user = player.user
|
self.user = player.user
|
||||||
self.uid = self.user.id
|
self.uid = self.user.id
|
||||||
|
|
@ -132,9 +187,14 @@ class SessionBase(object):
|
||||||
#add session to connected list
|
#add session to connected list
|
||||||
SESSIONS.add_loggedin_session(self)
|
SESSIONS.add_loggedin_session(self)
|
||||||
|
|
||||||
#call hook
|
#call login hook
|
||||||
self.at_login(player)
|
self.at_login(player)
|
||||||
|
|
||||||
|
# post-login hooks
|
||||||
|
player.at_post_login()
|
||||||
|
if character:
|
||||||
|
character.at_post_login()
|
||||||
|
|
||||||
def session_disconnect(self):
|
def session_disconnect(self):
|
||||||
"""
|
"""
|
||||||
Clean up the session, removing it from the game and doing some
|
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_ssh import TerminalRealm, _Glue, ConchFactory
|
||||||
from twisted.conch.manhole import Manhole, recvline
|
from twisted.conch.manhole import Manhole, recvline
|
||||||
from twisted.internet import defer
|
from twisted.internet import defer
|
||||||
|
from twisted.conch import interfaces as iconch
|
||||||
|
from twisted.python import components
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from src.server import session
|
from src.server import session
|
||||||
|
from src.players.models import PlayerDB
|
||||||
from src.utils import ansi, utils, logger
|
from src.utils import ansi, utils, logger
|
||||||
|
#from src.commands.default.unloggedin import _login
|
||||||
|
|
||||||
ENCODINGS = settings.ENCODINGS
|
ENCODINGS = settings.ENCODINGS
|
||||||
|
|
||||||
|
|
@ -37,6 +40,13 @@ class SshProtocol(Manhole, session.Session):
|
||||||
them. All communication between game and player goes through
|
them. All communication between game and player goes through
|
||||||
here.
|
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):
|
def terminalSize(self, width, height):
|
||||||
"""
|
"""
|
||||||
|
|
@ -48,9 +58,12 @@ class SshProtocol(Manhole, session.Session):
|
||||||
self.terminal.cursorHome()
|
self.terminal.cursorHome()
|
||||||
self.width = width
|
self.width = width
|
||||||
self.height = height
|
self.height = height
|
||||||
|
|
||||||
# initialize the session
|
# initialize the session
|
||||||
self.session_connect(self.getClientAddress())
|
self.session_connect(self.getClientAddress())
|
||||||
|
if self.player is not None:
|
||||||
|
self.session_login(self.player)
|
||||||
|
self.execute_cmd('look')
|
||||||
|
|
||||||
def connectionMade(self):
|
def connectionMade(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -161,7 +174,6 @@ class SshProtocol(Manhole, session.Session):
|
||||||
"""
|
"""
|
||||||
self.telnet_markup = True
|
self.telnet_markup = True
|
||||||
# show connection screen
|
# show connection screen
|
||||||
self.execute_cmd('look')
|
|
||||||
|
|
||||||
def at_login(self, player):
|
def at_login(self, player):
|
||||||
"""
|
"""
|
||||||
|
|
@ -184,7 +196,7 @@ class SshProtocol(Manhole, session.Session):
|
||||||
|
|
||||||
def at_data_out(self, string, data=None):
|
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:
|
try:
|
||||||
string = utils.to_str(string, encoding=self.encoding)
|
string = utils.to_str(string, encoding=self.encoding)
|
||||||
|
|
@ -216,6 +228,7 @@ class SshProtocol(Manhole, session.Session):
|
||||||
logger.log_errmsg(str(e))
|
logger.log_errmsg(str(e))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ExtraInfoAuthServer(SSHUserAuthServer):
|
class ExtraInfoAuthServer(SSHUserAuthServer):
|
||||||
def auth_password(self, packet):
|
def auth_password(self, packet):
|
||||||
"""
|
"""
|
||||||
|
|
@ -230,10 +243,11 @@ class ExtraInfoAuthServer(SSHUserAuthServer):
|
||||||
return self.portal.login(c, None, IConchUser).addErrback(
|
return self.portal.login(c, None, IConchUser).addErrback(
|
||||||
self._ebPassword)
|
self._ebPassword)
|
||||||
|
|
||||||
|
class PlayerDBPasswordChecker(object):
|
||||||
class AnyAuth(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,)
|
credentialInterfaces = (credentials.IUsernamePassword,)
|
||||||
|
|
||||||
|
|
@ -242,8 +256,31 @@ class AnyAuth(object):
|
||||||
up = credentials.IUsernamePassword(c, None)
|
up = credentials.IUsernamePassword(c, None)
|
||||||
username = up.username
|
username = up.username
|
||||||
password = up.password
|
password = up.password
|
||||||
src_ip = str(up.transport.transport.getPeer().host)
|
player = PlayerDB.objects.get_player_from_name(username)
|
||||||
return defer.succeed(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:
|
class TerminalSessionTransport_getPeer:
|
||||||
|
|
@ -276,6 +313,7 @@ class TerminalSessionTransport_getPeer:
|
||||||
|
|
||||||
self.chainedProtocol.terminalProtocol.terminalSize(width, height)
|
self.chainedProtocol.terminalProtocol.terminalSize(width, height)
|
||||||
|
|
||||||
|
|
||||||
def getKeyPair(pubkeyfile, privkeyfile):
|
def getKeyPair(pubkeyfile, privkeyfile):
|
||||||
"""
|
"""
|
||||||
This function looks for RSA keypair files in the current directory. If they
|
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)
|
return Key.fromString(publicKeyString), Key.fromString(privateKeyString)
|
||||||
|
|
||||||
|
|
||||||
def makeFactory(configdict):
|
def makeFactory(configdict):
|
||||||
"""
|
"""
|
||||||
Creates the ssh server factory.
|
Creates the ssh server factory.
|
||||||
|
|
@ -310,13 +349,13 @@ def makeFactory(configdict):
|
||||||
pubkeyfile = "ssh-public.key"
|
pubkeyfile = "ssh-public.key"
|
||||||
privkeyfile = "ssh-private.key"
|
privkeyfile = "ssh-private.key"
|
||||||
|
|
||||||
def chainProtocolFactory():
|
def chainProtocolFactory(username=None):
|
||||||
return insults.ServerProtocol(
|
return insults.ServerProtocol(
|
||||||
configdict['protocolFactory'],
|
configdict['protocolFactory'],
|
||||||
*configdict.get('protocolConfigdict', ()),
|
*configdict.get('protocolConfigdict', (username,)),
|
||||||
**configdict.get('protocolKwArgs', {}))
|
**configdict.get('protocolKwArgs', {}))
|
||||||
|
|
||||||
rlm = TerminalRealm()
|
rlm = PassAvatarIdTerminalRealm()
|
||||||
rlm.transportFactory = TerminalSessionTransport_getPeer
|
rlm.transportFactory = TerminalSessionTransport_getPeer
|
||||||
rlm.chainedProtocolFactory = chainProtocolFactory
|
rlm.chainedProtocolFactory = chainProtocolFactory
|
||||||
factory = ConchFactory(Portal(rlm))
|
factory = ConchFactory(Portal(rlm))
|
||||||
|
|
@ -333,6 +372,6 @@ def makeFactory(configdict):
|
||||||
factory.services = factory.services.copy()
|
factory.services = factory.services.copy()
|
||||||
factory.services['ssh-userauth'] = ExtraInfoAuthServer
|
factory.services['ssh-userauth'] = ExtraInfoAuthServer
|
||||||
|
|
||||||
factory.portal.registerChecker(AnyAuth())
|
factory.portal.registerChecker(PlayerDBPasswordChecker())
|
||||||
|
|
||||||
return factory
|
return factory
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ class TelnetProtocol(StatefulTelnetProtocol, session.Session):
|
||||||
|
|
||||||
def at_data_out(self, string, data=None):
|
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:
|
try:
|
||||||
string = utils.to_str(string, encoding=self.encoding)
|
string = utils.to_str(string, encoding=self.encoding)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue