Code Monkey home page Code Monkey logo

st2-auth-ldap's Introduction

LDAP authentication backend for StackStorm

LDAP Unit Tests Status

Requirements

Ubuntu / Debian

sudo apt-get install -y python-dev libldap2-dev libsasl2-dev libssl-dev ldap-utils

CentOS / RHEL / Fedora

sudo dnf install python2-devel python3-devel openldap-devel

Configuration Options

option required default description
bind_dn yes DN of the service account to bind with the LDAP server
bind_password yes Password of the service account
base_ou yes Base OU to search for user and group entries
group_dns yes Which groups user must be member of to be granted access (group names are considered case-insensitive)
group_dns_check no and What kind of check to perform when validating user group membership (and / or). When and behavior is used, user needs to be part of all the specified groups and when or behavior is used, user needs to be part of at least one or more of the specified groups.
host yes Hostname of the LDAP server. Multiple comma-separated entries are allowed.
port yes Port of the LDAP server
use_ssl no false Use LDAPS to connect
use_tls no false Start TLS on LDAP to connect
cacert no None Path to the CA cert used to validate certificate
id_attr no uid Field name of the user ID attribute; ignored if account_pattern is specified.
account_pattern no {id_attr}={{username}} LDAP subtree pattern to match user. The user's username is escaped and interpolated into this string (see example).
group_pattern no (|(&(objectClass=*)(|(member={user_dn})(uniqueMember={user_dn})(memberUid={username})))) LDAP subtree pattern for user groups. Both user_dn and username are escaped and then interpolated into this string (see example).
scope no subtree Search scope (base, onelevel, or subtree)
network_timeout no 10.0 Timeout for network operations (in seconds)
chase_referrals no false True if the referrals should be automatically chased within the underlying LDAP C lib
debug no false Enable debug mode. When debug mode is enabled all the calls (including the results) to LDAP server are logged
client_options no A dictionary with additional Python LDAP client options which can be passed to set_connection() method
cache_user_groups_response no true When true, LDAP user groups response is cached for 120 seconds (by default) in memory. This decreases load on LDAP server and increases performance when remote LDAP group to RBAC role sync is enabled and / or when the same user authenticates concurrency in a short time frame. Keep in mind that even when this feature is enabled, single (authenticate) request to LDAP server will still be performed when user authenticates to st2auth - authentication information is not cached - only user groups are cached.
cache_user_groups_ttl no 120 How long (in seconds)
base_ou_group no None Base OU to search for group entries. If not specified will default to None and take value of base_ou

Implementation Overview

The LDAP backend attempts a few different LDAP operations to authenticate users against an LDAP server:

  1. Attempts an LDAP bind with the StackStorm service credentials bind_dn and bind_password.
  2. Searches the LDAP server for the username provided by the StackStorm user, and saves the user's bind_dn attribute as user_dn.
  3. Fetches the user's LDAP groups and compares them against the groups in the group_dns configuration using the logic from group_dns_check, the user_dn from step 2, and the username supplied by the StackStorm user.
  4. Attempts to re-bind to the LDAP server with the StackStorm user's supplied username and password.

If all of the steps succeed, then the user is authenticated. If any of those steps fail, then the authentication fails.

Configuration Examples

Simple Configuration

Please refer to the standalone mode in the configuration section for authentication for basic setup concept. The following is an example of the auth section in the StackStorm configuration file for the LDAP backend.

[auth]
mode = standalone
backend = ldap
backend_kwargs = {"bind_dn": "CN=st2admin,ou=users,dc=example,dc=com", "bind_password": "foobar123", "base_ou": "dc=example,dc=com", "group_dns": ["CN=st2users,ou=groups,dc=example,dc=com", "CN=st2developers,ou=groups,dc=example,dc=com"], "host": "identity.example.com", "port": 636, "use_ssl": true, "cacert": "/path/to/cacert.pem"}
enable = True
debug = False
use_ssl = True
cert = /path/to/mycert.crt
key = /path/to/mycert.key
logging = /path/to/st2auth.logging.conf
api_url = http://myhost.example.com:9101/

Note: Key in the client_options dictionary must be an integer representing a LDAP constant option value.

For example:

backend_kwargs = {..., "client_options": {"20482": 9}}

In this case, "20482" represents ldap.OPT_TIMEOUT option.

