Client-Server - Win Authentication problem

Client-Server - Win Authentication problem

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


Mr X posted on Friday, December 03, 2010

Working with Silverlight 3, CSLA 3.8.1, Visual Studio 2010.

 I am currently implementing my frst application using Silverlight and Csla 3.8.1 and I am using Rocky's Demo006 example from the Silverlight videos series as my template.  I am also using the AppPrincipal implementation from the WinAuth example from the same series. 

Our web application (folder) uses Windows Authentication.  My SA told me he had to change the access to the wcfStPortal.svc file and changed it to Anonymous and specified a domain user instead.  For some reason, Rocky's example did not have access to the file and would not work otherwise. 

Now that Rocky's example is working, I am getting this strange behaviour:

 I can't seem to be able to get the Domain\Username value from the client (user currently logged on to the client's machine running the Silverlight application).  For some strange reason, I always obtain "Network Service".  How can I retrieve the username of the user logged in on the client's workstation?  Are there any other settings we need to consider on the server?  Obviously, I am not an expert when it comes to setting the server access...   Any help would be appreciated.

I included the relevant portions of my code below if it helps. 

 

AppIdentity.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using Csla.Serialization;

 

namespace Business

{

  [Serializable]

  public class AppIdentity : Csla.Silverlight.Security.WindowsIdentity

  {

#if !SILVERLIGHT

    private void DataPortal_Fetch()

    {

      // get windows identity/group data

      PopulateWindowsIdentity();

    }

#endif

  }

}

 AppPrincipal.cs

 using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using Csla;

using Csla.Serialization;

 

namespace Business

{

  [Serializable]

  public class AppPrincipal : Csla.Security.BusinessPrincipalBase

  {

    public AppPrincipal()

    { }

 

    public AppPrincipal(AppIdentity identity)

      : base(identity)

    { }

 

    public static void Login(EventHandler callback)

    {

      var dp = new DataPortal<AppIdentity>();

      dp.FetchCompleted += (o, e) =>

        {

          if (e.Error == null)

          {

            var principal = new AppPrincipal(e.Object);

            Csla.ApplicationContext.User = principal;

          }

          else

          {

            Csla.ApplicationContext.User =

              new Csla.Security.UnauthenticatedPrincipal();

          }

          callback(null, EventArgs.Empty);

        };

      dp.BeginFetch();

    }

  }

}

I modified my business object to hold the client and the server username. 

 private static PropertyInfo<string> ClientUserProperty = RegisterProperty<string>(c => c.ClientUser, "Client User");

        public string ClientUser

        {

            get { return GetProperty(ClientUserProperty); }

            set { SetProperty(ClientUserProperty, value); }

        }

 

private static PropertyInfo<string> ServerUserProperty = RegisterProperty<string>(c => c.ServerUser, "Server User");

        public string ServerUser

        {

            get { return GetProperty(ServerUserProperty); }

            set { SetProperty(ServerUserProperty, value); }

        }

These values are set when the application call either the client or the server method "GetMyBusinessObject".

In .Client.cs the factory method code looks as followed. Notice the ClientUser when the Fetch completes.

public static void GetMyBO(EventHandler<DataPortalResult<MyBO>> callback)

        {

            var dp = new DataPortal<MyBO>();

            dp.FetchCompleted += (o, e) =>

            {

                if (e.Error == null)

                    e.Object.ClientUser = Csla.ApplicationContext.User.Identity.Name;

                callback(o, e);

            };

            dp.BeginFetch();

        }

In .Server.cs the code looks like this:

public static MyBO GetMyBO()

        {

            return DataPortal.Fetch<MyBO>();

        }

 

In both cases (client or server side Fetch calls), the application calls the Server side code "DataPortal_Fetch" which sets the ServerUser property with the server User.Identity.Name value.  (Omitted the database code here)

private void DataPortal_Fetch()

        {

             ServerUser = Csla.ApplicationContext.User.Identity.Name;

        }

In the Web.Config file, the authentication portion looks like this:

              <authentication mode="Windows"/>

              <identity impersonate="true"/>

 On the load event of my Silverlight usercontrol, I call the following code:

private void UserControl_Loaded(object sender, RoutedEventArgs e)

    {

      Business.AppPrincipal.Login((o, arg) =>

        {

         //do something here

        });

    }

 

 

 

 

RockfordLhotka replied on Friday, December 03, 2010

Are you sure you have your web.config set up so ASP.NET impersonates the logged in user? That's a requirement, since all the Silverlight code does is send an object to the server so that object can copy the identity of the user on the server. If the server isn't impersonating the end user it obviously won't copy the identity you are looking for.

Mr X replied on Friday, December 03, 2010

Thanks Rocky for this quick reply.  You help is very valuable.

As I mentionned in the original posting, my Web.config includes the necessary elements (I think) that specify Windows Authentication and impersonation (=true).  I am including the code of my Web.config file (renamed server and database name in my connection string).    Maybe I am missing something or there is something that should not be there (I am thinking of <dns value="localhost"/> in particular. I am not sure what this does) 

Thanks

-------------------------

<?xml version="1.0"?>

<configuration>

 

  <connectionStrings>

    <add name="Mydatabase" connectionString="data source=MyServerName;initial catalog=MyDatabase;Integrated Security=SSPI" providerName="System.Data.SqlClient"/>

  </connectionStrings>

  <system.serviceModel>

    <services>

      <service behaviorConfiguration="WcfPortalBehavior" name="Business.Compression.CompressedHost">

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

          <identity>

            <dns value="localhost"/>

          </identity>

        </endpoint>

      </service>

    </services>

    <behaviors>

      <serviceBehaviors>

        <behavior name="returnFaults">

          <serviceDebug includeExceptionDetailInFaults="true"/>

        </behavior>

        <behavior name="WcfPortalBehavior">

          <serviceMetadata httpGetEnabled="true"/>

          <serviceDebug includeExceptionDetailInFaults="true"/>

        </behavior>

      </serviceBehaviors>

    </behaviors>

    <bindings>

      <basicHttpBinding>

        <binding name="BasicHttpBinding_IWcfPortal" maxBufferSize="10000000" maxReceivedMessageSize="10000000" receiveTimeout="00:10:00" sendTimeout="00:10:00" openTimeout="00:10:00" closeTimeout="00:10:00">

          <readerQuotas maxBytesPerRead="10000000" maxArrayLength="10000000" maxStringContentLength="10000000"/>

        </binding>

      </basicHttpBinding>

    </bindings>

  </system.serviceModel>

  <system.web>

    <!--

            Set compilation debug="true" to insert debugging

            symbols into the compiled page. Because this

            affects performance, set this value to true only

            during development.

        -->

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

    </compilation>

    <!--

            The <authentication> section enables configuration

            of the security authentication mode used by

            ASP.NET to identify an incoming user.

        -->

    <authentication mode="Windows"/>

    <identity impersonate="true" />

 

 

    <!--

            The <customErrors> section enables configuration

            of what to do if/when an unhandled error occurs

            during the execution of a request. Specifically,

            it enables developers to configure html error pages

            to be displayed in place of a error stack trace.

 

        <customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">

            <error statusCode="403" redirect="NoAccess.htm" />

            <error statusCode="404" redirect="FileNotFound.htm" />

        </customErrors>

        -->

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

  </system.web>

  <!--

        The system.webServer section is required for running ASP.NET AJAX under Internet

        Information Services 7.0.  It is not necessary for previous version of IIS.

    -->

</configuration>

 

 

 

Copyright (c) Marimer LLC