dotnet, gists, aspnet, csharp comments edit

One of the new ASP.NET MVC 5 features, authentication filters, has dreadfully little documentation. There’s a Visual Studio Magazine article on it, but that basically replicates the AuthorizeAttribute in a different way. It doesn’t really explain much else.

Diving into the source doesn’t tell you too much, either. The context you get in the filter has a little more of an idea about what you should be doing, but… it’s really not enough.

The real magic happens in the ControllerActionInvoker.InvokeAction method. The source shows that the general flow is like this:

  1. MVC action gets selected.
  2. IAuthenticationFilter.OnAuthentication executes.
  3. If there is any result set from OnAuthentication, then IAuthenticationFilter.OnAuthenticationChallenge executes.
  4. IAuthorizationFilter.OnAuthorization executes. (The AuthorizeAttribute.)
  5. If there is any result set from OnAuthorization, then IAuthenticationFilter.OnAuthenticationChallenge executes.
  6. Assuming the user is authenticated/authorized, the controller action executes.
  7. IAuthenticationFilter.OnAuthentication executes.

From the comments in the code, it appears the intent is that you somehow “chain” action results together. I’m not sure what that means, whether there’s a decorator pattern intended or whether the design assumes that authentication challenges would just add specific HTTP headers to the response or what.

However, here’s a simple scenario that I came up with that lets you inject some sort of security challenge into a UI flow using the IAuthenticationFilter.

First, let’s create a custom result type. We’ll use this result as a “flag” in the system to indicate the user needs to be challenged. We’ll derive it from HttpUnauthorizedResult so if, for whatever reason, it “slips through the system,” the user will be denied access.

public class ChallengeResult : HttpUnauthorizedResult
{
  public ChallengeResult(string postAction)
  {
    this.PostAction = postAction;
  }

  public string PostAction { get; private set; }
}

The result stores the location where the user needs to return in order to complete the operation after they’ve been challenged.

Next, let’s create our filter. This filter won’t do anything during the authentication portion of its lifecycle, but it will handle challenges. In this case, it’ll look for our challenge result and take action if the user needs to be challenged.

public class ChallengeFilter : IAuthenticationFilter
{
  public void OnAuthentication(AuthenticationContext filterContext)
  {
    // Do nothing.
  }

  public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
  {
    var result = filterContext.Result as ChallengeResult;
    if (result == null)
    {
      // If it's something other than needing a challenge, move on.
      return;
    }

    // Save the location where the user needs to be returned.
    filterContext.RequestContext.HttpContext.Session["postAction"] = result.PostAction;

    // Send the user to be challenged.
    var helper = new UrlHelper(filterContext.RequestContext);
    var url = helper.Action("Index", "Challenge");
    filterContext.Result = new RedirectResult(url);
  }
}

You’ll notice the filter sends the user to a challenge controller. That’s the controller with the form that requires the user to answer a question or re-enter credentials or whatever. We’ll come back to that in a second. Before we do that, let’s see how we’d consume this filter so we can get challenged.

Here’s what you do in the controller where you need to issue a challenge:

  • Check to see if the user’s authorized. If they are, let the operation proceed.
  • If they’re not…
    • Store any form state you’ll need to complete the operation.
    • Issue the challenge result so the filter can pick it up.

A very, very simple controller might look like this:

public class DoWorkController
{
  public ActionResult Index()
  {
    // Display the view where the user enters
    // data or whatever.
    return View();
  }

  [HttpPost]
  [ActionName("Index")]
  [ValidateAntiForgeryToken]
  public ActionResult IndexNext(Model model)
  {
    // Handle form submission - POST/REDIRECT/GET.
    if (!this.ModelState.IsValid)
    {
      return View(model);
    }

    // Store the data so we can use it in later steps
    // and possibly in the challenge.
    this.Session["data"] = model;
    return this.RedirectToAction("Review");
  }

  public ActionResult Review()
  {
    var model = (Model)this.Session["data"];
    return View(model);
  }

