Nós encontramos uma situação interessante que precisa ser resolvida, e minhas pesquisas acabaram. Por isso, apelo à comunidade SO para obter ajuda.
O problema é o seguinte: precisamos acessar programaticamente um arquivo compartilhado que não esteja em nosso domínio e não esteja em um domínio externo confiável via compartilhamento remoto de arquivos / UNC. Naturalmente, precisamos fornecer credenciais para a máquina remota.
Normalmente, o problema é resolvido de duas maneiras:
- Mapeie o compartilhamento de arquivos como uma unidade e forneça as credenciais naquele momento. Isso geralmente é feito usando o
NET USE
comando ou as funções do Win32 duplicadasNET USE
. - Acesse o arquivo com um caminho UNC como se o computador remoto estivesse no domínio e verifique se a conta sob a qual o programa é executado está duplicada (incluindo senha) na máquina remota como usuário local. Basicamente, aproveite o fato de o Windows fornecer automaticamente as credenciais do usuário atual quando o usuário tentar acessar um arquivo compartilhado.
- Não use o compartilhamento remoto de arquivos. Use FTP (ou algum outro meio) para transferir o arquivo, trabalhe localmente e depois transfira-o novamente.
Por várias e diversas razões, nossos arquitetos de segurança / rede rejeitaram as duas primeiras abordagens. A segunda abordagem é obviamente uma falha de segurança; se o computador remoto estiver comprometido, o computador local está agora em risco. A primeira abordagem é insatisfatória porque a unidade recém-montada é um recurso compartilhado disponível para outros programas no computador local durante o acesso ao arquivo pelo programa. Embora seja possível tornar isso temporário, ainda é um buraco na opinião deles.
Eles estão abertos à terceira opção, mas os administradores de rede remota insistem no SFTP em vez do FTPS, e o FtpWebRequest suporta apenas o FTPS. O SFTP é a opção mais compatível com o firewall e há algumas bibliotecas que eu poderia usar para essa abordagem, mas eu prefiro reduzir minhas dependências, se puder.
Procurei no MSDN um meio gerenciado ou um win32 de usar o compartilhamento remoto de arquivos, mas não consegui encontrar nada útil.
E então pergunto: existe outro caminho? Perdi uma função super-secreta do win32 que faz o que eu quero? Ou devo buscar alguma variante da opção 3?
fonte
Respostas:
A maneira de resolver seu problema é usar uma API do Win32 chamada WNetUseConnection .
Use esta função para conectar-se a um caminho UNC com autenticação, NÃO para mapear uma unidade .
Isso permitirá que você se conecte a uma máquina remota, mesmo que não esteja no mesmo domínio e mesmo que tenha um nome de usuário e senha diferentes.
Depois de usar o WNetUseConnection, você poderá acessar o arquivo por um caminho UNC como se estivesse no mesmo domínio. A melhor maneira é provavelmente através dos compartilhamentos administrativos construídos.
Exemplo: \\ nome_do_computador \ c $ \ arquivos de programas \ Pasta \ arquivo.txt
Aqui está um exemplo de código C # que usa WNetUseConnection.
Observe que, para o NetResource, você deve passar nulo para lpLocalName e lpProvider. O dwType deve ser RESOURCETYPE_DISK. O lpRemoteName deve ser \\ ComputerName.
fonte
WNetUseConnection
ser fechadas manualmente chamandoWNetCancelConnection2
? Ou existe um tempo limite inativo (ou algum outro mecanismo) e não precisamos nos preocupar?Para quem procura uma solução rápida, você pode usar o
NetworkShareAccesser
que escrevi recentemente (com base nesta resposta (muito obrigado!)):Uso:
AVISO: Certifique-se de que
Dispose
oNetworkShareAccesser
nome é chamado (mesmo se o aplicativo travar!); Caso contrário, uma conexão aberta permanecerá no Windows. Você pode ver todas as conexões abertas, abrindo ocmd
prompt e insiranet use
.O código:
fonte
using System.Runtime.InteropServices;
eusing System.ComponentModel;
paraDllImport
eWin32Exception
AFAIK, você não precisa mapear o caminho UNC para uma letra de unidade para estabelecer credenciais para um servidor. Eu costumava usar scripts em lote como:
No entanto, qualquer programa em execução na mesma conta do seu programa ainda poderá acessar tudo o que
username:password
tem acesso. Uma solução possível poderia ser isolar seu programa em sua própria conta de usuário local (o acesso UNC é local para a conta chamadaNET USE
).Nota: O uso de SMB entre domínios não é um bom uso da tecnologia, IMO. Se a segurança é tão importante, o fato de o SMB não ter criptografia é um amortecedor por si só.
fonte
NET USE
, isso pode ser uma abordagem viável. Você tem certeza de que precisamos usar uma conta local? ANET USE
chamada não seria local para a máquina na qual foi chamada? Você me deu um bom caminho de pesquisaEm vez de WNetUseConnection, eu recomendaria NetUseAdd . WNetUseConnection é uma função herdada que foi substituída por WNetUseConnection2 e WNetUseConnection3, mas todas essas funções criam um dispositivo de rede visível no Windows Explorer. NetUseAdd é o equivalente a chamar o uso da rede em um prompt do DOS para autenticar em um computador remoto.
Se você ligar para o NetUseAdd, as tentativas subseqüentes de acessar o diretório deverão ter êxito.
fonte
Embora eu não me conheça, certamente espero que o número 2 esteja incorreto ... Gostaria de pensar que o Windows não fornecerá automaticamente minhas informações de login (menos a minha senha!) A qualquer máquina , muito menos um que não faz parte da minha confiança.
Independentemente disso, você explorou a arquitetura de representação? Seu código será semelhante a este:
Nesse caso, a
token
variável é um IntPtr. Para obter um valor para essa variável, você precisará chamar a função não gerenciada da API do Windows do LogonUser. Uma rápida viagem ao pinvoke.net nos dá a seguinte assinatura:Nome de usuário, domínio e senha devem parecer bastante óbvios. Veja os vários valores que podem ser passados para dwLogonType e dwLogonProvider para determinar o que melhor se adapta às suas necessidades.
Esse código não foi testado, pois não tenho um segundo domínio aqui onde possa verificar, mas espero que isso o coloque no caminho certo.
fonte
Aqui, uma classe POC mínima com todo o cruft removido
Você pode usar diretamente
\\server\share\folder
w /WNetUseConnection
, não há necessidade de removê-lo para\\server
separar apenas antecipadamente.fonte
A maioria dos servidores SFTP também suporta SCP, o que pode ser muito mais fácil de encontrar bibliotecas. Você pode até chamar um cliente existente do seu código, como o pscp incluído no PuTTY .
Se o tipo de arquivo com o qual você está trabalhando for algo simples como um arquivo de texto ou XML, você pode até escrever sua própria implementação de cliente / servidor para manipular o arquivo usando algo como o .NET Remoting ou serviços da Web.
fonte
Eu vi a opção 3 implementada com as ferramentas JScape de uma maneira bastante direta. Você pode tentar. Não é grátis, mas faz o seu trabalho.
fonte
im anexar meu código vb.net com base na referência brian
como usá-lo
fonte
Eu olhei para a MS para encontrar as respostas. A primeira solução supõe que a conta do usuário que está executando o processo do aplicativo tenha acesso à pasta ou unidade compartilhada (Mesmo domínio). Verifique se o seu DNS está resolvido ou tente usar o endereço IP. Simplesmente faça o seguinte:
Se você desejar em diferentes domínios, o .NET 2.0 com credenciais siga este modelo:
fonte