Silverlight with Windows auth

Silverlight with Windows auth

Old forum URL: forums.lhotka.net/forums/t/8931.aspx


artsd posted on Thursday, May 13, 2010

I read this thread http://forums.lhotka.net/forums/p/8825/42014.aspx and this article http://msdn.microsoft.com/en-us/library/aa302377.aspx.

I still cannot get anywhere with the VS2010 CSLA 4 Beta 1 Silverlight "WindowsAuthentication" sample app.

I think I have tried every combination of

The first problem is that the Csla.Silverlight.Security.PopulateWindowsIdentity() is throwing an exception on the foreach loop over IdentityReferenceCollection beause the Translate fails on one of my groups (it succeeds on earlier entries in the collection).

So I skip over that foreach and go right to the line that assigns identityName to System.Security.Principal.WindowsIdentity.GetCurrent().Name.

identityName is always set to "IIS APPPOOL\ASP.NET v4.0" which then gets shortened to just "ASP.NET v4.0".

I thought maybe this had something to do with the fact that I had to run VS2010 as administrator in order to debug with IIS hosting the WCF web service (as opposed to Cassini), but I am not sure of that.

And of course, I cannot run outside the debugger because of the Translate exception (unless I comment that code out and recompile CSLA -- which I am trying to avoid).

I am sure there is some little setting I missed somewhere but where?!?!?

artsd replied on Thursday, May 13, 2010

I also wanted to note that IIS Manager's Authentication settings for this virtual directory application only show "ASP.NET Impersonation" and "Windows Authentication" enabled. All others are disabled. Thanks for any assistance you can offer.

RockfordLhotka replied on Friday, May 14, 2010

You are going to have to help troubleshoot the Translate issue - I've never seen that. What is the exception, and what group causes it?

Regarding the impersonation - you might find it easier to troubleshoot that by just adding an aspx page to the virtual root and debugging with ASP.NET itself from a browser. Take Silverlight out of the picture, and just focus on getting ASP.NET and IIS to impersonate the caller. That really has nothing to do with SL - it is purely a server-side ASP.NET concept.

artsd replied on Friday, May 14, 2010

 

The exception on Translate was System.Security.Principal.IdentityNotMapped "Some or all identity references could not be translated."

Here are some screen shots showing the IdentityReference and the exception.
Let me know if I can give you anything else. Thanks.

RockfordLhotka replied on Friday, May 14, 2010

OK, that helps, thanks.

Can you try changing the code in WindowsIdentity.cs so the foreach loop looks like this:

      foreach (System.Security.Principal.IdentityReference item in groups)
      {
        if (item.IsValidTargetType(typeof(System.Security.Principal.NTAccount)))
        {
          System.Security.Principal.NTAccount account = (System.Security.Principal.NTAccount)item.Translate(typeof(System.Security.Principal.NTAccount));
          if (account.Value.Contains(DomainDelimiter))
          {
            roles.Add(account.Value.Substring(account.Value.LastIndexOf(DomainDelimiter) + 1));
          }
          else
          {
            roles.Add(account.Value);
          }
        }
      }

I think that will fix the issue, since I've added a check to confirm that the item is valid before trying the translate.

artsd replied on Friday, May 14, 2010

Sorry to say but that did not fix it. The call to IsValidTargetType passed but the Translate still threw the same exception.

I "fixed" it for now by eating the IdentityNotMappedException. Not the best way I am sure. I will try to post more details about the exception in a followup post.

      foreach (System.Security.Principal.IdentityReference item in groups)
      {
          try
          {
              if (item.IsValidTargetType(typeof(System.Security.Principal.NTAccount)))
              {
                  System.Security.Principal.NTAccount account = (System.Security.Principal.NTAccount)item.Translate(typeof(System.Security.Principal.NTAccount));
                  if (account.Value.Contains(DomainDelimiter))
                  {
                      roles.Add(account.Value.Substring(account.Value.LastIndexOf(DomainDelimiter) + 1));
                  }
                  else
                  {
                      roles.Add(account.Value);
                  }
              }
          }
          catch (System.Security.Principal.IdentityNotMappedException)
          {
              ; // ignore
          }
          catch
          {
              throw;
          }
      }

artsd replied on Friday, May 14, 2010

...

artsd replied on Friday, May 14, 2010

The SID that this is throwing on is "S-1-5-82-0". I found out that "S-1-5-82" has something to do with IIS7 app pool so maybe that is a clue.

http://blogs.msdn.com/spatdsg/archive/2010/02/10/wsfederationauthenticationmodule-auth-failure.aspx

http://www.adopenstatic.com/cs/blogs/ken/archive/2008/01/29/15759.aspx

 

RockfordLhotka replied on Friday, May 14, 2010

Maybe it is a non-issue then, since if impersonation was working you'd have a real identity, not one of the system identities, and this wouldn't happen at all.

I am pretty sure that's the case, since nobody has ever encountered (or at least reported) the issue you are seeing.

artsd replied on Friday, May 14, 2010

OK. I will try to get that working with simplified ASPX.

