Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
por Robert McMurray
A Microsoft criou um novo serviço FTP que foi completamente reescrito para o Windows Server® 2008. Esse novo serviço FTP incorpora muitos novos recursos que permitem que os autores da Web publiquem conteúdo com mais facilidade do que antes e oferece aos administradores da Web mais opções de segurança e implantação. O novo serviço FTP 7.5 dá suporte à extensibilidade que permite a você estender a funcionalidade interna incluída no serviço FTP. Mais especificamente, o FTP 7.5 dá suporte à criação de sua própria autenticação, diretório base e provedores de log.
Este passo a passo guiará você pelas etapas para usar código gerenciado para um provedor de autenticação FTP que usa a amostra de arquivo XML do seguinte passo a passo para usuários e funções:
Pré-requisitos
Os seguintes itens são necessários para concluir os procedimentos nessa seção:
O IIS 7.0 ou superior deve ser instalado no Windows Server 2008 e o Gerenciador do IIS (Serviços de Informações da Internet) também deve ser instalado.
O novo serviço do FTP 7.5 deve ser instalado.
Para um site, a publicação FTP deve ser habilitada.
Você deve usar o Visual Studio 2008.
Observação
Se você usar uma versão anterior do Visual Studio, algumas das etapas neste passo a passo poderão não estar corretas.
Importante
Para ajudar a melhorar o desempenho das solicitações de autenticação, o serviço FTP armazena em cache as credenciais para logons bem-sucedidos, por padrão, por 15 minutos. Isso significa que, se você alterar a senha no arquivo XML, essa alteração pode não ser refletida pela duração do cache. Para contornar isso, você pode desabilitar o cache de credenciais para o serviço FTP. Para fazer isso, execute as seguintes etapas:
Abra um prompt de comando.
Digite os seguintes comandos:
cd /d "%SystemRoot%\System32\Inetsrv" Appcmd.exe set config -section:system.ftpServer/caching /credentialsCache.enabled:"False" /commit:apphost Net stop FTPSVC Net start FTPSVC
Feche o prompt de comando.
Etapa 1: configurar o ambiente do projeto
Nesta etapa, você vai criar um projeto no Visual Studio 2008 para o provedor de demonstração.
Abra o Microsoft Visual Studio 2008.
Selecione o menu Arquivo, em Novo e em Projeto.
Na caixa de diálogo Novo Projeto:
- Escolha Visual C# como o tipo de projeto.
- Escolha Biblioteca de classes como o modelo.
- Digite FtpXmlAuthentication como o nome do projeto.
- Clique em OK.
Quando o projeto for aberto, adicione um caminho de referência à biblioteca de extensibilidade FTP:
Clique em Projeto e, em seguida, clique em Propriedades de FtpXmlAuthentication.
Clique na guia Caminhos de referência.
Insira o caminho para o assembly de extensibilidade FTP da sua versão do Windows, em que C: é a unidade do sistema operacional.
-Para Windows Server 2008 e Windows Vista:
C:\Windows\assembly\GAC\_MSIL\Microsoft.Web.FtpServer\7.5.0.0\_\_31bf3856ad364e35
-Para Windows 7:C:\Program Files\Reference Assemblies\Microsoft\IIS
Clique em Adicionar pasta.
Adicione uma chave de nome forte ao projeto:
- Clique em Projeto e, em seguida, clique em Propriedades de FtpXmlAuthentication.
- Clique na guia Assinatura .
- Marque a caixa de seleção Assinar o assembly.
- Escolha <Novo...> na caixa suspensa de nome de chave forte.
- Digite FtpXmlAuthenticationKey como o nome do arquivo de chave.
- Se desejar, insira uma senha para o arquivo de chave; caso contrário, desmarque a caixa de seleção Proteger meu arquivo de chave com uma senha.
- Clique em OK.
Opcional: você pode adicionar um evento de build personalizado para adicionar a DLL automaticamente ao GAC (Cache de Assembly Global) em seu computador de desenvolvimento:
Clique em Projeto e, em seguida, clique em Propriedades de FtpXmlAuthentication.
Selecione a guia Eventos de build.
Insira o seguinte na caixa de diálogo Linha de Comando do evento pós-build:
net stop ftpsvc call "%VS90COMNTOOLS%\vsvars32.bat">null gacutil.exe /if "$(TargetPath)" net start ftpsvc
Salvaro projeto.
Etapa 2: criar a classe de extensibilidade
Nesta etapa, você vai implementar a interface de extensibilidade de log para o provedor de demonstração.
Adicione uma referência à biblioteca de extensibilidade FTP para o projeto:
- Clique em Projeto e clique em Adicionar referência.
- Na guia .NET, clique em Microsoft.Web.FtpServer.
- Clique em OK.
Adicione uma referência ao System.Web para o projeto:
- Clique em Projeto e clique em Adicionar referência.
- Na guia .NET, clique em System.Web.
- Clique em OK.
Adicione uma referência ao System.Configuration para o projeto:
- Clique em Projeto e clique em Adicionar referência.
- Na guia .NET, clique em System.Configuration.
- Clique em OK.
Adicione o código para a classe de autenticação:
No Gerenciador de Soluções, clique duas vezes no arquivo Class1.cs.
Remova o código existente.
Cole o código a seguir no editor:
using System; using System.Collections; using System.Collections.Specialized; using System.Collections.Generic; using System.Configuration.Provider; using System.IO; using System.Linq; using System.Text; using System.Xml; using Microsoft.Web.FtpServer; using System.Xml.XPath; // Define the XML authentication provider class. public class FtpXmlAuthentication : BaseProvider, IFtpAuthenticationProvider, IFtpRoleProvider { // Create a string to store the path to the XML file that stores the user data. private static string _xmlFileName; // Create a file system watcher object for change notifications. private static FileSystemWatcher _xmlFileWatch; // Create a dictionary to hold user data. private static Dictionary<string, XmlUserData> _XmlUserData = new Dictionary<string, XmlUserData>( StringComparer.InvariantCultureIgnoreCase); // Override the Initialize method to retrieve the configuration settings. protected override void Initialize(StringDictionary config) { // Retrieve the path to the XML file. _xmlFileName = config["xmlFileName"]; // Test if the path is empty. if (string.IsNullOrEmpty(_xmlFileName)) { // Throw an exception if the path is missing or empty. throw new ArgumentException("Missing xmlFileName value in configuration."); } // Test if the file exists. if (File.Exists(_xmlFileName) == false) { // Throw an exception if the file does not exist. throw new ArgumentException("The specified XML file does not exist."); } try { // Create a file system watcher object for the XML file. _xmlFileWatch = new FileSystemWatcher(); // Specify the folder that contains the XML file to watch. _xmlFileWatch.Path = _xmlFileName.Substring(0, _xmlFileName.LastIndexOf(@"\")); // Filter events based on the XML file name. _xmlFileWatch.Filter = _xmlFileName.Substring(_xmlFileName.LastIndexOf(@"\") + 1); // Filter change notifications based on last write time and file size. _xmlFileWatch.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size; // Add the event handler. _xmlFileWatch.Changed += new FileSystemEventHandler(this.XmlFileChanged); // Enable change notification events. _xmlFileWatch.EnableRaisingEvents = true; } catch (Exception ex) { // Raise an exception if an error occurs. throw new ProviderException(ex.Message); } } // Define the event handler for changes to the XML file. public void XmlFileChanged(object sender, FileSystemEventArgs e) { // Verify that the changed file is the XML data file. if (e.Name.Equals( _xmlFileName.Substring(_xmlFileName.LastIndexOf(@"\") + 1), StringComparison.OrdinalIgnoreCase)) { // Clear the contents of the existing user dictionary. _XmlUserData.Clear(); // Repopulate the user dictionary. ReadXmlDataStore(); } } // Define the AuthenticateUser method. bool IFtpAuthenticationProvider.AuthenticateUser( string sessionId, string siteName, string userName, string userPassword, out string canonicalUserName) { // Define the canonical user name. canonicalUserName = userName; // Validate that the user name and password are not empty. if (String.IsNullOrEmpty(userName) || String.IsNullOrEmpty(userPassword)) { // Return false (authentication failed) if either are empty. return false; } else { try { // Retrieve the user/role data from the XML file. ReadXmlDataStore(); // Create a user object. XmlUserData user; // Test if the user name is in the dictionary of users. if (_XmlUserData.TryGetValue(userName, out user)) { // Perform a case-sensitive comparison on the password. if (String.Compare(user.Password, userPassword, false) == 0) { // Return true (authentication succeeded) if the passwords match. return true; } } } catch (Exception ex) { // Raise an exception if an error occurs. throw new ProviderException(ex.Message); } } // Return false (authentication failed) if authentication fails to this point. return false; } bool IFtpRoleProvider.IsUserInRole( string sessionId, string siteName, string userName, string userRole) { // Validate that the user and role names are not empty. if (String.IsNullOrEmpty(userName) || String.IsNullOrEmpty(userRole)) { // Return false (role lookup failed) if either are empty. return false; } else { try { // Retrieve the user/role data from the XML file. ReadXmlDataStore(); // Create a user object. XmlUserData user; // Test if the user name is in the dictionary of users. if (_XmlUserData.TryGetValue(userName, out user)) { // Loop through the user's roles. foreach (string role in user.Roles) { // Perform a case-insensitive comparison on the role name. if (String.Compare(role, userRole, true) == 0) { // Return true (role lookup succeeded) if the role names match. return true; } } } } catch (Exception ex) { // Raise an exception if an error occurs. throw new ProviderException(ex.Message); } } // Return false (role lookup failed) if role lookup fails to this point. return false; } // Retrieve the user/role data from the XML file. private void ReadXmlDataStore() { // Lock the provider while the data is retrieved. lock (this) { try { // Test if the dictionary already has data. if (_XmlUserData.Count == 0) { // Create an XML document object and load the data XML file XPathDocument xmlDocument = new XPathDocument(_xmlFileName); // Create a navigator object to navigate through the XML file. XPathNavigator xmlNavigator = xmlDocument.CreateNavigator(); // Loop through the users in the XML file. foreach (XPathNavigator node in xmlNavigator.Select("/Users/User")) { // Retrieve a user name. string userName = GetInnerText(node, "UserName"); // Retrieve the user's password. string password = GetInnerText(node, "Password"); // Test if the data is empty. if ((String.IsNullOrEmpty(userName) == false) && (String.IsNullOrEmpty(password) == false)) { // Retrieve the user's roles. string xmlRoles = GetInnerText(node, "Roles"); // Create a string array for the user roles. string[] userRoles = new string[0]; // Test if the user has any roles defined. if (String.IsNullOrEmpty(xmlRoles) == false) { // Split the roles by comma. userRoles = xmlRoles.Split(','); } // Create a user data class. XmlUserData userData = new XmlUserData(password, userRoles); // Store the user data in the dictionary. _XmlUserData.Add(userName, userData); } } } } catch (Exception ex) { // Raise an exception if an error occurs. throw new ProviderException(ex.Message); } } } // Retrieve data from an XML element. private static string GetInnerText(XPathNavigator xmlNode, string xmlElement) { string xmlText = ""; try { // Test if the XML element exists. if (xmlNode.SelectSingleNode(xmlElement) != null) { // Retrieve the text in the XML element. xmlText = xmlNode.SelectSingleNode(xmlElement).Value.ToString(); } } catch (Exception ex) { // Raise an exception if an error occurs. throw new ProviderException(ex.Message); } // Return the element text. return xmlText; } } // Define the user data class. internal class XmlUserData { // Create a private string to hold a user's password. private string _password = ""; // Create a private string array to hold a user's roles. private string[] _roles = new string[0]; // Define the class constructor requiring a user's password and roles array. public XmlUserData(string Password,string[] Roles) { this.Password = Password; this.Roles = Roles; } // Define the password property. public string Password { get { return _password; } set { try { _password = value; } catch (Exception ex) { throw new ProviderException(ex.Message); } } } // Define the roles property. public string[] Roles { get { return _roles; } set { try { _roles = value; } catch (Exception ex) { throw new ProviderException(ex.Message); } } } }
Salve e compile o projeto.
Observação
Se você não tiver usado as etapas opcionais para registrar os assemblies no GAC, será necessário copiar manualmente os assemblies para o computador do IIS e adicionar os assemblies ao GAC usando a ferramenta Gacutil.exe. Para obter mais informações, consulte Gacutil.exe (ferramenta de cache de assembly global).
Etapa 3: adicionar o provedor de demonstração ao FTP
Nesta etapa, você vai adicionar o provedor de demonstração ao serviço FTP e ao site padrão.
Adicionando o arquivo XML
Crie um arquivo XML para os usuários e funções associados:
Cole o seguinte código em um editor de texto:
<Users> <User> <UserName>Alice</UserName> <Password>contoso!</Password> <EMail>alice@contoso.com</EMail> <Roles>Members,Administrators</Roles> </User> <User> <UserName>Bob</UserName> <Password>contoso!</Password> <EMail>bob@contoso.com</EMail> <Roles>Members</Roles> </User> </Users>
Salve o código como "Users.xml" em seu computador. Por exemplo, você pode usar o caminho
C:\Inetpub\XmlSample\Users.xml
.
Observação
Por motivos de segurança, esse arquivo não deve ser armazenado em uma pasta localizada na área de conteúdo do site.
Adicionando o provedor
Determine as informações do assembly para o provedor de extensibilidade:
- No Windows Explorer, abra o caminho
C:\Windows\assembly
, em que C: é a unidade do sistema operacional. - Localize o assembly FtpXmlAuthentication.
- Clique com o botão direito do mouse no assembly e em Propriedades.
- Copie o valor Cultura, por exemplo: Neutro.
- Copie o número de Versão, por exemplo: 1.0.0.0.
- Copie o valor do Token de Chave Pública, por exemplo: 426f62526f636b73.
- Clique em Cancelar.
- No Windows Explorer, abra o caminho
Usando as informações das etapas anteriores, adicione o provedor de extensibilidade à lista global de provedores FTP e configure as opções para o provedor:
No momento, não há nenhuma interface de usuário que permita adicionar propriedades para um módulo de autenticação personalizada. Sendo assim, você terá que usar a seguinte linha de comando:
cd %SystemRoot%\System32\Inetsrv appcmd.exe set config -section:system.ftpServer/providerDefinitions /+"[name='FtpXmlAuthentication',type='FtpXmlAuthentication,FtpXmlAuthentication,version=1.0.0.0,Culture=neutral,PublicKeyToken=426f62526f636b73']" /commit:apphost appcmd.exe set config -section:system.ftpServer/providerDefinitions /+"activation.[name='FtpXmlAuthentication']" /commit:apphost appcmd.exe set config -section:system.ftpServer/providerDefinitions /+"activation.[name='FtpXmlAuthentication'].[key='xmlFileName',value='C:\Inetpub\XmlSample\Users.xml']" /commit:apphost
Observação
O caminho do arquivo especificado no atributo xmlFileName deve corresponder ao caminho onde você salvou o arquivo "Users.xml" no computador anteriormente neste passo a passo.
Adicione o provedor de autenticação personalizada para um site FTP:
- Abra um site FTP no Gerenciador do IIS (Serviços de Informações da Internet).
- Clique duas vezes na Autenticação FTP na janela principal.
- Clique em Provedores personalizados... no painel Ações.
- Verifique FtpXmlAuthentication na lista de provedores.
- Clique em OK.
Adicione uma regra de autorização para o provedor de autenticação:
Clique duas vezes em Regras de autorização FTP na janela principal.
Clique em Adicionar Regra de permissão... no painel Ações.
Você pode adicionar uma das seguintes regras de autorização:
-Para um usuário específico:
- Selecione Usuários especificados na opção de acesso.
- Insira o nome de usuário. Por exemplo, usando a amostra de XML neste passo a passo, você pode inserir "Alice" ou "Bob".
-Para uma função ou grupo:
- Selecione Funções ou grupos de usuários especificados na opção de acesso.
- Insira o nome da função ou grupo. Por exemplo, usando a amostra de XML neste passo a passo, você pode inserir "Membros" ou "Administradores".
-Selecione Leitura e/ou Gravação na opção de Permissões.
Clique em OK.
Resumo
Neste passo a passo, você aprendeu a:
- Criar um projeto no Visual Studio 2008 para um provedor de autenticação FTP personalizada.
- Implementar a interface de extensibilidade para autenticação FTP personalizada.
- Adicionar um provedor de autenticação personalizada ao seu serviço FTP.
Quando os usuários se conectam ao seu site FTP, o serviço FTP tentará autenticar os usuários com seu provedor de autenticação personalizada. Se isso falhar, o serviço FTP usará outros provedores internos ou de autenticação para autenticar usuários.