Skip to content

prepare for 2.2.2rc1 build #289

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Oct 26, 2017
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
27 changes: 10 additions & 17 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,27 @@
# Release Notes for User Sync Tool Version 2.2.1
# Release Notes for User Sync Tool Version 2.2.2

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

## New Features

[#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:
* `None` if the attribute has no value;
* a `str` (or `unicode` in py2) if the attribute has one value;
* a `list` of `str` (or `unicode` in py2) if the attribute has multiple values.

[#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.
None.

## Bug Fixes

[#257](https://github.com/adobe-apiplatform/user-sync.py/issues/257): Catch exceptions thrown by umapi-client when creating actions.

[#258](https://github.com/adobe-apiplatform/user-sync.py/issues/258): Correctly decrypt private keys in py3.
[#283](https://github.com/adobe-apiplatform/user-sync.py/issues/283): Don't import keyring unless needed.

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

[#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.

[#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.
[#288](https://github.com/adobe-apiplatform/user-sync.py/issues/288): Escape special characters in user input to LDAP queries.

## Compatibility with Prior Versions

There are no functional changes from prior versions.
There are no interface changes from prior versions.

## Known Issues

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

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`).

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.
12 changes: 10 additions & 2 deletions docs/_layouts/default.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,11 @@
<ul>
{% assign current_level = my_page.nav_level %}
{% elsif my_page.nav_level < current_level %}
</ul>
{% assign current_level = my_page.nav_level %}
{% assign ub = current_level | minus: 1 %}
{% for i in (my_page.nav_level .. ub) %}
</ul>
{% endfor %}
{% assign current_level = my_page.nav_level %}
{% endif %}
{% if my_page.url == page.url %}
<li><a class="page-link selected-page-link" href="{{ my_page.url | relative_url }}">{{ my_page.nav_link | escape }}</a></li>
Expand All @@ -41,6 +44,11 @@
</ul>
{% include post-nav-area.html %}
</div>
<div style="float: left; max-width: 23%;">
<!-- This div convinces the browser to give better width management behavior when the nav area has position fixed -->
<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>
</div>

<div class="wrapper">
{{ content }}
</div>
Expand Down
5 changes: 5 additions & 0 deletions docs/_sass/minima/_layout.scss
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,11 @@
margin-left: 30px;
/* border: black 1px solid; */
padding: 5px;
/* settings for scrollable nav area */
position: fixed;
height: calc(100% - 110px);
overflow-y: auto;
overflow-x: hidden;
}
.dummy-nav-area {
width: 8000px; /* just needs to exceed max-width in nav-area */
Expand Down
5 changes: 4 additions & 1 deletion examples/config files - basic/3 connector-ldap.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ search_page_size: 200
require_tls_cert: False

# (optional) all_users_filter (default value given below)
# all_users_filter specifies the query used to find all users in the directory.
# Use this filter to control exactly which LDAP resources are considered for synchronization.
# If a user is not accepted by this filter he will never be seen by the User Sync tool, even if
# your command line specifies --users all or he is in a group you have specified in your
# command line (--users group g1) or in your configuration file (for group mapping).
# The default value specified here is appropriate for Active Directory, which has a
# special field that is used to enable and disable users. The value for OpenLDAP
# directories might be much simpler: "(&(objectClass=person)(objectClass=top))"
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
'pycryptodome',
'pyldap==2.4.37',
'PyYAML',
'umapi-client>=2.7',
'umapi-client>=2.8',
'psutil',
'keyring',
'six'
Expand Down
2 changes: 1 addition & 1 deletion user_sync/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import subprocess
import types

import keyring
import yaml
import six

Expand Down Expand Up @@ -600,6 +599,7 @@ def get_credential(self, name, user_name, none_allowed=False):
raise AssertionException('%s: cannot contain setting for both "%s" and "%s"' % (scope, name, keyring_name))
if secure_value_key:
try:
import keyring
value = keyring.get_password(service_name=secure_value_key, username=user_name)
except Exception as e:
raise AssertionException('%s: Error accessing secure storage: %s' % (scope, e))
Expand Down
33 changes: 31 additions & 2 deletions user_sync/connector/directory_ldap.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def load_users_and_groups(self, groups, extended_attributes, all_users):
if not group_dn:
self.logger.warning("No group found for: %s", group)
continue
group_member_subfilter = group_member_filter_format.format(group_dn=group_dn)
group_member_subfilter = self.format_ldap_query_string(group_member_filter_format, group_dn=group_dn)
if not group_member_subfilter.startswith('('):
group_member_subfilter = six.text_type('(') + group_member_subfilter + six.text_type(')')
user_subfilter = all_users_filter
Expand Down Expand Up @@ -178,8 +178,9 @@ def find_ldap_group_dn(self, group):
base_dn = six.text_type(options['base_dn'])
group_filter_format = six.text_type(options['group_filter_format'])
try:
filter_string = self.format_ldap_query_string(group_filter_format, group=group)
res = connection.search_s(base_dn, ldap.SCOPE_SUBTREE,
filterstr=group_filter_format.format(group=group), attrsonly=1)
filterstr=filter_string, attrsonly=1)
except Exception as e:
raise AssertionException('Unexpected LDAP failure reading group info: %s' % e)
group_dn = None
Expand Down Expand Up @@ -324,6 +325,34 @@ def iter_search_result(self, base_dn, scope, filter_string, attributes):
connection.abandon(msgid)
raise

@staticmethod
def format_ldap_query_string(query, **kwargs):
"""
Escape LDAP special characters that may appear in injected query strings
Should be used with any string that will be injected into an LDAP query.
:param query:
:param kwargs:
:return:
"""
# See http://www.rfc-editor.org/rfc/rfc4515.txt
escape_chars = six.text_type('*()\\&|<>~!:')
escaped_args = {}
# kwargs is a dict that would normally be passed to string.format
for k, v in six.iteritems(kwargs):
# LDAP special characters are escaped in the general format '\' + hex(char)
# we need to run through the string char by char and if the char exists in
# the escape_char list, get the ord of it (decimal ascii value), convert it to hex, and
# replace the '0x' with '\'
escaped_list = []
for c in v:
if c in escape_chars:
replace = six.text_type(hex(ord(c))).replace('0x', '\\')
escaped_list.append(replace)
else:
escaped_list.append(c)
escaped_args[k] = six.text_type('').join(escaped_list)
return query.format(**escaped_args)


class LDAPValueFormatter(object):
encoding = 'utf8'
Expand Down
12 changes: 1 addition & 11 deletions user_sync/connector/umapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,6 @@ def update_user(self, attributes):
"""
:type attributes: dict
"""
if self.identity_type == user_sync.identity_type.ADOBEID_IDENTITY_TYPE:
# shouldn't happen, but ignore it if it does
return
if attributes is not None and len(attributes) > 0:
params = self.convert_user_attributes_to_params(attributes)
self.do_list.append(('update', params))
Expand Down Expand Up @@ -212,14 +209,7 @@ def add_user(self, attributes):
"""
:type attributes: dict
"""
if self.identity_type == user_sync.identity_type.ADOBEID_IDENTITY_TYPE:
email = self.email if self.email else self.username
if not email:
error_message = "ERROR: you must specify an email with an Adobe ID"
raise AssertionException(error_message)
params = self.convert_user_attributes_to_params({'email': email})
else:
params = self.convert_user_attributes_to_params(attributes)
params = self.convert_user_attributes_to_params(attributes)

on_conflict_value = None
option = params.pop('option', None)
Expand Down
2 changes: 1 addition & 1 deletion user_sync/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

__version__ = '2.2.1'
__version__ = '2.2.2rc1'