Oct 31, 2007

xsd maxOccurs="2" minOccurs="1"

XSD allow you to specified maxOccurs="2" minOccurs="1" in sequence and and element. What is the difference. Below is section

            
            
            
            
            
            
            
            
            
sequence with maxOccurs more than 1 means you can repeat the whole section more than one time, element with maxOccurs more than 1 means you can repeat that element for more than one time. There is no difference if the sequence has only one element. You can put maxOccurs on the sequence or the element. If there are more than one element in sequence there will be difference.
            
            1
            2
            3
            dfsdf
            1
            2222
            fred
            
            
Generally, we should put maxOccur on element rather on sequence. Or you can convert a sequence into a complex type and make that a element of that type, and put maxOccur on that element.

Oct 28, 2007

Debugging Form Authentication API in asp.net

  FormsAuthentication.RedirectFromLoginPage(UsernameText.Text, false);
This method performs serveral tasks at once:
  1. It creates an authentication ticket for the user.
  2. It encryptes the information from the authentication ticket.
  3. It creates a cookie to persist the encrypted ticket information.
  4. It adds the cookie to the HTTP response, sending it to the client.
  5. It redirects to the user to orignal requested page.

The second parameter of RedirectFromLoginPage() indicates whether a persistent cookie should be created. Persistent cookies are stored on the user’s hard drive and can be reused for later visits. If the value is false and user closes the browser, the cookie is immediately removed. The cookie returned is something like

"Set-Cookie: FormCookie=0AA27321DF30103594921784C0C2D721208FC509952739C2E5530F3BE9F8472E6A68283AF5C7DD539D56D2BD2CC39FCC3E488503B8299BCE04307B934B4B8B5C91224CBDBD81EAB3753F4FDEC0518199; path=/; HttpOnly".

If it is true, it will set the cookie for persisted for the timeout time in the forms tag. The cookie you get is something like

"Set-Cookie: FormCookie=C63E21885ED5930E10A2D10CC262FA0929B68DD467B05566226346CC612DE7728244C8122D8445085616412C45A9B47F2B430F369EA68E5596A9642E4FAD4413AA3D170056130847E175292F01FEED1A; expires=Mon, 29-Oct-2007 04:43:35 GMT; path=/; HttpOnly".

If you want to dynamically set the cookie's expiration date, you need to do manually.

if (FormsAuthentication.Authenticate(UsernameText.Text, PasswordText.Text))
{
            // Create the authentication cookie
            HttpCookie AuthCookie;
            AuthCookie = FormsAuthentication.GetAuthCookie(
            UsernameText.Text, true);
            AuthCookie.Expires = DateTime.Now.AddDays(10);
            // Add the cookie to the response
            Response.Cookies.Add(AuthCookie);
            // Redirect to the originally requested page
            Response.Redirect(FormsAuthentication.GetRedirectUrl(
            UsernameText.Text, true));
}
else
{
            // User name and password are not correct
            LegendStatus.Text = "Invalid username or password!";
}

When you Signout, you will get the response in header

"Set-Cookie: FormCookie=; expires=Tue, 12-Oct-1999 00:00:00 GMT; path=/; HttpOnly".

FormCookie is actually a ticket in a serialized string. You can also manually created the ticket, and then manually create a cooke and assign the cookie value with the ticket string.

private void btnLogin_Click(object sender, System.EventArgs e)
{
            SqlDataReader sdr;
            // Create a connection
            SqlConnection sc = new SqlConnection(Application["DSN"].ToString());

            // Open the database connection
            sc.Open();

            // Create a command to get the user
            SqlCommand cmd = new SqlCommand("GetUser '" + txtEmail.Text + "', '" + txtPassword.Text + "'", sc);

            // Execute the command
            sdr = cmd.ExecuteReader();

            // Attempt to read the first record
            if (sdr.Read())
            {
            // close the datareader
            sdr.Close();
            // Get the list of roles the user is in
            SqlDataReader drRoles;
            SqlCommand cmdRoles = new SqlCommand("GetRoles '" + txtEmail.Text + "'", sc);
            ArrayList arRoles = new ArrayList();

            // Execute the command
            drRoles = cmdRoles.ExecuteReader();

            // Get a string builder to store the roles in a csv list
            System.Text.StringBuilder bldr = new System.Text.StringBuilder();

            // Loop through the list of roles and get them
            while (drRoles.Read())
            {
            bldr.Append(drRoles["Role"]);
            bldr.Append(",");
            }

            // Strip the last comma
            bldr.Remove(bldr.Length - 1, 1);

            // Create an authentication ticket
            // Place a serialized representation of the roles into the authentication ticket
            FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, txtEmail.Text, DateTime.Now, DateTime.Now.AddMinutes(20), false, bldr.ToString());

            // Get the encrypted version of the ticket
            string strEncrypted = FormsAuthentication.Encrypt(ticket);

            // Put it into a cookie
            HttpCookie hc = new HttpCookie(FormsAuthentication.FormsCookieName, strEncrypted);
            hc.Expires = DateTime.Now.AddMinutes(20);


            // Add it to the cookies collection
            Response.Cookies.Add(hc);

            // Redirect the user to the page they requested
            string strReturnURL = Request.Params["ReturnUrl"].ToString();
            if (strReturnURL != "") Response.Redirect(strReturnURL);
            }
            else
            {
            // Show a message that the credentials are invalid
            lblInvalidPassword.Visible = false;
            }
            }

