From 8cf7d898b6b6569810bc21088dbdeb44fedb1a77 Mon Sep 17 00:00:00 2001 From: TheFrogPad Date: Fri, 12 Jul 2019 14:42:14 -0400 Subject: [PATCH 01/14] Initial update that adds to domainInfo a section with WebLogic roles --- .../python/wlsdeploy/aliases/alias_entries.py | 3 +- .../wlsdeploy/aliases/model_constants.py | 3 + .../wlsdeploy/tool/create/domain_creator.py | 4 + .../wlsdeploy/tool/create/wlsroles_helper.py | 116 ++++++++++++++++++ 4 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 core/src/main/python/wlsdeploy/tool/create/wlsroles_helper.py diff --git a/core/src/main/python/wlsdeploy/aliases/alias_entries.py b/core/src/main/python/wlsdeploy/aliases/alias_entries.py index c214619280..269fb79742 100644 --- a/core/src/main/python/wlsdeploy/aliases/alias_entries.py +++ b/core/src/main/python/wlsdeploy/aliases/alias_entries.py @@ -186,7 +186,8 @@ class AliasEntries(object): # servers in the domain. 'ServerGroupTargetingLimits': 'dict', 'RCUDbInfo': 'dict', - 'OPSSSecrets': 'string' + 'OPSSSecrets': 'string', + 'WLSRoles': 'dict' } __domain_name_token = 'DOMAIN' diff --git a/core/src/main/python/wlsdeploy/aliases/model_constants.py b/core/src/main/python/wlsdeploy/aliases/model_constants.py index b0b287be2a..a7f3dc1458 100644 --- a/core/src/main/python/wlsdeploy/aliases/model_constants.py +++ b/core/src/main/python/wlsdeploy/aliases/model_constants.py @@ -95,6 +95,7 @@ DYNAMIC_SERVERS = 'DynamicServers' ERROR_DESTINATION = 'ErrorDestination' EXECUTE_QUEUE = 'ExecuteQueue' +EXPRESSION = 'Expression' FAIR_SHARE_REQUEST_CLASS = 'FairShareRequestClass' FILE_OPEN = 'FileOpen' FILE_STORE = 'FileStore' @@ -248,6 +249,7 @@ UNIFORM_DISTRIBUTED_QUEUE = 'UniformDistributedQueue' UNIFORM_DISTRIBUTED_TOPIC = 'UniformDistributedTopic' UNIX_MACHINE = 'UnixMachine' +UPDATE = 'Update' USER = 'User' VIRTUAL_TARGET = 'VirtualTarget' VIRTUAL_USER_AUTHENTICATOR = 'VirtualUserAuthenticator' @@ -268,6 +270,7 @@ WLDF_INSTRUMENTATION_MONITOR = "WLDFInstrumentationMonitor" WLDF_RESOURCE = "WLDFResource" WLDF_SYSTEM_RESOURCE = "WLDFSystemResource" +WLS_ROLES = "WLSRoles" WS_RELIABLE_DELIVERY_POLICY = 'WSReliableDeliveryPolicy' XACML_AUTHORIZER = 'XACMLAuthorizer' XACML_ROLE_MAPPER = 'XACMLRoleMapper' diff --git a/core/src/main/python/wlsdeploy/tool/create/domain_creator.py b/core/src/main/python/wlsdeploy/tool/create/domain_creator.py index 1d9a763b73..b1ed4bb177 100644 --- a/core/src/main/python/wlsdeploy/tool/create/domain_creator.py +++ b/core/src/main/python/wlsdeploy/tool/create/domain_creator.py @@ -77,6 +77,7 @@ from wlsdeploy.tool.create.creator import Creator from wlsdeploy.tool.create.rcudbinfo_helper import RcuDbInfo from wlsdeploy.tool.create.security_provider_creator import SecurityProviderCreator +from wlsdeploy.tool.create.wlsroles_helper import WLSRoles from wlsdeploy.tool.deploy import deployer_utils from wlsdeploy.tool.deploy import model_deployer from wlsdeploy.tool.util.archive_helper import ArchiveHelper @@ -148,6 +149,8 @@ def __init__(self, model_dictionary, model_context, aliases): self.target_helper = TargetHelper(self.model, self.model_context, self.aliases, ExceptionType.CREATE, self.logger) + self.wlsroles_helper = WLSRoles(self._domain_info, self._domain_home, self.logger) + # # This list gets modified as the domain is being created so do use this list for anything else... # @@ -338,6 +341,7 @@ def __create_domain(self): self.library_helper.install_domain_libraries() self.library_helper.extract_classpath_libraries() + self.wlsroles_helper.process_roles() self.logger.exiting(class_name=self.__class_name, method_name=_method_name) return diff --git a/core/src/main/python/wlsdeploy/tool/create/wlsroles_helper.py b/core/src/main/python/wlsdeploy/tool/create/wlsroles_helper.py new file mode 100644 index 0000000000..632de3910e --- /dev/null +++ b/core/src/main/python/wlsdeploy/tool/create/wlsroles_helper.py @@ -0,0 +1,116 @@ +""" +Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. +Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl. +""" +from java.io import File +from wlsdeploy.aliases import alias_utils +from wlsdeploy.aliases.model_constants import EXPRESSION +from wlsdeploy.aliases.model_constants import UPDATE +from wlsdeploy.aliases.model_constants import WLS_ROLES + +WLS_GLOBAL_ROLES = { + 'Admin': '?weblogic.entitlement.rules.AdministrativeGroup(Administrators)', + 'Deployer': '?weblogic.entitlement.rules.AdministrativeGroup(Deployers)', + 'Operator': '?weblogic.entitlement.rules.AdministrativeGroup(Operators)', + 'Monitor': '?weblogic.entitlement.rules.AdministrativeGroup(Monitors)', + 'Anonymous': 'Grp(everyone)', + 'AppTester': '?weblogic.entitlement.rules.OwnerIDDGroup(AppTesters)', + 'CrossDomainConnector': '?weblogic.entitlement.rules.OwnerIDDGroup(CrossDomainConnectors)', + 'AdminChannelUser': '?weblogic.entitlement.rules.OwnerIDDGroup(AdminChannelUsers)' +} +WLS_ROLE_UPDATE_OPERAND = '|' +WLS_XACML_ROLE_MAPPER_LDIFT = 'XACMLRoleMapperInit.ldift' + +class WLSRoles(object): + """ + Handle the WLSRoles section from the model domainInfo + """ + __class_name = 'WLSRoles' + + def __init__(self, domain_info, domain_home, logger): + self.logger = logger + self._wls_roles_map = None + self._domain_security_folder = None + + if domain_info is not None: + if WLS_ROLES in domain_info: + self._wls_roles_map = domain_info[WLS_ROLES] + self._domain_security_folder = File(domain_home, 'security').getPath() + + def process_roles(self): + """ + Process the WebLogic roles contained in the domainInfo section of the model when specified + """ + _method_name = 'process_roles' + self.logger.entering(self._domain_security_folder, self._wls_roles_map, class_name=self.__class_name, method_name=_method_name) + if self._wls_roles_map is not None: + role_expressions = self._process_roles_map() + if role_expressions is not None: + self.logger.info('The WebLogic XACML role mapper will be updated with the roles: {0}', role_expressions.keys(), class_name=self.__class_name, method_name=_method_name) + self._update_xacml_role_mapper(role_expressions) + self.logger.exiting(class_name=self.__class_name, method_name=_method_name) + + def _process_roles_map(self): + """ + Loop through the WebLogic roles listed in the domainInfo and create a map of the role to the expression + """ + _method_name = '_process_roles_map' + self.logger.entering(class_name=self.__class_name, method_name=_method_name) + result = {} + role_list = self._wls_roles_map.keys() + for role in role_list: + # Get the role expression and if the role should be an update to the default set of roles + expression = self._get_role_expression(role) + if expression is None: + self.logger.warning('The role {0} has no specified expression value', role, class_name=self.__class_name, method_name=_method_name) + continue + update_role = self._is_role_updated(role) + if update_role and role not in WLS_GLOBAL_ROLES: + self.logger.warning('The role {0} is not a WebLogic global role and will use the expression as specified', role, class_name=self.__class_name, method_name=_method_name) + update_role = False + # Add the role and expression to the map of roles to be processed + if update_role: + expression = self._update_role_epression(role, expression) + result[role] = expression + + self.logger.exiting(class_name=self.__class_name, method_name=_method_name) + return result + + def _update_xacml_role_mapper(self, role_expression_map): + """ + Update the XACML role mapper based on the supplied map of WebLogic roles with expressions + """ + _method_name = '_update_xacml_role_mapper' + self.logger.entering(role_expression_map, class_name=self.__class_name, method_name=_method_name) + _xacml_ldift_file = File(self._domain_security_folder, WLS_XACML_ROLE_MAPPER_LDIFT).getPath() + self.logger.finer('Updating XACML role mapper file {0}', _xacml_ldift_file, class_name=self.__class_name, method_name=_method_name) + self.logger.exiting(class_name=self.__class_name, method_name=_method_name) + + def _get_role_expression(self, role_name): + """ + Determine if the role has an expression defined in the model + :return: the expression if the model value is present + """ + result = None + role_map = self._wls_roles_map[role_name] + if EXPRESSION in role_map: + result = role_map[EXPRESSION] + return result + + def _is_role_updated(self, role_name): + """ + Determine if the role is to be updated with the default definition + :return: True if the model value is present and indicates true, False otherwise + """ + role_map = self._wls_roles_map[role_name] + if UPDATE in role_map: + value = alias_utils.convert_to_type('boolean', role_map[UPDATE]) + return value == 'true' + return False + + def _update_role_epression(self, role_name, expression_value): + """ + Lookup the default role definition and logically OR the expressions + :return: the updated role expression + """ + return WLS_GLOBAL_ROLES[role_name] + WLS_ROLE_UPDATE_OPERAND + expression_value From 4817b16fdbeb01e6b6cd6c0442eb776743069809 Mon Sep 17 00:00:00 2001 From: TheFrogPad Date: Mon, 15 Jul 2019 19:27:26 -0400 Subject: [PATCH 02/14] Initial changes for updating role mapper ldift file with the specified expressions --- .../wlsdeploy/tool/create/domain_creator.py | 2 +- .../wlsdeploy/tool/create/wlsroles_helper.py | 11 +- .../wlsdeploy/util/weblogic_roles_helper.py | 104 ++++++++++++++++++ 3 files changed, 111 insertions(+), 6 deletions(-) create mode 100644 core/src/main/python/wlsdeploy/util/weblogic_roles_helper.py diff --git a/core/src/main/python/wlsdeploy/tool/create/domain_creator.py b/core/src/main/python/wlsdeploy/tool/create/domain_creator.py index b1ed4bb177..4f09c0dfbc 100644 --- a/core/src/main/python/wlsdeploy/tool/create/domain_creator.py +++ b/core/src/main/python/wlsdeploy/tool/create/domain_creator.py @@ -149,7 +149,7 @@ def __init__(self, model_dictionary, model_context, aliases): self.target_helper = TargetHelper(self.model, self.model_context, self.aliases, ExceptionType.CREATE, self.logger) - self.wlsroles_helper = WLSRoles(self._domain_info, self._domain_home, self.logger) + self.wlsroles_helper = WLSRoles(self._domain_info, self._domain_home, ExceptionType.CREATE, self.logger) # # This list gets modified as the domain is being created so do use this list for anything else... diff --git a/core/src/main/python/wlsdeploy/tool/create/wlsroles_helper.py b/core/src/main/python/wlsdeploy/tool/create/wlsroles_helper.py index 632de3910e..8da9ee365e 100644 --- a/core/src/main/python/wlsdeploy/tool/create/wlsroles_helper.py +++ b/core/src/main/python/wlsdeploy/tool/create/wlsroles_helper.py @@ -7,6 +7,8 @@ from wlsdeploy.aliases.model_constants import EXPRESSION from wlsdeploy.aliases.model_constants import UPDATE from wlsdeploy.aliases.model_constants import WLS_ROLES +from wlsdeploy.util.weblogic_roles_helper import WebLogicRolesHelper + WLS_GLOBAL_ROLES = { 'Admin': '?weblogic.entitlement.rules.AdministrativeGroup(Administrators)', @@ -19,7 +21,6 @@ 'AdminChannelUser': '?weblogic.entitlement.rules.OwnerIDDGroup(AdminChannelUsers)' } WLS_ROLE_UPDATE_OPERAND = '|' -WLS_XACML_ROLE_MAPPER_LDIFT = 'XACMLRoleMapperInit.ldift' class WLSRoles(object): """ @@ -27,7 +28,7 @@ class WLSRoles(object): """ __class_name = 'WLSRoles' - def __init__(self, domain_info, domain_home, logger): + def __init__(self, domain_info, domain_home, exception_type, logger): self.logger = logger self._wls_roles_map = None self._domain_security_folder = None @@ -36,6 +37,7 @@ def __init__(self, domain_info, domain_home, logger): if WLS_ROLES in domain_info: self._wls_roles_map = domain_info[WLS_ROLES] self._domain_security_folder = File(domain_home, 'security').getPath() + self._weblogic_roles_helper = WebLogicRolesHelper(logger, exception_type, self._domain_security_folder) def process_roles(self): """ @@ -46,7 +48,7 @@ def process_roles(self): if self._wls_roles_map is not None: role_expressions = self._process_roles_map() if role_expressions is not None: - self.logger.info('The WebLogic XACML role mapper will be updated with the roles: {0}', role_expressions.keys(), class_name=self.__class_name, method_name=_method_name) + self.logger.info('The WebLogic role mapper will be updated with the roles: {0}', role_expressions.keys(), class_name=self.__class_name, method_name=_method_name) self._update_xacml_role_mapper(role_expressions) self.logger.exiting(class_name=self.__class_name, method_name=_method_name) @@ -82,8 +84,7 @@ def _update_xacml_role_mapper(self, role_expression_map): """ _method_name = '_update_xacml_role_mapper' self.logger.entering(role_expression_map, class_name=self.__class_name, method_name=_method_name) - _xacml_ldift_file = File(self._domain_security_folder, WLS_XACML_ROLE_MAPPER_LDIFT).getPath() - self.logger.finer('Updating XACML role mapper file {0}', _xacml_ldift_file, class_name=self.__class_name, method_name=_method_name) + self._weblogic_roles_helper.update_xacml_role_mapper(role_expression_map) self.logger.exiting(class_name=self.__class_name, method_name=_method_name) def _get_role_expression(self, role_name): diff --git a/core/src/main/python/wlsdeploy/util/weblogic_roles_helper.py b/core/src/main/python/wlsdeploy/util/weblogic_roles_helper.py new file mode 100644 index 0000000000..9731c4441d --- /dev/null +++ b/core/src/main/python/wlsdeploy/util/weblogic_roles_helper.py @@ -0,0 +1,104 @@ +""" +Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. +Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl. +""" +import os +from java.io import File +from java.lang import String +from wlsdeploy.exception import exception_helper + +import com.bea.common.security.utils.encoders.BASE64Encoder as BASE64Encoder +import com.bea.common.security.xacml.DocumentParseException as DocumentParseException +import com.bea.common.security.xacml.URISyntaxException as URISyntaxException +import com.bea.security.providers.xacml.entitlement.EntitlementConverter as EntitlementConverter +import com.bea.security.xacml.cache.resource.ResourcePolicyIdUtil as ResourcePolicyIdUtil + +WLS_XACML_ROLE_MAPPER_LDIFT_FILENAME = 'XACMLRoleMapperInit.ldift' + +class WebLogicRolesHelper(object): + """ + Helper functions for handling WebLogic Roles + """ + __class_name = 'WebLogicRolesHelper' + + def __init__(self, logger, exception_type, domain_security_folder): + self.logger = logger + self._exception_type = exception_type + self._domain_security_folder = domain_security_folder + self._b64encoder = BASE64Encoder() + self._escaper = ResourcePolicyIdUtil.getEscaper() + self._converter = EntitlementConverter(None) + + def update_xacml_role_mapper(self, role_expressions_map): + _method_name = 'update_xacml_role_mapper' + self.logger.entering(class_name=self.__class_name, method_name=_method_name) + + try: + # Determine the current ldift file name + ldift_filename = File(self._domain_security_folder, WLS_XACML_ROLE_MAPPER_LDIFT_FILENAME).getPath() + self.logger.finer('XACML role mapper file: {0}', ldift_filename, class_name=self.__class_name, method_name=_method_name) + + # Compile expression (needs more work) + role_name = 'Admin' + role_expression = role_expressions_map['Admin'] + policy = self._converter.convertRoleExpression(None, role_name, role_expression, None) + role = self._escaper.escapeString(role_name) + cn = self._escaper.escapeString(policy.getId().toString()) + xacml = self._b64encoder.encodeBuffer(String(policy.toString()).getBytes("UTF-8")) + update_lines = ['\n'] + update_lines.append('dn: cn=' + cn + '+xacmlVersion=1.0,ou=Policies,ou=XACMLRole,ou=@realm@,dc=@domain@\n') + update_lines.append('objectclass: top\n') + update_lines.append('objectclass: xacmlEntry\n') + update_lines.append('objectclass: xacmlRoleAssignmentPolicy\n') + update_lines.append('cn: ' + cn + '\n') + update_lines.append('xacmlVersion: 1.0\n') + update_lines.append('xacmlStatus: 3\n') + update_lines.append('xacmlDocument:: ' + xacml + '\n') + update_lines.append('xacmlRole: ' + role + '\n') + update_lines.append('\n') + + # Update the ldift file (needs more work) + ldift_file = None + update_file = None + update_filename = ldift_filename + '.new' + try: + update_file = open(update_filename, 'w') + ldift_file = open(ldift_filename) + lines = ldift_file.readlines() + update_file.writelines(lines) + update_file.writelines(update_lines) + finally: + if ldift_file is not None: + ldift_file.close() + if update_file is not None: + update_file.close() + + # Backup or remove the existing ldift file + backup_filename = ldift_filename + '.bak' + if not os.path.exists(backup_filename): + self.logger.finer('Creating backup file: {0}', backup_filename, class_name=self.__class_name, method_name=_method_name) + os.rename(ldift_filename, backup_filename) + else: + os.remove(ldift_filename) + + # Rename updated ldift file to the regular ldift file + os.rename(update_filename, ldift_filename) + + except IOError, ioe: + ex = exception_helper.create_exception(self._exception_type, 'IOError: {0}', str(ioe), error=ioe) + self.logger.throwing(ex, class_name=self.__class_name, method_name=_method_name) + raise ex + except OSError, ose: + ex = exception_helper.create_exception(self._exception_type, 'OSError: {0}', str(ose), error=ose) + self.logger.throwing(ex, class_name=self.__class_name, method_name=_method_name) + raise ex + except DocumentParseException, dpe: + ex = exception_helper.create_exception(self._exception_type, 'Failed to convert role expression {0} because {1}', role_expression, dpe.getLocalizedMessage(), error=dpe) + self.logger.throwing(ex, class_name=self.__class_name, method_name=_method_name) + raise ex + except URISyntaxException, use: + ex = exception_helper.create_exception(self._exception_type, 'Failed to convert role expression {0} because {1}', role_expression, use.getLocalizedMessage(), error=use) + self.logger.throwing(ex, class_name=self.__class_name, method_name=_method_name) + raise ex + + self.logger.exiting(class_name=self.__class_name, method_name=_method_name) From 66c25fa492c11ac58edd602cb2c8e38b06fabe1e Mon Sep 17 00:00:00 2001 From: TheFrogPad Date: Tue, 16 Jul 2019 21:16:58 -0400 Subject: [PATCH 03/14] Complete the changes for updating role mapper ldift --- .../wlsdeploy/tool/create/wlsroles_helper.py | 6 +- .../wlsdeploy/util/weblogic_roles_helper.py | 129 +++++++++++++----- 2 files changed, 100 insertions(+), 35 deletions(-) diff --git a/core/src/main/python/wlsdeploy/tool/create/wlsroles_helper.py b/core/src/main/python/wlsdeploy/tool/create/wlsroles_helper.py index 8da9ee365e..7ab3b5a900 100644 --- a/core/src/main/python/wlsdeploy/tool/create/wlsroles_helper.py +++ b/core/src/main/python/wlsdeploy/tool/create/wlsroles_helper.py @@ -7,9 +7,9 @@ from wlsdeploy.aliases.model_constants import EXPRESSION from wlsdeploy.aliases.model_constants import UPDATE from wlsdeploy.aliases.model_constants import WLS_ROLES +from wlsdeploy.util import dictionary_utils from wlsdeploy.util.weblogic_roles_helper import WebLogicRolesHelper - WLS_GLOBAL_ROLES = { 'Admin': '?weblogic.entitlement.rules.AdministrativeGroup(Administrators)', 'Deployer': '?weblogic.entitlement.rules.AdministrativeGroup(Deployers)', @@ -34,7 +34,7 @@ def __init__(self, domain_info, domain_home, exception_type, logger): self._domain_security_folder = None if domain_info is not None: - if WLS_ROLES in domain_info: + if not dictionary_utils.is_empty_dictionary_element(domain_info, WLS_ROLES): self._wls_roles_map = domain_info[WLS_ROLES] self._domain_security_folder = File(domain_home, 'security').getPath() self._weblogic_roles_helper = WebLogicRolesHelper(logger, exception_type, self._domain_security_folder) @@ -47,7 +47,7 @@ def process_roles(self): self.logger.entering(self._domain_security_folder, self._wls_roles_map, class_name=self.__class_name, method_name=_method_name) if self._wls_roles_map is not None: role_expressions = self._process_roles_map() - if role_expressions is not None: + if role_expressions is not None and len(role_expressions) > 0: self.logger.info('The WebLogic role mapper will be updated with the roles: {0}', role_expressions.keys(), class_name=self.__class_name, method_name=_method_name) self._update_xacml_role_mapper(role_expressions) self.logger.exiting(class_name=self.__class_name, method_name=_method_name) diff --git a/core/src/main/python/wlsdeploy/util/weblogic_roles_helper.py b/core/src/main/python/wlsdeploy/util/weblogic_roles_helper.py index 9731c4441d..c6be905390 100644 --- a/core/src/main/python/wlsdeploy/util/weblogic_roles_helper.py +++ b/core/src/main/python/wlsdeploy/util/weblogic_roles_helper.py @@ -32,41 +32,88 @@ def __init__(self, logger, exception_type, domain_security_folder): def update_xacml_role_mapper(self, role_expressions_map): _method_name = 'update_xacml_role_mapper' self.logger.entering(class_name=self.__class_name, method_name=_method_name) + role_entries_map = self._create_xacml_role_mapper_entries(role_expressions_map) + self._update_xacml_role_mapper_ldift(role_entries_map) + self.logger.exiting(class_name=self.__class_name, method_name=_method_name) + + def _create_xacml_role_mapper_entries(self, role_expressions_map): + _method_name = '_create_xacml_role_mapper_entries' + self.logger.entering(class_name=self.__class_name, method_name=_method_name) + + entries = {} + if role_expressions_map is not None: + try: + role_list = role_expressions_map.keys() + for role_name in role_list: + # Get the role expression + role_expression = role_expressions_map[role_name] + # Convert the role expression + policy = self._converter.convertRoleExpression(None, role_name, role_expression, None) + role = self._escaper.escapeString(role_name) + cn = self._escaper.escapeString(policy.getId().toString()) + xacml = self._b64encoder.encodeBuffer(String(policy.toString()).getBytes("UTF-8")) + # Setup the lines that make up the role entry + entry = [] + entry.append('dn: cn=' + cn + '+xacmlVersion=1.0,ou=Policies,ou=XACMLRole,ou=@realm@,dc=@domain@\n') + entry.append('objectclass: top\n') + entry.append('objectclass: xacmlEntry\n') + entry.append('objectclass: xacmlRoleAssignmentPolicy\n') + entry.append('cn: ' + cn + '\n') + entry.append('xacmlVersion: 1.0\n') + entry.append('xacmlStatus: 3\n') + entry.append('xacmlDocument:: ' + xacml + '\n') + entry.append('xacmlRole: ' + role + '\n') + entry.append('\n') + # Add to the map of role entries + entries[role] = entry + + except DocumentParseException, dpe: + ex = exception_helper.create_exception(self._exception_type, 'Failed to convert role expression {0} because {1}', role_expression, dpe.getLocalizedMessage(), error=dpe) + self.logger.throwing(ex, class_name=self.__class_name, method_name=_method_name) + raise ex + except URISyntaxException, use: + ex = exception_helper.create_exception(self._exception_type, 'Failed to convert role expression {0} because {1}', role_expression, use.getLocalizedMessage(), error=use) + self.logger.throwing(ex, class_name=self.__class_name, method_name=_method_name) + raise ex + + self.logger.exiting(class_name=self.__class_name, method_name=_method_name) + return entries + + def _update_xacml_role_mapper_ldift(self, role_entries_map): + _method_name = '_update_xacml_role_mapper_ldift' + self.logger.entering(class_name=self.__class_name, method_name=_method_name) try: - # Determine the current ldift file name + # Determine the current XACML ldift file name ldift_filename = File(self._domain_security_folder, WLS_XACML_ROLE_MAPPER_LDIFT_FILENAME).getPath() self.logger.finer('XACML role mapper file: {0}', ldift_filename, class_name=self.__class_name, method_name=_method_name) - # Compile expression (needs more work) - role_name = 'Admin' - role_expression = role_expressions_map['Admin'] - policy = self._converter.convertRoleExpression(None, role_name, role_expression, None) - role = self._escaper.escapeString(role_name) - cn = self._escaper.escapeString(policy.getId().toString()) - xacml = self._b64encoder.encodeBuffer(String(policy.toString()).getBytes("UTF-8")) - update_lines = ['\n'] - update_lines.append('dn: cn=' + cn + '+xacmlVersion=1.0,ou=Policies,ou=XACMLRole,ou=@realm@,dc=@domain@\n') - update_lines.append('objectclass: top\n') - update_lines.append('objectclass: xacmlEntry\n') - update_lines.append('objectclass: xacmlRoleAssignmentPolicy\n') - update_lines.append('cn: ' + cn + '\n') - update_lines.append('xacmlVersion: 1.0\n') - update_lines.append('xacmlStatus: 3\n') - update_lines.append('xacmlDocument:: ' + xacml + '\n') - update_lines.append('xacmlRole: ' + role + '\n') - update_lines.append('\n') - - # Update the ldift file (needs more work) + # Update the XACML ldift file ldift_file = None update_file = None update_filename = ldift_filename + '.new' try: update_file = open(update_filename, 'w') ldift_file = open(ldift_filename) - lines = ldift_file.readlines() - update_file.writelines(lines) - update_file.writelines(update_lines) + # Look for existing entries to be replaced + for line in ldift_file: + if line.startswith('dn: cn='): + role_entry_lines = self.__read_xacml_role_entry(line, ldift_file) + role_name = self.__get_xacml_role_entry_name(role_entry_lines) + if role_name in role_entries_map: + self.logger.finer('Updating role: {0}', role_name, class_name=self.__class_name, method_name=_method_name) + update_file.writelines(role_entries_map[role_name]) + del role_entries_map[role_name] + else: + update_file.writelines(role_entry_lines) + else: + update_file.write(line) + # Append any remaining entries + role_names = role_entries_map.keys() + self.logger.finer('Adding roles: {0}', role_names, class_name=self.__class_name, method_name=_method_name) + for role_name in role_names: + update_file.write('\n') + update_file.writelines(role_entries_map[role_name]) finally: if ldift_file is not None: ldift_file.close() @@ -84,6 +131,10 @@ def update_xacml_role_mapper(self, role_expressions_map): # Rename updated ldift file to the regular ldift file os.rename(update_filename, ldift_filename) + except ValueError, ve: + ex = exception_helper.create_exception(self._exception_type, 'ValueError: {0}', str(ve), error=ve) + self.logger.throwing(ex, class_name=self.__class_name, method_name=_method_name) + raise ex except IOError, ioe: ex = exception_helper.create_exception(self._exception_type, 'IOError: {0}', str(ioe), error=ioe) self.logger.throwing(ex, class_name=self.__class_name, method_name=_method_name) @@ -92,13 +143,27 @@ def update_xacml_role_mapper(self, role_expressions_map): ex = exception_helper.create_exception(self._exception_type, 'OSError: {0}', str(ose), error=ose) self.logger.throwing(ex, class_name=self.__class_name, method_name=_method_name) raise ex - except DocumentParseException, dpe: - ex = exception_helper.create_exception(self._exception_type, 'Failed to convert role expression {0} because {1}', role_expression, dpe.getLocalizedMessage(), error=dpe) - self.logger.throwing(ex, class_name=self.__class_name, method_name=_method_name) - raise ex - except URISyntaxException, use: - ex = exception_helper.create_exception(self._exception_type, 'Failed to convert role expression {0} because {1}', role_expression, use.getLocalizedMessage(), error=use) - self.logger.throwing(ex, class_name=self.__class_name, method_name=_method_name) - raise ex self.logger.exiting(class_name=self.__class_name, method_name=_method_name) + + def __read_xacml_role_entry(self, start_line, ldift_file): + count = 1 + lines = [start_line] + for line in ldift_file: + count += 1 + lines.append(line) + if count == 10: + break + + if len(lines) != 10: + raise ValueError('Error reading XACML role entry!') + + if not lines[-2].startswith('xacmlRole: '): + raise ValueError('Unable to find XACML role entry!') + + return lines + + def __get_xacml_role_entry_name(self, role_entry_lines): + role_name_entry = role_entry_lines[-2] + role_name = role_name_entry[10:] + return role_name.strip() From 886ed0f3def4ddf93cd157048c2c117633e9b873 Mon Sep 17 00:00:00 2001 From: TheFrogPad Date: Tue, 16 Jul 2019 22:46:32 -0400 Subject: [PATCH 04/14] Create messages for the WebLogic role processing --- .../wlsdeploy/tool/create/wlsroles_helper.py | 9 +++++---- .../wlsdeploy/util/weblogic_roles_helper.py | 18 +++++++++--------- .../deploy/messages/wlsdeploy_rb.properties | 14 ++++++++++++++ 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/core/src/main/python/wlsdeploy/tool/create/wlsroles_helper.py b/core/src/main/python/wlsdeploy/tool/create/wlsroles_helper.py index 7ab3b5a900..12788ed474 100644 --- a/core/src/main/python/wlsdeploy/tool/create/wlsroles_helper.py +++ b/core/src/main/python/wlsdeploy/tool/create/wlsroles_helper.py @@ -8,6 +8,7 @@ from wlsdeploy.aliases.model_constants import UPDATE from wlsdeploy.aliases.model_constants import WLS_ROLES from wlsdeploy.util import dictionary_utils +from wlsdeploy.util import string_utils from wlsdeploy.util.weblogic_roles_helper import WebLogicRolesHelper WLS_GLOBAL_ROLES = { @@ -48,7 +49,7 @@ def process_roles(self): if self._wls_roles_map is not None: role_expressions = self._process_roles_map() if role_expressions is not None and len(role_expressions) > 0: - self.logger.info('The WebLogic role mapper will be updated with the roles: {0}', role_expressions.keys(), class_name=self.__class_name, method_name=_method_name) + self.logger.info('WLSDPLY-12500', role_expressions.keys(), class_name=self.__class_name, method_name=_method_name) self._update_xacml_role_mapper(role_expressions) self.logger.exiting(class_name=self.__class_name, method_name=_method_name) @@ -63,12 +64,12 @@ def _process_roles_map(self): for role in role_list: # Get the role expression and if the role should be an update to the default set of roles expression = self._get_role_expression(role) - if expression is None: - self.logger.warning('The role {0} has no specified expression value', role, class_name=self.__class_name, method_name=_method_name) + if string_utils.is_empty(expression): + self.logger.warning('WLSDPLY-12501', role, class_name=self.__class_name, method_name=_method_name) continue update_role = self._is_role_updated(role) if update_role and role not in WLS_GLOBAL_ROLES: - self.logger.warning('The role {0} is not a WebLogic global role and will use the expression as specified', role, class_name=self.__class_name, method_name=_method_name) + self.logger.warning('WLSDPLY-12502', role, class_name=self.__class_name, method_name=_method_name) update_role = False # Add the role and expression to the map of roles to be processed if update_role: diff --git a/core/src/main/python/wlsdeploy/util/weblogic_roles_helper.py b/core/src/main/python/wlsdeploy/util/weblogic_roles_helper.py index c6be905390..df2589ba98 100644 --- a/core/src/main/python/wlsdeploy/util/weblogic_roles_helper.py +++ b/core/src/main/python/wlsdeploy/util/weblogic_roles_helper.py @@ -68,11 +68,11 @@ def _create_xacml_role_mapper_entries(self, role_expressions_map): entries[role] = entry except DocumentParseException, dpe: - ex = exception_helper.create_exception(self._exception_type, 'Failed to convert role expression {0} because {1}', role_expression, dpe.getLocalizedMessage(), error=dpe) + ex = exception_helper.create_exception(self._exception_type, 'WLSDPLY-01804', role_expression, dpe.getLocalizedMessage(), error=dpe) self.logger.throwing(ex, class_name=self.__class_name, method_name=_method_name) raise ex except URISyntaxException, use: - ex = exception_helper.create_exception(self._exception_type, 'Failed to convert role expression {0} because {1}', role_expression, use.getLocalizedMessage(), error=use) + ex = exception_helper.create_exception(self._exception_type, 'WLSDPLY-01804', role_expression, use.getLocalizedMessage(), error=use) self.logger.throwing(ex, class_name=self.__class_name, method_name=_method_name) raise ex @@ -86,7 +86,7 @@ def _update_xacml_role_mapper_ldift(self, role_entries_map): try: # Determine the current XACML ldift file name ldift_filename = File(self._domain_security_folder, WLS_XACML_ROLE_MAPPER_LDIFT_FILENAME).getPath() - self.logger.finer('XACML role mapper file: {0}', ldift_filename, class_name=self.__class_name, method_name=_method_name) + self.logger.finer('WLSDPLY-01800', ldift_filename, class_name=self.__class_name, method_name=_method_name) # Update the XACML ldift file ldift_file = None @@ -101,7 +101,7 @@ def _update_xacml_role_mapper_ldift(self, role_entries_map): role_entry_lines = self.__read_xacml_role_entry(line, ldift_file) role_name = self.__get_xacml_role_entry_name(role_entry_lines) if role_name in role_entries_map: - self.logger.finer('Updating role: {0}', role_name, class_name=self.__class_name, method_name=_method_name) + self.logger.finer('WLSDPLY-01802', role_name, class_name=self.__class_name, method_name=_method_name) update_file.writelines(role_entries_map[role_name]) del role_entries_map[role_name] else: @@ -110,7 +110,7 @@ def _update_xacml_role_mapper_ldift(self, role_entries_map): update_file.write(line) # Append any remaining entries role_names = role_entries_map.keys() - self.logger.finer('Adding roles: {0}', role_names, class_name=self.__class_name, method_name=_method_name) + self.logger.finer('WLSDPLY-01803', role_names, class_name=self.__class_name, method_name=_method_name) for role_name in role_names: update_file.write('\n') update_file.writelines(role_entries_map[role_name]) @@ -123,7 +123,7 @@ def _update_xacml_role_mapper_ldift(self, role_entries_map): # Backup or remove the existing ldift file backup_filename = ldift_filename + '.bak' if not os.path.exists(backup_filename): - self.logger.finer('Creating backup file: {0}', backup_filename, class_name=self.__class_name, method_name=_method_name) + self.logger.finer('WLSDPLY-01801', backup_filename, class_name=self.__class_name, method_name=_method_name) os.rename(ldift_filename, backup_filename) else: os.remove(ldift_filename) @@ -132,15 +132,15 @@ def _update_xacml_role_mapper_ldift(self, role_entries_map): os.rename(update_filename, ldift_filename) except ValueError, ve: - ex = exception_helper.create_exception(self._exception_type, 'ValueError: {0}', str(ve), error=ve) + ex = exception_helper.create_exception(self._exception_type, 'WLSDPLY-01805', 'ValueError', str(ve), error=ve) self.logger.throwing(ex, class_name=self.__class_name, method_name=_method_name) raise ex except IOError, ioe: - ex = exception_helper.create_exception(self._exception_type, 'IOError: {0}', str(ioe), error=ioe) + ex = exception_helper.create_exception(self._exception_type, 'WLSDPLY-01805', 'IOError', str(ioe), error=ioe) self.logger.throwing(ex, class_name=self.__class_name, method_name=_method_name) raise ex except OSError, ose: - ex = exception_helper.create_exception(self._exception_type, 'OSError: {0}', str(ose), error=ose) + ex = exception_helper.create_exception(self._exception_type, 'WLSDPLY-01805', 'OSError', str(ose), error=ose) self.logger.throwing(ex, class_name=self.__class_name, method_name=_method_name) raise ex diff --git a/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties b/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties index fedb0541f3..5185f912ba 100644 --- a/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties +++ b/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties @@ -314,6 +314,14 @@ WLSDPLY-01786=MBean {0} getter {1} is not an attribute on the mbean instance WLSDPLY-01787=The list of attributes to discover that are not in the LSA map {0} WLSDPLY-01788=Attribute {0} from {1} not found in {2} +# wlsdeploy/util/weblogic_roles_helper.py +WLSDPLY-01800=Updating role mapper file: {0} +WLSDPLY-01801=Creating backup file: {0} +WLSDPLY-01802=Updating role: {0} +WLSDPLY-01803=Adding roles: {0} +WLSDPLY-01804=Failed to convert role expression {0} because {1} +WLSDPLY-01805=Unexpected {0} during role mapper processing: {1} + ############################################################################### # Encrypt Messages (04000 - 04999) # ############################################################################### @@ -1089,6 +1097,7 @@ WLSDPLY-12247=WebLogic does not support targeting resources to dynamic servers. will be targeted to the dynamic cluster using the applyJRF function. WLSDPLY-12248=The server group(s) {0} will not be targeted to the Admin server or a configured manage server + # domain_typedef.py WLSDPLY-12300={0} got the domain type {1} but the domain type definition file {2} was not valid: {3} WLSDPLY-12301={0} failed to load the definition for domain type {1} from {2} due to a parsing error: {3} @@ -1125,6 +1134,11 @@ WLSDPLY-12412=The model file specified ATP database info without oracle.net.tns_ archive specified WLSDPLY-12413=The model file specified RCUDbInfo section but key {0} is None or missing. Required keys are {1} +# wlsroles_helper.py +WLSDPLY-12500=The WebLogic role mapper will be updated with the roles: {0} +WLSDPLY-12501=The role {0} has no specified expression value +WLSDPLY-12502=The role {0} is not a WebLogic global role and will use the expression as specified + ############################################################################### # YAML/JSON messages (18000 - 18999) # ############################################################################### From 86717ba54bbab3db464a50712b139105cad5f3f6 Mon Sep 17 00:00:00 2001 From: TheFrogPad Date: Wed, 17 Jul 2019 14:39:48 -0400 Subject: [PATCH 05/14] Add WebLogic Server version check --- .../wlsdeploy/tool/create/domain_creator.py | 3 ++- .../wlsdeploy/tool/create/wlsroles_helper.py | 18 ++++++++++++------ .../deploy/messages/wlsdeploy_rb.properties | 2 +- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/core/src/main/python/wlsdeploy/tool/create/domain_creator.py b/core/src/main/python/wlsdeploy/tool/create/domain_creator.py index 4f09c0dfbc..be51f17534 100644 --- a/core/src/main/python/wlsdeploy/tool/create/domain_creator.py +++ b/core/src/main/python/wlsdeploy/tool/create/domain_creator.py @@ -149,7 +149,8 @@ def __init__(self, model_dictionary, model_context, aliases): self.target_helper = TargetHelper(self.model, self.model_context, self.aliases, ExceptionType.CREATE, self.logger) - self.wlsroles_helper = WLSRoles(self._domain_info, self._domain_home, ExceptionType.CREATE, self.logger) + self.wlsroles_helper = WLSRoles(self._domain_info, self._domain_home, self.wls_helper, + ExceptionType.CREATE, self.logger) # # This list gets modified as the domain is being created so do use this list for anything else... diff --git a/core/src/main/python/wlsdeploy/tool/create/wlsroles_helper.py b/core/src/main/python/wlsdeploy/tool/create/wlsroles_helper.py index 12788ed474..7af94bb607 100644 --- a/core/src/main/python/wlsdeploy/tool/create/wlsroles_helper.py +++ b/core/src/main/python/wlsdeploy/tool/create/wlsroles_helper.py @@ -29,8 +29,9 @@ class WLSRoles(object): """ __class_name = 'WLSRoles' - def __init__(self, domain_info, domain_home, exception_type, logger): + def __init__(self, domain_info, domain_home, wls_helper, exception_type, logger): self.logger = logger + self._wls_helper = wls_helper self._wls_roles_map = None self._domain_security_folder = None @@ -42,15 +43,20 @@ def __init__(self, domain_info, domain_home, exception_type, logger): def process_roles(self): """ - Process the WebLogic roles contained in the domainInfo section of the model when specified + Process the WebLogic roles contained in the domainInfo section of the model when specified + Support for the WebLogic roles handling is when using WebLogic Server 12.2.1 or greater """ _method_name = 'process_roles' self.logger.entering(self._domain_security_folder, self._wls_roles_map, class_name=self.__class_name, method_name=_method_name) if self._wls_roles_map is not None: - role_expressions = self._process_roles_map() - if role_expressions is not None and len(role_expressions) > 0: - self.logger.info('WLSDPLY-12500', role_expressions.keys(), class_name=self.__class_name, method_name=_method_name) - self._update_xacml_role_mapper(role_expressions) + # Process the WLSRoles section after checking for proper version support + if not self._wls_helper.is_weblogic_version_or_above('12.2.1'): + self.logger.warning('WLSDPLY-12503', self._wls_helper.get_actual_weblogic_version(), class_name=self.__class_name, method_name=_method_name) + else: + role_expressions = self._process_roles_map() + if role_expressions is not None and len(role_expressions) > 0: + self.logger.info('WLSDPLY-12500', role_expressions.keys(), class_name=self.__class_name, method_name=_method_name) + self._update_xacml_role_mapper(role_expressions) self.logger.exiting(class_name=self.__class_name, method_name=_method_name) def _process_roles_map(self): diff --git a/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties b/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties index 5185f912ba..4b72108457 100644 --- a/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties +++ b/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties @@ -1097,7 +1097,6 @@ WLSDPLY-12247=WebLogic does not support targeting resources to dynamic servers. will be targeted to the dynamic cluster using the applyJRF function. WLSDPLY-12248=The server group(s) {0} will not be targeted to the Admin server or a configured manage server - # domain_typedef.py WLSDPLY-12300={0} got the domain type {1} but the domain type definition file {2} was not valid: {3} WLSDPLY-12301={0} failed to load the definition for domain type {1} from {2} due to a parsing error: {3} @@ -1138,6 +1137,7 @@ WLSDPLY-12413=The model file specified RCUDbInfo section but key {0} is None or WLSDPLY-12500=The WebLogic role mapper will be updated with the roles: {0} WLSDPLY-12501=The role {0} has no specified expression value WLSDPLY-12502=The role {0} is not a WebLogic global role and will use the expression as specified +WLSDPLY-12503=The processing of WebLogic roles from the model is not support with WebLogic Server version {0} ############################################################################### # YAML/JSON messages (18000 - 18999) # From 07b25703e7127e4938525e0688e09380b28d1e15 Mon Sep 17 00:00:00 2001 From: TheFrogPad Date: Wed, 17 Jul 2019 18:01:46 -0400 Subject: [PATCH 06/14] Switch to use of update mode with support for append or prepend --- .../wlsdeploy/aliases/model_constants.py | 5 ++- .../wlsdeploy/tool/create/wlsroles_helper.py | 41 +++++++++++++------ 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/core/src/main/python/wlsdeploy/aliases/model_constants.py b/core/src/main/python/wlsdeploy/aliases/model_constants.py index a7f3dc1458..f89a15dd76 100644 --- a/core/src/main/python/wlsdeploy/aliases/model_constants.py +++ b/core/src/main/python/wlsdeploy/aliases/model_constants.py @@ -17,6 +17,7 @@ ADMIN_USERNAME = 'AdminUserName' APP_DEPLOYMENTS = 'appDeployments' APP_DIR = 'AppDir' +APPEND = 'append' APPLICATION = 'Application' RCU_DB_INFO = 'RCUDbInfo' OPSS_SECRETS = 'OPSSSecrets' @@ -184,11 +185,13 @@ PKI_CREDENTIAL_MAPPER = 'PKICredentialMapper' PLAN_DIR = 'PlanDir' PLAN_PATH = 'PlanPath' +PREPEND = 'prepend' PROPERTIES = 'Properties' QUEUE = 'Queue' QUOTA = 'Quota' REALM = 'Realm' RECOVER_ONLY_ONCE = 'RecoverOnlyOnce' +REPLACE = 'replace' RESOURCE_GROUP = 'ResourceGroup' RESOURCE_GROUP_TEMPLATE = 'ResourceGroupTemplate' RESOURCES = 'resources' @@ -249,7 +252,7 @@ UNIFORM_DISTRIBUTED_QUEUE = 'UniformDistributedQueue' UNIFORM_DISTRIBUTED_TOPIC = 'UniformDistributedTopic' UNIX_MACHINE = 'UnixMachine' -UPDATE = 'Update' +UPDATE_MODE = 'UpdateMode' USER = 'User' VIRTUAL_TARGET = 'VirtualTarget' VIRTUAL_USER_AUTHENTICATOR = 'VirtualUserAuthenticator' diff --git a/core/src/main/python/wlsdeploy/tool/create/wlsroles_helper.py b/core/src/main/python/wlsdeploy/tool/create/wlsroles_helper.py index 7af94bb607..d5c50b78a2 100644 --- a/core/src/main/python/wlsdeploy/tool/create/wlsroles_helper.py +++ b/core/src/main/python/wlsdeploy/tool/create/wlsroles_helper.py @@ -3,9 +3,11 @@ Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl. """ from java.io import File -from wlsdeploy.aliases import alias_utils +from wlsdeploy.aliases.model_constants import APPEND from wlsdeploy.aliases.model_constants import EXPRESSION -from wlsdeploy.aliases.model_constants import UPDATE +from wlsdeploy.aliases.model_constants import PREPEND +from wlsdeploy.aliases.model_constants import REPLACE +from wlsdeploy.aliases.model_constants import UPDATE_MODE from wlsdeploy.aliases.model_constants import WLS_ROLES from wlsdeploy.util import dictionary_utils from wlsdeploy.util import string_utils @@ -73,7 +75,7 @@ def _process_roles_map(self): if string_utils.is_empty(expression): self.logger.warning('WLSDPLY-12501', role, class_name=self.__class_name, method_name=_method_name) continue - update_role = self._is_role_updated(role) + update_role = self._is_role_update_mode(role) if update_role and role not in WLS_GLOBAL_ROLES: self.logger.warning('WLSDPLY-12502', role, class_name=self.__class_name, method_name=_method_name) update_role = False @@ -105,20 +107,35 @@ def _get_role_expression(self, role_name): result = role_map[EXPRESSION] return result - def _is_role_updated(self, role_name): + def _is_role_update_mode(self, role_name): """ - Determine if the role is to be updated with the default definition - :return: True if the model value is present and indicates true, False otherwise + Determine if the role update mode indicates that a role update is specified + :return: True if the update mode value is present and set to append or prepend mode """ + result = False role_map = self._wls_roles_map[role_name] - if UPDATE in role_map: - value = alias_utils.convert_to_type('boolean', role_map[UPDATE]) - return value == 'true' - return False + if UPDATE_MODE in role_map: + mode = role_map[UPDATE_MODE] + if not string_utils.is_empty(mode): + mode = mode.lower() + if APPEND == mode or PREPEND == mode: + result = True + return result def _update_role_epression(self, role_name, expression_value): """ - Lookup the default role definition and logically OR the expressions + Lookup the default role definition and logically OR the expression + Based on the update mode the expression is appended or prepended :return: the updated role expression """ - return WLS_GLOBAL_ROLES[role_name] + WLS_ROLE_UPDATE_OPERAND + expression_value + result = expression_value + role_map = self._wls_roles_map[role_name] + if UPDATE_MODE in role_map: + mode = role_map[UPDATE_MODE] + if not string_utils.is_empty(mode): + mode = mode.lower() + if APPEND == mode: + result = WLS_GLOBAL_ROLES[role_name] + WLS_ROLE_UPDATE_OPERAND + expression_value + elif PREPEND == mode: + result = expression_value + WLS_ROLE_UPDATE_OPERAND + WLS_GLOBAL_ROLES[role_name] + return result From 2a45a64f107e6ad42eeb02081ad36dfbcfd0aa32 Mon Sep 17 00:00:00 2001 From: TheFrogPad Date: Thu, 18 Jul 2019 11:14:46 -0400 Subject: [PATCH 07/14] Fix message for invalid expression --- core/src/main/python/wlsdeploy/util/weblogic_roles_helper.py | 4 ++-- .../oracle/weblogic/deploy/messages/wlsdeploy_rb.properties | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/python/wlsdeploy/util/weblogic_roles_helper.py b/core/src/main/python/wlsdeploy/util/weblogic_roles_helper.py index df2589ba98..d9065145d6 100644 --- a/core/src/main/python/wlsdeploy/util/weblogic_roles_helper.py +++ b/core/src/main/python/wlsdeploy/util/weblogic_roles_helper.py @@ -68,11 +68,11 @@ def _create_xacml_role_mapper_entries(self, role_expressions_map): entries[role] = entry except DocumentParseException, dpe: - ex = exception_helper.create_exception(self._exception_type, 'WLSDPLY-01804', role_expression, dpe.getLocalizedMessage(), error=dpe) + ex = exception_helper.create_exception(self._exception_type, 'WLSDPLY-01804', role_name, role_expression, dpe.getLocalizedMessage(), error=dpe) self.logger.throwing(ex, class_name=self.__class_name, method_name=_method_name) raise ex except URISyntaxException, use: - ex = exception_helper.create_exception(self._exception_type, 'WLSDPLY-01804', role_expression, use.getLocalizedMessage(), error=use) + ex = exception_helper.create_exception(self._exception_type, 'WLSDPLY-01804', role_name, role_expression, use.getLocalizedMessage(), error=use) self.logger.throwing(ex, class_name=self.__class_name, method_name=_method_name) raise ex diff --git a/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties b/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties index 4b72108457..f0903529bd 100644 --- a/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties +++ b/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties @@ -319,7 +319,7 @@ WLSDPLY-01800=Updating role mapper file: {0} WLSDPLY-01801=Creating backup file: {0} WLSDPLY-01802=Updating role: {0} WLSDPLY-01803=Adding roles: {0} -WLSDPLY-01804=Failed to convert role expression {0} because {1} +WLSDPLY-01804=Failed to convert role {0} with expression {1} because {2} WLSDPLY-01805=Unexpected {0} during role mapper processing: {1} ############################################################################### From edbd0e666ee8c6018444bd096f9d538196ccce72 Mon Sep 17 00:00:00 2001 From: TheFrogPad Date: Thu, 18 Jul 2019 16:41:47 -0400 Subject: [PATCH 08/14] Updates to add validation, hook up to the validator and use valdation warnings --- .../python/wlsdeploy/aliases/alias_entries.py | 2 +- .../wlsdeploy/tool/create/wlsroles_helper.py | 84 +++++++++++++++---- .../wlsdeploy/tool/validate/validator.py | 51 +++++++++-- .../wlsdeploy/util/weblogic_roles_helper.py | 6 +- .../deploy/messages/wlsdeploy_rb.properties | 3 +- 5 files changed, 118 insertions(+), 28 deletions(-) diff --git a/core/src/main/python/wlsdeploy/aliases/alias_entries.py b/core/src/main/python/wlsdeploy/aliases/alias_entries.py index 269fb79742..fdf75ecec0 100644 --- a/core/src/main/python/wlsdeploy/aliases/alias_entries.py +++ b/core/src/main/python/wlsdeploy/aliases/alias_entries.py @@ -186,7 +186,7 @@ class AliasEntries(object): # servers in the domain. 'ServerGroupTargetingLimits': 'dict', 'RCUDbInfo': 'dict', - 'OPSSSecrets': 'string', + 'OPSSSecrets': 'password', 'WLSRoles': 'dict' } diff --git a/core/src/main/python/wlsdeploy/tool/create/wlsroles_helper.py b/core/src/main/python/wlsdeploy/tool/create/wlsroles_helper.py index d5c50b78a2..a27f53214a 100644 --- a/core/src/main/python/wlsdeploy/tool/create/wlsroles_helper.py +++ b/core/src/main/python/wlsdeploy/tool/create/wlsroles_helper.py @@ -31,17 +31,19 @@ class WLSRoles(object): """ __class_name = 'WLSRoles' - def __init__(self, domain_info, domain_home, wls_helper, exception_type, logger): + def __init__(self, domain_info, domain_home, wls_helper, exception_type, logger, validation_roles_map = None): self.logger = logger self._wls_helper = wls_helper self._wls_roles_map = None self._domain_security_folder = None + self._validation_roles_map = validation_roles_map if domain_info is not None: if not dictionary_utils.is_empty_dictionary_element(domain_info, WLS_ROLES): self._wls_roles_map = domain_info[WLS_ROLES] self._domain_security_folder = File(domain_home, 'security').getPath() self._weblogic_roles_helper = WebLogicRolesHelper(logger, exception_type, self._domain_security_folder) + return def process_roles(self): """ @@ -52,36 +54,52 @@ def process_roles(self): self.logger.entering(self._domain_security_folder, self._wls_roles_map, class_name=self.__class_name, method_name=_method_name) if self._wls_roles_map is not None: # Process the WLSRoles section after checking for proper version support - if not self._wls_helper.is_weblogic_version_or_above('12.2.1'): - self.logger.warning('WLSDPLY-12503', self._wls_helper.get_actual_weblogic_version(), class_name=self.__class_name, method_name=_method_name) + if self._wls_helper is not None and not self._wls_helper.is_weblogic_version_or_above('12.2.1'): + self.logger.warning('WLSDPLY-12504', self._wls_helper.get_actual_weblogic_version(), class_name=self.__class_name, method_name=_method_name) else: - role_expressions = self._process_roles_map() + role_expressions = self._process_roles_map(self._wls_roles_map, None) if role_expressions is not None and len(role_expressions) > 0: self.logger.info('WLSDPLY-12500', role_expressions.keys(), class_name=self.__class_name, method_name=_method_name) self._update_xacml_role_mapper(role_expressions) self.logger.exiting(class_name=self.__class_name, method_name=_method_name) + return - def _process_roles_map(self): + def validate_roles(self, validation_result): + """ + Validate WLSRoles section of the domainInfo independent of any domain home location + """ + _method_name = 'validate_roles' + self.logger.entering(self._validation_roles_map, class_name=self.__class_name, method_name=_method_name) + if self._validation_roles_map is not None and len(self._validation_roles_map) > 0: + self._validate_update_mode(self._validation_roles_map, validation_result) + self._process_roles_map(self._validation_roles_map, validation_result) + self.logger.exiting(class_name=self.__class_name, method_name=_method_name) + return validation_result + + def _process_roles_map(self, roles_map, validation_result): """ Loop through the WebLogic roles listed in the domainInfo and create a map of the role to the expression """ _method_name = '_process_roles_map' self.logger.entering(class_name=self.__class_name, method_name=_method_name) result = {} - role_list = self._wls_roles_map.keys() - for role in role_list: + for role in roles_map.keys(): # Get the role expression and if the role should be an update to the default set of roles - expression = self._get_role_expression(role) + expression = self._get_role_expression(role, roles_map) if string_utils.is_empty(expression): - self.logger.warning('WLSDPLY-12501', role, class_name=self.__class_name, method_name=_method_name) + self.logger.finer('WLSDPLY-12501', role, class_name=self.__class_name, method_name=_method_name) + if validation_result is not None: + validation_result.add_warning('WLSDPLY-12501', role) continue - update_role = self._is_role_update_mode(role) + update_role = self._is_role_update_mode(role, roles_map) if update_role and role not in WLS_GLOBAL_ROLES: - self.logger.warning('WLSDPLY-12502', role, class_name=self.__class_name, method_name=_method_name) + self.logger.finer('WLSDPLY-12502', role, class_name=self.__class_name, method_name=_method_name) + if validation_result is not None: + validation_result.add_warning('WLSDPLY-12502', role) update_role = False # Add the role and expression to the map of roles to be processed if update_role: - expression = self._update_role_epression(role, expression) + expression = self._update_role_epression(role, expression, roles_map) result[role] = expression self.logger.exiting(class_name=self.__class_name, method_name=_method_name) @@ -95,25 +113,26 @@ def _update_xacml_role_mapper(self, role_expression_map): self.logger.entering(role_expression_map, class_name=self.__class_name, method_name=_method_name) self._weblogic_roles_helper.update_xacml_role_mapper(role_expression_map) self.logger.exiting(class_name=self.__class_name, method_name=_method_name) + return - def _get_role_expression(self, role_name): + def _get_role_expression(self, role_name, roles_map): """ Determine if the role has an expression defined in the model :return: the expression if the model value is present """ result = None - role_map = self._wls_roles_map[role_name] + role_map = roles_map[role_name] if EXPRESSION in role_map: result = role_map[EXPRESSION] return result - def _is_role_update_mode(self, role_name): + def _is_role_update_mode(self, role_name, roles_map): """ Determine if the role update mode indicates that a role update is specified :return: True if the update mode value is present and set to append or prepend mode """ result = False - role_map = self._wls_roles_map[role_name] + role_map = roles_map[role_name] if UPDATE_MODE in role_map: mode = role_map[UPDATE_MODE] if not string_utils.is_empty(mode): @@ -122,14 +141,14 @@ def _is_role_update_mode(self, role_name): result = True return result - def _update_role_epression(self, role_name, expression_value): + def _update_role_epression(self, role_name, expression_value, roles_map): """ Lookup the default role definition and logically OR the expression Based on the update mode the expression is appended or prepended :return: the updated role expression """ result = expression_value - role_map = self._wls_roles_map[role_name] + role_map = roles_map[role_name] if UPDATE_MODE in role_map: mode = role_map[UPDATE_MODE] if not string_utils.is_empty(mode): @@ -139,3 +158,32 @@ def _update_role_epression(self, role_name, expression_value): elif PREPEND == mode: result = expression_value + WLS_ROLE_UPDATE_OPERAND + WLS_GLOBAL_ROLES[role_name] return result + + def _validate_update_mode(self, roles_map, validation_result): + """ + Check that the UpdateMode value of a role is one of append, prepend or replace + Provide a warning for other values as these will be treated as the default of replace + """ + _method_name = '_validate_update_mode' + self.logger.entering(class_name=self.__class_name, method_name=_method_name) + + for role_name in roles_map.keys(): + role_map = roles_map[role_name] + if UPDATE_MODE in role_map: + mode = role_map[UPDATE_MODE] + if not string_utils.is_empty(mode): + mode = mode.lower() + if APPEND == mode or PREPEND == mode or REPLACE == mode: + continue + self.logger.finer('WLSDPLY-12503', role_name, class_name=self.__class_name, method_name=_method_name) + if validation_result is not None: + validation_result.add_warning('WLSDPLY-12503', role_name) + + self.logger.exiting(class_name=self.__class_name, method_name=_method_name) + return + +def validator(roles_map, logger): + """ + Obtain a WLSRoles helper only for the validation of the WLSRoles section + """ + return WLSRoles(None, None, None, None, logger, validation_roles_map = roles_map) diff --git a/core/src/main/python/wlsdeploy/tool/validate/validator.py b/core/src/main/python/wlsdeploy/tool/validate/validator.py index 695b08e4c1..cf391f0f23 100644 --- a/core/src/main/python/wlsdeploy/tool/validate/validator.py +++ b/core/src/main/python/wlsdeploy/tool/validate/validator.py @@ -16,6 +16,7 @@ from wlsdeploy.exception.expection_types import ExceptionType from wlsdeploy.exception import exception_helper from wlsdeploy.logging.platform_logger import PlatformLogger +from wlsdeploy.tool.create import wlsroles_helper from wlsdeploy.tool.util.alias_helper import AliasHelper from wlsdeploy.tool.util.archive_helper import ArchiveHelper from wlsdeploy.tool.validate import validation_utils @@ -32,6 +33,7 @@ from wlsdeploy.aliases.model_constants import NAME from wlsdeploy.aliases.model_constants import SERVER_GROUP_TARGETING_LIMITS from wlsdeploy.aliases.model_constants import TOPOLOGY +from wlsdeploy.aliases.model_constants import WLS_ROLES _class_name = 'Validator' _logger = PlatformLogger('wlsdeploy.validate') @@ -210,6 +212,17 @@ def print_usage(self, model_path, control_option=None): # #################################################################################### + def __get_attribute_log_value(self, attribute_name, attribute_value, attribute_infos): + """ + Get the log output for an attribute value to protect sensitive data + """ + result = attribute_value + if attribute_name in attribute_infos: + expected_data_type = dictionary_utils.get_element(attribute_infos, attribute_name) + if expected_data_type == 'password': + result = '' + return result + def __validate_model_file(self, model_dict, variables_file_name, archive_file_name): _method_name = '__validate_model_file' @@ -387,7 +400,8 @@ def __validate_domain_info_section(self, model_section_key, model_dict, validati if '${' in section_dict_key: validation_result.add_error('WLSDPLY-05035', model_folder_path, section_dict_key) - self._logger.finer('WLSDPLY-05011', section_dict_key, section_dict_value, + log_value = self.__get_attribute_log_value(section_dict_key, section_dict_value, valid_attr_infos) + self._logger.finer('WLSDPLY-05011', section_dict_key, log_value, class_name=_class_name, method_name=_method_name) if section_dict_key in valid_attr_infos: @@ -405,6 +419,14 @@ def __validate_domain_info_section(self, model_section_key, model_dict, validati model_folder_path, validation_location, validation_result) + elif section_dict_key == WLS_ROLES: + validation_result = self.__validate_wlsroles_section(section_dict_key, + section_dict_value, + valid_attr_infos, + path_tokens_attr_keys, + model_folder_path, + validation_location, + validation_result) else: validation_result = self.__validate_attribute(section_dict_key, section_dict_value, @@ -740,11 +762,7 @@ def __validate_attribute(self, attribute_name, attribute_value, valid_attr_infos model_folder_path, validation_location, validation_result): _method_name = '__validate_attribute' - log_value = attribute_value - expected_data_type = dictionary_utils.get_element(valid_attr_infos, attribute_name) - if expected_data_type == 'password': - log_value = '' - + log_value = self.__get_attribute_log_value(attribute_name, attribute_value, valid_attr_infos) self._logger.entering(attribute_name, log_value, str(valid_attr_infos), str(path_tokens_attr_keys), model_folder_path, str(validation_location), class_name=_class_name, method_name=_method_name) @@ -980,6 +998,27 @@ def __validate_server_group_targeting_limits(self, attribute_name, attribute_val self._logger.exiting(class_name=_class_name, method_name=__method_name) return validation_result + def __validate_wlsroles_section(self, attribute_name, attribute_value, valid_attr_infos, path_tokens_attr_keys, + model_folder_path, validation_location, validation_result): + __method_name = '__validate_wlsroles_section' + self._logger.entering(class_name=_class_name, method_name=__method_name) + + # Validate the basics of the WLSRoles section definition + validation_result = self.__validate_attribute(attribute_name, + attribute_value, + valid_attr_infos, + path_tokens_attr_keys, + model_folder_path, + validation_location, + validation_result) + + # Validate WebLogic role content using WLSRoles helper + wlsroles_validator = wlsroles_helper.validator(attribute_value, self._logger) + validation_result = wlsroles_validator.validate_roles(validation_result) + + self._logger.exiting(class_name=_class_name, method_name=__method_name) + return validation_result + def _validate_single_server_group_target_limits_value(key, value, model_folder_path, validation_result): if type(value) is str: diff --git a/core/src/main/python/wlsdeploy/util/weblogic_roles_helper.py b/core/src/main/python/wlsdeploy/util/weblogic_roles_helper.py index d9065145d6..6dced8309e 100644 --- a/core/src/main/python/wlsdeploy/util/weblogic_roles_helper.py +++ b/core/src/main/python/wlsdeploy/util/weblogic_roles_helper.py @@ -28,6 +28,7 @@ def __init__(self, logger, exception_type, domain_security_folder): self._b64encoder = BASE64Encoder() self._escaper = ResourcePolicyIdUtil.getEscaper() self._converter = EntitlementConverter(None) + return def update_xacml_role_mapper(self, role_expressions_map): _method_name = 'update_xacml_role_mapper' @@ -35,6 +36,7 @@ def update_xacml_role_mapper(self, role_expressions_map): role_entries_map = self._create_xacml_role_mapper_entries(role_expressions_map) self._update_xacml_role_mapper_ldift(role_entries_map) self.logger.exiting(class_name=self.__class_name, method_name=_method_name) + return def _create_xacml_role_mapper_entries(self, role_expressions_map): _method_name = '_create_xacml_role_mapper_entries' @@ -43,8 +45,7 @@ def _create_xacml_role_mapper_entries(self, role_expressions_map): entries = {} if role_expressions_map is not None: try: - role_list = role_expressions_map.keys() - for role_name in role_list: + for role_name in role_expressions_map.keys(): # Get the role expression role_expression = role_expressions_map[role_name] # Convert the role expression @@ -145,6 +146,7 @@ def _update_xacml_role_mapper_ldift(self, role_entries_map): raise ex self.logger.exiting(class_name=self.__class_name, method_name=_method_name) + return def __read_xacml_role_entry(self, start_line, ldift_file): count = 1 diff --git a/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties b/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties index f0903529bd..62ec206935 100644 --- a/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties +++ b/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties @@ -1137,7 +1137,8 @@ WLSDPLY-12413=The model file specified RCUDbInfo section but key {0} is None or WLSDPLY-12500=The WebLogic role mapper will be updated with the roles: {0} WLSDPLY-12501=The role {0} has no specified expression value WLSDPLY-12502=The role {0} is not a WebLogic global role and will use the expression as specified -WLSDPLY-12503=The processing of WebLogic roles from the model is not support with WebLogic Server version {0} +WLSDPLY-12503=The role {0} specifies an invalid update mode and will use the default replace mode +WLSDPLY-12504=The processing of WebLogic roles from the model is not support with WebLogic Server version {0} ############################################################################### # YAML/JSON messages (18000 - 18999) # From a5de6dd32363e2200d72f07b8cf6ea6d23ebc4ea Mon Sep 17 00:00:00 2001 From: TheFrogPad Date: Fri, 19 Jul 2019 12:57:19 -0400 Subject: [PATCH 09/14] Improve warning message and add test case --- .../deploy/messages/wlsdeploy_rb.properties | 2 +- core/src/test/python/validation_test.py | 41 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties b/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties index 62ec206935..d987ad7c7a 100644 --- a/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties +++ b/core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties @@ -1135,7 +1135,7 @@ WLSDPLY-12413=The model file specified RCUDbInfo section but key {0} is None or # wlsroles_helper.py WLSDPLY-12500=The WebLogic role mapper will be updated with the roles: {0} -WLSDPLY-12501=The role {0} has no specified expression value +WLSDPLY-12501=The role {0} has no specified expression value and will be ignored WLSDPLY-12502=The role {0} is not a WebLogic global role and will use the expression as specified WLSDPLY-12503=The role {0} specifies an invalid update mode and will use the default replace mode WLSDPLY-12504=The processing of WebLogic roles from the model is not support with WebLogic Server version {0} diff --git a/core/src/test/python/validation_test.py b/core/src/test/python/validation_test.py index 623a593e45..5e00252f83 100644 --- a/core/src/test/python/validation_test.py +++ b/core/src/test/python/validation_test.py @@ -19,6 +19,9 @@ import oracle.weblogic.deploy.util.TranslateException as TranslateException from oracle.weblogic.deploy.validate import ValidateException +from wlsdeploy.tool.create import wlsroles_helper +from wlsdeploy.tool.validate.validation_results import ValidationResult + class ValidationTestCase(unittest.TestCase): _program_name = 'validation_test' _class_name = 'ValidationTestCase' @@ -232,5 +235,43 @@ def testYamlModelValidation(self): self.assertNotEqual(return_code, Validator.ReturnCode.STOP) + def testWLSRolesValidation(self): + """ + Run the validation portion of the WLSRoles helper and check for expected results. + """ + _method_name = 'testWLSRolesValidation' + + validation_result = ValidationResult('Test WLSRoles Section') + wlsroles_dict = {'Admin': {'UpdateMode': 'append', + 'Expression': 'Grp(AppAdmin)'}, + 'Deployer': {'UpdateMode': 'prepend', + 'Expression': 'Grp(AppDeployer)'}, + 'Tester': {'Expression': 'Grp(AppTester)'}, + 'MyEmpty': { }, + 'MyTester': {'UpdateMode': 'append', + 'Expression': 'Grp(MyTester)'}, + 'MyTester2': {'UpdateMode': 'replace', + 'Expression': 'Grp(MyTester2)'}, + 'MyTester3': {'UpdateMode': 'bad', + 'Expression': 'Grp(MyTester3)'}} + + wlsroles_validator = wlsroles_helper.validator(wlsroles_dict, self._logger) + validation_result = wlsroles_validator.validate_roles(validation_result) + self._logger.info('The WLSRoles validation result is: {0}', validation_result, + class_name=self._class_name, method_name=_method_name) + + # Verify only warnings resulted + self.assertEqual(validation_result.get_errors_count(), 0) + self.assertEqual(validation_result.get_warnings_count(), 3) + self.assertEqual(validation_result.get_infos_count(), 0) + + # Verify each warning message is a different message id + msgid_dict = {} + warn_msg_list = validation_result.get_warnings_messages() + for warn_msg in warn_msg_list: + id = warn_msg['resource_id'] + msgid_dict[id] = 'true' + self.assertEqual(len(msgid_dict), 3) + if __name__ == '__main__': unittest.main() From 7f33ab9253aa5e4e0d5bff961c31a317222c033f Mon Sep 17 00:00:00 2001 From: TheFrogPad Date: Fri, 19 Jul 2019 17:02:36 -0400 Subject: [PATCH 10/14] Add some documentation on security related topics including user, groups and roles --- README.md | 8 +++-- site/security.md | 7 ++++ site/security_users_groups_roles.md | 53 +++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 site/security.md create mode 100644 site/security_users_groups_roles.md diff --git a/README.md b/README.md index 9a25cded2a..cd2aaed2d1 100644 --- a/README.md +++ b/README.md @@ -16,9 +16,11 @@ Many organizations are using WebLogic Server, with or without other Oracle Fusio - [Model Names](#model-names) - [Model Semantics](#model-semantics) - [Administration Server Configuration](site/admin_server.md) - - [Modeling Security Providers](site/security_providers.md) - - [JRF Trust Service Identity Asserter](site/security_providers.md#trust-service-identity-asserter) - - [Custom Security Providers](site/security_providers.md#custom-security-providers) + - [Model Security](site/security.md) + - [Modeling Security Providers](site/security_providers.md) + - [JRF Trust Service Identity Asserter](site/security_providers.md#trust-service-identity-asserter) + - [Custom Security Providers](site/security_providers.md#custom-security-providers) + - [Modeling WebLogic Users, Groups and Roles](site/security_users_groups_roles.md) - [Variable Injection](site/variable_injection.md) - [Model Filters](site/tool_filters.md) - [Downloading and Installing](#downloading-and-installing-the-software) diff --git a/site/security.md b/site/security.md new file mode 100644 index 0000000000..618e29e696 --- /dev/null +++ b/site/security.md @@ -0,0 +1,7 @@ +### Model Security +Oracle WebLogic Server Deploy Tooling covers several aspects for the modeling of security including encryption of model data to protect sensitive information as well as the security configuration and handling of WebLogic domains. + +#### Table of Contents +- [Encrypt Model Tool](encrypt.md) +- [Modeling Security Providers](security_providers.md) +- [Modeling WebLogic Users, Groups and Roles](security_users_groups_roles.md) diff --git a/site/security_users_groups_roles.md b/site/security_users_groups_roles.md new file mode 100644 index 0000000000..f488ddd96e --- /dev/null +++ b/site/security_users_groups_roles.md @@ -0,0 +1,53 @@ +### Modeling WebLogic Users, Groups and Roles +WebLogic Server has the ability to establish a set of Users, Groups and Global Roles as part of the WebLogic domain creation. The WebLogic global roles become part of the WebLogic role mapper (i.e. `XACMLRoleMapper`) and are specified under `domainInfo` in the `WLSRoles` section. The users and groups become part of the Embedded LDAP server (i.e. `DefaultAuthenticator`) and are specified under `topology` in the `Security` section. + +#### WebLogic Global Roles +The model allows for the definition of WebLogic roles that can augment the well known WebLogic global roles (e.g. `Admin`, `Deployer`, `Monitor`, ...) in addition to defining new roles. When updating the well known WebLogic roles an `UpdateMode` can be specified as `{ append | prepend | replace }` with the default being `replace` when not specified. Also, when updating the well known roles, the specified `Expression` will be a logical `OR` with the default expression. The `Expression` value for the role is the same as when using the WebLogic `RoleEditorMBean` for a WebLogic security role mapping provider. + +For example, the `WLSRoles` section below updates the well known `Admin`, `Deployer` and `Monitor` roles while adding a new global role with `Tester` as the role name: + +```yaml +domainInfo: + WLSRoles: + Admin: + UpdateMode: append + Expression: "?weblogic.entitlement.rules.IDCSAppRoleName(AppAdmin,@@PROP:AppName@@)" + Deployer: + UpdateMode: replace + Expression: "?weblogic.entitlement.rules.AdministrativeGroup(@@PROP:Deployers@@)" + Monitor: + UpdateMode: prepend + Expression: "?weblogic.entitlement.rules.AdministrativeGroup(AppMonitors)" + Tester: + Expression: "?weblogic.entitlement.rules.IDCSAppRoleName(AppTester,@@PROP:AppName@@)" +``` + +The `Admin` role will have the expression appended to the default expression, the `Deployer` role expression will replace the default, the `Monitor` role expression will be prepended to the default expression and `Tester` will be a new role with the specified expression. + +In addition, the `Expression` value can use the variable placeholder syntax specified when running the [Create Tool](create.md) as shown in the above example. + +#### WebLogic Users and Groups +The model allows for the definition of a set of users and groups that will be loaded into the WebLogic Embedded LDAP Server (i.e. `DefaultAuthenticator`). New groups can be specified and users can be added as members of the new groups or existing groups such as the `Administrators` group which is defaulted to be in the WebLogic `Admin` global role. + +The user password can be specified with a placeholder or encrypted with [Encrypt Tool](encyrpt.md). An example `Security` section that adds an additional group `AppMonitors`, adds two new users and places the users into groups is as follows: + +```yaml +topology: + Security: + Group: + AppMonitors: + Description: Application Monitors + User: + john: + Password: welcome1 + GroupMemberOf: [ AppMonitors, Administrators ] + joe: + Password: welcome1 + GroupMemberOf: [ AppMonitors ] +``` + +#### Known Limitations + +- The processing of Users, Groups and Roles will only take place when using the [Create Domain Tool](create.md) +- WebLogic Global Roles are only supported with WebLogic Server version 12.2.1 or greater +- WebLogic Global Roles are only updated for the WebLogic security XACML role mapping provider (i.e. `XACMLRoleMapper`) From 326804fa8d7f94bb92696b526f41a373fc660a84 Mon Sep 17 00:00:00 2001 From: TheFrogPad Date: Fri, 19 Jul 2019 17:16:32 -0400 Subject: [PATCH 11/14] Fix broken link to encrypt tool --- site/security_users_groups_roles.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/site/security_users_groups_roles.md b/site/security_users_groups_roles.md index f488ddd96e..fced7e7110 100644 --- a/site/security_users_groups_roles.md +++ b/site/security_users_groups_roles.md @@ -4,7 +4,7 @@ WebLogic Server has the ability to establish a set of Users, Groups and Global R #### WebLogic Global Roles The model allows for the definition of WebLogic roles that can augment the well known WebLogic global roles (e.g. `Admin`, `Deployer`, `Monitor`, ...) in addition to defining new roles. When updating the well known WebLogic roles an `UpdateMode` can be specified as `{ append | prepend | replace }` with the default being `replace` when not specified. Also, when updating the well known roles, the specified `Expression` will be a logical `OR` with the default expression. The `Expression` value for the role is the same as when using the WebLogic `RoleEditorMBean` for a WebLogic security role mapping provider. -For example, the `WLSRoles` section below updates the well known `Admin`, `Deployer` and `Monitor` roles while adding a new global role with `Tester` as the role name: +For example, the `WLSRoles` section below updates the well known `Admin`, `Deployer` and `Monitor` roles while adding a new global role with `Tester` as the role name: ```yaml domainInfo: @@ -29,7 +29,7 @@ In addition, the `Expression` value can use the variable placeholder syntax spec #### WebLogic Users and Groups The model allows for the definition of a set of users and groups that will be loaded into the WebLogic Embedded LDAP Server (i.e. `DefaultAuthenticator`). New groups can be specified and users can be added as members of the new groups or existing groups such as the `Administrators` group which is defaulted to be in the WebLogic `Admin` global role. -The user password can be specified with a placeholder or encrypted with [Encrypt Tool](encyrpt.md). An example `Security` section that adds an additional group `AppMonitors`, adds two new users and places the users into groups is as follows: +The user password can be specified with a placeholder or encrypted with [Encrypt Tool](encrypt.md). An example `Security` section that adds an additional group `AppMonitors`, adds two new users and places the users into groups is as follows: ```yaml topology: @@ -50,4 +50,4 @@ topology: - The processing of Users, Groups and Roles will only take place when using the [Create Domain Tool](create.md) - WebLogic Global Roles are only supported with WebLogic Server version 12.2.1 or greater -- WebLogic Global Roles are only updated for the WebLogic security XACML role mapping provider (i.e. `XACMLRoleMapper`) +- WebLogic Global Roles are only updated for the WebLogic security XACML role mapping provider (i.e. `XACMLRoleMapper`) From 9ca8c8feeb8a143ceadeac86123f790d43946918 Mon Sep 17 00:00:00 2001 From: TheFrogPad Date: Mon, 22 Jul 2019 18:25:25 -0400 Subject: [PATCH 12/14] Address documentation comments --- README.md | 2 +- site/security.md | 2 +- site/security_users_groups_roles.md | 14 +++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index cd2aaed2d1..03a34e5e90 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Many organizations are using WebLogic Server, with or without other Oracle Fusio - [Modeling Security Providers](site/security_providers.md) - [JRF Trust Service Identity Asserter](site/security_providers.md#trust-service-identity-asserter) - [Custom Security Providers](site/security_providers.md#custom-security-providers) - - [Modeling WebLogic Users, Groups and Roles](site/security_users_groups_roles.md) + - [Modeling WebLogic Users, Groups, and Roles](site/security_users_groups_roles.md) - [Variable Injection](site/variable_injection.md) - [Model Filters](site/tool_filters.md) - [Downloading and Installing](#downloading-and-installing-the-software) diff --git a/site/security.md b/site/security.md index 618e29e696..4147fc8f8f 100644 --- a/site/security.md +++ b/site/security.md @@ -4,4 +4,4 @@ Oracle WebLogic Server Deploy Tooling covers several aspects for the modeling of #### Table of Contents - [Encrypt Model Tool](encrypt.md) - [Modeling Security Providers](security_providers.md) -- [Modeling WebLogic Users, Groups and Roles](security_users_groups_roles.md) +- [Modeling WebLogic Users, Groups, and Roles](security_users_groups_roles.md) diff --git a/site/security_users_groups_roles.md b/site/security_users_groups_roles.md index fced7e7110..b903868c95 100644 --- a/site/security_users_groups_roles.md +++ b/site/security_users_groups_roles.md @@ -1,8 +1,8 @@ -### Modeling WebLogic Users, Groups and Roles -WebLogic Server has the ability to establish a set of Users, Groups and Global Roles as part of the WebLogic domain creation. The WebLogic global roles become part of the WebLogic role mapper (i.e. `XACMLRoleMapper`) and are specified under `domainInfo` in the `WLSRoles` section. The users and groups become part of the Embedded LDAP server (i.e. `DefaultAuthenticator`) and are specified under `topology` in the `Security` section. +### Modeling WebLogic Users, Groups, and Roles +WebLogic Server has the ability to establish a set of users, groups, and global roles as part of the WebLogic domain creation. The WebLogic global roles become part of the WebLogic role mapper (i.e. `XACMLRoleMapper`) and are specified under `domainInfo` in the `WLSRoles` section. The users and groups become part of the Embedded LDAP server (i.e. `DefaultAuthenticator`) and are specified under `topology` in the `Security` section. #### WebLogic Global Roles -The model allows for the definition of WebLogic roles that can augment the well known WebLogic global roles (e.g. `Admin`, `Deployer`, `Monitor`, ...) in addition to defining new roles. When updating the well known WebLogic roles an `UpdateMode` can be specified as `{ append | prepend | replace }` with the default being `replace` when not specified. Also, when updating the well known roles, the specified `Expression` will be a logical `OR` with the default expression. The `Expression` value for the role is the same as when using the WebLogic `RoleEditorMBean` for a WebLogic security role mapping provider. +The model allows for the definition of WebLogic roles that can augment the well known WebLogic global roles (e.g. `Admin`, `Deployer`, `Monitor`, ...) in addition to defining new roles. When updating the well known WebLogic roles, an `UpdateMode` can be specified as `{ append | prepend | replace }` with the default being `replace` when not specified. Also, when updating the well known roles, the specified `Expression` will be a logical `OR` with the default expression. The `Expression` value for the role is the same as when using the WebLogic `RoleEditorMBean` for a WebLogic security role mapping provider. For example, the `WLSRoles` section below updates the well known `Admin`, `Deployer` and `Monitor` roles while adding a new global role with `Tester` as the role name: @@ -29,7 +29,7 @@ In addition, the `Expression` value can use the variable placeholder syntax spec #### WebLogic Users and Groups The model allows for the definition of a set of users and groups that will be loaded into the WebLogic Embedded LDAP Server (i.e. `DefaultAuthenticator`). New groups can be specified and users can be added as members of the new groups or existing groups such as the `Administrators` group which is defaulted to be in the WebLogic `Admin` global role. -The user password can be specified with a placeholder or encrypted with [Encrypt Tool](encrypt.md). An example `Security` section that adds an additional group `AppMonitors`, adds two new users and places the users into groups is as follows: +The user password can be specified with a placeholder or encrypted with the [Encrypt Tool](encrypt.md). An example `Security` section that adds an additional group `AppMonitors`, adds two new users and places the users into groups is as follows: ```yaml topology: @@ -48,6 +48,6 @@ topology: #### Known Limitations -- The processing of Users, Groups and Roles will only take place when using the [Create Domain Tool](create.md) -- WebLogic Global Roles are only supported with WebLogic Server version 12.2.1 or greater -- WebLogic Global Roles are only updated for the WebLogic security XACML role mapping provider (i.e. `XACMLRoleMapper`) +- The processing of users, groups, and roles will only take place when using the [Create Domain Tool](create.md) +- WebLogic global roles are only supported with WebLogic Server version 12.2.1 or greater +- WebLogic global roles are only updated for the WebLogic security XACML role mapping provider (i.e. `XACMLRoleMapper`) From bb284fdb8c52f7e84bf81ca958babde82a3602cf Mon Sep 17 00:00:00 2001 From: TheFrogPad Date: Tue, 23 Jul 2019 18:13:52 -0400 Subject: [PATCH 13/14] Add documentation note about limitations for users and groups --- site/security_users_groups_roles.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/site/security_users_groups_roles.md b/site/security_users_groups_roles.md index b903868c95..a034ef08c8 100644 --- a/site/security_users_groups_roles.md +++ b/site/security_users_groups_roles.md @@ -27,7 +27,7 @@ The `Admin` role will have the expression appended to the default expression, th In addition, the `Expression` value can use the variable placeholder syntax specified when running the [Create Tool](create.md) as shown in the above example. #### WebLogic Users and Groups -The model allows for the definition of a set of users and groups that will be loaded into the WebLogic Embedded LDAP Server (i.e. `DefaultAuthenticator`). New groups can be specified and users can be added as members of the new groups or existing groups such as the `Administrators` group which is defaulted to be in the WebLogic `Admin` global role. +The model allows for the definition of a set of users and groups that will be loaded into the WebLogic Embedded LDAP Server (i.e. `DefaultAuthenticator`). New groups can be specified and users can be added as members of the new groups or existing groups such as the `Administrators` group which is defaulted to be in the WebLogic `Admin` global role. Please see [known limitations](#known-limitations) below for additional information on users and groups. The user password can be specified with a placeholder or encrypted with the [Encrypt Tool](encrypt.md). An example `Security` section that adds an additional group `AppMonitors`, adds two new users and places the users into groups is as follows: @@ -51,3 +51,4 @@ topology: - The processing of users, groups, and roles will only take place when using the [Create Domain Tool](create.md) - WebLogic global roles are only supported with WebLogic Server version 12.2.1 or greater - WebLogic global roles are only updated for the WebLogic security XACML role mapping provider (i.e. `XACMLRoleMapper`) +- The user and group processing is not complete, groups are created but users are only assigned to the `Administrators` group From e90cc3f45af2ebe2e8bc00ef307f2b891c49ab6b Mon Sep 17 00:00:00 2001 From: TheFrogPad Date: Wed, 24 Jul 2019 15:44:08 -0400 Subject: [PATCH 14/14] Clarify the limitation for user and group processing --- site/security_users_groups_roles.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/security_users_groups_roles.md b/site/security_users_groups_roles.md index a034ef08c8..37e112c9e1 100644 --- a/site/security_users_groups_roles.md +++ b/site/security_users_groups_roles.md @@ -51,4 +51,4 @@ topology: - The processing of users, groups, and roles will only take place when using the [Create Domain Tool](create.md) - WebLogic global roles are only supported with WebLogic Server version 12.2.1 or greater - WebLogic global roles are only updated for the WebLogic security XACML role mapping provider (i.e. `XACMLRoleMapper`) -- The user and group processing is not complete, groups are created but users are only assigned to the `Administrators` group +- The user and group processing is not complete, currently, users cannot be assigned to groups. Users created using the `Security` section are automatically added to the `Administrators` group and are not added to the groups specified. As soon as a patch to correct the user and group processing is available, we will post it here.