时间:11:06:45 来源:顺德匕渡新能源有限公司 作者:竞彩倍投最佳方案资讯网 点击:47386314
{随机段子}

十八岁的天空_解决 Jumpserver coco 使用登录用户(ldap)进行SSH连接目标主机,忽略系统用户

前言

  Jumpserver 作为国内流行的开源堡垒机,很多公司都在尝试使用,同时 Jumpserver 为了契合众多公司的用户认证,也提供了 LDAP 的用户认证方式,作为 Jumpserver 的用户,大家可能知道了 Jumpserver 的 LDAP 认证方式,仅是作为 登录Jumpserver Web UI、登录 Jumpserver 终端(COCO) 的用户认证,进入 Jumpserver 终端(COCO)后,再而跳到目标主机,却需要使用Jumpserver 创建的系统用户,也就是 登录Jumpserver 和 Jumpserver登录目标主机 是需要两个完全没有关系的用户,对于很多基于LDAP用户登录主机的场景,Jumpserver 这种双用户认证概念显得有点鸡肋,既然接入了 LDAP, 我们希望做到 登录Jumpserver 和 Jumpserver跳转主机都使用 LDAP 完成认证登录,带着这一想法,便开始了对 Jumpserver 终端核心 COCO 进行了部分修改。

qian yan   Jumpserver zuo wei guo nei liu xing de kai yuan bao lei ji, hen duo gong si dou zai chang shi shi yong, tong shi Jumpserver wei le qi he zhong duo gong si de yong hu ren zheng, ye ti gong le LDAP de yong hu ren zheng fang shi, zuo wei Jumpserver de yong hu, da jia ke neng zhi dao le Jumpserver de LDAP ren zheng fang shi, jin shi zuo wei deng lu Jumpserver Web UI deng lu Jumpserver zhong duan COCO de yong hu ren zheng, jin ru Jumpserver zhong duan COCO hou, zai er tiao dao mu biao zhu ji, que xu yao shi yong Jumpserver chuang jian de xi tong yong hu, ye jiu shi deng lu Jumpserver he Jumpserver deng lu mu biao zhu ji shi xu yao liang ge wan quan mei you guan xi de yong hu, dui yu hen duo ji yu LDAP yong hu deng lu zhu ji de chang jing, Jumpserver zhe zhong shuang yong hu ren zheng gai nian xian de you dian ji lei, ji ran jie ru le LDAP, wo men xi wang zuo dao deng lu Jumpserver he Jumpserver tiao zhuan zhu ji dou shi yong LDAP wan cheng ren zheng deng lu, dai zhe zhe yi xiang fa, bian kai shi le dui Jumpserver zhong duan he xin COCO jin xing le bu fen xiu gai.

?

COCO前后对比

?

注:LDAP 用户登录Jumpserver coco、选择登录主机后,直接使用登录coco 的用户进行登录主机,取消了选择系统用户的步骤。

?

详细流程

?

注1:用户名密码登录 Jumpserver 时,COCO 处理线程存储用户名密码,用于SSH 连接目标主机;

注2:公钥登录 Jumpserver 时,COCO 处理线程存储用户名和空密码,SSH 连接目标主机时,根据用户名从COCO本地查找密码,有则使用,无则提示输出密码;

注3:SSH 连接认证失败可尝试输入密码尝试三次,认证成功则向本地存储最近一次连接成功的加密密码。

?

代码实现

修改 coco/models.py,添加 password 参数

 1 class Request:
 2     def __init__(self, addr):
 3         self.type = []
 4         self.meta = {"width": 80, "height": 24}
 5         self.user = None
 6         self.password = ""     # @ 周旺
 7         self.addr = addr
 8         self.remote_ip = self.addr[0]
 9         self.change_size_event = threading.Event()
10         self.date_start = datetime.datetime.now()
11     
12 
13 class Client:
14     def __init__(self, chan, request):
15         self.chan = chan
16         self.request = request
17         self.user = request.user
18         self.password = request.password    # @ 周旺
19         self.addr = request.addr

?

修改 coco/interface.py, 赋值?request.password?

 1 class SSHInterface(paramiko.ServerInterface):
 2     def validate_auth(self, username, password="", public_key=""):
 3         info = app_service.authenticate(
 4             username, password=password, public_key=public_key,
 5             remote_addr=self.request.remote_ip
 6         )
 7         user = info.get("user", None)
 8         if user:
 9             self.request.user = user
10             self.request.password = password   # request password 赋值 @ 周旺
11             self.info = info
12 
13         seed = info.get("seed", None)
14         token = info.get("token", None)
15         if seed and not token:
16             self.otp_auth = True
17 
18         return user

