Slide 1

Slide 1 text

Um novo autenticador para o JupyterHub

Slide 2

Slide 2 text

LETICIA PORTELLA /in/leportella @leportella @leleportella leportella.com pizzadedados.com

Slide 3

Slide 3 text

Quem não ama Jupyter notebooks? <3

Slide 4

Slide 4 text

Mas… e se existirem mais pessoas além de mim?

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

JupyterHub HTTP Proxy Hub All icons where obtain on Flaticon

Slide 7

Slide 7 text

JupyterHub HTTP Proxy Hub Authenticator All icons where obtain on Flaticon /hub/

Slide 8

Slide 8 text

JupyterHub HTTP Proxy Hub Authenticator Spawners All icons where obtain on Flaticon /hub/

Slide 9

Slide 9 text

JupyterHub HTTP Proxy Hub Authenticator Spawners All icons where obtain on Flaticon /hub/ /user/

Slide 10

Slide 10 text

JupyterHub HTTP Proxy Hub Authenticator Spawners Database All icons where obtain on Flaticon /hub/ /user/

Slide 11

Slide 11 text

JupyterHub HTTP Proxy Hub Authenticator Spawners Database All icons where obtain on Flaticon /user/ /hub/ Admin /hub/admin

Slide 12

Slide 12 text

JupyterHub HTTP Proxy Hub Authenticator Spawners Database Config.py All icons where obtain on Flaticon /user/ /hub/ Admin /hub/admin

Slide 13

Slide 13 text

JupyterHub HTTP Proxy Hub Authenticator Spawners Database Config.py All icons where obtain on Flaticon /user/ /hub/ Admin /hub/admin

Slide 14

Slide 14 text

JupyterHub Authenticator Options PAM LDAP OAuth FirstUse Dummy

Slide 15

Slide 15 text

JupyterHub Authenticator Options PAM LDAP OAuth FirstUse Dummy

Slide 16

Slide 16 text

JupyterHub Authenticator Options PAM LDAP OAuth FirstUse Dummy Native Authenticator

Slide 17

Slide 17 text

Vamos ver como foi a experiência!

Slide 18

Slide 18 text

Criando um Autenticador / USERNAME + SENHA

Slide 19

Slide 19 text

Criando um Autenticador / USERNAME + SENHA LOGIN HANDLER MÉTODO POST POST

Slide 20

Slide 20 text

Criando um Autenticador / USERNAME + SENHA LOGIN HANDLER AUTHORIZED CLASSE DO AUTHENTICATOR MÉTODO POST POST MÉTODO AUTHENTICATE UNAUTHORIZED

Slide 21

Slide 21 text

Criando um Autenticador from jupyterhub.auth import Authenticator from tornado import gen class NewAuth(Authenticator): # ... @gen.coroutine def authenticate(self, handler, data): if self.can_login: return data['username'] return

Slide 22

Slide 22 text

Vamos mais a fundo?

Slide 23

Slide 23 text

Native Authenticator /SIGNUP USUÁRIA

Slide 24

Slide 24 text

Jupyterhub + Tornado class NewAuth(Authenticator): # ... def get_handlers(self, app): native_handlers = [ (r'/signup', SignUpHandler), ] return native_handlers

Slide 25

Slide 25 text

Jupyterhub + Tornado class SignUpHandler(LocalBase): async def get(self): # … html = self.render_template(‘signup.html’) self.finish(html) async def post(self): user_info = { 'username': self.get_body_argument(‘username’) 'pw': self.get_body_argument(‘pw') } # do stuff… html = self.render_template(‘signup.html’, message='succesful') self.finish(html)

Slide 26

Slide 26 text

Native Authenticator /SIGNUP CRIA NOVA USUÁRIA USUÁRIA ESTÁ DESAUTORIZADA USUÁRIA

Slide 27

Slide 27 text

Native Authenticator /SIGNUP CRIA NOVA USUÁRIA USUÁRIA ESTÁ DESAUTORIZADA USUÁRIA EU PRECISO DE INFORMAÇÃO EXTRA!

Slide 28

Slide 28 text

Criando uma nova usuária from jupyterhub.orm import User

Slide 29

Slide 29 text

Criando uma nova usuária from jupyterhub.orm import User

Slide 30

Slide 30 text

Criando uma nova usuária from .orm import UserInfo class NewAuth(Authenticator): # ... def add_new_table(self): inspector = inspect(self.db.bind) if 'users_info' not in inspector.get_table_names(): UserInfo.__table__.create(self.db.bind)

Slide 31

Slide 31 text

Quer saber mais? SQLBasic Tutorial Adding relationship tables already created on SQLAlchemy

Slide 32

Slide 32 text

