Banno / getsentry-ldap-auth

A Sentry extension to add an LDAP server as an authention source.
Apache License 2.0
163 stars 55 forks source link

sentry-ldap-auth for Active Directory #22

Open Piknik1990 opened 7 years ago

Piknik1990 commented 7 years ago

Hello!

I need to set up AD-authorization on Sentry. In the Internet on this theme I found this topic only: https://forum.sentry.io/t/how-to-set-up-to-auth-via-ms-active-directory-or-ldap/1880/5

But settings of this topic leads or not work AD-auth, or full non-work sentry (He not accept options "LOGGING").

I have next AD-server

IP 10.10.10.10 Domain: test.comp.com Users: test.comp.com/Users Groups: test.comp.com/Groups

Test User: test.comp.com/Users/user Test Groups: test.comp.com/Groups/adminsupport (full right) test.comp.com/Groups/support (read only)

Now my conf-file have follow parameters:

sentry.conf.py

from sentry.conf.server import *

import os.path

CONF_ROOT = os.path.dirname(__file__)

DATABASES = {
    'default': {
        'ENGINE': 'sentry.db.postgres',
        'NAME': 'sentry',
        'USER': 'sentry',
        'PASSWORD': '123',
        'HOST': '127.0.0.1',
        'PORT': '5432',
        'AUTOCOMMIT': True,
        'ATOMIC_REQUESTS': False,
    }
}

SENTRY_USE_BIG_INTS = True
SENTRY_SINGLE_ORGANIZATION = True
DEBUG = False
SENTRY_CACHE = 'sentry.cache.redis.RedisCache'
BROKER_URL = 'redis://localhost:6379'
SENTRY_RATELIMITER = 'sentry.ratelimits.redis.RedisRateLimiter'
SENTRY_BUFFER = 'sentry.buffer.redis.RedisBuffer'
SENTRY_QUOTAS = 'sentry.quotas.redis.RedisQuota'
SENTRY_TSDB = 'sentry.tsdb.redis.RedisTSDB'
SENTRY_DIGESTS = 'sentry.digests.backends.redis.RedisBackend'
# FORCE_SCRIPT_NAME = '/sentry'
SENTRY_WEB_HOST = '0.0.0.0'
SENTRY_WEB_PORT = 9000
SENTRY_WEB_OPTIONS = {
    # 'workers': 3,  # the number of web workers
    # 'protocol': 'uwsgi',  # Enable uwsgi protocol instead of http
}

import ldap
from django_auth_ldap.config import LDAPSearch, GroupOfUniqueNamesType

AUTH_LDAP_SERVER_URI = 'ldap://10.10.10.10.'
AUTH_LDAP_BIND_DN = 'CN=User,CN=Users,DC=test,DC=comp,DC=com'
AUTH_LDAP_BIND_PASSWORD = '123'

AUTH_LDAP_CONNECTION_OPTIONS = {
ldap.OPT_DEBUG_LEVEL: 0,
ldap.OPT_REFERRALS: 0,
}

AUTH_LDAP_USER_SEARCH = LDAPSearch(
    'dc=test,dc=comp,dc=com',
    ldap.SCOPE_SUBTREE,
    'member={1}',
)

AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
    'dc=test,dc=comp,dc=comp',
    ldap.SCOPE_SUBTREE,
    'objectClass=group'
)

AUTH_LDAP_GROUP_TYPE = GroupOfUniqueNamesType()
AUTH_LDAP_REQUIRE_GROUP = None
AUTH_LDAP_DENY_GROUP = None

AUTH_LDAP_USER_ATTR_MAP = {
    'name': 'cn',
    'email': 'mail'
}

AUTH_LDAP_FIND_GROUP_PERMS = False
AUTH_LDAP_CACHE_GROUPS = True
AUTH_LDAP_GROUP_CACHE_TIMEOUT = 3600

AUTH_LDAP_DEFAULT_SENTRY_ORGANIZATION = u'TEST COMP COM'
AUTH_LDAP_SENTRY_ORGANIZATION_ROLE_TYPE = 'member'
AUTH_LDAP_SENTRY_ORGANIZATION_GLOBAL_ACCESS = True

AUTHENTICATION_BACKENDS = AUTHENTICATION_BACKENDS + (
    'sentry_ldap_auth.backend.SentryLdapBackend',
)

