How-To: CS and DNN SSO for Developers

Rate It (1)

Last post 03-19-2006 6:23 PM by yeoshua. 22 replies.

Sort Posts:

  • How-To: CS and DNN SSO for Developers

    04-27-2005, 2:34 AM
    • Participant
      965 point Participant
    • gsc4
    • Member since 05-29-2003, 3:24 AM
    • Posts 193

    Overview:

    Many consumers of DNN and CS have been eagerly awaiting a solution for integrating the two products. There are two broad visions (options) for such a solution.

    Option 1. Fully integrate CS into DNN by converting it into a DNN module.
    Option 2. Integrate/share the membership database only and therefore the membership functionality.

    Both options are valid and complete approaches. Both options share the goal of a Single Sign On (SSO). This method (in this post) aims to achieve only the SSO portion of these, I do not consider this a "complete" solution (the membership databases will only be synchronised, not shared and core code changes are required). Note: there are no database alterations made, changes may be reversed to run the applications separately (or to switch to an alternate method, upgrade etc). 

    The reason for this approach is as follows: a). the DNN module is already being developed (re-invention), b). the membership providers and implementations are yet to standardise (not the same yet, maybe too early to implement sharing) and c). we all want something that works *now* (impatience).

    The title of this piece contains the word "Developers" because if you are not confident about changing core code and configurations then this is not for you. I wouldn't like to see anyone implement this in a production environment in it's current state. But that's what this is all about - let's test and develop this together from this point forward.


    How does this work then?

    The keys to this implementation are as follows:

    1. The use of identical machine keys between the two applications
    2. The use of identical forms authentication name values
    3. The use of secure web services to synchronise the membership databases


    Environment:

    The environment used for this development:
    - 1 PC
    - Windows XP Professional (IIS v5.1)
    - Visual Studio .NET 2003
    - MSDE 2000 REL A
    - Web Services Enhancements 2.0 SP3

    If your development environment differs, you may need to alter the following instructions to suit.


    General Process

    The general steps to set this up for development are (see detailed steps below before starting):

    1. install DNN 3.0.13
    2. modify DNN and CS config files
    3. install CS 1.0 (build 50218) with build support
    4. install Web Services Enhancements 2.0 SP3
    5. add web service to CS
    6. add code to UserController in DNN
    7. modify CS urls and UI element


    Specific Steps

    The specific steps are as follows:

    1. Create databases
    - Create DNN database e.g. DNN3013
    - Create CS database e.g. CS50218
    - Add the ASPNET Windows account to the SQL Server logins
    - Assign the db_owner role on the ASPNET account for both databases

    2. Extract files
    - Extract/copy DNN files to a folder e.g. C:\Inetpub\DotNetNuke3013
    - Grant the ASPNET account modify access to the folder
    - Extract/copy the source code files (all files in the src folder) for CS to a folder e.g. C:\Inetpub\CS50218
    - Copy the .dll files in the /Web/bin folder from the CS runtime version to the /Web/bin folder of the source code version in the location above (replace files is ok) e.g. copy to C:\Inetpub\CS50218\Web\bin
    - Grant the ASPNET account modify access to the /Web/blogs and /Web/photos folders

    3. Install DNN 3.0.13
    - Set the database connection string in the web.config file e.g. set the SiteSqlServer appSettings key to Server=(local);Database=DNN3013;Trusted_Connection=True;
    - Add a virtual directory to IIS e.g. Alias: dotnetnuke, Directory: C:\Inetpub\DotNetNuke3013
    - Browse to http://localhost/dotnetnuke
    - NOTE: The MachineValidationKey and the MachineDecryptionKey in the appSettings section of the web.config file will be changed by the DNN installer

    4. Modify the DNN and CS web.config files (e.g. C:\Inetpub\DotNetNuke3013\Web.config and C:\Inetpub\CS50218\Web\Web.config)
    - Copy the MachineValidationKey and the MachineDecryptionKey values from the DNN config file to the CS config file to replace the CS values
    - Add the following to the <system.web> section in both config files using the values from the previous step:

      <!-- ADDED FOR DNN CS SINGLE LOGIN -->
      <machineKey
      validationKey="INSERT-MACHINEVALIDATIONKEY-VALUE-FROM-PREVIOUS-STEP"
      decryptionKey="INSERT-MACHINEDECRYPTIONKEY-VALUE-FROM-PREVIOUS-STEP"
      validation="SHA1"
      />

    - In the CS web.config change:

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

    - To the same name as DNN:

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

    5. Install CS (build 50218)
    - Edit the web/installer/default.aspx file and change "bool INSTALLER_ENABLED = false;" to true
    - Add a virtual directory to IIS e.g. Alias: cs, Directory: C:\Inetpub\CS50218\Web
    - Browse to http://localhost/cs/installer
    - Welcome screen > Next > Read and I Agree > Next > Database Login (local) and Windows > Next > Choose CS50218 > Next > All options checked > Next > set the admin password to the same as DNN i.e. admin > Next > when the installation completes follow the instructions pertaining to the SQL connection string and the CS installer

    6. Install Web Services Enhancements 2.0 SP3
    - Download Web Services Enhancements 2.0 SP3 from http://msdn.microsoft.com/webservices/building/wse/default.aspx
    - Install as "Visual Studio Developer"

    7. Add the web service to CS
    - Open the Community Server solution in Visual Studio e.g. double click the following sln file C:\Inetpub\CS50218\Community Server.sln
    - Right click the CommunityServerWeb project and select WSE Settings 2.0...
    - Check "Enable this project for Web Services Enhancements"
    - Check "Enable Microsoft Web Services Enhancement Soap Extensions"
    - Click OK
    - Note: this will make changes to the web.config file and add a reference to Microsoft.Web.Services2.dll
    - Note: it seems you may also need to correct the MemberRole reference in this project, delete the reference and add it back in e.g. browse to C:\Inetpub\CS50218\Web\bin\MemberRole.dll
    - Right click the CommunityServerWeb project and select Add > Add Web Service, name it UserService.asmx
    - Change to the code view for the UserService.asmx file and replace the entire content with the following:

    using System;
    using System.Collections;
    using System.ComponentModel;
    using System.Data;
    using System.Diagnostics;
    using System.Web;
    using System.Web.Services;
    using CommunityServer;
    using CommunityServer.Components;
    using CommunityServer.Components.Enumerations;
    using Microsoft.ScalableHosting.Security;
    using Microsoft.Web.Services2.Security;
    using Microsoft.Web.Services2.Security.Tokens;
    namespace CommunityServerWeb
    {
     /// <summary>
     /// Summary description for UserService.
     /// </summary>
     public class UserService : System.Web.Services.WebService
     {
      /// <summary>
      ///
      /// </summary>
      public UserService()
      {
       //CODEGEN: This call is required by the ASP.NET Web Services Designer
       InitializeComponent();
      }
      #region Component Designer generated code
      
      //Required by the Web Services Designer
      private IContainer components = null;
        
      /// <summary>
      /// Required method for Designer support - do not modify
      /// the contents of this method with the code editor.
      /// </summary>
      private void InitializeComponent()
      {
      }
      /// <summary>
      /// Clean up any resources being used.
      /// </summary>
      protected override void Dispose( bool disposing )
      {
       if(disposing && components != null)
       {
        components.Dispose();
       }
       base.Dispose(disposing);  
      }
      
      #endregion
      /// <summary>
      ///
      /// </summary>
      /// <returns></returns>
      [WebMethod()]
      public string GetSecretMessage()
      {
       return "Only authenticated users can view this secret message!";
      }
      /// <summary>
      ///
      /// </summary>
      /// <param name="username"></param>
      /// <param name="email"></param>
      /// <returns></returns>
      [WebMethod]
      public string CanCreateUser(string username, string email)
      {
       string result = "Success";
       // Check if username already exists
       User usernameLookup = Users.FindUserByUsername( username );
       if (usernameLookup.UserID != 0)
        result = "DuplicateUserName";
       // Check if email already exists
       User emailLookup = Users.FindUserByEmail(email);
       if (emailLookup.Member.Email != null)
        result = "DuplicateEmail";
       // Check if username is disallowed
       if ( DisallowedNames.NameIsDisallowed(username) == true )
        result = "InvalidUserName";
       
       // Otherwise return success
       return result;
      }
      /// <summary>
      ///
      /// </summary>
      /// <param name="username"></param>
      /// <param name="password"></param>
      /// <param name="email"></param>
      /// <returns></returns>
      [WebMethod]
      public string CreateUser(string username, string password, string email)
      {
       CommunityServer.Components.AccountActivation activation = SiteSettingsManager.GetSiteSettings().AccountActivation;
       string output = "";
       MembershipCreateStatus status = MembershipCreateStatus.ProviderError;
       // try to create the new user account
       User user = new User();
       user.Username = username;   
       user.Email = email;
       user.Password = password.Trim();
       user.PasswordFormat = SiteSettingsManager.GetSiteSettings().PasswordFormat;
       // Does the user require approval?
       //
       if (activation == AccountActivation.AdminApproval)
        user.AccountStatus = UserAccountStatus.ApprovalPending;
       else
        user.AccountStatus = UserAccountStatus.Approved;
               
       // Set the Anonymous flag to false
       //
       user.IsAnonymous = false;
       // Attempt to create the user
       //
       if (user.Username == "Anonymous")
       {
        status = MembershipCreateStatus.DuplicateUserName;
       }
       else
       {
        try 
        {
         if (Users.Create(user, true) == CreateUserStatus.Created)
          status = MembershipCreateStatus.Success;
        }
        catch (MembershipCreateUserException exception)
        {
         status = exception.StatusCode;
        }
       }
       // Determine if the account was created successfully
       //
       switch (status)
       {
         // Username already exists!
        case MembershipCreateStatus.DuplicateUserName:
         output = CommunityServer.Components.ResourceManager.GetString("CreateNewAccount_CreateUserStatus_DuplicateUsername");
         break;
         // Email already exists!
        case MembershipCreateStatus.DuplicateEmail:
         output = CommunityServer.Components.ResourceManager.GetString("CreateNewAccount_CreateUserStatus_DuplicateEmailAddress");
         break;
         // Unknown failure has occurred!
        case MembershipCreateStatus.ProviderError:
         output = CommunityServer.Components.ResourceManager.GetString("CreateNewAccount_CreateUserStatus_UnknownFailure");
         break;
         // Username is disallowed
        case MembershipCreateStatus.UserRejected:
         output = CommunityServer.Components.ResourceManager.GetString("CreateNewAccount_CreateUserStatus_DisallowedUsername");
         break;
        case MembershipCreateStatus.InvalidAnswer:
        case MembershipCreateStatus.InvalidQuestion:
         output = "invalid answer or question";
         break;
         // Everything went off fine, good
        case MembershipCreateStatus.Success:
        switch (activation) 
        {
         case AccountActivation.AdminApproval:
          output = "admin approved activation";
          break;
         case AccountActivation.Email:
          output = "email activation";
          break;
         case AccountActivation.Automatic:
          // Are we allowing login?
          output = "automatic activation";
          break;
        }
         break;
       }
     
       return output;
      }
      /// <summary>
      ///
      /// </summary>
      /// <param name="username"></param>
      /// <param name="password"></param>
      /// <param name="newPassword"></param>
      /// <returns></returns>
      [WebMethod]
      public bool ChangePassword(string username, string password, string newPassword)
      {
       bool status = false;
       try
       {
        User user = Users.FindUserByUsername(username);
        status = user.Member.ChangePassword(password, newPassword);
        return status;
       }
       catch
       {
        return status;
       }
      }
      /// <summary>
      ///
      /// </summary>
      /// <param name="username"></param>
      /// <param name="email"></param>
      /// <param name="approved"></param>
      /// <returns></returns>
      [WebMethod]
      public bool UpdateUser(string username, string email, string approved)
      {
       bool status = false;
       try
       {
        User user = Users.FindUserByUsername(username);
        user.Email = email;
        if (approved == "True")
        {
         user.AccountStatus = UserAccountStatus.Approved;
        }
        else
        {
         user.AccountStatus = UserAccountStatus.Disapproved;
        }
        Users.UpdateUser(user);
        status = true;
        return status;
       }
       catch
       {
        return status;
       }
      }
      /// <summary>
      ///
      /// </summary>
      /// <param name="username"></param>
      /// <returns></returns>
      [WebMethod]
      public bool DeactivateUser(string username)
      {
       bool status = false;
       try
       {
        User user = Users.FindUserByUsername(username);
        user.Email = user.UserID.ToString() + ".inactive@host.local";
        user.AccountStatus = UserAccountStatus.Disapproved;
        user.Member.ResetPassword();
        user.ForceLogin = true;
        Users.UpdateUser(user);
        status = true;
        return status;
       }
       catch
       {
        return status;
       }
      }
     }
     /// <summary>
     ///
     /// </summary>
     public class AuthenticationManager : UsernameTokenManager
     {
      // This method returns the password for the provided username
      // WSE will make the determination if they match
      /// <summary>
      ///
      /// </summary>
      /// <param name="token"></param>
      /// <returns></returns>
      protected override string AuthenticateToken( UsernameToken token )
      {
       string username = token.Username;
       // The following may be substituted with a more complex lookup routine...
       if (String.Compare("INSERT-UNIQUE-USERNAME", username, true) == 0)
        return "INSERT-UNIQUE-PASSWORD";
       else
        return String.Empty;
      }
     }
    }

    - Note: The GetSecretMessage method is for testing the security provided by WSE 2.0, you may choose to remove it.
    - Save the file
    - Right click the CommunityServerWeb project and select WSE Settings 2.0...
    - Click the Security tab
    - In the Security Tokens Managers section, click Add
    - Enter the following values: 
       - Type: CommunityServerWeb.AuthenticationManager, CommunityServer.Web 
       - Namespace: http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd 
       - Qname: wsse:UsernameToken
    - Click OK
    - Click the Policy tab
    - Check Enable Policy
    - Click Add
    - Accept the default for the Endpoint URI by clicking OK
    - In the Security Settings Wizard, select "Secure a service application" > Next > Check Require signatures in the Request Method section, uncheck all others > Next > Select Username > Next > Next > Finish (these settings are used only to fullfill the requirement of completing the wizard)
    - Click OK on the main WSE Settings dialog
    - Open the policyCache.config file created by the Security Settings Wizard
    - Replace the entire contents with the following:

    <?xml version="1.0" encoding="utf-8"?>
    <policyDocument xmlns="http://schemas.microsoft.com/wse/2003/06/Policy">
      <mappings xmlns:wse="http://schemas.microsoft.com/wse/2003/06/Policy">
        <defaultEndpoint>
          <defaultOperation>
            <request policy="#Sign-Username" />
            <response policy="" />
            <fault policy="" />
          </defaultOperation>
        </defaultEndpoint>
      </mappings>
      <policies xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
        <wsp:Policy wsu:Id="Sign-Username"
          xmlns:wsp="http://schemas.xmlsoap.org/ws/2002/12/policy"
          xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/03/addressing" >
          <SecurityToken wsp:Usage="wsp:Required" xmlns="http://schemas.xmlsoap.org/ws/2002/12/secext">
            <TokenType>http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#UsernameToken</TokenType>
          </SecurityToken>
          <wssp:Confidentiality wsp:Usage="wsp:Required"
            xmlns:wssp="http://schemas.xmlsoap.org/ws/2002/12/secext">
            <wssp:KeyInfo>
              <SecurityToken xmlns="http://schemas.xmlsoap.org/ws/2002/12/secext">
                <wssp:TokenType>http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#UsernameToken</wssp:TokenType>
                <wssp:Claims>
                  <wssp:SubjectName MatchType="wssp:Exact">
                    INSERT-UNIQUE-USERNAME</wssp:SubjectName>
                  <wssp:UsePassword Type="wssp:PasswordDigest"
                    wsp:Usage="wsp:Required" />
                </wssp:Claims>
              </SecurityToken>
            </wssp:KeyInfo>
            <wssp:MessageParts Dialect="http://schemas.xmlsoap.org/2002/12/wsse#part">
              wsp:Body()
            </wssp:MessageParts>
          </wssp:Confidentiality>
          <wssp:Integrity wsp:Usage="wsp:Required"
            xmlns:wssp="http://schemas.xmlsoap.org/ws/2002/12/secext">
            <wssp:TokenInfo>
              <SecurityToken xmlns="http://schemas.xmlsoap.org/ws/2002/12/secext">
                <wssp:TokenType>http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#UsernameToken</wssp:TokenType>
                <wssp:Claims>
                    <wssp:SubjectName MatchType="wssp:Exact">
                      INSERT-UNIQUE-USERNAME</wssp:SubjectName>
                    <wssp:UsePassword Type="wssp:PasswordDigest"
                      wsp:Usage="wsp:Required" />
                </wssp:Claims>
              </SecurityToken>
            </wssp:TokenInfo>
            <wssp:MessageParts Dialect="http://schemas.xmlsoap.org/2002/12/wsse#part">
              wsp:Body() wsp:Header(wsa:To) wsp:Header(wsa:Action)
              wsp:Header(wsa:MessageID) wsp:Header(wsa:From)
            </wssp:MessageParts>
          </wssp:Integrity>
        </wsp:Policy>
      </policies>
    </policyDocument>

    - Save the file
    - Right click the CommunityServerWeb project > Rebuild

    8. Add code to DNN
    - Open the DotNetNuke solution in Visual Studio e.g. double click the following sln file C:\Inetpub\DotNetNuke3013\DotNetNuke.sln
    - Right click the DotNetNuke project and select WSE Settings 2.0...
    - Check "Enable this project for Web Services Enhancements"
    - Check "Enable Microsoft Web Services Enhancement Soap Extensions"
    - Click OK
    - Note: this will make changes to the web.config file and add a reference to Microsoft.Web.Services2.dll

    - In the DotNetNuke project, right click Web References and click Add Web Reference
    - Enter the URL http://localhost/cs/userservice.asmx and click GO
    - Change the Web reference name to CommunityServer
    - Click Add Reference

    - Open the file /components/Users/UserController.vb
    - Add the following Imports statements:
    Imports Microsoft.Web.Services2.Security
    Imports Microsoft.Web.Services2.Security.Tokens

    - In the Private Methods Region, in Private Function DeleteUser, add the following code before the line "Return CanDelete"

                    ''' -------------------------------------------------------------------------
                    ''' Start Community Server Deactivate User
                    ''' -------------------------------------------------------------------------
                    Dim token As UsernameToken = New UsernameToken("INSERT-UNIQUE-USERNAME", "INSERT-UNIQUE-PASSWORD", PasswordOption.SendHashed)
                    Dim cs As CommunityServer.UserServiceWse = New CommunityServer.UserServiceWse
                    cs.RequestSoapContext.Security.Timestamp.TtlInSeconds = 300
                    cs.RequestSoapContext.Security.Tokens.Add(token)
                    cs.RequestSoapContext.Security.Elements.Add(New EncryptedData(token))
                    ' sign the UsernameToken
                    cs.RequestSoapContext.Security.Elements.Add(New MessageSignature(token))
                    If CanDelete Then
                        Dim result As Boolean
                        result = cs.DeactivateUser(objUser.Membership.Username)
                    End If
                    ''' -------------------------------------------------------------------------
                    ''' End Community Server Deactivate User
                    ''' -------------------------------------------------------------------------

    - In the Public Methods Region, in Public Function AddUser (the second function of this name), add the following code after the line "Try"

                    ''' -------------------------------------------------------------------------
                    ''' Start Community Server Check CanCreateUser
                    ''' -------------------------------------------------------------------------
                    Dim token As UsernameToken = New UsernameToken("INSERT-UNIQUE-USERNAME", "INSERT-UNIQUE-PASSWORD", PasswordOption.SendHashed)
                    Dim cs As CommunityServer.UserServiceWse = New CommunityServer.UserServiceWse
                    cs.RequestSoapContext.Security.Timestamp.TtlInSeconds = 300
                    cs.RequestSoapContext.Security.Tokens.Add(token)
                    cs.RequestSoapContext.Security.Elements.Add(New EncryptedData(token))
                    ' sign the UsernameToken
                    cs.RequestSoapContext.Security.Elements.Add(New MessageSignature(token))
                    Dim result As String
                    result = cs.CanCreateUser(objUser.Membership.Username, objUser.Membership.Email)
                    ' end processing and return result if CS would reject this new user
                    If result = "DuplicateUserName" Then
                        Return -1 * CType(MembershipCreateStatus.DuplicateUserName, Integer)
                    End If
                    If result = "DuplicateEmail" Then
                        Return -1 * CType(MembershipCreateStatus.DuplicateEmail, Integer)
                    End If
                    If result = "InvalidUserName" Then
                        Return -1 * CType(MembershipCreateStatus.InvalidUserName, Integer)
                    End If
                    ''' -------------------------------------------------------------------------
                    ''' End Community Server Check CanCreateUser
                    ''' -------------------------------------------------------------------------

    - In the same function, add the following before the line "Return UserId"

                    ''' -------------------------------------------------------------------------
                    ''' Start Community Server Create User
                    ''' -------------------------------------------------------------------------
                    If UserId <> -1 Then
                        result = cs.CreateUser(objUser.Membership.Username, objUser.Membership.Password, objUser.Membership.Email)
                    End If
                    ''' -------------------------------------------------------------------------
                    ''' End Community Server Create User
                    ''' -------------------------------------------------------------------------

    - In the Public Methods Region, in Public Function SetPassword (the second function of this name), add the following code before the line "Catch ex As Exception"

                    ''' -------------------------------------------------------------------------
                    ''' Start Community Server Change Password
                    ''' -------------------------------------------------------------------------
                    If confirmPassword = newPassword Then
                        Dim token As UsernameToken = New UsernameToken("INSERT-UNIQUE-USERNAME", "INSERT-UNIQUE-PASSWORD", PasswordOption.SendHashed)
                        Dim cs As CommunityServer.UserServiceWse = New CommunityServer.UserServiceWse
                        cs.RequestSoapContext.Security.Timestamp.TtlInSeconds = 300
                        cs.RequestSoapContext.Security.Tokens.Add(token)
                        cs.RequestSoapContext.Security.Elements.Add(New EncryptedData(token))
                        ' sign the UsernameToken
                        cs.RequestSoapContext.Security.Elements.Add(New MessageSignature(token))
                        Dim result As Boolean
                        result = cs.ChangePassword(objUser.Membership.Username, oldPassword, newPassword)
                    End If
                    ''' -------------------------------------------------------------------------
                    ''' End Community Server Change Password
                    ''' -------------------------------------------------------------------------

    - In the Public Methods Region, in Public Sub UpdateUser, add the following code before the line "Catch ex As Exception"

                    ''' -------------------------------------------------------------------------
                    ''' Start Community Server Update User
                    ''' -------------------------------------------------------------------------
                    Dim token As UsernameToken = New UsernameToken("INSERT-UNIQUE-USERNAME", "INSERT-UNIQUE-PASSWORD", PasswordOption.SendHashed)
                    Dim cs As CommunityServer.UserServiceWse = New CommunityServer.UserServiceWse
                    cs.RequestSoapContext.Security.Timestamp.TtlInSeconds = 300
                    cs.RequestSoapContext.Security.Tokens.Add(token)
                    cs.RequestSoapContext.Security.Elements.Add(New EncryptedData(token))
                    ' sign the UsernameToken
                    cs.RequestSoapContext.Security.Elements.Add(New MessageSignature(token))
                    Dim result As Boolean
                    result = cs.UpdateUser(objUser.Membership.Username, objUser.Membership.Email, objUser.Membership.Approved.ToString)
                    ''' -------------------------------------------------------------------------
                    ''' End Community Server Update User
                    ''' -------------------------------------------------------------------------

    - Right click the DotNetNuke project > Rebuild

    9. Modify CS URLS and UI
    - In the CommunityServerWeb project open the file /Themes/default/Skins/Skin-EditProfile.ascx
    - Switch to the HTML view and search for id="PrivateEmail"
    - Add Enabled="False" to this TextBox
    - Save the file

    - In the CommunityServerWeb project open the file SiteUrls.config (see the User paths section)
    - Direct the CS Registration link to the DNN address e.g:
     - Change:  <url name="user_Register" location = "user" path="CreateUser.aspx?ReturnUrl={0}" />
     - To:  <url name="user_Register" location = "" path="http://localhost/dotnetnuke/Home/tabid/36/ctl/Register/Default.aspx" />
    - Direct the CS Password link to the DNN address e.g:
     - Change: <url name="user_ChangePassword" location = "user" path="ChangePassword.aspx" />
     - To:  <url name="user_ChangePassword" location = "" path="http://localhost/dotnetnuke/Home/tabid/36/ctl/Register/Default.aspx" />
    - Save the file

    10. Add a menu link
    - Login to http://localhost/dotnetnuke using the admin account
    - Add a page named Community, allow All Users to view the page, set the Link Url to "URL" and set the Location to http://localhost/cs

    ** NOTE: The values INSERT-UNIQUE-USERNAME and INSERT-UNIQUE-PASSWORD should be changed to your own values but could be left as-is for development environments, they are used in:
    - CS, UserService.asmx.cs, once each
    - CS, policyCache.config, username only in two different places
    - DNN, UserController.vb, once each for each DNN function changed

    ** You should now be able to:
    - Register a new user using DNN, the new user will also be added to CS
    - Login (from DNN or CS) without the "Remember Login" option and remain logged into both CS and DNN using the same browser window (or same thread/process)
    - Login (from DNN or CS) with the "Remember Login" option and remain logged into both CS and DNN indefinately using any browser window
    - Logout from CS or DNN
    - Change the user password using the DNN interface with the change being synchronised in CS (CS page will redirect to DNN)
    - Change the user email address using the DNN interface with the change being synchronised in CS (CS TextBox is now disabled)
    - Remove the user Authorization in DNN and have the change synchronised in CS (this will not synch if changed in CS)
    - Delete the user using the DNN interface (deleted from DNN) and have the user disapproved in CS with their email address changed to "[MemberID].inactive@host.local" and the password reset (users cannot be deleted from CS). The username will not be able to be registered a second time in DNN or CS

    ** The functionality of this SSO Method has received very limited testing. Testing has been confined to the environment and changes outlined in this post. For example, testing was not carried out using Private or Verified User Registration

    I look forward to your comments, suggestions and improvements.

    Regards,
    gsc4 (Steve).


    UPDATE: fatatiba has made a post about how to share the membership database here: http://www.communityserver.org/forums/481547/ShowPost.aspx - It is good to see that sharing the membership database in this way is possible, I can't wait to try it out and see what the data looks like. However, no change has been made to the DNN or CS data using the method outlined above, it is only synchronised. I feel this may be a cleaner approach with regard to the data which may allow for an easier move to a different solution later (I haven't tried fatatiba's method yet). I'm sure each method has relative strengths and weaknesses depending on the environment or requirement it is applied to, and let's not forget that a module is on the way and so are changes to Membership.

    THANKS, to John Hodgkinson for the idea.

  • Re: How-To: CS and DNN SSO for Developers

    05-17-2005, 12:36 AM
    • Participant
      965 point Participant
    • gsc4
    • Member since 05-29-2003, 3:24 AM
    • Posts 193

    UPDATE: I have added the following to the CanCreateUser WebMethod in UserService.asmx.cs in the CommunityServerWeb project:

    // Check escape character

    if ( Regex.IsMatch(username,@"[\\]+") )

    result = "InvalidUserName";

     

    The whole function becomes:

    [WebMethod]

    public string CanCreateUser(string username, string email)

    {

    string result = "Success";

    // Check if username already exists

    User usernameLookup = Users.FindUserByUsername( username );

    if (usernameLookup.UserID != 0)

    result = "DuplicateUserName";

    // Check if email already exists

    User emailLookup = Users.FindUserByEmail(email);

    if (emailLookup.Member.Email != null)

    result = "DuplicateEmail";

    // Check if username is disallowed

    if ( DisallowedNames.NameIsDisallowed(username) == true )

    result = "InvalidUserName";

    // Check if username meets site regular expression

    if ( !Regex.IsMatch(username,"^" + SiteSettingsManager.GetSiteSettings().UsernameRegex) )

    result = "InvalidUserName";

    // Check escape character

    if ( Regex.IsMatch(username,@"[\\]+") )

    result = "InvalidUserName";

    // Otherwise return success

    return result;

    }

    EDIT: You may need to add the following along with the existing using statements at the begining of the file:
      using System.Text.RegularExpressions;

  • Sad [:(] Re: How-To: CS and DNN SSO for Developers

    05-26-2005, 11:36 AM
    • Member
      405 point Member
    • gmanupnorth
    • Member since 03-31-2005, 2:34 PM
    • Halifax, Nova Scotia Canada
    • Posts 81
    Thanks again for your hard work Steve. The SSO is working fine if I browse to my DNN site directly from my dev box...but if I try to brwose from another PC in my office, the SSO does not work when I go to post to a thread and I get the CS login page.

    Any ideas where to start looking to solve this problem??


    Gordon
    Gordo
    "The Library...were we bury the lies."
  • Re: How-To: CS and DNN SSO for Developers

    05-26-2005, 12:45 PM
    here is an integration from a while ago that is on the CommunityServer forums

    http://www.communityserver.org/forums/485689/ShowPost.aspx#485689

    No code changes but DB changes.
  • Re: How-To: CS and DNN SSO for Developers

    05-26-2005, 7:51 PM
    • Participant
      965 point Participant
    • gsc4
    • Member since 05-29-2003, 3:24 AM
    • Posts 193

    Gordon,

    DNN and CS both use the url used to access them to decide which content to return. For example, if you set-up DNN and CS on your workstation using http://localhost/dotnetnuke and http://localhost/cs (or something like this) then these urls will be tied to your portal and your community. If you look in the PortalAlias table in DNN (3.0.13) you will see the url your using in the HTTPAlias column. If you look in the cs_Sites table in CS (1.0 Build 50218) you will see the url your using in the SiteUrl column.

    If you want to switch from using http://localhost to using http://mypcname the first thing you should try is changing the values in the fields mentioned above accordingly
    e.g. from localhost/dotnetnuke to mypcname/dotnetnuke and from localhost/cs to mypcname/cs

    The single sign-on discussed in this thread relies on the fact that the same domain name is used to access both the DNN app and the CS app. For example, if you were to login to DNN at http://localhost/dotnetnuke but then browse to http://mypcname/cs you would need to login again (this would be the same for sub-domains). This is due to the default cookie processing setup in both apps. If you use the same domain the login will work fine.

    If you have checked all of the above and followed the initial instructions exactly then you should try logging out of the portal and the community and clear all cookies before trying again using the same domain name. You could also try going back through the instructions using the URL you are using from the other PC. If you were going to use this on a live site I would recommend using the proper URL from the very start and ensuring only one domain name is linked to the sites.

    As, I posted in the CS forum thread, for other DNN folks who just read this:
    "You can see this working here: www.gameserve.com.au (this is an active community, please don't register here if you do not intend to be a part of the community - or at least use a username prefaced with Test and don't post anything to the forum)."

    Regards,
    Steve.

  • Re: How-To: CS and DNN SSO for Developers

    05-27-2005, 11:49 AM
    • Member
      405 point Member
    • gmanupnorth
    • Member since 03-31-2005, 2:34 PM
    • Halifax, Nova Scotia Canada
    • Posts 81

    Thanks Steve. The changes that you documented worked and the two sites are now working with the SSO.

     

     

    Gordo
    "The Library...were we bury the lies."
  • Cool [cool] Re: How-To: CS and DNN SSO for Developers

    05-28-2005, 2:49 PM
    Hi,

    Would be nice to have single sign on between CommunityServer and Dotnetnuke by Portal intead by Host!

    Login/get/find/insert/update methodo should include PortalID as parameter

    Today if one Portal have a user "Mike" another portal with different domain can not have a another user Mike becouse it is by host.

    To host another account you have to create another instance of IIS and create another Database.

    With SSO by Portal it could be just another Portal Account.

    José Augusto Guimarães
  • Re: How-To: CS and DNN SSO for Developers

    05-28-2005, 11:36 PM
    • Participant
      965 point Participant
    • gsc4
    • Member since 05-29-2003, 3:24 AM
    • Posts 193

    That's a great idea. It shouldn't be too hard for any DNN junky to adapt this in that way.

    As I run my own server and have discrete rather than related sites I always use a new web and database. I have only ever used a second portal in the one DB for an alternate language version of the same site.

    I guess I could try to lend a hand to anyone who wants to have a shot at the adaptation. The first thing to do would be to ascertain exactly how each app (DNN and CS) handle user accounts with respect to multiple portals and multiple communities. For example, can one user account be used to access multiple DNN portals? How about multiple CS communities?

    Regards,
    Steve.

  • Re: How-To: CS and DNN SSO for Developers

    06-15-2005, 4:14 PM
    • Member
      10 point Member
    • Craugory
    • Member since 06-15-2005, 8:07 PM
    • Posts 2

    Thanks so much for this.  It works great on my Dev Box but when I compile and upload the CS solution to my production server I get the following error:

     

     

    Source Error:

     
    Line 215:      <soapExtensionTypes>
    Line 217:        <add type="Microsoft.Web.Services2.WebServicesExtension, Microsoft.Web.Services2, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" priority="1" group="0" />
    Line 218:      </soapExtensionTypes>
    Line 219:    </webServices>


    Source File: c:\hosting\webhost4life\member\crugory\symposium.net\web.config    Line: 217

    Assembly Load Trace: The following information can be helpful to determine why the assembly 'Microsoft.Web.Services2' could not be loaded.

     
    === Pre-bind state information ===
    LOG: DisplayName = Microsoft.Web.Services2, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
     (Fully-specified)
    LOG: Appbase = file:///c:/hosting/webhost4life/member/crugory/symposium.net
    LOG: Initial PrivatePath = bin
    Calling assembly : (Unknown).
    ===
     
    LOG: Publisher policy file is not found.
    LOG: No redirect found in host configuration file (C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\aspnet.config).
    LOG: Using machine configuration file from C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\config\machine.config.
    LOG: Post-policy reference: Microsoft.Web.Services2, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
    LOG: Attempting download of new URL file:///C:/WINDOWS/Microsoft.NET/Framework/v1.1.4322/Temporary ASP.NET Files/symposium.net/e09a1801/bea532b4/Microsoft.Web.Services2.DLL.
    LOG: Attempting download of new URL file:///C:/WINDOWS/Microsoft.NET/Framework/v1.1.4322/Temporary ASP.NET Files/symposium.net/e09a1801/bea532b4/Microsoft.Web.Services2/Microsoft.Web.Services2.DLL.
    LOG: Attempting download of new URL file:///c:/hosting/webhost4life/member/crugory/symposium.net/bin/Microsoft.Web.Services2.DLL.
    WRN: Comparing the assembly name resulted in the mismatch: Build Number

     

    I’ve uploaded all the dlls into the bin directory including Microsoft.Web.Services2.dll and System.Web.Services.dll. 

     

    Any thoughts?

     

    Tia.

    Craig.

  • Re: How-To: CS and DNN SSO for Developers

    06-15-2005, 7:05 PM
    • Participant
      965 point Participant
    • gsc4
    • Member since 05-29-2003, 3:24 AM
    • Posts 193
    Just quickly (really busy at work right now):

    - I think you might be right to think of the Microsoft.Web.Services2.dll as this is a part of Web Services Enhancements 2.0 SP3.
    - You would have installed Web Services Enhancements 2.0 SP3 on your development box but I have no idea whether this would be installed on the server used for your webhost4life account - have you asked them?
    (I'm not sure that simply copying the DLL to your websites BIN folder will work).

    Regards,
    gsc4

  • Re: How-To: CS and DNN SSO for Developers

    06-20-2005, 12:39 PM
    • Member
      10 point Member
    • Craugory
    • Member since 06-15-2005, 8:07 PM
    • Posts 2
    You were right, WSE 2 isn't wasn't installed by default... it's up and running now :)
    Thank you so much.
    Craig
  • Re: How-To: CS and DNN SSO for Developers

    08-09-2005, 9:17 PM
    • Participant
      965 point Participant
    • gsc4
    • Member since 05-29-2003, 3:24 AM
    • Posts 193

    UPDATE: This works for DotNetNuke 3.1 and Community Server 1.1 (people have already dicovered this, but I thought it should be stated here).

    UPDATE: When installing Community Server 1.1 you can force it to use the keys generated by the DotNetNuke installer (this is not necessary for this to work). To force this you can edit the ../Installer/default.aspx, for example:

    <code>
     protected string ValidationKey
     {
      get
      {
       string key = ViewState["ValidationKey"] as string;
       if(key == null)
       {
        key = CreateKey(20);
        ViewState["ValidationKey"] = key;
       }
       return "INSERT-MACHINEVALIDATIONKEY-VALUE-FROM-DOTNETNUKE"; 
      }
     }

     protected string DecryptionKey
     {
      get
      {
       string key = ViewState["DecryptionKey"] as string;
       if(key == null)
       {
        key = CreateKey(24);
        ViewState["DecryptionKey"] = key;
       }
       return "INSERT-MACHINEDECRYPTIONKEY-VALUE-FROM-DOTNETNUKE"; 
      }
     }
    </code>

  • Re: How-To: CS and DNN SSO for Developers

    08-10-2005, 8:16 PM
    • Participant
      900 point Participant
    • eric@digitrends
    • Member since 02-02-2004, 10:41 PM
    • Sydney Australia
    • Posts 180
    Thanks for all your help mate on SSO solution.

    I plan to try it this weekend. I have a DNN2.12 module that i need to migrate users from. I was going to get the DNNMasters Membership Management Suite PRO from Snowcovered to move the users into 3.1 format.

    Do you know if I start migrating users across, will the CS database get updated as well?

    I have an added complication that I have to move forums from dotnetbb to Cs as well lol

    regards
    Eric
  • Re: How-To: CS and DNN SSO for Developers

    08-13-2005, 6:10 AM
    • Participant
      900 point Participant
    • eric@digitrends
    • Member since 02-02-2004, 10:41 PM
    • Sydney Australia
    • Posts 180

    Steve,

    I implemented it and i can add a user in dnn and see it reflected in CS however i can't seem to log in to one and have it login in to another.

    I have a site beta.site.com and defined beta.site.com/dnn and beta.site.com/cs and did as you did with window 2003 directing the url to beta.site.com/dnn

    any clues where i should look at?

    regards
    Eric

  • Re: How-To: CS and DNN SSO for Developers

    08-15-2005, 7:55 AM
    • Participant
      965 point Participant
    • gsc4
    • Member since 05-29-2003, 3:24 AM
    • Posts 193

    Eric,

    It's not much information to go on but the best bet is to probably check Step 4. It sounds to me like the web service is being called correctly because you have your user synchronisation, but this step contains the crucial stuff for the SSO to work. This basically ensures that both applications are using the same cookie and encrypting using the same keys. Note that the keys are edited in the appSettings section AND added to the system.web section.

    Regards,
    gsc4.

Page 1 of 2 (23 items) 1 2 Next >