Oct 27, 2007

Improving the Performance of a Reusable Authorization Framework

  • Batch authorization queries whenever possible to avoid frequent out-of-process round trips. For example, retrieve roles for multiple users in a single request.
  • Cache the authorization data close to where you will use it with an in-memory store, such as a Hashtable. The cache also reduces dependencies on the location and organization of the underlying store. You might also want a separate cache for each physical computer, for performance and increased security.
  • Implement scheduled or on-demand refreshes of the cache information.
  • Implement lazy initialization of the authorization cache to avoid retrieving authorization information when no access checks will occur.

How to Change the Principal in an ASP.NET Application

protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
   // Check whether there is a current user and that
   // authentication has occurred.
   if (!(HttpContext.Current.User == null))
   {
      IIdentity CurrentUserIdentity = HttpContext.Current.User.Identity;
      // Check to see whether the Principal was cached.
      string CachedPrincipalKey = "CachedPrincipal" + id.Name;
      if (HttpContext.Current.Cache[CachedPrincipalKey] == null)
      {
            // Load the principal by calling the GetPrincipal method.
            HttpContext.Current.Cache.Add(
            CachedPrincipalKey,
            GetPrincipal(CurrentUserIdentity),
            null,
            DateTime.MaxValue,
            new TimeSpan(0,30,0),
            CacheItemPriority.Normal,
            null);
      }
      HttpContext.Current.User = (IPrincipal)
      HttpContext.Current.Cache[CachedPrincipalKey];
   }
}


            IF EXISTS (select * from dbo.sysobjects where id = object_id(N'[UserRoles]') and
            OBJECTPROPERTY(id, N'IsUserTable') = 1)
            DROP TABLE [UserRoles]
            GO
            CREATE TABLE [UserRoles] (
            [UserName] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
            [Role] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
            ) ON [PRIMARY]
            GO
            INSERT INTO [Claims].[dbo].[UserRoles]([UserName], [Role])
            VALUES('Chris', 'Admin')
            INSERT INTO [Claims].[dbo].[UserRoles]([UserName], [Role])
            VALUES('Doug', 'Admin')
            INSERT INTO [Claims].[dbo].[UserRoles]([UserName], [Role])
            VALUES('Doug', 'Manager')
            GO

            private IPrincipal GetPrincipal(IIdentity user)
            {
            //Get the roles from the table based on a user name only.
            string SQL =
            "SELECT Role FROM UserRoles WHERE UserName = '" + user.Name + "'";
            SqlConnection MyConnection = new SqlConnection(
            "data source=localhost;initial catalog=Claims;Integrated Security=SSPI");
            SqlCommand MyCommand = new SqlCommand(SQL, MyConnection);
            MyConnection.Open();
            SqlDataReader MyDataReader = MyCommand.ExecuteReader();
            ArrayList alRoles = new ArrayList();
            // Load the roles into an ArrayList.
            while (MyDataReader.Read())
            alRoles.Add(MyDataReader.GetString(0));
            MyDataReader.Close();
            MyCommand.Dispose();
            MyConnection.Close();
            MyConnection.Dispose();
            // Convert the roles to a string[], and load GenericPrincipal.
            string[] myRoles = (string[])al.ToArray(typeof(string));
            return new GenericPrincipal(
            new GenericIdentity(user.Name, user.GetType()),
            myRoles);
            }

Impersonator