import logging
logger = logging.getLogger('django_auth_ldap')
logger.addHandler(logging.StreamHandler())
logger.addHandler(logging.FileHandler(r"/tmp/ldap2.log"))
logger.setLevel('DEBUG')

#LOGGING[‘overridable’] = [‘sentry’, ‘django_auth_ldap’ ]
#LOGGING[‘loggers’][‘django_auth_ldap’] = {
#‘handlers’: [‘console’],
#‘level’: ‘DEBUG’
#}

Tell me, do you have AD-like config file for Sentry for example?

barronhagerman commented 7 years ago

After just a quick look at your configuration, it doesn't look like your AUTH_LDAP_USER_SEARCH is correct. The LDAP query (parameter 3 for LDAPSearch()) should be something like (uid=%(user)s)

Piknik1990 commented 7 years ago

Slightly differently explain.

I experimented several days and now I have this:

Active Directory on Windows 2008R2 1) domain test.comp.com 2) User: user in catalog test.comp.com/Users/ 3) IP 10.10.10.1

Sentry on CentOS 7 1) SELinux and Firewalld disable 2) IP 10.10.10.10 3) Installed: pip install redis==2.10.5 pip install sentry pyyaml sentry upgrade --noinput sentry createuser --email sentry@test.com --password '123' --superuser --no-input yum -y install openldap-devel openldap-clients pip install python-ldap django-auth-ldap sentry-ldap-auth sentry run worker sentry run web sentry run cron 4) If enter command "ldapsearch -x -h 10.10.10.1 -D "user@test.comp.com" -W -b "cn=users,dc=test,dc=comp,dc=com" -s sub "(&(objectClass=user)(objectClass=person))" cn mail" and password I see username and email. Wherein in Windows logging massage of successful/failed authorization. 5) If I try authorization via Sentry interface I get failed auth, but in the Windows not no one messages of successful/failed authorization. No one. Such sensation, that at all does not try to unite with AD.

My sentry.conf.py:

...
import ldap
from django_auth_ldap.config import LDAPSearch, GroupOfUniqueNamesType

AUTH_LDAP_SERVER_URI = 'ldap://10.10.10.1'
AUTH_LDAP_BIND_DN = 'user'
AUTH_LDAP_BIND_PASSWORD = '1qaz@WSX'

AUTH_LDAP_USER_SEARCH = LDAPSearch(
    'cn=Users,dc=test,dc=comp,dc=com',
    ldap.SCOPE_SUBTREE,
    '(&(objectClass=user)(objectClass=person))',
)

AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
    'cn=Groups,dc=test,dc=comp,dc=com',
    ldap.SCOPE_SUBTREE,
    '(objectClass=groupOfUniqueNames)'
)

AUTH_LDAP_GROUP_TYPE = GroupOfUniqueNamesType()
AUTH_LDAP_REQUIRE_GROUP = None
AUTH_LDAP_DENY_GROUP = None

AUTH_LDAP_USER_ATTR_MAP = {
    'name': 'cn',
    'email': 'mail'
}

AUTH_LDAP_FIND_GROUP_PERMS = False
AUTH_LDAP_CACHE_GROUPS = True
AUTH_LDAP_GROUP_CACHE_TIMEOUT = 3600

AUTH_LDAP_DEFAULT_SENTRY_ORGANIZATION = u'TEST Company'
AUTH_LDAP_SENTRY_ORGANIZATION_ROLE_TYPE = 'member'
AUTH_LDAP_SENTRY_ORGANIZATION_GLOBAL_ACCESS = True

AUTHENTICATION_BACKENDS = AUTHENTICATION_BACKENDS + (
    'sentry_ldap_auth.backend.SentryLdapBackend',
)

import logging
logger = logging.getLogger('django_auth_ldap')
logger.addHandler(logging.StreamHandler())
logger.setLevel('DEBUG')

I tried change ldap.SCOPE_SUBTREE: In the ldapsearch work (&(objectClass=user)(objectClass=person)) and (cn=*), not work (uid=%(user)s) (ldap_search_ext: Bad search filter (-7)) In the Sentry not work nothing.

Also I tried this config with diverse "dap.SCOPE_SUBTREE" and this not work too:

#########################
## LDAP Authentication ##
#########################

import ldap
from django_auth_ldap.config import LDAPSearch, GroupOfNamesType

# Baseline configuration.
AUTH_LDAP_SERVER_URI = "ldap://10.10.10.1"

