mirror of
https://github.com/ansible/awx.git
synced 2026-02-16 02:30:01 -03:30
implement multiple ldap servers
This commit is contained in:
163
awx/main/tests/data/ldap_ansible.ldif
Normal file
163
awx/main/tests/data/ldap_ansible.ldif
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
|
||||||
|
dn: dc=ansible,dc=com
|
||||||
|
dc: ansible
|
||||||
|
description: My wonderful company as much text as you want to place
|
||||||
|
in this line up to 32K continuation data for the line above must
|
||||||
|
have <CR> or <CR><LF> i.e. ENTER work
|
||||||
|
on both Windows and *nix system - new line MUST begin with ONE SPACE
|
||||||
|
objectClass: dcObject
|
||||||
|
objectClass: organization
|
||||||
|
o: ansible.com
|
||||||
|
|
||||||
|
# groups
|
||||||
|
|
||||||
|
dn: ou=groups,dc=ansible,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: organizationalUnit
|
||||||
|
ou: groups
|
||||||
|
|
||||||
|
# group: Superusers
|
||||||
|
|
||||||
|
dn: cn=superusers,ou=groups,dc=ansible,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: groupOfNames
|
||||||
|
cn: superusers
|
||||||
|
member: cn=super_user1,ou=people,dc=ansible,dc=com
|
||||||
|
|
||||||
|
# group: Engineering
|
||||||
|
|
||||||
|
dn: cn=engineering,ou=groups,dc=ansible,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: groupOfNames
|
||||||
|
cn: engineering
|
||||||
|
member: cn=eng_admin1,ou=people,dc=ansible,dc=com
|
||||||
|
member: cn=eng_user1,ou=people,dc=ansible,dc=com
|
||||||
|
member: cn=eng_user2,ou=people,dc=ansible,dc=com
|
||||||
|
|
||||||
|
dn: cn=engineering_admins,ou=groups,dc=ansible,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: groupOfNames
|
||||||
|
cn: engineering_admins
|
||||||
|
member: cn=eng_admin1,ou=people,dc=ansible,dc=com
|
||||||
|
|
||||||
|
# group: Sales
|
||||||
|
|
||||||
|
dn: cn=sales,ou=groups,dc=ansible,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: groupOfNames
|
||||||
|
cn: sales
|
||||||
|
member: cn=sales_user1,ou=people,dc=ansible,dc=com
|
||||||
|
member: cn=sales_user2,ou=people,dc=ansible,dc=com
|
||||||
|
|
||||||
|
# group: IT
|
||||||
|
|
||||||
|
dn: cn=it,ou=groups,dc=ansible,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: groupOfNames
|
||||||
|
cn: it
|
||||||
|
member: cn=it_user1,ou=people,dc=ansible,dc=com
|
||||||
|
member: cn=it_user2,ou=people,dc=ansible,dc=com
|
||||||
|
|
||||||
|
|
||||||
|
# users
|
||||||
|
|
||||||
|
dn: ou=people,dc=ansible,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: organizationalUnit
|
||||||
|
ou: people
|
||||||
|
|
||||||
|
# users - superusers
|
||||||
|
|
||||||
|
dn: cn=super_user1,ou=people,dc=ansible,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: person
|
||||||
|
objectClass: organizationalPerson
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
cn: super_user1
|
||||||
|
sn: User 1
|
||||||
|
givenName: Super
|
||||||
|
mail: super_user1@ansible.com
|
||||||
|
userPassword: password
|
||||||
|
|
||||||
|
# users - engineering
|
||||||
|
|
||||||
|
dn: cn=eng_user1,ou=people,dc=ansible,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: person
|
||||||
|
objectClass: organizationalPerson
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
cn: eng_user1
|
||||||
|
sn: User 1
|
||||||
|
givenName: Engineering
|
||||||
|
mail: eng_user1@ansible.com
|
||||||
|
userPassword: password
|
||||||
|
|
||||||
|
dn: cn=eng_user2,ou=people,dc=ansible,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: person
|
||||||
|
objectClass: organizationalPerson
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
cn: eng_user2
|
||||||
|
sn: User 2
|
||||||
|
givenName: Engineering
|
||||||
|
mail: eng_user2@ansible.com
|
||||||
|
userPassword: password
|
||||||
|
|
||||||
|
dn: cn=eng_admin1,ou=people,dc=ansible,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: person
|
||||||
|
objectClass: organizationalPerson
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
cn: eng_admin1
|
||||||
|
sn: Admin 1
|
||||||
|
givenName: Engineering
|
||||||
|
mail: eng_admin1@ansible.com
|
||||||
|
userPassword: password
|
||||||
|
|
||||||
|
# users - IT
|
||||||
|
|
||||||
|
dn: cn=it_user1,ou=people,dc=ansible,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: person
|
||||||
|
objectClass: organizationalPerson
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
cn: it_user1
|
||||||
|
sn: Technology User 1
|
||||||
|
givenName: Information
|
||||||
|
mail: it_user1@ansible.com
|
||||||
|
userPassword: password
|
||||||
|
|
||||||
|
dn: cn=it_user2,ou=people,dc=ansible,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: person
|
||||||
|
objectClass: organizationalPerson
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
cn: it_user2
|
||||||
|
sn: Technology User 2
|
||||||
|
givenName: Information
|
||||||
|
mail: it_user2@ansible.com
|
||||||
|
userPassword: password
|
||||||
|
|
||||||
|
# users - Sales
|
||||||
|
|
||||||
|
dn: cn=sales_user1,ou=people,dc=ansible,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: person
|
||||||
|
objectClass: organizationalPerson
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
cn: sales_user1
|
||||||
|
sn: Person 1
|
||||||
|
givenName: Sales
|
||||||
|
mail: sales_user1@ansible.com
|
||||||
|
userPassword: password
|
||||||
|
|
||||||
|
dn: cn=sales_user2,ou=people,dc=ansible,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: person
|
||||||
|
objectClass: organizationalPerson
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
cn: sales_user2
|
||||||
|
sn: Person 2
|
||||||
|
givenName: Sales
|
||||||
|
mail: sales_user2@ansible.com
|
||||||
|
userPassword: password
|
||||||
78
awx/main/tests/data/ldap_example.ldif
Normal file
78
awx/main/tests/data/ldap_example.ldif
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
|
||||||
|
dn: dc=example,dc=com
|
||||||
|
dc: example
|
||||||
|
description: My wonderful company as much text as you want to place
|
||||||
|
in this line up to 32K continuation data for the line above must
|
||||||
|
have <CR> or <CR><LF> i.e. ENTER work
|
||||||
|
on both Windows and *nix system - new line MUST begin with ONE SPACE
|
||||||
|
objectClass: dcObject
|
||||||
|
objectClass: organization
|
||||||
|
o: example.com
|
||||||
|
|
||||||
|
# groups
|
||||||
|
|
||||||
|
dn: ou=groups,dc=example,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: organizationalUnit
|
||||||
|
ou: groups
|
||||||
|
|
||||||
|
# group: Superusers
|
||||||
|
|
||||||
|
dn: cn=superusers,ou=groups,dc=example,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: groupOfNames
|
||||||
|
cn: superusers
|
||||||
|
member: cn=super_user1,ou=people,dc=example,dc=com
|
||||||
|
|
||||||
|
# group: Sales
|
||||||
|
|
||||||
|
dn: cn=sales,ou=groups,dc=example,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: groupOfNames
|
||||||
|
cn: sales
|
||||||
|
member: cn=sales_user1,ou=people,dc=example,dc=com
|
||||||
|
member: cn=sales_user2,ou=people,dc=example,dc=com
|
||||||
|
|
||||||
|
# users
|
||||||
|
|
||||||
|
dn: ou=people,dc=example,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: organizationalUnit
|
||||||
|
ou: people
|
||||||
|
|
||||||
|
# users - superusers
|
||||||
|
|
||||||
|
dn: cn=super_user1,ou=people,dc=example,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: person
|
||||||
|
objectClass: organizationalPerson
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
cn: super_user1
|
||||||
|
sn: User 1
|
||||||
|
givenName: Super
|
||||||
|
mail: super_user1@example.com
|
||||||
|
userPassword: password
|
||||||
|
|
||||||
|
# users - Sales
|
||||||
|
|
||||||
|
dn: cn=sales_user1,ou=people,dc=example,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: person
|
||||||
|
objectClass: organizationalPerson
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
cn: sales_user1
|
||||||
|
sn: Person 1
|
||||||
|
givenName: Sales
|
||||||
|
mail: sales_user1@example.com
|
||||||
|
userPassword: password
|
||||||
|
|
||||||
|
dn: cn=sales_user2,ou=people,dc=example,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: person
|
||||||
|
objectClass: organizationalPerson
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
cn: sales_user2
|
||||||
|
sn: Person 2
|
||||||
|
givenName: Sales
|
||||||
|
mail: sales_user2@example.com
|
||||||
|
userPassword: password
|
||||||
163
awx/main/tests/data/ldap_redhat.ldif
Normal file
163
awx/main/tests/data/ldap_redhat.ldif
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
|
||||||
|
dn: dc=redhat,dc=com
|
||||||
|
dc: redhat
|
||||||
|
description: My wonderful company as much text as you want to place
|
||||||
|
in this line up to 32K continuation data for the line above must
|
||||||
|
have <CR> or <CR><LF> i.e. ENTER work
|
||||||
|
on both Windows and *nix system - new line MUST begin with ONE SPACE
|
||||||
|
objectClass: dcObject
|
||||||
|
objectClass: organization
|
||||||
|
o: redhat.com
|
||||||
|
|
||||||
|
# groups
|
||||||
|
|
||||||
|
dn: ou=groups,dc=redhat,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: organizationalUnit
|
||||||
|
ou: groups
|
||||||
|
|
||||||
|
# group: Superusers
|
||||||
|
|
||||||
|
dn: cn=superusers,ou=groups,dc=redhat,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: groupOfNames
|
||||||
|
cn: superusers
|
||||||
|
member: cn=super_user1,ou=people,dc=redhat,dc=com
|
||||||
|
|
||||||
|
# group: Engineering
|
||||||
|
|
||||||
|
dn: cn=engineering,ou=groups,dc=redhat,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: groupOfNames
|
||||||
|
cn: engineering
|
||||||
|
member: cn=eng_admin1,ou=people,dc=redhat,dc=com
|
||||||
|
member: cn=eng_user1,ou=people,dc=redhat,dc=com
|
||||||
|
member: cn=eng_user2,ou=people,dc=redhat,dc=com
|
||||||
|
|
||||||
|
dn: cn=engineering_admins,ou=groups,dc=redhat,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: groupOfNames
|
||||||
|
cn: engineering_admins
|
||||||
|
member: cn=eng_admin1,ou=people,dc=redhat,dc=com
|
||||||
|
|
||||||
|
# group: Sales
|
||||||
|
|
||||||
|
dn: cn=sales,ou=groups,dc=redhat,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: groupOfNames
|
||||||
|
cn: sales
|
||||||
|
member: cn=sales_user1,ou=people,dc=redhat,dc=com
|
||||||
|
member: cn=sales_user2,ou=people,dc=redhat,dc=com
|
||||||
|
|
||||||
|
# group: IT
|
||||||
|
|
||||||
|
dn: cn=it,ou=groups,dc=redhat,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: groupOfNames
|
||||||
|
cn: it
|
||||||
|
member: cn=it_user1,ou=people,dc=redhat,dc=com
|
||||||
|
member: cn=it_user2,ou=people,dc=redhat,dc=com
|
||||||
|
|
||||||
|
|
||||||
|
# users
|
||||||
|
|
||||||
|
dn: ou=people,dc=redhat,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: organizationalUnit
|
||||||
|
ou: people
|
||||||
|
|
||||||
|
# users - superusers
|
||||||
|
|
||||||
|
dn: cn=super_user1,ou=people,dc=redhat,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: person
|
||||||
|
objectClass: organizationalPerson
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
cn: super_user1
|
||||||
|
sn: User 1
|
||||||
|
givenName: Super
|
||||||
|
mail: super_user1@redhat.com
|
||||||
|
userPassword: password
|
||||||
|
|
||||||
|
# users - engineering
|
||||||
|
|
||||||
|
dn: cn=eng_user1,ou=people,dc=redhat,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: person
|
||||||
|
objectClass: organizationalPerson
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
cn: eng_user1
|
||||||
|
sn: User 1
|
||||||
|
givenName: Engineering
|
||||||
|
mail: eng_user1@redhat.com
|
||||||
|
userPassword: password
|
||||||
|
|
||||||
|
dn: cn=eng_user2,ou=people,dc=redhat,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: person
|
||||||
|
objectClass: organizationalPerson
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
cn: eng_user2
|
||||||
|
sn: User 2
|
||||||
|
givenName: Engineering
|
||||||
|
mail: eng_user2@redhat.com
|
||||||
|
userPassword: password
|
||||||
|
|
||||||
|
dn: cn=eng_admin1,ou=people,dc=redhat,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: person
|
||||||
|
objectClass: organizationalPerson
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
cn: eng_admin1
|
||||||
|
sn: Admin 1
|
||||||
|
givenName: Engineering
|
||||||
|
mail: eng_admin1@redhat.com
|
||||||
|
userPassword: password
|
||||||
|
|
||||||
|
# users - IT
|
||||||
|
|
||||||
|
dn: cn=it_user1,ou=people,dc=redhat,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: person
|
||||||
|
objectClass: organizationalPerson
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
cn: it_user1
|
||||||
|
sn: Technology User 1
|
||||||
|
givenName: Information
|
||||||
|
mail: it_user1@redhat.com
|
||||||
|
userPassword: password
|
||||||
|
|
||||||
|
dn: cn=it_user2,ou=people,dc=redhat,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: person
|
||||||
|
objectClass: organizationalPerson
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
cn: it_user2
|
||||||
|
sn: Technology User 2
|
||||||
|
givenName: Information
|
||||||
|
mail: it_user2@redhat.com
|
||||||
|
userPassword: password
|
||||||
|
|
||||||
|
# users - Sales
|
||||||
|
|
||||||
|
dn: cn=sales_user1,ou=people,dc=redhat,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: person
|
||||||
|
objectClass: organizationalPerson
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
cn: sales_user1
|
||||||
|
sn: Person 1
|
||||||
|
givenName: Sales
|
||||||
|
mail: sales_user1@redhat.com
|
||||||
|
userPassword: password
|
||||||
|
|
||||||
|
dn: cn=sales_user2,ou=people,dc=redhat,dc=com
|
||||||
|
objectClass: top
|
||||||
|
objectClass: person
|
||||||
|
objectClass: organizationalPerson
|
||||||
|
objectClass: inetOrgPerson
|
||||||
|
cn: sales_user2
|
||||||
|
sn: Person 2
|
||||||
|
givenName: Sales
|
||||||
|
mail: sales_user2@redhat.com
|
||||||
|
userPassword: password
|
||||||
@@ -73,7 +73,8 @@ def user():
|
|||||||
try:
|
try:
|
||||||
user = User.objects.get(username=name)
|
user = User.objects.get(username=name)
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
user = User(username=name, is_superuser=is_superuser, password=name)
|
user = User(username=name, is_superuser=is_superuser)
|
||||||
|
user.set_password(name)
|
||||||
user.save()
|
user.save()
|
||||||
return user
|
return user
|
||||||
return u
|
return u
|
||||||
|
|||||||
130
awx/main/tests/functional/test_ldap.py
Normal file
130
awx/main/tests/functional/test_ldap.py
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
|
||||||
|
import ldap
|
||||||
|
import ldif
|
||||||
|
import pytest
|
||||||
|
import os
|
||||||
|
from mockldap import MockLdap
|
||||||
|
|
||||||
|
from awx.api.versioning import reverse
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def ldap_generator():
|
||||||
|
def fn(fname, host='localhost'):
|
||||||
|
|
||||||
|
fh = open(os.path.join(os.path.dirname(os.path.realpath(__file__)), fname), 'rb')
|
||||||
|
ctrl = ldif.LDIFRecordList(fh)
|
||||||
|
ctrl.parse()
|
||||||
|
|
||||||
|
directory = dict(ctrl.all_records)
|
||||||
|
|
||||||
|
mockldap = MockLdap(directory)
|
||||||
|
|
||||||
|
mockldap.start()
|
||||||
|
mockldap['ldap://{}/'.format(host)]
|
||||||
|
|
||||||
|
conn = ldap.initialize('ldap://{}/'.format(host))
|
||||||
|
|
||||||
|
return conn
|
||||||
|
#mockldap.stop()
|
||||||
|
|
||||||
|
return fn
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def ldap_settings_generator():
|
||||||
|
def fn(prefix='', dc='ansible', host='ldap.ansible.com'):
|
||||||
|
prefix = '_{}'.format(prefix) if prefix else ''
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'AUTH_LDAP_SERVER_URI': 'ldap://{}'.format(host),
|
||||||
|
'AUTH_LDAP_BIND_DN': 'cn=eng_user1,ou=people,dc={},dc=com'.format(dc),
|
||||||
|
'AUTH_LDAP_BIND_PASSWORD': 'password',
|
||||||
|
"AUTH_LDAP_USER_SEARCH": [
|
||||||
|
"ou=people,dc={},dc=com".format(dc),
|
||||||
|
"SCOPE_SUBTREE",
|
||||||
|
"(cn=%(user)s)"
|
||||||
|
],
|
||||||
|
"AUTH_LDAP_TEAM_MAP": {
|
||||||
|
"LDAP Sales": {
|
||||||
|
"organization": "LDAP Organization",
|
||||||
|
"users": "cn=sales,ou=groups,dc={},dc=com".format(dc),
|
||||||
|
"remove": True
|
||||||
|
},
|
||||||
|
"LDAP IT": {
|
||||||
|
"organization": "LDAP Organization",
|
||||||
|
"users": "cn=it,ou=groups,dc={},dc=com".format(dc),
|
||||||
|
"remove": True
|
||||||
|
},
|
||||||
|
"LDAP Engineering": {
|
||||||
|
"organization": "LDAP Organization",
|
||||||
|
"users": "cn=engineering,ou=groups,dc={},dc=com".format(dc),
|
||||||
|
"remove": True
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AUTH_LDAP_REQUIRE_GROUP": None,
|
||||||
|
"AUTH_LDAP_USER_ATTR_MAP": {
|
||||||
|
"first_name": "givenName",
|
||||||
|
"last_name": "sn",
|
||||||
|
"email": "mail"
|
||||||
|
},
|
||||||
|
"AUTH_LDAP_GROUP_SEARCH": [
|
||||||
|
"dc={},dc=com".format(dc),
|
||||||
|
"SCOPE_SUBTREE",
|
||||||
|
"(objectClass=groupOfNames)"
|
||||||
|
],
|
||||||
|
"AUTH_LDAP_USER_FLAGS_BY_GROUP": {
|
||||||
|
"is_superuser": "cn=superusers,ou=groups,dc={},dc=com".format(dc)
|
||||||
|
},
|
||||||
|
"AUTH_LDAP_ORGANIZATION_MAP": {
|
||||||
|
"LDAP Organization": {
|
||||||
|
"admins": "cn=engineering_admins,ou=groups,dc={},dc=com".format(dc),
|
||||||
|
"remove_admins": False,
|
||||||
|
"users": [
|
||||||
|
"cn=engineering,ou=groups,dc={},dc=com".format(dc),
|
||||||
|
"cn=sales,ou=groups,dc={},dc=com".format(dc),
|
||||||
|
"cn=it,ou=groups,dc={},dc=com".format(dc)
|
||||||
|
],
|
||||||
|
"remove_users": False
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if prefix:
|
||||||
|
data_new = dict()
|
||||||
|
for k,v in data.iteritems():
|
||||||
|
k_new = k.replace('AUTH_LDAP', 'AUTH_LDAP{}'.format(prefix))
|
||||||
|
data_new[k_new] = v
|
||||||
|
else:
|
||||||
|
data_new = data
|
||||||
|
|
||||||
|
return data_new
|
||||||
|
return fn
|
||||||
|
|
||||||
|
|
||||||
|
# Note: mockldap isn't fully featured. Fancy queries aren't fully baked.
|
||||||
|
# However, objects returned are solid so they should flow through django ldap middleware nicely.
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_login(ldap_generator, patch, post, admin, ldap_settings_generator):
|
||||||
|
auth_url = reverse('api:auth_token_view')
|
||||||
|
ldap_settings_url = reverse('api:setting_singleton_detail', kwargs={'category_slug': 'ldap'})
|
||||||
|
|
||||||
|
# Generate mock ldap servers and init with ldap data
|
||||||
|
ldap_generator("../data/ldap_example.ldif", "ldap.example.com")
|
||||||
|
ldap_generator("../data/ldap_redhat.ldif", "ldap.redhat.com")
|
||||||
|
ldap_generator("../data/ldap_ansible.ldif", "ldap.ansible.com")
|
||||||
|
|
||||||
|
ldap_settings_example = ldap_settings_generator(dc='example')
|
||||||
|
ldap_settings_ansible = ldap_settings_generator(prefix='1', dc='ansible')
|
||||||
|
ldap_settings_redhat = ldap_settings_generator(prefix='2', dc='redhat')
|
||||||
|
|
||||||
|
# eng_user1 exists in ansible and redhat but not example
|
||||||
|
patch(ldap_settings_url, user=admin, data=ldap_settings_example, expect=200)
|
||||||
|
|
||||||
|
post(auth_url, data={'username': 'eng_user1', 'password': 'password'}, expect=400)
|
||||||
|
|
||||||
|
patch(ldap_settings_url, user=admin, data=ldap_settings_ansible, expect=200)
|
||||||
|
patch(ldap_settings_url, user=admin, data=ldap_settings_redhat, expect=200)
|
||||||
|
|
||||||
|
post(auth_url, data={'username': 'eng_user1', 'password': 'password'}, expect=200)
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ def test_model_to_dict_user(alice):
|
|||||||
output_dict = model_to_dict(alice)
|
output_dict = model_to_dict(alice)
|
||||||
assert output_dict['username'] == username
|
assert output_dict['username'] == username
|
||||||
assert output_dict['password'] == 'hidden'
|
assert output_dict['password'] == 'hidden'
|
||||||
assert alice.username == password
|
assert alice.username == username
|
||||||
assert alice.password == password
|
assert alice.password == password
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -305,6 +305,11 @@ REST_FRAMEWORK = {
|
|||||||
|
|
||||||
AUTHENTICATION_BACKENDS = (
|
AUTHENTICATION_BACKENDS = (
|
||||||
'awx.sso.backends.LDAPBackend',
|
'awx.sso.backends.LDAPBackend',
|
||||||
|
'awx.sso.backends.LDAPBackend1',
|
||||||
|
'awx.sso.backends.LDAPBackend2',
|
||||||
|
'awx.sso.backends.LDAPBackend3',
|
||||||
|
'awx.sso.backends.LDAPBackend4',
|
||||||
|
'awx.sso.backends.LDAPBackend5',
|
||||||
'awx.sso.backends.RADIUSBackend',
|
'awx.sso.backends.RADIUSBackend',
|
||||||
'awx.sso.backends.TACACSPlusBackend',
|
'awx.sso.backends.TACACSPlusBackend',
|
||||||
'social_core.backends.google.GoogleOAuth2',
|
'social_core.backends.google.GoogleOAuth2',
|
||||||
|
|||||||
@@ -133,6 +133,26 @@ class LDAPBackend(BaseLDAPBackend):
|
|||||||
return set()
|
return set()
|
||||||
|
|
||||||
|
|
||||||
|
class LDAPBackend1(LDAPBackend):
|
||||||
|
settings_prefix = 'AUTH_LDAP_1_'
|
||||||
|
|
||||||
|
|
||||||
|
class LDAPBackend2(LDAPBackend):
|
||||||
|
settings_prefix = 'AUTH_LDAP_2_'
|
||||||
|
|
||||||
|
|
||||||
|
class LDAPBackend3(LDAPBackend):
|
||||||
|
settings_prefix = 'AUTH_LDAP_3_'
|
||||||
|
|
||||||
|
|
||||||
|
class LDAPBackend4(LDAPBackend):
|
||||||
|
settings_prefix = 'AUTH_LDAP_4_'
|
||||||
|
|
||||||
|
|
||||||
|
class LDAPBackend5(LDAPBackend):
|
||||||
|
settings_prefix = 'AUTH_LDAP_5_'
|
||||||
|
|
||||||
|
|
||||||
def _decorate_enterprise_user(user, provider):
|
def _decorate_enterprise_user(user, provider):
|
||||||
user.set_unusable_password()
|
user.set_unusable_password()
|
||||||
user.save()
|
user.save()
|
||||||
|
|||||||
514
awx/sso/conf.py
514
awx/sso/conf.py
@@ -129,271 +129,283 @@ register(
|
|||||||
# LDAP AUTHENTICATION SETTINGS
|
# LDAP AUTHENTICATION SETTINGS
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
register(
|
|
||||||
'AUTH_LDAP_SERVER_URI',
|
|
||||||
field_class=fields.LDAPServerURIField,
|
|
||||||
allow_blank=True,
|
|
||||||
default='',
|
|
||||||
label=_('LDAP Server URI'),
|
|
||||||
help_text=_('URI to connect to LDAP server, such as "ldap://ldap.example.com:389" '
|
|
||||||
'(non-SSL) or "ldaps://ldap.example.com:636" (SSL). Multiple LDAP '
|
|
||||||
'servers may be specified by separating with spaces or commas. LDAP '
|
|
||||||
'authentication is disabled if this parameter is empty.'),
|
|
||||||
category=_('LDAP'),
|
|
||||||
category_slug='ldap',
|
|
||||||
placeholder='ldaps://ldap.example.com:636',
|
|
||||||
feature_required='ldap',
|
|
||||||
)
|
|
||||||
|
|
||||||
register(
|
def _register_ldap(append=None):
|
||||||
'AUTH_LDAP_BIND_DN',
|
append_str = '_{}'.format(append) if append else ''
|
||||||
field_class=fields.CharField,
|
|
||||||
allow_blank=True,
|
|
||||||
default='',
|
|
||||||
validators=[validate_ldap_bind_dn],
|
|
||||||
label=_('LDAP Bind DN'),
|
|
||||||
help_text=_('DN (Distinguished Name) of user to bind for all search queries. This'
|
|
||||||
' is the system user account we will use to login to query LDAP for other'
|
|
||||||
' user information. Refer to the Ansible Tower documentation for example syntax.'),
|
|
||||||
category=_('LDAP'),
|
|
||||||
category_slug='ldap',
|
|
||||||
feature_required='ldap',
|
|
||||||
)
|
|
||||||
|
|
||||||
register(
|
register(
|
||||||
'AUTH_LDAP_BIND_PASSWORD',
|
'AUTH_LDAP{}_SERVER_URI'.format(append_str),
|
||||||
field_class=fields.CharField,
|
field_class=fields.LDAPServerURIField,
|
||||||
allow_blank=True,
|
allow_blank=True,
|
||||||
default='',
|
default='',
|
||||||
label=_('LDAP Bind Password'),
|
label=_('LDAP Server URI'),
|
||||||
help_text=_('Password used to bind LDAP user account.'),
|
help_text=_('URI to connect to LDAP server, such as "ldap://ldap.example.com:389" '
|
||||||
category=_('LDAP'),
|
'(non-SSL) or "ldaps://ldap.example.com:636" (SSL). Multiple LDAP '
|
||||||
category_slug='ldap',
|
'servers may be specified by separating with spaces or commas. LDAP '
|
||||||
feature_required='ldap',
|
'authentication is disabled if this parameter is empty.'),
|
||||||
encrypted=True,
|
category=_('LDAP'),
|
||||||
)
|
category_slug='ldap',
|
||||||
|
placeholder='ldaps://ldap.example.com:636',
|
||||||
|
feature_required='ldap',
|
||||||
|
)
|
||||||
|
|
||||||
register(
|
register(
|
||||||
'AUTH_LDAP_START_TLS',
|
'AUTH_LDAP{}_BIND_DN'.format(append_str),
|
||||||
field_class=fields.BooleanField,
|
field_class=fields.CharField,
|
||||||
default=False,
|
allow_blank=True,
|
||||||
label=_('LDAP Start TLS'),
|
default='',
|
||||||
help_text=_('Whether to enable TLS when the LDAP connection is not using SSL.'),
|
validators=[validate_ldap_bind_dn],
|
||||||
category=_('LDAP'),
|
label=_('LDAP Bind DN'),
|
||||||
category_slug='ldap',
|
help_text=_('DN (Distinguished Name) of user to bind for all search queries. This'
|
||||||
feature_required='ldap',
|
' is the system user account we will use to login to query LDAP for other'
|
||||||
)
|
' user information. Refer to the Ansible Tower documentation for example syntax.'),
|
||||||
|
category=_('LDAP'),
|
||||||
|
category_slug='ldap',
|
||||||
|
feature_required='ldap',
|
||||||
|
)
|
||||||
|
|
||||||
register(
|
register(
|
||||||
'AUTH_LDAP_CONNECTION_OPTIONS',
|
'AUTH_LDAP{}_BIND_PASSWORD'.format(append_str),
|
||||||
field_class=fields.LDAPConnectionOptionsField,
|
field_class=fields.CharField,
|
||||||
default={'OPT_REFERRALS': 0, 'OPT_NETWORK_TIMEOUT': 30},
|
allow_blank=True,
|
||||||
label=_('LDAP Connection Options'),
|
default='',
|
||||||
help_text=_('Additional options to set for the LDAP connection. LDAP '
|
label=_('LDAP Bind Password'),
|
||||||
'referrals are disabled by default (to prevent certain LDAP '
|
help_text=_('Password used to bind LDAP user account.'),
|
||||||
'queries from hanging with AD). Option names should be strings '
|
category=_('LDAP'),
|
||||||
'(e.g. "OPT_REFERRALS"). Refer to '
|
category_slug='ldap',
|
||||||
'https://www.python-ldap.org/doc/html/ldap.html#options for '
|
feature_required='ldap',
|
||||||
'possible options and values that can be set.'),
|
encrypted=True,
|
||||||
category=_('LDAP'),
|
)
|
||||||
category_slug='ldap',
|
|
||||||
placeholder=collections.OrderedDict([
|
|
||||||
('OPT_REFERRALS', 0),
|
|
||||||
('OPT_NETWORK_TIMEOUT', 30)
|
|
||||||
]),
|
|
||||||
feature_required='ldap',
|
|
||||||
)
|
|
||||||
|
|
||||||
register(
|
register(
|
||||||
'AUTH_LDAP_USER_SEARCH',
|
'AUTH_LDAP{}_START_TLS'.format(append_str),
|
||||||
field_class=fields.LDAPSearchUnionField,
|
field_class=fields.BooleanField,
|
||||||
default=[],
|
default=False,
|
||||||
label=_('LDAP User Search'),
|
label=_('LDAP Start TLS'),
|
||||||
help_text=_('LDAP search query to find users. Any user that matches the given '
|
help_text=_('Whether to enable TLS when the LDAP connection is not using SSL.'),
|
||||||
'pattern will be able to login to Tower. The user should also be '
|
category=_('LDAP'),
|
||||||
'mapped into a Tower organization (as defined in the '
|
category_slug='ldap',
|
||||||
'AUTH_LDAP_ORGANIZATION_MAP setting). If multiple search queries '
|
feature_required='ldap',
|
||||||
'need to be supported use of "LDAPUnion" is possible. See '
|
)
|
||||||
'Tower documentation for details.'),
|
|
||||||
category=_('LDAP'),
|
|
||||||
category_slug='ldap',
|
|
||||||
placeholder=(
|
|
||||||
'OU=Users,DC=example,DC=com',
|
|
||||||
'SCOPE_SUBTREE',
|
|
||||||
'(sAMAccountName=%(user)s)',
|
|
||||||
),
|
|
||||||
feature_required='ldap',
|
|
||||||
)
|
|
||||||
|
|
||||||
register(
|
register(
|
||||||
'AUTH_LDAP_USER_DN_TEMPLATE',
|
'AUTH_LDAP{}_CONNECTION_OPTIONS'.format(append_str),
|
||||||
field_class=fields.LDAPDNWithUserField,
|
field_class=fields.LDAPConnectionOptionsField,
|
||||||
allow_blank=True,
|
default={'OPT_REFERRALS': 0, 'OPT_NETWORK_TIMEOUT': 30},
|
||||||
allow_null=True,
|
label=_('LDAP Connection Options'),
|
||||||
default=None,
|
help_text=_('Additional options to set for the LDAP connection. LDAP '
|
||||||
label=_('LDAP User DN Template'),
|
'referrals are disabled by default (to prevent certain LDAP '
|
||||||
help_text=_('Alternative to user search, if user DNs are all of the same '
|
'queries from hanging with AD). Option names should be strings '
|
||||||
'format. This approach is more efficient for user lookups than '
|
'(e.g. "OPT_REFERRALS"). Refer to '
|
||||||
'searching if it is usable in your organizational environment. If '
|
'https://www.python-ldap.org/doc/html/ldap.html#options for '
|
||||||
'this setting has a value it will be used instead of '
|
'possible options and values that can be set.'),
|
||||||
'AUTH_LDAP_USER_SEARCH.'),
|
category=_('LDAP'),
|
||||||
category=_('LDAP'),
|
category_slug='ldap',
|
||||||
category_slug='ldap',
|
placeholder=collections.OrderedDict([
|
||||||
placeholder='uid=%(user)s,OU=Users,DC=example,DC=com',
|
('OPT_REFERRALS', 0),
|
||||||
feature_required='ldap',
|
('OPT_NETWORK_TIMEOUT', 30)
|
||||||
)
|
]),
|
||||||
|
feature_required='ldap',
|
||||||
|
)
|
||||||
|
|
||||||
register(
|
register(
|
||||||
'AUTH_LDAP_USER_ATTR_MAP',
|
'AUTH_LDAP{}_USER_SEARCH'.format(append_str),
|
||||||
field_class=fields.LDAPUserAttrMapField,
|
field_class=fields.LDAPSearchUnionField,
|
||||||
default={},
|
default=[],
|
||||||
label=_('LDAP User Attribute Map'),
|
label=_('LDAP User Search'),
|
||||||
help_text=_('Mapping of LDAP user schema to Tower API user attributes. The default'
|
help_text=_('LDAP search query to find users. Any user that matches the given '
|
||||||
' setting is valid for ActiveDirectory but users with other LDAP'
|
'pattern will be able to login to Tower. The user should also be '
|
||||||
' configurations may need to change the values. Refer to the Ansible'
|
'mapped into a Tower organization (as defined in the '
|
||||||
' Tower documentation for additonal details.'),
|
'AUTH_LDAP_ORGANIZATION_MAP setting). If multiple search queries '
|
||||||
category=_('LDAP'),
|
'need to be supported use of "LDAPUnion" is possible. See '
|
||||||
category_slug='ldap',
|
'Tower documentation for details.'),
|
||||||
placeholder=collections.OrderedDict([
|
category=_('LDAP'),
|
||||||
('first_name', 'givenName'),
|
category_slug='ldap',
|
||||||
('last_name', 'sn'),
|
placeholder=(
|
||||||
('email', 'mail'),
|
'OU=Users,DC=example,DC=com',
|
||||||
]),
|
'SCOPE_SUBTREE',
|
||||||
feature_required='ldap',
|
'(sAMAccountName=%(user)s)',
|
||||||
)
|
),
|
||||||
|
feature_required='ldap',
|
||||||
|
)
|
||||||
|
|
||||||
register(
|
register(
|
||||||
'AUTH_LDAP_GROUP_SEARCH',
|
'AUTH_LDAP{}_USER_DN_TEMPLATE'.format(append_str),
|
||||||
field_class=fields.LDAPSearchField,
|
field_class=fields.LDAPDNWithUserField,
|
||||||
default=[],
|
allow_blank=True,
|
||||||
label=_('LDAP Group Search'),
|
allow_null=True,
|
||||||
help_text=_('Users are mapped to organizations based on their membership in LDAP'
|
default=None,
|
||||||
' groups. This setting defines the LDAP search query to find groups. '
|
label=_('LDAP User DN Template'),
|
||||||
'Unlike the user search, group search does not support LDAPSearchUnion.'),
|
help_text=_('Alternative to user search, if user DNs are all of the same '
|
||||||
category=_('LDAP'),
|
'format. This approach is more efficient for user lookups than '
|
||||||
category_slug='ldap',
|
'searching if it is usable in your organizational environment. If '
|
||||||
placeholder=(
|
'this setting has a value it will be used instead of '
|
||||||
'DC=example,DC=com',
|
'AUTH_LDAP_USER_SEARCH.'),
|
||||||
'SCOPE_SUBTREE',
|
category=_('LDAP'),
|
||||||
'(objectClass=group)',
|
category_slug='ldap',
|
||||||
),
|
placeholder='uid=%(user)s,OU=Users,DC=example,DC=com',
|
||||||
feature_required='ldap',
|
feature_required='ldap',
|
||||||
)
|
)
|
||||||
|
|
||||||
register(
|
register(
|
||||||
'AUTH_LDAP_GROUP_TYPE',
|
'AUTH_LDAP{}_USER_ATTR_MAP'.format(append_str),
|
||||||
field_class=fields.LDAPGroupTypeField,
|
field_class=fields.LDAPUserAttrMapField,
|
||||||
label=_('LDAP Group Type'),
|
default={},
|
||||||
help_text=_('The group type may need to be changed based on the type of the '
|
label=_('LDAP User Attribute Map'),
|
||||||
'LDAP server. Values are listed at: '
|
help_text=_('Mapping of LDAP user schema to Tower API user attributes. The default'
|
||||||
'https://django-auth-ldap.readthedocs.io/en/stable/groups.html#types-of-groups'),
|
' setting is valid for ActiveDirectory but users with other LDAP'
|
||||||
category=_('LDAP'),
|
' configurations may need to change the values. Refer to the Ansible'
|
||||||
category_slug='ldap',
|
' Tower documentation for additonal details.'),
|
||||||
feature_required='ldap',
|
category=_('LDAP'),
|
||||||
default='MemberDNGroupType',
|
category_slug='ldap',
|
||||||
)
|
placeholder=collections.OrderedDict([
|
||||||
|
('first_name', 'givenName'),
|
||||||
|
('last_name', 'sn'),
|
||||||
|
('email', 'mail'),
|
||||||
|
]),
|
||||||
|
feature_required='ldap',
|
||||||
|
)
|
||||||
|
|
||||||
register(
|
register(
|
||||||
'AUTH_LDAP_REQUIRE_GROUP',
|
'AUTH_LDAP{}_GROUP_SEARCH'.format(append_str),
|
||||||
field_class=fields.LDAPDNField,
|
field_class=fields.LDAPSearchField,
|
||||||
allow_blank=True,
|
default=[],
|
||||||
allow_null=True,
|
label=_('LDAP Group Search'),
|
||||||
default=None,
|
help_text=_('Users are mapped to organizations based on their membership in LDAP'
|
||||||
label=_('LDAP Require Group'),
|
' groups. This setting defines the LDAP search query to find groups. '
|
||||||
help_text=_('Group DN required to login. If specified, user must be a member '
|
'Unlike the user search, group search does not support LDAPSearchUnion.'),
|
||||||
'of this group to login via LDAP. If not set, everyone in LDAP '
|
category=_('LDAP'),
|
||||||
'that matches the user search will be able to login via Tower. '
|
category_slug='ldap',
|
||||||
'Only one require group is supported.'),
|
placeholder=(
|
||||||
category=_('LDAP'),
|
'DC=example,DC=com',
|
||||||
category_slug='ldap',
|
'SCOPE_SUBTREE',
|
||||||
placeholder='CN=Tower Users,OU=Users,DC=example,DC=com',
|
'(objectClass=group)',
|
||||||
feature_required='ldap',
|
),
|
||||||
)
|
feature_required='ldap',
|
||||||
|
)
|
||||||
|
|
||||||
register(
|
register(
|
||||||
'AUTH_LDAP_DENY_GROUP',
|
'AUTH_LDAP{}_GROUP_TYPE'.format(append_str),
|
||||||
field_class=fields.LDAPDNField,
|
field_class=fields.LDAPGroupTypeField,
|
||||||
allow_blank=True,
|
label=_('LDAP Group Type'),
|
||||||
allow_null=True,
|
help_text=_('The group type may need to be changed based on the type of the '
|
||||||
default=None,
|
'LDAP server. Values are listed at: '
|
||||||
label=_('LDAP Deny Group'),
|
'https://django-auth-ldap.readthedocs.io/en/stable/groups.html#types-of-groups'),
|
||||||
help_text=_('Group DN denied from login. If specified, user will not be '
|
category=_('LDAP'),
|
||||||
'allowed to login if a member of this group. Only one deny group '
|
category_slug='ldap',
|
||||||
'is supported.'),
|
feature_required='ldap',
|
||||||
category=_('LDAP'),
|
default='MemberDNGroupType',
|
||||||
category_slug='ldap',
|
)
|
||||||
placeholder='CN=Disabled Users,OU=Users,DC=example,DC=com',
|
|
||||||
feature_required='ldap',
|
|
||||||
)
|
|
||||||
|
|
||||||
register(
|
register(
|
||||||
'AUTH_LDAP_USER_FLAGS_BY_GROUP',
|
'AUTH_LDAP{}_REQUIRE_GROUP'.format(append_str),
|
||||||
field_class=fields.LDAPUserFlagsField,
|
field_class=fields.LDAPDNField,
|
||||||
default={},
|
allow_blank=True,
|
||||||
label=_('LDAP User Flags By Group'),
|
allow_null=True,
|
||||||
help_text=_('Retrieve users from a given group. At this time, superuser and system'
|
default=None,
|
||||||
' auditors are the only groups supported. Refer to the Ansible Tower'
|
label=_('LDAP Require Group'),
|
||||||
' documentation for more detail.'),
|
help_text=_('Group DN required to login. If specified, user must be a member '
|
||||||
category=_('LDAP'),
|
'of this group to login via LDAP. If not set, everyone in LDAP '
|
||||||
category_slug='ldap',
|
'that matches the user search will be able to login via Tower. '
|
||||||
placeholder=collections.OrderedDict([
|
'Only one require group is supported.'),
|
||||||
('is_superuser', 'CN=Domain Admins,CN=Users,DC=example,DC=com'),
|
category=_('LDAP'),
|
||||||
('is_system_auditor', 'CN=Domain Auditors,CN=Users,DC=example,DC=com'),
|
category_slug='ldap',
|
||||||
]),
|
placeholder='CN=Tower Users,OU=Users,DC=example,DC=com',
|
||||||
feature_required='ldap',
|
feature_required='ldap',
|
||||||
)
|
)
|
||||||
|
|
||||||
register(
|
register(
|
||||||
'AUTH_LDAP_ORGANIZATION_MAP',
|
'AUTH_LDAP{}_DENY_GROUP'.format(append_str),
|
||||||
field_class=fields.LDAPOrganizationMapField,
|
field_class=fields.LDAPDNField,
|
||||||
default={},
|
allow_blank=True,
|
||||||
label=_('LDAP Organization Map'),
|
allow_null=True,
|
||||||
help_text=_('Mapping between organization admins/users and LDAP groups. This '
|
default=None,
|
||||||
'controls which users are placed into which Tower organizations '
|
label=_('LDAP Deny Group'),
|
||||||
'relative to their LDAP group memberships. Configuration details '
|
help_text=_('Group DN denied from login. If specified, user will not be '
|
||||||
'are available in the Ansible Tower documentation.'),
|
'allowed to login if a member of this group. Only one deny group '
|
||||||
category=_('LDAP'),
|
'is supported.'),
|
||||||
category_slug='ldap',
|
category=_('LDAP'),
|
||||||
placeholder=collections.OrderedDict([
|
category_slug='ldap',
|
||||||
('Test Org', collections.OrderedDict([
|
placeholder='CN=Disabled Users,OU=Users,DC=example,DC=com',
|
||||||
('admins', 'CN=Domain Admins,CN=Users,DC=example,DC=com'),
|
feature_required='ldap',
|
||||||
('users', ['CN=Domain Users,CN=Users,DC=example,DC=com']),
|
)
|
||||||
('remove_users', True),
|
|
||||||
('remove_admins', True),
|
|
||||||
])),
|
|
||||||
('Test Org 2', collections.OrderedDict([
|
|
||||||
('admins', 'CN=Administrators,CN=Builtin,DC=example,DC=com'),
|
|
||||||
('users', True),
|
|
||||||
('remove_users', True),
|
|
||||||
('remove_admins', True),
|
|
||||||
])),
|
|
||||||
]),
|
|
||||||
feature_required='ldap',
|
|
||||||
)
|
|
||||||
|
|
||||||
register(
|
register(
|
||||||
'AUTH_LDAP_TEAM_MAP',
|
'AUTH_LDAP{}_USER_FLAGS_BY_GROUP'.format(append_str),
|
||||||
field_class=fields.LDAPTeamMapField,
|
field_class=fields.LDAPUserFlagsField,
|
||||||
default={},
|
default={},
|
||||||
label=_('LDAP Team Map'),
|
label=_('LDAP User Flags By Group'),
|
||||||
help_text=_('Mapping between team members (users) and LDAP groups. Configuration'
|
help_text=_('Retrieve users from a given group. At this time, superuser and system'
|
||||||
' details are available in the Ansible Tower documentation.'),
|
' auditors are the only groups supported. Refer to the Ansible Tower'
|
||||||
category=_('LDAP'),
|
' documentation for more detail.'),
|
||||||
category_slug='ldap',
|
category=_('LDAP'),
|
||||||
placeholder=collections.OrderedDict([
|
category_slug='ldap',
|
||||||
('My Team', collections.OrderedDict([
|
placeholder=collections.OrderedDict([
|
||||||
('organization', 'Test Org'),
|
('is_superuser', 'CN=Domain Admins,CN=Users,DC=example,DC=com'),
|
||||||
('users', ['CN=Domain Users,CN=Users,DC=example,DC=com']),
|
('is_system_auditor', 'CN=Domain Auditors,CN=Users,DC=example,DC=com'),
|
||||||
('remove', True),
|
]),
|
||||||
])),
|
feature_required='ldap',
|
||||||
('Other Team', collections.OrderedDict([
|
)
|
||||||
('organization', 'Test Org 2'),
|
|
||||||
('users', 'CN=Other Users,CN=Users,DC=example,DC=com'),
|
register(
|
||||||
('remove', False),
|
'AUTH_LDAP{}_ORGANIZATION_MAP'.format(append_str),
|
||||||
])),
|
field_class=fields.LDAPOrganizationMapField,
|
||||||
]),
|
default={},
|
||||||
feature_required='ldap',
|
label=_('LDAP Organization Map'),
|
||||||
)
|
help_text=_('Mapping between organization admins/users and LDAP groups. This '
|
||||||
|
'controls which users are placed into which Tower organizations '
|
||||||
|
'relative to their LDAP group memberships. Configuration details '
|
||||||
|
'are available in the Ansible Tower documentation.'),
|
||||||
|
category=_('LDAP'),
|
||||||
|
category_slug='ldap',
|
||||||
|
placeholder=collections.OrderedDict([
|
||||||
|
('Test Org', collections.OrderedDict([
|
||||||
|
('admins', 'CN=Domain Admins,CN=Users,DC=example,DC=com'),
|
||||||
|
('users', ['CN=Domain Users,CN=Users,DC=example,DC=com']),
|
||||||
|
('remove_users', True),
|
||||||
|
('remove_admins', True),
|
||||||
|
])),
|
||||||
|
('Test Org 2', collections.OrderedDict([
|
||||||
|
('admins', 'CN=Administrators,CN=Builtin,DC=example,DC=com'),
|
||||||
|
('users', True),
|
||||||
|
('remove_users', True),
|
||||||
|
('remove_admins', True),
|
||||||
|
])),
|
||||||
|
]),
|
||||||
|
feature_required='ldap',
|
||||||
|
)
|
||||||
|
|
||||||
|
register(
|
||||||
|
'AUTH_LDAP{}_TEAM_MAP'.format(append_str),
|
||||||
|
field_class=fields.LDAPTeamMapField,
|
||||||
|
default={},
|
||||||
|
label=_('LDAP Team Map'),
|
||||||
|
help_text=_('Mapping between team members (users) and LDAP groups. Configuration'
|
||||||
|
' details are available in the Ansible Tower documentation.'),
|
||||||
|
category=_('LDAP'),
|
||||||
|
category_slug='ldap',
|
||||||
|
placeholder=collections.OrderedDict([
|
||||||
|
('My Team', collections.OrderedDict([
|
||||||
|
('organization', 'Test Org'),
|
||||||
|
('users', ['CN=Domain Users,CN=Users,DC=example,DC=com']),
|
||||||
|
('remove', True),
|
||||||
|
])),
|
||||||
|
('Other Team', collections.OrderedDict([
|
||||||
|
('organization', 'Test Org 2'),
|
||||||
|
('users', 'CN=Other Users,CN=Users,DC=example,DC=com'),
|
||||||
|
('remove', False),
|
||||||
|
])),
|
||||||
|
]),
|
||||||
|
feature_required='ldap',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
_register_ldap()
|
||||||
|
_register_ldap('1')
|
||||||
|
_register_ldap('2')
|
||||||
|
_register_ldap('3')
|
||||||
|
_register_ldap('4')
|
||||||
|
_register_ldap('5')
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# RADIUS AUTHENTICATION SETTINGS
|
# RADIUS AUTHENTICATION SETTINGS
|
||||||
|
|||||||
@@ -31,6 +31,21 @@ class AuthenticationBackendsField(fields.StringListField):
|
|||||||
('awx.sso.backends.LDAPBackend', [
|
('awx.sso.backends.LDAPBackend', [
|
||||||
'AUTH_LDAP_SERVER_URI',
|
'AUTH_LDAP_SERVER_URI',
|
||||||
]),
|
]),
|
||||||
|
('awx.sso.backends.LDAPBackend1', [
|
||||||
|
'AUTH_LDAP_1_SERVER_URI',
|
||||||
|
]),
|
||||||
|
('awx.sso.backends.LDAPBackend2', [
|
||||||
|
'AUTH_LDAP_2_SERVER_URI',
|
||||||
|
]),
|
||||||
|
('awx.sso.backends.LDAPBackend3', [
|
||||||
|
'AUTH_LDAP_3_SERVER_URI',
|
||||||
|
]),
|
||||||
|
('awx.sso.backends.LDAPBackend4', [
|
||||||
|
'AUTH_LDAP_4_SERVER_URI',
|
||||||
|
]),
|
||||||
|
('awx.sso.backends.LDAPBackend5', [
|
||||||
|
'AUTH_LDAP_5_SERVER_URI',
|
||||||
|
]),
|
||||||
('awx.sso.backends.RADIUSBackend', [
|
('awx.sso.backends.RADIUSBackend', [
|
||||||
'RADIUS_SERVER',
|
'RADIUS_SERVER',
|
||||||
]),
|
]),
|
||||||
@@ -70,6 +85,11 @@ class AuthenticationBackendsField(fields.StringListField):
|
|||||||
|
|
||||||
REQUIRED_BACKEND_FEATURE = {
|
REQUIRED_BACKEND_FEATURE = {
|
||||||
'awx.sso.backends.LDAPBackend': 'ldap',
|
'awx.sso.backends.LDAPBackend': 'ldap',
|
||||||
|
'awx.sso.backends.LDAPBackend1': 'ldap',
|
||||||
|
'awx.sso.backends.LDAPBackend2': 'ldap',
|
||||||
|
'awx.sso.backends.LDAPBackend3': 'ldap',
|
||||||
|
'awx.sso.backends.LDAPBackend4': 'ldap',
|
||||||
|
'awx.sso.backends.LDAPBackend5': 'ldap',
|
||||||
'awx.sso.backends.RADIUSBackend': 'enterprise_auth',
|
'awx.sso.backends.RADIUSBackend': 'enterprise_auth',
|
||||||
'awx.sso.backends.SAMLAuth': 'enterprise_auth',
|
'awx.sso.backends.SAMLAuth': 'enterprise_auth',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,3 +16,4 @@ uwsgitop
|
|||||||
jupyter
|
jupyter
|
||||||
matplotlib
|
matplotlib
|
||||||
backports.tempfile # support in unit tests for py32+ tempfile.TemporaryDirectory
|
backports.tempfile # support in unit tests for py32+ tempfile.TemporaryDirectory
|
||||||
|
mockldap
|
||||||
|
|||||||
Reference in New Issue
Block a user