I am trying to get all group members of Active Directory.
I have this code:
from ldap3 import Server, Connection, ALL, core
server = Server(address, get_info=ALL)
ad_conn = Connection(server, dn, password, auto_bind=True)
members = []
AD_GROUP_FILTER = '(&(objectClass=GROUP)(cn={group_name}))'
ad_filter = AD_GROUP_FILTER.replace('{group_name}', group_name)
result = ad_conn.search_s('OU details', ldap3.SCOPE_SUBTREE, ad_filter)
if result:
if len(result[0]) >= 2 and 'member' in result[0][1]:
members_tmp = result[0][1]['member']
for m in members_tmp:
email = get_email_by_dn(m, ad_conn)
if email:
members.append(email)
return members
But I am getting an error
'Connection' object has no attribute 'search_s'
Use search(), specify the attributes you need (it seems you build 'email' from user dn but if it were present in the directory), and fix the arguments in function call (arg. order filter then scope, plus use the proper constant SUBTREE) :
from ldap3 import Server, Connection, ALL, core
server = Server(address, get_info=ALL)
ad_conn = Connection(server, dn, password, auto_bind=True)
members = []
AD_GROUP_FILTER = '(&(objectClass=GROUP)(cn={group_name}))'
ad_filter = AD_GROUP_FILTER.replace('{group_name}', group_name)
ad_conn.search('OU details', ad_filter, ldap3.SUBTREE, attributes=['member', 'mail'])
if len(ad_conn.response):
# To grab data, you might prefer the following - or use ad_conn.entries :
for entry in ad_conn.response:
print(entry['dn'], entry['attributes'])
Related
I am trying to create a service account via the Ldap3 library in Python. The service account is successfully created, but there is a small problem. The "User cannot change password" checkboxes is not selected.
I did some research and found that to set this property I need to follow some steps given here : https://learn.microsoft.com/en-us/windows/win32/adsi/modifying-user-cannot-change - password-ldap-provider . The logic given in this link is in a different programming language than Python, so i tried to replicate the same logic in Python. From what we understand, I’ve implemented the feature, which executed successfully, but didn't see the expected effect on the AD server ("User cannot change password" checkbox is still unchecked).
Below is the code used to create and add the ACL object to the service account.
def create_object_ace(privguid, sid):
print("creating ace object")
nace = ldaptypes.ACE()
nace['AceType'] = ldaptypes.ACCESS_DENIED_OBJECT_ACE.ACE_TYPE
nace['AceFlags'] = 0x00
acedata = ldaptypes.ACCESS_DENIED_OBJECT_ACE()
acedata['Mask'] = ldaptypes.ACCESS_MASK()
acedata['Mask']['Mask'] = ldaptypes.ACCESS_ALLOWED_OBJECT_ACE.ADS_RIGHT_DS_CONTROL_ACCESS
acedata['ObjectType'] = string_to_bin(privguid)
acedata['InheritedObjectType'] = b''
acedata['Sid'] = ldaptypes.LDAP_SID()
acedata['Sid'].fromCanonical(sid)
assert sid == acedata['Sid'].formatCanonical()
acedata['Flags'] = ldaptypes.ACCESS_DENIED_OBJECT_ACE.ACE_OBJECT_TYPE_PRESENT
nace['Ace'] = acedata
return nace
s = Server('ad_server.com', get_info=ALL)
c = Connection(s, user="testdomain\\username", password="password", authentication=NTLM)
c.search(search_base="DC=testad,DC=com", search_filter="(CN=svc_account_47)",
search_scope=SUBTREE, attributes=['objectSid', 'sAMAccountName'])
entry = c.entries[0]
usersid = entry['objectSid'].value
controls = security_descriptor_control(sdflags=0x04)
c.search(search_base="DC=testahs,DC=com", search_filter='(&(objectCategory=domain))',
attributes=['SAMAccountName', 'nTSecurityDescriptor'], controls=controls)
entry = c.entries[0]
secDescData =. entry['nTSecurityDescriptor'].raw_values[0]
secDesc = ldaptypes.SR_SECURITY_DESCRIPTOR(data=secDescData)
secDesc['Dacl']['Data'].append(create_object_ace('ab721a53-1e2f-11d0-9819-00aa0040529b', usersid)) # This GUID is for 'User cannot change password'
dn = entry.entry_dn
data = secDesc.getData()
c.modify(dn, {'nTSecurityDescriptor': (ldap3.MODIFY_REPLACE, [data])}, controls=controls)
print(c.result)
# gives -> {'result': 0, 'description': 'success', 'dn': '', 'message': '', 'referrals': None, 'type': 'modifyResponse'}
The Python code reference is from the following link:
https://github.com/SecureAuthCorp/impacket/blob/master/impacket/examples/ntlmrelayx/attacks/ldapattack.py
Can someone help me here. Thanks in advance.
In AWS, I have a centralized networking account that defines all the VPCs and subnets. And each VPC is shared with target accounts using Resource Access Manager (RAM). Given an IP, need to find out the target account ID with which the VPC/subnet has been shared with. Here is what I have done so far:
In the code below, vpc parameter contains the vpc lookup response and and ip_addr is the IP address we are looking for
def lookup_ipaddr (session, ec2_client, vpc, ip_addr):
found = False
if (ipaddress.ip_address(ip_addr) in ipaddress.ip_network(vpc['CidrBlock'])):
filters = [{'Name':'vpc-id', 'Values':[ vpc['VpcId'] ]}]
subnets = ec2_client.describe_subnets( Filters = filters )['Subnets']
for subnet in subnets:
if (ipaddress.ip_address(ip_addr) in ipaddress.ip_network(subnet['CidrBlock'])):
found = True
tags = subnet['Tags']
# tags returned by previous api is in different form than that required by RAM
for tag in tags:
tag['tagKey'] = tag['Key']
tag['tagValues'] = [tag['Value']]
del tag['Key']
del tag['Value']
print("\n\n")
print (tags)
print("\n\n")
resourceArn = subnet['SubnetArn']
ram_client = session.client('ram')
resp = ram_client.get_resource_shares (resourceOwner = 'SELF', tagFilters=tags)
However the API call get_resource_shares doesn't return any response (except Response Metadata). Any suggestion on how to find out the destination account ID/Principal with which the subnet was shared?
After a bit of digging, I was able to obtain the destination account id by using list_principals api of AWS Resource Access Manager (RAM): https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ram.html#RAM.Client.list_principals
Here is the full python code:
def lookup_ipaddr (session, ec2_client, vpc, ip_addr):
found = False
filters = [{'Name':'vpc-id', 'Values':[ vpc['VpcId'] ]}]
subnets = ec2_client.describe_subnets( Filters = filters )['Subnets']
for subnet in subnets:
if (ipaddress.ip_address(ip_addr) in ipaddress.ip_network(subnet['CidrBlock'])):
resourceArn = subnet['SubnetArn']
ram_client = session.client('ram')
resp = ram_client.list_principals(
resourceOwner = 'SELF',
resourceArn = resourceArn
)
print(f"Subnet {subnet['SubnetId']} is shared with account [{resp['principals'][0]['id']}]")
found = True
break
return found
Hi i have succeeded ton connect azure devops with python and retrieve data from system fields with wiql query.but i Can not execute programm and i got an error like this
KeyError[Microsoft.vsts.common.acceptedcriteria] i do not understand where is the probleme because i get the value for priority and not for acceptedcriteria. what am i missing ? any help would be appreciated
Every time i exécuté this Quercy i get this error
from vsts.vss_connection import VssConnection
from msrest.authentication import BasicAuthentication
import json
from vsts.work_item_tracking.v4_1.models.wiql import Wiql
def emit(msg, *args):
print(msg % args)
def print_work_item(work_item):
emit(
"{0} ,{1},{2},{3}".format(
work_item.fields["System.WorkItemType"],
work_item.id,
work_item.fields["System.Title"],
work_item.fields["Microsoft.VSTS.Common.AcceptanceCriteria"]
work_item.fields["Microsoft.VSTS.Common.Priority"]
)
)
personal_access_token = 'xbxbxxbxhhdhdjdkdkddkdkdkdkdkdkkdkdkd'
organization_url = 'https://dev.azure.com/YourorgName'
# Create a connection to the org
credentials = BasicAuthentication('', personal_access_token)
connection = VssConnection(base_url=organization_url, creds=credentials)
wiql = Wiql(
query="""select [System.Id],[Microsoft.VSTS.Common.AcceptanceCriteria],[System.Title],[System.WorkItemType],[Microsoft.VSTS.Common.Priority] From WorkItems """
)
wit_client = connection.get_client('vsts.work_item_tracking.v4_1.work_item_tracking_client.WorkItemTrackingClient')
wiql_results = wit_client.query_by_wiql(wiql).work_items
if wiql_results:
# WIQL query gives a WorkItemReference with ID only
# => we get the corresponding WorkItem from id
work_items = (
wit_client.get_work_item(int(res.id)) for res in wiql_results
As a simple answer, you can update your print function to
def print_work_item(work_item):
emit(
"{0} ,{1},{2}".format(
work_item.fields["System.WorkItemType"],
work_item.id,
work_item.fields["System.Title"]
)
)
Some fields (like Microsoft.VSTS.Common.AcceptanceCriteria and Microsoft.VSTS.Common.Priority) may not be represented in some work item types. Therefore, before printing a field you have to check its availability in fields dictionary.
To enable digest auth in Cherrypy they say to use code like this:
from cherrypy.lib import auth_digest
USERS = {'jon': 'secret'}
conf = {
'/protected/area': {
'tools.auth_digest.on': True,
'tools.auth_digest.realm': 'localhost',
'tools.auth_digest.get_ha1': auth_digest.get_ha1_dict_plain(USERS),
'tools.auth_digest.key': 'a565c27146791cfb'
}
}
cherrypy.quickstart(myapp, '/', conf)
And it works pretty well. But I use server.conf file to store all the configs of my app and I want to continue of using this file. So I write there new section:
[/protected/area]
tools.auth_digest.on = True
tools.auth_digest.realm = 'localhost',
tools.auth_digest.get_ha1 = auth_digest.get_ha1_dict_plain({'jon': 'secret'}),
tools.auth_digest.key = 'a565c27146791cfb'
After thjis I've got errr:
ValueError: ('Config error in section: \'/protected/area\', option: \'tools.auth_digest.get_ha1\', value: "auth_digest.get_ha1_dict_plain({\'jon\': \'secret\'}),". Config values must be valid Python.', 'TypeError', ("unrepr could not resolve the name 'auth_digest'",))
I understand the reason but I dont know how to provide "valid Python" with server.conf. Help me, please.
You can make that function call in you application and use the resulting function in the config like:
myapp/__init__.py:
get_ha1 = auth_digest.get_ha1_dict_plain({'jon': 'secret'})
server.conf:
[/protected/area]
tools.auth_digest.on = True
tools.auth_digest.realm = 'localhost'
tools.auth_digest.get_ha1 = myapp.get_ha1
tools.auth_digest.key = 'a565c27146791cfb'
The problem with that is that you're defining credentials in code.
It might worth mention that you can use other functions no just the one that you define your users with plain texts passwords in a dict, you can use an htdigest file using the one from cherrypy.lib.auth_digest.get_ha1_file_htdigest or implement your own ha1 function like the one that the get_ha1_dict_plain returns:
def get_ha1_dict_plain(user_password_dict):
"""Returns a get_ha1 function which obtains a plaintext password from a
dictionary of the form: {username : password}.
If you want a simple dictionary-based authentication scheme, with plaintext
passwords, use get_ha1_dict_plain(my_userpass_dict) as the value for the
get_ha1 argument to digest_auth().
"""
def get_ha1(realm, username):
password = user_password_dict.get(username)
if password:
return md5_hex('%s:%s:%s' % (username, realm, password))
return None
return get_ha1
I implemented one that gets the ha1 from the database, for example using this sqlalchemy model (https://github.com/cyraxjoe/maki/blob/master/maki/db/models.py#L174-L189):
class User(Base):
__tablename__ = 'users'
name = Column(String(32), unique=True, nullable=False)
vname = Column(String(64))
email = Column(String(64), nullable=False)
ha1 = Column(String(32), nullable=False)
active = Column(Boolean, server_default='True')
#validates('ha1')
def validates_ha1(self, key, passwd):
if self.name is None:
raise Exception('Set the name first')
pack = ':'.join([self.name, maki.constants.REALM, passwd])
return hashlib.md5(pack.encode()).hexdigest()
And a get_ha1 function (https://github.com/cyraxjoe/maki/blob/master/maki/db/utils.py#L63):
def get_user_ha1(realm, username):
# realm is not used the stored hash already used it.
user = db.ses.query(db.models.User).filter_by(name=username).scalar()
if user is not None:
return user.ha1
The important part is that a ha1 is only an md5 hash of "user:real:password", you can implement that in a lot of different places.
In python xmpp module, I'm able to retrieve the nickname of any contacts as follows:
self.connection.auth(userJid.getNode(), self.password)
self.roster = self.connection.getRoster()
name = self.roster.getName(buddyJid)
..where buddyJid is of the form user#gmail.com.
Now, I need to retrieve the nickname of the user who authenticates the connection (userJid). I cannot find the name using the above method.
Which method can I use retrieve the name of the current user?
This information is not in the roster. You will need to query the clients individually and get their vCard by sending this IQ :
<iq from='stpeter#jabber.org/roundabout'
id='v1'
type='get'>
<vCard xmlns='vcard-temp'/>
</iq>
Thank you nicholas_o, this is a sample function I put together based your suggestion. (The XML logic isn't ideal, but it was sufficient for the simple task I needed this for)
def vcard(disp, jid):
msg = xmpp.protocol.Iq()
msg.setType('get')
msg.setTo(jid)
qc = msg.addChild('vCard')
qc.setAttr('xmlns', 'vcard-temp')
rep = disp.SendAndWaitForResponse(msg)
# to see what other fields are available in the XML output:
# print rep
userid=fname=lname=title=department=region=None
for i in rep.getChildren():
for j in i.getChildren():
if j.getName() == "TITLE":
title = j.getData().encode('utf-8')
for k in j.getChildren():
if k.getName() == "GIVEN":
fname = k.getData().encode('utf-8')
if k.getName() == "FAMILY":
lname = k.getData().encode('utf-8')
if k.getName() == "ORGUNIT":
department = k.getData().encode('utf-8')
if k.getName() == "REGION":
region = k.getData().encode('utf-8')
return fname, lname, title, department, region