To retrieve a integer value of a particular client option constant, you can run the following code:

import ldap
print(ldap.OPT_TIMEOUT)

Additionally, this simple example uses the default values for the id_attr, account_pattern, and group_pattern configuration options. This means that the user's account will be queried with the default LDAP search pattern uid={username}, and the groups will be queried with the default LDAP search pattern (|(&(objectClass=*)(|(member={user_dn})(uniqueMember={user_dn})(memberUid={username})))).

Configuration Specifying id_attr

If your LDAP server uses a different name for the user ID attribute, you can simply specify the id_attr configuration option.

[auth]
mode = standalone
backend = ldap
backend_kwargs = {"bind_dn": "CN=st2admin,ou=users,dc=example,dc=com", "bind_password": "foobar123", "base_ou": "dc=example,dc=com", "id_attr": "username", "group_dns": ["CN=st2users,ou=groups,dc=example,dc=com", "CN=st2developers,ou=groups,dc=example,dc=com"], "host": "identity.example.com", "port": 636, "use_ssl": true, "cacert": "/path/to/cacert.pem"}
enable = True
debug = False
use_ssl = True
cert = /path/to/mycert.crt
key = /path/to/mycert.key
logging = /path/to/st2auth.logging.conf
api_url = http://myhost.example.com:9101/

Explanation

In this example, the user's account will be queried with the LDAP search pattern username={username}, and the user's groups will be queried with the default LDAP search pattern from above.

Configuration Overriding account_pattern and group_pattern

[auth]
mode = standalone
backend = ldap
backend_kwargs = {"bind_dn": "CN=st2admin,ou=users,dc=example,dc=com", "bind_password": "foobar123", "base_ou": "dc=example,dc=com", "account_pattern": "(&(objectClass=person)(|(accountName={username})(mail={username})))", "group_pattern": "(&(objectClass=userGroup)(|(member={user_dn})(uniqueMember={user_dn})(memberUsername={username})))", "group_dns": ["CN=st2users,ou=groups,dc=example,dc=com", "CN=st2developers,ou=groups,dc=example,dc=com"], "host": "identity.example.com", "port": 636, "use_ssl": true, "cacert": "/path/to/cacert.pem"}
enable = True
debug = False
use_ssl = True
cert = /path/to/mycert.crt
key = /path/to/mycert.key
logging = /path/to/st2auth.logging.conf
api_url = http://myhost.example.com:9101/

Note: You do not have to override both account_pattern and group_pattern together, you may only need to override one of them.

Explanation

It's easier to read the account_pattern string (&(objectClass=person)(|(accountName={username})(mail={username}))) if it is reformatted to show the nesting:

(&
  (objectClass=person)
  (|
    (accountName={username})
    (mail={username})
  )
)

The Python string format patterns {username} will be interpolated with the LDAP username of users who are authenticating with StackStorm. This means that the account_pattern search string will query the LDAP server for a user who has the LDAP objectClass attribute equal to person and whose LDAP accountName or LDAP mail attributes are equal to the username they submit to StackStorm.

For group_pattern, the usage is similar, but it has an additional user_dn variable that will be interpolated into the string:

(&
  (objectClass=userGroup)
  (|
    (member={user_dn})
    (uniqueMember={user_dn})
    (memberUsername={username})
  )
)

This search string will query for LDAP objects that have objectClass attributes equal to userGroup and whose LDAP member or uniqueMember attributes are equal to the user's LDAP user_dn value or whose LDAP memberUsername attributes are equal to the username they submit to StackStorm.

The user_dn value is the user's bind_dn attribute returned by the LDAP server in step 2.

Running tests

Unit tests:

make unit-tests

Copyright, License, and Contributors Agreement

Copyright 2015-2020 Extreme Networks, Inc.

Copyright 2020 StackStorm, Inc.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License. You may obtain a copy of the License in the LICENSE file, or at:

http://www.apache.org/licenses/LICENSE-2.0

By contributing you agree that these contributions are your own (or approved by your employer) and you grant a full, complete, irrevocable copyright license to all users and developers of the project, present and future, pursuant to the license of the project.

st2-auth-ldap's People

Contributors