Please also reference this article http://blogs.msdn.com/jimmytr/archive/2007/04/14/writing-test-code-with-impersonation.aspx and http://www.123aspx.com/redir.aspx?res=31987
public class Impersonator
{
   // private members for holding domain user account credentials
   private string username = String.Empty;
   private string password = String.Empty;
   private string domain = String.Empty;
   // this will hold the security context for reverting back to the client after impersonation operations are complete
   private WindowsImpersonationContext impersonationContext = null;

   // disable instantiation via default constructor
   private Impersonator()
   {}

   public Impersonator(string username, string domain, string password)
   {
     // set the properties used for domain user account
     this.username = username;
     this.domain = domain;
     this.password = password;
   }

   private WindowsIdentity Logon()
   {
     IntPtr handle = new IntPtr(0);
     handle = IntPtr.Zero;

            const int LOGON32_LOGON_NETWORK = 3;
            const int LOGON32_PROVIDER_DEFAULT = 0;

     // attempt to authenticate domain user account
     bool logonSucceeded = LogonUser(this.username, this.domain, this.password, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, ref handle);

     if(!logonSucceeded)
     {
       // if the logon failed, get the error code and throw an exception
       int errorCode = Marshal.GetLastWin32Error();
       throw new Exception("User logon failed. Error Number: " + errorCode);
     }

     // if logon succeeds, create a WindowsIdentity instance
     WindowsIdentity winIdentity = new WindowsIdentity(handle);

     // close the open handle to the authenticated account
     CloseHandle(handle);

     return winIdentity;
}


public void Impersonate()
{
   // authenticates the domain user account and begins impersonating it
   this.impersonationContext = this.Logon().Impersonate();
}


   public void Undo()
   {
     // rever back to original security context which was store in the   WindowsImpersonationContext instance
     this.impersonationContext.Undo();
   }

   [DllImport("advapi32.dll", SetLastError=true)]
   private static extern bool LogonUser(string lpszUsername,
   string lpszDomain,
   string lpszPassword,
   int dwLogonType,
   int dwLogonProvider,
   ref IntPtr phToken);

   [DllImport("kernel32.dll", CharSet=CharSet.Auto)]
   private static extern bool CloseHandle(IntPtr handle);

}

How To: Use Forms Authentication with Active Directory in ASP.NET 1.1

http://msdn2.microsoft.com/en-us/library/aa302397.aspx

More on Kerberos

By default, the Microsoft® Windows® 2000 operating system uses the Kerberos protocol for authentication. This How To describes how to configure Kerberos delegation, a powerful feature that allows a server, while impersonating a client, to access remote resources on behalf of the client.

Delegation is a very powerful feature and is unconstrained on Windows 2000. It should be used with caution. Computers that are configured to support delegation should be under controlled access to prevent misuse of this feature. Windows .NET Server will support a constrained delegation feature.

When a server impersonates a client, Kerberos authentication generates a delegatelevel token (capable of being used to respond to network authentication challenges from remote computers) if the following conditions are met:

  1. The client account that is being impersonated is not marked as sensitive and cannot be delegated in Microsoft Active Directory® directory service.
    1. Log onto the domain controller using an administrator account.
    2. On the taskbar, click the Start button, point to Programs, point to Administrative Tools, and then click Active Directory Users and Computers.
    3. Under your domain, click the Users folder.
    4. Right-click the user account that is to be delegated, and then click Properties.
    5. Click the Account tab.
    6. Within the Account options list, make sure Account is sensitive and cannot be delegated is not selected.
    7. Click OK to close the Properties dialog box.
  2. The server process account (the user account under which the server process is running, or the computer account if the process is running under the local SYSTEM account) is marked as trusted for delegation in Active Directory.
    This procedure ensures that the account used to run the server process (the process that performs impersonation) is allowed to delegate client accounts. You must configure the user account under which the server process runs, or if the process runs under the local SYSTEM account, you must configure the computer account. Perform the appropriate procedure that follows, depending on if your server process runs under a Windows account or a local SYSTEM account.
    1. To confirm that the server process account is trusted for delegation if the server process runs under a Windows user account
      1. Within the Users folder of Active Directory Users and Computers, right-click the user account that is used to run the server process that will impersonate the client, and then click Properties.
      2. Click the Account tab.
      3. Within the Account options list, click Account is trusted for delegation.
    2. To onfirm that the server process account is trusted for delegation if the server process runs under the local SYSTEM account
      1. Right-click the Computers folder within Active Directory Users and Computers, and then click Properties.
      2. Right-click the server computer (where the process that impersonates the client will be running), and then click Properties.
      3. On the General page, click Trust computer for delegation.

