Skip to content
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
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion core/src/main/python/wlsdeploy/aliases/alias_entries.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,8 @@ class AliasEntries(object):
# servers in the domain.
'ServerGroupTargetingLimits': 'dict',
'RCUDbInfo': 'dict',
'OPSSSecrets': 'string'
'OPSSSecrets': 'password',
'WLSRoles': 'dict'
}

__domain_name_token = 'DOMAIN'
Expand Down
6 changes: 6 additions & 0 deletions core/src/main/python/wlsdeploy/aliases/model_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
ADMIN_USERNAME = 'AdminUserName'
APP_DEPLOYMENTS = 'appDeployments'
APP_DIR = 'AppDir'
APPEND = 'append'
APPLICATION = 'Application'
RCU_DB_INFO = 'RCUDbInfo'
OPSS_SECRETS = 'OPSSSecrets'
Expand Down Expand Up @@ -95,6 +96,7 @@
DYNAMIC_SERVERS = 'DynamicServers'
ERROR_DESTINATION = 'ErrorDestination'
EXECUTE_QUEUE = 'ExecuteQueue'
EXPRESSION = 'Expression'
FAIR_SHARE_REQUEST_CLASS = 'FairShareRequestClass'
FILE_OPEN = 'FileOpen'
FILE_STORE = 'FileStore'
Expand Down Expand Up @@ -183,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'
Expand Down Expand Up @@ -248,6 +252,7 @@
UNIFORM_DISTRIBUTED_QUEUE = 'UniformDistributedQueue'
UNIFORM_DISTRIBUTED_TOPIC = 'UniformDistributedTopic'
UNIX_MACHINE = 'UnixMachine'
UPDATE_MODE = 'UpdateMode'
USER = 'User'
VIRTUAL_TARGET = 'VirtualTarget'
VIRTUAL_USER_AUTHENTICATOR = 'VirtualUserAuthenticator'
Expand All @@ -268,6 +273,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'
Expand Down
5 changes: 5 additions & 0 deletions core/src/main/python/wlsdeploy/tool/create/domain_creator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -148,6 +149,9 @@ 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.wls_helper,
ExceptionType.CREATE, self.logger)

#
# This list gets modified as the domain is being created so do use this list for anything else...
#
Expand Down Expand Up @@ -338,6 +342,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

Expand Down
189 changes: 189 additions & 0 deletions core/src/main/python/wlsdeploy/tool/create/wlsroles_helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
"""
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.model_constants import APPEND
from wlsdeploy.aliases.model_constants import EXPRESSION
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
from wlsdeploy.util.weblogic_roles_helper import WebLogicRolesHelper

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 = '|'

class WLSRoles(object):
"""
Handle the WLSRoles section from the model domainInfo
"""
__class_name = 'WLSRoles'

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):
"""
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:
# Process the WLSRoles section after checking for proper version support
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(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 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 = {}
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, roles_map)
if string_utils.is_empty(expression):
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, roles_map)
if update_role and role not in WLS_GLOBAL_ROLES:
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, roles_map)
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)
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, 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 = roles_map[role_name]
if EXPRESSION in role_map:
result = role_map[EXPRESSION]
return result

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 = 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:
result = True
return result

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 = 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

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)
51 changes: 45 additions & 6 deletions core/src/main/python/wlsdeploy/tool/validate/validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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')
Expand Down Expand Up @@ -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 = '<masked>'
return result

def __validate_model_file(self, model_dict, variables_file_name, archive_file_name):
_method_name = '__validate_model_file'

Expand Down Expand Up @@ -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:
Expand All @@ -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,
Expand Down Expand Up @@ -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 = '<masked>'

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)
Expand Down Expand Up @@ -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:
Expand Down
Loading