Python の code (正確には Jupyter Notebook)を Web 上でインタラクティブに動作させる環境である Jupyterhub で LDAP 認証が使えるのであるが(つまりマルチユーザで利用可能),LDAP w/o SSL 環境(port #: 389)ではそのままではうまく認証できない,という話.
以下のようなエラーを吐いて,認証しようとするとコケる.
[I 2021-12-11 12:48:55.527 JupyterHub app:2717] Running JupyterHub version 2.0.0
[I 2021-12-11 12:48:55.527 JupyterHub app:2747] Using Authenticator: ldapauthenticator.ldapauthenticator.LDAPAuthenticator-1.3.2
[I 2021-12-11 12:48:55.527 JupyterHub app:2747] Using Spawner: jupyterhub.spawner.LocalProcessSpawner-2.0.0
[I 2021-12-11 12:48:55.527 JupyterHub app:2747] Using Proxy: jupyterhub.proxy.ConfigurableHTTPProxy-2.0.0
[I 2021-12-11 12:48:55.528 JupyterHub app:1641] Writing cookie_secret to /tf/jupyterhub_cookie_secret
[I 2021-12-11 12:48:55.541 alembic.runtime.migration migration:201] Context impl SQLiteImpl.
[I 2021-12-11 12:48:55.541 alembic.runtime.migration migration:204] Will assume non-transactional DDL.
[I 2021-12-11 12:48:55.548 alembic.runtime.migration migration:615] Running stamp_revision -> 833da8570507
[I 2021-12-11 12:48:55.683 JupyterHub proxy:496] Generating new CONFIGPROXY_AUTH_TOKEN
[I 2021-12-11 12:48:55.709 JupyterHub app:1913] Not using allowed_users. Any authenticated user will be allowed.
[I 2021-12-11 12:48:55.727 JupyterHub roles:358] Adding role admin for User: myn
[W 2021-12-11 12:48:55.729 JupyterHub app:2152] No admin role found; assuming hub upgrade. Initializing default roles for all entities
[I 2021-12-11 12:48:55.768 JupyterHub app:2786] Initialized 0 spawners in 0.002 seconds
[W 2021-12-11 12:48:55.769 JupyterHub proxy:687] Running JupyterHub without SSL. I hope there is SSL termination happening somewhere else...
[I 2021-12-11 12:48:55.769 JupyterHub proxy:691] Starting proxy @ http://:8000
12:48:55.921 [ConfigProxy] info: Proxying http://*:8000 to (no default)
12:48:55.934 [ConfigProxy] info: Proxy API at http://127.0.0.1:8001/api/routes
[I 2021-12-11 12:48:56.023 JupyterHub app:3035] Hub API listening on http://0.0.0.0:8081/hub/
[I 2021-12-11 12:48:56.023 JupyterHub app:3037] Private Hub API connect url http://hoge-mydockerimage:8081/hub/
12:48:56.023 [ConfigProxy] info: 200 GET /api/routes
12:48:56.024 [ConfigProxy] info: 200 GET /api/routes
[I 2021-12-11 12:48:56.024 JupyterHub proxy:431] Adding route for Hub: / => http://hoge-mydockerimage:8081
12:48:56.025 [ConfigProxy] info: Adding route / -> http://hoge-mydockerimage:8081
12:48:56.026 [ConfigProxy] info: Route added / -> http://hoge-mydockerimage:8081
12:48:56.026 [ConfigProxy] info: 201 POST /api/routes/
[I 2021-12-11 12:48:56.026 JupyterHub app:3101] JupyterHub is now running at http://:8000
[I 2021-12-11 12:53:41.998 JupyterHub log:189] 302 GET / -> /hub/ (@::ffff:10.8.1.6) 0.61ms
[I 2021-12-11 12:53:42.069 JupyterHub log:189] 302 GET /hub/ -> /hub/login?next=%2Fhub%2F (@::ffff:10.8.1.6) 0.51ms
[I 2021-12-11 12:53:42.240 JupyterHub log:189] 200 GET /hub/login?next=%2Fhub%2F (@::ffff:10.8.1.6) 27.24ms
[E 2021-12-11 12:53:47.996 JupyterHub web:1789] Uncaught exception POST /hub/login?next=%2Fhub%2F (::ffff:10.8.1.6)
HTTPServerRequest(protocol='http', host='hoge:8000', method='POST', uri='/hub/login?next=%2Fhub%2F', version='HTTP/1.1', remote_ip='::ffff:10.8.1.6')
Traceback (most recent call last):
File "/usr/local/lib/python3.8/dist-packages/tornado/web.py", line 1704, in _execute
result = await result
File "/usr/local/lib/python3.8/dist-packages/jupyterhub/handlers/login.py", line 151, in post
user = await self.login_user(data)
File "/usr/local/lib/python3.8/dist-packages/jupyterhub/handlers/base.py", line 788, in login_user
authenticated = await self.authenticate(data)
File "/usr/local/lib/python3.8/dist-packages/jupyterhub/auth.py", line 473, in get_authenticated_user
authenticated = await maybe_future(self.authenticate(handler, data))
File "/usr/local/lib/python3.8/dist-packages/ldapauthenticator/ldapauthenticator.py", line 382, in authenticate
conn = self.get_connection(userdn, password)
File "/usr/local/lib/python3.8/dist-packages/ldapauthenticator/ldapauthenticator.py", line 314, in get_connection
conn = ldap3.Connection(
File "/usr/local/lib/python3.8/dist-packages/ldap3/core/connection.py", line 363, in __init__
self._do_auto_bind()
File "/usr/local/lib/python3.8/dist-packages/ldap3/core/connection.py", line 391, in _do_auto_bind
if self.start_tls(read_server_info=False):
File "/usr/local/lib/python3.8/dist-packages/ldap3/core/connection.py", line 1314, in start_tls
if self.server.tls.start_tls(self) and self.strategy.sync: # for asynchronous connections _start_tls is run by the strategy
File "/usr/local/lib/python3.8/dist-packages/ldap3/core/tls.py", line 277, in start_tls
raise LDAPStartTLSError(connection.last_error)
ldap3.core.exceptions.LDAPStartTLSError: startTLS failed - protocolError
[E 2021-12-11 12:53:48.018 JupyterHub log:181] {
"X-Forwarded-Host": "hoge:8000",
"X-Forwarded-Proto": "http",
"X-Forwarded-Port": "8000",
"X-Forwarded-For": "::ffff:10.8.1.6",
"Accept-Language": "en-US,en;q=0.9,ja;q=0.8",
"Accept-Encoding": "gzip, deflate",
"Referer": "http://hoge:8000/hub/login?next=%2Fhub%2F",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36",
"Content-Type": "application/x-www-form-urlencoded",
"Origin": "http://hoge:8000",
"Upgrade-Insecure-Requests": "1",
"Cache-Control": "max-age=0",
"Content-Length": "34",
"Connection": "close",
"Host": "hoge:8000"
}
[E 2021-12-11 12:53:48.018 JupyterHub log:189] 500 POST /hub/login?next=%2Fhub%2F (@::ffff:10.8.1.6) 23.50ms
12:53:56.029 [ConfigProxy] info: 200 GET /api/routes
Jupyterhub は Docker image として構築していて,Jupyterhub (+ LDAP auth) 関連の Docierfile 該当部は以下.
RUN pip install jupyterhub
RUN pip install jupyterhub-ldapauthenticator
RUN npm install -g configurable-http-proxy
あとは,起動時に
jupyterhub --config=/etc/jupyterhub_config.py
が呼ばれるようになっていて,jupyterhub_config.py
は以下のようなもの.
c.JupyterHub.authenticator_class = "ldapauthenticator.LDAPAuthenticator"
c.LDAPAuthenticator.server_address = "10.0.0.1"
c.LDAPAuthenticator.server_port = 389
c.LDAPAuthenticator.bind_dn_template = "uid={username},ou=People,dc=example,dc=com"
c.LDAPAuthenticator.use_ssl = False
c.JupyterHub.hub_ip = '0.0.0.0'
c.Authenticator.admin_users = {'myn'}
LDAP には SSL 使っていない(ローカル環境なので)のに startTLS
しようとしているように見える.たぶん /usr/local/lib/python3.8/dist-packages/ldapauthenticator/ldapauthenticator.py
の以下の箇所がおかしいような気がしていて,
def get_connection(self, userdn, password):
server = ldap3.Server(
self.server_address, port=self.server_port, use_ssl=self.use_ssl
)
auto_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
)
return conn
ここの箇所で以下の修正をするとうまく動いてくれる.
- ldap3.AUTO_BIND_NO_TLS if self.use_ssl else ldap3.AUTO_BIND_TLS_BEFORE_BIND
+ ldap3.AUTO_BIND_NO_TLS if not self.use_ssl else ldap3.AUTO_BIND_TLS_BEFORE_BIND
Dockerfile 的には以下を書いている.
RUN sed -i 's/ldap3\.AUTO_BIND_NO_TLS if self\.use_ssl/ldap3.AUTO_BIND_NO_TLS if not self.use_ssl/g' /usr/local/lib/python3.*/dist-packages/ldapauthenticator/ldapauthenticator.py