Search code examples
c#svnwmivisualsvn-server

How to add permission entries to visual svn server in C#


I have looked at this question and got it working to create a repo and add permissions for a user using the WMI interface. The issue I am running into now is this: if I am trying to update a repo I created and add another user to the repo, it clears out the current use (deletes it entirely from the repo) and just adds the one person.

So, I need to figure out how to do two things:

  1. Add a user to an existing repo
  2. Remove a user from an existing repo

I think once I have that I will be able to figure out the rest of my interactions. I referred to the wof file and found these entries that I believe I need to implement:

class VisualSVN_Repository

[provider("VisualSVNWMIProvider"), dynamic]
class VisualSVN_Repository
    {
    [Description ("Repository name"), key]
    string Name;

    ...
    [implemented] void GetSecurity([in] string Path,
                               [out] VisualSVN_PermissionEntry Permissions[]);
    [implemented] void SetSecurity([in] string Path,
                               [in] VisualSVN_PermissionEntry Permissions[],
                               [in] boolean ResetChildren = false);
}

I am implementing set security like so:

static public void UpdatePermissions(string sid, string repository, AccessLevel level, bool isAdmin = false)
{
    ManagementClass repoClass = new ManagementClass("root\\VisualSVN", "VisualSVN_Repository", null);
     ManagementObject repoObject = repoClass.CreateInstance();
    repoObject.SetPropertyValue("Name", repository);

    ManagementBaseObject inParams =
        repoClass.GetMethodParameters("SetSecurity");

    inParams["Path"] = "/";
    inParams["Permissions"] = new object[] { permObject };

    ManagementBaseObject outParams =
        repoObject.InvokeMethod("SetSecurity", inParams, null);
}

This works, but like I said, only for one user. It seems like it cleans out anything in there and just adds the one user object.

The other method I think I need to interact with is "GetSecurity" which looks like it returns an array of VisualSVN_PermissionEntry

VisualSVN_PermissionEntry

class VisualSVN_PermissionEntry
{
    VisualSVN_Account Account;
    uint32 AccessLevel;
};

So this one has an AccessLevel property and VisualSVN_Account object

VisualSVN_Account (I am using Windows auth, so I would need to use that one)

[provider("VisualSVNWMIProvider"), dynamic, abstract]
class VisualSVN_Account
{
};

class VisualSVN_WindowsAccount : VisualSVN_Account
{
    [key] string SID;
};

So here is where I am lost. I assume I need to call "GetSecurity" and then iterate through those results and add them to an object array of the input parameters for "SetSecurity". I can't seem to get that to work. Some psuedo-code I have played with but am getting various errors (object reference errors mostly):

ManagementBaseObject inSecParams=
        repoClass.GetMethodParameters("GetSecurity");

    inSecParams["Path"] = "/";

ManagementBaseObject existingPerms =
        repoObject.InvokeMethod("GetSecurity");

//now I need to loop through the array existingPerms and add them to an array of VisualSVN_PermissionEntry object.

--or--
//can I take this result and just add the users I need to add to it somehow.

Solution

  • I got this awhile ago from someone at visualSVN, figured I should paste the working solution in!

    Here is the whole class file that handles creation, and repository rights assignments:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Diagnostics;
    using System.IO;
    using System.Management;
    
    public static class SVNManager
    {
        public enum AccessLevel : uint
        {
            NoAccess = 0, ReadOnly, ReadWrite
        }
    
        private static ManagementObject GetRepositoryObject(string name)
        {
            return new ManagementObject("root\\VisualSVN", string.Format("VisualSVN_Repository.Name='{0}'", name), null);
        }
    
        private static ManagementObject GetPermissionObject(string sid, AccessLevel accessLevel)
        {
            var accountClass = new ManagementClass("root\\VisualSVN",
                                               "VisualSVN_WindowsAccount", null);
            var entryClass = new ManagementClass("root\\VisualSVN",
                                             "VisualSVN_PermissionEntry", null);
            var account = accountClass.CreateInstance();
            account["SID"] = sid;
            var entry = entryClass.CreateInstance();
            entry["AccessLevel"] = accessLevel;
            entry["Account"] = account;
            return entry;
        }
    
        private static IDictionary<string, AccessLevel> GetPermissions(string repositoryName, string path)
        {
            var repository = GetRepositoryObject(repositoryName);
            var inParameters = repository.GetMethodParameters("GetSecurity");
            inParameters["Path"] = path;
            var outParameters = repository.InvokeMethod("GetSecurity", inParameters, null);
    
            var permissions = new Dictionary<string, AccessLevel>();
    
            foreach (var p in (ManagementBaseObject[])outParameters["Permissions"])
            {
                // NOTE: This will fail if VisualSVN Server is configured to use Subversion
                // authentication.  In that case you'd probably want to check if the account
                // is a VisualSVN_WindowsAccount or a VisualSVN_SubversionAccount instance
                // and tweak the property name accordingly.
    
                var account = (ManagementBaseObject)p["Account"];
                var sid = (string)account["SID"];
                var accessLevel = (AccessLevel)p["AccessLevel"];
    
                permissions[sid] = accessLevel;
            }
    
            return permissions;
        }
    
        private static void SetPermissions(string repositoryName, string path, IDictionary<string, AccessLevel> permissions)
        {
            var repository = GetRepositoryObject(repositoryName);
    
            var inParameters = repository.GetMethodParameters("SetSecurity");
        inParameters["Path"] = path;
    
            var permissionObjects = permissions.Select(p => GetPermissionObject(p.Key, p.Value));
            inParameters["Permissions"] = permissionObjects.ToArray();
    
            repository.InvokeMethod("SetSecurity", inParameters, null);
        }
    
        /// <summary>
        /// Will execute the commands needed to create a repository on the SVN server
        /// </summary>
        /// <param name="r">Object with the repository name.</param>
        /// <returns>True if creation was successful, False if there was a failure.</returns>
        static public bool CreateRepository(repository r)
        {
            ManagementClass repoClass = new ManagementClass("root\\VisualSVN", "VisualSVN_Repository", null);
            // Obtain in-parameters for the method
            ManagementBaseObject inParams = repoClass.GetMethodParameters("Create");
    
    
            // Add the input parameters.
            inParams["Name"] = r.name;
    
            // Execute the method and obtain the return values.
            ManagementBaseObject outParams =
                repoClass.InvokeMethod("Create", inParams, null);
    
            return true;
        }
    }
    

    I think that was all the relevant code. If you see anything missing let me know and I can double check the project (it's been a month, I forgot most of this)