From a8839a459e4494aef88f5ff1b7132705ecb5cdd6 Mon Sep 17 00:00:00 2001 From: zeroleo12345 Date: Sat, 27 Mar 2021 12:53:43 +0800 Subject: [PATCH 01/15] =?UTF-8?q?[IMPROVED]=20=E8=B0=83=E6=95=B4session.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- etc/dictionary/dictionary.h3c | 60 ++++++++++++++++++++ src/auth/eap_peap_gtc_flow.py | 4 +- src/auth/eap_peap_mschapv2_flow.py | 4 +- src/auth/mschap_flow.py | 21 ++++--- src/auth/{eap_peap_session.py => session.py} | 13 ++++- src/child_pyrad/packet.py | 2 + 6 files changed, 88 insertions(+), 16 deletions(-) create mode 100644 etc/dictionary/dictionary.h3c rename src/auth/{eap_peap_session.py => session.py} (93%) diff --git a/etc/dictionary/dictionary.h3c b/etc/dictionary/dictionary.h3c new file mode 100644 index 00000000..1a05d103 --- /dev/null +++ b/etc/dictionary/dictionary.h3c @@ -0,0 +1,60 @@ +# -*- text -*- +# Copyright (C) 2019 The FreeRADIUS Server project and contributors +# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0 +# +############################################################################## +# +# Dictionary for Huawei-3Com. See also dictionary.huawei +# +# http://www.h3c.com +# +# $Id: 26d8612a0392298b9f54f84bcbad7ad91b898f9c $ +# +############################################################################## + +VENDOR H3C 25506 + +BEGIN-VENDOR H3C + +ATTRIBUTE H3C-Input-Peak-Rate 1 integer +ATTRIBUTE H3C-Input-Average-Rate 2 integer +ATTRIBUTE H3C-Input-Basic-Rate 3 integer +ATTRIBUTE H3C-Output-Peak-Rate 4 integer +ATTRIBUTE H3C-Output-Average-Rate 5 integer +ATTRIBUTE H3C-Output-Basic-Rate 6 integer +ATTRIBUTE H3C-Remanent-Volume 15 integer +ATTRIBUTE H3C-Command 20 integer + +VALUE H3C-Command Trigger-Request 1 +VALUE H3C-Command Terminate-Request 2 +VALUE H3C-Command SetPolicy 3 +VALUE H3C-Command Result 4 +VALUE H3C-Command PortalClear 5 + +ATTRIBUTE H3C-Control-Identifier 24 integer +ATTRIBUTE H3C-Result-Code 25 integer +ATTRIBUTE H3C-Connect_Id 26 integer +ATTRIBUTE H3C-Ftp-Directory 28 string +ATTRIBUTE H3C-Exec-Privilege 29 integer + +VALUE H3C-Exec-Privilege Visit 0 +VALUE H3C-Exec-Privilege Monitor 1 +VALUE H3C-Exec-Privilege System 2 +VALUE H3C-Exec-Privilege Manage 33 + +ATTRIBUTE H3C-NAS-Startup-Timestamp 59 integer +ATTRIBUTE H3C-Ip-Host-Addr 60 string +ATTRIBUTE H3C-User-Notify 61 string +ATTRIBUTE H3C-User-HeartBeat 62 string +ATTRIBUTE H3C-User-Group 140 string +ATTRIBUTE H3C-Security-Level 141 integer +ATTRIBUTE H3C-Input-Interval-Octets 201 integer +ATTRIBUTE H3C-Output-Interval-Octets 202 integer +ATTRIBUTE H3C-Input-Interval-Packets 203 integer +ATTRIBUTE H3C-Output-Interval-Packets 204 integer +ATTRIBUTE H3C-Input-Interval-Gigawords 205 integer +ATTRIBUTE H3C-Output-Interval-Gigawords 206 integer +ATTRIBUTE H3C-Backup-NAS-IP 207 ipaddr +ATTRIBUTE H3C-Product-ID 255 string + +END-VENDOR H3C diff --git a/src/auth/eap_peap_gtc_flow.py b/src/auth/eap_peap_gtc_flow.py index cd605995..aa483305 100644 --- a/src/auth/eap_peap_gtc_flow.py +++ b/src/auth/eap_peap_gtc_flow.py @@ -10,7 +10,7 @@ from child_pyrad.eap_packet import EapPacket from child_pyrad.eap_peap_packet import EapPeapPacket from child_pyrad.mppe import create_mppe_recv_key_send_key -from auth.eap_peap_session import EapPeapSession, SessionCache +from auth.session import EapPeapSession, SessionCache from settings import libhostapd from loguru import logger as log @@ -30,7 +30,7 @@ def authenticate(cls, request: AuthRequest, auth_user: AuthUser): if 'State' in request: session_id: str = request['State'][0].decode() # 2. 从redis获取会话 - session = SessionCache.load_and_housekeeping(session_id=session_id) # 旧会话 + session: EapPeapSession = SessionCache.load_and_housekeeping(session_id=session_id) # 旧会话 if not session: # 携带 State 字段表示之前已经认证成功, 现在再申请连入网络 # 必须是 PEAP-Start 前的 identity 报文, 例如: EAP-Message: ['\x02\x01\x00\r\x01testuser'] diff --git a/src/auth/eap_peap_mschapv2_flow.py b/src/auth/eap_peap_mschapv2_flow.py index 2e0721bb..86dbed95 100644 --- a/src/auth/eap_peap_mschapv2_flow.py +++ b/src/auth/eap_peap_mschapv2_flow.py @@ -11,7 +11,7 @@ from child_pyrad.eap_mschapv2_packet import EapMschapv2Packet from child_pyrad.eap_peap_packet import EapPeapPacket from child_pyrad.mppe import create_mppe_recv_key_send_key -from auth.eap_peap_session import EapPeapSession, SessionCache +from auth.session import EapPeapSession, SessionCache from settings import libhostapd from loguru import logger as log @@ -32,7 +32,7 @@ def authenticate(cls, request: AuthRequest, auth_user: AuthUser): if 'State' in request: session_id: str = request['State'][0].decode() # 2. 从redis获取会话 - session = SessionCache.load_and_housekeeping(session_id=session_id) # 旧会话 + session: EapPeapSession = SessionCache.load_and_housekeeping(session_id=session_id) # 旧会话 if not session: # 携带 State 字段表示之前已经认证成功, 现在再申请连入网络 # 必须是 PEAP-Start 前的 identity 报文, 例如: EAP-Message: ['\x02\x01\x00\r\x01testuser'] diff --git a/src/auth/mschap_flow.py b/src/auth/mschap_flow.py index 86a58061..07220275 100644 --- a/src/auth/mschap_flow.py +++ b/src/auth/mschap_flow.py @@ -7,6 +7,7 @@ from controls.user import AuthUser from models.account import Account from models.platform import Platform +from auth.session import BaseSession from settings import libhostapd @@ -14,8 +15,9 @@ class MsChapFlow(Flow): @classmethod def authenticate(cls, request: AuthRequest, auth_user: AuthUser): + session = BaseSession(auth_user=auth_user) # 查找用户密码 - account_name = auth_user.outer_username + account_name = session.auth_user.outer_username account = Account.get(username=account_name) if not account: raise AccessReject() @@ -28,11 +30,11 @@ def authenticate(cls, request: AuthRequest, auth_user: AuthUser): log.error(f'platform ssid not match. platform_ssid: {platform.ssid}, request.ssid: {request.ssid}') raise AccessReject() # 保存用户密码 - auth_user.set_user_password(account.radius_password) + session.auth_user.set_user_password(account.radius_password) ################ - username = auth_user.outer_username - user_password = auth_user.user_password + username = session.auth_user.outer_username + user_password = session.auth_user.user_password auth_challenge: bytes = request['MS-CHAP-Challenge'][0] """ Microsoft Vendor-specific RADIUS Attributes: https://tools.ietf.org/html/rfc2548 @@ -87,17 +89,18 @@ def is_correct_password() -> bool: # 42字节 authenticator_response: bytes = ctypes.string_at(p_out_auth_response, len(p_out_auth_response)) authenticator_response: bytes = b'S=' + authenticator_response.hex().upper().encode() - ms_chap2_success = ident + authenticator_response + ms_chap2_success: bytes = ident + authenticator_response + session.extra['MS-CHAP2-Success'] = ms_chap2_success ################ if is_correct_password(): - return cls.access_accept(request=request, ms_chap2_success=ms_chap2_success) + return cls.access_accept(request=request, session=session) else: - log.error(f'user_password: {auth_user.user_password} not correct') + log.error(f'user_password: {session.auth_user.user_password} not correct') raise AccessReject() @classmethod - def access_accept(cls, request: AuthRequest, ms_chap2_success: bytes): + def access_accept(cls, request: AuthRequest, session: BaseSession): data = [ 'MS-CHAPv2', request.username, @@ -107,5 +110,5 @@ def access_accept(cls, request: AuthRequest, ms_chap2_success: bytes): ] log.info(f'OUT: accept|{"|".join(data)}|') reply = AuthResponse.create_access_accept(request=request) - reply['MS-CHAP2-Success'] = ms_chap2_success + reply['MS-CHAP2-Success'] = session.extra['MS-CHAP2-Success'] return request.reply_to(reply) diff --git a/src/auth/eap_peap_session.py b/src/auth/session.py similarity index 93% rename from src/auth/eap_peap_session.py rename to src/auth/session.py index 47938c57..53e363c8 100644 --- a/src/auth/eap_peap_session.py +++ b/src/auth/session.py @@ -9,11 +9,20 @@ from loguru import logger as log -class EapPeapSession(object): +class BaseSession(object): + + def __init__(self, auth_user: AuthUser): + self.auth_user: AuthUser = auth_user + self.reply: AuthPacket = None + self.extra = dict() + + +class EapPeapSession(BaseSession): def __init__(self, auth_user: AuthUser, session_id: str): # 该保存入Redis Session; 读取Session时, 恢复所有变量! assert isinstance(session_id, str) + super(self.__class__, self).__init__(auth_user=auth_user) self.session_id: str = session_id self.next_state = Flow.PEAP_CHALLENGE_START self.peap_version: int = 1 @@ -21,8 +30,6 @@ def __init__(self, auth_user: AuthUser, session_id: str): self.prev_eap_id: int = -1 # 用于检查是否重发消息 self.current_eap_id: int = -1 # - self.auth_user: AuthUser = auth_user - self.reply: AuthPacket = None self.update_time = datetime.datetime.now() # self.msk: bytes = b'' # Master Session Key diff --git a/src/child_pyrad/packet.py b/src/child_pyrad/packet.py index 493e313e..69c2cf72 100644 --- a/src/child_pyrad/packet.py +++ b/src/child_pyrad/packet.py @@ -94,6 +94,8 @@ def create_access_accept(cls, request: AuthRequest) -> AuthPacket: # reply = request.create_reply(code=Packet.CODE_ACCESS_ACCEPT) # reply['Session-Timeout'] = 600 # 用户可用的剩余时间 + # reply['H3C-Input-Peak-Rate'] = int(self.bandwidth_max_up) # 用户到NAS的峰值速率, 以bps为单位. 1/8字节每秒 + # reply['H3C-Output-Peak-Rate'] = int(self.bandwidth_max_down) # NAS到用户的峰值速率, 以bps为单位. 1/8字节每秒 reply['Idle-Timeout'] = 86400 # 用户的闲置切断时间 reply['Acct-Interim-Interval'] = ACCOUNTING_INTERVAL # reply['Class'] = '\x7f'.join(('EAP-PEAP', session.auth_user.peap_username, session.session_id)) # Access-Accept发送给AC, AC在计费报文内会携带Class值上报 From eec588070119fbd22cecfa55c31d7c99da66be51 Mon Sep 17 00:00:00 2001 From: zeroleo12345 Date: Sat, 27 Mar 2021 12:55:16 +0800 Subject: [PATCH 02/15] add --- src/auth/chap_flow.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/auth/chap_flow.py b/src/auth/chap_flow.py index 66b3e26a..ef623b5c 100644 --- a/src/auth/chap_flow.py +++ b/src/auth/chap_flow.py @@ -6,32 +6,34 @@ from controls.user import AuthUser from models.account import Account from child_pyrad.chap import Chap +from auth.session import BaseSession class ChapFlow(Flow): @classmethod def authenticate(cls, request: AuthRequest, auth_user: AuthUser): + session = BaseSession(auth_user=auth_user) # 查找用户密码 - account_name = auth_user.outer_username + account_name = session.auth_user.outer_username user = Account.get(username=account_name) if not user: raise AccessReject() else: # 保存用户密码 - auth_user.set_user_password(user.password) + session.auth_user.set_user_password(user.password) def is_correct_password() -> bool: - return Chap.is_correct_challenge_value(request=request, user_password=auth_user.user_password) + return Chap.is_correct_challenge_value(request=request, user_password=session.auth_user.user_password) if is_correct_password(): - return cls.access_accept(request=request) + return cls.access_accept(request=request, session=session) else: - log.error(f'user_password: {auth_user.user_password} not correct') + log.error(f'user_password: {session.auth_user.user_password} not correct') raise AccessReject() @classmethod - def access_accept(cls, request: AuthRequest): + def access_accept(cls, request: AuthRequest, session: BaseSession): data = [ 'CHAP', request.username, From 944d01e35f66c9ba068abca1df3003dc18ed6d0a Mon Sep 17 00:00:00 2001 From: zeroleo12345 Date: Sat, 27 Mar 2021 12:57:31 +0800 Subject: [PATCH 03/15] add --- src/auth/pap_flow.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/auth/pap_flow.py b/src/auth/pap_flow.py index dc9236a1..251b77ed 100644 --- a/src/auth/pap_flow.py +++ b/src/auth/pap_flow.py @@ -8,31 +8,33 @@ from loguru import logger as log from controls.user import AuthUser from models.mac_account import MacAccount +from auth.session import BaseSession class PapFlow(Flow): @classmethod def authenticate(cls, request: AuthRequest, auth_user: AuthUser): + session = BaseSession(auth_user=auth_user) # 获取报文 encrypt_password = request['User-Password'][0] # 密码解密 decrypt_password = request.PwCrypt(password=encrypt_password) - auth_user.user_password = decrypt_password.decode().split('\x00', 1)[0] + session.auth_user.user_password = decrypt_password.decode().split('\x00', 1)[0] # User-Name: '5af3ce3a0959' # User-Password: '5af3ce3a0959\x00\x00\x00\x00' # 验证方法 - if request.user_mac.replace('-', '').lower() == auth_user.outer_username: - return cls.mac_auth(request=request, auth_user=auth_user) + if request.user_mac.replace('-', '').lower() == session.auth_user.outer_username: + return cls.mac_auth(request=request, session=session) else: - return cls.pap_auth(request=request, auth_user=auth_user) + return cls.pap_auth(request=request, session=session) @classmethod - def mac_auth(cls, request: AuthRequest, auth_user: AuthUser): + def mac_auth(cls, request: AuthRequest, session: BaseSession): # mac Flow: 用户不存在则创建 - account = MacAccount.get(username=auth_user.outer_username) + account = MacAccount.get(username=session.auth_user.outer_username) if not account: redis = get_redis() key = 'enable_mac_authentication' @@ -43,17 +45,17 @@ def mac_auth(cls, request: AuthRequest, auth_user: AuthUser): created_at = datetime.datetime.now() expired_at = created_at + datetime.timedelta(days=3600) MacAccount.create( - username=auth_user.outer_username, radius_password=auth_user.user_password, is_enable=True, ap_mac=request.ap_mac, + username=session.auth_user.outer_username, radius_password=session.auth_user.user_password, is_enable=True, ap_mac=request.ap_mac, expired_at=expired_at, created_at=created_at, ) - sentry_sdk.capture_message(f'新增放通 MAC 设备, mac_address: {auth_user.user_mac}, ssid: {request.ssid}') + sentry_sdk.capture_message(f'新增放通 MAC 设备, mac_address: {session.auth_user.user_mac}, ssid: {request.ssid}') redis.delete(key) return cls.access_accept(request=request, auth_method='MAC-PAP') @classmethod - def pap_auth(cls, request: AuthRequest, auth_user: AuthUser): - log.info(f'PAP username: {request.username}, password: {auth_user.user_password}') + def pap_auth(cls, request: AuthRequest, session: BaseSession): + log.info(f'PAP username: {request.username}, password: {session.auth_user.user_password}') return cls.access_accept(request=request, auth_method='PAP') @classmethod From 00efa871d4e50de0a173a2e8c6335ad55655db09 Mon Sep 17 00:00:00 2001 From: zeroleo12345 Date: Sat, 27 Mar 2021 13:02:00 +0800 Subject: [PATCH 04/15] add --- src/auth/pap_flow.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/auth/pap_flow.py b/src/auth/pap_flow.py index 251b77ed..265e9641 100644 --- a/src/auth/pap_flow.py +++ b/src/auth/pap_flow.py @@ -51,17 +51,19 @@ def mac_auth(cls, request: AuthRequest, session: BaseSession): sentry_sdk.capture_message(f'新增放通 MAC 设备, mac_address: {session.auth_user.user_mac}, ssid: {request.ssid}') redis.delete(key) - return cls.access_accept(request=request, auth_method='MAC-PAP') + session.extra['Auth-Type'] = 'MAC-PAP' + return cls.access_accept(request=request, session=session) @classmethod def pap_auth(cls, request: AuthRequest, session: BaseSession): log.info(f'PAP username: {request.username}, password: {session.auth_user.user_password}') - return cls.access_accept(request=request, auth_method='PAP') + session.extra['Auth-Type'] = 'PAP' + return cls.access_accept(request=request, session=session) @classmethod - def access_accept(cls, request: AuthRequest, auth_method: str): + def access_accept(cls, request: AuthRequest, session: BaseSession): data = [ - auth_method, + session.extra['Auth-Type'], request.username, request.user_mac, request.ssid, From 43d8efa22da96787da90f834cfd6d90f409c70f2 Mon Sep 17 00:00:00 2001 From: zeroleo12345 Date: Sat, 27 Mar 2021 13:11:35 +0800 Subject: [PATCH 05/15] fix --- src/auth/session.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/auth/session.py b/src/auth/session.py index 53e363c8..b732f005 100644 --- a/src/auth/session.py +++ b/src/auth/session.py @@ -3,7 +3,6 @@ from pyrad.packet import AuthPacket # 项目库 from auth.flow import Flow -from child_pyrad.eap_peap_packet import EapPeapPacket from controls.user import AuthUser from settings import libhostapd from loguru import logger as log @@ -33,7 +32,7 @@ def __init__(self, auth_user: AuthUser, session_id: str): self.update_time = datetime.datetime.now() # self.msk: bytes = b'' # Master Session Key - self.certificate_fragment: EapPeapPacket = None + self.certificate_fragment: 'EapPeapPacket' = None self.tls_connection = None def set_peap_version(self, version): From b5b2ec51014b570b4e2d4a61b2d8a91d29fbca02 Mon Sep 17 00:00:00 2001 From: zeroleo12345 Date: Sat, 27 Mar 2021 13:13:14 +0800 Subject: [PATCH 06/15] fix --- src/auth/session.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/auth/session.py b/src/auth/session.py index b732f005..53e363c8 100644 --- a/src/auth/session.py +++ b/src/auth/session.py @@ -3,6 +3,7 @@ from pyrad.packet import AuthPacket # 项目库 from auth.flow import Flow +from child_pyrad.eap_peap_packet import EapPeapPacket from controls.user import AuthUser from settings import libhostapd from loguru import logger as log @@ -32,7 +33,7 @@ def __init__(self, auth_user: AuthUser, session_id: str): self.update_time = datetime.datetime.now() # self.msk: bytes = b'' # Master Session Key - self.certificate_fragment: 'EapPeapPacket' = None + self.certificate_fragment: EapPeapPacket = None self.tls_connection = None def set_peap_version(self, version): From 8ed406a684335ec7edac111fbdb2bd065b7834c5 Mon Sep 17 00:00:00 2001 From: zeroleo12345 Date: Sat, 27 Mar 2021 13:15:05 +0800 Subject: [PATCH 07/15] fix --- src/auth/session.py | 5 ++++- src/child_pyrad/packet.py | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/auth/session.py b/src/auth/session.py index 53e363c8..73d7a05f 100644 --- a/src/auth/session.py +++ b/src/auth/session.py @@ -3,10 +3,13 @@ from pyrad.packet import AuthPacket # 项目库 from auth.flow import Flow -from child_pyrad.eap_peap_packet import EapPeapPacket from controls.user import AuthUser from settings import libhostapd from loguru import logger as log +# +import typing +if typing.TYPE_CHECKING: + from child_pyrad.eap_peap_packet import EapPeapPacket class BaseSession(object): diff --git a/src/child_pyrad/packet.py b/src/child_pyrad/packet.py index 69c2cf72..154d29ae 100644 --- a/src/child_pyrad/packet.py +++ b/src/child_pyrad/packet.py @@ -3,10 +3,13 @@ # 项目库 from .exception import AuthenticatorError from .eap_packet import EapPacket -from .eap_peap_packet import EapPeapPacket from controls.stat import ApStat, UserStat from loguru import logger as log from settings import ACCOUNTING_INTERVAL +# +import typing +if typing.TYPE_CHECKING: + from .eap_peap_packet import EapPeapPacket class Packet(object): From c5b8ceead5e11ad8b1ceb8448e76389079668323 Mon Sep 17 00:00:00 2001 From: zeroleo12345 Date: Sat, 27 Mar 2021 13:20:36 +0800 Subject: [PATCH 08/15] fix --- src/child_pyrad/packet.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/child_pyrad/packet.py b/src/child_pyrad/packet.py index 154d29ae..69c2cf72 100644 --- a/src/child_pyrad/packet.py +++ b/src/child_pyrad/packet.py @@ -3,13 +3,10 @@ # 项目库 from .exception import AuthenticatorError from .eap_packet import EapPacket +from .eap_peap_packet import EapPeapPacket from controls.stat import ApStat, UserStat from loguru import logger as log from settings import ACCOUNTING_INTERVAL -# -import typing -if typing.TYPE_CHECKING: - from .eap_peap_packet import EapPeapPacket class Packet(object): From f68ce37b37c72649e4283e8ab8856b4275ef4b47 Mon Sep 17 00:00:00 2001 From: zeroleo12345 Date: Sat, 27 Mar 2021 13:22:03 +0800 Subject: [PATCH 09/15] fix --- src/auth/session.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/auth/session.py b/src/auth/session.py index 73d7a05f..53e363c8 100644 --- a/src/auth/session.py +++ b/src/auth/session.py @@ -3,13 +3,10 @@ from pyrad.packet import AuthPacket # 项目库 from auth.flow import Flow +from child_pyrad.eap_peap_packet import EapPeapPacket from controls.user import AuthUser from settings import libhostapd from loguru import logger as log -# -import typing -if typing.TYPE_CHECKING: - from child_pyrad.eap_peap_packet import EapPeapPacket class BaseSession(object): From b1f5abac86dc659f41d14cea594a8e04eecf57c8 Mon Sep 17 00:00:00 2001 From: zeroleo12345 Date: Sat, 27 Mar 2021 13:31:25 +0800 Subject: [PATCH 10/15] rename user -> account --- src/acct/accounting_flow.py | 4 ++-- src/auth/chap_flow.py | 7 ++++--- src/auth/eap_peap_gtc_flow.py | 9 +++++---- src/auth/eap_peap_mschapv2_flow.py | 7 ++++--- src/auth/mschap_flow.py | 1 + src/child_pyrad/packet.py | 7 ++++--- src/controls/user.py | 4 ++++ src/models/account.py | 1 + src/processor/sync_user.py | 18 +++++++++--------- 9 files changed, 34 insertions(+), 24 deletions(-) diff --git a/src/acct/accounting_flow.py b/src/acct/accounting_flow.py index 08287113..0b35ce37 100644 --- a/src/acct/accounting_flow.py +++ b/src/acct/accounting_flow.py @@ -16,8 +16,8 @@ def accounting(cls, request: AcctRequest, acct_user: AcctUser): log.debug(f'IN: {request.iut}|{acct_user.outer_username}|{acct_user.user_mac}') # 查找用户密码 - user = Account.get(username=acct_user.outer_username) - if not user: + account = Account.get(username=acct_user.outer_username) + if not account: return # 每隔x秒清理会话 diff --git a/src/auth/chap_flow.py b/src/auth/chap_flow.py index ef623b5c..87ad3ffe 100644 --- a/src/auth/chap_flow.py +++ b/src/auth/chap_flow.py @@ -16,12 +16,13 @@ def authenticate(cls, request: AuthRequest, auth_user: AuthUser): session = BaseSession(auth_user=auth_user) # 查找用户密码 account_name = session.auth_user.outer_username - user = Account.get(username=account_name) - if not user: + account: Account = Account.get(username=account_name) + if not account: raise AccessReject() else: # 保存用户密码 - session.auth_user.set_user_password(user.password) + session.auth_user.set_user_password(account.password) + session.auth_user.set_user_speed(account.speed) def is_correct_password() -> bool: return Chap.is_correct_challenge_value(request=request, user_password=session.auth_user.user_password) diff --git a/src/auth/eap_peap_gtc_flow.py b/src/auth/eap_peap_gtc_flow.py index aa483305..e3e1abe5 100644 --- a/src/auth/eap_peap_gtc_flow.py +++ b/src/auth/eap_peap_gtc_flow.py @@ -230,12 +230,13 @@ def peap_challenge_gtc_password(cls, request: AuthRequest, eap: EapPacket, peap: session.auth_user.set_peap_username(account_name) # 查找用户密码 - user = Account.get(username=account_name) - if not user: + account = Account.get(username=account_name) + if not account: raise AccessReject() else: # 保存用户密码 - session.auth_user.set_user_password(user.radius_password) + session.auth_user.set_user_password(account.radius_password) + session.auth_user.set_user_speed(account.speed) # 返回数据 response_data = b'Password' @@ -262,7 +263,7 @@ def peap_challenge_success(cls, request: AuthRequest, eap: EapPacket, peap: EapP tls_decrypt_data = libhostapd.decrypt(session.tls_connection, peap.tls_data) eap_password = EapPacket.parse(packet=tls_decrypt_data) auth_password = eap_password.type_data.decode() - log.debug(f'PEAP account: {session.auth_user.peap_username}, packet_password: {auth_password}') + log.debug(f'PEAP user: {session.auth_user.peap_username}, packet_password: {auth_password}') def is_correct_password() -> bool: return session.auth_user.user_password == auth_password diff --git a/src/auth/eap_peap_mschapv2_flow.py b/src/auth/eap_peap_mschapv2_flow.py index 86dbed95..21230863 100644 --- a/src/auth/eap_peap_mschapv2_flow.py +++ b/src/auth/eap_peap_mschapv2_flow.py @@ -239,12 +239,13 @@ def peap_challenge_mschapv2_random(cls, request: AuthRequest, eap: EapPacket, pe # 保存用户名 session.auth_user.set_peap_username(account_name) # 查找用户密码 - user = Account.get(username=account_name) - if not user: + account = Account.get(username=account_name) + if not account: raise AccessReject() else: # 保存用户密码 - session.auth_user.set_user_password(user.radius_password) + session.auth_user.set_user_password(account.radius_password) + session.auth_user.set_user_speed(account.speed) # 返回数据 # MSCHAPV2_OP_CHALLENGE(01) + 与EAP_id相同(07) + MSCHAPV2_OP 到结束的长度(00 1c) + diff --git a/src/auth/mschap_flow.py b/src/auth/mschap_flow.py index 07220275..4643cf86 100644 --- a/src/auth/mschap_flow.py +++ b/src/auth/mschap_flow.py @@ -31,6 +31,7 @@ def authenticate(cls, request: AuthRequest, auth_user: AuthUser): raise AccessReject() # 保存用户密码 session.auth_user.set_user_password(account.radius_password) + session.auth_user.set_user_speed(account.speed) ################ username = session.auth_user.outer_username diff --git a/src/child_pyrad/packet.py b/src/child_pyrad/packet.py index 69c2cf72..4cc8a9a9 100644 --- a/src/child_pyrad/packet.py +++ b/src/child_pyrad/packet.py @@ -6,6 +6,7 @@ from .eap_peap_packet import EapPeapPacket from controls.stat import ApStat, UserStat from loguru import logger as log +from auth.session import BaseSession from settings import ACCOUNTING_INTERVAL @@ -88,14 +89,14 @@ class AuthResponse(AuthPacket): # 使用父类初始化自己 @classmethod - def create_access_accept(cls, request: AuthRequest) -> AuthPacket: + def create_access_accept(cls, request: AuthRequest, session: BaseSession) -> AuthPacket: UserStat.report_user_online(username=request.username, user_mac=request.user_mac, ap_mac=request.ap_mac) ApStat.report_ap_online(username=request.username, ap_mac=request.ap_mac) # reply = request.create_reply(code=Packet.CODE_ACCESS_ACCEPT) # reply['Session-Timeout'] = 600 # 用户可用的剩余时间 - # reply['H3C-Input-Peak-Rate'] = int(self.bandwidth_max_up) # 用户到NAS的峰值速率, 以bps为单位. 1/8字节每秒 - # reply['H3C-Output-Peak-Rate'] = int(self.bandwidth_max_down) # NAS到用户的峰值速率, 以bps为单位. 1/8字节每秒 + reply['H3C-Input-Peak-Rate'] = int(self.bandwidth_max_up) # 用户到NAS的峰值速率, 以bps为单位. 1/8字节每秒 + reply['H3C-Output-Peak-Rate'] = int(self.bandwidth_max_down) # NAS到用户的峰值速率, 以bps为单位. 1/8字节每秒 reply['Idle-Timeout'] = 86400 # 用户的闲置切断时间 reply['Acct-Interim-Interval'] = ACCOUNTING_INTERVAL # reply['Class'] = '\x7f'.join(('EAP-PEAP', session.auth_user.peap_username, session.session_id)) # Access-Accept发送给AC, AC在计费报文内会携带Class值上报 diff --git a/src/controls/user.py b/src/controls/user.py index dc50d5b8..aaca7198 100644 --- a/src/controls/user.py +++ b/src/controls/user.py @@ -10,6 +10,7 @@ def __init__(self, request: AuthRequest): self.peap_username: str = '' self.user_mac = request.user_mac # mac地址 self.user_password: str = '' + self.user_speed: int = 0 self.server_challenge: bytes = b'' self.peer_challenge: bytes = b'' @@ -19,6 +20,9 @@ def set_peap_username(self, account_name: str): def set_user_password(self, password: str): self.user_password = password + def set_user_speed(self, speed: int): + self.user_speed = speed + def set_server_challenge(self, server_challenge: bytes): self.server_challenge = server_challenge diff --git a/src/models/account.py b/src/models/account.py index 2e0ab7de..90448359 100644 --- a/src/models/account.py +++ b/src/models/account.py @@ -22,6 +22,7 @@ class Role(ModelEnum): password = Column(String(255)) radius_password = Column(String(255)) role = Column(String(32)) + speed = Column(String(32)) expired_at = Column(DateTime) def __repr__(self): diff --git a/src/processor/sync_user.py b/src/processor/sync_user.py index 37a775e6..cb22d94c 100755 --- a/src/processor/sync_user.py +++ b/src/processor/sync_user.py @@ -38,19 +38,19 @@ def run(self): # expired_at_dt = parse(expired_at) # datetime 类型 expired_at_str = expired_at_dt.strftime('%Y-%m-%d %H:%M:%S') # 字符串类型 - user = session.query(Account).filter(Account.username == username).first() - if not user: - new_user = Account(username=username, password=password, expired_at=expired_at_dt) - session.add(new_user) + account = session.query(Account).filter(Account.username == username).first() + if not account: + new_account = Account(username=username, password=password, expired_at=expired_at_dt) + session.add(new_account) session.commit() - log.info(f'insert user: {username}') + log.info(f'insert account: {username}') else: # sync 同步用户 - if user.expired_at.strftime('%Y-%m-%d %H:%M:%S') != expired_at_str or user.password != password: - user.expired_at = expired_at_dt - user.password = password + if account.expired_at.strftime('%Y-%m-%d %H:%M:%S') != expired_at_str or account.password != password: + account.expired_at = expired_at_dt + account.password = password session.commit() - log.info(f'update user: {user.username}') + log.info(f'update account: {account.username}') TaskLoop().start() From d6f65195fbd94de22556625da34bad6e3b1eef34 Mon Sep 17 00:00:00 2001 From: zeroleo12345 Date: Sat, 27 Mar 2021 13:33:59 +0800 Subject: [PATCH 11/15] fix --- src/models/account.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/account.py b/src/models/account.py index 90448359..4bf142b4 100644 --- a/src/models/account.py +++ b/src/models/account.py @@ -22,7 +22,7 @@ class Role(ModelEnum): password = Column(String(255)) radius_password = Column(String(255)) role = Column(String(32)) - speed = Column(String(32)) + speed = Column(Integer) expired_at = Column(DateTime) def __repr__(self): From d6e148e677466dce2717a485bfb6687c995293bc Mon Sep 17 00:00:00 2001 From: zeroleo12345 Date: Sat, 27 Mar 2021 13:36:03 +0800 Subject: [PATCH 12/15] fix --- src/auth/chap_flow.py | 2 +- src/auth/eap_peap_gtc_flow.py | 2 +- src/auth/eap_peap_mschapv2_flow.py | 2 +- src/auth/mschap_flow.py | 2 +- src/auth/pap_flow.py | 2 +- src/child_pyrad/packet.py | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/auth/chap_flow.py b/src/auth/chap_flow.py index 87ad3ffe..1671b9f4 100644 --- a/src/auth/chap_flow.py +++ b/src/auth/chap_flow.py @@ -43,7 +43,7 @@ def access_accept(cls, request: AuthRequest, session: BaseSession): request.ap_mac, ] log.info(f'OUT: accept|{"|".join(data)}|') - reply = AuthResponse.create_access_accept(request=request) + reply = AuthResponse.create_access_accept(request=request, session=session) return request.reply_to(reply) @classmethod diff --git a/src/auth/eap_peap_gtc_flow.py b/src/auth/eap_peap_gtc_flow.py index e3e1abe5..98a366af 100644 --- a/src/auth/eap_peap_gtc_flow.py +++ b/src/auth/eap_peap_gtc_flow.py @@ -310,7 +310,7 @@ def access_accept(cls, request: AuthRequest, session: EapPeapSession): request.ap_mac, ] log.info(f'OUT: accept|{"|".join(data)}|') - reply = AuthResponse.create_access_accept(request=request) + reply = AuthResponse.create_access_accept(request=request, session=session) reply['State'] = session.session_id.encode() # octets log.debug(f'msk: {session.msk}, secret: {reply.secret}, authenticator: {request.authenticator}') reply['MS-MPPE-Recv-Key'], reply['MS-MPPE-Send-Key'] = create_mppe_recv_key_send_key(session.msk, reply.secret, request.authenticator) diff --git a/src/auth/eap_peap_mschapv2_flow.py b/src/auth/eap_peap_mschapv2_flow.py index 21230863..84db032f 100644 --- a/src/auth/eap_peap_mschapv2_flow.py +++ b/src/auth/eap_peap_mschapv2_flow.py @@ -437,7 +437,7 @@ def access_accept(cls, request: AuthRequest, session: EapPeapSession): request.ap_mac, ] log.info(f'OUT: accept|{"|".join(data)}|') - reply = AuthResponse.create_access_accept(request=request) + reply = AuthResponse.create_access_accept(request=request, session=session) reply['State'] = session.session_id.encode() log.trace(f'msk: {session.msk}, secret: {reply.secret}, authenticator: {request.authenticator}') reply['MS-MPPE-Recv-Key'], reply['MS-MPPE-Send-Key'] = create_mppe_recv_key_send_key(session.msk, reply.secret, request.authenticator) diff --git a/src/auth/mschap_flow.py b/src/auth/mschap_flow.py index 4643cf86..e1952ec2 100644 --- a/src/auth/mschap_flow.py +++ b/src/auth/mschap_flow.py @@ -110,6 +110,6 @@ def access_accept(cls, request: AuthRequest, session: BaseSession): request.ap_mac, ] log.info(f'OUT: accept|{"|".join(data)}|') - reply = AuthResponse.create_access_accept(request=request) + reply = AuthResponse.create_access_accept(request=request, session=session) reply['MS-CHAP2-Success'] = session.extra['MS-CHAP2-Success'] return request.reply_to(reply) diff --git a/src/auth/pap_flow.py b/src/auth/pap_flow.py index 265e9641..80879041 100644 --- a/src/auth/pap_flow.py +++ b/src/auth/pap_flow.py @@ -70,5 +70,5 @@ def access_accept(cls, request: AuthRequest, session: BaseSession): request.ap_mac, ] log.info(f'OUT: accept|{"|".join(data)}|') - reply = AuthResponse.create_access_accept(request=request) + reply = AuthResponse.create_access_accept(request=request, session=session) return request.reply_to(reply) diff --git a/src/child_pyrad/packet.py b/src/child_pyrad/packet.py index 4cc8a9a9..38d0799b 100644 --- a/src/child_pyrad/packet.py +++ b/src/child_pyrad/packet.py @@ -95,8 +95,8 @@ def create_access_accept(cls, request: AuthRequest, session: BaseSession) -> Aut # reply = request.create_reply(code=Packet.CODE_ACCESS_ACCEPT) # reply['Session-Timeout'] = 600 # 用户可用的剩余时间 - reply['H3C-Input-Peak-Rate'] = int(self.bandwidth_max_up) # 用户到NAS的峰值速率, 以bps为单位. 1/8字节每秒 - reply['H3C-Output-Peak-Rate'] = int(self.bandwidth_max_down) # NAS到用户的峰值速率, 以bps为单位. 1/8字节每秒 + reply['H3C-Input-Peak-Rate'] = session.auth_user.user_speed / 4 # 上传速度. 用户到NAS的峰值速率, 以bps为单位. 1/8字节每秒 + reply['H3C-Output-Peak-Rate'] = session.auth_user.user_speed # 下载速度. NAS到用户的峰值速率, 以bps为单位. 1/8字节每秒 reply['Idle-Timeout'] = 86400 # 用户的闲置切断时间 reply['Acct-Interim-Interval'] = ACCOUNTING_INTERVAL # reply['Class'] = '\x7f'.join(('EAP-PEAP', session.auth_user.peap_username, session.session_id)) # Access-Accept发送给AC, AC在计费报文内会携带Class值上报 From ce19574e0bb865cd85948f8f1911b0c67d876960 Mon Sep 17 00:00:00 2001 From: zeroleo12345 Date: Sat, 27 Mar 2021 13:39:27 +0800 Subject: [PATCH 13/15] fix --- src/child_pyrad/packet.py | 4 ++-- src/controls/user.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/child_pyrad/packet.py b/src/child_pyrad/packet.py index 38d0799b..ab4bb861 100644 --- a/src/child_pyrad/packet.py +++ b/src/child_pyrad/packet.py @@ -95,8 +95,8 @@ def create_access_accept(cls, request: AuthRequest, session: BaseSession) -> Aut # reply = request.create_reply(code=Packet.CODE_ACCESS_ACCEPT) # reply['Session-Timeout'] = 600 # 用户可用的剩余时间 - reply['H3C-Input-Peak-Rate'] = session.auth_user.user_speed / 4 # 上传速度. 用户到NAS的峰值速率, 以bps为单位. 1/8字节每秒 - reply['H3C-Output-Peak-Rate'] = session.auth_user.user_speed # 下载速度. NAS到用户的峰值速率, 以bps为单位. 1/8字节每秒 + reply['H3C-Input-Peak-Rate'] = session.auth_user.user_speed * 1024 * 1024 * 8 / 4 # 上传速度. 用户到NAS的峰值速率, 以bps为单位. 1/8字节每秒 + reply['H3C-Output-Peak-Rate'] = session.auth_user.user_speed * 1024 * 1024 * 8 # 下载速度. NAS到用户的峰值速率, 以bps为单位. 1/8字节每秒 reply['Idle-Timeout'] = 86400 # 用户的闲置切断时间 reply['Acct-Interim-Interval'] = ACCOUNTING_INTERVAL # reply['Class'] = '\x7f'.join(('EAP-PEAP', session.auth_user.peap_username, session.session_id)) # Access-Accept发送给AC, AC在计费报文内会携带Class值上报 diff --git a/src/controls/user.py b/src/controls/user.py index aaca7198..c4c0e905 100644 --- a/src/controls/user.py +++ b/src/controls/user.py @@ -8,9 +8,9 @@ def __init__(self, request: AuthRequest): # 提取报文 self.outer_username: str = request.username self.peap_username: str = '' - self.user_mac = request.user_mac # mac地址 + self.user_mac = request.user_mac # mac地址 self.user_password: str = '' - self.user_speed: int = 0 + self.user_speed: int = 0 # 兆 self.server_challenge: bytes = b'' self.peer_challenge: bytes = b'' From 624aa797b600fc15dddb03d439d6e4f0c13c96eb Mon Sep 17 00:00:00 2001 From: zeroleo12345 Date: Sat, 27 Mar 2021 13:40:31 +0800 Subject: [PATCH 14/15] fix --- src/child_pyrad/packet.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/child_pyrad/packet.py b/src/child_pyrad/packet.py index ab4bb861..e81031df 100644 --- a/src/child_pyrad/packet.py +++ b/src/child_pyrad/packet.py @@ -94,12 +94,17 @@ def create_access_accept(cls, request: AuthRequest, session: BaseSession) -> Aut ApStat.report_ap_online(username=request.username, ap_mac=request.ap_mac) # reply = request.create_reply(code=Packet.CODE_ACCESS_ACCEPT) - # reply['Session-Timeout'] = 600 # 用户可用的剩余时间 - reply['H3C-Input-Peak-Rate'] = session.auth_user.user_speed * 1024 * 1024 * 8 / 4 # 上传速度. 用户到NAS的峰值速率, 以bps为单位. 1/8字节每秒 - reply['H3C-Output-Peak-Rate'] = session.auth_user.user_speed * 1024 * 1024 * 8 # 下载速度. NAS到用户的峰值速率, 以bps为单位. 1/8字节每秒 reply['Idle-Timeout'] = 86400 # 用户的闲置切断时间 reply['Acct-Interim-Interval'] = ACCOUNTING_INTERVAL - # reply['Class'] = '\x7f'.join(('EAP-PEAP', session.auth_user.peap_username, session.session_id)) # Access-Accept发送给AC, AC在计费报文内会携带Class值上报 + + if session.auth_user.user_speed: + # 上传速度. 用户到NAS的峰值速率, 以bps为单位. 1/8字节每秒 + reply['H3C-Input-Peak-Rate'] = session.auth_user.user_speed * 1024 * 1024 * 8 / 4 + # 下载速度. NAS到用户的峰值速率, 以bps为单位. 1/8字节每秒 + reply['H3C-Output-Peak-Rate'] = session.auth_user.user_speed * 1024 * 1024 * 8 + # reply['Session-Timeout'] = 600 # 用户可用的剩余时间 + # reply['Class'] = '\x7f'.join(('EAP-PEAP', session.auth_user.peap_username, session.session_id)) # Access-Accept发送给AC, AC在计费报文内会携带Class值上报 + return reply @classmethod From c09f16c2b32f2fcf58db4daaa90f9625d5c13a39 Mon Sep 17 00:00:00 2001 From: zeroleo12345 Date: Sun, 28 Mar 2021 12:25:05 +0800 Subject: [PATCH 15/15] add --- src/child_pyrad/packet.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/child_pyrad/packet.py b/src/child_pyrad/packet.py index e81031df..fc18cb61 100644 --- a/src/child_pyrad/packet.py +++ b/src/child_pyrad/packet.py @@ -102,6 +102,7 @@ def create_access_accept(cls, request: AuthRequest, session: BaseSession) -> Aut reply['H3C-Input-Peak-Rate'] = session.auth_user.user_speed * 1024 * 1024 * 8 / 4 # 下载速度. NAS到用户的峰值速率, 以bps为单位. 1/8字节每秒 reply['H3C-Output-Peak-Rate'] = session.auth_user.user_speed * 1024 * 1024 * 8 + reply['Filter-Id'] = f'pay_user_{session.auth_user.user_speed}m' # reply['Session-Timeout'] = 600 # 用户可用的剩余时间 # reply['Class'] = '\x7f'.join(('EAP-PEAP', session.auth_user.peap_username, session.session_id)) # Access-Accept发送给AC, AC在计费报文内会携带Class值上报