Skip to content

Commit 13a5809

Browse files
Group and User updates to work around offline issues (#904)
1 parent d3bde98 commit 13a5809

File tree

7 files changed

+244
-14
lines changed

7 files changed

+244
-14
lines changed

core/src/main/python/wlsdeploy/aliases/model_constants.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@
9595
DEFAULT_WLS_DOMAIN_NAME = 'base_domain'
9696
DELIVERY_FAILURE_PARAMS = 'DeliveryFailureParams'
9797
DELIVERY_PARAMS_OVERRIDES = 'DeliveryParamsOverrides'
98+
DESCRIPTION = 'Description'
9899
DESTINATION_KEY = 'DestinationKey'
99100
DIRECTORY = 'Directory'
100101
DISTRIBUTED_QUEUE = 'DistributedQueue'
@@ -127,6 +128,7 @@
127128
FOREIGN_SERVER = 'ForeignServer'
128129
GROUP = 'Group'
129130
GROUP_PARAMS = 'GroupParams'
131+
GROUP_MEMBER_OF = 'GroupMemberOf'
130132
GLOBAL_VARIABLE_SUBSTITUTION = 'VariableSubstitution'
131133
HARVESTED_TYPE = 'HarvestedType'
132134
HARVESTER = 'Harvester'
@@ -315,6 +317,7 @@
315317
WLDF_SYSTEM_RESOURCE = "WLDFSystemResource"
316318
WLS_ROLES = "WLSRoles"
317319
WLS_USER_PASSWORD_CREDENTIAL_MAPPINGS = 'WLSUserPasswordCredentialMappings'
320+
WLS_DEFAULT_AUTHENTICATION = 'WLSDefaultAuthentication'
318321
WS_RELIABLE_DELIVERY_POLICY = 'WSReliableDeliveryPolicy'
319322
WTC_SERVER = 'WTCServer'
320323
XACML_AUTHORIZER = 'XACMLAuthorizer'

core/src/main/python/wlsdeploy/tool/create/domain_creator.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
from wlsdeploy.aliases.model_constants import USER
7070
from wlsdeploy.aliases.model_constants import VIRTUAL_TARGET
7171
from wlsdeploy.aliases.model_constants import WLS_USER_PASSWORD_CREDENTIAL_MAPPINGS
72+
from wlsdeploy.aliases.model_constants import WLS_DEFAULT_AUTHENTICATION
7273
from wlsdeploy.aliases.model_constants import WS_RELIABLE_DELIVERY_POLICY
7374
from wlsdeploy.aliases.model_constants import XML_ENTITY_CACHE
7475
from wlsdeploy.aliases.model_constants import XML_REGISTRY
@@ -83,6 +84,7 @@
8384
from wlsdeploy.tool.deploy import model_deployer
8485
from wlsdeploy.tool.util.archive_helper import ArchiveHelper
8586
from wlsdeploy.tool.util.credential_map_helper import CredentialMapHelper
87+
from wlsdeploy.tool.util.default_authenticator_helper import DefaultAuthenticatorHelper
8688
from wlsdeploy.tool.util.library_helper import LibraryHelper
8789
from wlsdeploy.tool.util.rcu_helper import RCUHelper
8890
from wlsdeploy.tool.util.target_helper import TargetHelper
@@ -544,8 +546,6 @@ def __extend_domain_with_select_template(self, domain_home):
544546
self.__configure_fmw_infra_database()
545547
self.__configure_opss_secrets()
546548
topology_folder_list = self.aliases.get_model_topology_top_level_folder_names()
547-
548-
self.__create_security_folder()
549549
topology_folder_list.remove(SECURITY)
550550

551551
resources_dict = self.model.get_model_resources()
@@ -577,6 +577,10 @@ def __extend_domain_with_select_template(self, domain_home):
577577
self.logger.info('WLSDPLY-12206', self._domain_name, domain_home,
578578
class_name=self.__class_name, method_name=_method_name)
579579
self.wlst_helper.read_domain(domain_home)
580+
581+
print '******* create security folder'
582+
self.__create_security_folder()
583+
580584
self.logger.exiting(class_name=self.__class_name, method_name=_method_name)
581585
return
582586

@@ -688,20 +692,17 @@ def __create_mbeans_used_by_topology_mbeans(self, topology_folder_list):
688692

689693
def __create_security_folder(self):
690694
"""
691-
Create the /Security folder objects, if any.
695+
Create the the security objects if any. The security information
696+
from the model will be writting to the DefaultAuthenticatorInit.ldift file
692697
:raises: CreateException: if an error occurs
693698
"""
694699
_method_name = '__create_security_folder'
695-
696-
location = LocationContext()
697-
domain_name_token = self.aliases.get_name_token(location)
698-
location.add_name_token(domain_name_token, self._domain_name)
699-
self.logger.entering(str(location), class_name=self.__class_name, method_name=_method_name)
700-
security_nodes = dictionary_utils.get_dictionary_element(self._topology, SECURITY)
701-
if len(security_nodes) > 0:
702-
self._create_mbean(SECURITY, security_nodes, location)
700+
self.logger.entering(class_name=self.__class_name, method_name=_method_name)
701+
security_folder = dictionary_utils.get_dictionary_element(self._topology, SECURITY)
702+
if security_folder is not None:
703+
helper = DefaultAuthenticatorHelper(self.model_context, ExceptionType.CREATE)
704+
helper.create_default_init_file(security_folder)
703705
self.logger.exiting(class_name=self.__class_name, method_name=_method_name)
704-
return
705706

706707
def __create_log_filters(self, location):
707708
"""
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
"""
2+
Copyright (c) 2021, Oracle Corporation and/or its affiliates.
3+
Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
4+
"""
5+
import com.bea.common.security.utils.encoders.BASE64Encoder as BASE64Encoder
6+
import com.bea.security.xacml.cache.resource.ResourcePolicyIdUtil as ResourcePolicyIdUtil
7+
from java.io import File
8+
from java.lang import String
9+
10+
import oracle.weblogic.deploy.aliases.TypeUtils as TypeUtils
11+
12+
from wlsdeploy.aliases.model_constants import DESCRIPTION
13+
from wlsdeploy.aliases.model_constants import GROUP
14+
from wlsdeploy.aliases.model_constants import GROUP_MEMBER_OF
15+
from wlsdeploy.aliases.model_constants import PASSWORD
16+
from wlsdeploy.aliases.model_constants import USER
17+
from wlsdeploy.exception import exception_helper
18+
from wlsdeploy.logging.platform_logger import PlatformLogger
19+
from wlsdeploy.tool.util.targets import file_template_helper
20+
from wlsdeploy.util import dictionary_utils
21+
from wlsdeploy.util.weblogic_helper import WebLogicHelper
22+
23+
TEMPLATE_PATH = 'oracle/weblogic/deploy/security'
24+
DEFAULT_AUTH_INIT_FILE = 'DefaultAuthenticatorInit.ldift'
25+
SECURITY_SUBDIR = 'security'
26+
GROUP_MAPPINGS = 'group'
27+
USER_MAPPINGS = 'user'
28+
29+
# template hash constants
30+
HASH_NAME = 'name'
31+
HASH_DESCRIPTION = 'description'
32+
HASH_GROUPS = 'groups'
33+
HASH_GROUP = 'groupMemberOf'
34+
HASH_USER_PASSWORD = 'password'
35+
36+
37+
class DefaultAuthenticatorHelper(object):
38+
"""
39+
This class is used to write the Security Group and User data into the ldift file. The reason is
40+
that there are several issues that are broken in offline, while they work in online. This works
41+
around these problems.
42+
"""
43+
_class_name = 'DefaultAuthenticatorHelper'
44+
45+
def __init__(self, model_context, exception_type):
46+
self._model_context = model_context
47+
self._exception_type = exception_type
48+
self._logger = PlatformLogger('wlsdeploy.tool.util')
49+
self._weblogic_helper = WebLogicHelper(self._logger)
50+
self._resource_escaper = ResourcePolicyIdUtil.getEscaper()
51+
self._b64_encoder = BASE64Encoder()
52+
53+
def create_default_init_file(self, security_mapping_nodes):
54+
"""
55+
Use the security information to write user/groups to the DefaultAuthenticatorInit.ldift file.
56+
This file must exist before writing the data. Build a hash map from the model data and
57+
append to the file using the template file for structure.
58+
:param security_mapping_nodes: the Security elements from the model
59+
"""
60+
_method_name = 'create_default_init_file'
61+
62+
template_hash = self._build_default_template_hash(security_mapping_nodes)
63+
template_path = TEMPLATE_PATH + '/' + DEFAULT_AUTH_INIT_FILE
64+
65+
output_dir = File(self._model_context.get_domain_home(), SECURITY_SUBDIR)
66+
output_file = File(output_dir, DEFAULT_AUTH_INIT_FILE)
67+
68+
self._logger.info('WLSDPLY-01900', output_file, class_name=self._class_name, method_name=_method_name)
69+
70+
file_template_helper.append_file_from_resource(template_path, template_hash, output_file, self._exception_type)
71+
72+
def _build_default_template_hash(self, mapping_section_nodes):
73+
"""
74+
Create a dictionary of substitution values to apply to the default authenticator template.
75+
:param mapping_section_nodes: the security elements from the model
76+
:return: the template hash dictionary
77+
"""
78+
template_hash = dict()
79+
80+
group_mappings = []
81+
user_mappings = []
82+
83+
if GROUP in mapping_section_nodes.keys():
84+
group_mapping_nodes = mapping_section_nodes[GROUP]
85+
for name in group_mapping_nodes:
86+
mapping_hash = self._build_group_mapping_hash(group_mapping_nodes[name], name)
87+
group_mappings.append(mapping_hash)
88+
if USER in mapping_section_nodes.keys():
89+
user_mapping_nodes = mapping_section_nodes[USER]
90+
for name in user_mapping_nodes:
91+
mapping_hash = self._build_user_mapping_hash(user_mapping_nodes[name], name)
92+
user_mappings.append(mapping_hash)
93+
94+
template_hash[GROUP_MAPPINGS] = group_mappings
95+
template_hash[USER_MAPPINGS] = user_mappings
96+
print '****** template hash ', template_hash
97+
return template_hash
98+
99+
def _build_group_mapping_hash(self, group_mapping_section, name):
100+
"""
101+
Build a template hash for the specified mapping element from the model.
102+
:param group_mapping_section: the security group entry from the model
103+
:param name: The name of the group
104+
:return: the template hash
105+
"""
106+
hash_entry = dict()
107+
hash_entry[HASH_NAME] = name
108+
group_attributes = group_mapping_section
109+
description = dictionary_utils.get_element(group_attributes, DESCRIPTION)
110+
hash_entry[HASH_DESCRIPTION] = description
111+
groups = dictionary_utils.get_element(group_attributes, GROUP_MEMBER_OF)
112+
group_list = []
113+
group_mappings = list()
114+
if groups is not None:
115+
group_list = TypeUtils.convertToType('list', groups)
116+
for group in group_list:
117+
group_mappings.append({HASH_GROUP: group})
118+
hash_entry[HASH_GROUPS] = group_mappings
119+
else:
120+
hash_entry[HASH_GROUPS] = group_list
121+
122+
return hash_entry
123+
124+
def _build_user_mapping_hash(self, user_mapping_section, name):
125+
"""
126+
Build a template hash map from the security user data from the model.
127+
This includes encoding the required password.
128+
:param user_mapping_section: The security user section from the model
129+
:param name: name of the user for the user section
130+
:return: template hash map
131+
"""
132+
hash_entry = dict()
133+
hash_entry[HASH_NAME] = name
134+
group_attributes = user_mapping_section
135+
description = dictionary_utils.get_element(group_attributes, DESCRIPTION)
136+
hash_entry[HASH_DESCRIPTION] = description
137+
groups = dictionary_utils.get_element(group_attributes, GROUP_MEMBER_OF)
138+
password = self._get_required_attribute(user_mapping_section, PASSWORD, USER, name)
139+
encrypted = self._weblogic_helper.encrypt(password, self._model_context.get_domain_home())
140+
password_encoded = self._b64_encoder.encodeBuffer(String(encrypted).getBytes("UTF-8"))
141+
hash_entry[HASH_USER_PASSWORD] = password_encoded
142+
group_list = []
143+
group_mappings = list()
144+
if groups is not None:
145+
group_list = TypeUtils.convertToType('list', groups)
146+
for group in group_list:
147+
group_mappings.append({HASH_GROUP: group})
148+
hash_entry[HASH_GROUPS] = group_mappings
149+
else:
150+
hash_entry[HASH_GROUPS] = group_list
151+
152+
return hash_entry
153+
154+
def _get_required_attribute(self, dictionary, name, mapping_type, mapping_name):
155+
"""
156+
Return the value of the specified attribute from the specified dictionary.
157+
Log and throw an exception if the attribute is not found.
158+
:param dictionary: the dictionary to be checked
159+
:param name: the name of the attribute to find
160+
:param mapping_type: the type of the mapping, such as 'CrossDomain'
161+
:param mapping_name: the mapping name from the model, such as 'map1'
162+
:return: the value of the attribute
163+
:raises: Tool type exception: if an the attribute is not found
164+
"""
165+
_method_name = '_get_required_attribute'
166+
167+
result = dictionary_utils.get_element(dictionary, name)
168+
if result is None:
169+
pwe = exception_helper.create_exception(self._exception_type, '-01791', name, mapping_type,
170+
mapping_name)
171+
self._logger.throwing(class_name=self._class_name, method_name=_method_name, error=pwe)
172+
raise pwe
173+
return result

core/src/main/python/wlsdeploy/tool/util/targets/file_template_helper.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,26 @@ def create_file_from_resource(resource_path, template_hash, output_file, excepti
4444
_create_file_from_stream(template_stream, template_hash, output_file)
4545

4646

47+
def append_file_from_resource(resource_path, template_hash, output_file, exception_type):
48+
"""
49+
Read the template from the resource stream, perform any substitutions,
50+
and write it to the output file.
51+
:param resource_path: the resource path of the source template
52+
:param template_hash: a dictionary of substitution values
53+
:param output_file: the file to write
54+
:param exception_type: the type of exception to throw if needed
55+
"""
56+
_method_name = 'append_file_from_resource'
57+
58+
template_stream = FileUtils.getResourceAsStream(resource_path)
59+
if template_stream is None:
60+
ex = exception_helper.create_exception(exception_type, 'WLSDPLY-01661', resource_path)
61+
__logger.throwing(ex, class_name=__class_name, method_name=_method_name)
62+
raise ex
63+
FileUtils.validateExistingFile(output_file)
64+
_create_file_from_stream(template_stream, template_hash, output_file, 'a')
65+
66+
4767
def create_file_from_file(file_path, template_hash, output_file, exception_type):
4868
"""
4969
Read the template from the template file, perform any substitutions,
@@ -65,9 +85,9 @@ def create_file_from_file(file_path, template_hash, output_file, exception_type)
6585
raise ex
6686

6787

68-
def _create_file_from_stream(template_stream, template_hash, output_file):
88+
def _create_file_from_stream(template_stream, template_hash, output_file, write_access='w'):
6989
template_reader = BufferedReader(InputStreamReader(template_stream))
70-
file_writer = open(output_file.getPath(), "w")
90+
file_writer = open(output_file.getPath(), write_access)
7191

7292
block_key = None
7393
block_lines = []

core/src/main/resources/oracle/weblogic/deploy/aliases/category_modules/Security.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"folders": { },
1111
"attributes": {
1212
"Description": [ {"version": "[10,)", "wlst_mode": "offline", "wlst_name": "Description", "wlst_path": "WP001", "value": {"default": "None" }, "wlst_type": "string", "get_method": "NONE" } ],
13+
"GroupMemberOf": [ {"version": "[10,)", "wlst_mode": "offline", "wlst_name": "GroupMemberOf", "wlst_path": "WP001", "value": {"default": "None" }, "wlst_type": "delimited_string", "get_method": "NONE" } ],
1314
"Name": [ {"version": "[10,)", "wlst_mode": "offline", "wlst_name": "Name", "wlst_path": "WP001", "value": {"default": "None" }, "wlst_type": "string", "get_method": "NONE" } ]
1415
},
1516
"wlst_attributes_path": "WP001",

core/src/main/resources/oracle/weblogic/deploy/messages/wlsdeploy_rb.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,8 @@ WLSDPLY-01805=Unexpected {0} during role mapper processing: {1}
385385
WLSDPLY-01790=Creating default credential mapper initialization file {0}
386386
WLSDPLY-01791=Attribute "{0}" is required for {1} credential mapping {2}
387387

388+
# wlsdeploy/tool/util/default_authenticator_helper.py
389+
WLSDPLY-01900=Append to default authenticator initialization file {0}
388390
###############################################################################
389391
# Encrypt Messages (04000 - 04999) #
390392
###############################################################################
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{{#group}}
2+
3+
dn: cn={{{name}}},ou=groups,ou=@realm@,dc=@domain@
4+
memberURL: ldap:///ou=people,ou=@realm@,dc=@domain@??sub?(&(objectclass=person)(wlsMemberOf=cn={{{name}}},ou=groups,ou=@realm@,dc=@domain@))
5+
description: {{{description}}}
6+
objectclass: top
7+
objectclass: groupOfURLs
8+
objectclass: groupOfUniqueNames
9+
cn: {{{name}}}
10+
{{#groups}}
11+
uniquemember: cn={{{groupMemberOf}}},ou=groups,ou=@realm@,dc=@domain@
12+
{{/groups}}
13+
{{/group}}
14+
{{#user}}
15+
16+
dn: uid={{{name}}},ou=people,ou=@realm@,dc=@domain@
17+
description: {{{description}}}
18+
objectclass: inetOrgPerson
19+
objectclass: organizationalPerson
20+
objectclass: person
21+
objectclass: top
22+
cn: {{{name}}}
23+
sn: {{{name}}}
24+
userpassword: {{{password}}}
25+
uid: {{{name}}}
26+
objectclass: wlsUser
27+
{{#groups}}
28+
wlsMemberOf: cn={{{groupMemberOf}}},ou=groups,ou=@realm@,dc=@domain@
29+
{{/groups}}
30+
{{/user}}

0 commit comments

Comments
 (0)