Autenticação e Autorização – um caso interessante…

Há umas 2 semanas tive um desafio interessante para resolver, por isso resolvi postar aqui o “causo”, pois ele é mais comum do que se imagina.

Um cliente em início de projeto possui os usuários no Active Directory (mais de 10.000), porém o AD não tem nenhuma configuração de roles. As roles ficam armazenadas em uma tabela de banco de dados e são gerenciadas por outro sistema. Ou seja, a autenticação é feita em um lugar e a autorização é feita em outro.

Aparentemente esta configuração é mais comum do que se imagina: o AD é usado apenas para usuários e senhas, e outro sistema é usado para a parte de autorização…

O UCM pode usar o AD como diretório de usuários. Isto é feito através de um componente fornecido pela Oracle, e o mapeamento é feito na interface visual:

image

Um Provider é um elemento externo que vai ser usado pelo repositório: um banco de dados, um diretório LDAP, uma ferramenta de conversão, etc. Neste caso, cadastramos o AD como um provider que será usado para autenticação. Você pode ter mais de um LDAP configurado, em ambientes de múltiplos domínios ou para contingência.

O problema aqui é que o provider pede o mapeamento das roles (campo Role Prefix). E, como o AD não tem role configurada, os usuários entrariam no sistema como guest (role padrão para usuários não-autenticados).

Para resolver este problema, temos 3 soluções, da mais para a menos indicada:

1 - Usar um produto da Oracle chamado Virtual Directory. Este produto pode consolidar os dados do AD e do Banco em uma visão consolidada, e expor uma interface LDAP. Desta forma, precisaríamos apenas registrar o Virtual Directory no Content Server como um provider, que não precisaria lidar com a complexidade de duas origens de autenticação.

2 – Customizar o provider para autenticar os usuários no AD, mas ir ao banco de dados para pegar as roles.

3 – Separar as tarefas: Usar o Web Server (Apache, neste caso) para forçar a autenticação dos usuários (usando um plugin chamado mod_ntlm), e mapear o provider no Content Server apenas para trazer as roles.

Neste caso optamos pela opção 2. Na figura acima, repare no campo Provider Class. Este campo se refere à classe Java que irá fazer a comunicação com o AD. É esta classe que precisamos modificar: ldap.ActiveDirectoryLdapProvider

*** DISCLAIMER *** Antes de fazer este tipo de alteração no seu ambiente, entre em contato com o suporte técnico Oracle. O procedimento deste artigo não é oficial e não foi testado apropriadamente. As instruções abaixo tem caráter meramente informativo. Siga estas instruções por sua conta e risco. A Oracle Corporation e o autor deste artigo se isentam de qualquer responsabilidade por problemas causados por esta configuração.

Se você tem um cenário parecido, (e um espírito aventureiro :-)  vamos fazer as modificações no Provider. O ideal é criar um novo componente com base no componente atual (ActiveDirectoryLdapComponent), desta forma preservando o componente original. Para não deixar este post muito longo, vamos pular esta parte e ir direto ao que interessa:

Editando a classe

O ideal é você usar uma IDE de desenvolvimento para editar a classe. No meu caso, o JDeveloper foi a ferramenta escolhida:

image

Para compilar esta classe, você precisa colocar 2 jars no classpath do projeto. Ambos estão na pasta %UCM_HOME%\shared\classes. Os arquivos são: server.zip e classes111.zip.

O método que nos interessa para este caso é o protected Vector retrieveGroups(String dn). Ele recebe como entrada a string dn, que representa o Distinguished Name no AD. Vejamos abaixo as características de um usuário do AD:

image

Para o usuário Denis Abrantes, o Distinguished Name é:

CN=Denis Abrantes,CN=Users,DC=oracle-ecm,DC=br,DC=oracle,DC=com

O método original usa os seguintes comandos:

protected Vector retrieveGroups(String dn)
    throws ServiceException
{
    LdapConnectionInterface con = getLdapConnection();
    Hashtable results = con.read(dn);
    Vector attributes = (Vector)results.get("memberOf");
    if(attributes != null)
        return attributes;
    else
        return new Vector();
}

Basicamente o que ele faz é conectar ao AD e buscar o atributo memberOf. Este atributo é o que contém as roles. O problema é que os nossos usuários do AD não tem roles, logo o atributo memberOf volta em branco. O que precisamos fazer é mudar a lógica, mas neste caso o método retorna um Vetor com a informação no formato do atributo memberOf. Por isso a nossa nova lógica deverá manter o mesmo padrão de string do atributo memberOf. Na imagem abaixo podemos ver as características de um usuário com roles no AD:

image

Podemos ver que cada role está em um atributo memberOf diferente. Este é o motivo pelo qual o método retorna um Vetor, não uma String. A nossa busca precisa montar, para cada role, uma string do seguinte formato:

CN=<<Role>>,OU=Roles,OU=UCM,OU=Oracle,DC=oracle-ecm,DC=br,DC=oracle,DC=com

O nosso código, portanto, ficaria da seguinte forma:

protected Vector retrieveGroups(String dn)
    throws ServiceException
{
    Vector attributes = new Vector();
    String usuariodn = dn.substring(3,dn.indexOf(","));
    String userrole = "";
     try {
      Connection conn;     
      String username = "stellent";
      String password = "*****";
      String thinConn = "jdbc:oracle:thin:@localhost:1521:xe";
      DriverManager.registerDriver(new OracleDriver());
      conn = DriverManager.getConnection(thinConn,username,password);
     
String comando = "select role from empregadoecm where nm_empregado='"+usuariodn+"';
      Statement s = conn.createStatement();
      ResultSet rs= s.executeQuery(comando);
      rs.next();
      while (!rs.isAfterLast())
            {
         userrole = "CN="+rs.getString("role")+",OU=Roles,OU=UCM,OU=Oracle,DC=oracle-cm,DC=br,DC=oracle,DC=com";
         attributes.addElement(userrole);

         rs.next();
     }
     rs.close();
     }
     catch ( SQLException ex ) { } 

    if(attributes != null)
        return attributes;
    else
        return new Vector();
}

Observe as linhas em vermelho. Pegamos o nome do usuário na DN e usamos para buscar as roles deste usuário na tabela empregadoecm. Em seguida, incluimos esta role em uma string e adicionamos ao Vetor que será retornado.

Após compilar esta classe, só precisamos substituir a classe original, na pasta %UCM_HOME%\classes\ldap pela classe modificada e reiniciar o Content Server. Naturalmente o componente de integração com o AD já deverá estar instalado e mapeado no servidor.

Testando a Nova Classe

O usuário denis.abrantes não existe no Content Server, como podemos conferir pela imagem abaixo:

image

No Active Directory ele não possui nenhuma role, e no banco de dados ele possui a role de Gerente. Quando fizermos o login no UCM com este usuário, ele será autenticado no AD e suas roles serão consultadas no banco de dados:

 

image

A partir do login, o usuário passa a existir no Content Server, com os atributos herdados do AD e as roles, do banco:

image

Outros diversos metadados podem ser importados do LDAP e definidos como atributos do usuário: cargo, departamento, email, ramal, etc.

Este exemplo mostra o poder de customização que o Content Server tem: com apenas algumas linhas de código, podemos mudar radicalmente a forma como um login de usuário acontece. Usando recursos como serviços, filtros e triggers, podemos mudar muitos outros comportamentos do servidor, como as rotinas de check-in, busca, workflow, etc.

Mas isso fica para um próximo post…

[]’s

Comments:

Essa ai foi boa cara, até anotei!

Posted by Juliano Albuquerque on Junho 22, 2009 at 12:54 PM BRT #

Olá Denisd, muito boa essa dica. Hoje na empresa temos o segundo cenário descrito mas as roles estão mapeadas no OID. Hoje a nossa autenticação é via NTLM via mod_ntlm em Linux. Temos uma iniciativa de liberar o UCM para acesso externo uma extranet então mudamos a auth para AD resolveria se replicassemos as senhas do AD para OID, mas não optamos por essa solução. No momento que usuário se autentica pelo AD o UCM alterar dois campos na tabela users: duserorgpath e dusersourceorgpath para as informações do AD antes estavam as informações do OID. Você acredita que há um problema nesse sentido? mudar o duserorgpath e dusersourceorgpath para o AD ?

Posted by Raphael Milani on Agosto 24, 2010 at 09:49 AM BRT #

Raphael, na verdade o ideal é alinhar com a consultoria que implementou o UCM na sua empresa, além de confirmar com o Suporte Técnico Oracle se este cenário é suportado. Uma opção que pode ser interessante é criar um novo ambiente para acesso externo, e configurar a replicação entre os dois ambientes, de forma que somente o conteúdo público poderá ser replicado para a instância "extranet".

Posted by Denisd on Agosto 26, 2010 at 04:04 AM BRT #

Olá
Denis,

Implementamos essa solução em nosso UCM ao invés das roles estarem no banco de dados estão no OID, mas as senhas de rede estão no AD.

Agora estamos migrando a restrição de conteudo para Account e acontece qndo usuário se autentica pelo AD as Accounts nao sao sincronizadas para UCM prq obviamente nao existem no OID.
Saberia me dizer como UCM busca as Accounts prq seria a mesma solução que vc descreveu acima.

Abs
Raphael Milani

Posted by Raphael Milani on Setembro 21, 2011 at 09:57 AM BRT #

Post a Comment:
  • HTML Syntax: NOT allowed
About

bocadmin_ww

Search

Categories
Archives
« Abril 2014
SegTerQuaQuiSexSábDom
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    
       
Today