  [HttpPost]
  [ActionName("Review")]
  [ValidateAntiForgeryToken]
  public ActionResult ReviewNext()
  {
    var model = (Model)this.Session["data"];
    var authorized = this.Session["authorized"];

    // Here's where you determine if the user needs to
    // be challenged.
    if (UserNeedsChallenge(model) && authorized == null)
    {
      // On successful challenge, POST back to the Review action.
      return new ChallengeResult(this.Url.Action("Review"));
    }

    // If the user gets here, they're authorized or don't need
    // a challenge. Do the work, clear any authorization status,
    // and issue a confirmation view.
    PerformWork(model);
    this.Session.Remove("authorized");
    return this.RedirectToAction("Confirm");
  }

  public ActionResult Confirm()
  {
    // Display some sort of success message about
    // the operation performed.
    var model = (Model)this.Session["data"];
    return View(model);
  }
}

This is obviously not copy/paste ready for use. There are all sorts of things wrong with that sample, like the fact the session data is never cleared, we don’t have the ability to handle multiple windows running multiple operations at a time, and so on. The idea holds, though – you need to persist the form data somewhere so you can send the user over to be challenged and then resume the operation when you come back. Maybe you can create a service that holds that information in a database; maybe you invent a backing store in session that has a more “keyed” approach so each operation has a unique ID. Whatever it is, the important part is that persistence.

OK, so now we have a custom result, a filter that looks for that result and sends the user to be challenged, and a controller that uses some business logic to determine if the user needs the challenge.

The next piece is the challenge controller. This is the controller that asks the user a question, prompts for credentials, or whatever, and resumes the operation once the user successfully answers.

I won’t put the whole controller in here – that’s up to you. But on successfully answering the question, that’s the tricky bit. If you’re doing things right, you’re not doing anything “important” (deleting records, modifying data) on a GET request, so you will need to issue a POST to the appropriate endpoint. You also have to mark the operation as authorized so the POST to the original controller will skip the challenge.

And don’t forget handling the unauthorized scenario - if the user fails the challenge, you don’t want them to be able to “go back and try again”so you need to clear out all the state related to the operation.

public class ChallengeController : Controller
{
  // Other actions in this controller should take care of
  // running the user through the gamut of questions or
  // challenges. In the end, after the final challenge is
  // verified, you need to resume the transaction.
  [HttpPost]
  [ValidateAntiForgeryToken]
  public ActionResult VerifyAnswer(ChallengeModel challenge)
  {
    if (!this.ModelState.IsValid)
    {
      return this.View(challenge);
    }

    // Remove the POST action. It's make-it-or-break-it time.
    var postAction = this.Session["postAction"].ToString();
    this.Session.Remove("postAction");

    if(!AnswerIsCorrect(challenge.Answer))
    {
      // If the user doesn't make it through all the challenges,
      // clear the data and deny them access.
      this.Session.Remove("authorized");
      this.Session.Remove("data");
      return RedirectToAction("Denied");
    }

    // If they do get the challenge right, authorize the operation
    // and resume where they left off. Send them to a special "success"
    // view with the post action.
    this.Session["authorized"] = true;
    return this.View("Success", postAction);
  }
}

Again, this is not copy/paste ready. It’s just to show you the general premise – if they fail the challenge, you need to remember to clean things up and totally deny access; if they succeed, authorize the challenge and send them on their way.

The final question is in that Success view how to resume the transaction. The easiest way is to issue a very tiny view with a POST action to the original location and auto-submit it via script. That might look something like this:

@model string
@{
  Layout = null;
}
<!DOCTYPE html>
<html><head><title>Successful Authorization</title></head>
<body>
<form method="post" action="@this.Model" id="successform">
@Html.AntiForgeryToken()
<input type="submit" value="Process Transaction" />
</form>
<script>document.getElementById("successform").submit();</script>
</body>
</html>

Nothing too fancy, but works like a charm.

Now when the user succeeds, this form will load up, a POST will be issued back to the original controller doing work, and since the authorization value is set, the user won’t be challenged again – everything will just succeed.

Last thing to do – register that challenge filter in the global filters collection. That way when you issue the challenge result from your controller, the filter will catch it and do the redirect.

public class FilterConfig
{
  public static void RegisterGlobalFilters(GlobalFilterCollection filters)
  {
    filters.Add(new AuthorizeAttribute());
    filters.Add(new HandleErrorAttribute());

    // Add that challenge filter!
    filters.Add(new ChallengeFilter());
  }
}

You’re done! You’re now using the IAuthenticationFilter to issue a challenge to verify a transaction prior to committing it. This is what I see the primary value of the new IAuthenticationFilter as being, though I wish there was a bit more guidance around it.