amanda11 avatar arm4b avatar armab avatar bigmstone avatar blag avatar cognifloyd avatar dennybaa avatar dependabot[bot] avatar enykeev avatar humblearner avatar kami avatar ktyogurt avatar lakshmi-kannan avatar lindsayhill avatar m4dcoder avatar mamercad avatar manasdk avatar mierdin avatar niraj-13 avatar nzlosh avatar sagarvasav-admin avatar swollo avatar warrenvw avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

st2-auth-ldap's Issues

ldap

How is ST2 integrated with LDAP

Rename the repository to `st2-auth-ldap`

As mentioned in the the other EWC migration issues, repository st2-enterprise-auth-backend-ldap needs a rename to avoid enterprise in the naming.

After looking closer the code produces deb/rpm packages named st2-auth-ldap.
If not objections, let's rename st2-enterprise-auth-backend-ldap -> st2-auth-ldap as the most making sense logically.

We'll need to find references in st2ci and st2cd workflows as well to make sure nothing is broken StackStorm/st2ci#187 StackStorm/st2cd#438

You can log in through LDAP only when required_groups equals actual_groups

The log tells me that I can log in to LDAP only when required_groups equals actual_groups
required_groups= {'cn=st2users,cn=people,ou=people,dc=example,dc=cn'}
actual_groups= {'cn=st2users,cn=people,ou=people,dc=example,dc=cn'}

The following configuration does not allow login

backend_kwargs = {
"bind_dn": "cn=admin,dc=example,dc=cn",
"bind_password": "123",
"base_ou": "ou=People,dc=example,dc=cn",
"id_attr":"cn" ,
"group_dns": ["ou=People,dc=example,dc=cn"],
"group_pattern": "(&(objectClass=person)(&(cn={username})))",
"group_dns_check":"or",
"host": "ldap.example.cn",
"port": 389}

2022-05-13 07:34:54,293 ERROR [-] Unable to verify membership for user "st2users (
required_groups={'ou=people,dc=example,dc=cn'},
actual_groups={'cn=st2users,ou=people,dc=example,dc=cn'},
check_behavior=or)".

I have to change group_dns to "cn=st2users,ou=people,dc=example,dc=cn",so that I can log in successfully

Currently I can only add my LDAP authentication by adding group_dns
example: [
"cn=user1,ou=ops,ou=people,dc=example,dc=cn",
"cn=user2,ou=ops,ou=people,dc=example,dc=cn"
]
I can't find my user information without changing group-pattern

my ldap user dn = cn=user1,ou=ops,ou=People,dc=example,dc=cn

I can log in successfully only when group_dns equals my user DN

pip/sudo warning during install/upgrade

Running sudo apt-get upgrade on an EWC system results in these error messages:

The directory '/home/extreme/.cache/pip/http' or its parent directory is not owned by the current user and the cache has been disabled. Please check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.
You are using pip version 9.0.1, however version 19.0.3 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
Preparing to unpack .../st2-rbac-backend_3.0dev-4_amd64.deb ...
Unpacking st2-rbac-backend (3.0dev-4) over (3.0dev-3) ...
The directory '/home/extreme/.cache/pip/http' or its parent directory is not owned by the current user and the cache has been disabled. Please check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.
The directory '/home/extreme/.cache/pip/http' or its parent directory is not owned by the current user and the cache has been disabled. Please check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.
You are using pip version 9.0.1, however version 19.0.3 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.

We should fix or suppress both the pip version warning, and the warning about sudo -H.

Same issue applies to github.com/StackStorm/st2-enterprise-rbac-backend packages too.

Loop control for failed logins

Something happened with my docker setup when I enabled rbac with LDAP. I'm still trying to troubleshoot why this is happening but one of the containers is continually trying to authenticate my user and basically locked out my account. My password was reset by our IT team but my account is continually locked out. I had to disable LDAP to get this to stop. There needs to be some kind of loop control in place to where the auth container isn't just bombarding the LDAP server every 5 seconds to try and auth someone.

Here's the events in order:

  1. LDAP was enabled and working correctly
  2. RBAC was then enabled but wasn't running correctly because I didn't have "backend" set
  3. Set the backend to "default"
  4. My account in LDAP is now locked out.
  5. I restarted containers, rebuilt containers, closed all browsers, etc but I couldn't recover this. Eventually had to disable LDAP all together to get it to stop.

Version:
st2 3.4dev (03869c913), on Python 3.6.9

I'm adding this to the release discussion, but the issue of adding some loop control I'm adding here.

