.NET - Trabalhando com propriedades e atributos de arquivos, diretórios e ACL (Access Control List)


A plataforma .NET fornece um conjunto de classes no namespace System.IO que permitem a leitura e escrita síncrona e assíncrona em arquivos e fluxo de dados que são muito usadas no dia a dia de um desenvolvedor para manipular arquivos e diretórios.

A partir da versão 2.0 (estamos na versão 4.0) a plataforma .NET introduziu um novo conjunto de classes no Framework Class Library que permitem trabalhar com Acess Control Lists NTFS. Com isso podemos ter acesso a objetos owners, security descriptors, criar security descriptors, etc. Os recursos que nos permitem realizar tais tarefas estão sob namespace System.Security.AccessControl.

Arquivos e diretórios compartilham certas propriedades que podemos usar para determinar a data de criação do arquivo/diretório, tamanho, data da última modificação, extensão, etc. Estas propriedades podem ser exibidas pela abertura da janela de diálogo Propriedades do arquivo, geralmente feita através do Windows Explorer ou clicando com o botão direito do mouse sobre o arquivo e selecionando a opção Propriedades do menu de contexto.

Usando as classes FileInfo e DirctoryInfo podemos acessar as propriedades e também modificá-las. Apenas para ilustrar vejamos a seguir um exemplo bem simples que exibe informações de um arquivo em uma aplicação VB .NET.

Abra o Visual Basic 2010 Express Edition e crie um novo projeto do tipo Windows Application definindo no formulário form1.vb o seguinte leiaute:

Controles usados no formulário:
  • TextBox - txtArquivo
  • ListBox - lstInfo
  • Button - btnInfo

Defina os seguintes namespaces:

Imports System.IO
Imports System.Security.AccessControl

No evento Click do botão de comando inclua o código que irá exibir as informações do arquivo selecionado:

   Private Sub btnInfo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnInfo.Click
        If Not txtArquivo.Text = String.Empty Then
            Dim file As FileInfo = New FileInfo(txtArquivo.Text)
            lstInfo.Items.Add("Hora de criação  : " & file.CreationTime)
            lstInfo.Items.Add("Nome da pasta    : " & file.DirectoryName)
            lstInfo.Items.Add("Último Acesso    : " & file.LastAccessTime)
            lstInfo.Items.Add("Tamanho Arquivo  : " & file.Length)
            lstInfo.Items.Add("Extensão Arquivo : " & file.Extension)
        End If
    End Sub

Para trabalhar de forma segura com arquivos e diretórios em um sistema de arquivos NTFS (usados pelo Windows XP,2000,Vista, et.) devemos usar o ACL - Access Control List, e para isso usar a classe AccessControl para consultar as informações no sistema de arquivos.

Obs: estas informações podem ser vistas na janela de propriedades do arquivo na aba Segurança:

Quando trabalhamos com aplicações Web o quesito segurança reveste-se de grande importância devido ao ambiente hostil que é a web e por isso precisamos de uma forma segura de acessar as informações no sistema de arquivos.

Vamos criar uma aplicação web usando o Visual Web Developer 2010 Express Edition para obter informações de um arquivo usando o recurso ACL e a classe AccesControl.

Abra o Visual Web Developer 2010 Express Edition e no menu File->New Web Site crie um novo web site com o nome ControleAcesso;

Em seguida vamos incluir um arquivo texto no projeto clicando com o botão direito do mouse sobre o nome do projeto e selecionando Add New Item;

A seguir selecione o template Text File e informe o nome Macoratti.txt e clique em Add;

Vamos usar este arquivo para acessar as informações de segurança e incluir e remover uma regra de acesso.

Para obter informações do ACL para o arquivo texto criado e exibi-las na aplicação web vamos definir na página Defatul.aspx o seguinte leiaute:

Temos apenas dois Buttons uma Label e uma tabela onde iremos exibir as informações da ACL e incluir/remover uma regra de acesso para o arquivo texto.

O código fonte do leiaute acima é dado a seguir:

%@ Page Language="VB" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
</head>
<body>
      <form id="form1" runat="server">
    <div>
        <span class="style2">Proprietário do Arquivo:</span>
              <asp:Label ID="Label1" runat="server" Text="Label" CssClass="style1" />        
        
        <span class="style1">Regras de Acesso:&nbsp;</span>&nbsp;&nbsp;&nbsp;
        <asp:Button ID="Button1" runat="server" Text="Incluir Regra Acesso" 
            Width="139px" />
        <asp:Button ID="Button2" runat="server" Text="Remover Regra Acesso" 
            Width="149px" />
        <br />
        <asp:Table ID="Table1" runat="server" CellPadding="2" GridLines="Both" 
            style="font-weight: 700; color: #0033CC; font-family: 'Trebuchet MS'">
            <asp:TableRow>
                <asp:TableHeaderCell>Tipo Controle</asp:TableHeaderCell>
                <asp:TableHeaderCell>Identidade</asp:TableHeaderCell>
                <asp:TableHeaderCell>Herança</asp:TableHeaderCell>
                <asp:TableHeaderCell>É herdado</asp:TableHeaderCell>
                <asp:TableHeaderCell>Propagação</asp:TableHeaderCell>     
                <asp:TableHeaderCell>Direitos</asp:TableHeaderCell>
            </asp:TableRow>
        </asp:Table>
    </div>
    </form>
</body>
</html>

A seguir vamos definir o código no arquivo Default.aspx.vb. Primeiro declare os namespaces usados:

Imports System.IO
Imports System.Security.AccessControl

