Update on the Auto-Signon Broken Bug ...



  • Hey All,

    Thought I'd provide an update of where I'm at with this.

    So far, I have no idea why this isn't working. The auto-logon is handled via ASP.NET and should "just work." I've followed some recommendations on from the folks at cs.org but have gotten nowhere -- once the timeout hits, it won't "remember" me. I've spent a couple hours trying debug this to no avail.

    I've decided to tackle it with a new approach -- use ASP.NET 1.1 instead of ASP.NET 2.0. This, by the way, is one of the more impressive things about CS2.0 -- it works very well in both platforms. Anyway, I've rebuilt it on my VS2003 machine and will be testing this out some more ... so hopefully soon this will be fixed.

     



  • Why don't you post some of the details here?  I'm not the one to ask, but there's got to be at least one .net non-punk programmer here... well, probably.



  • Out of curiosity, are you using those newfangled asp:Login and asp:PasswordRecovery tags?



  • Well, as for the details ...

    • I've stepped through the code to watch it set the authentication ticket cookie. The cookie has the appropriate expiration date/time on it (30 days). 
    • If I access the site within the authentication ticket expiration (60 minutes), it works fine
    • outside the 60 minute window, it ignores the auth ticket cookie and doesn't recognize it.
    • All this auth ticket stuff is handled internally by ASP.NET
    • Here's the help from the cs.org guy: http://communityserver.org/forums/thread/530491.aspx
    • I've made the changes he recommended

    And AFAIK, this does not use the Membership Provider stuff in ASP.NET 2.0 -- they wanted CS2.0 to work fine in ASP.NET 1.1 and ASP.NET 2.0.



  • Just a wild guess after some googling...
    in the file web.config

    <authentication mode="Forms"> 
    <forms name="login"
    loginUrl="login.aspx" protection="All" timeout="60" />
    </authentication>




  • I do suspect it's a web.config problem, but unfortunately not that simple of one. Here's the one it's using ...

    <configuration>

     <configSections>
      <sectionGroup name="memberrolesprototype">
       <section name="membership" type="Microsoft.ScalableHosting.Configuration.MembershipConfigHandler, MemberRole, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b7c773fb104e7562"/>
       <section name="roleManager" type="Microsoft.ScalableHosting.Configuration.RolesConfigHandler, MemberRole, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b7c773fb104e7562"/>
       <section name="profile" type="Microsoft.ScalableHosting.Configuration.ProfileConfigHandler, MemberRole, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b7c773fb104e7562"/>
       <section name="anonymousIdentification" type="Microsoft.ScalableHosting.Configuration.AnonymousIdConfigHandler, MemberRole, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b7c773fb104e7562"/>
      </sectionGroup>
     </configSections>
     
     <appSettings>
      <add key="SiteSqlServer" value="--snip--" />
      <add key="SiteSqlServerOwner" value="dbo" />
        <add key="MachineValidationKey" value="F9D1A2D3E1D3E2F7B3D9F90FF3965ABDAC304902" />
         <add key="MachineDecryptionKey" value="F9D1A2D3E1D3E2F7B3D9F90FF3965ABDAC304902F8D923AC" />
         <add key="MachineValidationMode" value="SHA1" />
         <add key = "ComponentArt.Web.UI.ClientScriptLocation" value = "~/Utility/componentart_webui_client" />
     </appSettings>

         <system.web>

      <machineKey
      validationKey="F9D1A2D3E1D3E2F7B3D9F90FF3965ABDAC304902"
      decryptionKey="F9D1A2D3E1D3E2F7B3D9F90FF3965ABDAC304902F8D923AC"
      validation="SHA1" />

      <!-- Standard Application Settings -->
      <compilation defaultLanguage="c#" debug="false">
       <assemblies>
        <add assembly="MemberRole, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b7c773fb104e7562"/>
       </assemblies>
      </compilation>
      <pages validateRequest="false" autoEventWireup="true" pageBaseType="CommunityServer.Components.CSPage, CommunityServer.Components"/>
      <trace enabled="false" requestLimit="40" localOnly="true"/>
      <sessionState mode="Off" />
      
      <!-- Permit detailed errors to be displayed for remote clients -->
      <customErrors mode="Off" defaultRedirect = "error.htm" />


      <!-- START - CommunityServer specific application settings -->
      <httpModules>
       <add name="CommunityServer" type="CommunityServer.CSHttpModule, CommunityServer.Components" />
       <add name="CSProfile" type="Microsoft.ScalableHosting.Profile.ProfileModule, MemberRole, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b7c773fb104e7562"/>
       <add name="CSRoleManager" type="Microsoft.ScalableHosting.Security.RoleManagerModule, MemberRole, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b7c773fb104e7562" />
      </httpModules>

      <httpHandlers>
       <add verb="GET" path="Utility/redirect.aspx" type="CommunityServer.Components.Redirect, CommunityServer.Components" />
       <add verb="GET" path="aggbug.aspx" type="CommunityServer.Components.HttpHandler.AggBugHandler, CommunityServer.Components" />
       <add verb="GET" path="avatar.aspx" type="CommunityServer.Components.HttpHandler.AvatarHttpHandler, CommunityServer.Components" />
       <add verb="GET" path="vcard.aspx" type="CommunityServer.Components.HttpHandler.VCardHttpHandler, CommunityServer.Components" />
       <add verb="POST" path = "rsscomments/*.aspx" type="CommunityServer.Blogs.Components.RssCommentHandler, CommunityServer.Blogs" />
       <add verb="GET" path="r.ashx" type="CommunityServer.Components.HttpHandler.TinyUrlHttpHandler, CommunityServer.Components" />
          <add verb="*" path="ImageHipChallenge.aspx" type="Msdn.Web.UI.WebControls.ImageHipChallengeHandler, Hip"/>
        </httpHandlers>

      <!--
      authentication :
       To use Windows Authentication, you must turn off Anonymous authentication in IIS
       or IIS will never pass the user credentials to the forums. 

       To enable Windows Authentication, simply comment out the forms authentication section
       below and uncomment the Windows Authentication stuff.

       To use the CookieAuthentication add-on module, set the authentication mode to "None" and
       comment out the forms element.
      -->
      <authentication mode="Forms">
       <forms name=".CommunityServer" protection="All" timeout="60" loginUrl="login.aspx" slidingExpiration="true" />
      </authentication>
     </system.web>

     <location path="EditPost.aspx">
      <system.web>
       <authorization>
        <deny users="?" />
       </authorization>
      </system.web>
     </location>

     <location path="PrivateMessage.aspx">
      <system.web>
       <authorization>
        <deny users="?" />
       </authorization>
      </system.web>
     </location>
     
     <location path="Download.aspx">
      <system.web>
       <authorization>
        <deny users="?" />
       </authorization>
      </system.web>
     </location>

     <location path="License.aspx">
      <system.web>
       <authorization>
        <deny users="?" />
       </authorization>
      </system.web>
     </location>
      
     <memberrolesprototype>

      <!--
      ========================
      Membership
      ========================
      Attributes:
                      userIsOnlineTimeWindow="int"                Time window (in minutes) to consider a User as being Online after since last activity
                      hashAlgorithmType="[SHA1|SHA512|MD5|...]"   Any valid hash algorithm supported by .NET framework, default is SHA1
      Child nodes:
                    <providers>              Providers (class must inherit from MembershipProvider)
                        <add                 Add a provider
                            name="string"    Name to identify this provider instance by
                            type="string"    Class that implements MembershipProvider
                            provider-specific-configuration />
                    </providers>

                    Configuration for SqlMembershipProvider and AccessMembershipProvider:
                       connectionStringName="string"              Name corresponding to the entry in <connectionStrings> section where the connection string for the provider is specified
                       passwordAttemptThreshold="int"             The number of failed password attempts, or failed password answer attempts that are allowed before locking out a user?s account
                       passwordAttemptWindow="int"                The time window, in minutes, during which failed password attempts and failed password answer attempts are tracked
                       enablePasswordRetrieval="[true|false]"     Should the provider support password retrievals
                       enablePasswordReset="[true|false]"         Should the provider support password resets
                       requiresQuestionAndAnswer="[true|false]"   Should the provider require Q & A
                       applicationName="string"                   Optional string to identity the application: defaults to Application Metabase path
                       requiresUniqueEmail="[true|false]"         Should the provider require a unique email to be specified
                       passwordFormat="[Clear|Hashed|Encrypted]"  Storage format for the password: Hashed (SHA1), Clear or Encrypted (Triple-DES)
                       description="string"                       Description of what the provider does
      -->
     
      <membership userIsOnlineTimeWindow="15" >
       <providers>
        <add
         name="CommunityServerSqlProvider"   
         type="CommunityServer.MemberRole.CSMembershipProvider, CommunityServer.MemberRole"
         connectionStringName="SiteSqlServer"
         enablePasswordRetrieval="false"
         enablePasswordReset="true"
         requiresQuestionAndAnswer="false"
         requiresUniqueEmail="true"
         passwordFormat="Hashed"
         applicationName="dev"
         description="Stores and retrieves membership data from the local Microsoft SQL Server database"
         maxInvalidPasswordAttempts = "999"
         passwordAttemptWindow = "999"
         minRequiredPasswordLength = "6"
         minRequiredNonalphanumericCharacters = "0"
        />
       </providers>
      </membership>
           
           
      <!--
      ========================
      Role Manager
      ========================
                    enabled="[true|false]"                            Feature is enabled?
                    cacheRolesInCookie="[true|false]"                 Cache roles in cookie?
                    cookieName=".ASPXROLES"                           Cookie Name
                    createPersistentCookie="[true|false]"             Creates a persistent cookie or session cookie?
                    cookieTimeout="30"                                Cookie Timeout
                    cookiePath="/"                                    Cookie Path
                    cookieRequireSSL="[true|false]"                   Set Secure bit in Cookie
                    cookieSlidingExpiration="[true|false]"            Reissue expiring cookies?
                    cookieProtection="[None|Validation|Encryption|All]"    How to protect cookies from being read/tampered
                    defaultProvider="string"                          Name of provider to use by default
                    domain="[domain]"                                 Enables output of the "domain" cookie attribute set to the specified value
                    maxCachedResults="int"                            Maximum number of roles to cache in cookie

      Child nodes:
                    <providers>              Providers (class must inherit from RoleProvider)

                        <add                 Add a provider
                            name="string"    Name to identify this provider instance by
                            type="string"    Class that implements RoleProvider
                            provider-specific-configuration />

                    </providers>


                    <providers> type="TypeName"                        Class that inherits from System.Web.Security.RoleProvider
                        providerSpecificConfig                        Config for the provider


      Configuration for SqlRoleProvider:
                       connectionStringName="string"  Name corresponding to the entry in <connectionStrings> section where the connection string for the provider is specified
                       description="string"           Description of what the provider does
                       commandTimeout="int"           Command timeout value for SQL command
      -->

      <roleManager
       cacheRolesInCookie="true" cookieName=".CSRoles" cookieTimeout="90"
       cookiePath="/"  cookieRequireSSL="false" cookieSlidingExpiration="true"
       createPersistentCookie="true" cookieProtection="All" maxCachedResults="1000" >
       <providers>
        <add
         name="CommunityServerSqlProvider"
         type="CommunityServer.MemberRole.CSRoleProvider, CommunityServer.MemberRole"
         connectionStringName="SiteSqlServer"
         applicationName="dev"
         description="Stores and retrieves roles data from the local Microsoft SQL Server database"
        />
       </providers>
      </roleManager> 
           
           
      <!--
      ========================
      Profile
      ========================
      Configuration for profile:
      <profile>
       enabled="[true|false]"   Feature is enabled?
       automaticSaveEnabled="[true|false]" Enable automatic save of profile
       inherits="type-name"     Class from which the profile type inherits from. This type must inherit from ProfileBase type.

                     <providers>              Providers (class must inherit from ProfileProvider)
                         <add                 Add a provider (only single entry supported)
                             name="string"    Name to identify this provider instance by
                             type="string"    Class that implements ProfileProvider
                             provider-specific-configuration />
                     <providers>

                     <properties>                Optional element. List of properties in the Profile system
        <add                    Add a property
                                 name="string"                 Name of the property
                                 type="string"                 Optional. Type of the property. Default: string.
                                 readOnly="[true|false]"       Optional. Is Value read-only. Default: false.
                                 defaultValue="string"         Optional. Default Value. Default: Empty string.
                                 allowAnonymous="[true|false]" Optional. Allow storing values for anonymous users. Default: false.
                                 serializeAs=["String|Xml|Binary|ProviderSpecific"] Optional. How to serialize the type. Default: ProviderSpecific.
        />
       </properties>
      </profile>
      -->

      <profile enabled="true" >
       <providers>
        <add 
         name="CommunityServerSqlProvider" 
         type="CommunityServer.MemberRole.CSProfileProvider, CommunityServer.MemberRole"
         connectionStringName="SiteSqlServer"
         applicationName="dev"
                       description="Stores and retrieves profile data from the local Microsoft SQL Server database"
        />
       </providers>

       <properties>
        <add name = "commonName" type = "string" />
                      <add name = "birthdate" type = "DateTime" />
                      <add name = "gender" type = "int" defaultValue = "0" />
                      <add name = "dateFormat" type = "string" defaultValue="MM-dd-yyyy" />
                      <add name = "publicEmail" type = "string" />
                      <add name = "language" type = "string" />
                      <add name = "webAddress" type = "string" />
                      <add name = "webLog" type = "string" />
                      <add name = "webGallery" type = "string" />
                      <add name = "signature" type = "string" />
                      <add name = "signatureFormatted" type = "string" />
                      <add name = "location" type = "string" />
                      <add name = "occupation" type = "string" />
                      <add name = "interests" type = "string" />
                      <add name = "msnIM" type = "string" /> 
                      <add name = "yahooIM" type = "string" />
                      <add name = "aolIM" type = "string" />
                      <add name = "icqIM" type = "string" />
                      <add name = "enablePostPreviewPopup" type = "System.Boolean" defaultValue = "false" />
                      <add name = "enableEmoticons" type = "System.Boolean" defaultValue = "true" />
                      <add name = "timezone" type = "System.Double" defaultValue="0" />
                      <add name = "fontsize" type = "int" defaultValue = "0" />
                      <add name = "bio" type = "string" />
                 </properties>
             </profile>
           
      <!--
      ========================
      Anonymous Identification
      ========================
      anonymousIdentification configuration:
       enabled="[true|false]"                            Feature is enabled?
                     cookieName=".ASPXANONYMOUS"                       Cookie Name
                     cookieTimeout="100000"                            Cookie Timeout in minutes
                     cookiePath="/"                                    Cookie Path
                     cookieRequireSSL="[true|false]"                   Set Secure bit in Cookie
                     cookieSlidingExpiration="[true|false]"            Reissue expiring cookies?
                     cookieProtection="[None|Validation|Encryption|All]"    How to protect cookies from being read/tampered
                     domain="[domain]"                                 Enables output of the "domain" cookie attribute set to the specified value
             -->
             <anonymousIdentification
       enabled="false"
       cookieName=".ASPXANONYMOUS"
       cookieTimeout="100000"
                     cookiePath="/"
       cookieRequireSSL="false"
       cookieSlidingExpiration="true"
                     cookieProtection="None" domain="" />
                    
         </memberrolesprototype>
     
     
    </configuration>



  • The following line looks suspicious:

    <forms name=".CommunityServer" protection="All" timeout="60" loginUrl="login.aspx" slidingExpiration="true" />

    Maybe you should try what happens if you change 60 to, say, 240. If auto-signon lasts for 4 hours then, you know this is the right place.



  • That line indeed is the auto-signon, but when creating the ticket an option is to create a persisitant one -- i.e., one that ignores the 60 minute timeout.

    No matter, I've just now deployed the site using 1.1 framework, so let's see how this goes ...



  • @Alex Papadimoulis said:

    That line indeed is the auto-signon, but when creating the ticket an option is to create a persisitant one -- i.e., one that ignores the 60 minute timeout.

    I hope I'm not too much of a "know-it-all", but are you sure this persistance doesn't only affect the lifetime of the cookie (on the browser side) while the timeout on the server side (how long does the server accept it) stays the same?



  • @ammoQ said:

    @Alex Papadimoulis said:

    That line indeed is the auto-signon, but when creating the ticket an option is to create a persisitant one -- i.e., one that ignores the 60 minute timeout.

    I hope I'm not too much of a "know-it-all", but are you sure this persistance doesn't only affect the lifetime of the cookie (on the browser side) while the timeout on the server side (how long does the server accept it) stays the same?



    I agree with ammoQ.  Seems that the option to create a persistent one, according to the thread in the cs.org forum you linked to, is to create a persitent cookie -- as opposed to a session cookie -- and perhaps does not override the server-side time-out.  If this is the case, then the end result would be that the browser receives a persistent cookie for 30 days, as you configured it, yet the server expires the authentication session token after 60 minutes.  Which sounds pretty close to what is actually occurring.

           -dZ.



  • This is exactly what happened -- the server expired the token after XX minutes (60, or whatever I configured it for). However, it shouldn't have -- here's what happens when you logon:

    HttpCookie formsAuthCookie;
    formsAuthCookie = FormsAuthentication.GetAuthCookie(userToLogin.Username, autoLogin.Checked);
    UserCookie userCookie = csContext.User.GetUserCookie();
    userCookie.WriteCookie(formsAuthCookie, 30, autoLogin.Checked);

    The WriteCookie method writes it out to the Response.Cookies collection as expected. The FormsAuthentication class is built into ASP.NET, so I have no idea why ASP.NET expired the cookie even though the "createPersistent" flag (2nd param to GetAuthCookie) was set to true.

    But no matter, switching the compilation to ASP.NET 1.1 seemed to do the trick. I have no intention of making any other significant changes (maybe when they do CS3.0) anytime soon, so I can worry about this later :-)



  • @Alex Papadimoulis said:

    This is exactly what happened -- the server expired the token after XX minutes (60, or whatever I configured it for). However, it shouldn't have -- here's what happens when you logon:

    HttpCookie formsAuthCookie;
    formsAuthCookie = FormsAuthentication.GetAuthCookie(userToLogin.Username, autoLogin.Checked);
    UserCookie userCookie = csContext.User.GetUserCookie();
    userCookie.WriteCookie(formsAuthCookie, 30, autoLogin.Checked);

    The WriteCookie method writes it out to the Response.Cookies collection as expected. The FormsAuthentication class is built into ASP.NET, so I have no idea why ASP.NET expired the cookie even though the "createPersistent" flag (2nd param to GetAuthCookie) was set to true.

    But no matter, switching the compilation to ASP.NET 1.1 seemed to do the trick. I have no intention of making any other significant changes (maybe when they do CS3.0) anytime soon, so I can worry about this later :-)

    A quick Google of "ASP.NET persistent cookie timeout" suggests that, while in ASP.NET 1.1 an auth token created with GetAuthCookie and createPersistent set to true essentially never expires, on ASP.NET 2.0 it expires just as soon as one created with createPersistent set to false. Don't ask me why... apparently ASP.NET is the real WTF.



  • Hooked on Auto Sign-on worked for me!



  • Totally works for me also and has worked for the past few days.


Log in to reply
 

Looks like your connection to What the Daily WTF? was lost, please wait while we try to reconnect.