Skip to content

Commit e1eb3c4

Browse files
committed
Merge branch 'wls-policies-update' into 'main'
Allow updates to existing WLS policies with notification See merge request weblogic-cloud/weblogic-deploy-tooling!1669
2 parents c062b68 + 46bd50d commit e1eb3c4

File tree

5 files changed

+150
-117
lines changed

5 files changed

+150
-117
lines changed

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

+2-21
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,10 @@
1111
from wlsdeploy.util import dictionary_utils
1212
from wlsdeploy.util.weblogic_policies_helper import WebLogicPoliciesHelper
1313

14-
_BUILTIN_POLICIES = {
15-
'type=<adm>': 'Rol(Admin)',
16-
'type=<ejb>': 'Grp(everyone)',
17-
'type=<jdbc>': 'Grp(everyone)',
18-
'type=<jms>': 'Grp(everyone)',
19-
'type=<jmx>': 'Rol(Admin)',
20-
'type=<jndi>': 'Grp(everyone)',
21-
'type=<eis>': 'Grp(everyone)',
22-
'type=<svr>': 'Rol(Admin) | Rol(Operator)',
23-
'type=<url>': 'Grp(everyone)',
24-
'type=<webservices>': 'Grp(everyone)',
25-
'type=<workcontext>': 'Grp(everyone)',
26-
'type=<adm>, category=Configuration': 'Rol(Admin) | Rol(Deployer) | Rol(Operator) | Rol(Monitor)',
27-
'type=<adm>, category=FileDownload': 'Rol(Admin) | Rol(Operator)',
28-
'type=<adm>, category=FileUpload': 'Rol(Admin) | Rol(Deployer)',
29-
'type=<adm>, category=ViewLog': 'Rol(Admin) | Rol(Deployer) | Rol(Operator) | Rol(Monitor)'
30-
}
3114
_DOMAIN_SECURITY_SUBDIR = 'security'
3215
_WL_HOME_AUTHORIZER_LDIFT_FILE = os.path.join('server', 'lib', 'XACMLAuthorizerInit.ldift')
3316

17+
3418
class WLSPolicies(object):
3519
__class_name = 'WLSPolicies'
3620

@@ -58,10 +42,7 @@ def validate_policies(self):
5842
continue
5943

6044
resource_id = dictionary_utils.get_element(value, RESOURCE_ID)
61-
if resource_id in _BUILTIN_POLICIES:
62-
self._logger.severe('WLSDPLY-12601', key, RESOURCE_ID, resource_id, _BUILTIN_POLICIES[resource_id],
63-
class_name=self.__class_name, method_name=_method_name)
64-
elif resource_id in policy_resource_map:
45+
if resource_id in policy_resource_map:
6546
self._logger.severe('WLSDPLY-12602', key, RESOURCE_ID, resource_id, policy_resource_map[resource_id],
6647
class_name=self.__class_name, method_name=_method_name)
6748
else:

core/src/main/python/wlsdeploy/tool/util/ldif_entry.py

+21-8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import re
66

77
from wlsdeploy.logging.platform_logger import PlatformLogger
8+
from wlsdeploy.util import unicode_helper as str_helper
89

910
QUALIFIED_CN_REGEX = re.compile('(,|^)cn=([^,]*)(,|$)')
1011
QUALIFY_VALUE_TEMPLATE = 'cn=%s,ou=groups,ou=@realm@,dc=@domain@'
@@ -59,13 +60,13 @@ def update_single_field(self, field_name, new_value):
5960
for line_text in self._lines:
6061
key, value = _get_assignment(line_text)
6162
if key == field_name:
62-
self._add_assignment(field_name, new_value, new_lines)
63+
_add_assignment(field_name, new_value, new_lines)
6364
found = True
6465
else:
6566
new_lines.append(line_text)
6667

6768
if not found:
68-
self._add_assignment(field_name, new_value, new_lines)
69+
_add_assignment(field_name, new_value, new_lines)
6970

7071
self._lines = new_lines
7172

@@ -86,11 +87,10 @@ def add_qualified_assignments(self, key, cn_names):
8687
for cn_name in cn_names:
8788
if cn_name not in existing_names:
8889
value = QUALIFY_VALUE_TEMPLATE % cn_name
89-
self._add_assignment(key, value, self._lines)
90+
self.add_assignment(key, value)
9091

