From 1732ad1714a801be9a85a896b3eee4445a127d5f Mon Sep 17 00:00:00 2001 From: Jon Fautley Date: Thu, 12 Jul 2018 13:29:56 +0100 Subject: [PATCH 01/18] Allow lookup of groups directly from user object Also add Microsoft Active directory specific lookup logic to resolve nested groups. --- ldapauthenticator/ldapauthenticator.py | 183 +++++++++++++++++++++---- 1 file changed, 157 insertions(+), 26 deletions(-) diff --git a/ldapauthenticator/ldapauthenticator.py b/ldapauthenticator/ldapauthenticator.py index 0cc80d1..1eccbf0 100644 --- a/ldapauthenticator/ldapauthenticator.py +++ b/ldapauthenticator/ldapauthenticator.py @@ -51,7 +51,8 @@ def _server_port_default(self): help=""" Template from which to construct the full dn when authenticating to LDAP. {username} is replaced - with the actual username used to log in. + with the user's resolved username (i.e. their CN attribute). + {login} is replaced with the actual username used to login. If your LDAP is set in such a way that the userdn can not be formed from a template, but must be looked up with an attribute @@ -63,9 +64,12 @@ def _server_port_default(self): List Example: [ - uid={username},ou=people,dc=wikimedia,dc=org, - uid={username},ou=Developers,dc=wikimedia,dc=org - ] + uid={username},ou=people,dc=wikimedia,dc=org, + uid={username},ou=Developers,dc=wikimedia,dc=org + ] + + Active Directory Example: + DOMAIN\{login} """, ) @@ -142,6 +146,20 @@ def _server_port_default(self): """, ) + group_search_base = Unicode( + config=True, + default=user_search_base, + allow_none=True, + help=""" + Base for looking up groups in the directory. Defaults to the value of user_search_base if unset. + + For example: + ``` + c.LDAPAuthenticator.group_search_base = 'ou=groups,dc=wikimedia,dc=org' + ``` + """ + ) + user_attribute = Unicode( config=True, default=None, @@ -156,6 +174,66 @@ def _server_port_default(self): """, ) + memberof_attribute = Unicode( + config=True, + default_value='memberOf', + allow_none=False, + help=""" + Attribute attached to user objects containing the list of groups the user is a member of. + + Defaults to 'memberOf', you probably won't need to change this. + """ + ) + + get_groups_from_user = Bool( + False, + config=True, + help=""" + If set, this will confirm a user's group membership by querying the + user object in LDAP directly, and querying the attribute set in + `memberof_attribute` (defaults to `memberOf`). + + If unset (the default), then each authorised group set in + `allowed_group` is queried from LDAP and matched against the user's DN. + + This should be set when the LDAP server is Microsoft Active Directory, + and you probably also want to set the `activedirectory` configuration + setting to 'true' as well' + """ + ) + + activedirectory = Bool( + False, + config=True, + help=""" + If set, this treats the remote LDAP server as a Microsoft Active + Directory instance, and will optimise group membership queries where + `allow_groups` is used. This requires `get_groups_from_user` to be + enabled. + + This allows nested groups to be resolved when using Active Directory. + + Example Active Directory configuration: + ``` + c.LDAPAuthenticator.bind_dn_template = 'DOMAIN\{login}' + c.LDAPAuthenticator.lookup_dn = False + c.LDAPAuthenticator.activedirectory = True + c.LDAPAuthenticator.get_groups_from_user = True + c.LDAPAuthenticator.lookup_dn_user_dn_attribute = 'distinguishedName' + c.LDAPAuthenticator.lookup_dn_search_filter = '({login_attr}={login})' + c.LDAPAuthenticator.lookup_dn_search_user = 'readonly' + c.LDAPAuthenticator.lookup_dn_search_password = 'notarealpassword' + c.LDAPAuthenticator.user_attribute = 'sAMAccountName' + c.LDAPAuthenticator.user_search_base = 'OU=Users,DC=example,DC=org' + c.LDAPAuthenticator.group_search_base = 'OU=Groups,DC=example,DC=org' + + c.LDAPAuthenticator.admin_users = {'Administrator'} + c.LDAPAuthenticator.allowed_groups = [ + 'CN=JupyterHub_Users,OU=Groups,DC=example,DC=org'] + ``` + """ + ) + lookup_dn_search_filter = Unicode( config=True, default_value="({login_attr}={login})", @@ -190,7 +268,7 @@ def _server_port_default(self): default_value=None, allow_none=True, help=""" - Attribute containing user's name needed for building DN string, if `lookup_dn` is set to True. + Attribute containing user's name needed for building DN string, if `lookup_dn` is set to True. See `user_search_base` for info on how this attribute is used. @@ -234,7 +312,8 @@ def resolve_username(self, username_supplied_by_user): if self.escape_userdn: search_dn = escape_filter_chars(search_dn) conn = self.get_connection( - userdn=search_dn, password=self.lookup_dn_search_password + userdn=search_dn, + password=self.lookup_dn_search_password, ) is_bound = conn.bind() if not is_bound: @@ -331,6 +410,42 @@ def authenticate(self, handler, data): username = data["username"] password = data["password"] + def get_user_groups(username): + if self.activedirectory: + self.log.debug('Active Directory enabled') + user_dn = self.resolve_username(username) + search_filter='(member:1.2.840.113556.1.4.1941:={dn})'.format(dn=escape_filter_chars(user_dn)) + search_attribs=['cn'] # We don't actually care, we just want the DN + search_base=self.group_search_base, + self.log.debug('LDAP Group query: user_dn:[%s] filter:[%s]', user_dn, search_filter) + else: + search_filter=self.lookup_dn_search_filter.format(login_attr=self.user_attribute, login=username) + search_attribs=[self.memberof_attribute] + search_base=self.user_search_base, + self.log.debug('LDAP Group query: username:[%s] filter:[%s]', username, search_filter) + + conn.search( + search_base=self.group_search_base, + search_scope=ldap3.SUBTREE, + search_filter=search_filter, + attributes=search_attribs) + + if self.activedirectory: + user_groups = [] + + if len(conn.response) == 0: + return None + + for g in conn.response: + user_groups.append(g['dn']) + return user_groups + else: + if len(conn.response) == 0 or 'attributes' not in conn.response[0].keys(): + self.log.debug('User %s is not a member of any groups (via memberOf)', username) + return None + else: + return conn.response[0]['attributes'][self.memberof_attribute] + # Protect against invalid usernames as well as LDAP injection attacks if not re.match(self.valid_username_regex, username): self.log.warning( @@ -340,6 +455,10 @@ def authenticate(self, handler, data): ) return None + # Allow us to reference the actual username the user typed (rather than + # what we might resolve it to later) + login = username + # No empty passwords! if password is None or password.strip() == "": self.log.warning("username:%s Login denied for blank password", username) @@ -372,7 +491,7 @@ def authenticate(self, handler, data): if not dn: self.log.warning("Ignoring blank 'bind_dn_template' entry!") continue - userdn = dn.format(username=username) + userdn = dn.format(username=username, login=login) if self.escape_userdn: userdn = escape_filter_chars(userdn) msg = "Attempting to bind {username} with {userdn}" @@ -430,24 +549,37 @@ def authenticate(self, handler, data): if self.allowed_groups: self.log.debug("username:%s Using dn %s", username, userdn) found = False - for group in self.allowed_groups: - group_filter = ( - "(|" - "(member={userdn})" - "(uniqueMember={userdn})" - "(memberUid={uid})" - ")" - ) - group_filter = group_filter.format(userdn=userdn, uid=username) - group_attributes = ["member", "uniqueMember", "memberUid"] - found = conn.search( - group, - search_scope=ldap3.BASE, - search_filter=group_filter, - attributes=group_attributes, - ) - if found: - break + + if self.get_groups_from_user: + user_groups = get_user_groups(login) + if user_groups is None: + self.log.debug('Username %s has no group membership', username) + return None + else: + self.log.debug('Username %s is a member of %d groups', username, len(user_groups)) + for group in self.allowed_groups: + if group in user_groups: + self.log.info('User %s is a member of permitted group %s', username, group) + return username + else: + for group in self.allowed_groups: + group_filter = ( + "(|" + "(member={userdn})" + "(uniqueMember={userdn})" + "(memberUid={uid})" + ")" + ) + group_filter = group_filter.format(userdn=userdn, uid=username) + group_attributes = ["member", "uniqueMember", "memberUid"] + found = conn.search( + group, + search_scope=ldap3.BASE, + search_filter=group_filter, + attributes=group_attributes, + ) + if found: + break if not found: # If we reach here, then none of the groups matched msg = "username:{username} User not in any of the allowed groups" @@ -463,7 +595,6 @@ def authenticate(self, handler, data): return {"name": username, "auth_state": user_info} return username - if __name__ == "__main__": import getpass From c50ac68a8b920c14a8848f5c4d25478788718d90 Mon Sep 17 00:00:00 2001 From: 1kastner Date: Wed, 12 Aug 2020 16:33:10 +0200 Subject: [PATCH 02/18] Pin ldap3 version to lower than 2.8 See https://github.com/jupyterhub/ldapauthenticator/issues/171 for further information --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 7573ded..d445117 100644 --- a/setup.py +++ b/setup.py @@ -19,5 +19,5 @@ author_email="yuvipanda@riseup.net", license="3 Clause BSD", packages=["ldapauthenticator"], - install_requires=["jupyterhub", "ldap3", "tornado", "traitlets"], + install_requires=["jupyterhub", "ldap3<2.8", "tornado", "traitlets"], ) From c04ce4f86377791c26faeb5ea0a2c27b89df24f2 Mon Sep 17 00:00:00 2001 From: Simon Li Date: Thu, 13 Aug 2020 20:33:07 +0100 Subject: [PATCH 03/18] 1.3.1 changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fce5fb..929f7f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ ## [1.3] +### [1.3.1] - 2020-08-13 + +#### Fixes +* Pin ldap3 version to lower than 2.8 ([#172](https://github.com/jupyterhub/ldapauthenticator/pull/172)) ([@1kastner](https://github.com/1kastner)) + ### [1.3.0] - 2020-02-09 From 3e46906ead4669f79aac5f1131837315cbd23e57 Mon Sep 17 00:00:00 2001 From: Simon Li Date: Thu, 13 Aug 2020 20:26:31 +0100 Subject: [PATCH 04/18] release 1.3.1 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index d445117..9ebc568 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ from setuptools import setup -version = "1.3.1.dev" +version = "1.3.1" with open("./ldapauthenticator/__init__.py", "a") as f: From 506caefa9f0b0f19db671e89610afef4a7c2708c Mon Sep 17 00:00:00 2001 From: Simon Li Date: Thu, 13 Aug 2020 20:41:49 +0100 Subject: [PATCH 05/18] back to dev --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 9ebc568..51267f4 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ from setuptools import setup -version = "1.3.1" +version = "1.3.2.dev" with open("./ldapauthenticator/__init__.py", "a") as f: From 1a61314cfd2fa9efb8054dbb2c59d75a3c37535d Mon Sep 17 00:00:00 2001 From: 1kastner Date: Tue, 18 Aug 2020 09:37:44 +0200 Subject: [PATCH 06/18] Exchanging ldap3 constants in if/else See https://github.com/cannatag/ldap3/issues/855#issuecomment-674970069 --- ldapauthenticator/ldapauthenticator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ldapauthenticator/ldapauthenticator.py b/ldapauthenticator/ldapauthenticator.py index 1eccbf0..a5b9734 100644 --- a/ldapauthenticator/ldapauthenticator.py +++ b/ldapauthenticator/ldapauthenticator.py @@ -388,7 +388,7 @@ def get_connection(self, userdn, password): self.server_address, port=self.server_port, use_ssl=self.use_ssl ) auto_bind = ( - self.use_ssl and ldap3.AUTO_BIND_TLS_BEFORE_BIND or ldap3.AUTO_BIND_NO_TLS + ldap3.AUTO_BIND_NO_TLS if use_ssl else ldap3.AUTO_BIND_TLS_BEFORE_BIND ) conn = ldap3.Connection( server, user=userdn, password=password, auto_bind=auto_bind From 0c11004130d5d9e3768fa6f35a74e716999b696b Mon Sep 17 00:00:00 2001 From: 1kastner Date: Tue, 18 Aug 2020 09:46:03 +0200 Subject: [PATCH 07/18] Update ldapauthenticator.py --- ldapauthenticator/ldapauthenticator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ldapauthenticator/ldapauthenticator.py b/ldapauthenticator/ldapauthenticator.py index a5b9734..6ddeaf3 100644 --- a/ldapauthenticator/ldapauthenticator.py +++ b/ldapauthenticator/ldapauthenticator.py @@ -388,7 +388,7 @@ def get_connection(self, userdn, password): self.server_address, port=self.server_port, use_ssl=self.use_ssl ) auto_bind = ( - ldap3.AUTO_BIND_NO_TLS if use_ssl else ldap3.AUTO_BIND_TLS_BEFORE_BIND + ldap3.AUTO_BIND_NO_TLS if self.use_ssl else ldap3.AUTO_BIND_TLS_BEFORE_BIND ) conn = ldap3.Connection( server, user=userdn, password=password, auto_bind=auto_bind From 73023f87876c5ff717e0884ec4b670a8f4bd3ef4 Mon Sep 17 00:00:00 2001 From: 1kastner Date: Tue, 18 Aug 2020 09:52:39 +0200 Subject: [PATCH 08/18] Remove fixed version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 51267f4..478f4da 100644 --- a/setup.py +++ b/setup.py @@ -19,5 +19,5 @@ author_email="yuvipanda@riseup.net", license="3 Clause BSD", packages=["ldapauthenticator"], - install_requires=["jupyterhub", "ldap3<2.8", "tornado", "traitlets"], + install_requires=["jupyterhub", "ldap3", "tornado", "traitlets"], ) From 121b0491eb55e9f72b0dbfeb0155ae44799fb8ad Mon Sep 17 00:00:00 2001 From: Simon Li Date: Fri, 28 Aug 2020 12:44:30 +0100 Subject: [PATCH 09/18] 1.3.2 changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 929f7f6..8c818e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ ## [1.3] +### [1.3.2] - 2020-08-28 + +#### Fixes +* Exchanging ldap3 constants in if/else ([#175](https://github.com/jupyterhub/ldapauthenticator/pull/175)) ([@1kastner](https://github.com/1kastner)) + + ### [1.3.1] - 2020-08-13 #### Fixes From bb82d23b99c7be8e057c37d95651bc011c0dabee Mon Sep 17 00:00:00 2001 From: Simon Li Date: Fri, 28 Aug 2020 12:51:11 +0100 Subject: [PATCH 10/18] release 1.3.2 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 478f4da..9358ecd 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ from setuptools import setup -version = "1.3.2.dev" +version = "1.3.2" with open("./ldapauthenticator/__init__.py", "a") as f: From caaf7ad831dc3f68cf3311edb44da883b0e04768 Mon Sep 17 00:00:00 2001 From: Simon Li Date: Fri, 28 Aug 2020 12:53:37 +0100 Subject: [PATCH 11/18] back to dev --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 9358ecd..6e1d805 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ from setuptools import setup -version = "1.3.2" +version = "1.3.3.dev" with open("./ldapauthenticator/__init__.py", "a") as f: From b42218a119bd3ba722b764519e6b5b4df3b96334 Mon Sep 17 00:00:00 2001 From: Simon Li Date: Fri, 11 Dec 2020 12:45:40 +0000 Subject: [PATCH 12/18] Copy https://github.com/jupyterhub/oauthenticator/tree/be91e7d9e58f13221615a64a506529c775abe593/.github/workflows --- .github/workflows/publish.yml | 35 +++++++++++++ .github/workflows/test.yml | 96 +++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 .github/workflows/publish.yml create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..3dfe659 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,35 @@ +# Build releases and (on tags) publish to PyPI +name: Release + +# always build releases (to make sure wheel-building works) +# but only publish to PyPI on tags +on: + push: + pull_request: + +jobs: + build-release: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: 3.8 + + - name: install build package + run: | + pip install --upgrade pip + pip install build + pip freeze + + - name: build release + run: | + python -m build --sdist --wheel . + ls -l dist + + - name: publish to pypi + uses: pypa/gh-action-pypi-publish@v1.4.1 + if: startsWith(github.ref, 'refs/tags/') + with: + user: __token__ + password: ${{ secrets.pypi_password }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..51f8d4e --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,96 @@ +# This is a GitHub workflow defining a set of jobs with a set of steps. +# ref: https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions +# +name: Tests + +on: + pull_request: + push: + +defaults: + run: + # Declare bash be used by default in this workflow's "run" steps. + # + # NOTE: bash will by default run with: + # --noprofile: Ignore ~/.profile etc. + # --norc: Ignore ~/.bashrc etc. + # -e: Exit directly on errors + # -o pipefail: Don't mask errors from a command piped into another command + shell: bash + +env: + OAUTH2_TOKEN_URL: "token_url" + OAUTH2_USERDATA_URL: "userdata_url" + +jobs: + # Run "linter" + lint: + runs-on: ubuntu-20.04 + timeout-minutes: 2 + + steps: + - uses: actions/checkout@v2 + + - uses: actions/setup-python@v2 + with: + python-version: 3.8 + + - name: install linter + run: | + pip install --upgrade pip + pip install flake8 + pip freeze + + - name: run lint check + run: | + flake8 oauthenticator + + # Run tests + test: + + runs-on: ubuntu-20.04 + timeout-minutes: 10 + + strategy: + # Keep running even if one variation of the job fail + fail-fast: false + matrix: + python: + - "3.6" + - "3.7" + - "3.8" + - "3.9" + + steps: + - uses: actions/checkout@v2 + + - name: Install Python ${{ matrix.python }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python }} + + # preserve pip cache to speed up installation + - name: Cache pip + uses: actions/cache@v2 + with: + path: ~/.cache/pip + # Look to see if there is a cache hit for the corresponding requirements file + key: ${{ runner.os }}-pip-${{ hashFiles('*requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + + - name: Install Python dependencies + run: | + pip install --upgrade pip + pip install --upgrade --pre -r test-requirements.txt . + pip freeze + + - name: Run tests + # FIXME: --color=yes explicitly set because: + # https://github.com/actions/runner/issues/241 + run: | + pytest -v --color=yes --cov=oauthenticator oauthenticator + + - name: Submit codecov report + run: | + codecov From c806dfda068cf812f2dad9b12ab7883689a7e2b3 Mon Sep 17 00:00:00 2001 From: Simon Li Date: Fri, 11 Dec 2020 13:02:46 +0000 Subject: [PATCH 13/18] ldapauthenticator GitHub test workflow --- .github/workflows/test.yml | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 51f8d4e..d0f92a8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,8 +19,7 @@ defaults: shell: bash env: - OAUTH2_TOKEN_URL: "token_url" - OAUTH2_USERDATA_URL: "userdata_url" + LDAP_HOST: 127.0.0.1 jobs: # Run "linter" @@ -30,20 +29,10 @@ jobs: steps: - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 with: python-version: 3.8 - - - name: install linter - run: | - pip install --upgrade pip - pip install flake8 - pip freeze - - - name: run lint check - run: | - flake8 oauthenticator + - uses: pre-commit/action@v2.0.0 # Run tests test: @@ -52,7 +41,7 @@ jobs: timeout-minutes: 10 strategy: - # Keep running even if one variation of the job fail + # Keep running even if one job fails fail-fast: false matrix: python: @@ -79,18 +68,19 @@ jobs: restore-keys: | ${{ runner.os }}-pip- - - name: Install Python dependencies + - name: Install run: | pip install --upgrade pip - pip install --upgrade --pre -r test-requirements.txt . + pip install --upgrade --pre -r dev-requirements.txt . pip freeze + # start LDAP server + ci/docker-ldap.sh - name: Run tests # FIXME: --color=yes explicitly set because: # https://github.com/actions/runner/issues/241 - run: | - pytest -v --color=yes --cov=oauthenticator oauthenticator + run: pytest -v --color=yes --cov=ldapauthenticator ldapauthenticator/tests + # https://github.com/marketplace/actions/codecov - name: Submit codecov report - run: | - codecov + uses: codecov/codecov-action@v1 From d1eeaccdb6b032095d83ca4fd2eb837e15419956 Mon Sep 17 00:00:00 2001 From: Simon Li Date: Fri, 11 Dec 2020 13:07:46 +0000 Subject: [PATCH 14/18] Remove travis --- .travis.yml | 73 ----------------------------------------------------- 1 file changed, 73 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index acd4337..0000000 --- a/.travis.yml +++ /dev/null @@ -1,73 +0,0 @@ -dist: bionic -language: python -cache: - - pip -env: - global: - - LDAP_HOST=127.0.0.1 -services: - - docker - -# installing dependencies -before_install: - - set -e -install: - - pip install --upgrade pip - - pip install --upgrade --pre -r dev-requirements.txt . - - pip freeze - - | - # start LDAP server - if [[ -z "$TEST" ]]; then - ci/docker-ldap.sh - fi - -# running tests -script: - - | - # run tests - if [[ -z "$TEST" ]]; then - pytest -v --maxfail=2 --cov=ldapauthenticator ldapauthenticator/tests - fi - - | - # run autoformat - if [[ "$TEST" == "lint" ]]; then - pre-commit run --all-files - fi -after_success: - - codecov -after_failure: - - | - # point to auto-lint-fix - if [[ "$TEST" == "lint" ]]; then - echo "You can install pre-commit hooks to automatically run forma- python: nightly - echo "or you can run by hand on staged files with" - echo " pre-commit run" - echo "or after-the-fact on already committed files with" - echo " pre-commit run --all-files" - fi - -jobs: - allow_failures: - - python: nightly - fast_finish: true - include: - # Default stage: test - - python: 3.6 - env: TEST=lint - - python: 3.6 - - python: 3.7 - - python: 3.8 - - python: nightly - # Only deploy if all test jobs passed - - stage: deploy - python: 3.7 - if: tag IS present - deploy: - provider: pypi - user: __token__ - # password: see secret PYPI_PASSWORD variable - distributions: sdist bdist_wheel - on: - # Without this we get the note about: - # Skipping a deployment with the pypi provider because this branch is not permitted: - tags: true From 8cdf3e90544eb583c7c74d15f97bfafe04d4c10f Mon Sep 17 00:00:00 2001 From: "Bruno P. Kinoshita" Date: Thu, 9 Jul 2020 15:26:23 +1200 Subject: [PATCH 15/18] Fix traitlets warnings when running tests --- ldapauthenticator/ldapauthenticator.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ldapauthenticator/ldapauthenticator.py b/ldapauthenticator/ldapauthenticator.py index 6ddeaf3..f00f7ed 100644 --- a/ldapauthenticator/ldapauthenticator.py +++ b/ldapauthenticator/ldapauthenticator.py @@ -76,7 +76,7 @@ def _server_port_default(self): allowed_groups = List( config=True, allow_none=True, - default=None, + default_value=None, help=""" List of LDAP group DNs that users could be members of to be granted access. @@ -122,7 +122,7 @@ def _server_port_default(self): user_search_base = Unicode( config=True, - default=None, + default_value=None, allow_none=True, help=""" Base for looking up user accounts in the directory, if `lookup_dn` is set to True. @@ -162,7 +162,7 @@ def _server_port_default(self): user_attribute = Unicode( config=True, - default=None, + default_value=None, allow_none=True, help=""" Attribute containing user's name, if `lookup_dn` is set to True. From 4675773d8c073a4ea27a13b00935dc9e3db1f4f4 Mon Sep 17 00:00:00 2001 From: Kota Tsuyuzaki Date: Wed, 13 Jan 2021 15:21:00 +0900 Subject: [PATCH 16/18] Change test ldap server port mapping The port was changed at https://github.com/rroemhild/docker-test-openldap/commit/adb4650727e0123c7c24c7d7ce8609d12384a29b --- ci/docker-ldap.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/docker-ldap.sh b/ci/docker-ldap.sh index 7c140f4..1526f19 100755 --- a/ci/docker-ldap.sh +++ b/ci/docker-ldap.sh @@ -6,7 +6,7 @@ set -e NAME="hub-test-ldap" DOCKER_RUN="docker run -d --name $NAME" -RUN_ARGS="-p 389:389 -p 636:636 rroemhild/test-openldap" +RUN_ARGS="-p 389:10389 -p 636:10636 rroemhild/test-openldap" docker rm -f "$NAME" 2>/dev/null || true From b45ac31fe99a1dd0497b9d82c0269073e6f40bab Mon Sep 17 00:00:00 2001 From: Sarah Gibson <44771837+sgibson91@users.noreply.github.com> Date: Fri, 11 Jun 2021 11:59:52 +0100 Subject: [PATCH 17/18] Add study participation noteice to readme --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index 3849329..cd42bf1 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,20 @@ Simple LDAP Authenticator Plugin for JupyterHub +--- + +Please note that this repository is participating in a study into sustainability +of open source projects. Data will be gathered about this repository for +approximately the next 12 months, starting from 2021-06-11. + +Data collected will include number of contributors, number of PRs, time taken to +close/merge these PRs, and issues closed. + +For more information, please visit +[our informational page](https://sustainable-open-science-and-software.github.io/) or download our [participant information sheet](https://sustainable-open-science-and-software.github.io/assets/PIS_sustainable_software.pdf). + +--- + ## Installation ## You can install it from pip with: From b1dbcbfd1730b25655652184b4f53f091a87a010 Mon Sep 17 00:00:00 2001 From: Sarah Gibson <44771837+sgibson91@users.noreply.github.com> Date: Mon, 14 Jun 2021 11:15:04 +0100 Subject: [PATCH 18/18] Update README.md Co-authored-by: Simon Li --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cd42bf1..626b633 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Data collected will include number of contributors, number of PRs, time taken to close/merge these PRs, and issues closed. For more information, please visit -[our informational page](https://sustainable-open-science-and-software.github.io/) or download our [participant information sheet](https://sustainable-open-science-and-software.github.io/assets/PIS_sustainable_software.pdf). +[the informational page](https://sustainable-open-science-and-software.github.io/) or download the [participant information sheet](https://sustainable-open-science-and-software.github.io/assets/PIS_sustainable_software.pdf). ---