Ignore my last post because the SID for IIS7 was "S-1-5-8-82" not "S-1-5-82" like I had.

artsd replied on Friday, May 14, 2010

I did as you suggested and made a simple ASPX page. If ASP.NET impersonation and Windows authentication in enabled, I correctly get my domain user and my groups. If impersonation is disabled, I get the Translate exception when processing SID S-1-5-82-0 for user "IIS APPPOOL\ASP.NET v4.0".

So ASPX is working as you expected.

Of course I still have the same exact problem with the WCF service though. Still working on it...

RockfordLhotka replied on Friday, May 14, 2010

Have you read through the PnP guidance book for WCF configuration? It is on codeplex, and is probably the most comprehensive discussion of WCF configuration available. iirc, they talk about configuring WCF for impersonation pretty thoroughly.

artsd replied on Friday, May 14, 2010

OK. I will read that guide. I finally got something to work (but not CSLA yet). I decided to do a dirt simple WCF service with the following implementation. I made the following DoWork() method. The WindowsIdentity was always coming back as the ASP account. The HttpContext was always null. The Thread was always correct.

When I added the OperationBehavior Impersonation "Required" attribute, then the WindowsIdentity now works and is the same as the Thread. This is what I want.

If I use OperationBehavior Impersonation "Allowed" attribute, then it goes back to ASP user. CSLA uses the Allowed attribute.

I thought adding:
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
to the <system.serviceModel> section of Web.Config would help. But then I needed to add service class attribute:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]. But even with that, WindowsIdentity is still ASP acct. 

namespace AgWcfSecTest.Web
{
public class Service1 : IService1
{
  [OperationBehavior(Impersonation = ImpersonationOption.Required)]
  public string DoWork()
  {
    string s1 = "WindowsIdentity: <null>";
    string s2 = "HttpContext.Current.User: <null>";
    string s3 = "Thread.CurrentPrincipal.Identity: <null>";

    string s = "";

    System.Security.Principal.WindowsIdentity ident = System.Security.Principal.WindowsIdentity.GetCurrent();
    if (ident != null)
      s1 = "WindowsIdentity: " + ident.Name;

    if (HttpContext.Current != null && HttpContext.Current.User != null && HttpContext.Current.User.Identity != null)
      s2 = "HttpContext.Current.User: " + HttpContext.Current.User.Identity.Name;

    if (Thread.CurrentPrincipal != null && Thread.CurrentPrincipal.Identity != null)
      s3 = "Thread.CurrentPrincipal.Identity: " + Thread.CurrentPrincipal.Identity.Name;

    s = s1 + "\n" + s2 + "\n" + s3;

    return s;
    }
}
}

artsd replied on Friday, May 14, 2010

OK. I think this will be my last post to this thread but I wanted to share my final findings in case it helps someone else.

Fyi, I am using: VS2010, CSLA v4 beta 1, IIS7, .NET 4.

In order to make WCF CSLA service properly work with Silverlight and Windows authentication such that PopulateWindowsIdentity() in WindowsIdentity.cs does the right thing, in IIS Authentication settings, enable only ASP.NET Impersonation and Windows Authentication.

In Web.Config, configure as below.. In the end I think my problem came down to themissing impersonateCallerForAllOperations:.

<configuration>

    <appSettings>

        <add key="CslaAuthentication" value="Windows" />

    </appSettings>

    <system.web>

       <compilation debug="true" targetFramework="4.0"> </compilation>

       <authentication mode="Windows" />

       <identity impersonate="true" />

       <pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID" />

    </system.web>

    <system.serviceModel>

        <bindings>

            <basicHttpBinding>

                <binding name="ArtsBasicHttpEndpointBinding">

                    <security mode="TransportCredentialOnly">

                        <transport clientCredentialType="Windows" />

                    </security>

                </binding>

            </basicHttpBinding>

         </bindings>

         <behaviors>

             <serviceBehaviors>

                 <behavior name="WcfPortalBehavior">

                     <serviceMetadata httpGetEnabled="true" />

                     <serviceDebug includeExceptionDetailInFaults="true" />

                     <serviceAuthorization impersonateCallerForAllOperations="true" />

                 </behavior>

             </serviceBehaviors>

        </behaviors>

        <services>

            <service behaviorConfiguration="WcfPortalBehavior" name="Csla.Server.Hosts.Silverlight.WcfPortal">

                <endpoint address="" binding="basicHttpBinding" bindingConfiguration="ArtsBasicHttpEndpointBinding" name="ArtsEndpoint" contract="Csla.Server.Hosts.Silverlight.IWcfPortal">

                    <identity>

                        <dns value="localhost" />

                    </identity>

                </endpoint>

            </service>

        </services>

    </system.serviceModel>

 

    <system.webServer>

        <validation validateIntegratedModeConfiguration="false" />

        <directoryBrowse enabled="false" />

    </system.webServer>

</configuration>

 

RockfordLhotka replied on Friday, May 14, 2010

Thanks for sharing your results!!

Copyright (c) Marimer LLC