Skip to content

Commit

Permalink
Updates
Browse files Browse the repository at this point in the history
  • Loading branch information
Hugh Pyle committed Sep 26, 2018
1 parent 4d85343 commit f246613
Show file tree
Hide file tree
Showing 106 changed files with 17,365 additions and 2,140 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
build/
__pycache__
.DS_Store
.gradle
.settings
.idea
.cache
.pytest_cache
.coverage
.tox
.swp
.eggs
.virtualenv*
resilient_circuits_lockfile
*.iml
*.pem
Expand All @@ -17,3 +20,4 @@ resilient_circuits_lockfile
*~
*.egg-info
*.tar.gz
*.pytest_cache
13 changes: 7 additions & 6 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ python: 2.6

env:
global:
- TEST_RESILIENT_APPLIANCE=d2-direct.resilientsystems.com
- TEST_RESILIENT_APPLIANCE=staging2.internal.resilientsystems.com
- OCTOKIT_API_ENDPOINT="https://github.ibm.com/api/v3/"
- PIP_FIND_LINKS="$TRAVIS_BUILD_DIR/pkgs"
- secure: VU1PL2bWOE+E3ieBz/0Oa2hIRXGeSFYubE9SYh3dH541h8V8FWE0kGt8P6xdZOGmf9xNsDL/O+rKqrq5TCKTdUQqFXm7RCD//iQrHUcbu2YU38XPpBQrWxSZs29sR3R6UkUypZahHmn/ghjgZnRxQIWGscYPvvNCiOP9X85ckmVaKLYPwW0HPH7vIKs9zcT8tEyRDANokc0BQDjeVu0s29FeKGyy9JVbuye8/1TmVkQWBvutvcQ/z/mOQ7dOO3fW0wkVwOHPF9FtBc79WzjK5w/Ej30EWHC5zdRG46+2FLcqKSHvkyuV59f0ojxLzRmeR1ueS37pNncmXfVMREwtiIYN/Dd3isLsg14RK1leu/JHiPxfQtz2TV4+yeVO4aZk+Bs/JLf1ZbXAE+A71hIH6rTUpEBq1S8qjKsfTPEWLg1cuq1ujf2WOAumdIf8rSOnQ9EbEfBlm3N8Wo9RjXbEx6hq+UHr7L28tw0u00gcAex6Ky2eRk+USFnXBHs/Kf5i29CWzw4Lcnb2hPa0bup3yNQuss/Yy+cQO5tDW8jJPP8joR5Fvr8fJZVtGlTGp09odHcrDGKvbdlf0gVmVDYawKi0v4m0URCKVy0vYAbzVOgZF46nW+VfcexiLxomwYpKeltigk+L52aV5DIodfuxS9aB6IJtEYSTO8Mf+Yo2x8Q=
- secure: kr5Zz5frfrGOeuAylefGbDhY5s/YwyRhktuAly1ovOn/7Q3OJYjTq6h7wvnt1KQ/YeSdA+bxwOhWKbYHPQHAhovyo/5gsII7LruSs7VjdcD9tDoaYEoDBP7nki+NGr+dBVwrooGJ3f7TbuZs+4OSyPWD2FdN4PsOYLof4soDEW7C0cTP2KZ/wNGDjBGB2stOb6a5h4MQSohx+7B795noUoK5ojmygZObIGSDWmahR4kzCm+rEVLlMV0ptDCBXvn4xmJLCz5UOZhR27ckuiW342vNxShlms+rwWcvoxwbj61Qn3MEf9S9D59aJ+n4+u9Kb3VD4HJjlQ3rWZ/DADPfp7h6XOmfrQq3Xj3sQ4K2+8RMSFHdxWPsmhWd/Aty+YmWjoOnewoBfFaDUzFRURqwO3K+oh1H0IALTOTYQSYEeuVfi/+mwJRkKh0+IgvgscL5/bo+nVnQBk4FpWJRHV0x2fWiG8DHCKmInkkFSDHax3dHc9pYZXQTdNdfvsJRtc0rEn6GyVnRMia1TKLpB1joRhb7mkyc7pgDSatvV9W6+v6+evplHFxS7lkm9gqlW/ygJzPVYx7UaFuqo9cOi/c8sR6qf7NUTUi9Aa4aqY6qHNrkxfh7+5ck7wLTWmE0WL+0r3Z09Zg746SIGYqLrFQJZPn+JanFEy0q7kAU2Zr8vgE=

