Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DR-876 Update discovery-common #1366

Merged
merged 1 commit into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion keepercommander/discovery_common/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '1.0.27'
__version__ = '1.0.28'
105 changes: 74 additions & 31 deletions keepercommander/discovery_common/process.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,30 @@ def _directory_exists(self, domain: str, directory_info_func: Callable, context:

self.logger.debug(f"search for directories: {', '.join(domains)}")

# Some providers provider directory type services.
# They can also provide mulitple domains
provider_vertices = self.infra.dag.search_content({
"record_type": ["pamAzureConfiguration", "pamDomainConfiguration"],
}, ignore_case=True)
found_provider_directories = []
for provider_vertex in provider_vertices:
content = DiscoveryObject.get_discovery_object(provider_vertex)
found = False
for domain in domains:
for provider_domain in content.item.info.get("domains", []):
if domain.lower() in provider_domain.lower():
found = True
break
if found is True:
break
if found is True:
found_provider_directories.append(provider_vertex)
if len(found_provider_directories) > 0:
return found_provider_directories

# Check the graph first.
# `search_content` does an "is in" type match; so subdomains should match a full domain
# pamDomainConfiguration is an edge case because it's name in the record is the domain name.
for domain_name in domains:
directories = self.infra.dag.search_content({
"record_type": ["pamDirectory", "pamDomainConfiguration"],
Expand All @@ -327,16 +350,17 @@ def _directory_exists(self, domain: str, directory_info_func: Callable, context:

self.logger.debug(f"found {len(directories)} directories in the graph")


# If we found directories, return the list of directory vertices.
if len(directories) > 0:
# Return vertices
return directories

# Check the vault secondly.
for domain_name in domains:
info = directory_info_func(domain=domain_name, skip_users=False, context=context)
if info is not None:
# If we found directories in the Vault, then return directory info
# This will be an instance of DirectoryInfo
return info

return None
Expand Down Expand Up @@ -751,11 +775,6 @@ def _process_auto_add_level(self,
if access_dn is not None:
access_dn = access_dn.lower()

self.logger.debug(f"REMOVE ME: access_username_and_domain = {access_username_and_domain}")
self.logger.debug(f"REMOVE ME: access_username = {access_username}")
self.logger.debug(f"REMOVE ME: access_domain = {access_domain}")
self.logger.debug(f"REMOVE ME: access_dn = {access_dn}")

# Go through the users to find the administrative user.
found_user_in_discovery_user_list = False
for user_vertex in vertex.has_vertices():
Expand All @@ -780,11 +799,6 @@ def _process_auto_add_level(self,
if dn is not None:
dn = dn.lower()

self.logger.debug(f"REMOVE ME: user_and_domain = {user_and_domain}")
self.logger.debug(f"REMOVE ME: user = {user}")
self.logger.debug(f"REMOVE ME: domain = {domain}")
self.logger.debug(f"REMOVE ME: dn = {dn}")

if (access_username_and_domain == user_and_domain
or access_username_and_domain == user
or access_username == user
Expand Down Expand Up @@ -1051,24 +1065,6 @@ def _process_level(self,
# If the ignore_object flag is set, then continue.
continue

# # If the rule engine flagged this object to be auto added, and no record exists,
# # prepare a record and add it to the bulk_add_records queue.
# # At the end of processing, the record will be added.
# elif content.action_rules_result == RuleActionEnum.ADD.value and content.record_exists is False:
# self.logger.debug(f" vertex {vertex.uid} had an ADD result for the rule engine, auto add")
#
# # The record could be a resource or user record.
# self._prepare_record(
# record_prepare_func=record_prepare_func,
# bulk_add_records=bulk_add_records,
# content=content,
# parent_content=current_content,
# vertex=vertex,
# context=context
# )
#
# self.record_link.discovery_belongs_to(vertex, current_vertex, acl=default_acl)

# If the record doesn't exist, then prompt the user.
else:
self.logger.debug(f" vertex {vertex.uid} had an PROMPT result, prompt user")
Expand Down Expand Up @@ -1210,6 +1206,8 @@ def _process_level(self,
resource_content=content,
bulk_add_records=bulk_add_records,
bulk_convert_records=bulk_convert_records,
record_lookup_func=record_lookup_func,
directory_info_func=directory_info_func,
prompt_admin_func=prompt_admin_func,
record_prepare_func=record_prepare_func,
indent=indent,
Expand Down Expand Up @@ -1269,6 +1267,8 @@ def _process_admin_user(self,
resource_content: DiscoveryObject,
bulk_add_records: List[BulkRecordAdd],
bulk_convert_records: List[BulkRecordConvert],
record_lookup_func: Callable,
directory_info_func: Callable,
prompt_admin_func: Callable,
record_prepare_func: Callable,
indent: int = 0,
Expand Down Expand Up @@ -1338,6 +1338,8 @@ def _process_admin_user(self,

# If the action is to ADD, replace the PLACEHOLDER data.
if admin_result.action == PromptActionEnum.ADD:
self.logger.debug("adding admin user")

source = "local"
if resource_content.record_type == PAM_DIRECTORY:
source = resource_content.name
Expand All @@ -1348,7 +1350,6 @@ def _process_admin_user(self,
admin_acl = UserAcl(is_admin=True)

if admin_record_uid is None:
logging.debug("add admin user from content")
admin_content = admin_result.content

# With the result, we can fill in information in the object item.
Expand All @@ -1362,6 +1363,8 @@ def _process_admin_user(self,
admin_content.item.source = source
admin_content.name = admin_content.item.user

self.logger.debug(f"added admin user from content")

if admin_content.item.user is None or admin_content.item.user == "":
raise ValueError("The user name is missing or is blank. Cannot create the administrator user.")

Expand All @@ -1372,25 +1375,61 @@ def _process_admin_user(self,
# We need to populate the id and uid of the content, now that we have data in the content.
self.populate_admin_content_ids(admin_content, resource_vertex)

ad_user, ad_domain = split_user_and_domain(admin_content.item.user)
if ad_domain is not None and admin_content.item.source == LOCAL_USER:
self.logger.debug("The admin is an directory user, but the source is set to a local user")

found_admin_record_uid = None
try:
found_admin_record_uid = self._find_admin_directory_user(
domain=ad_domain,
admin_acl=admin_acl,
directory_info_func=directory_info_func,
record_lookup_func=record_lookup_func,
context=context,
user=admin_content.item.user,
dn=admin_content.item.dn
)
except DirectoryNotFoundException:
self.logger.debug(f" directory {source} was not found for admin user")
except UserNotFoundException:
self.logger.debug(f" directory user was not found in directory {source}")

if found_admin_record_uid is not None:
self.logger.debug(" found directory user admin, connect to resource")
found_admin_vertices = self.infra.dag.search_content({"record_uid": found_admin_record_uid})
if len(found_admin_vertices) == 1:
found_admin_vertices[0].belongs_to(resource_vertex, edge_type=EdgeType.KEY)
self.record_link.belongs_to(found_admin_record_uid, resource_content.record_uid,
acl=admin_acl)
return

# Does an admin vertex already exist for this user?
# This most likely user on the gateway, since without a resource record users can be discovered.
# If we did find it, get the content for the admin; we really want any existing record uid.
admin_vertex = self.infra.dag.get_vertex(admin_content.uid)
if admin_vertex is not None and admin_vertex.active is True and admin_vertex.has_data is True:
self.logger.debug("admin exists in the graph")
found_content = DiscoveryObject.get_discovery_object(admin_vertex)
admin_record_uid = found_content.record_uid
else:
self.logger.debug("admin does not exists in the graph")

# If there is a record UID for the admin user, connect it.
if admin_record_uid is not None:
self.logger.debug("the admin has a record UID")

# If the admin record does not belong to another resource, make this resource its owner.
if self.record_link.get_parent_record_uid(admin_record_uid) is None:
self.logger.debug("the admin does not belong to another resourse, "
"setting it belong to this resource")
admin_acl.belongs_to = True

admin_vertex.belongs_to(resource_vertex, edge_type=EdgeType.KEY)
self.record_link.belongs_to(admin_record_uid, resource_content.record_uid, acl=admin_acl)
else:
if admin_vertex is None:
self.logger.debug("creating an entry in the graph for the admin")
admin_vertex = self.infra.dag.add_vertex(uid=admin_content.uid,
name=admin_content.description)

Expand All @@ -1415,13 +1454,15 @@ def _process_admin_user(self,
self.record_link.discovery_belongs_to(admin_vertex, resource_vertex, acl=admin_acl)

else:
logging.debug("add admin user from existing record")
self.logger.debug("add admin user from existing record")

# If this is NOT existing directory user, we want to convert the record rotation setting to
# work with this gateway/controller.
# If it is a directory user, we just want link this record; no conversion.
if admin_result.is_directory_user is False:

self.logger.debug("the admin user is NOT a directory user, convert record's rotation settings")

# This is a pamUser record that may need to have the controller set.
# Add it to this queue to make sure the protobuf items are current.
parent_record_uid = resource_content.record_uid
Expand All @@ -1442,6 +1483,8 @@ def _process_admin_user(self,

# There is _prepare_record, the record exists.
# Needs to add to records linking.
else:
self.logger.debug("the admin user is a directory user")

# Link the record UIDs.
# We might not have this user in discovery data.
Expand Down
8 changes: 4 additions & 4 deletions keepercommander/discovery_common/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ def record_exists(self):

def get_field_value(self, label):
for field in self.fields:
if field.label == label:
if field.label == label or field.type == label:
value = field.value
if len(value) == 0:
return None
Expand All @@ -497,7 +497,7 @@ def set_field_value(self, label, value):
if isinstance(value, list) is False:
value = [value]
for field in self.fields:
if field.label == label:
if field.label == label or field.type == label:
field.value = value
return
raise ValueError(f"Cannot not find field with label {label}")
Expand Down Expand Up @@ -560,12 +560,12 @@ class NormalizedRecord(BaseModel):
fields: List[RecordField] = []
note: Optional[str] = None

def _field(self, type, label) -> Optional[RecordField]:
def _field(self, field_type, label) -> Optional[RecordField]:
for field in self.fields:
value = field.value
if value is None or len(value) == 0:
continue
if field.label == type and value[0].lower() == label.lower():
if field.label == field_type and value[0].lower() == label.lower():
return field
return None

Expand Down
Loading