

# Usar ganchos do PostgreSQL com suas extensões TLE
<a name="PostgreSQL_trusted_language_extension.overview.tles-and-hooks"></a>

Um *gancho* é um mecanismo de retorno de chamada disponível no PostgreSQL que possibilita aos desenvolvedores chamar funções personalizadas ou outras rotinas durante operações regulares de banco de dados. O kit de desenvolvimento TLE é compatível com ganchos do PostgreSQL para que você possa integrar funções personalizadas com o comportamento do PostgreSQL no ambiente de execução. Por exemplo, você pode usar um gancho para associar o processo de autenticação ao seu próprio código personalizado ou modificar o processo de planejamento e execução de consultas de acordo com suas necessidades específicas.

Suas extensões TLE podem usar ganchos. Se um gancho tiver escopo global, ele se aplicará a todos os bancos de dados. Portanto, se sua extensão TLE usar um gancho global, você precisará criar sua extensão TLE em todos os bancos de dados que seus usuários puderem acessar.

Ao usar a extensão `pg_tle` para criar seu próprio Trusted Language Extensions, você pode usar os ganchos disponíveis de uma API SQL para criar as funções de sua extensão. Você deve registrar todos os ganchos com `pg_tle`. Para alguns ganchos, talvez você também precise definir vários parâmetros de configuração. Por exemplo, o gancho de verificação `passcode` pode ser configurado como ativado, desativado ou obrigatório. Para obter mais informações sobre os requisitos específicos dos ganchos `pg_tle` disponíveis, consulte [Referência de ganchos para Trusted Language Extensions para PostgreSQL](PostgreSQL_trusted_language_extension-hooks-reference.md). 

## Exemplo: Criar uma extensão que use um gancho do PostgreSQL
<a name="PostgreSQL_trusted_language_extension-example-hook"></a>

O exemplo abordado nesta seção usa um gancho do PostgreSQL para conferir a senha fornecida durante operações específicas de SQL e impede que os usuários do banco de dados definam suas senhas como qualquer uma das contidas na tabela `password_check.bad_passwords`. A tabela contém as dez opções de senhas mais usadas, mas facilmente identificáveis. 

Para configurar esse exemplo em seu cluster de banco de dados do Aurora PostgreSQL, você já deve ter instalado o Trusted Language Extensions. Para obter detalhes, consulte [Configurar o Trusted Language Extensions em seu cluster de banco de dados do Aurora PostgreSQL](PostgreSQL_trusted_language_extension-setting-up.md). 

**Como configurar o exemplo de gancho de verificação de senha**

1. Use o `psql` para se conectar à instância de gravador do cluster de banco de dados do Aurora PostgreSQL. 

   ```
   psql --host=db-instance-123456789012.aws-region.rds.amazonaws.com
   --port=5432 --username=postgres --password --dbname=labdb
   ```