matrix:
fast_finish: true
Expand All @@ -17,10 +18,10 @@ matrix:
include:
- python: 2.7
env:
- TOXENV=py27 TEST_RESILIENT_ORG="Resilient PS - Test"
- TOXENV=py27 TEST_RESILIENT_ORG="Resilient PS - Test"
- python: 3.4
env:
- TOXENV=py34 TEST_RESILIENT_ORG="Resilient PS - Test2"
- TOXENV=py34 TEST_RESILIENT_ORG="Resilient PS - Test2"

install:
- pip install --upgrade pip
Expand All @@ -35,17 +36,17 @@ before_script:
- cp resilient-python-api/*/dist/*.tar.gz ./pkgs

script:
- ./build_packages.sh && ./run_tests.sh
- .scripts/build_packages.sh && .scripts/run_tests.sh

after_script:
- echo "Packages To Deploy"
- ls -l *.tar.gz
- ls -l .scripts/*.tar.gz

deploy:
provider: releases
api_key: "$GITHUB_OAUTH_TOKEN"
file_glob: true
file: ./rc-*.tar.gz
file: .scripts/rc-*.tar.gz
skip_cleanup: true
on:
tags: true
Expand Down
4 changes: 4 additions & 0 deletions fn_ldap_utilities/MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
include README.md
include fn_ldap_utilities/util/*
include fn_ldap_utilities/LICENSE
include docs/*
100 changes: 100 additions & 0 deletions fn_ldap_utilities/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Resilient LDAP Utilities v1.0.0

This Python Package is comprised of various Resilient Functions that allow you to manage users in your Directory Service, without having to leave the UI of Resilient

See [Detailed PDF Documentation here](./docs/Resilient%20Integration%20LDAP%20Utility%20Function.pdf)

## ldap_utilities_search
* Supports **Active Directory** and **OpenLDAP**
* When using with **Microsoft Active Directory** server
* Set the following in the **app.config file**:
```python
[fn_ldap_utilities]
ldap_port=636
ldap_use_ssl=True
ldap_is_active_directory=True
```

The LDAP search requires **4 input parameters**. The parameters are setup from a Resilient systems workflow on the Resilient console.
The following are examples of setup of each parameter using a simple workflow pre-processing script. The %param% token
will be replaced by the actual inputs.param value at time of execution.

```
inputs.ldap_search_base = "dc=example,dc=com"
inputs.ldap_search_filter = "(&(objectClass=person)(uid=%ldap_param%))"
inputs.ldap_search_attributes = "cn,sn,mail,telephoneNumber"
inputs.ldap_search_param = artifact.value
```
The results returned to Resilient will be in JSON format and will consist of a list of
entries where each entry has a 'dn' entry and a set of attributes
```
{
"entries": [
{"dn': "entry1_dn1_value", "entry1_attribute2", "entry1_attribute3", ... },
{"dn": "entry2_dn2_value", "entry2_attribute2", "entry2_attribute3", ... }
...
]
}
```
## ldap_utilities_set_password
* Supports **Active Directory** and **OpenLDAP**
* When using with **Microsoft Active Directory** server
* Set the following in the **app.config file**:
```python
[fn_ldap_utilities]
ldap_port=636
ldap_use_ssl=True
ldap_is_active_directory=True
```
* Must use a secure connection
* Microsoft does not allow you to change an user's password unless using a secure connection
* Microsoft have their own ldap3 function to change the password of an entry in the Active Directory [see here](https://ldap3.readthedocs.io/microsoft.html)
* For other directory services using LDAP (i.e. **OpenLDAP**)
* Set the following in the **app.config file**:
```python
[fn_ldap_utilities]
ldap_is_active_directory=False
```
## ldap_utilities_update
* Supports **Active Directory** and **OpenLDAP**
* Takes the name of the attribute you want to update and an list of values to update that attribute with
* The function input `ldap_attribute_values` must be a **string representation of an list:**
```python
inputs.ldap_attribute_values = "['stringValue1', 1234, 'stringValue2']"
```
* Uses **MODIFY_REPLACE** as documented [here](https://ldap3.readthedocs.io/modify.html)
* _"Replace all existing values of the specified attribute with the new values listed"_
* _"Creates the attribute if it does not already exist"_
* _"It is ignored if the attribute does not exist"_

## ldap_utilities_toggle_access
* Supports only **Active Directory**.
* Set the following in the **app.config file**:
```python
[fn_ldap_utilities]
ldap_port=636
ldap_use_ssl=True
ldap_is_active_directory=True
```
* Enables or Disables an **Active Directory** user
* Requires the DN of the user you wish to toggle access for
* Example shows how to use with **LDAP Utilities: Search Function** to toggle access for a user using their email address

## ldap_utilities_add_to_groups / ldap_utilities_remove_from_groups
* Supports only **Active Directory**.
* Set the following in the **app.config file**:
```python
[fn_ldap_utilities]
ldap_port=636
ldap_use_ssl=True
ldap_is_active_directory=True
```
* The function inputs `ldap_multiple_user_dn` and `ldap_multiple_group_dn` must be **string representation of a list:**
```python
# Pre-Processing Script::
inputs.ldap_multiple_user_dn = "['dn=user1,dc=example,dc=com', 'dn=user2,dc=example,dc=com']"
inputs.ldap_multiple_group_dn = "['dn=Accounts Group,dc=example,dc=com', 'dn=IT Group,dc=example,dc=com']"
```
Binary file not shown.
Binary file not shown.
12 changes: 12 additions & 0 deletions fn_ldap_utilities/fn_ldap_utilities/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Copyright © IBM Corporation 2010, 2018

Permission is hereby granted, free of charge, to any person obtaining a copyof this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included inall copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THEAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
5 changes: 5 additions & 0 deletions fn_ldap_utilities/fn_ldap_utilities/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import pkg_resources
try:
__version__ = pkg_resources.get_distribution(__name__).version
except pkg_resources.DistributionNotFound:
pass
1 change: 1 addition & 0 deletions fn_ldap_utilities/fn_ldap_utilities/components/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# -*- coding: utf-8 -*-
# (c) Copyright IBM Corp. 2018. All Rights Reserved.
# pragma pylint: disable=unused-argument, no-self-use
"""Function implementation"""

import logging
from resilient_circuits import ResilientComponent, function, handler, StatusMessage, FunctionResult, FunctionError
from fn_ldap_utilities.util.helper import LDAPUtilitiesHelper
from ast import literal_eval
from ldap3.extend.microsoft.addMembersToGroups import ad_add_members_to_groups as ad_add_members_to_groups

class FunctionComponent(ResilientComponent):
"""Component that implements Resilient function 'ldap_utilities_add_to_groups"""

def __init__(self, opts):
"""constructor provides access to the configuration options"""
super(FunctionComponent, self).__init__(opts)
self.options = opts.get("fn_ldap_utilities", {})

@handler("reload")
def _reload(self, event, opts):
"""Configuration options have changed, save new values"""
self.options = opts.get("fn_ldap_utilities", {})

@function("ldap_utilities_add_to_groups")
def _ldap_utilities_add_to_groups_function(self, event, *args, **kwargs):
"""Function: A function that allows adding multiple users to multiple groups"""
log = logging.getLogger(__name__)
try:
yield StatusMessage("Starting ldap_utilities_add_to_groups")

# Instansiate helper (which gets appconfigs from file)
helper = LDAPUtilitiesHelper(self.options)
yield StatusMessage("Appconfig Settings OK")

# Get function inputs
input_ldap_multiple_user_dn_asString = helper.get_function_input(kwargs, "ldap_multiple_user_dn") # text (required) [string repersentation of an array]
input_ldap_multiple_group_dn_asString = helper.get_function_input(kwargs, "ldap_multiple_group_dn") # text (required) [string repersentation of an array]
yield StatusMessage("Function Inputs OK")

if not helper.LDAP_IS_ACTIVE_DIRECTORY:
raise FunctionError("This function only supports an Active Directory connection. Make sure ldap_is_active_directory is set to True in the app.config file")

try:
# Try converting input to an array
input_ldap_multiple_user_dn = literal_eval(input_ldap_multiple_user_dn_asString)
input_ldap_multiple_group_dn = literal_eval(input_ldap_multiple_group_dn_asString)

except Exception:
raise ValueError("""input_ldap_multiple_user_dn and input_ldap_multiple_group_dn must be a string repersenation of an array e.g. "['dn=Accounts Group,dc=example,dc=com', 'dn=IT Group,dc=example,dc=com']" """)

# Instansiate LDAP Server and Connection
c = helper.get_ldap_connection()

try:
# Bind to the connection
c.bind()
except:
raise ValueError("Cannot connect to LDAP Server. Ensure credentials are correct")

# Inform user
msg = "Connected to {0}".format("Active Directory")
yield StatusMessage(msg)

res = False

try:
yield StatusMessage("Attempting to add user(s) to group(s)")
# perform the removeMermbersFromGroups operation
res = ad_add_members_to_groups(c, input_ldap_multiple_user_dn, input_ldap_multiple_group_dn, True)

except Exception:
raise ValueError("Ensure all user and group DNs exist")

finally:
# Unbind connection
c.unbind()

results = {
"success": res,
"users_dn": input_ldap_multiple_user_dn,
"groups_dn": input_ldap_multiple_group_dn
}

log.info("Completed")

# Produce a FunctionResult with the results
yield FunctionResult(results)
except Exception:
yield FunctionError()
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# -*- coding: utf-8 -*-
# (c) Copyright IBM Corp. 2018. All Rights Reserved.
# pragma pylint: disable=unused-argument, no-self-use
"""Function implementation"""

import logging
from resilient_circuits import ResilientComponent, function, handler, StatusMessage, FunctionResult, FunctionError
from fn_ldap_utilities.util.helper import LDAPUtilitiesHelper
from ast import literal_eval
from ldap3.extend.microsoft.removeMembersFromGroups import ad_remove_members_from_groups as ad_remove_members_from_groups

class FunctionComponent(ResilientComponent):
"""Component that implements Resilient function 'ldap_utilities_remove_from_groups"""

def __init__(self, opts):
"""constructor provides access to the configuration options"""
super(FunctionComponent, self).__init__(opts)
self.options = opts.get("fn_ldap_utilities", {})

@handler("reload")
def _reload(self, event, opts):
"""Configuration options have changed, save new values"""
self.options = opts.get("fn_ldap_utilities", {})

@function("ldap_utilities_remove_from_groups")
def _ldap_utilities_remove_from_groups_function(self, event, *args, **kwargs):
"""Function: A function that allows you to remove multiple from multiple groups"""
log = logging.getLogger(__name__)

try:
yield StatusMessage("Starting ldap_utilities_remove_from_groups")

# Instansiate helper (which gets appconfigs from file)
helper = LDAPUtilitiesHelper(self.options)
yield StatusMessage("Appconfig Settings OK")

# Get function inputs
input_ldap_multiple_user_dn_asString = helper.get_function_input(kwargs, "ldap_multiple_user_dn") # text (required) [string repersentation of an array]
input_ldap_multiple_group_dn_asString = helper.get_function_input(kwargs, "ldap_multiple_group_dn") # text (required) [string repersentation of an array]
yield StatusMessage("Function Inputs OK")

if not helper.LDAP_IS_ACTIVE_DIRECTORY:
raise FunctionError("This function only supports an Active Directory connection. Make sure ldap_is_active_directory is set to True in the app.config file")

try:
# Try converting input to an array
input_ldap_multiple_user_dn = literal_eval(input_ldap_multiple_user_dn_asString)
input_ldap_multiple_group_dn = literal_eval(input_ldap_multiple_group_dn_asString)

except Exception:
raise ValueError("""input_ldap_multiple_user_dn and input_ldap_multiple_group_dn must be a string repersenation of an array e.g. "['dn=Accounts Group,dc=example,dc=com', 'dn=IT Group,dc=example,dc=com']" """)

# Instansiate LDAP Server and Connection
c = helper.get_ldap_connection()

try:
# Bind to the connection
c.bind()
except:
raise ValueError("Cannot connect to LDAP Server. Ensure credentials are correct")

# Inform user
msg = "Connected to {0}".format("Active Directory")
yield StatusMessage(msg)

res = False
users_dn = []

try:
yield StatusMessage("Attempting to remove user(s) from group(s)")
# perform the removeMermbersFromGroups operation
res = ad_remove_members_from_groups(c, input_ldap_multiple_user_dn, input_ldap_multiple_group_dn, True)

# Return list of users that were removed, and ignore users that do not exist, not valid, or not member of group
if res and "changes" in c.request:
users_dn = c.request["changes"][0]["attribute"]["value"]

except Exception:
raise ValueError("Ensure all group DNs exist")

finally:
# Unbind connection
c.unbind()

results = {
"success": res,
"users_dn": users_dn if len(users_dn) > 0 else None,
"groups_dn": input_ldap_multiple_group_dn
}

log.info("Completed")

# Produce a FunctionResult with the results
yield FunctionResult(results)
except Exception:
yield FunctionError()
Loading

0 comments on commit f246613

Please sign in to comment.