Oct 21, 2007

NTLM vs Kerberos

Both NTLM and Kerberos are forms of Integrated Windows Authentication. NTLM uses a challenge-response protocal to authenticatet the client to the server. It begins when the client attempts to connect to a secure application. The server sends a challenge to the client, and the client responds with a hashed value that the server can use to validate the user and password. All of this is seamless to the end user who simply sees the requested web page open in the browser. NTLM is simple, works well, and developers have often been able to ignore authentication concerns because it was essentially transparent. As security concerns have grown, however, the need for a more secure authentication provider has become increasingly obvious. This is where Kerberos comes in to the picture.

Kerberos is a ticket-based authentication protocol. When a client wants to access a secure application, it requests a ticket from the key distribution center (KDC), which is the server running Active Directory. The KDC then creates a ticket based on the user credentials stored in Active Directory. The ticket is then sent back to the client, which can only use the ticket if it has the correct password. Once the user is authenticated, the ticket is cached locally where it remains until it expires.

Kerberos has several advantages over NTLM that SharePoint developers should care about. First, Kerberos has much better performance than NTLM. Because Kerberos caches credentials, servers can respond more quickly than under NTLM. Kerberos is also more secure than NTLM because the client can essentially authenticate the server as well as have the server authenticate the client. The biggest reason for developers to care about Kerberos, however, is delegation.

Take a step back and consider the process of connecting to a WSS team site using NTLM authentication. We know that NTLM will successfully authenticate a user that has a Windows account and grant access to the team site, which will then appear in the browser. While most of the page content will appear correctly, what if a web part on that page displays information from a line-of-business system with its own separate database? The web part itself must also authenticate against this other database. What credentials does it use? In many cases, we want the web part to use the same credentials as the current user. In other words, we want the web part to impersonate the current user.

SharePoint sites are set up so that web parts will initially impersonate the user accessing them. The user credentials may subsequently be passed to any system residing on the same server as SharePoint or on a different server that requires only a single additional authentication. If the data source requires a second authentication—like when you access a web service, which subsequently accesses a database—the impersonation will fail. This is typically referred to as the “double-hop” issue.

Kerberos, on the other hand, supports impersonation across machines. This type of extended impersonation is known as delegation. If the end user were authenticating to the team site using Kerberos, the web part would successfully authenticate to the line-of-business database and information would appear in the page.

It’s important to point out that Kerberos requires some additional configuration that can only be accomplished if you have rights to Active Directory. Additionally, there are other ways to solve the double-hop issue. Many developers, for example, utilize a SQL Server standard security account buried in a connection string that a web part uses to access the database. The MOSS SSO service can also be used to gain access to any system in the enterprise. The bottom line, however, is that Kerberos is superior to NTLM in several ways and you should utilize it where you can. In the exercise in this chapter, “Creating a Development Environment,” I detail the steps necessary to set up and configure Kerberos.

Oct 10, 2007

Referencing a schema in an XML instance document

            
                            My Life and Times
            Paul McCartney
            July, 1998
            94303-12021-43892
            McMillin Publishing
                    ...
            

Global element vs Local element in xsd

Global element declarations, global type definitions: These are element declarations/type definitions that are immediate children of Local element declarations, local type definitions: These are element declarations/type definitions that are nested within other elements/types.
So what if an element or type is global or local. What practical impact does it have? Answer: only global elements/types can be referenced (i.e., reused). Thus, if an element/type is local then it is effectively invisible to the rest of the schema (and to other schemas).

xsd type inheritance

                 
            
            
            
            
                
                        
            
            
                    
            
            

Oct 9, 2007

Enable InfoPath intellisense in VS.NET IDE

C:\>copy "C:\Program Files\Microsoft office\Office12\Microsoft.Office.InfoPath.x ml" "C:\WINDOWS\assembly\GAC_MSIL\Microsoft.Office.InfoPath\12.0.0.0__71e9bce111 e9429c"
C:\>copy "C:\Program Files\Microsoft office\Office12\Microsoft.Office.Interop.In foPath.SemiTrust.xml" "C:\WINDOWS\assembly\GAC\Microsoft.Office.Interop.InfoPath .SemiTrust\11.0.0.0__71e9bce111e9429c"