8 Identity-Based Access Control - API Security in Action
8 Identity-Based Access Control - API Security in Action
Figura 8.1 Os grupos são adicionados como um novo tipo de assunto. As permis-
sões podem ser atribuídas a usuários individuais ou a grupos. Um usuário pode
ser membro de muitos grupos e cada grupo pode ter muitos membros.
A vantagem dos grupos é que agora você pode atribuir permissões a grupos e cer-
tificar-se de que todos os membros desse grupo tenham permissões consistentes.
Quando um novo engenheiro de software ingressa em sua organização, você pode
simplesmente adicioná-lo ao grupo “engenheiros de software” em vez de ter que
se lembrar de todas as permissões individuais necessárias para realizar seu traba-
lho. E quando eles mudam de emprego, basta removê-los desse grupo e adicioná-
los a um novo.
Grupos UNIX
Outra vantagem dos grupos é que eles podem ser usados para compactar as per-
missões associadas a um objeto em alguns casos. Por exemplo, o sistema de arqui-
vos UNIX armazena permissões para cada arquivo como um simples triplo de per-
missões para o usuário atual, o grupo do usuário e qualquer outra pessoa. Em vez
de armazenar permissões para muitos usuários individuais, o proprietário do ar-
quivo pode atribuir permissões a apenas um único grupo pré-existente, redu-
zindo drasticamente a quantidade de dados que devem ser armazenados para
cada arquivo. A desvantagem dessa compactação é que, se um grupo não existir
com os membros necessários, o proprietário poderá ter que conceder acesso a um
grupo maior do que gostaria.
A implementação de grupos simples é direta. Atualmente na API Natter que você
escreveu, há uma users tabelae uma permissions mesaque atua como uma
ACL que vincula usuários a permissões dentro de um espaço. Para adicionar gru-
pos, você pode primeiro adicionar uma nova tabela para indicar quais usuários
são membros de quais grupos:
Quando o usuário é autenticado, você pode procurar os grupos dos quais o usuá-
rio é membro e adicioná-los como um atributo de solicitação adicional que pode
ser visualizado por outros processos. A Listagem 8.1 mostra como os grupos po-
dem ser pesquisados no authenticate() métododentro UserController de-
pois que o usuário for autenticado com sucesso.
ou você pode criar duas tabelas de permissão separadas e definir uma visualiza-
ção que realize uma união das duas:
DICA Ao criar consultas SQL dinâmicas, certifique-se de usar apenas espaços re-
servados e nunca inclua a entrada do usuário diretamente na consulta que está
sendo criada para evitar ataques de injeção de SQL, que são discutidos no capítulo
2. Alguns bancos de dados suportam tabelas temporárias, que permitem inserir
valores dinâmicos na tabela temporária e, em seguida, executar um SQL JOIN na
tabela temporária em sua consulta. Cada transação vê sua própria cópia da tabela
temporária, evitando a necessidade de gerar consultas dinâmicas.
requireAuthentication(solicitação, resposta);
❹ Falha se nenhuma das permissões para o usuário ou grupos permitir esta ação.
Você pode estar se perguntando por que dividiria a pesquisa dos grupos do usuá-
rio durante a autenticação para usá-los em uma segunda consulta na permissi-
ons tabeladurante o controle de acesso. Em vez disso, seria mais eficiente execu-
tar uma única consulta que verificasse automaticamente os grupos de um usuário
usando uma JOIN ou subconsulta na tabela de associação de grupo, como a
seguinte:
Embora essa consulta seja mais eficiente, é improvável que a consulta extra do
design original se torne um gargalo de desempenho significativo. Mas combinar
as consultas em uma tem uma desvantagem significativa, pois viola as camadas
de autenticação e controle de acesso. Na medida do possível, você deve garantir
que todos os atributos de usuário necessários para decisões de controle de acesso
sejam coletados durante a etapa de autenticação e, em seguida, decidir se a solici-
tação é autorizada usando esses atributos. Como um exemplo concreto de como a
violação dessa camada pode causar problemas, considere o que aconteceria se
você mudasse sua API para usar um armazenamento de usuário externo, como
LDAP (discutido na próxima seção) ou um provedor de identidade OpenID Con-
nect (capítulo 7). Nesses casos,
Para localizar de quais grupos estáticos um usuário é membro no LDAP, você deve
realizar uma pesquisa no diretório para todos os grupos que possuem o nome dis-
tinto desse usuáriocomo um valor de seu member atributo, conforme a Listagem
8.3. Primeiro, você precisa se conectar ao servidor LDAP usando oJava Naming
and Directory Interface (JNDI) ou outra biblioteca cliente LDAP. Os usuários nor-
mais do LDAP geralmente não têm permissão para executar pesquisas, portanto,
você deve usar um JNDI separado InitialDirContext para pesquisar os grupos
de um usuário, configurado para usar um usuário de conexão que tenha as per-
missões apropriadas. Para localizar os grupos em que um usuário está, você pode
usar o seguinte filtro de pesquisa, que localiza todas as groupOfNames entradas
LDAP que contêm o usuário fornecido como membro:
(&(objectClass=groupOfNames)(member=uid=test,dc=example,dc=org))
importar javax.naming.*;
importar javax.naming.directory.*;
importar java.util.*;
while (resultados.temMais()) {
var resultado = resultados.próximo();
groups.add((String) result.getAttributes() ❹
.get("cn").get(0)); ❹
}
diretório.close();
grupos de retorno;
}
Para tornar mais eficiente a pesquisa dos grupos aos quais um usuário pertence,
muitos servidores de diretório oferecem suporte a um atributo virtual na própria
entrada do usuário que lista os grupos dos quais o usuário é membro. O servidor
de diretórios atualiza automaticamente esse atributo à medida que o usuário é
adicionado e removido de grupos (estáticos e dinâmicos). Como esse atributo não
é padrão, ele pode ter nomes diferentes, mas geralmente é chamado isMemberO-
f ou algo semelhante. Verifique a documentação do seu servidor LDAP para ver se
ele fornece esse atributo. Normalmente, é muito mais eficiente ler esse atributo
do que pesquisar os grupos dos quais um usuário faz parte.membrodo.
DICA Se você precisar pesquisar grupos regularmente, pode ser útil armazenar
os resultados em cache por um curto período para evitar pesquisas excessivas no
diretório.
questionário
(&(objectClass=#A)(member=uid=alice,dc=example,dc=com))
qual das seguintes classes de objeto seria inserida na posição marcada como #A
para procurar por grupos estáticos aos quais Alice pertence?
1. group
2. herdOfCats
3. groupOfURLs
4. groupOfNames
5. gameOfThrones
6. murderOfCrows
7. groupOfSubjects
Em princípio, tudo o que você pode realizar com o RBAC pode ser realizado com
grupos, mas na prática existem várias diferenças em como eles são usados, in-
cluindo o seguinte:
O RBAC é quase sempre utilizado como uma forma de controle de acesso obrigató-
rio, sendo as funções descritas e atribuídas por quem controla os sistemas que es-
tão sendo acessados. É muito menos comum permitir que os usuários atribuam
funções a outros usuários da maneira que podem com permissões em abordagens
de controle de acesso discricionário. Em vez disso, é comum colocar um meca-
nismo DAC como OAuth2 (capítulo 7) sobre um sistema RBAC subjacente para que
um usuário com uma função de moderador, por exemplo, possa delegar parte de
suas permissões a terceiros. Alguns sistemas RBAC fornecem aos usuários algum
poder sobre quais funções eles usam ao executar operações de API. Por exemplo,
o mesmo usuário pode enviar mensagens para uma sala de bate-papo como ele
mesmo ou usar sua função de Diretor Financeiro quando deseja postar uma de-
claração oficial. oO modelo RBAC padrão do NIST (Instituto Nacional de Padrões e
Tecnologia) ( http://mng.bz/v9eJ ) inclui uma noção de sessão, na qual um usuário
pode escolher quais de suas funções estão ativas em um determinado momento
ao fazer solicitações de API. Isso funciona de maneira semelhante aos tokens com
escopo no OAuth, permitindo que uma sessão ative apenas um subconjunto das
funções de um usuário, reduzindo o dano se a sessão for comprometida. Dessa
forma, o RBAC também suporta melhor o princípio do menor privilégio do que os
grupos porque um usuário pode agir com apenas um subconjunto de sua autori-
dade total.
Lásão duas abordagens básicas para mapear funções para permissões de nível in-
ferior dentro de sua API. A primeira é eliminar completamente as permissões e,
em vez disso, apenas anotar cada operação em sua API com a função ou funções
que podem chamar essa operação. Nesse caso, você substituiria o requirePer-
mission filtro existentecom um novo requireRole filtroque impôs requisitos de
função em vez disso. Esta é a abordagem adotada no Java Enterprise Edition (Java
EE) e no framework JAX-RS, onde os métodos podem ser anotados com a
@RolesAllowed anotaçãopara descrever quais funções podem chamar aquele
método por meio de uma API, conforme mostrado na Listagem 8.4.
Listagem 8.4 Anotando métodos com papéis em Java EE
importar javax.ws.rs.*;
importar javax.ws.rs.core.*;
importar javax.annotation.security.*; ❶
@PUBLICAR
@RolesAllowed("proprietário") ❸
public Response addMember() { .. }
@PEGUE
@RolesAllowed({"dono", "moderador"}) ❸
public Response listMembers() { .. }
}
Agoraque você definiu como as funções são mapeadas para as permissões, você só
precisa decidir como mapear os usuários para as funções. A abordagem mais co-
mum é definir estaticamente quais usuários (ou grupos) são atribuídos a quais
funções. Essa é a abordagem adotada pela maioria dos servidores de aplicativos
Java EE, que definem arquivos de configuração para listar os usuários e grupos
aos quais devem ser designadas funções diferentes. Você pode implementar o
mesmo tipo de abordagem na API do Natter adicionando uma nova tabela para
mapear usuários para funções em um espaço social. As funções na API do Natter
têm como escopo cada espaço social para que o proprietário de um espaço social
não possa fazer alterações em outro.
DEFINIÇÃO Quando usuários, grupos ou funções estão confinados a um sub-
conjunto de seu aplicativo, isso é conhecido como domínio de segurançaou reino.
A Listagem 8.6 mostra o SQL para criar uma nova tabela para mapear um usuário
em um espaço social para uma função. Abra schema.sql novamente e adicione a
nova definição de tabela ao arquivo. a user_roles mesa, juntamente com a
role_permissions tabela, ocupa o lugar da velha permissions mesa. Na API
do Natter, você restringirá um usuário a ter apenas uma função em um espaço,
para poder adicionar uma restrição de chave primária
no space_id e user_id Campos. Se você quiser permitir mais de uma função,
pode deixar isso de fora e adicionar manualmente um índice nesses campos. Não
se esqueça de conceder permissões ao usuário do banco de dados da API Natter.
Para conceder funções aos usuários, você precisa atualizar os dois locais onde as
permissões são concedidas atualmente dentro da SpaceController classe:
database.updateUnique(
"INSERT INTO user_roles(space_id, user_id, role_id)" +
"VALUES(?, ?, ?)", spaceId, proprietário, "proprietário");
if (!DEFINED_ROLES.contains(role)) { ❶
throw new IllegalArgumentException("role inválido"); ❶
}
database.updateUnique(
"INSERT INTO user_roles(space_id, user_id, role_id)" + ❷
" VALUES(?, ?, ?)", spaceId, userToAdd, função); ❷
resposta.status(200);
retornar novo JSONObject()
.put("nome de usuário", userToAdd)
.put("função", função); ❸
}
SELECT rp.perms
DE role_permissions rp
JOIN user_roles ur
ON ur.role_id = rp.role_id
WHERE ur.space_id = ? E ur.user_id = ?
Pesquisar funções e permissões no banco de dados pode ser caro, mas a imple-
mentação atual repetirá esse trabalho toda vez que o requirePermission fil-
troé chamado, o que pode ocorrer várias vezes durante o processamento de uma
solicitação. Para evitar esse problema e simplificar a lógica, você pode extrair a
pesquisa de permissão em um filtro separado que é executado antes de qualquer
verificação de permissão e armazena as permissões em um atributo de solicita-
ção. A Listagem 8.8 mostra o novo lookupPermissions filtroque executa o ma-
peamento de usuário para função para permissões e, em seguida, requirePer-
mission método atualizado. Ao reutilizar as verificações de permissões existen-
tes, você pode adicionar RBAC sem precisar alterar as regras de controle de
acesso. Abra UserController.java em seu editor e atualize o requirePermissi-
on método para corresponder à listagem.
Agora você precisa adicionar chamadas ao novo filtro para garantir que as per-
missões sejam consultadas. Abra o arquivo Main.java e adicione as seguintes li-
nhas ao main método, antes da definição da postMessage operação:
before("/espaços/:espaçoId/mensagens",
userController::lookupPermissions);
before("/espaços/:espaçoId/mensagens/*",
userController::lookupPermissions);
before("/espaços/:espaçoId/membros",
userController::lookupPermissions);
Se você reiniciar o servidor API, agora poderá adicionar usuários, criar espaços e
adicionar membros usando a nova abordagem RBAC. Todas as verificações de
permissão existentes nas operações da API ainda são aplicadas, só que agora elas
são gerenciadas usando funções em vez de permissão explícitaatribuições.
8.2.4 Funções dinâmicas
Outros sistemas RBAC implementam restrições, como tornar duas funções mutua-
mente exclusivas; um usuário não pode ter as duas funções ao mesmo tempo. Isso
pode ser útil para impor a separação de tarefas, como impedir que um adminis-
trador de sistema também gerencie logs de auditoria para umconfidencialsistema.
questionário
4. Quais das opções a seguir são mais prováveis de se aplicar a papéis do que a
grupos?
1. Os papéis geralmente são maiores que os grupos.
2. As funções geralmente são menores que os grupos.
3. Todas as permissões são atribuídas usando funções.
4. As funções suportam melhor a separação de funções.
5. As funções são mais prováveis de serem específicas do aplicativo.
6. As funções permitem que as permissões sejam atribuídas a usuários
individuais.
5. Para que é usada uma sessão no modelo NIST RBAC? Escolha uma resposta.
1. Para permitir que os usuários compartilhem funções.
2. Para permitir que um usuário deixe seu computador desbloqueado.
3. Para permitir que um usuário ative apenas um subconjunto de suas funções.
4. Para lembrar o nome do usuário e outros atributos de identidade.
5. Para permitir que um usuário acompanhe por quanto tempo eles
trabalharam.
6. Dada a seguinte definição de método
@<anotação aqui>
public Response adminOnlyMethod(String arg);
qual valor de anotação pode ser usado no sistema de funções Java EE e JAX-RS
para restringir o método a ser chamado apenas por usuários com a função
ADMIN?
1. @DenyAll
2. @PermitAll
3. @RunAs("ADMIN")
4. @RolesAllowed("ADMIN")
5. @DeclareRoles("ADMIN")
Para lidar com esses tipos de decisões de controle de acesso dinâmico, uma alter-
nativa ao RBAC foi desenvolvida, conhecida como ABAC: controle de acesso base-
ado em atributos. No ABAC, as decisões de controle de acesso são feitas dinamica-
mente para cada solicitação de API usando coleções de atributos agrupados em
quatro categorias:
Atributos sobre o assunto; ou seja, o usuário que faz a solicitação. Isso pode in-
cluir seu nome de usuário, quaisquer grupos aos quais eles pertençam, como
foram autenticados, quando foram autenticados pela última vez e assim por
diante.
Atributos sobre o recursoou objeto sendo acessado, como o URI do recurso ou
um rótulo de segurança (TOP SECRET, por exemplo).
Atributos sobre a ação que o usuário está tentando executar, como o método
HTTP.
Atributos sobre o ambiente ou contexto em que a operação está ocorrendo. Isso
pode incluir a hora local do dia ou a localização do usuário que executa a ação.
A saída de ABAC é então uma decisão de permitir ou negar, conforme mostrado
na figura 8.3.
Figura 8.3 Em um sistema ABAC, as decisões de controle de acesso são tomadas di-
namicamente com base em atributos que descrevem o assunto, recurso, ação e
ambiente ou contexto da solicitação de API.
pacote com.manning.apisecurityinaction.controller;
importar java.time.LocalTime;
importar java.util.Map;
importar faísca.*;
importar spark.Spark.halt estático;
classe abstrata pública ABACAccessController {
public void applyPolicy(Solicitação de solicitação, Resposta de resposta)
if (!decision.isPermitted()) { ❸
halt(403); ❸
}
}
Qual deve ser a decisão padrão se nenhuma regra de controle de acesso corres-
ponder à solicitação?
Como as decisões conflitantes devem ser resolvidas?
A opção mais segura é negar solicitações por padrão, a menos que seja explicita-
mente permitido por alguma regra de acesso, e dar prioridade às decisões de ne-
gação sobre as decisões de permissão. Isso requer pelo menos uma regra para cor-
responder e decidir permitir a ação e nenhuma regra para decidir negar a ação
para que a solicitação seja permitida. Ao adicionar ABAC em cima de um sistema
de controle de acesso existente para impor restrições adicionais que não podem
ser expressas no sistema existente, pode ser mais simples optar por uma estraté-
gia de permissão padrãoonde as solicitações podem prosseguir se nenhuma regra
ABAC corresponder. Essa é a abordagem que você adotará com a API do Natter,
adicionando regras ABAC adicionais que negam algumas solicitações e permitem
a passagem de todas as outras. Nesse caso, as outras solicitações ainda podem ser
rejeitadas pelas permissões RBAC existentes impostas anteriormente no capítulo.
booleano éPermitido() {
permissão de retorno;
}
}
Para adicionar o mecanismo de regras do Drools ao projeto Natter API, abra o ar-
quivo pom.xml em seu editor e adicione as seguintes dependências à
<dependencies> seção:
<dependência>
<groupId>org.kie</groupId>
<artifactId>kie-api</artifactId>
<version>7.26.0.Final</version>
</dependência>
<dependência>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
<version>7.26.0.Final</version>
</dependência>
<dependência>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>7.26.0.Final</version>
</dependência>
Ao iniciar, o Drools procurará um arquivo chamado kmodule.xml no classpath
que define a configuração. Você pode usar a configuração padrão, então navegue
até a pasta src/main/resources e crie uma nova pasta chamada META-INF em re-
sources. Em seguida, crie um novo arquivo chamado kmodule.xml dentro da
pasta src/main/resource/META-INF com o seguinte conteúdo:
Para consultar as regras para uma decisão, você deve primeiro criar uma nova
sessão KIE e definir uma instância da classe Decision da seção anterior como uma
variável global que as regras podem acessar. Cada regra pode então chamar
o deny () ou permit() métodosneste objeto para indicar se a solicitação deve
ser permitida. Os atributos podem então ser adicionados à memória de trabalho
do Drools usando o insert() métodona sessão. Como o Drools prefere valores
fortemente tipados, você pode agrupar cada conjunto de atributos em uma classe
wrapper simples para distingui-los uns dos outros (descritos brevemente). Final-
mente, ligue session.fireAllRules () para avaliar as regras em relação aos
atributos e, em seguida, verificar o valor da variável de decisão para determinar a
decisão final. Crie um novo arquivo chamado DroolsAccessController.java dentro
da pasta do controlador e adicione o conteúdo da listagem 8.11.
pacote com.manning.apisecurityinaction.controller;
importar java.util.*;
importar org.kie.api.KieServices;
importar org.kie.api.runtime.KieContainer;
public DroolsAccessController() {
this.kieContainer = KieServices.get().getKieClasspathContainer(); ❶
}
@Sobrepor
boolean checkPermitted(Map<String, Object> subject,
Recurso Map<String, Object>,
Ação Map<String, Object>,
Map<String, Object> env) {
sessão.insert(new Assunto(assunto)); ❹
sessão.insert(novo Recurso(recurso)); ❹
sessão.insert(nova Ação(ação)); ❹
session.insert(new Environment(env)); ❹
sessão.fireAllRules(); ❺
return decision.isPermitted(); ❺
} finalmente {
sessão.dispose(); ❻
}
}
}
❸ Crie um objeto Decisão e defina-o como uma variável global chamada “decisão”.
regra "descrição"
quando
condições
então
ações
terminam
A descrição pode ser qualquer string útil para descrever a regra. As condições da
regra correspondem às classes que foram inseridas na memória de trabalho e
consistem no nome da classe seguido por uma lista de restrições entre parênteses.
Nesse caso, como as classes são mapas, você pode usar a this["key"] sintaxe
para corresponder aos atributos dentro do mapa. Para esta regra, você deve veri-
ficar se o método HTTP é DELETE e se o campo hora do timeOfDay atributoestá
fora das horas de trabalho permitidas das 9 às 5. Se a regra corresponder, a ação
da regra chamará o deny() métododa decision variável global. Você pode en-
contrar informações mais detalhadas sobre como escrever as regras do Drools no
site https://drools.org ou no livro Mastering JBoss Drools 6, de Mauricio Salatino,
Mariano De Maio e Esteban Aliverti (Packt, 2016).
pacote com.manning.apisecurityinaction.rules; ❶
import com.manning.apisecurityinaction.controller.
➥ DroolsAccessController.*; ❶
import com.manning.apisecurityinaction.controller.
➥ ABACAccessController.Decision; ❶
decisão de decisão global; ❷
❸ Uma regra tem uma descrição, uma seção quando com padrões e uma seção então
com ações.
Agora que você escreveu uma regra ABAC, pode conectar o método principal para
aplicar suas regras como um Spark before () filtro que é executado antes das
outras regras de controle de acesso. O filtro chamará o enforcePolicy méto-
doherdado do ABACAccessController (listagem 8.9), que preenche os atributos
das requisições. A classe base então chama o checkDecision métododa listagem
8.11, que usará o Drools para avaliar as regras. Abra Main.java em seu editor e
adicione as seguintes linhas ao main() métodologo antes das definições de rota
nesse arquivo:
Reinicie o servidor API e faça algumas solicitações de amostra para ver se a polí-
tica está sendo aplicada e não está interferindo nas verificações de permissão
RBAC existentes. Para verificar se as solicitações DELETE estão sendo rejeitadas
fora do horário comercial, você pode ajustar o relógio do seu computador para
um horário diferente ou ajustar o atributo de ambiente de hora do dia para defi-
nir artificialmente a hora do dia como 23h Abra ABACAccessController .java e al-
terar a definição do timeOfDay atributoComosegue:
envAttrs.put("timeOfDay", LocalTime.now().withHour(23));
Se você tentar fazer qualquer solicitação DELETE para a API, ela será rejeitada:
$ curl -i -X
DELETE \
-u demo:senha https://localhost:4567/spaces/1/messages/1
HTTP/1.1 403 Proibido
...
DICA Não importa se você não implementou nenhum método DELETEna API do
Natter, porque as regras ABAC serão aplicadas antes que a solicitação corres-
ponda a qualquer ponto de extremidade (mesmo que não exista nenhum). A im-
plementação da API Natter no repositório GitHub que acompanha este livro tem
implementações de várias solicitações REST adicionais, incluindo suporte a DE-
LETE, se você quiser experimentá-lo.
Descobriu-se que uma pequena alteração na estrutura do documento feita por ou-
tra equipe fez com que muitas das regras não correspondessem mais, o que per-
mitiu que solicitações inválidas fossem processadas por várias semanas antes que
alguém percebesse. Teria sido bom poder dizer automaticamente quando essas
expressões XPath não poderiam mais corresponder a nenhuma mensagem, mas
devido à flexibilidade do XPath, isso acaba sendo impossível de determinar auto-
maticamente em geral, e todos os nossos testes continuaram usando o formato an-
tigo. Essa anedota mostra a possível desvantagem dos mecanismos flexíveis de
avaliação de política, mas eles ainda são uma maneira muito poderosa de estrutu-
rar a lógica de controle de acesso.
Camada ABAC sobre uma tecnologia de controle de acesso mais simples, como
RBAC. Isso fornece uma estratégia de defesa em profundidade para que um
erro nas regras ABAC não resulte em perda total de segurança.
Implemente testes automatizados de seus endpoints de API para que você seja
alertado rapidamente se uma alteração de política resultar na concessão de
acesso a partes indesejadas.
Certifique-se de que as políticas de controle de acesso sejam mantidas em um
sistema de controle de versão para que possam ser facilmente revertidas, se ne-
cessário. Assegure a revisão adequada de todas as mudanças de política.
Considere quais aspectos da política devem ser centralizados e quais devem ser
deixados para APIs individuais ou agentes de políticas locais. Embora possa ser
tentador centralizar tudo, isso pode introduzir uma camada de burocracia que
pode dificultar as mudanças. No pior dos casos, isso pode violar o princípio do
menor privilégio porque políticas excessivamente amplas são mantidas devido
à sobrecarga de alterá-las.
Meça a sobrecarga de desempenho da avaliação de política ABAC com antece-
dência e frequência.
questionário
Resumo
1.
Uma classe de objeto no LDAP define o esquema de uma entrada de diretório, des-
crevendo quais atributos ele contém.