?

修改 coco/interactive.py?

 1 class InteractiveServer:
 2     def display_search_result(self):
 3         sort_by = current_app.config["ASSET_LIST_SORT_BY"]
 4         self.search_result = sort_assets(self.search_result, sort_by)
 5         fake_data = [_("ID"), _("Hostname"), _("IP"), _("LoginAs")]
 6         id_length = max(len(str(len(self.search_result))), 4)
 7         hostname_length = item_max_length(self.search_result, 15,
 8                                           key=lambda x: x.hostname)
 9         sysuser_length = item_max_length(self.search_result,
10                                          key=lambda x: x.system_users_name_list)
11         size_list = [id_length, hostname_length, 16, sysuser_length]
12         header_without_comment = format_with_zh(size_list, *fake_data)
13         comment_length = max(
14             self.request.meta["width"] -
15             size_of_str_with_zh(header_without_comment) - 1,
16             2
17         )
18         size_list.append(comment_length)
19         fake_data.append(_("Comment"))
20         self.client.send(wr(title(format_with_zh(size_list, *fake_data))))
21         for index, asset in enumerate(self.search_result, 1):
22             # data = [                                      # 注释主机显示列表  @ 周旺
23             #     index, asset.hostname, asset.ip,
24             #     asset.system_users_name_list, asset.comment
25             # ]
26 
27             data = [                                        # 主机显示列表 @ 周旺
28                 index, asset.hostname, asset.ip,
29                 self.client.user.username, asset.comment
30             ]
31 
32             self.client.send(wr(format_with_zh(size_list, *data)))
33         self.client.send(wr(_("总共: {} 匹配: {}").format(
34             len(self.assets), len(self.search_result)), before=1)
35         )
36 
37     def proxy(self, asset):
38         # system_user = self.choose_system_user(asset.system_users_granted)   # 注释 @ 周旺
39         # if system_user is None:
40         #     self.client.send(_("没有系统用户"))
41         #     return
42         system_user = self.client.user      # 修改系统用户为登录用户 @ 周旺   注: 仍保持system_user 变量名,后面所有 system_user 皆是登录用户
43         password = self.client.password     # 密码 @ 周旺   --> by client -> by request
44         forwarder = ProxyServer(self.client)
45         forwarder.proxy(asset, system_user, password)  # password @ 周旺

?

修改 coco/proxy.py

 1 class ProxyServer:
 2     def proxy(self, asset, system_user, password=""):  # 添加 password 参数 @ 周旺
 3         #self.get_system_user_auth(system_user)        # 注释 @ 周旺
 4 
 5         if not password:                                # 添加46-74行 @ 周旺
 6             with open("/opt/pwd/%s.pwd" % system_user.username, "ab+") as pwd:    # 查找本地缓存密码
 7                 pwd.seek(0)
 8                 try:
 9                     password = base64.b64decode(pwd.read().strip()).decode().strip()