How do I fill in this group_dns

St2's LDAP is the search group of the group, while our LDAP is in the People group, so there is no group in it.
How do I fill in this group_dns

Change the License to OpenSource

Currently the repository LICENSE file in repo and packages lists Extreme Workflow Composer EULA, including Homepage: https://www.extremenetworks.com/product/workflow-composer/, EWC naming and other Extreme Networks references.
This should be changed to Apache 2 OSS license.

Additionally, every file needs a new Apache 2 license/copyright header instead of Extreme proprietary.

Here is the list:

  • README and repository descriptions
  • LICENSE file
  • deb packaging descriptions, references and license
  • rpm packaging descriptions, references and license
  • Copyright headers for every file

Besides of that, we'll need to rename the st2-enterprise-auth-backend-ldap repo and remove enterprise from it.

Package & deploy to StackStorm OSS PackageCloud

This repository is producing deb/rpm packages and should come as an extension to StackStorm (not part of the core).

The code needs an update to remove enterprise from the package naming and CD process needs an update for this package to be deployed to https://packagecloud.io/stackstorm/ repositories.

Besides of that, github.com/stackstorm/st2ci and github.com/stackstorm/st2cd e2e tests and promotion workflows should reflect this change.

Invalid "st2auth.backends.backend" backend specified: ldap

Hi Team,
Do we need to install ldap driver in backend, following this doc lead me to error:

2020-07-19 00:44:10,636 140472718459440 DEBUG router [-] Adding API: StackStorm API 1.0.0
2020-07-19 00:44:10,673 140472718459440 DEBUG driver_loader [-] Retrieving driver for backend "ldap"
2020-07-19 00:44:10,673 140472718459440 DEBUG extension [-] found extension EntryPoint.parse('pam = st2auth_pam_backend.pam_backend:PAMAuthenticationBackend')
2020-07-19 00:44:10,674 140472718459440 DEBUG extension [-] found extension EntryPoint.parse('flat_file = st2auth_flat_file_backend.flat_file:FlatFileAuthenticationBackend')
2020-07-19 00:44:10,674 140472718459440 WARNING named [-] Could not load ldap
2020-07-19 00:44:10,674 140472718459440 ERROR driver_loader [-] Invalid "st2auth.backends.backend" backend specified: ldap

I installed ldap backend with /opt/stackstorm/st2/bin/pip install git+https://github.com/StackStorm/st2-auth-backend-ldap.git@master#egg=st2_auth_backend_ldap following https://github.com/StackStorm/st2-auth-backend-ldap but got another error :

TypeError: Failed to instantiate auth backend "ldap" (class LDAPAuthenticationBackend) with backend settings "{u'bind_dn': u'CN=*,ou=*,ou=*,dc=*,dc=*', u'base_ou': u'dc=*,dc=*', u'host': u'*', u'bind_password': u'*', u'cacert': u'*', u'use_ssl': True, u'port': 636}": __init__() got an unexpected keyword argument 'base_ou'

Please help me understanding what I'm missing here.
Cheers!

Check RPM upgrades are working

Had customer report that with RHEL 7.x, when using yum to upgrade from 2.2.1 -> 2.3.2, this package was upgraded, but it didn't upgrade the python module here:

rpm -qa|grep -e bwc -e st2:

st2-2.3.2-2.x86_64
bwc-enterprise-2.3.2-2.x86_64
bwc-ui-2.3.2-1.x86_64
st2-auth-ldap-2.3.2-1.x86_64
st2chatops-2.3.2-1.x86_64
st2flow-2.3.2-1.x86_64
st2mistral-2.3.2-2.x86_64

ls -l /opt/stackstorm/share/wheels/

total 740
-rw-r--r-- 1 root root 260374 Jul 25 09:41 python_ldap-2.4.41-cp27-none-linux_x86_64.whl
-rw-r--r-- 1 root root 477339 Jul 25 09:41 setuptools-36.2.2-py2.py3-none-any.whl
-rw-r--r-- 1 root root 15076 Jul 25 09:41 st2_enterprise_auth_backend_ldap-2.3.2-py2-none-any.whl

/opt/stackstorm/st2/bin/pip freeze|grep ldap

python-ldap==2.4.32
st2-enterprise-auth-backend-ldap==2.2.1

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.