radius挑战认证+对接华为防火墙实现SSLvpn 双因子认证1


近日公司有个需求,需要对使用vpn的用户进行二次认证,要求使用动态码进行验证,我再网上搜了很多资料都没有找到合适的解决方案。

使用第三方设备吧,费用太贵,不是很值得。 正好博客园有位大佬之前趟过坑,文章给了我思路。他的博文地址是:

https://www.cnblogs.com/luckpiky/p/11441916.html

废话不多说,上我修改过的代码。

环境说明:

py3.8   数据库mysql (存radius第一次认证的密码),安装pyrad插件

修改过的
 1  # -*- coding: UTF-8 -*-
 2  2 from pyrad import *
 3  3 import socket
 4  4 import pyrad.host
 5  5 import random
 6  6 import pymysql
 7  7 
 8  8 BUFSIZE = 1024
 9  9 KEY = b"test123456789"
10 10 CHALLENGE = "666" #挑战码初始为666
11 11 
12 12 class RadiusServer(pyrad.host.Host):
13 13     def __init__(self):
14 14         dict = pyrad.dictionary.Dictionary("dictionary") #从通用的字典使用
15 15         pyrad.host.Host.__init__(self, dict=dict)
16 16 
17 17     def get_challenge(self): #产生一个4字节的随机挑战码
18 18         challenge = ""  #初始化挑战码
19 19         challenge = challenge + str(chr(random.randint(65,90)))
20 20         challenge = challenge + str(chr(random.randint(65,90)))
21 21         challenge = challenge + str(chr(random.randint(65,90)))
22 22         challenge = challenge + str(chr(random.randint(65,90)))
23 23         return challenge
24 24     def check_pass(self, radpkt): 
25 25         global CHALLENGE
26 26         print("检查用户名称")
27 27         conn=pymysql.connect(
28 28             host='x.x.x.x',     #数据库的ip地址
29 29             port=3306,          #数据库端口
30 30             user='root',        #数据库用户名
31 31             password='12345678',#数据库密码
32 32             db='test',          #数据库表名
33 33             charset='utf8'      #数据库编码
34 34         )
35 35          # 拿到游标
36 36         cursor=conn.cursor()
37 37         user=radpkt["User-Name"][0]
38 38         print(user)
39 39         password=radpkt["User-Password"][0]
40 40         print(password)
41 41          # 执行sql语句 
42 42         sql='select * from test where user = "%s" '% (user)
43 44         res=cursor.execute(sql)
44 46         pwd=cursor.fetchall()
45 48         cursor.close()
46 49         conn.close()
47 50 
48 52         if radpkt.PwCrypt(CHALLENGE) == radpkt["User-Password"][0]:
49 53             radpkt.code = packet.AccessAccept
50 54             CHALLENGE = self.get_challenge() #挑战码使用过后就更换掉
51 55             print("AccessAccept")
52 56         elif radpkt.PwCrypt(pwd[0][1]) == radpkt["User-Password"][0]:
53 57             radpkt.code = packet.AccessChallenge
54 58             CHALLENGE = self.get_challenge()
55 59             radpkt.AddAttribute("Reply-Message","Enter Token Code") 
56 60             radpkt.AddAttribute("State",b'0x123231')#随机生成一个state,此处简单写的,可以仿照挑战码写一个类似的
57 61             print("AccessChallenge, please input", CHALLENGE)
58 62         else:
59 63             radpkt.code = packet.AccessReject
60 64             print("AccessReject")
61 65 
62 66     def get_pkt(self, pkt):
63 67         get_pw = None
64 68         get_name = None
65 69         radpkt = self.CreateAuthPacket(packet=pkt) #解析请求报文
66 70         #radpkt.code = packet.AccessChallenge
67 71         radpkt.secret = KEY
68 72 
69 73         print("输出相关参数")
70 74         for key in radpkt.keys():        
71 75             print(key, radpkt[key])
72 76             if key == "User-Password":
73 77                 get_pw = 1
74 78             if key == "User-Name":
75 79                 get_name = 1
76 80         
77 81         if 1 == get_pw and 1 == get_name:
78 82             self.check_pass(radpkt)
79 83              
80 84         return radpkt.ReplyPacket()
81 85      
82 87 ip_port = ('', 1812)
83 88 server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  # udp协议
84 89 server.bind(ip_port)
85 90 
86 91 
87 92 while True:
88 93     data,client_addr = server.recvfrom(BUFSIZE)
89 94     srv = RadiusServer()
90 95     reply = srv.get_pkt(data)
91 96     server.sendto(reply, client_addr)

验证过程。打开ssl vpn的登录页面 使用数据库表的用户名和密码登录

python服务端 动态码

输入动态码

登录成功0

写在后面:

当然这样仅仅是双因子认证成功而已,我们可以在结合企业微信或者钉钉机器人之类的工具,把生成的动态码 即时的发给vpn的使用者。

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM