Beispiel #1
0
    def __call__(self,
                 server: SMTP,
                 session: Session,
                 envelope: Envelope,
                 mechanism: str,
                 auth_data: Tuple[bytes, bytes],
                 ) -> AuthResult:
        fail_nothandled = AuthResult(success=False, handled=False)
        if mechanism not in ("LOGIN", "PLAIN"):
            return fail_nothandled
        if not isinstance(auth_data, LoginPassword):
            return fail_nothandled
        username = auth_data.login.decode('utf-8')
        password = auth_data.password.decode('utf-8')

        conn = sqlite3.connect(str(self.auth_db))
        curs = conn.execute(
            "SELECT hashpass FROM userauth WHERE username=?", (username,)
        )
        hash_db = curs.fetchone()
        conn.close()
        if not hash_db:
            return fail_nothandled
        try:
            if self.ph.verify(hash_db[0], password):
                self.logger.info(f"User {username} authenticated")
                return AuthResult(success=True)
        except VerifyMismatchError:
            self.logger.warning(f"User {username} failed authentication!")

        return fail_nothandled
Beispiel #2
0
 async def handle_smtpd_auth(self, server: SMTP, method: str,
                             data: Any) -> AuthResult:
     if method == 'login' or method == 'plain':
         assert isinstance(data, LoginPassword)
         username: bytes = data.login
         password: bytes = data.password
         username_s = username.decode(
             'utf-8')  # TODO (rubicon): support the other charsets
         result = await self.storage_hub.user_records.check_user_password(
             username_s, password)
         return AuthResult(success=result, handled=True)
     else:
         return AuthResult(success=False, handled=False)
Beispiel #3
0
 async def auth_PLAIN(self, server: SMTP, args: List[str]) -> AuthResult:
     words = await server.challenge_auth("", encode_to_b64=False)
     if words == aiosmtpd.smtp.MISSING:
         return AuthResult(success=False, handled=False)
     decoded_words = standard_b64decode(cast(bytes, words))
     parts = decoded_words.split(b"\0")
     if parts:
         if not parts[0]:
             parts.pop(0)
     if len(parts) != 2:
         return AuthResult(success=False, handled=True)
     return await self.smtp_auth_handler(server, "plain",
                                         LoginPassword(parts[0], parts[1]))
Beispiel #4
0
 async def auth_LOGIN(self, server: SMTP, args: List[str]) -> AuthResult:
     username = await server.challenge_auth("Username:"******"Password:"******"login",
         LoginPassword(cast(bytes, username), cast(bytes, password)))
    def authenticator(self, _unused_server: SMTP, _unused_session: Session,
                      _unused_envelope: Envelope, mechanism: str,
                      login_data: Tuple[bytes, bytes]) -> AuthResult:

        if mechanism not in ('LOGIN', 'PLAIN'):
            return AuthResult(success=False, handled=False)
        if not isinstance(login_data, LoginPassword):  # type: ignore
            return AuthResult(success=False, handled=False)

        username = login_data.login.decode()  # type: ignore
        password = login_data.password.decode()  # type: ignore

        if username != self._user or password != self._password:
            return AuthResult(success=False, handled=False)

        return AuthResult(success=True)
Beispiel #6
0
def authenticator(
    server: SMTP,
    session: Session,
    envelope: Envelope,
    mechanism: str,
    auth_data: LoginPassword,
) -> AuthResult:
    fail_nothandled = AuthResult(success=False, handled=False)
    if mechanism not in ("LOGIN", "PLAIN"):
        return fail_nothandled
    if not isinstance(auth_data, LoginPassword):
        return fail_nothandled

    if auth_data.login == b"*****@*****.**" and auth_data.password == b"secret":
        return AuthResult(success=True)
    else:
        return fail_nothandled
Beispiel #7
0
 def __call__(self, server: SMTP, session: Session, envelope: Envelope,
              mechanism: str, auth_data):
     fail_nothandled = AuthResult(success=False, handled=False)
     if mechanism not in ("LOGIN", "PLAIN"):
         return fail_nothandled
     if not isinstance(auth_data, LoginPassword):
         return fail_nothandled
     username = auth_data.login.decode()
     password = auth_data.password.decode()
     auth_client = db.clients.find_one({
         "username": username,
         "password": password
     })
     if auth_client:
         return AuthResult(success=True,
                           auth_data={"id": str(auth_client['_id'])})
     return fail_nothandled