91-
def _add_assignment(self, key, value, lines):
92-
line = key + ': ' + value
93-
lines.append(line)
92+
def add_assignment(self, key, value):
93+
_add_assignment(key, value, self._lines)
9494

9595

9696
def read_entries(file):
@@ -118,7 +118,7 @@ def read_entries(file):
118118
entries.append(current_entry)
119119
current_entry.add_assignment_line(line_text)
120120

121-
__logger.exiting(class_name=__class_name, method_name=_method_name, result=entries)
121+
__logger.exiting(class_name=__class_name, method_name=_method_name, result=len(entries))
122122
return entries
123123

124124

@@ -131,10 +131,23 @@ def find_entry(cn_name, entries):
131131
return None
132132

133133

134+
def _add_assignment(key, value, lines):
135+
line = key + ': ' + str_helper.to_string(value)
136+
lines.append(line)
137+
138+
134139
def _get_assignment(line):
135140
fields = line.split(':', 1)
136141
key = fields[0].strip()
137142
value = None
138143
if len(fields) > 1:
139-
value = fields[1].strip()
144+
value = fields[1]
145+
146+
# some assignments are "key:: value", we return the key "key:"
147+
if value.startswith(':'):
148+
key += ':'
149+
value = value[1:]
150+
151+
value = value.strip()
152+
140153
return key, value

core/src/main/python/wlsdeploy/util/weblogic_policies_helper.py

+124-84
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,29 @@
33
Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
44
"""
55
import os
6-
import shutil
76

7+
from com.bea.common.security.utils.encoders import BASE64Encoder
8+
from com.bea.common.security.xacml import DocumentParseException
9+
from com.bea.common.security.xacml import URISyntaxException
10+
from com.bea.security.providers.xacml.entitlement import EntitlementConverter
11+
from com.bea.security.xacml.cache.resource import ResourcePolicyIdUtil
812
from java.io import File
913
from java.lang import String
1014

1115
from wlsdeploy.aliases.model_constants import POLICY
1216
from wlsdeploy.aliases.model_constants import RESOURCE_ID
17+
from wlsdeploy.aliases.model_constants import WLS_POLICIES
1318
from wlsdeploy.exception import exception_helper
14-
import wlsdeploy.util.unicode_helper as str_helper
15-
16-
import com.bea.common.security.utils.encoders.BASE64Encoder as BASE64Encoder
17-
import com.bea.common.security.xacml.DocumentParseException as DocumentParseException
18-
import com.bea.common.security.xacml.URISyntaxException as URISyntaxException
19-
import com.bea.security.providers.xacml.entitlement.EntitlementConverter as EntitlementConverter
20-
import com.bea.security.xacml.cache.resource.ResourcePolicyIdUtil as ResourcePolicyIdUtil
19+
from wlsdeploy.tool.util import ldif_entry
20+
from wlsdeploy.tool.util.ldif_entry import LDIFEntry
21+
from wlsdeploy.util import dictionary_utils
22+
from wlsdeploy.util import unicode_helper as str_helper
2123

2224
_DOMAIN_SECURITY_SUBDIR = 'security'
2325
_WLS_XACML_AUTHORIZER_LDIFT_FILENAME = 'XACMLAuthorizerInit.ldift'
2426
_WL_HOME_AUTHORIZER_LDIFT_FILE = os.path.join('server', 'lib', _WLS_XACML_AUTHORIZER_LDIFT_FILENAME)
25-
_WLS_POLICY_DN_TEMPLATE = 'dn: cn=%s+xacmlVersion=1.0,ou=Policies,ou=XACMLAuthorization,ou=@realm@,dc=@domain@\n'
27+
_WLS_POLICY_DN_TEMPLATE = 'dn: cn=%s+xacmlVersion=1.0,ou=Policies,ou=XACMLAuthorization,ou=@realm@,dc=@domain@'
28+
2629

2730
class WebLogicPoliciesHelper(object):
2831
"""
@@ -50,7 +53,6 @@ def __init__(self, model_context, logger, exception_type):
5053
self._target_xacml_authorizer_ldift_dir = os.path.join(domain_home, _DOMAIN_SECURITY_SUBDIR)
5154
self._target_xacml_authorizer_ldift_file = \
5255
os.path.join(self._target_xacml_authorizer_ldift_dir, _WLS_XACML_AUTHORIZER_LDIFT_FILENAME)
53-
self._target_xacml_authorizer_ldift_temp_file = '%s.new' % self._target_xacml_authorizer_ldift_file
5456
else:
5557
ex = exception_helper.create_exception(exception_type, 'WLSDPLY-02001')
5658
self._logger.throwing(ex, class_name=self.__class_name, method_name=_method_name)
@@ -69,8 +71,7 @@ def update_xacml_authorizer(self, model_policies_dict):
6971
return
7072