There’s a huge, huge ton of room for improvement in the stuff I showed you above. Please, please, please do not just copy/paste it into your app and start using it like it’s production-ready. You need to integrate your own business logic for challenging people. You need to make sure people can’t start two different transactions, authorize one, and then complete the other one. You need to protect yourself against all the standard OWASP stuff. What I’ve shown you here is proof-of-concept spike level stuff that probably would have been really difficult to follow if I put in all the bells and whistles. I’ll leave that as an exercise to the reader.

Minor aside: It seems to me that there’s some ambiguity between “authentication” and “authorization” here. The AuthorizeAttribute sort of mixes the two, determining both if the user’s authenticated (they have identified themselves) and, optionally, if the user is in a specific role or has a specific name. The IAuthenticationFilter runs before authorization, which is correct, but with the addition of the ability to challenge built in… it seems that it’s more suited to authorization – I’ve already proved who I am, but I may need to be challenged to elevate my privileges or something, which is an authorization thing.

net comments edit

I just had an interesting unit test failure I haven’t seen before due to DateTime calculation.

The code under test was roughly like this:

public Lifetime GetTokenLifetime(int seconds)
{
  return new Lifetime(DateTime.UtcNow, DateTime.UtcNow.AddSeconds(seconds));
}

The unit test was also pretty straightforward:

[Test]
public GetTokenLifetime_ExpectedLifetime()
{
  var provider = new Provider();
  var lifetime = provider.GetTokenLifetime(120);
  Assert.AreEqual(120, lifetime.Seconds);
}

The test was intermittently failing… and the error pretty much explained why:

Expected: 120
Actual: 120.0000063d

There was just a tiny fraction of a second happening between the first DateTime.UtcNow call and the second DateTime.UtcNow call.

To fix it, I stored the DateTime in a local variable.

public Lifetime GetTokenLifetime(int seconds)
{
  var now = DateTime.UtcNow;
  return new Lifetime(now, now.AddSeconds(seconds));
}

Something to keep in the back of your mind as you’re working with DateTime - or times in general. If you are setting up a date range based on a fixed point, best to store that fixed point somewhere and reuse it.

gaming, xbox comments edit

I haven’t blogged much about games I’m playing recently, so given I’m “between games” at the moment, I figured I’d talk a bit.

Yesterday, after about 172 hours, I finished Skyrim with 1000/1000 achievements. I probably could have finished sooner, but I did spend quite a bit of time building up my various skills and running non-required side missions before getting to the main story. I didn’t get any of the DLC, so the time doesn’t include that.

Back in 2006 I played through Oblivion with a buddy of mine and I don’t remember it being nearly this big. I do remember it being more “grindy” – having to jump a lot to build up stamina, or run everywhere to build up strength. I don’t feel like Skyrim was quite like that, but there was a fair amount of tedium. The alchemy thing – having to make potions – was annoying and tedious. I think there were too many possible combinations of things, too many ingredients. Mining ore to refine into metal ingots that could be fashioned into armor or weapons that you’d then have to improve… yeah, that was pretty tedious, too. But I think the most tedious thing was selling stuff. I had so much stuff to sell and no one had enough money to buy it all. I’d stick it in a chest in my house intending to come back and sell it when I needed money… but I never needed money. I had so much money I couldn’t spend it all. I really wish you could set up sort of a… well, like a consignment deal with the local merchants. Deposit your unwanted stuff in a chest in the shop and over the course of time they’d just take stuff out and put money in.

That’s not to say I didn’t have fun. Skyrim was, for me, incredibly addictive. Just one more mission, just one more quest… and even though a lot of it was sort of the same, I didn’t really get tired of it. If I didn’t have Grand Theft Auto 5 to get to next, I’d go for the DLC on Skyrim.

I played a female orc character, though I spent far too much time getting her to look right considering I play in first person view so I never actually saw her except in a couple of cut scenes after that. I think you had to name your character, too, but they never used her name, or not enough to remember. I think in a couple of ransom notes or something.

What I liked most about Skyrim was how I actually kind of got to know and like (or dislike) some of the NPC characters. Cicero, from the Dark Brotherhood, I hated. I hated him from the first time I met him. He was annoying and whiny. I sold him off to the Blades. The whole battle between the Stormcloaks and the Empire was cool, too – the whole world changes when you decide who to side with and it makes it feel so real and important.