Beispiel #8
0
    async def auth_PLAIN(self, server, args):
        log.debug("AUTH PLAIN received")

        response = None
        if len(args) >= 2:
            response = base64.b64decode(args[1])
        else:
            response = await server.challenge_auth("")
        response = response.decode()
        response = response.split()
        if len(response) < 2:
            return AuthResult(success=False, handled=False)
        if (
            len(response) >= 2 and
            server._authenticator.validate(response[0], response[-1])
        ):
            return AuthResult(success=True, handled=True)
        return AuthResult(success=False, handled=False)
Beispiel #9
0
 def __call__(self, server, session, envelope, mechanism, auth_data):
     fail_nothandled = AuthResult(success=False, handled=False)
     if mechanism not in ("LOGIN", "PLAIN"):
         return fail_nothandled
     if not isinstance(auth_data, LoginPassword):
         return fail_nothandled
     username = auth_data.login
     password = auth_data.password
     hashpass = self.ph.hash(password)
     conn = sqlite3.connect(self.auth_db)
     curs = conn.execute("SELECT hashpass FROM userauth WHERE username=?",
                         (username, ))
     hash_db = curs.fetchone()
     conn.close()
     if not hash_db:
         return fail_nothandled
     if hashpass != hash_db[0]:
         return fail_nothandled
     return AuthResult(success=True)
Beispiel #10
0
    async def auth_PLAIN(self, server: SMTP, args: List[str]) -> AuthResult:
        log.debug("AUTH PLAIN received")

        response = b""
        if len(args) >= 2:
            response = base64.b64decode(args[1])
        else:
            response = await server.challenge_auth("")
        decoded_resp = response.decode()
        split_resp: List[str] = decoded_resp.split()
        if len(split_resp) < 2:
            return AuthResult(success=False, handled=False)
        if (
            len(split_resp) >= 2
            and server._authenticator.validate(split_resp[0], split_resp[-1])
        ):
            log.debug("AUTH PLAIN succeeded")
            return AuthResult(success=True, handled=True)

        log.debug("AUTH PLAIN failed")
        return AuthResult(success=False, handled=False)
Beispiel #11
0
    async def auth_CRAM_MD5(self, server: SMTP, args: List[str]) -> AuthResult:
        log.debug("AUTH CRAM-MD5 received")

        # Generate challenge
        secret = secrets.token_hex(8)
        ts = datetime.now().timestamp()
        hostname = server.hostname
        challenge = f"<{secret}{ts}@{hostname}>"
        response = await server.challenge_auth(challenge)
        user, received = response.split()
        password = server._authenticator.get_password(user.decode())

        # Verify
        mac = hmac.HMAC(password.encode(),
                        challenge.encode(),
                        "md5")
        expected = mac.hexdigest().encode()
        if hmac.compare_digest(expected, received):
            log.debug("AUTH CARM-MD5 succeeded")
            return AuthResult(success=True, handled=True, auth_data=user)
        log.debug("AUTH CRAM-MD5 failed")
        return AuthResult(success=False, handled=False)
Beispiel #12
0
    async def auth_LOGIN(self, server: SMTP, args: List[str]) -> AuthResult:
        log.info("AUTH LOGIN received")

        login = []
        for n in range(1, len(args)):
            arg = base64.b64decode(args[n]).decode()
            login.extend(arg.split(maxsplit=1))

        while len(login) < 2:
            prompt = "Password" if len(login) >= 1 else ""
            response = await server.challenge_auth(prompt)
            if response is MISSING:
                return AuthResult(success=False, handled=True)
            response = response.decode()
            login.extend(response.split(maxsplit=1 - len(login)))

        username = login[0]
        password = login[1]

        if server._authenticator.validate(username, password):
            log.info("AUTH LOGIN succeeded.")
            return AuthResult(success=True, handled=True, auth_data=username)
        log.info("AUTH LOGIN failed.")
        return AuthResult(success=False, handled=False)
Beispiel #13
0
 def __call__(self, server, session, envelope, mechanism, auth_data):
     return AuthResult(success=True)
Beispiel #14
0
 async def auth_PLAIN(self, _, args: list[str]) -> AuthResult:
     expected = 'AHVzZXJuYW1lAHBhc3N3b3Jk'
     if args[1] == expected and success:
         return AuthResult(success=True)
     else:
         return AuthResult(success=False, handled=False)
Beispiel #15
0
async def smtpd_auth_rejectall(*args, **kargs):
    return AuthResult(success=False, handled=True)