7173
self._ensure_source_file_and_target_dir()
72-
policy_entries_map = self._create_xacml_authorizer_entries(model_policies_dict)
73-
self._update_xacml_authorizer_ldift(policy_entries_map)
74+
self._update_xacml_authorizer_ldift(model_policies_dict)
7475
self._logger.exiting(class_name=self.__class_name, method_name=_method_name)
7576

7677
def _ensure_source_file_and_target_dir(self):
@@ -90,94 +91,133 @@ def _ensure_source_file_and_target_dir(self):
9091
self._logger.throwing(ex, class_name=self.__class_name, method_name=_method_name)
9192
raise ex
9293

93-
try:
94-
shutil.copyfile(self._source_xacml_authorizer_ldift_file, self._target_xacml_authorizer_ldift_temp_file)
95-
except IOError, ioe:
96-
error = exception_helper.convert_error_to_exception()
97-
ex = exception_helper.create_exception(self._exception_type, 'WLSDPLY-02003',
98-
self._target_xacml_authorizer_ldift_dir, error.getLocalizedMssage(),
99-
error=error)
100-
self._logger.throwing(ex, class_name=self.__class_name, method_name=_method_name)
101-
raise ex
102-
10394
self._logger.exiting(class_name=self.__class_name, method_name=_method_name)
10495

105-
def _create_xacml_authorizer_entries(self, model_policies_map):
106-
_method_name = '_create_xacml_authorizer_entries'
107-
self._logger.entering(class_name=self.__class_name, method_name=_method_name)
108-
109-
entries = dict()
110-
if model_policies_map is not None:
111-
for model_policy_name, model_policy_dict in model_policies_map.iteritems():
112-
model_policy_resource_id = model_policy_dict[RESOURCE_ID]
113-
model_policy_policy = model_policy_dict[POLICY]
114-
try:
115-
policy = self._converter.convertResourceExpression(model_policy_resource_id, model_policy_policy)
116-
scope = self._escaper.escapeString(String(model_policy_resource_id))
117-
cn = self._escaper.escapeString(policy.getId().toString())
118-
xacml = self._b64encoder.encodeBuffer(String(policy.toString()).getBytes('UTF-8'))
119-
entry = [
120-
_WLS_POLICY_DN_TEMPLATE % cn,
121-
'objectclass: top\n',
122-
'objectclass: xacmlEntry\n',
123-
'objectclass: xacmlAuthorizationPolicy\n',
124-
'objectclass: xacmlResourceScoping\n',
125-
'cn: %s\n' % cn,
126-
'xacmlResourceScope: %s\n' % scope,
127-
'xacmlVersion: 1.0\n',
128-
'xacmlStatus: 3\n',
129-
'xacmlDocument:: %s\n' % xacml
130-
]
131-
entries[model_policy_name] = entry
132-
except DocumentParseException, dpe:
133-
ex = exception_helper.create_exception(self._exception_type, 'WLSDPLY-02004', model_policy_name,
134-
RESOURCE_ID, model_policy_resource_id, POLICY,
135-
model_policy_policy, dpe.getLocalizedMessage(), error=dpe)
136-
self._logger.throwing(ex, class_name=self.__class_name, method_name=_method_name)
137-
raise ex
138-
except URISyntaxException, use:
139-
ex = exception_helper.create_exception(self._exception_type, 'WLSDPLY-02005', model_policy_name,
140-
RESOURCE_ID, model_policy_resource_id, POLICY,
141-
model_policy_policy, use.getLocalizedMessage(), error=use)
142-
self._logger.throwing(ex, class_name=self.__class_name, method_name=_method_name)
143-
raise ex
144-
145-
self._logger.exiting(class_name=self.__class_name, method_name=_method_name)
146-
return entries
147-
148-
def _update_xacml_authorizer_ldift(self, policy_entries_map):
96+
def _update_xacml_authorizer_ldift(self, model_policies_dict):
14997
_method_name = '_update_xacml_authorizer_ldift'
15098
self._logger.entering(class_name=self.__class_name, method_name=_method_name)
15199