And you could get married in the game, which was neat. I ended up marrying Lydia, my housecarl from Whiterun. It didn’t make sense to me to marry anyone else. She was the first “follower” I got; she was always there and friendly when I went to my house to drop stuff off; and she’s the only real NPC who was totally loyal – she doesn’t stab you in the back or send you on a stupid quest. When I thought about which NPC to marry, it didn’t even occur to me to pick anyone else, like it’d be in-game “cheating” or something. I sort of surprised myself when I felt like that, like it actually mattered somehow, which just speaks to the depth of the game.

Before Skyrim, I ran through Borderlands 2. I got the season pass for that so I’ve run through all the DLC, too, with the exception of this latest “Tiny Tina’s Assault on Dragon Keep.”

I loved the first Borderlands, and this second one didn’t disappoint. Bigger, better, faster, stronger. Great characters, great writing. Some of the Claptrap jokes actually made me laugh out loud and when I think back I still giggle. (“WHY AREN’T YOU LAUGHING? THAT WAS COMING F\^&*ING GOLD!”)

I had intended to play through it co-op with my dad and uncle, but with our various life commitments it was really hard to get together on a consistent basis. In the end, we all ended up playing through on our own, teaming up occasionally for harder battles.

That’s the biggest problem I had with this latest Borderlands. It pretty much assumed you had a group of four people to run through the game with. The harder guys – no way you can beat them on your own. And even some of the DLC was super hard until you really leveled up and were a few levels above the bad guys. I never did kill most of the “Blah the Impossible” or “Blah the Invincible” characters. I got in there with my dad and uncle, we all died enough times that we lost millions, and we still couldn’t kill these guys. I don’t mind a challenge, and I’m a fairly decent player, but it got pretty ridiculous in there. Watching YouTube videos and reading forums for strategy, I wondered where people were getting these full inventories of super-rare weapons, which I have to assume is because they went through the whole rest of the game with the team of people. What about the solo Vault Hunters?

I played through with a couple of different characters, and with one of my characters I played through twice. After all that, plus the DLC, plus the ridiculous challenge in places… it burned me out. I will probably return to it at some point to get through Tiny Tina’s DLC, but it’ll be a bit.

Somewhere in there I played through BioShock Infinite. I liked it, as I liked the rest of the BioShock franchise, but I didn’t feel all blown away by the ending the way many folks did. The game play was fun, the environments very immersive, and I did love the characters. Some of the “jumping onto skyhook lines” stuff got a little frantic. It was a neat idea, but seemed to make it a little more complex than it should have been. I didn’t play through the DLC in that, and I may at some point since they’ll be returning to Rapture, but, again, after GTA5.

personal, blog, gaming comments edit

It’s been a while since I’ve checked in on stuff I do in my off-time, so I figured I’d do a round-up entry to catch up.

Since Phoenix was born it’s been harder to get so-called “free time” to do much. Probably more accurately put: There are a lot of things I like to do, and I have a lot of time to do things if I can involve my toddler, but most of the stuff I want to do isn’t toddler-friendly so I don’t get to do it. I mean, toddlers plus RC helicopters equals disaster.

Jenn’s been helping out a bit trying to get me a bit more time to do stuff on my own. She’ll take Phoe to the zoo or something so I’ll get a chance to pick up some of the activities I used to enjoy but don’t get to as much anymore. What am I up to?

I’m switching up my comic book subscriptions. I’ve had a comic box at Things From Another World for many years and for most of those years I’ve subscribed to the same stuff. I’ve finally started getting caught up on my comic reading (“That 2011 Annual story was great!”) and some of the titles I’ve been subscribing to seem to have jumped the shark, so I’ve been trimming up the list. I’ve canceled Witchblade, The Darkness, and all of my Buffy the Vampire Slayer titles. I’ve been in on those from the beginning, but the stories are feeling played out and stale, and at $3 – $5 a pop, I can find other titles. I’m trying out a couple of new ones like Ten Grand, and I’m keeping Daredevil, Powers, and the myriad Grimm Fairy Tales titles.

