I have Airflow successfully setup to work with my AD/LDAP when everyone is a superuser and data profiler. But now I want to define an admin group and a regular user group. I have the following settings,
Working Config Where Everyone Is An Admin:
# set a connection without encryption: uri = ldap://<your.ldap.server>:<port>
uri = ldap://123.456.789:123
user_filter = objectClass=*
# in case of Active Directory you would use: user_name_attr = sAMAccountName
user_name_attr = sAMAccountName
# group_member_attr should be set accordingly with *_filter
# eg :
# group_member_attr = groupMembership
# superuser_filter = groupMembership=CN=airflow-super-users...
group_member_attr = member
group_name_attr = CN
group_filter = objectclass=group
bind_user = CN=blah,OU=foo,DC=us,DC=bar,DC=com
bind_password = yahoo
basedn = DC=us,DC=bar,DC=com
# Set search_scope to one of them: BASE, LEVEL , SUBTREE
# Set search_scope to SUBTREE if using Active Directory, and not specifying an Organizational Unit
search_scope = SUBTREE
New Config With Specific Admin Group Set:
# set a connection without encryption: uri = ldap://<your.ldap.server>:<port>
uri = ldap://123.456.789:123
user_filter = objectclass=*
# in case of Active Directory you would use: user_name_attr = sAMAccountName
user_name_attr = sAMAccountName
# group_member_attr should be set accordingly with *_filter
# eg :
# group_member_attr = groupMembership
# superuser_filter = groupMembership=CN=airflow-super-users...
superuser_filter = memberOf=CN=MyAdminGroupName,OU=foo,DC=us,DC=bar,DC=com
data_profiler_filter = memberOf=CN=MyAdminGroupName,OU=foo,DC=us,DC=bar,DC=com
group_member_attr = member
group_name_attr = CN
group_filter = objectclass=group
bind_user = CN=blah,OU=foo,DC=us,DC=bar,DC=com
bind_password = yahoo
basedn = DC=us,DC=bar,DC=com
# Set search_scope to one of them: BASE, LEVEL , SUBTREE
# Set search_scope to SUBTREE if using Active Directory, and not specifying an Organizational Unit
search_scope = SUBTREE
Resource: https://airflow.apache.org/security.html
With this new configuration I am able to log into the Airflow UI but I'm no longer able to view the Admin tab. I am 100% sure I am a part of the admin group MyAdminGroupName. I'm also not sure where to put my regular user group name MyRegularGroupName.
Can someone please guide me on how to configure my Admin group (MyAdminGroupName) and my regular user group (MyRegularGroupName)?
I also struggled with setting up LDAP in Airflow.
First of: What is group_filter = objectclass=group in your config? I cannot find it specified in the docs or in the ldap_auth.py.
Then, your group_member_attr is set to member, but in the filter queries you're using memberOf, so I guess that memberOf should be your group_member_attr (it usually is, if your using Active Directory).
Your superuser_filter and data_profiler_filter look good to me.
To whoever reads this: the filters are inserted into a string like this in the code: (&(<FILTER_HERE>)), so if you want to build a more sophisticated filter, take this into account.
E.g. I wanted to only give three users superuser rights (using environment variables for config):
AIRFLOW__LDAP__SUPERUSER_FILTER: "&(objectCategory=Person)(|(sAMAccountName=user1)(sAMAccountName=user2)(sAMAccountName=user3))(memberOf=CN=MyDepartment,OU=Departments,OU=UserGroup,DC=MyCompany,DC=local)"
Regarding your question about MyRegularUserGroup: I guess, you can specify the user filter to filter for persons in your regular user group and then specify the admin group for superuser and data profiler. But that would only work if the admin group is a subset of the regular user group.
Hope that helps.
Related
I am trying to configure a SAML non-gallery Enterprise app and am having a problem with configuring the claims. To summarize the current claims, objectGUID is being sent as the name identifier. They send extensionAttribute6 as OrgID. GivenName, sn and e-mail address are sent without any changes.
AD Connect has been configured to sync objectGUID and extensionAttribute6 to AAD, and those attributes are available in the SSO configuration blade for the Enterprise App.
My questions are:
1) Does a Namespace need to be defined for the objectGUID, or can it just be selected from the source attribute in the claim and name identifier?
2) How to transform the extensionAttribute6 to be OrgID?
The current claim rules in ADFS are:
1)
c:[Type ==
"http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname",
Issuer == "AD AUTHORITY"]
=> issue(store = "Active Directory", types = ("GUID"), query = ";objectGuid;{0}", param = c.Value);
2)
c:[Type == "GUID"]
=> issue(Type = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
Issuer = c.Issuer, OriginalIssuer = c.OriginalIssuer, Value = c.Value,
ValueType = c.ValueType,
Properties["http://schemas.xmlsoap.org/ws/2005/05/identity/claimproperties/format"]
= "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified");
3)
c:[Type ==
"http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname",
Issuer == "AD AUTHORITY"]
=> issue(store = "Active Directory", types = ("givenName", "sn", "OrgID", "mail"), query =
";givenName,sn,extensionAttribute6,mail;{0}", param = c.Value);
You do not have to specify the namespace when you are mapping the User.ObjectID as the NameID claim. Also note that do not select any NameID Format and keep that as Default. Azure AD does support the pairwise Name Identifier. That means if the Service Provider is sending the NameID Format then the app will get that from Azure AD based on the Format specified in the SAML Request.
If you are trying to map the User.ObjectID claim as another claim then you can add the Namespace value as needed but it based on how the app need that back.
About transforming OrgID I Am not sure what you want to send. You can define that as a claim name and then select the ExtensionAttribute 6 as value and if the value exist for the user then you should see that in the SAML Response.
I hope this helps.
Thanks and Regards,
Jeevan Desarda
I am trying to send a few groups memberships as a claim on ADFS3 to a cloud relying party.
I am using a Microsoft article (Below) to Create a Rule to Send Group Membership as a Claim. the MS article says under Claim rule template, select Send Group Membership as Claim and then after giving a name to the rule and selecting a group from the Active Directory, it does not specify what to choose for "Outgoing Claim type" and what to enter in "Outgoing Claim Value" box.
Does anyone have any suggestions?
https://learn.microsoft.com/en-us/windows-server/identity/ad-fs/operations/create-a-rule-to-send-group-membership-as-a-claim
Thanks,
Majid
The following custom rules worked.
#RuleName = "Add Group Claims"
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname",
Issuer == "AD AUTHORITY"]
=> add(store = "Active Directory", types = ("http://test.com/phase1"), query =
";memberOf;{0}", param = c.Value);
#RuleName = "Edit Group"
c:[Type == "http://test.com/phase1"]
=> add(Type = "http://test.com/phase2", Value = RegExReplace(c.Value, ",[^\n]*", ""));
#RuleName = "Remove CN from Group"
c:[Type == "http://test.com/phase2"]
=> add(Type = "http://schemas.xmlsoap.org/claims/Group", Value = RegExReplace(c.Value,
"^CN=", ""));
#RuleName = "Send Only Groups Containing ADFS"
c:[Type == "http://schemas.xmlsoap.org/claims/Group", Value =~ "(?i)Groups-prefix"]
Assume you wanted to pass AD group "isAdmin".
The first part is selecting that group in AD.
Then decide on a group name (e.g. http://company.com/Admin) and then a group value (e.g. isAdmin).
Then if the user is a member of that group, you will get a claim:
http://company.com/Admin/isAdmin
So I have a SID of a FSP: S-1-5-21-2127521184-1604012920-1887927527-72713.
Translation worked in powershell but I would like to do the ldap query by myself, like here but have a little trouble with proper SID conversion.
Could you help me with query that give me a corresponding account name based on SID ?
You can bind directly to an object using the SID using LDAP://<SID=S-1-5-21-2127521184-1604012920-1887927527-72713>. Then get the username after that.
In PowerShell, it would look something like:
$account = [adsi]"LDAP://<SID=S-1-5-21-2127521184-1604012920-1887927527-72713>"
$username = $account.Properties["sAMAccountName"]
If the computer you run this from is on a different domain than the account, you may have to specify the domain:
$account = [adsi]"LDAP://domain.com/<SID=S-1-5-21-2127521184-1604012920-1887927527-72713>"
If you have Java available you can query the ObjectSID directly.
We show an Example with code
I am able to use an ldapsearch like:
ldapsearch -h example.net -D "EXAMPLE\myID" -b "OU=Accounts,DC=EXAMPLE,DC=NET" -s sub -a search -z 1000 "(ObjectSID=S-1-5-21-333675845-1535931152-1111140340-22234762)" "objectClass"
And get results.
# extended LDIF
# LDAPv3
# base <OU=Accounts,DC=EXAMPLE,DC=NET> with scope subtree
# filter: (ObjectSID=S-1-5-21-333675845-1535931152-1111140340-22234762)
# requesting: objectClass samAccountName
#
# userid, sales, Accounts, EXAMPLE.NET
dn: CN=userid,OU=sales,OU=Accounts,DC=EXAMPLE,DC=NET
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
sAMAccountName: userid
# search result
search: 2
result: 0 Success
# numResponses: 2
# numEntries: 1
This search is done from a Linux machine and done by a user that is not represented by the ObjectSID.
This query works fine:
(&(objectCategory=user)(objectClass=user)(memberOf=*) )
but any ever, with selection of group - with no result
(&(objectCategory=user)(objectClass=user)(memberOf=myGroup) )
(&(objectCategory=user)(objectClass=user)(memberOf=CN=myGroup) )
(&(objectCategory=user)(objectClass=user)(memberOf:1.2.840.113556.1.4.1941:=CN=myGroup) )
It's because memberof attribute stores dn values, so you have to provide a dn in the filter.
And by dn I mean a full dn all the way to the root of the ldap directory tree.
If your group : CN=myGroup is in the branch ou=groups and the baseDn of your directory is dc=local,dc=com, you have to specify a filter like :
memberof=CN=myGroup,ou=groups,dc=local,dc=com
The normal way to query a directory for users is (&(objectClass=user)(objectCategory=person)). The normal way to query for deleted objects is to add (isDeleted=TRUE).
However, the objectCategory attribute does not exist on tombstone objects, so a query for (&(objectClass=user)(objectCategory=person)(isDeleted=TRUE)) will get you nothing.
If you remove the (objectCategory=person) part, you'll get computers too, as they inherit from user.
Is it possible to retrieve only deleted users?
If not, is it possible to tell from the returned tombstone object if it's a user or not?
Try an LDAP filter like:
(&(isDeleted=TRUE)(userAccountControl:1.2.840.113556.1.4.803:=512))
This should retrieve most deleted user type entries.
python3 code
import ldap
from ldap.controls.simple import ValueLessRequestControl
...
base =
scope = ldap.SCOPE_SUBTREE
filterstr = '(&(objectClass=user)(isDeleted=TRUE))'
attrlist =
result_set = []
ct = ldap.controls.simple.ValueLessRequestControl('1.2.840.113556.1.4.417', True)
result_id = l.search_ext(base, scope, filterstr, attrlist, serverctrls=[ct, ])
for i in range(0, 100):
result_type, result_data = l.result(result_id, 0)
if result_type == ldap.RES_SEARCH_ENTRY:
result_set.append(result_data)
else:
break
...