Skip to content

Commit 3cc4953

Browse files
authored
Merge pull request #289 from adobe-apiplatform/v2
prepare for 2.2.2rc1 build
2 parents 0235ebc + f368d29 commit 3cc4953

File tree

9 files changed

+64
-36
lines changed

9 files changed

+64
-36
lines changed

RELEASE_NOTES.md

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,27 @@
1-
# Release Notes for User Sync Tool Version 2.2.1
1+
# Release Notes for User Sync Tool Version 2.2.2
22

3-
These notes apply to v2.2.1 of 2017-08-30.
3+
These notes apply to v2.2.2rc1 of 2017-10-25.
44

55
## New Features
66

7-
[#266](https://github.com/adobe-apiplatform/user-sync.py/issues/266): Extended attribute values (defined in extensions) can now be multi-valued. The type of the attribute value in the `source_attributes` dictionary will be:
8-
* `None` if the attribute has no value;
9-
* a `str` (or `unicode` in py2) if the attribute has one value;
10-
* a `list` of `str` (or `unicode` in py2) if the attribute has multiple values.
11-
12-
[#268](https://github.com/adobe-apiplatform/user-sync.py/issues/268): To make sure users get all the right overlapping entitlements associated with mapped user groups, `--strategy push` now does group removals before group adds.
7+
None.
138

149
## Bug Fixes
1510

16-
[#257](https://github.com/adobe-apiplatform/user-sync.py/issues/257): Catch exceptions thrown by umapi-client when creating actions.
17-
18-
[#258](https://github.com/adobe-apiplatform/user-sync.py/issues/258): Correctly decrypt private keys in py3.
11+
[#283](https://github.com/adobe-apiplatform/user-sync.py/issues/283): Don't import keyring unless needed.
1912

20-
[#260](https://github.com/adobe-apiplatform/user-sync.py/issues/260): Make sure the requests library is loaded when using pex on Windows.
13+
[#286](https://github.com/adobe-apiplatform/user-sync.py/issues/286): Allow specifying attributes for Adobe IDs.
2114

22-
[#265](https://github.com/adobe-apiplatform/user-sync.py/issues/265): Extended attributes in extensions couldn't be fetched unless they had non-ascii names.
23-
24-
[#269](https://github.com/adobe-apiplatform/user-sync.py/issues/269): When using `--strategy sync`, new users created in secondary organizations were not being added to any groups.
15+
[#288](https://github.com/adobe-apiplatform/user-sync.py/issues/288): Escape special characters in user input to LDAP queries.
2516

2617
## Compatibility with Prior Versions
2718

28-
There are no functional changes from prior versions.
19+
There are no interface changes from prior versions.
2920

3021
## Known Issues
3122

32-
Because the release on Windows is built with a pre-compiled version of pyldap, we have to specify a specific version to be used in each release. This not always be the latest version.
23+
Because the release on Windows is built with a pre-compiled version of pyldap, we have to specify a specific version to be used in each release. This may not always be the latest version.
3324

3425
On the Win64 platform, there are very long pathnames embedded in the released build artifact `user-sync.pex`, which will cause problems unless you are on Windows 10 and are either running Python 3.6 or have enabled long pathnames system-wide (as described in this [Microsoft Dev Center article](https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx)). To work around this issue on older platforms, set the `PEX_ROOT` environment variable (as described [in the docs here](https://adobe-apiplatform.github.io/user-sync.py/en/user-manual/setup_and_installation.html)) to be a very short path (e.g., `set PEX_ROOT=C:\pex`).
26+
27+
Each release on each platform is built with a specific version of Python. Typically this is the latest available (from the OS vendor, if they provide one) for that platform. In general, and especially on Windows, you should use the same Python to run User Sync as it was built with.

docs/_layouts/default.html

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,11 @@
2828
<ul>
2929
{% assign current_level = my_page.nav_level %}
3030
{% elsif my_page.nav_level < current_level %}
31-
</ul>
32-
{% assign current_level = my_page.nav_level %}
31+
{% assign ub = current_level | minus: 1 %}
32+
{% for i in (my_page.nav_level .. ub) %}
33+
</ul>
34+
{% endfor %}
35+
{% assign current_level = my_page.nav_level %}
3336
{% endif %}
3437
{% if my_page.url == page.url %}
3538
<li><a class="page-link selected-page-link" href="{{ my_page.url | relative_url }}">{{ my_page.nav_link | escape }}</a></li>
@@ -41,6 +44,11 @@
4144
</ul>
4245
{% include post-nav-area.html %}
4346
</div>
47+
<div style="float: left; max-width: 23%;">
48+
<!-- This div convinces the browser to give better width management behavior when the nav area has position fixed -->
49+
<p> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</p>
50+
</div>
51+
4452
<div class="wrapper">
4553
{{ content }}
4654
</div>

docs/_sass/minima/_layout.scss

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,11 @@
209209
margin-left: 30px;
210210
/* border: black 1px solid; */
211211
padding: 5px;
212+
/* settings for scrollable nav area */
213+
position: fixed;
214+
height: calc(100% - 110px);
215+
overflow-y: auto;
216+
overflow-x: hidden;
212217
}
213218
.dummy-nav-area {
214219
width: 8000px; /* just needs to exceed max-width in nav-area */

examples/config files - basic/3 connector-ldap.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,10 @@ search_page_size: 200
5252
require_tls_cert: False
5353

5454
# (optional) all_users_filter (default value given below)
55-
# all_users_filter specifies the query used to find all users in the directory.
55+
# Use this filter to control exactly which LDAP resources are considered for synchronization.
56+
# If a user is not accepted by this filter he will never be seen by the User Sync tool, even if
57+
# your command line specifies --users all or he is in a group you have specified in your
58+
# command line (--users group g1) or in your configuration file (for group mapping).
5659
# The default value specified here is appropriate for Active Directory, which has a
5760
# special field that is used to enable and disable users. The value for OpenLDAP
5861
# directories might be much simpler: "(&(objectClass=person)(objectClass=top))"

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
'pycryptodome',
4949
'pyldap==2.4.37',
5050
'PyYAML',
51-
'umapi-client>=2.7',
51+
'umapi-client>=2.8',
5252
'psutil',
5353
'keyring',
5454
'six'

user_sync/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import subprocess
2626
import types
2727

28-
import keyring
2928
import yaml
3029
import six
3130

@@ -600,6 +599,7 @@ def get_credential(self, name, user_name, none_allowed=False):
600599
raise AssertionException('%s: cannot contain setting for both "%s" and "%s"' % (scope, name, keyring_name))
601600
if secure_value_key:
602601
try:
602+
import keyring
603603
value = keyring.get_password(service_name=secure_value_key, username=user_name)
604604
except Exception as e:
605605
raise AssertionException('%s: Error accessing secure storage: %s' % (scope, e))

user_sync/connector/directory_ldap.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ def load_users_and_groups(self, groups, extended_attributes, all_users):
133133
if not group_dn:
134134
self.logger.warning("No group found for: %s", group)
135135
continue
136-
group_member_subfilter = group_member_filter_format.format(group_dn=group_dn)
136+
group_member_subfilter = self.format_ldap_query_string(group_member_filter_format, group_dn=group_dn)
137137
if not group_member_subfilter.startswith('('):
138138
group_member_subfilter = six.text_type('(') + group_member_subfilter + six.text_type(')')
139139
user_subfilter = all_users_filter
@@ -178,8 +178,9 @@ def find_ldap_group_dn(self, group):
178178
base_dn = six.text_type(options['base_dn'])
179179
group_filter_format = six.text_type(options['group_filter_format'])
180180
try:
181+
filter_string = self.format_ldap_query_string(group_filter_format, group=group)
181182
res = connection.search_s(base_dn, ldap.SCOPE_SUBTREE,
182-
filterstr=group_filter_format.format(group=group), attrsonly=1)
183+
filterstr=filter_string, attrsonly=1)
183184
except Exception as e:
184185
raise AssertionException('Unexpected LDAP failure reading group info: %s' % e)
185186
group_dn = None
@@ -324,6 +325,34 @@ def iter_search_result(self, base_dn, scope, filter_string, attributes):
324325
connection.abandon(msgid)
325326
raise
326327

328+
@staticmethod
329+
def format_ldap_query_string(query, **kwargs):
330+
"""
331+
Escape LDAP special characters that may appear in injected query strings
332+
Should be used with any string that will be injected into an LDAP query.
333+
:param query:
334+
:param kwargs:
335+
:return:
336+
"""
337+
# See http://www.rfc-editor.org/rfc/rfc4515.txt
338+
escape_chars = six.text_type('*()\\&|<>~!:')
339+
escaped_args = {}
340+
# kwargs is a dict that would normally be passed to string.format
341+
for k, v in six.iteritems(kwargs):
342+
# LDAP special characters are escaped in the general format '\' + hex(char)
343+
# we need to run through the string char by char and if the char exists in
344+
# the escape_char list, get the ord of it (decimal ascii value), convert it to hex, and
345+
# replace the '0x' with '\'
346+
escaped_list = []
347+
for c in v:
348+
if c in escape_chars:
349+
replace = six.text_type(hex(ord(c))).replace('0x', '\\')
350+
escaped_list.append(replace)
351+
else:
352+
escaped_list.append(c)
353+
escaped_args[k] = six.text_type('').join(escaped_list)
354+
return query.format(**escaped_args)
355+
327356

328357
class LDAPValueFormatter(object):
329358
encoding = 'utf8'

user_sync/connector/umapi.py

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,6 @@ def update_user(self, attributes):
178178
"""
179179
:type attributes: dict
180180
"""
181-
if self.identity_type == user_sync.identity_type.ADOBEID_IDENTITY_TYPE:
182-
# shouldn't happen, but ignore it if it does
183-
return
184181
if attributes is not None and len(attributes) > 0:
185182
params = self.convert_user_attributes_to_params(attributes)
186183
self.do_list.append(('update', params))
@@ -212,14 +209,7 @@ def add_user(self, attributes):
212209
"""
213210
:type attributes: dict
214211
"""
215-
if self.identity_type == user_sync.identity_type.ADOBEID_IDENTITY_TYPE:
216-
email = self.email if self.email else self.username
217-
if not email:
218-
error_message = "ERROR: you must specify an email with an Adobe ID"
219-
raise AssertionException(error_message)
220-
params = self.convert_user_attributes_to_params({'email': email})
221-
else:
222-
params = self.convert_user_attributes_to_params(attributes)
212+
params = self.convert_user_attributes_to_params(attributes)
223213

224214
on_conflict_value = None
225215
option = params.pop('option', None)

user_sync/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@
1818
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1919
# SOFTWARE.
2020

21-
__version__ = '2.2.1'
21+
__version__ = '2.2.2rc1'

0 commit comments

Comments
 (0)