Skip to content

Commit 7764291

Browse files
committed
🎨 工具管理凭证校验逻辑调整
1 parent 2fb6e3a commit 7764291

5 files changed

Lines changed: 130 additions & 71 deletions

File tree

server/projects/main/apps/codeproj/core/scmmgr.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,11 +217,13 @@ def create_checktool_auth(cls, checktool, user, scm_auth_type=None,
217217
"""
218218
auth_key = "%s_%s" % (ScmAuth.KeyEnum.TOOL, checktool.id)
219219
logger.debug("create checktool scm auth: %s" % auth_key)
220+
# 兼容逻辑
221+
if scm_auth_type == ScmAuth.ScmAuthTypeEnum.OAUTH and not scm_oauth:
222+
scm_oauth = cls.get_scm_auth(user)
220223
scm_auth = cls.create_or_update_auth(
221224
auth_key=auth_key, auth_type=scm_auth_type,
222225
scm_account=scm_account, scm_ssh=scm_ssh_info,
223-
scm_oauth=scm_oauth
224-
)
226+
scm_oauth=scm_oauth)
225227
checktool.scm_auth = scm_auth
226228
checktool.save(user=user)
227229

@@ -239,6 +241,9 @@ def create_toollib_auth(cls, toollib, user, scm_auth_type=None,
239241
"""
240242
auth_key = "%s_%s" % (ScmAuth.KeyEnum.TOOLLIB, toollib.id)
241243
logger.debug("create toollib scm auth: %s" % auth_key)
244+
# 兼容逻辑
245+
if scm_auth_type == ScmAuth.ScmAuthTypeEnum.OAUTH and not scm_oauth:
246+
scm_oauth = cls.get_scm_auth(user)
242247
scm_auth = cls.create_or_update_auth(
243248
auth_key=auth_key, auth_type=scm_auth_type,
244249
scm_account=scm_account, scm_ssh=scm_ssh_info,

server/projects/main/apps/scan_conf/core/basemgr.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
# 项目内
2121
from apps.scan_conf import models
2222
from apps.scan_conf.api_filters import base as base_filters
23+
from apps.codeproj.core.scmmgr import ScmAuthManager
2324
from apps.base.basemodel import CDBaseModel
2425

2526
logger = logging.getLogger(__name__)
@@ -196,3 +197,76 @@ def get_checkpackage_rules_filter(cls, queryset, filter_class=base_filters.Packa
196197
for field in filter_class.Meta.fields
197198
}
198199
return cls._get_filter(queryset, field_maps, models.PackageMap, user=user)
200+
201+
202+
class CommonManager(object):
203+
"""公共manager
204+
"""
205+
206+
@classmethod
207+
def is_eq_instance_auth(cls, scm_auth, instance=None):
208+
"""用于更新凭证时判断,判断传入的scm_auth是否与实例原本的scm_auth相同,相同则返回该凭证的信息
209+
:param scm_auth: ScmAuth
210+
:param instance: ToolLib or CheckTool
211+
:return is_eq, credential_info: bool, dict
212+
"""
213+
if instance and instance.scm_auth:
214+
auth_type = scm_auth.get("auth_type")
215+
scm_oauth = scm_auth.get("scm_oauth")
216+
scm_account = scm_auth.get("scm_account")
217+
scm_ssh = scm_auth.get("scm_ssh")
218+
if auth_type == models.ScmAuth.ScmAuthTypeEnum.OAUTH and \
219+
instance.scm_auth.scm_oauth == scm_oauth:
220+
return True, scm_oauth.credential_info
221+
elif auth_type == models.ScmAuth.ScmAuthTypeEnum.PASSWORD and \
222+
instance.scm_auth.scm_account == scm_account:
223+
return True, scm_account.credential_info
224+
elif auth_type == models.ScmAuth.ScmAuthTypeEnum.SSHTOKEN and \
225+
instance.scm_auth.scm_ssh == scm_ssh:
226+
return True, scm_ssh.credential_info
227+
return False, None
228+
229+
@classmethod
230+
def validate_scm_auth(cls, scm_auth, user):
231+
"""校验传入的scm_auth是否是当前用户创建的凭证,否则认为是无效凭证
232+
:param scm_auth: ScmAuth
233+
:param user: User
234+
:return credential_info: dict
235+
"""
236+
auth_type = scm_auth.get("auth_type")
237+
scm_oauth = scm_auth.get("scm_oauth")
238+
scm_account = scm_auth.get("scm_account")
239+
scm_ssh = scm_auth.get("scm_ssh")
240+
if auth_type == models.ScmAuth.ScmAuthTypeEnum.OAUTH:
241+
if not scm_oauth:
242+
# 如果没有传递scm_oauth
243+
scm_oauth = ScmAuthManager.get_scm_auth(user)
244+
if not scm_oauth or scm_oauth.user != user:
245+
raise ParseError({"scm_auth": "请选择有效OAuth凭证"})
246+
credential_info = scm_oauth.credential_info
247+
elif auth_type == models.ScmAuth.ScmAuthTypeEnum.PASSWORD:
248+
if not scm_account or scm_account.user != user:
249+
raise ParseError({"scm_auth": "请选择有效HTTP凭证"})
250+
credential_info = scm_account.credential_info
251+
elif auth_type == models.ScmAuth.ScmAuthTypeEnum.SSHTOKEN:
252+
if not scm_ssh or scm_ssh.user != user:
253+
raise ParseError({"scm_auth": "请选择有效SSH凭证"})
254+
credential_info = scm_ssh.credential_info
255+
else:
256+
raise ParseError({"auth_type": "不支持%s鉴权方式" % auth_type})
257+
return credential_info
258+
259+
@classmethod
260+
def get_and_check_scm_auth(cls, scm_auth, user, instance=None):
261+
"""获取并校验凭证,获取凭证信息
262+
:param scm_auth: ScmAuth
263+
:param user: User
264+
:param instance: ToolLib or CheckTool
265+
:return credential_info: dict
266+
"""
267+
# 更新凭证时,用于判断凭证是否切换
268+
is_eq, credential_info = cls.is_eq_instance_auth(scm_auth, instance)
269+
if is_eq is False:
270+
# 创建或凭证切换时,校验凭证并获取凭证信息
271+
credential_info = cls.validate_scm_auth(scm_auth, user)
272+
return credential_info

server/projects/main/apps/scan_conf/serializers/base/tool.py

Lines changed: 17 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@
1515

1616
# 项目内
1717
from apps.scan_conf import models
18-
from apps.scan_conf.core import ToolLibMapManager, ToolLibSchemeManager, CheckToolManager, ToolLibManager
18+
from apps.scan_conf.core import CommonManager, ToolLibMapManager, ToolLibSchemeManager, \
19+
CheckToolManager, ToolLibManager
20+
from apps.scan_conf.serializers.base.rule import CheckRuleSerializer
1921
from apps.base.serializers import CDBaseModelSerializer
2022
from apps.authen.models import Organization
2123
from apps.authen.serializers.base import ScmAuthCreateSerializer, ScmAuthSerializer
2224
from apps.authen.serializers.base_org import OrganizationSimpleSerializer
2325
from apps.codeproj.core import ScmAuthManager
24-
from .rule import CheckRuleSerializer
2526

2627
logger = logging.getLogger(__name__)
2728

@@ -215,25 +216,8 @@ def validate(self, attrs):
215216
if not scm_auth:
216217
# raise serializers.ValidationError({"scm_auth": "凭证为必填项"})
217218
return super().validate(attrs)
218-
auth_type = scm_auth.get("auth_type")
219-
if auth_type == models.ScmAuth.ScmAuthTypeEnum.OAUTH:
220-
scm_oauth = scm_auth.get("scm_oauth")
221-
if not scm_oauth or scm_oauth.user != user:
222-
raise serializers.ValidationError({"scm_auth": "请选择有效OAuth凭证"})
223-
credential_info = scm_oauth.credential_info
224-
elif auth_type == models.ScmAuth.ScmAuthTypeEnum.PASSWORD:
225-
scm_account = scm_auth.get("scm_account")
226-
if not scm_account or scm_account.user != user:
227-
raise serializers.ValidationError({"scm_auth": "请选择有效HTTP凭证"})
228-
credential_info = scm_account.credential_info
229-
elif auth_type == models.ScmAuth.ScmAuthTypeEnum.SSHTOKEN:
230-
scm_ssh = scm_auth.get("scm_ssh")
231-
if not scm_ssh or scm_ssh.user != user:
232-
raise serializers.ValidationError({"scm_auth": "请选择有效SSH凭证"})
233-
credential_info = scm_ssh.credential_info
234-
else:
235-
raise serializers.ValidationError({"auth_type": ["不支持%s鉴权方式" % auth_type]})
236-
# 校验
219+
# 校验凭证有效性
220+
credential_info = CommonManager.get_and_check_scm_auth(scm_auth, user, instance=self.instance)
237221
ScmAuthManager.check_scm_url_credential(scm_type, scm_url, credential_info)
238222
return super().validate(attrs)
239223

@@ -243,13 +227,18 @@ def _create_or_update(self, validated_data, instance=None):
243227
scm_auth = validated_data.pop("scm_auth", None)
244228
instance, _ = ToolLibManager.create_or_update(name, user, instance=instance, **validated_data)
245229
# 保存凭证信息
246-
if validated_data.get("scm_type") != models.ToolLib.ScmTypeEnum.LINK and scm_auth:
247-
ScmAuthManager.create_toollib_auth(
248-
instance, user, scm_auth_type=scm_auth.get("auth_type"),
249-
scm_account=scm_auth.get("scm_account"),
250-
scm_ssh_info=scm_auth.get("scm_ssh"),
251-
scm_oauth=scm_auth.get("scm_oauth"),
252-
)
230+
if validated_data.get("scm_type") != models.ToolLib.ScmTypeEnum.LINK:
231+
if scm_auth:
232+
ScmAuthManager.create_toollib_auth(
233+
instance, user, scm_auth_type=scm_auth.get("auth_type"),
234+
scm_account=scm_auth.get("scm_account"),
235+
scm_ssh_info=scm_auth.get("scm_ssh"),
236+
scm_oauth=scm_auth.get("scm_oauth"),
237+
)
238+
elif instance:
239+
# 更新时允许移除scm_auth
240+
instance.scm_auth = None
241+
instance.save(user=user)
253242
return instance
254243

255244
def create(self, validated_data):

server/projects/main/apps/scan_conf/serializers/v3/tool.py

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
# 项目内
1818
from apps.scan_conf import models
1919
from apps.scan_conf.serializers import base
20-
from apps.scan_conf.core import CheckToolManager
20+
from apps.scan_conf.core import CommonManager, CheckToolManager
2121
from apps.authen.models import Organization
2222
from apps.authen.serializers.base import ScmAuthCreateSerializer, ScmAuthSerializer
2323
from apps.codeproj.core import ScmAuthManager
@@ -82,6 +82,7 @@ def get_user(self):
8282
def validate(self, attrs):
8383
attrs["org"] = get_and_check_view_org(self)
8484
user = self.get_user()
85+
scm_type = attrs.get("scm_type")
8586
scm_auth = attrs.get("scm_auth")
8687
scm_url = attrs.get('scm_url')
8788
run_cmd = attrs.get('run_cmd')
@@ -93,26 +94,8 @@ def validate(self, attrs):
9394
raise serializers.ValidationError({"run_cmd": "工具执行命令必填"})
9495
# 存在时则进行凭证校验
9596
if scm_url and scm_auth:
96-
scm_type = attrs.get("scm_type")
97-
auth_type = scm_auth.get("auth_type")
98-
if auth_type == models.ScmAuth.ScmAuthTypeEnum.OAUTH:
99-
scm_oauth = scm_auth.get("scm_oauth")
100-
if not scm_oauth or scm_oauth.user != user:
101-
raise serializers.ValidationError({"scm_auth": "请选择有效OAuth凭证"})
102-
credential_info = scm_oauth.credential_info
103-
elif auth_type == models.ScmAuth.ScmAuthTypeEnum.PASSWORD:
104-
scm_account = scm_auth.get("scm_account")
105-
if not scm_account or scm_account.user != user:
106-
raise serializers.ValidationError({"scm_auth": "请选择有效HTTP凭证"})
107-
credential_info = scm_account.credential_info
108-
elif auth_type == models.ScmAuth.ScmAuthTypeEnum.SSHTOKEN:
109-
scm_ssh = scm_auth.get("scm_ssh")
110-
if not scm_ssh or scm_ssh.user != user:
111-
raise serializers.ValidationError({"scm_auth": "请选择有效SSH凭证"})
112-
credential_info = scm_ssh.credential_info
113-
else:
114-
raise serializers.ValidationError({"auth_type": ["不支持%s鉴权方式" % auth_type]})
115-
# 校验
97+
# 校验凭证有效性
98+
credential_info = CommonManager.get_and_check_scm_auth(scm_auth, user, instance=self.instance)
11699
ScmAuthManager.check_scm_url_credential(scm_type, scm_url, credential_info)
117100
return super().validate(attrs)
118101

@@ -129,6 +112,10 @@ def _create_or_update(self, validated_data, instance=None):
129112
scm_ssh_info=scm_auth.get("scm_ssh"),
130113
scm_oauth=scm_auth.get("scm_oauth"),
131114
)
115+
elif instance:
116+
# 更新时允许移除scm_auth
117+
checktool.scm_auth = None
118+
checktool.save(user=user)
132119
return checktool
133120

134121
def create(self, validated_data):

server/projects/main/apps/scan_conf/utils/base.py

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def loadlib(cls, toollib_json, user):
6868
scm_auth = slz.validated_data.pop("scm_auth", None)
6969
toollib_name = slz.validated_data.pop("name")
7070
toollib, _ = ToolLibManager.create_or_update(toollib_name, user, instance=toollib,
71-
lib_key=lib_key, **slz.validated_data)
71+
lib_key=lib_key, **slz.validated_data)
7272
return True, cls.postload_handler(toollib, scm_auth=scm_auth, user=user)
7373
except Exception as e:
7474
logger.error(e)
@@ -122,7 +122,7 @@ def postload_handler(cls, checktool, admins=None):
122122
:return: checktool_name
123123
"""
124124
if admins and not checktool.owners.exists():
125-
# 如果工具owners为农历了
125+
# 如果工具owners不存在
126126
checktool.owners.add(*admins)
127127
return checktool.name
128128

@@ -136,15 +136,17 @@ def loadchecker(cls, checktool_json, admins=None):
136136
checktool_name = checktool_json["name"]
137137
try:
138138
data = cls.preload_handler(checktool_json)
139-
checktool = models.CheckTool.objects.filter(name=checktool_name).first()
140-
slz = CheckerSerializer(instance=checktool, data=data, context={"is_local_script": True})
141-
slz.is_valid(raise_exception=True)
142-
logger.info("开始保存工具%s数据。。。" % checktool_name)
143-
checktool_name = slz.validated_data.pop("name")
144-
tool_key = data.get('tool_key')
145-
checktool = CheckToolManager.load_by_script(checktool_name, None, checktool=checktool,
146-
tool_key=tool_key, **slz.validated_data)
147-
return True, cls.postload_handler(checktool, admins=admins)
139+
if data:
140+
checktool = models.CheckTool.objects.filter(name=checktool_name).first()
141+
slz = CheckerSerializer(instance=checktool, data=data, context={"is_local_script": True})
142+
slz.is_valid(raise_exception=True)
143+
logger.info("开始保存工具%s数据。。。" % checktool_name)
144+
checktool_name = slz.validated_data.pop("name")
145+
tool_key = data.get('tool_key')
146+
checktool = CheckToolManager.load_by_script(checktool_name, None, checktool=checktool,
147+
tool_key=tool_key, **slz.validated_data)
148+
return True, cls.postload_handler(checktool, admins=admins)
149+
return True, checktool_name
148150
except Exception as e:
149151
logger.error(e)
150152
return False, checktool_name
@@ -221,14 +223,16 @@ def loadpkg(cls, checkpackage_json):
221223
checkpackage_name = checkpackage_json["name"]
222224
try:
223225
data = cls.preload_handler(checkpackage_json)
224-
checkpackage = models.CheckPackage.objects.filter(name=checkpackage_name).first()
225-
slz = CheckPackageJsonSerializer(instance=checkpackage, data=data)
226-
slz.is_valid(raise_exception=True)
227-
logger.info("开始保存规则包[%s]数据。。。" % checkpackage_name)
228-
checkpackage_name = slz.validated_data.pop("name")
229-
checkpackage = CheckPackageManager.load_by_script(checkpackage_name, None,
230-
checkpackage=checkpackage, **slz.validated_data)
231-
return True, cls.postload_handler(checkpackage)
226+
if data:
227+
checkpackage = models.CheckPackage.objects.filter(name=checkpackage_name).first()
228+
slz = CheckPackageJsonSerializer(instance=checkpackage, data=data)
229+
slz.is_valid(raise_exception=True)
230+
logger.info("开始保存规则包[%s]数据。。。" % checkpackage_name)
231+
checkpackage_name = slz.validated_data.pop("name")
232+
checkpackage = CheckPackageManager.load_by_script(checkpackage_name, None,
233+
checkpackage=checkpackage, **slz.validated_data)
234+
return True, cls.postload_handler(checkpackage)
235+
return True, checkpackage_name
232236
except Exception as e:
233237
logger.error(e)
234238
return False, checkpackage_name
@@ -252,7 +256,7 @@ def loadpkg_by_workers(cls, checkpackage_json_list, workers=10):
252256
break
253257
checkpackage_json = checkpackage_json_list[i_idx+j_idx]
254258
logger.info('--> [%s/%s], checkpackage name: %s' % (
255-
index+1, checkpackage_count, checkpackage_json["name"]))
259+
checkpackage_count, index+1, checkpackage_json["name"]))
256260
task = t_thread.submit(cls.loadpkg, checkpackage_json)
257261
all_task.append(task)
258262
for future in as_completed(all_task):

0 commit comments

Comments
 (0)