10                     # password = pwd.read().strip()
11                 except:
12                     password = ""
13 
14             if not password:
15                 prompt = "{}@{} password: ".format(system_user.username, asset.ip)
16                 password = net_input(self.client, prompt=prompt, sensitive=True)
17 
18         for n in range(4):
19             self.connecting = True
20             self.send_connecting_message(asset, system_user)
21             self.server = self.get_server_conn(asset, system_user, password)
22             if self.server:
23                 with open("/opt/pwd/%s.pwd" % system_user.username, "wb") as pwd:    # 保存最后一次的正确密码
24                     pwd.write(base64.b64encode(password.encode(encoding="utf-8")))
25                     #pwd.write(password)
26                 break
27 
28             if n < 3:
29                 prompt = "{}@{} password({}/3): ".format(system_user.username, asset.ip, n+1)
30                 password = net_input(self.client, prompt=prompt, sensitive=True)
31         else:
32             return False
33 
34 
35         # self.send_connecting_message(asset, system_user)                  # 注释 @ 周旺
36         # self.server = self.get_server_conn(asset, system_user, password)
37 
38         command_recorder = current_app.new_command_recorder()
39         replay_recorder = current_app.new_replay_recorder()
40         session = Session(
41             self.client, self.server,
42             command_recorder=command_recorder,
43             replay_recorder=replay_recorder,
44         )
45         current_app.add_session(session)
46         self.watch_win_size_change_async()
47         session.bridge()
48         self.stop_event.set()
49         self.end_watch_win_size_change()
50         current_app.remove_session(session)
51 
52     def get_server_conn(self, asset, system_user, password=""):  # 添加 password 参数 @ 周旺
53         logger.info("Connect to {}".format(asset.hostname))
54         # if not self.validate_permission(asset, system_user):    # 注释 @ 周旺
55         #     self.client.send(warning("No permission"))
56         #     return None
57         # if True:
58         #     server = self.get_ssh_server_conn(asset, system_user)
59         # else:
60         #     server = self.get_ssh_server_conn(asset, system_user)
61 
62         server = self.get_ssh_server_conn(asset, system_user, password) # password @ 周旺
63         return server
64 
65     def get_ssh_server_conn(self, asset, system_user, password=""): # 添加 password 参数 @ 周旺
66         request = self.client.request
67         term = request.meta.get("term", "xterm")
68         width = request.meta.get("width", 80)
69         height = request.meta.get("height", 24)
70         ssh = SSHConnection()
71         chan, sock, msg = ssh.get_channel(
72             asset, system_user, term=term, width=width, height=height, password=password)   # password @ 周旺
73         if not chan:
74             self.client.send(warning(wr(msg, before=1, after=0)))
75             server = None
76         else:
77             server = Server(chan, sock, asset, system_user)
78         self.connecting = False
79         self.client.send(b"
")
80         return server
81 
82     def send_connecting_message(self, asset, system_user):
83         def func():
84             delay = 0.0
85             self.client.send("Connecting to {}@{} {:.1f}".format(
86                 system_user.username, asset.ip, delay)          # 修改为 用户名,ip地址 @ 周旺
87             )
88             while self.connecting and delay < TIMEOUT:
89                 self.client.send("x08x08x08{:.1f}".format(delay).encode())
90                 time.sleep(0.1)
91                 delay += 0.1
92         thread = threading.Thread(target=func)
93         thread.start()

?

?修改 coco/connection.py

 1 class SSHConnection:
 2     def get_ssh_client(self, asset, system_user, password=""):  # 添加 password 参数 @ 周旺
 3         ssh = paramiko.SSHClient()
 4         ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
 5         sock = None
 6 
 7         # if not system_user.password and not system_user.private_key:    # 注释 @ 周旺
 8         #     self.get_system_user_auth(system_user)
 9 
10         if asset.domain:
11             sock = self.get_proxy_sock_v2(asset)
12         try:
13             ssh.connect(
14                 asset.ip, port=asset.port, username=system_user.username,
15                 #password=system_user.password, pkey=system_user.private_key,  # 注释 @ 周旺
16                 password=password,                                             # password @ 周旺
17                 timeout=TIMEOUT, compress=True, auth_timeout=TIMEOUT,
18                 look_for_keys=False, sock=sock
19             )
20         except (paramiko.AuthenticationException,
21                 paramiko.BadAuthenticationType,
22                 SSHException) as e:
23             # password_short = "None"                                       # 注释 @ 周旺  注:感觉没啥用
24             # key_fingerprint = "None"
25             # if system_user.password:
26             #     password_short = system_user.password[:5] + 
27             #                      (len(system_user.password) - 5) * "*"
28             # if system_user.private_key:
29             #     key_fingerprint = get_private_key_fingerprint(
30             #         system_user.private_key
31             #     )
32             #
33             # logger.error("Connect {}@{}:{} auth failed, password: 
34             #                      {}, key: {}".format(
35             #     system_user.username, asset.ip, asset.port,
36             #     password_short, key_fingerprint,
37             # ))
38             return None, None, str(e)
39         except (socket.error, TimeoutError) as e:
40             return None, None, str(e)
41         return ssh, sock, None
42 
43     def get_channel(self, asset, system_user, term="xterm", width=80, height=24, password=""):  # password 参数 @ 周旺
44         ssh, sock, msg = self.get_ssh_client(asset, system_user, password) # password @ 周旺
45         if ssh:
46             chan = ssh.invoke_shell(term, width=width, height=height)
47             return chan, sock, None
48         else:
49             return None, sock, msg

?

效果展示

?

?后记

  以上仅适用 jumpserver 终端命令行,没有涉及对jumpserver web 终端及SFTP的修改。

? ? ? 谢 jumpserver 团队:http://www.jumpserver.org/

? ? ??

当前文章:http://www.koncihan.com/988t5bfb/233420-524702-69206.html

发布时间:11:48:51

东方心经马报图纸??kj138本港台现场报码室??梦幻百宝箱??曾道人??www.44459.com??开奖结果??高手联盟心水论坛??世外桃园藏宝图6cccc??老钱庄高手论坛??管家婆心水论坛??

本文标签: 怀化市幻褂陡有限公司 恩平市劝沙有限公司 鹤岗市禾关黄有限公司

回到顶部