none
Manipulation de Directory et File sur un server distant RRS feed

  • Question

  • Bonjour,

    Je suis en train d'adapter un service windows. cet outils réalise des traitements mais aussi des flux de fichiers.

    Mon client ayant changé son architecture système. Un des serveur avec lequel le service communique est en dehors du domaine.

    Un VPN permanent a été mis en place. J'ai créé les partage sur les répertoires de travail sur le serveur distant.

    Le service est installé sur un des serveur du domaine de mon client. quand j'essaie d'atteindre les répertoires partagés du serveur distant via l'explorateur, il me demande une authentification.

    Ceci est la source de mon problème puisque toutes les fonctions de manipulation de répertoire et de fichier que j'utilise dans mon service n'implémente pas l'authentification.

    Du coup, Directory.Exists par exemple me retourne donc toujours faux.

    Ma question est existe t'il des fonctions dans le framework 4 qui permettent des manipulations de fichier/répertoire sur des répertoires distant nécessitant une authentification?

    Merci


    FB

    vendredi 29 juin 2012 11:36

Réponses

Toutes les réponses

  • Bonjour,

    Il suffit d'utiliser l'emprunt d'identité (c'est à dire de faire en sorte que le bout de code qui accède à votre répertoire fonctionne sur un compte qui dispose des droits).

    Pour cela utilisez la méthode WindowsIdentity.Impersonate(). Voici un article qui explique comment emprunter l'identiter d'un utilisateur dans une application .NET :

    http://blog.mathieu-perrein.net/post/NET-Impersonation-changer-utilisateur-(WindowsIdentity)-a-la-volee.aspx

    Cordialement


    Gilles TOURREAU - MVP C#
    Architecte logiciel/Consultant/Formateur Freelance
    Blog : http://gilles.tourreau.fr
    - MCPD : Enterprise Developper / Windows Developper 3.5 / ASP .NET 3.5/4.0
    - MCITP : SQL Server 2008 Developper
    - MCTS : ADO .NET 3.5 / SQL Server 2008 Developper / Windows Forms 3.5 / ASP .NET 3.5/4.0

    vendredi 29 juin 2012 12:18
    Modérateur
  • Dim p As New Process()
                p.StartInfo.RedirectStandardOutput = False
                p.StartInfo.FileName = "net"
                p.StartInfo.Arguments = "use \\10.10.10.10\SharedFolder /USER:Domaine\User Password /PERSISTENT:YES"
                p.StartInfo.UseShellExecute = True
                Dim rtn As Boolean = p.Start()
                If Not rtn Then
                    Throw New Exception("Mappage plante")
                End If
                If Directory.Exists("\\10.10.10.10\SharedFolder") Then
                    Log(EventLog_S_CatWeb, "Mappage fait!")
                Else
                    Log(EventLog_S_CatWeb, "Mappage Marche po!!!")
                End If

    J'ai essayé ça, tout fonctionne sous winform,

    Mais dans le service windows, le process ne plante pas pourtant Directory.Exists retourne encore faux

    Je vais voir votre solution


    FB





    vendredi 29 juin 2012 13:13
  • Il y a quelque chose que je n'arrive pas à comprendre dans votre solution

    Instancier une nouvelle "impersonation" revient à changer d'utilisateur courant?

    Apres le dispose, revient-on  dans le contexte initial? ou doit on se reloguer compte systeme local?


    FB

    vendredi 29 juin 2012 13:41
  • Imports System.Runtime.InteropServices
    Imports System.Security.Principal
    
    Public Class Impersonation
        Implements IDisposable
        <DllImport("advapi32.dll", SetLastError:=True)> _
        Private Shared Function LogonUser(lpszUsername As String, lpszDomain As String, lpszPassword As String, dwLogonType As Integer, dwLogonProvider As Integer, ByRef phToken As IntPtr) As Boolean
        End Function
    
        Private Const LOGON32_PROVIDER_DEFAULT As Integer = 0
        Private Const LOGON32_LOGON_INTERACTIVE As Integer = 2
    
        Public Event Erreur(ByVal MsgErreur As String)
    
        Private _impersonationContext As WindowsImpersonationContext
        Public Sub New(domain As String, login As String, password As String)
            Try
                Dim tokenHdle As IntPtr = IntPtr.Zero
    
                Dim ret As Boolean = LogonUser(login, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, tokenHdle)
    
                Dim newIdentity As New WindowsIdentity(tokenHdle)
                _impersonationContext = newIdentity.Impersonate()
    
            Catch e As Exception
                RaiseEvent Erreur(e.Message)
            End Try
        End Sub
    
    #Region "IDisposable Membres"
    
        Public Overloads Sub Dispose() Implements IDisposable.Dispose
            _impersonationContext.Undo()
        End Sub
    
    #End Region
    End Class

    Bonjour,

    A priori, la solution ne fonctionne pas...

    au retour de LogonUser, tokenHdle reste à zero et de toute façon ret est à false


    FB


    vendredi 29 juin 2012 15:39
  • Bonjour,

    Le lien suivant pourrait vous être utile : http://msdn.microsoft.com/fr-fr/library/b80a7e92.aspx

    Cordialement.

    vendredi 29 juin 2012 15:50
    Auteur de réponse
  • Désolé non :)

    je l'avais vu, le problème vient de LogonUser

    Je n'ai pas positionner les paramètres comme il faut je pense mais l'aide associée ne m'aide pas beaucoup

                Dim imp As New Impersonation("", "user@Domaine", "pwd")
                ...
                imp.Dispose()


    FB

    vendredi 29 juin 2012 15:53
  • Le code suivant pourrait aussi vous être utile :

     protected void LogonUser()
        {
            IntPtr token = IntPtr.Zero;
            WindowsImpersonationContext impersonatedUser = null;
    
            try
            {
                // Create a token for DomainName\Bob
                // Note: Credentials should be encrypted in configuration file
                bool result = LogonUser("Bob", "DomainName",
                                        "P@ssw0rd",
                                        LogonSessionType.Network,
                                        LogonProvider.Default,
                                        out token);
                if (result)
                {
                    WindowsIdentity id = new WindowsIdentity(token);
                    
                    // Begin impersonation
                    impersonatedUser = id.Impersonate();
                    // Log the new identity
                    Response.Write(String.Format(
                                   "</p>Identity after impersonation: {0}<br>",
                                   WindowsIdentity.GetCurrent().Name));
                    // Resource access here uses the impersonated identity
                }
                else
                {
                    Response.Write("</p>LogonUser failed: " +
                                   Marshal.GetLastWin32Error().ToString());
                }
            }
            catch
            {
                // Prevent any exceptions that occur while the thread is 
                // impersonating from propagating
            }
            finally
            {
                // Stop impersonation and revert to the process identity
                if (impersonatedUser != null)
                    impersonatedUser.Undo();
                // Free the token
                if (token != IntPtr.Zero)
                    CloseHandle(token);
            }

    Cordialement.

    vendredi 29 juin 2012 16:00
    Auteur de réponse
  • Je ne comprends pas.

    LogonUser récursive avec un nombre d'argument différent?

    LogonSessionType.Network et LogonProvider.Default sont déclarés comment?


    FB

    vendredi 29 juin 2012 16:34
  • Voici la classe que j'ai implémentée :

    Imports System.Runtime.InteropServices
    Imports System.Security.Principal
    
    Public Class Impersonation
        Implements IDisposable
        <DllImport("advapi32.dll", SetLastError:=True)> _
        Private Shared Function LogonUser(principal As String, authority As String, password As String, logonType As UInteger, logonProvider As UInteger, ByRef token As IntPtr) As Boolean
        End Function
        <DllImport("kernel32.dll", SetLastError:=True)> _
        Private Shared Function CloseHandle(handle As IntPtr) As Boolean
        End Function
    
        Public Event Erreur(ByVal MsgErreur As String)
    
        Private _impersonationContext As WindowsImpersonationContext
        Public Sub New(domain As String, login As String, password As String)
            Dim tokenHdle As IntPtr = IntPtr.Zero
            Try
    
                Dim ret As Boolean = LogonUser(login, domain, password, 9, 3, tokenHdle)
                If ret Then
                    Dim newIdentity As New WindowsIdentity(tokenHdle)
                    _impersonationContext = newIdentity.Impersonate()
                Else
                    Throw New Exception("Authentification échouée (" & login & ") : " & Marshal.GetLastWin32Error().ToString)
                End If
    
            Catch e As Exception
                RaiseEvent Erreur(e.Message)
            Finally
                If (tokenHdle <> IntPtr.Zero) Then CloseHandle(tokenHdle)
            End Try
        End Sub
    
    #Region "IDisposable Membres"
    
        Public Overloads Sub Dispose() Implements IDisposable.Dispose
            _impersonationContext.Undo()
        End Sub
    
    #End Region
    End Class
    

    Je l'exploite ainsi :

    Dim imp As New Impersonation(ipserveur, user@domaine, password)
    If Directory.Exists("\\ipserveur") Then
      Log(EventLog_S_CatWeb, "Mappage fait!")
    Else
      Log(EventLog_S_CatWeb, "Mappage Marche po!!!")
    End If
    imp.Dispose()
    Directory.Exists me retourne false...

    FB

    vendredi 29 juin 2012 17:28
  • Cette fonction ne fonctionne pas dans mon context.

    Voici ce que j'ai essayé :

     Dim imp As New Impersonation(ipserveur, user@domaine, password)
    If Directory.Exists("\\ipserveur") Then
       Log(EventLog_S_CatWeb, "Mappage fait!")
    Else
       Log(EventLog_S_CatWeb, "Mappage Marche po!!!")
    End If
    imp.Dispose()

    Et voici ma classe Impersonation :

    Imports System.Runtime.InteropServices
    Imports System.Security.Principal
    
    Public Class Impersonation
        Implements IDisposable
        <DllImport("advapi32.dll", SetLastError:=True)> _
        Private Shared Function LogonUser(principal As String, authority As String, password As String, logonType As UInteger, logonProvider As UInteger, ByRef token As IntPtr) As Boolean
        End Function
        <DllImport("kernel32.dll", SetLastError:=True)> _
        Private Shared Function CloseHandle(handle As IntPtr) As Boolean
        End Function
    
        Public Event Erreur(ByVal MsgErreur As String)
    
        Private _impersonationContext As WindowsImpersonationContext
        Public Sub New(domain As String, login As String, password As String)
            Dim tokenHdle As IntPtr = IntPtr.Zero
            Try
    
                Dim ret As Boolean = LogonUser(login, domain, password, 9, 3, tokenHdle)
                If ret Then
                    Dim newIdentity As New WindowsIdentity(tokenHdle)
                    _impersonationContext = newIdentity.Impersonate()
                Else
                    Throw New Exception("Authentification échouée (" & login & ") : " & Marshal.GetLastWin32Error().ToString)
                End If
    
            Catch e As Exception
                RaiseEvent Erreur(e.Message)
            Finally
                If (tokenHdle <> IntPtr.Zero) Then CloseHandle(tokenHdle)
            End Try
        End Sub
    
    #Region "IDisposable Membres"
    
        Public Overloads Sub Dispose() Implements IDisposable.Dispose
            _impersonationContext.Undo()
        End Sub
    
    #End Region
    End Class
    

    La solution présentée au début avec Net use donnait de meilleur résultat. Au moins elle fonctionnait sous Winform...


    FB

    vendredi 29 juin 2012 17:59
  • Je n'ai JAMAIS réussi à mettre en place cette solution, je suis repassé à un flux FTP

    FB

    samedi 7 juillet 2012 13:56