17

I am trying to work out why attribute based security isn't working as I'd expect in WCF and I suspect it might have something to do with the following:

AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);

var identity = new WindowsIdentity("ksarfo");
var principal = new WindowsPrincipal(identity);
Console.WriteLine("\nChecking whether current user [" + identity.Name + "] is member of [" + groupName + "]");
Console.WriteLine(principal.IsInRole(groupName)); // returns true

principal = (WindowsPrincipal)Thread.CurrentPrincipal;
identity = (WindowsIdentity) principal.Identity;
Console.WriteLine("\nChecking whether current user [" + identity.Name + "] is member of [" + groupName + "]");
Console.WriteLine(principal.IsInRole(groupName)); // returns false

I don't understand why the results differ for the function call:

principal.IsInRole(groupName)

For the sake of completeness the point at which the code actually fails is here:

PrincipalPermission(SecurityAction.Demand, Role = "PortfolioManager")]

Help appreciated.

Kofi Sarfo
  • 3,310
  • 6
  • 23
  • 24
  • I'm not very familiar with that class, but I wonder if comparing .Token property of the two identities would show a difference? Is one a local system account and the other a network account...something like that. – Greg Dec 30 '10 at 14:43
  • Thanks Greg. The token is a "handle of the access token associated with the current execution thread" - they do differ. Not sure what that means other than they have different pointers. Each time the code runs the tokens are different from each other and the previous execution. I expected this. Both return true for IsSystem property. The values for the Owner property (SID or Security Identifier) are identical also. Two hours on I'm losing the will to live. – Kofi Sarfo Dec 30 '10 at 14:58
  • 1
    Are you running on Windows Vista or higher? I wonder if this could relate to UAC evilness; I think windows creates a faux user during login that looks mostly but not quite the same as the existing user. You can test if this is the issue by running the application as admin and seeing if that resolves the problem. – Brian Dec 30 '10 at 19:27
  • Look up client impersonation on MSDN. – wj32 Dec 30 '10 at 20:53

3 Answers3

5

Maybe it's because this is not the same classes.

Look at MSDN :

So, if there are differents classes, maybe there are differents implementations.

EDIT :

I have try this code :

public class InGroup
{
    public string Name { get; set; }
    public bool Current { get; set; }
    public bool Fixe { get; set; }
    public bool Thread { get; set; }
}

WindowsIdentity current = System.Security.Principal.WindowsIdentity.GetCurrent();
WindowsPrincipal principalcurrent = new WindowsPrincipal(current);

WindowsIdentity fixe = new WindowsIdentity("JW2031");
WindowsPrincipal principalFixe = new WindowsPrincipal(fixe);

IPrincipal principalThread = System.Threading.Thread.CurrentPrincipal;

List<InGroup> ingroups = new List<InGroup>();
foreach (IdentityReference item in current.Groups)
{
    IdentityReference reference = item.Translate(typeof(NTAccount));
    Console.WriteLine("{0}\t{1}\t{2}\t{3}",
        reference.Value,
        principalcurrent.IsInRole(reference.Value),
        principalFixe.IsInRole(reference.Value),
        principalThread.IsInRole(reference.Value));

    ingroups.Add(new InGroup()
    {
        Name = reference.Value,
        Current = principalcurrent.IsInRole(reference.Value),
        Fixe = principalFixe.IsInRole(reference.Value),
        Thread = principalThread.IsInRole(reference.Value)
    });
}
foreach (IdentityReference item in fixe.Groups)
{
    IdentityReference reference = item.Translate(typeof(NTAccount));
    if (ingroups.FindIndex(g => g.Name == reference.Value) == -1)
    {
        ingroups.Add(new InGroup()
        {
            Name = reference.Value,
            Current = principalcurrent.IsInRole(reference.Value),
            Fixe = principalFixe.IsInRole(reference.Value),
            Thread = principalThread.IsInRole(reference.Value)
        });
        Console.WriteLine("{0}\t{1}\t{2}\t{3}",
            reference.Value,
            principalcurrent.IsInRole(reference.Value),
            principalFixe.IsInRole(reference.Value),
            principalThread.IsInRole(reference.Value));
    }
}

And here is the result

As you can see, I did not have the same groups with differents ways. So (because I'm administrator of my local machine) I think that WindowsIdentity.GetCurrent will get the user from AD and WindowsPrincipal(WindowsIdentity("")) will get the user from local machine.

In my webapp, I have got the lowest authorisation possible (I think). But, I have no explanations for the consoleapp...

It's only suppositions, but this is coherent.

kerrubin
  • 1,606
  • 1
  • 20
  • 25
3

I believe the difference is between the logged in user and the account running the app (thread). These will not always be the same.

Alex
  • 2,342
  • 1
  • 18
  • 30
1

I admit it's a rather ugly workaround, but if all else fails you could replace:

principal = (WindowsPrincipal)Thread.CurrentPrincipal;

with something like

principal = new WindowsPrincipal(new WindowsIdentity(Thread.CurrentPrincipal.Identity.Name));

If that doesn't work, it will probably at least be instructive in showing where things are going wrong.

But I can't imagine it failing, since it does exactly the same thing (where it is relevant) as the line that worked: I assume Thread.CurrentPrincipal.Identity.Name is "ksarfo".

Brian
  • 25,523
  • 18
  • 82
  • 173