Skip to content

Allow search() to request user/group attributes #56

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

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
43 changes: 22 additions & 21 deletions crowd.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,18 @@ class CrowdServer(object):
The ``ssl_verify`` parameter controls how and if certificates are verified.
If ``True``, the SSL certificate will be verified.
A CA_BUNDLE path can also be provided.

The ``client_cert`` tuple (cert,key) specifies a SSL client certificate and key files.
"""

def __init__(self, crowd_url, app_name, app_pass, ssl_verify=True,
def __init__(self, crowd_url, app_name, app_pass, ssl_verify=True,
timeout=None, client_cert=None):
self.crowd_url = crowd_url
self.app_name = app_name
self.app_pass = app_pass
self.rest_url = crowd_url.rstrip("/") + "/rest/usermanagement/1"
# XXX the leading '/crowd' is necessary for Crowd Data Center (should
# add logic to auto-determine the need for it)
self.rest_url = crowd_url.rstrip("/") + "/crowd/rest/usermanagement/1"
self.ssl_verify = ssl_verify
self.client_cert = client_cert
self.timeout = timeout
Expand All @@ -51,9 +53,10 @@ def __init__(self, crowd_url, app_name, app_pass, ssl_verify=True,
def __str__(self):
return "Crowd Server at %s" % self.crowd_url

# don't include the password!
def __repr__(self):
return "<CrowdServer('%s', '%s', '%s')>" % \
(self.crowd_url, self.app_name, self.app_pass)
return "<CrowdServer('%s', '%s', '********')>" % \
(self.crowd_url, self.app_name)
Comment on lines +58 to +59
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think instead of a static string, we can maybe mask the password string matching it's length?

I know this gives away the length of the password but that could still be useful for users to know which password was used to configure the server.

Suggested change
return "<CrowdServer('%s', '%s', '********')>" % \
(self.crowd_url, self.app_name)
return "<CrowdServer('%s', '%s', '%s')>" % (
self.crowd_url, self.app_name, '*' * len(self.app_pass))

Optionally, we could add a private method that returns the raw password (probably out of scope for this PR).


def _build_session(self, content_type='json'):
headers = {
Expand Down Expand Up @@ -434,16 +437,15 @@ def set_user_attribute(self, username, attribute, value, raise_on_error=False):
"""Set an attribute on a user
:param username: The username on which to set the attribute
:param attribute: The name of the attribute to set
:param value: The value of the attribute to set
:param value: The value of the attribute to set (can be a list or tuple)
:return: True on success, False on failure.
"""
values = value if isinstance(value, (list, tuple)) else [value]
data = {
'attributes': [
{
'name': attribute,
'values': [
value
]
'values': values
},
]
}
Expand Down Expand Up @@ -652,7 +654,8 @@ def get_memberships(self):
memberships[group] = {u'users': users, u'groups': groups}
return memberships

def search(self, entity_type, property_name, search_string, start_index=0, max_results=99999):
def search(self, entity_type, property_name, search_string,
start_index=0, max_results=99999, with_attributes=False):
"""Performs a user search using the Crowd search API.

https://developer.atlassian.com/display/CROWDDEV/Crowd+REST+Resources#CrowdRESTResources-SearchResource
Expand All @@ -663,35 +666,33 @@ def search(self, entity_type, property_name, search_string, start_index=0, max_r
search_string: the string to search for.
start_index: starting index of the results (default: 0)
max_results: maximum number of results returned (default: 99999)
with_attributes: whether also to return entity attributes

Returns:
json results:
Returns search results.
"""

params = {
"entity-type": entity_type,
"expand": entity_type,
"property-search-restriction": {
"property": {"name": property_name, "type": "STRING"},
"match-mode": "CONTAINS",
"value": search_string,
}
}
# optionally return attributes (might expect <entity-type>.attributes
# but that doesn't work and this does)
expand = entity_type
if with_attributes:
expand += ",attributes"

params = {
'entity-type': entity_type,
'expand': entity_type,
'expand': expand,
'start-index': start_index,
'max-results': max_results
}

# Construct XML payload of the form:
# <property-search-restriction>
# <property>
# <name>email</name>
# <type>STRING</type>
# </property>
# <match-mode>EXACTLY_MATCHES</match-mode>
# <match-mode>CONTAINS</match-mode>
# <value>[email protected]</value>
# </property-search-restriction>

Expand Down