152-
self._logger.finer('WLSDPLY-02006', self._target_xacml_authorizer_ldift_temp_file,
100+
self._logger.finer('WLSDPLY-02006', self._target_xacml_authorizer_ldift_file,
153101
class_name=self.__class_name, method_name=_method_name)
154-
ldift_temp_file = None
102+
103+
target_ldift_file = None
155104
try:
156105
try:
157-
ldift_temp_file = open(self._target_xacml_authorizer_ldift_temp_file, 'a')
158-
for model_policy_name, ldift_lines in policy_entries_map.iteritems():
159-
self._logger.finer('WLSDPLY-02007', model_policy_name,
160-
class_name=self.__class_name, method_name=_method_name)
161-
ldift_temp_file.write('\n')
162-
ldift_temp_file.writelines(ldift_lines)
106+
existing_policies = ldif_entry.read_entries(File(self._source_xacml_authorizer_ldift_file))
107+
108+
# build a map of resource IDs to existing policies
109+
existing_policy_map = {}
110+
for policy in existing_policies:
111+
cn = policy.get_single_value('cn')
112+
if cn:
113+
policy_id = self._escaper.unescapeString(cn)
114+
resource_id = ResourcePolicyIdUtil.getResourceId(policy_id)
115+
resource_key = _get_resource_key(resource_id)
116+
existing_policy_map[resource_key] = policy
117+
118+
# for each model policy, update an existing policy, or add a new one
119+
new_policies = []
120+
for model_policy_name, model_policy_dict in model_policies_dict.iteritems():
121+
model_resource_id = model_policy_dict[RESOURCE_ID]
122+
model_policy = model_policy_dict[POLICY]
123+
resource_key = _get_resource_key(model_resource_id)
124+
existing_policy = dictionary_utils.get_element(existing_policy_map, resource_key) # type: LDIFEntry
125+
if existing_policy:
126+
self._update_policy_from_model(existing_policy, model_policy, model_policy_name)
127+
else:
128+
new_policy = self._create_policy_from_model(model_resource_id, model_policy, model_policy_name)
129+
new_policies.append(new_policy)
130+
131+
target_ldift_file = open(self._target_xacml_authorizer_ldift_file, 'w')
132+
first = True
133+
all_policies = existing_policies + new_policies
134+
for policy in all_policies:
135+
if not first:
136+
target_ldift_file.write('\n')
137+
lines_text = '\n'.join(policy.get_assignment_lines()) + '\n'
138+
target_ldift_file.writelines(lines_text)
139+
first = False
140+
163141
except (ValueError,IOError,OSError), error:
164142
ex = exception_helper.create_exception(self._exception_type, 'WLSDPLY-02008',
165143
str_helper.to_string(error), error=error)
166144
self._logger.throwing(ex, class_name=self.__class_name, method_name=_method_name)
167145
raise ex
168146
finally:
169-
if ldift_temp_file is not None:
170-
ldift_temp_file.close()
147+
if target_ldift_file is not None:
148+
target_ldift_file.close()
149+
150+
self._logger.exiting(class_name=self.__class_name, method_name=_method_name)
151+
152+
def _update_policy_from_model(self, policy_entry, model_policy, model_policy_name):
153+
_method_name = '_update_policy_from_model'
154+
155+
self._logger.info('WLSDPLY-02010', model_policy_name, class_name=self.__class_name, method_name=_method_name)
156+
157+
self._logger.notification('WLSDPLY-02011', WLS_POLICIES, model_policy_name,
158+
class_name=self.__class_name, method_name=_method_name)
159+
160+
scope = policy_entry.get_single_value('xacmlResourceScope')
161+
resource_id = self._escaper.unescapeString(scope)
162+
policy = self._convert_resource_expression(resource_id, model_policy, model_policy_name)
163+
xacml = self._b64encoder.encodeBuffer(String(policy.toString()).getBytes('UTF-8'))
164+
165+
policy_entry.update_single_field('xacmlDocument:', xacml) # double colon assignment
166+
167+
def _create_policy_from_model(self, model_resource_id, model_policy, model_policy_name):
168+
_method_name = '_create_policy_from_model'
169+
170+
self._logger.info('WLSDPLY-02007', model_policy_name, class_name=self.__class_name, method_name=_method_name)
171+
172+
policy = self._convert_resource_expression(model_resource_id, model_policy, model_policy_name)
173+
scope = self._escaper.escapeString(String(model_resource_id))
174+
cn = self._escaper.escapeString(policy.getId().toString())
175+
xacml = self._b64encoder.encodeBuffer(String(policy.toString()).getBytes('UTF-8'))
176+
177+
policy_entry = LDIFEntry()
178+
policy_entry.add_assignment_line(_WLS_POLICY_DN_TEMPLATE % cn)
179+
policy_entry.add_assignment('objectclass', 'top')
180+
policy_entry.add_assignment('objectclass', 'xacmlEntry')
181+
policy_entry.add_assignment('objectclass', 'xacmlAuthorizationPolicy')
182+
policy_entry.add_assignment('objectclass', 'xacmlResourceScoping')
183+
policy_entry.add_assignment('cn', cn)
184+
policy_entry.add_assignment('xacmlResourceScope', scope)
185+
policy_entry.add_assignment('xacmlVersion', '1.0')
186+
policy_entry.add_assignment('xacmlStatus', 3)
187+
policy_entry.add_assignment('xacmlDocument:', xacml) # double colon assignment
188+
return policy_entry
189+
190+
def _convert_resource_expression(self, model_resource_id, model_policy, model_policy_name):
191+
_method_name = '_convert_resource_expression'
171192

172-
# Rename the temp file
173193
try:
174-
os.rename(self._target_xacml_authorizer_ldift_temp_file, self._target_xacml_authorizer_ldift_file)
175-
except OSError, ose:
176-
ex = exception_helper.create_exception(self._exception_type, 'WLSDPLY-02009',
177-
self._target_xacml_authorizer_ldift_temp_file,
178-
self._target_xacml_authorizer_ldift_file,
179-
str_helper.to_string(ose), error=ose)
194+
return self._converter.convertResourceExpression(model_resource_id, model_policy)
195+
196+
except DocumentParseException, dpe:
197+
ex = exception_helper.create_exception(
198+
self._exception_type, 'WLSDPLY-02004', model_policy_name, RESOURCE_ID,
199+
model_resource_id, POLICY, model_policy, dpe.getLocalizedMessage(), error=dpe)
200+
self._logger.throwing(ex, class_name=self.__class_name, method_name=_method_name)
201+
raise ex
202+
except URISyntaxException, use:
203+
ex = exception_helper.create_exception(
204+
self._exception_type, 'WLSDPLY-02005', model_policy_name, RESOURCE_ID,
205+
model_resource_id, POLICY, model_policy, use.getLocalizedMessage(), error=use)
180206
self._logger.throwing(ex, class_name=self.__class_name, method_name=_method_name)
181207
raise ex
182208

183-
self._logger.exiting(class_name=self.__class_name, method_name=_method_name)
209+
210+
def _get_resource_key(resource_id):
211+
"""
212+
Create a key from the specified resource ID that can be used for comparison,
213+
accounting for differences in spaces and ordering.
214+
*** This key is for comparison and lookup only, don't use it as resource ID ***
215+
:param resource_id: the resource ID for the key
216+
:return: the resulting key
217+
"""
218+
parts = resource_id.split(', ') # don't split path={weblogic,common,T3Services}
219+
just_parts = []
220+
for part in parts:
221+
just_parts.append(part.strip()) # clear any whitespace around the assignment
222+
just_parts.sort() # put assignments in alpha order in the key only
223+
return ', '.join(just_parts)

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

+2
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,8 @@ WLSDPLY-02006=Updating {0} with model-defined policies
516516
WLSDPLY-02007=Adding model-defined policy {0}
517517
WLSDPLY-02008=Failed to add model-defined policies due to an error: {0}
518518
WLSDPLY-02009=Failed to deploy WebLogic Policies because renaming the initialization file from {0} to {1} failed: {2}
519+
WLSDPLY-02010=Updating existing policy from model-defined policy {0}
520+
WLSDPLY-02011={0} entry {1} changed an existing policy, and may result in failure of the created domain
519521

520522
# wlsdeploy/util/path_helper.py
521523
WLSDPLY-02100=Setting local file system to use {0}-style paths

0 commit comments

Comments
 (0)