Native Authenticator /SIGNUP CRIA NOVA USUÁRIA USUÁRIA ESTÁ DESAUTORIZADA /AUTHORIZE USUÁRIA É AUTORIZADA ADMIN USUÁRIA

Slide 33

Slide 33 text

Native Authenticator /SIGNUP CRIA NOVO USUÁRIO USUÁRIA ESTÁ DESAUTORIZADO / USUÁRIA CONSEGUE ACESSO /AUTHORIZE USUÁRIA É AUTORIZADA ADMIN USUÁRIA USUÁRIA

Slide 34

Slide 34 text

Native Authenticator Features: Cadastro de novos usuários Limpeza de username Bloqueio dinâmico

Slide 35

Slide 35 text

Native Authenticator

Slide 36

Slide 36 text

Native Authenticator Features: Permite troca de senha dos usuários Permite adicionar checks de segurança de senhas Pedido de informações extras no signup 2fa

Slide 37

Slide 37 text

Native Authenticator Features: Bloqueando após múltiplas tentativas falhas de login

Slide 38

Slide 38 text

Bloqueando múltiplas tentativas de login • Usuária tenta logar X vezes ela é bloqueada • Usuária pode tentar de novo depois de X minutos • Usuária tem a contagem zerada quando tem uma tentativa bem sucedida

Slide 39

Slide 39 text

class NewAuth(Authenticator): # ... @gen.coroutine def authenticate(self, handler, data): # pega username e senha… # se não tiver validado… self.add_login_attempt(username) Bloqueando múltiplas tentativas de login

Slide 40

Slide 40 text

Bloqueando múltiplas tentativas de login class NewAuth(Authenticator): def add_login_attempt(self, username): if not self.login_attempts.get(username): self.login_attempts[username] = { 'count': 1, 'time': datetime.now() } else: self.login_attempts[username]['count'] += 1 self.login_attempts[username]['time'] = datetime.now()

Slide 41

Slide 41 text

class NewAuth(Authenticator): # ... @gen.coroutine def authenticate(self, handler, data): # pega username e senha… # antes de validar… if self.is_blocked(username): return Bloqueando múltiplas tentativas de login

Slide 42

Slide 42 text

Bloqueando múltiplas tentativas de login class NewAuth(Authenticator): def is_blocked(self, username): logins = self.login_attempts.get(username) if not logins or logins['count'] < self.allowed_failed_logins: return False if self.can_try_to_login_again(username): return False return True

Slide 43

Slide 43 text

Bloqueando múltiplas tentativas de login class NewAuth(Authenticator): def is_blocked(self, username): logins = self.login_attempts.get(username) if not logins or logins['count'] < self.allowed_failed_logins: return False if self.can_try_to_login_again(username): return False return True PERSONALIZADA!!!

Slide 44

Slide 44 text

Bloqueando múltiplas tentativas de login class NewAuth(Authenticator): def can_try_to_login_again(self, username): login_attempts = self.login_attempts.get(username) if not login_attempts: return True time_last_attempt = datetime.now() - login_attempts['time'] if time_last_attempt.seconds > self.seconds_before_next_try: return True return False

Slide 45

Slide 45 text

Bloqueando múltiplas tentativas de login class NewAuth(Authenticator): def can_try_to_login_again(self, username): login_attempts = self.login_attempts.get(username) if not login_attempts: return True time_last_attempt = datetime.now() - login_attempts['time'] if time_last_attempt.seconds > self.seconds_before_next_try: return True return False PERSONALIZADA!!!

Slide 46

Slide 46 text

Configurações personalizadas?

Slide 47

Slide 47 text

Adicionando configurações personalizadas class NewAuth(Authenticator): # ... allowed_failed_logins = Integer( config=True, default=0, help=("Configures the number of failed attempts a user can have before being blocked.”) )

Slide 48

Slide 48 text

Adicionando configurações personalizadas # jupyter.config c.Authenticator.allowed_failed_logins = 3

Slide 49

Slide 49 text

Native Authenticator Mas trabalho open-source não é só escrever código!

Slide 50

Slide 50 text

E como EU fui parar aqui??

Slide 51

Slide 51 text

E como EU fui parar aqui? Crie um perfil no outreachy.org Seja aceita na primeira etapa de avaliação :) Selecione um projeto que você preenche os requisitos Resolva uma micro-tarefa do projeto Peça ajuda dos mentores! Submita um pull request

Slide 52

Slide 52 text

E como EU fui parar aqui? Preencha o formulário final Aguarde os resultados Seja parte de um time maravilhoso <3

Slide 53

Slide 53 text

Quer saber mais? Report I Report II Report III Report IV Report V Blog post oficial

Slide 54

Slide 54 text

Jupyter <3

Slide 55

Slide 55 text

LETICIA PORTELLA /in/leportella @leportella @leleportella leportella.com pizzadedados.com