Search code examples
c#svnwmivisualsvn-server

Visual-SVN Server C# code not properly adding user permissions (version 2.7.2)


Story time! One of our more disgruntled employees decided to upgrade visual svn and modify our web interface a day before his last day. We had the old authentication set up, and it was all working fine. Give this particular applications footprint in the grand scheme we followed the 'if it ain't broke, don't fix it' mantra.

It wasn't broke, and he fixed it...

SO here we are. I found This Question regarding interfacing with Visual SVN with C#, and it looks like he had just copied and pasted the code verbatim from there.

The interface we have is very simple. There is an input box that the user types in the name of there desired repo. Below that is a text area where he/she can add users to have access to the repo. The user lookup is done based off of email address and it hits our active directory. The end result of this is I have the name of the repo I need to create, and the users/SIDs of the people I need to give read/write access to.

Testing this code he pasted in, it seems like the repositories are getting created fine (they show up when I log into the server as an admin). Here is the repo creation code:

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;
}

'repository r' in the method parameters, repository is a class with the following properties:

private int _id;
private string _name;
private System.Nullable<System.DateTime> _deleteAfter;
private EntitySet<UserRepositoryRight> _UserRepositoryRights;

with all the public getters and setters you would expect from a linq to sql generated file. UserRepositoryRight is a table that holds the one (repo) to many (users) relationships.

Like I said, I think this code is fine, since I am seeing the repositories being created.

The next copypasta code is the UpdatePermissions method

static public void UpdatePermissions(string sid, string repository, AccessLevel level, bool isAdmin = false)
{

    //Update SVN
    ManagementClass userClass = new ManagementClass("root\\VisualSVN", "VisualSVN_WindowsAccount", null);
    ManagementClass permClass = new ManagementClass("root\\VisualSVN", "VisualSVN_PermissionEntry", null);
    ManagementClass repoClass = new ManagementClass("root\\VisualSVN", "VisualSVN_Repository", null);

    ManagementObject userObject = userClass.CreateInstance();
    userObject.SetPropertyValue("SID", sid);

    ManagementObject permObject = permClass.CreateInstance();
    permObject.SetPropertyValue("Account", userObject);
    permObject.SetPropertyValue("AccessLevel", level);

    ManagementObject repoObject = repoClass.CreateInstance();
    repoObject.SetPropertyValue("Name", repository);

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

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

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


    //Update in DB
    var db = new DataMapSVNServiceDataContext();
    if (level == AccessLevel.NoAccess) //If we are removing the user
    {
        var output = (db.repositories.Single(r => r.name == repository)).UserRepositoryRights.Single(u => u.User.Sid == sid);
        if (output.isAdmin != null && !((bool)output.isAdmin)) //making sure DB owner isn't ever removed
            db.UserRepositoryRights.DeleteOnSubmit(output);
    }
    if (level == AccessLevel.ReadWrite) //if we are adding the user
    {
        var add = new UserRepositoryRight
        {
            isAdmin = isAdmin,
            User = db.Users.Single(u => u.Sid == sid),
            repository = db.repositories.Single(r => r.name == repository)
        };
        db.UserRepositoryRights.InsertOnSubmit(add);
    }
    db.SubmitChanges();
}

Here everything looks ok, but it does not seem to be carrying over to the repo and adding the user to have ReadWrite (key value is 2) permissions on the created repo. The tail end of the method just saves the data to our websites databases to allow us to interface with it.

So, the root problem is if I create a repo via the web interface here, I get a 403 Forbidden error when trying to access it, but NO errors when creating and deleting it. Can anyone point me in the right direction here?


Solution

  • You should use VisualSVN Server PowerShell cmdlets instead of using the server's WMI provider. The WMI provider of VisualSVN Server can be considered as an internal API. It is not documented and is not intended to be used to build custom applications.

    Old answer

    If you don't get any errors when running the code, I guess that the access rule is set on path <repo>/trunk which simply does not exist in the youngest revision. You can try the script on some fresh testing repository which contains "/trunk" in it's root. Otherwise, you can simply change change the code string inParams["Path"] = "/trunk"; to inParams["Path"] = "/";.

    VisualSVN Server allows you to setup path-based authorization rules on items (files and folders) that don't exist in youngest revision because these items can exist in earlier and newer revisions.