No evento Load da página vamos colocar o código para exibir as informações da ACL para o arquivo Macoratti.txt;

 Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        Dim sec As System.Security.AccessControl.FileSecurity = System.IO.File.GetAccessControl(Server.MapPath("Macoratti.txt"))
        Me.Label1.Text = sec.GetOwner(System.Type.GetType("System.Security.Principal.NTAccount")).Value

        Dim auth As AuthorizationRuleCollection = sec.GetAccessRules(True, True, System.Type.GetType("System.Security.Principal.NTAccount"))
        Dim tc As TableCell
        For Each r As FileSystemAccessRule In auth

            Dim tr As New TableRow()

            tc = New TableCell()
            tc.Text = r.AccessControlType.ToString()
            tr.Cells.Add(tc)

            tc = New TableCell()
            tc.Text = r.IdentityReference.Value
            tr.Cells.Add(tc)

            tc = New TableCell()
            tc.Text = r.InheritanceFlags.ToString()
            tr.Cells.Add(tc)

            tc = New TableCell()
            tc.Text = r.IsInherited.ToString()
            tr.Cells.Add(tc)

            tc = New TableCell()
            tc.Text = r.PropagationFlags.ToString()
            tr.Cells.Add(tc)

            tc = New TableCell()
            tc.Text = r.FileSystemRights.ToString()
            tr.Cells.Add(tc)

            Table1.Rows.Add(tr)
        Next

    End Sub

No código acima o método GetOwner do objeto Filesecurity exibe o proprietário associado com o grupo primário para o arquivo .

A coleção AuthorizationRuleCollection possui uma coleção de dados retornada pelo FileSecurity, sendo que através do método GetAccessRules usamos um laço e o objeto FileSystemAccessRule para exibir a informação na tabela.

Abaixo vemos o resultado da execução do web site:

Para incluir uma regra de acesso vamos incluir o código abaixo no evento Click do botão de comando: Incluir Regra Acesso

Protected Sub btnIncluirRegra_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnIncluirRegra.Click
        Dim sec As System.Security.AccessControl.FileSecurity = _
       System.IO.File.GetAccessControl(Server.MapPath("Macoratti.txt"))

        sec.AddAccessRule( _
                 New System.Security.AccessControl.FileSystemAccessRule( _
                          "SP\Macoratti", _
                          System.Security.AccessControl.FileSystemRights.FullControl, _
                          System.Security.AccessControl.AccessControlType.Allow _
                          ) _
                 )

        File.SetAccessControl(Server.MapPath("Macoratti.txt"), sec)

    End Sub

O construtor FileSystemAccessRule usa 3 parâmetros:

O primeiro é o usuário sobre o qual desejamos dar direito (lembre-se que o valor do primeiro parâmetro pode mudar com base no sistema e que precisamos especificar o domínio completo do usuário);

A enumeração FileSystemRight foi usada para especificar o direito dado ao usuário;(No meu exemplo SP\Macoratti)

Depois de executar o código acima veremos o seguinte resultado:

Para remover a regra incluída acima vamos colocar o código abaixo no evento Click do botão de comando : Remover Regra Acesso


    Protected Sub btnRemoverRegra_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnRemoverRegra.Click
        Dim sec As System.Security.AccessControl.FileSecurity = _
         System.IO.File.GetAccessControl(Server.MapPath("Macoratti.txt"))

        sec.RemoveAccessRule( _
                 New System.Security.AccessControl.FileSystemAccessRule( _
                          "SP\Macoratti", _
                          System.Security.AccessControl.FileSystemRights.FullControl, _
                          System.Security.AccessControl.AccessControlType.Allow _
                          ) _
                 )

        File.SetAccessControl(Server.MapPath("Macoratti.txt"), sec)

    End Sub

Usando o método RemoveAccessRule estamos removendo a regra de acesso incluída.

Da mesma forma que fizemos para um arquivo podemos fazer para diretórios, neste caso, podemos aplicar as entradas da Access Control List especificadas pelo objeto DIrectorySecurity.

Abaixo temos um exemplo de código para esta tarefa:

System.Security.AccessControl.DirectorySecurity dSec =   Directory.GetAccessControl("C:/DiretorioTeste");

dSec.AddAccessRule(new System.Security.AccessControl.FileSystemAccessRule(@
  "SP\Macoratti", System.Security.AccessControl.FileSystemRights.FullControl,
  System.Security.AccessControl.AccessControlType.Allow));

Directory.SetAccessControl("C:/DiretorioTeste", dSec);

Apenas para recordar lembramos que existem dois tipos de permissões :

1 - Explícitas - São permissões definidas por padrão quando o objeto é criado pela ação do usuário;

2 - Herdadas - São permissões que se propagam para um objeto de um objeto pai e facilitam a tarefa de gerenciar permissões e asseguram a consistência de permissões entre objetos de um dado container;

Por padrão objetos de um container herdam permissões do container onde foram criados, assim quando criamos uma pasta chamada DiretorioTeste, todas as sub-pastas e arquivos criados nesta pasta herdam a automaticamente as permissões da pasta DiretorioTeste. A pasta DiretorioTeste possui permissões explícitas enquanto que as sub-pastas e os arquivos desta pasta possuem permissões herdadas.

As permissões explícitas possuem precedência sobre as permissões herdadas e dessa forma uma permissão que nega o acesso a um arquivo e foi herdada não impede o acesso ao arquivo se o objeto possui uma permissão explicita que permite o acesso.

Eu sei é apenas ASP .NET, mas eu gosto...

Referências:


José Carlos Macoratti