Skip to content
This repository has been archived by the owner on Aug 12, 2019. It is now read-only.

Ds10 #21

Open
wants to merge 5 commits into
base: ds10
Choose a base branch
from
Open

Ds10 #21

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
11 changes: 8 additions & 3 deletions deepsecurity/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,13 @@ def _request(self, request, auth_required=True):
elif request.has_key('data') and request['data']:
# POST
url_request = urllib2.Request(url, data=json.dumps(request['data']), headers=headers)
request_type = 'POST'
self.log("Making a REST POST request with headers {}".format(headers), level='debug')
if request['call'].startswith('tenants/name'):
setattr(url_request, 'get_method', lambda: 'PUT') # make this request use the PUT HTTP verb
request_type = 'PUT'
self.log("Making a REST PUT request with headers {}".format(headers), level='debug')
else:
request_type = 'POST'
self.log("Making a REST POST request with headers {}".format(headers), level='debug')
Copy link

Choose a reason for hiding this comment

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

For starters, this is indented by two spaces which should be corrected to four. Next, the third parameter to setattr, lambda: 'PUT' doesn't really make sense to me. Why not just setattr(url_request, 'get_method', 'PUT')?

self.log(" and data {}".format(request['data']), level='debug')
else:
# GET
Expand Down Expand Up @@ -577,4 +582,4 @@ def find(self, **kwargs):

if item_matches: results.append(item_id)

return results
return results
33 changes: 19 additions & 14 deletions deepsecurity/dsm.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@
import computers
import environments
import policies
import tenants
import tenanttemplates
import translation