I’m getting back into RC helicopters. A few years back I bought the original Blade CX coaxial helicopter from the local hobby shop to start getting into flying. It’s been fun, but I’m not very good at it, and it requires a lot of space with zero wind. Here and there I’ve been upgrading it, adding better blades and so on, but I’ve not really gotten it dialed in. I recently picked up a Blade MSR and a Spektrum DX6i controller and I’m starting to get back into it. The MSR is much smaller so it’s easier to fly indoors, though I still think I need to tweak some of the settings. I’ve also upgraded my Blade CX with a new receiver so I can control both helicopters from the one transmitter. All that, plus I got this monster battery charger so I don’t have the problems getting my batteries properly balanced/charged/stored and I’m good to go.

I’m having fun with frisbee golf. The weather has been really nice this summer so my team at work went to a local course and I played frisbee golf for the first time. I’m not very good, but it’s fun, so I’ve been back a few times since. I picked up a starter kit of discs for myself and one for Jenn. This is something Phoenix can participate in, too – we give her a disc and she throws it all over. (She also runs and fetches your discs after you throw them so you have to watch where they land because they’re not going to stay there long.)

I’m burning hours playing Skyrim. I got Skyrim for Christmas and started playing it a couple months back. That’s a time-sink, right there. It’s kind of relaxing and compelling at the same time. There’s just enough tedium to take my mind off the troubles of the day and enough missions to run that there’s always something to do.

I’m taking online bartending courses. I picked up a membership to Bartending College Online through Groupon a while ago and I’ve had fun watching the videos and learning the various techniques and recipes. I’m not going to quit and go be a bartender, but it’s fun to learn something new that doesn’t have to do with computers.

I haven’t gotten back into electronics with my Snap Circuits yet, but I hope to do that, too. Once it turns to Autumn and the weather goes to crap, frisbee golf will be out and I’ll see about getting into the electronics again. I really enjoy working with them, but about halfway through the exercises that come with the set I realized I don’t have a good grasp of the fundamentals, so I took a pause on it to read a book on the math and basics behind why the components behave the way they do and that’s where I stalled out. It’s not a book you want to read when you’re sleepy, but I think it’s important to understand the basics so I can go beyond what the pre-printed exercises show and maybe make electronic inventions of my own.

I’m trying to migrate my blog to WordPress. Subtext was fun while it lasted, but development on it has pretty much ended and I’d like to be on a supported platform. I honestly thought I’d use my blog as more of a hobby, someplace to try out new code and ideas, but there’s really not any plugin mechanism in Subtext and, while that was the plan, it never came to fruition. Rather than move to another smaller platform and go through the growing pains again (and possible abandonment of the platform) I’m trying to get into WP. That means I have to figure out how to export my content in WP format, though, which isn’t going to be easy.

I’m trying to get my images out of ImageShack. I had a paid account with ImageShack for a year or two to host my images and reduce bandwidth consumption on my hosting provider, but ImageShack randomly deletes or loses images all the time. Like, constantly. Links break, the images disappear… today I found that they’ve “lost” my blog skin images, so my blog doesn’t render right. I’m going to switch to a simpler/lighter-weight skin until I can get that fixed (probably until I move to WordPress – it was time for a change anyway).

vs comments edit

I tried to update to the latest version of NuGet in Visual Studio recently and failed. Miserably. The error I kept getting was:

The process cannot access the file because it is being used by another process.

Totally generic, not even any info about the file being locked.

Looking in the log, I see the following error:

7/29/2013 7:30:36 AM - Install Error : System.IO.IOException: The process cannot access the file because it is being used by another process.
    at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
    at System.IO.__Error.WinIOError()
    at System.IO.File.InternalMove(String sourceFileName, String destFileName, Boolean checkHost)
    at Microsoft.VisualStudio.ExtensionManager.ExtensionManagerService.AtomicallyDeleteFiles(IEnumerable`1 filePaths, Boolean justMarkForDeletion)
    at Microsoft.VisualStudio.ExtensionManager.ExtensionManagerService.DeleteDiscoverableFiles(IInstalledExtension extension)
    at Microsoft.VisualStudio.ExtensionManager.ExtensionManagerService.UninstallInternal(IInstalledExtension extension, Boolean forceDelete)
    at Microsoft.VisualStudio.ExtensionManager.ExtensionManagerService.CommitInstalledAndUninstalledExtensions(IEnumerable`1 installedExtensions, IEnumerable`1 uninstalledExtensions, IEnumerable`1 packComponentChanges)
    at Microsoft.VisualStudio.ExtensionManager.ExtensionManagerService.BeginInstall(IInstallableExtension installableExtension, Boolean perMachine, AsyncOperation asyncOp)
    at Microsoft.VisualStudio.ExtensionManager.ExtensionManagerService.InstallWorker(IInstallableExtension extension, Boolean perMachine, AsyncOperation asyncOp)