AUTH_LDAP_USER_SEARCH = LDAPSearch("cn=Users,dc=test,dc=comp,dc=com",
    ldap.SCOPE_SUBTREE, "(&(objectClass=user)(objectClass=person))")

AUTHENTICATION_BACKENDS = (
    'sentry.utils.auth.EmailAuthBackend',
    'django_auth_ldap.backend.LDAPBackend',
    'django.contrib.auth.backends.ModelBackend',
)

Main question, why Sentry does not even try connecting on AD-server?

barronhagerman commented 7 years ago

@Piknik1990 Try changing the search filter to (&(objectClass=user)(objectClass=person)(cn=%(user)s).

I don't understand why you say "Sentry does not even try connecting on AD-server". You received an error Bad search filter (-7), right? Can you connect to AD with a basic LDAP client?

Also, it's been a while since I did anything with AD, but I'm not sure you can bind a user to AD using an unencrypted channel. You should be able to connect anonymously by setting AUTH_LDAP_BIND_DN = '' and AUTH_LDAP_BIND_PASSWORD = ''

Piknik1990 commented 7 years ago

Ok. I am poorly described problem.

At first I install Windows 2008R2, create AD domain and create user in this domain. IP: 10.10.10.1 Domain: test.comp.com

All connect to AD server (successful or unsuccessful) I see in the Event Viewer - Security log example: https://technet.microsoft.com/en-us/library/dd277415.w2kab163_big(l=en-us).gif

Sentry server installed in Centos 7. Now config Sentry is:

import ldap
from django_auth_ldap.config import LDAPSearch, GroupOfUniqueNamesType

AUTH_LDAP_SERVER_URI = 'ldap://10.10.10.1'
AUTH_LDAP_BIND_DN = ''
AUTH_LDAP_BIND_PASSWORD = ''

AUTH_LDAP_USER_SEARCH = LDAPSearch(
    'cn=Users,dc=test,dc=comp,dc=com',
    ldap.SCOPE_SUBTREE,
    '(&(objectClass=user)(objectClass=person)',
)

AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
    'cn=Groups,dc=test,dc=comp,dc=com',
    ldap.SCOPE_SUBTREE,
    '(objectClass=groupOfUniqueNames)'
)

AUTH_LDAP_GROUP_TYPE = GroupOfUniqueNamesType()
AUTH_LDAP_REQUIRE_GROUP = None
AUTH_LDAP_DENY_GROUP = None

AUTH_LDAP_USER_ATTR_MAP = {
    'name': 'cn',
    'email': 'mail'
}

AUTH_LDAP_FIND_GROUP_PERMS = False
AUTH_LDAP_CACHE_GROUPS = True
AUTH_LDAP_GROUP_CACHE_TIMEOUT = 3600

AUTH_LDAP_DEFAULT_SENTRY_ORGANIZATION = u'TEST'
AUTH_LDAP_SENTRY_ORGANIZATION_ROLE_TYPE = 'member'
AUTH_LDAP_SENTRY_ORGANIZATION_GLOBAL_ACCESS = True

AUTHENTICATION_BACKENDS = AUTHENTICATION_BACKENDS + (
    'sentry_ldap_auth.backend.SentryLdapBackend',
)

import logging
logger = logging.getLogger('django_auth_ldap')
logger.addHandler(logging.StreamHandler())
logger.setLevel('DEBUG')

Besides Sentry I install openldap-clients package. He contains useful program ldapsearch

I use this program so:

# ldapsearch -x -h 10.10.10.1 -D "user@test.comp.com" -W -b "cn=users,dc=test,dc=comp,dc=com" -s sub "(&(objectClass=user)(objectClass=person))" cn mail sn
Enter LDAP Password: 
# extended LDIF
#
# LDAPv3
# base <cn=users,dc=test,dc=comp,dc=com> with scope subtree
# filter: (&(objectClass=user)(objectClass=person))
# requesting: cn mail sn 
#
**** DATA OF AD-SERVER****
# search result
search: 2
result: 0 Success

# numResponses: 5
# numEntries: 4

Wherein in the Event Viewer Windows server writes logs about the successful entry and exit AD-user.

If I introduce incorrect password, I get follow:

# ldapsearch -x -h 10.10.10.1 -D "user@test.comp.com" -W -b "cn=users,dc=test,dc=comp,dc=com" -s sub "(&(objectClass=user)(objectClass=person))" cn mail sn
Enter LDAP Password: 
ldap_bind: Invalid credentials (49)
    additional info: 80090308: LdapErr: DSID-0C0903A9, comment: AcceptSecurityContext error, data 52e, v1db1