class Manager(core.CoreApi):
def __init__(self,
hostname='app.deepsecurity.trendmicro.com',
port='4119',
tenant=None,
tenantname=None,
username=None,
password=None,
prefix="",
Expand All @@ -25,7 +27,7 @@ def __init__(self,
core.CoreApi.__init__(self)
self._hostname = None
self._port = port
self._tenant = None
self._tenantname = None
self._username = None
self._password = None
self._prefix = prefix
Expand All @@ -35,8 +37,8 @@ def __init__(self,
self._get_local_config_file()

# allow for explicit override
if tenant:
self._tenant = unicode(tenant, "utf-8") if not type(tenant) == type(unicode("")) else tenant
if tenantname:
self._tenantname = unicode(tenantname, "utf-8") if not type(tenantname) == type(unicode("")) else tenantname
if username:
self._username = unicode(username, "utf-8") if not type(username) == type(unicode("")) else username
if password:
Expand All @@ -48,6 +50,9 @@ def __init__(self,
self.rules = policies.Rules(manager=self)
self.ip_lists = policies.IPLists(manager=self)
self.cloud_accounts = environments.CloudAccounts(manager=self)
self.tenants = tenants.Tenants(manager=self)
self.tenant = tenants.Tenant(manager=self)
self.tenanttemplate = tenanttemplates.TenantTemplate(manager=self)

def __del__(self):
"""
Expand Down Expand Up @@ -89,11 +94,11 @@ def port(self, value):
self._set_endpoints()

@property
def tenant(self): return self._tenant
def tenantname(self): return self._tenantname

@tenant.setter
def tenant(self, value):
self._tenant = value
@tenantname.setter
def tenantname(self, value):
self._tenantname = value
self._reset_session()

@property
Expand Down Expand Up @@ -160,7 +165,7 @@ def _get_local_config_file(self):
credentials = {
'username': None,
'password': None,
'tenant': None,
'tenantname': None,
}
try:
credential_line_pattern = re.compile(r'(?P<key>\w+) = (?P<val>[^\n]+)')
Expand Down Expand Up @@ -193,9 +198,9 @@ def sign_in(self):
'username': self.username,
'password': self.password,
}
if self.tenant:
if self.tenantname:
soap_call['call'] = 'authenticateTenant'
soap_call['data']['tenantName'] = self.tenant
soap_call['data']['tenantName'] = self.tenantname
else:
soap_call['call'] = 'authenticate'

Expand All @@ -211,9 +216,9 @@ def sign_in(self):
'password': self.password,
}
}
if self.tenant:
if self.tenantname:
rest_call['call'] = 'authentication/login'
rest_call['data']['dsCredentials']['tenantName'] = self.tenant
rest_call['data']['dsCredentials']['tenantName'] = self.tenantname
else:
rest_call['call'] = 'authentication/login/primary'

Expand Down Expand Up @@ -434,4 +439,4 @@ def get_rule_recommendations_for_computer(self, computer_id):
results[rule_key].append(internal_rule_id)
results['total_recommedations'] += 1

return results
return results
2 changes: 1 addition & 1 deletion deepsecurity/policies.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,4 +317,4 @@ def _split_items(self):
if getattr(self, 'items') and "\n" in self.items:
self.addresses = self.items.split('\n')
else:
self.addresses.append(self.items.strip())
self.addresses.append(self.items.strip())
117 changes: 117 additions & 0 deletions deepsecurity/tenants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import core
import translation
import json
import urllib

class Tenants(core.CoreDict):
def __init__(self, manager=None):
core.CoreDict.__init__(self)
self.manager = manager
self.log = self.manager.log if self.manager else None

def get(self):
"""
Get all of the Tenants from Deep Security
"""

rest_call = self.manager._get_request_format(api=self.manager.API_TYPE_REST)

rest_call['call'] = 'tenants'
rest_call['query'] = {}
rest_call['query']['sID'] = self.manager._sessions[self.manager.API_TYPE_REST]

response = self.manager._request(rest_call, auth_required=False)

return response
Copy link

Choose a reason for hiding this comment

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

This is one of those trivial things, but if response isn't used beyond the return, why not return the call to _request rather than setting a variable?


class Tenant(core.CoreObject):
def __init__(self, manager=None, api_response=None, log_func=None):
core.CoreObject.__init__(self)
self.manager = manager
self.log = self.manager.log if self.manager else None
if api_response: self._set_properties(api_response, log_func)
Copy link

Choose a reason for hiding this comment

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

Coding style question for the maintainers, but I think the newline makes this more clear unless using the full ternary.


def add(self, admin_acct=None, admin_pw=None, admin_eml=None, name=None, modules_visible=['AM']):
"""
Add a Tenant
"""

rest_call = self.manager._get_request_format(api=self.manager.API_TYPE_REST)

rest_call['call'] = 'tenants'
rest_call['data'] = {
'createTenantRequest': {
'createOptions': {
'adminAccount': admin_acct,
'adminPassword': admin_pw,
'adminEmail': admin_eml,
'activationCodes': [ 'AM' ]
},
'tenantElement': {
'tenantID': 11,
'name': name,
'language': 'en',
'country': 'US',
'timeZone': 'US/Pacific',
'modulesVisible': modules_visible
},
'sessionId': self.manager._sessions[self.manager.API_TYPE_REST]
}
}

response = self.manager._request(rest_call, auth_required=False)

return response

def get(self, tenant_id=None, tenant_name=None, tenant_state=None, max_items=None, tenant_idop=None):
"""
Describe one/ more Tenants
"""

rest_call = self.manager._get_request_format(api=self.manager.API_TYPE_REST)

rest_call['query'] = {}
rest_call['query']['sID'] = self.manager._sessions[self.manager.API_TYPE_REST]

if tenant_state:
rest_call['call'] = 'tenants/state/'+tenant_state
if max_items:
rest_call['query']['maxItems'] = max_items
if tenant_id:
rest_call['query']['tenantID'] = str(tenant_id)
if tenant_idop:
rest_call['query']['tenantIDOp'] = tenant_idop
elif tenant_id:
rest_call['call'] = 'tenants/id/'+str(tenant_id)
elif tenant_name:
rest_call['call'] = 'tenants/name/'+urllib.quote(tenant_name)
else:
rest_call['call'] = 'tenants'

response = self.manager._request(rest_call, auth_required=False)

return response

def update(self, tenant_name=None, modules_visible=None):
"""
Update a Tenant by name
"""

rest_call = self.manager._get_request_format(api=self.manager.API_TYPE_REST)

rest_call['query'] = {}
rest_call['query']['sID'] = self.manager._sessions[self.manager.API_TYPE_REST]
rest_call['call'] = 'tenants/name/'+urllib.quote(tenant_name)

rest_call['data'] = {
'updateTenantRequest': {
'tenantElement': {
'modulesVisible': modules_visible
},
'sessionId': self.manager._sessions[self.manager.API_TYPE_REST]
}
}

response = self.manager._request(rest_call, auth_required=False)

return response
46 changes: 46 additions & 0 deletions deepsecurity/tenanttemplates.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import core
import translation
import json
import urllib

class TenantTemplate(core.CoreObject):
def __init__(self, manager=None, api_response=None, log_func=None):
core.CoreObject.__init__(self)
self.manager = manager
self.log = self.manager.log if self.manager else None
if api_response: self._set_properties(api_response, log_func)

def add(self, tenant_id=None):
"""
Add a Tenant Template
"""

rest_call = self.manager._get_request_format(api=self.manager.API_TYPE_REST)

rest_call['call'] = 'tenanttemplate'
rest_call['data'] = {
'createTenantTemplateRequest': {
'tenantId': tenant_id,
'sessionId': self.manager._sessions[self.manager.API_TYPE_REST]
}
}

response = self.manager._request(rest_call, auth_required=False)

return response

def get(self):
"""
Describe a Tenant Template
"""

rest_call = self.manager._get_request_format(api=self.manager.API_TYPE_REST)

rest_call['query'] = {}
rest_call['query']['sID'] = self.manager._sessions[self.manager.API_TYPE_REST]

rest_call['call'] = 'tenanttemplate'

response = self.manager._request(rest_call, auth_required=False)

return response
95 changes: 95 additions & 0 deletions sample.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import deepsecurity, json

# 1. Create a manager object and authenticate. Usage via the API mirrors the
# web administration console for permissions. This defaults to Deep Security
# as a Service
mgr = deepsecurity.dsm.Manager(hostname="dsm.cleardata.com", port="443", username="<username>", password="<password>", tenantname="primary", ignore_ssl_validation=True)
#mgr = deepsecurity.dsm.Manager(username=user, password=pwd, tenantname=tenant_name)
# Create same object against your own Deep Security Manager with a self-signed SSL certificate
#mgr = deepsecurity.dsm.Manager(hostname=hostname, username=user, password=pwd, ignore_ssl_validation=True)

# 2. With the object created, you have to authenticate
mgr.sign_in()

# 3. The Manager() object won't have any data populated yet but does have a number of properties
# all work in a similar manner
mgr.tenant.add(admin_acct='testadmin', admin_pw='Ou812345!', admin_eml='[email protected]', name='mytenanttest')
#print json.dumps(mgr.tenants.get(),indent=2,sort_keys=True)
#print json.dumps(mgr.tenant.get(tenant_id=11),indent=2,sort_keys=True)
print json.dumps(mgr.tenant.get(tenant_name='mytenanttest'),indent=2,sort_keys=True)
#print mgr.tenant.get(tenant_state='active', tenant_id=6, tenant_idop='eq')
#mgr.tenanttemplate.add(tenant_id=11)
#print json.dumps(mgr.tenanttemplate.get(),indent=2,sort_keys=True)
#mgr.tenant.update(tenant_name='mytenanttest',modules_visible=['AM','FW'])
'''
mgr.policies.get()
mgr.rules.get()
mgr.ip_lists.get()
mgr.cloud_accounts.get()
mgr.computer_groups.get()
mgr.computers.get()

# 4. Each of these properties inherits from core.CoreDict which exposes the .get() and other
# useful methods. .get() can be filtered for various properties in order to reduce the
# amount of data you're getting from the Manager(). By default .get() will get all
# of the data it can.
#
# core.CoreDict also exposes a .find() method which is extremely useful for searching
# for specific objects that meet various criteria. .find() takes a set of keyword arguments
# that translate to properties on the objects in the core.CoreDict
#
# For example, this simple loop shows all computers that are currently 'Unmanaged' by
# by Deep Security
for computer_id in mgr.computers.find(overall_status='Unmanaged.*'):
computer = mgr.computers[computer_id]
print "{}\t{}\t{}".format(computer.name, computer.display_name, computer.overall_status)

# For example, here's all the computers that are running Windows and have the security
# policy "Store UI" or "Shipping"
for computer_id in mgr.computers.find(platform='Windows.*', policy_name=['Store UI', 'Shipping']):
computer = mgr.computers[computer_id]
print "{}\t{}\t{}".format(computer.name, computer.display_name, computer.overall_status)

# The .find() method takes uses a regex for string comparison and direct comparison for
# other objects. It's extremely flexible and works for all core.CoreDict objects

# 5. You can also take actions on each of these objects. Where it makes sense, the relevant API
# methods have been added to the object itself.
#
# For example, if you want to scan a set of computers for malware
#mgr.computer[1].scan_for_malware()

# Apply the same logic for a ComputerGroup
#mgr.computer_group[1].scan_for_malware()

# Of course, you can use the .find() method on all Computers or ComputerGroups to filter the
# request with a finer granularity
for computer_id in mgr.computers.find(platform='Windows.*', policy_name=['Store UI', 'Shipping']):
computer = mgr.computers[computer_id]
computer.scan_for_malware()

# This applies to any type of scan or action:
# .scan_for_integrity()
# .scan_for_recommendations()
# .assign_policy()
# ...

# 6. Adding an AWS account is a good example of a unique property for the
# environments.CloudAccounts object
#mgr.cloud_accounts.add_aws_account(friendly_name, aws_access_key=AWS_ACCESS_KEY, aws_secret_key=AWS_SECRET_KEY)

# This would add the AWS account and all regions to Deep Security in order to sync
# the inventory of EC2 instances automatically
#
# The IAM identity for the access/secret key needs:
# - ec2::describeInstances
# - ec2::describeImages
# - ec2::describeTags

# 7. Old school but key. API access is the same as a user logging in. If you are going to
# start a large number of session, you'll need to finish each of them to avoid
# exception being thrown.
#
# This function is also called automatically with the object's destructor
'''
mgr.sign_out()
Loading