Again, no info about which file is locked.

I used ProcMon.exe to figure out the sharing violation was happening on NuGet.pkgdef in the new installation of NuGet. Of course, it was happening at exactly the wrong point in the installation process, so I ended up with 10 or 15 nearly-installed-but-corrupted copies of NuGet.

I’m pretty sure this has to do with our antivirus software holding a lock just a little too long on the file, but who’s to say. I just needed it fixed.

Here’s how I fixed it.

  1. Close all instances of Visual Studio.
  2. Go to your global Visual Studio extensions folder. NuGet doesn’t install in your per-user folder; instead, you’ll see it in Program Files. Something like: C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\Extensions
  3. Look in that folder. You will see a lot of randomly named folders like “sdjfksiov.djd” and so on. Most (if not all) of those are NuGet. You’ll want to be aware of which ones are NuGet and which ones aren’t, particularly if you have other extensions installed. (You can tell if it’s NuGet because it’ll have a bunch of NuGet.*.dll files in there. If you don’t see NuGet stuff in there, you’ll want to keep it.)
  4. Rename that Extensions folder  to something like: C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\Extensions_RENAMED
  5. Download NuGet directly from the Visual Studio extension gallery.
  6. Execute the downloaded NuGet.Tools.vsix file you just downloaded. Don’t do it through Visual Studio. Just double-click the .vsix file to install it.
  7. NuGet should successfully install. As part of that install, it will create the Extensions folder again, so you will once again see C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\Extensions
  8. Open up your renamed extensions folder and move all of the non-NuGet extensions into the new Extensions folder.
  9. Now open Visual Studio. You should see the new version of NuGet installed and working.
  10. You can delete that renamed Extensions folder once you’ve verified everything is working.

I fought with this for a long time. Enough that I corrupted my whole VS install and had to pave my machine and fully reinstall. Hopefully this will help other folks that see the same issue.

One additional note: My local user account isn’t an administrator, but when I need to do admin operations I can provide credentials. This process seems to require you’re actually running as an administrator account. Simply providing credentials to elevate the privileges didn’t work for me.

UPDATE FOR VS 2015 - THIS TRICK MAY OR MAY NOT ALWAYS WORK: After installing VS 2015 RC1 I found this problem started happening with many more extensions besides just NuGet. I’m not sure if VS 2015 extensions install differently or if more extensions have just adopted the way NuGet installs. There’s also the added challenge of add-in dependencies.

For example, the “Powershell Tools” extension immediately had an update after install. I tried this, but found that “Powershell Tools” relies on another add-in also being installed, so having an empty extensions folder doesn’t work. However, after locating the dependencies and making sure those were all in place, I still ended up with the file lock error. I never did find a combination of actions that could work around it.

I effectively can’t update any add-ins after they’re installed in VS 2015 RC1 on the machine with the guilty antivirus software. Installing on a VM without the antivirus software, everything works swimmingly.

UPDATE MAY 8, 2017: After a lot of research I found that this was caused, for me, by the McAfee Endpoint Encryption full-disk encryption product, not the antivirus. The lack of antivirus in my initial tests was a red herring; the VM I tested with also did not have the full-disk encryption product running. This problem was acknowledged as an issue in this McAfee KB article. The solution if this is what’s causing it for you is to tell full-disk encryption to exclude devenv.exe and VSIXInstaller.exe. Note the KB article doesn’t mention VSIXInstaller.exe; that’s an omission in the article.

Here’s a registry snippet to tell McAfee Endpoint Encryption to exclude these files. Once you do that, reboot, and the problem should be solved. I’ve tested this on Windows 7, Windows 2008 Server, and Windows 2012 Server. YMMV; I’m not responsible if your stuff breaks; disclaimer disclaimer disclaimer.

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\MfeEEFF\ExemptedProcesses]
"1"="devenv.exe"
"2"="VSIXInstaller.exe"