... and in Event Viewer Windows server writes about unsuccessful entry.

The (&(objectClass=user)(objectClass=person)) I found in the Google and this one of two filters, which AD processes correctly (second - (cn=*) ). To all other filters I get follow error:

# ldapsearch -x -h 10.10.10.1 -D "user@test.comp.com" -W -b "cn=users,dc=test,dc=comp,dc=com" -s sub "(uid=%(user)s)" cn mail
Enter LDAP Password: 
# extended LDIF
#
# LDAPv3
# base <cn=users,dc=test,dc=comp,dc=com> with scope subtree
# filter: (uid=%(user)s)
# requesting: cn mail 
#

ldap_search_ext: Bad search filter (-7)

And in the Event Viewer writes the successful entry.

So I'm currently using (&(objectClass=user)(objectClass=person)) in the Sentry config.

Generally, program ldapsearch makes me understand, that the LDAP-client is working fine.

Further on Sentry:

Whatever I filter and the credentials would not write to the config, nothing falls into Event Viewer when trying to enter through Web-interface.

I introduce login "user" and password "1qaz@WSX" I introduce login "user@test.comp.com" and password "1qaz@WSX" I introduce login "user@test.comp.com" and password "123" (incorrect) But nothing not writes in the Event Viewer. As if Sentry did not try to contact with AD. Maybe I'm misusing the data in the Web-interface?

(&(objectClass=user)(objectClass=person)(cn=%(user)s) in the ldapsearch output "ldap_search_ext: Bad search filter (-7). " Anonymously user in Sentry config does not affect the result in any way.

I do not understand why Sentry does not try to contact the AD server at all. Even if there was an incorrect filter, then the logs Event Viewer would at least have information about the wrong request or password. But he is not. Can really the whole point is that I incorrectly enter the login in the WEB interface?

wolfbo commented 6 years ago

Hello Piknik1990, have you found a solution? I have the same Problem.

Piknik1990 commented 6 years ago

No, we moved to OpenLDAP and no solved this problem more.

CBEPX commented 5 years ago

Working confing for AD Testing on sentry 8-9.1

########
# LDAP #
########

import sys
reload(sys)
sys.setdefaultencoding('utf8')
import ldap

from django_auth_ldap.config import LDAPSearch, GroupOfUniqueNamesType

AUTH_LDAP_ALWAYS_UPDATE_USER = True
AUTH_LDAP_SERVER_URI = env('SENTRY_LDAP_SERVER_URI')
AUTH_LDAP_BIND_DN = env('SENTRY_LDAP_BIND_DN')
AUTH_LDAP_BIND_PASSWORD = env('SENTRY_LDAP_BIND_PASSWORD')
AUTH_LDAP_USER_SEARCH = LDAPSearch(u"dc=domain,dc=lan",ldap.SCOPE_SUBTREE,u"(sAMAccountName=%(user)s)"
)

AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
    u'',
    ldap.SCOPE_SUBTREE,
    u'(objectClass=groupOfUniqueNames)'
)

AUTH_LDAP_GROUP_TYPE = GroupOfUniqueNamesType()
AUTH_LDAP_REQUIRE_GROUP = None
AUTH_LDAP_DENY_GROUP = None

AUTH_LDAP_USER_ATTR_MAP = {
    "username": "sAMAccountName",
    "first_name": u"givenName",
    "last_name": u"sn",
    "email": "mail",
}

AUTH_LDAP_FIND_GROUP_PERMS = False
AUTH_LDAP_CACHE_GROUPS = True
AUTH_LDAP_GROUP_CACHE_TIMEOUT = 3600

AUTH_LDAP_DEFAULT_SENTRY_ORGANIZATION = u'Sentry'
AUTH_LDAP_SENTRY_ORGANIZATION_ROLE_TYPE = 'member'
AUTH_LDAP_SENTRY_ORGANIZATION_GLOBAL_ACCESS = True
AUTH_LDAP_SENTRY_SUBSCRIBE_BY_DEFAULT = False

SENTRY_MANAGED_USER_FIELDS = ('email', 'first_name', 'last_name', 'password', )

AUTHENTICATION_BACKENDS = AUTHENTICATION_BACKENDS + (
    'sentry_ldap_auth.backend.SentryLdapBackend',
)