1. Copie o código do [Lista de códigos do gancho de verificação de senha](#PostgreSQL_trusted_language_extension-example-hook_code_listing) e cole-o no banco de dados.

   ```
   SELECT pgtle.install_extension (
     'my_password_check_rules',
     '1.0',
     'Do not let users use the 10 most commonly used passwords',
   $_pgtle_$
     CREATE SCHEMA password_check;
     REVOKE ALL ON SCHEMA password_check FROM PUBLIC;
     GRANT USAGE ON SCHEMA password_check TO PUBLIC;
   
     CREATE TABLE password_check.bad_passwords (plaintext) AS
     VALUES
       ('123456'),
       ('password'),
       ('12345678'),
       ('qwerty'),
       ('123456789'),
       ('12345'),
       ('1234'),
       ('111111'),
       ('1234567'),
       ('dragon');
     CREATE UNIQUE INDEX ON password_check.bad_passwords (plaintext);
   
     CREATE FUNCTION password_check.passcheck_hook(username text, password text, password_type pgtle.password_types, valid_until timestamptz, valid_null boolean)
     RETURNS void AS $$
       DECLARE
         invalid bool := false;
       BEGIN
         IF password_type = 'PASSWORD_TYPE_MD5' THEN
           SELECT EXISTS(
             SELECT 1
             FROM password_check.bad_passwords bp
             WHERE ('md5' || md5(bp.plaintext || username)) = password
           ) INTO invalid;
           IF invalid THEN
             RAISE EXCEPTION 'Cannot use passwords from the common password dictionary';
           END IF;
         ELSIF password_type = 'PASSWORD_TYPE_PLAINTEXT' THEN
           SELECT EXISTS(
             SELECT 1
             FROM password_check.bad_passwords bp
             WHERE bp.plaintext = password
           ) INTO invalid;
           IF invalid THEN
             RAISE EXCEPTION 'Cannot use passwords from the common password dictionary';
           END IF;
         END IF;
       END
     $$ LANGUAGE plpgsql SECURITY DEFINER;
   
     GRANT EXECUTE ON FUNCTION password_check.passcheck_hook TO PUBLIC;
   
     SELECT pgtle.register_feature('password_check.passcheck_hook', 'passcheck');
   $_pgtle_$
   );
   ```

   Quando a extensão for carregada em seu banco de dados, você verá uma saída como a seguinte.

   ```
    install_extension
   -------------------
    t
   (1 row)
   ```

1. Enquanto ainda estiver conectado ao banco de dados, agora você poderá criar a extensão. 

   ```
   CREATE EXTENSION my_password_check_rules;
   ```

1. Você pode confirmar que a extensão foi criada no banco de dados usando o metacomando `psql` a seguir.

   ```
   \dx
                           List of installed extensions
             Name           | Version |   Schema   |                         Description
   -------------------------+---------+------------+-------------------------------------------------------------
    my_password_check_rules | 1.0     | public     | Prevent use of any of the top-ten most common bad passwords
    pg_tle                  | 1.0.1   | pgtle      | Trusted-Language Extensions for PostgreSQL
    plpgsql                 | 1.0     | pg_catalog | PL/pgSQL procedural language
   (3 rows)
   ```

1. Abra outra sessão do terminal para trabalhar com o AWS CLI. Você precisa modificar seu grupo de parâmetros de banco de dados personalizado para ativar o gancho de verificação de senha. Para isso, use o comando [modify-db-parameter-group](https://docs.aws.amazon.com/cli/latest/reference/rds/modify-db-parameter-group.html) da CLI, conforme mostrado no exemplo a seguir.

   ```
   aws rds modify-db-parameter-group \
       --region aws-region \
       --db-parameter-group-name your-custom-parameter-group \
       --parameters "ParameterName=pgtle.enable_password_check,ParameterValue=on,ApplyMethod=immediate"
   ```

   Poderá levar alguns minutos para que a alteração na configuração do grupo de parâmetros tenha efeito. No entanto, esse parâmetro é dinâmico, portanto, você não precisa reiniciar a instância de gravador do cluster de banco de dados do Aurora PostgreSQL para que a configuração tenha efeito.

1. Abra a sessão `psql` e consulte o banco de dados para verificar se o gancho password\$1check foi ativado.

   ```
   labdb=> SHOW pgtle.enable_password_check;
   pgtle.enable_password_check
   -----------------------------
   on
   (1 row)
   ```

O gancho de verificação de senha agora está ativo. É possível testá-lo criando uma função e usando uma das senhas incorretas, conforme mostrado no exemplo a seguir.

```
CREATE ROLE test_role PASSWORD 'password';
ERROR:  Cannot use passwords from the common password dictionary
CONTEXT:  PL/pgSQL function password_check.passcheck_hook(text,text,pgtle.password_types,timestamp with time zone,boolean) line 21 at RAISE
SQL statement "SELECT password_check.passcheck_hook(
    $1::pg_catalog.text, 
    $2::pg_catalog.text, 
    $3::pgtle.password_types, 
    $4::pg_catalog.timestamptz, 
    $5::pg_catalog.bool)"
```

A saída foi formatada para facilitar a leitura.

O exemplo a seguir mostra que o comportamento do metacomando interativo `pgsql` `\password` também é afetado pelo gancho password\$1check. 

```
postgres=> SET password_encryption TO 'md5';
SET
postgres=> \password
Enter new password for user "postgres":*****
Enter it again:*****
ERROR:  Cannot use passwords from the common password dictionary
CONTEXT:  PL/pgSQL function password_check.passcheck_hook(text,text,pgtle.password_types,timestamp with time zone,boolean) line 12 at RAISE
SQL statement "SELECT password_check.passcheck_hook($1::pg_catalog.text, $2::pg_catalog.text, $3::pgtle.password_types, $4::pg_catalog.timestamptz, $5::pg_catalog.bool)"
```

Você poderá descartar essa extensão TLE e desinstalar seus arquivos de origem, se desejar. Para obter mais informações, consulte [Descartar suas extensões TLE de um banco de dadosDescartar suas extensões TLE de um banco de dados](PostgreSQL_trusted_language_extension-creating-TLE-extensions.dropping-TLEs.md). 

### Lista de códigos do gancho de verificação de senha
<a name="PostgreSQL_trusted_language_extension-example-hook_code_listing"></a>

O código de exemplo mostrado aqui define a especificação da extensão TLE `my_password_check_rules`. Quando você copia esse código e o cola em seu banco de dados, o código da extensão `my_password_check_rules` é carregado no banco de dados e o gancho `password_check` é registrado para uso pela extensão.

```
SELECT pgtle.install_extension (
  'my_password_check_rules',
  '1.0',
  'Do not let users use the 10 most commonly used passwords',
$_pgtle_$
  CREATE SCHEMA password_check;
  REVOKE ALL ON SCHEMA password_check FROM PUBLIC;
  GRANT USAGE ON SCHEMA password_check TO PUBLIC;

  CREATE TABLE password_check.bad_passwords (plaintext) AS
  VALUES
    ('123456'),
    ('password'),
    ('12345678'),
    ('qwerty'),
    ('123456789'),
    ('12345'),
    ('1234'),
    ('111111'),
    ('1234567'),
    ('dragon');
  CREATE UNIQUE INDEX ON password_check.bad_passwords (plaintext);

  CREATE FUNCTION password_check.passcheck_hook(username text, password text, password_type pgtle.password_types, valid_until timestamptz, valid_null boolean)
  RETURNS void AS $$
    DECLARE
      invalid bool := false;
    BEGIN
      IF password_type = 'PASSWORD_TYPE_MD5' THEN
        SELECT EXISTS(
          SELECT 1
          FROM password_check.bad_passwords bp
          WHERE ('md5' || md5(bp.plaintext || username)) = password
        ) INTO invalid;
        IF invalid THEN
          RAISE EXCEPTION 'Cannot use passwords from the common password dictionary';
        END IF;
      ELSIF password_type = 'PASSWORD_TYPE_PLAINTEXT' THEN
        SELECT EXISTS(
          SELECT 1
          FROM password_check.bad_passwords bp
          WHERE bp.plaintext = password
        ) INTO invalid;
        IF invalid THEN
          RAISE EXCEPTION 'Cannot use passwords from the common password dictionary';
        END IF;
      END IF;
    END
  $$ LANGUAGE plpgsql SECURITY DEFINER;

  GRANT EXECUTE ON FUNCTION password_check.passcheck_hook TO PUBLIC;

  SELECT pgtle.register_feature('password_check.passcheck_hook', 'passcheck');
$_pgtle_$
);
```