split out credentials to credentials.py

This commit is contained in:
Michel Oosterhof
2015-08-28 11:48:36 +00:00
parent 5dd463e8ef
commit a572c4fd15
3 changed files with 88 additions and 35 deletions

View File

@ -10,8 +10,7 @@ from random import randint
from zope.interface import implementer from zope.interface import implementer
from twisted.cred.checkers import ICredentialsChecker from twisted.cred.checkers import ICredentialsChecker
from twisted.cred.credentials import IUsernamePassword, ISSHPrivateKey, \ from twisted.cred.credentials import ISSHPrivateKey
ICredentials
from twisted.cred.error import UnauthorizedLogin, UnhandledCredentials from twisted.cred.error import UnauthorizedLogin, UnhandledCredentials
from twisted.internet import defer from twisted.internet import defer
@ -19,6 +18,8 @@ from twisted.python import log, failure
from twisted.conch import error from twisted.conch import error
from twisted.conch.ssh import keys from twisted.conch.ssh import keys
import credentials
# by Walter de Jong <walter@sara.nl> # by Walter de Jong <walter@sara.nl>
class UserDB(object): class UserDB(object):
@ -257,38 +258,13 @@ class HoneypotPublicKeyChecker:
fingerprint=_pubKey.fingerprint()) fingerprint=_pubKey.fingerprint())
return failure.Failure(error.ConchError('Incorrect signature')) return failure.Failure(error.ConchError('Incorrect signature'))
class IUsername(ICredentials):
"""
Encapsulate username only
@type username: C{str}
@ivar username: The username associated with these credentials.
"""
@implementer(IUsername)
class Username:
def __init__(self, username):
self.username = username
# This credential interface also provides an IP address
@implementer(IUsernamePassword)
class UsernamePasswordIP:
def __init__(self, username, password, ip):
self.username = username
self.password = password
self.ip = ip
@implementer(ICredentialsChecker) @implementer(ICredentialsChecker)
class HoneypotNoneChecker: class HoneypotNoneChecker:
""" """
Checker that does no authentication check Checker that does no authentication check
""" """
credentialInterfaces = (IUsername,) credentialInterfaces = (credentials.IUsername,)
def __init__(self): def __init__(self):
pass pass
@ -302,7 +278,7 @@ class HoneypotPasswordChecker:
Checker that accepts "keyboard-interactive" and "password" Checker that accepts "keyboard-interactive" and "password"
""" """
credentialInterfaces = (IUsernamePassword,) credentialInterfaces = (credentials.IUsernamePasswordIP,)
def __init__(self, cfg): def __init__(self, cfg):
self.cfg = cfg self.cfg = cfg

View File

@ -0,0 +1,75 @@
# Copyright (c) 2015 Michel Oosterhof <michel@oosterhof.net>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. The names of the author(s) may not be used to endorse or promote
# products derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
from zope.interface import implementer
from twisted.cred.credentials import IUsernamePassword, \
ICredentials
class IUsername(ICredentials):
"""
Encapsulate username only
@type username: C{str}
@ivar username: The username associated with these credentials.
"""
class IUsernamePasswordIP(IUsernamePassword):
"""
I encapsulate a username, a plaintext password and a source IP
@type username: C{str}
@ivar username: The username associated with these credentials.
@type password: C{str}
@ivar password: The password associated with these credentials.
@type ip: C{str}
@ivar ip: The source ip address associated with these credentials.
"""
@implementer(IUsername)
class Username:
"""
"""
def __init__(self, username):
self.username = username
# This credential interface also provides an IP address
@implementer(IUsernamePasswordIP)
class UsernamePasswordIP:
"""
"""
def __init__(self, username, password, ip):
self.username = username
self.password = password
self.ip = ip
# vim: set sw=4 et:

View File

@ -20,6 +20,7 @@ from twisted.internet import defer
import ConfigParser import ConfigParser
import credentials
import fs import fs
import auth import auth
import connection import connection
@ -29,7 +30,8 @@ import protocol
class HoneyPotSSHUserAuthServer(userauth.SSHUserAuthServer): class HoneyPotSSHUserAuthServer(userauth.SSHUserAuthServer):
def serviceStarted(self): def serviceStarted(self):
self.interfaceToMethod[auth.IUsername] = 'none' self.interfaceToMethod[credentials.IUsername] = 'none'
self.interfaceToMethod[credentials.IUsernamePasswordIP] = 'password'
userauth.SSHUserAuthServer.serviceStarted(self) userauth.SSHUserAuthServer.serviceStarted(self)
self.bannerSent = False self.bannerSent = False
@ -54,18 +56,18 @@ class HoneyPotSSHUserAuthServer(userauth.SSHUserAuthServer):
return userauth.SSHUserAuthServer.ssh_USERAUTH_REQUEST(self, packet) return userauth.SSHUserAuthServer.ssh_USERAUTH_REQUEST(self, packet)
def auth_none(self, packet): def auth_none(self, packet):
c = auth.Username(self.user) c = credentials.Username(self.user)
return self.portal.login(c, None, conchinterfaces.IConchUser) return self.portal.login(c, None, conchinterfaces.IConchUser)
# Overridden to pass src_ip to auth.UsernamePasswordIP # Overridden to pass src_ip to credentials.UsernamePasswordIP
def auth_password(self, packet): def auth_password(self, packet):
password = getNS(packet[1:])[0] password = getNS(packet[1:])[0]
src_ip = self.transport.transport.getPeer().host src_ip = self.transport.transport.getPeer().host
c = auth.UsernamePasswordIP(self.user, password, src_ip) c = credentials.UsernamePasswordIP(self.user, password, src_ip)
return self.portal.login(c, None, return self.portal.login(c, None,
conchinterfaces.IConchUser).addErrback(self._ebPassword) conchinterfaces.IConchUser).addErrback(self._ebPassword)
# Overridden to pass src_ip to auth.PluggableAuthenticationModulesIP # Overridden to pass src_ip to credentials.PluggableAuthenticationModulesIP
def auth_keyboard_interactive(self, packet): def auth_keyboard_interactive(self, packet):
if self._pamDeferred is not None: if self._pamDeferred is not None:
self.transport.sendDisconnect( self.transport.sendDisconnect(
@ -73,7 +75,7 @@ class HoneyPotSSHUserAuthServer(userauth.SSHUserAuthServer):
"only one keyboard interactive attempt at a time") "only one keyboard interactive attempt at a time")
return defer.fail(error.IgnoreAuthentication()) return defer.fail(error.IgnoreAuthentication())
src_ip = self.transport.transport.getPeer().host src_ip = self.transport.transport.getPeer().host
c = auth.PluggableAuthenticationModulesIP(self.user, self._pamConv, src_ip) c = credentials.PluggableAuthenticationModulesIP(self.user, self._pamConv, src_ip)
return self.portal.login(c, None, return self.portal.login(c, None,
conchinterfaces.IConchUser).addErrback(self._ebPassword) conchinterfaces.IConchUser).addErrback(self._ebPassword)