Thursday, August 25, 2005

I’ll be doing a social experiment for the next few weeks: no reliable Internet access.

It will be interesting to relive how our ancestors lived before 1995.

8/25/2005 11:49:21 PM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [427]  |  Trackback

I have been busy preparing for the first run of the MS Indigo (WCF) class in Redmond.

Lots of interest, lots of sharp questions, lots of fun. If this class is any indication, WCF should be very successful.

I was reminded once more of what make Microsoft special: people here are really hungry for knowledge.

8/25/2005 11:38:43 PM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [306]  |  Trackback
 Monday, June 13, 2005
Until legal implications are clarified.   
6/13/2005 2:17:57 AM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [2588]  |  Trackback
 Friday, June 10, 2005

I decompiled and recompiled Indigo’s System.ServiceModel.dll and System.Transactions.Indigo.dll.

You can download it here.

Diving inside Indigo’s code is a great way to learn how it works. For example, add a breakpoint in the constructor HttpOutput and spy what messages are sent when.

 

There are a few differences:

-          The public key is different – you have to go to machine.config and change the public key token for System.ServiceModel.dll.

-          There are still some glitches. If you find any difference, send me an email.

 

Enjoy!

 

6/10/2005 6:01:40 AM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [2672]  |  Trackback
 Wednesday, June 01, 2005

Consider code below [1]. The main window contains a list box with 4 times "Hello" in it.

However it behaves funny. why? Because the list box contains four times the same instance of "Hello". Understanding string and interning is useful after all.

[1]

    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application app = new Application();
            app.StartingUp += new StartingUpCancelEventHandler(app_StartingUp);
            app.Run();
        }

        static void app_StartingUp(object sender, StartingUpCancelEventArgs e)
        {
            Window w = new Window();
            ListBox b = new ListBox();
            w.Content = b;
            b.Items.Add("Hello");
            b.Items.Add("Hello");
            b.Items.Add("Hello");
            b.Items.Add("Hello");
            w.Show();
        }
    }

6/1/2005 4:16:11 PM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [2138]  |  Trackback
 Wednesday, April 13, 2005

A bitpiece of trivia:

static void Main(string[] args)

{

   int i = 0;

   i = i++;

}

What is the value of i at the end of this method?

in C#: 1

in C++: 0

in managed C++: 0

 

4/13/2005 10:29:46 PM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [1417]  |  Trackback
 Thursday, March 31, 2005

System.Security.Authorization.dll

 

Indigo includes a new assembly: System.Security.Authorization.dll.

This assembly defines claims and tokens.

Claims

 

A claim is a piece of information the sender of the messages claims to be true. When the listener receives a message, she should verify the claims and makes authorization decisions based on them.

 Claims implement the IClaim interface. Examples of implementers include

AgeClaim: “I claim my age is 21 (so I can buy alcohol on the web ?)”

UserNameClaim: ‘I claim my username is …”

RoleClaim: ‘I claim I am in role …”

WindowsSidClaim: “I claim I have a given windows security identifier”

All in all, Indigo comes with a few dozens claim types.

Security tokens

Claims are not directly included in a message; they are embedded inside a security token.

A security token provides two things:

  • A series of claims
  • A set of cryptographic algorithms

In fact, security tokens implement ISecurityToken. ISecurityToken itself derives from IClaimsProvider (provides a set of claims) and ICryptoProvider (provides crypto…)

IClaimsProvider looks like this:

public interface IClaimsProvider
{
      IList<IClaimSet> ClaimSets { get; }

}

ICryptoProvider looks like this

public interface ICryptoProvider
{
      IList<ICrypto> CryptoCollection { get; }

}

ICrypto looks like this

public interface ICrypto
{
      byte[] DecryptKey(string algorithmUri, byte[] keyData);
      byte[] EncryptKey(string algorithmUri, byte[] keyData);
      bool IsAsymmetricAlgorithm(string algorithmUri);
      bool IsSupportedAlgorithm(string algorithmUri);
      bool IsSymmetricAlgorithm(string algorithmUri);

}

Examples of tokens include:

X509Token: the sender has an X509 certificate

WindowsToken: the sender is a windows user. This is an abstract class; actual implementations are built either from username/password or from Kerberos tickets

SecurityContextToken: WS secure conversation token

SamlToken: SAML token

 

Exploring a security token

The following code [1] shows the claims of a windows token build from a name password. If you go through the code, you’ll notice things tokens are not a set of tokens but rather a list of sets of tokens. Conceptually however, it does not make any difference.

If you run it, you’ll see the list of group sids the user is in:

 

System.Security.Tokens.WindowsUserNameToken

primary identityMYLAPTOP\Alice

MYLAPTOP\Alice

issuerSystem.Security.Authorization.SystemIdentityClaim

 

S-1-5-21-220523388-1060284298-1343024091-513

MYLAPTOP\None

S-1-1-0

Everyone

S-1-5-32-545

BUILTIN\Users

S-1-5-2

NT AUTHORITY\NETWORK

S-1-5-11

NT AUTHORITY\Authenticated Users

S-1-2-0

LOCAL

 

 

[1]

using System;

using System.Security.Authorization;

using System.Security.Tokens;

using System.Security.Principal;

namespace TestClaims

{

      class Program

      {

            static void Main(string[] args)

            {

                  WindowsUserNameToken t = new WindowsUserNameToken(

                        @"domain\user",

                        "password",

                        true);

                  t.Validate();

                  ShowToken(t);

                  Console.Read();

            }

            static void ShowToken(SecurityToken t)

            {

                  Console.WriteLine(t.ToString());

                  if (!t.HasBeenValidated)

                  {

                        t.Validate();

                  }

                  foreach (ClaimSet o in t.ClaimSets)

                  {

                        ShowClaimSets(o);

                  }

            }

            static void ShowClaimSets(ClaimSet claimSet)

            {

                  Console.Write("primary identity");

                  ShowClaim(claimSet.PrimaryIdentity);

                  Console.Write("issuer");

                  ShowClaim(claimSet.PrimaryIssuer);

                  Console.WriteLine("");

                  foreach (IClaim claim in claimSet)

                        ShowClaim(claim);

            }

            static void ShowClaim(IClaim claim)

            {

                  if (claim == null)

                        Console.WriteLine("");

                  Console.WriteLine(claim.ToString());

                  if (claim is WindowsSidClaim)

                  {

                        WindowsSidClaim sClaim = (WindowsSidClaim)claim;

                        NTAccount account = (NTAccount)sClaim.SecurityIdentifier.Translate(typeof(NTAccount));

                        Console.WriteLine(account.Value);

                  }

            }

      }

}

 

 

 

3/31/2005 4:39:02 AM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [3283]  |  Trackback
 Saturday, March 19, 2005

When I was learning computer sciences, I was told that “small is beautiful”.  I have to admit I did not quite know what to make of it. After thinking about it for some time, I believe it’s neither true nor false. Just irrelevant.

What I now believe is

 

Easier is better

 

Software can have many qualities: performance, flexibility, maintainability, manageability, reusability and so forth. But if it’s not easy, it’s really missing something. Besides, unlike other qualities, it is easy to know whether something is easy or not. In other words, if it’s difficult to know whether it’s easy or not, it’s not easy.

 

The English language gives hints that “easy” is better than “difficult”. For example, when someone “makes things difficult for himself”, he is probably on the wrong track. Similarly, when a leader (guess who) is repeating that he had to make “difficult decisions”, he is not saying he addressed important problems with correct answers but only that he struggled to come up with something. Conversely, something that is “easy on the eyes” is visually pleasing while someone who is easy is accommodating.

 

Easy is not simple

 

When people hear the word “easy”, they usually think “but wait, things are not that simple”. “Simple” and “easy” are two completely different concepts. For example, if you want to author a large document, MS Word is easy but complex while notepad is simple but hard to use (if you want to accomplish anything significant that is).

 

This brings me to one subject I enjoy: security.

It seems Microsoft does not understand why nobody uses Code Access Security. In fact, Microsoft has a survey on the Internet. You can go ahead and answer the survey but if you have followed this entry, you should know what I am getting at: Code Access Security is too hard. Don’t get me wrong, I think Code Access Security is great. In particular, the stack walk mechanism is terrific. But the policy side is way too hard for most people.

 

How can it be easier?

1)      For single users, ClickOnce will greatly help

2)      For corporate environments, CAS policy should be better integrated with Active directory so that administrators, not users administer security.

 

Take it easy

 

3/19/2005 6:28:32 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [1389]  |  Trackback
 Monday, March 14, 2005

CAS quiz

 

When I teach .NET security for DevelopMentor, I usually spend some testing students for understanding. Here are some of the tests I offer. In each case, you have the choice between “it fails with an exception” and “it succeeds”. Of course, you can look at the solution but it’s more fun to try to guess the result and see how many you get right.

 

Ready?

Go

 

Test 1

using System;

using System.Security.Permissions;

namespace Test1

{

      class Program

      {

            static void Main(string[] args)

            {

                  new FileIOPermission (PermissionState.Unrestricted).Demand();

            }

      }

}

 

 

 

 

This one is easy. If you run the program from your computer and do not change the default policy, you will be grated full trust. Therefore it will succeed.

 

Test 2

using System;

using System.Security.Permissions;

namespace Test2

{

      class Program

      {

            static void Main(){A();}

            static void A ()

            {

                  new FileIOPermission (PermissionState.Unrestricted).Deny();

                  B ();

            }

            static void B ()

            {

                  new FileIOPermission (PermissionState.Unrestricted).Demand();

            }

      }

}

 

 

 

 

This fails because the permission has been denied before it has been demanded.

 

Test 3

using System;

using System.Security.Permissions;

namespace Test3

{

      class Program

      {

            static void Main(){A();}

            static void A ()

            {

                  new FileIOPermission (PermissionState.Unrestricted).Assert();

                  B ();

            }

            static void B ()

            {

                  new FileIOPermission (PermissionState.Unrestricted).Deny();

                  C ();

            }

            static void C ()

            {

                  new FileIOPermission (PermissionState.Unrestricted).Demand();

            }

      }

}

 

 

 

 

This fails because the stack walk will reach B before it reaches A. In other words, the Deny overrides Assert in this case

 

Test 4

using System;

using System.Security.Permissions;

namespace Test14

{

      class Program

      {

            static void Main(){A();}

            static void A ()

            {

                  new FileIOPermission (PermissionState.Unrestricted).Deny();

                  B ();

            }

            static void B ()

            {

                  new FileIOPermission (PermissionState.Unrestricted).Assert();

                  C ();

            }

            static void C ()

            {

                  new FileIOPermission (PermissionState.Unrestricted).Demand();

            }

      }

}

 

 

 

 

This one succeeds for the opposite reason. When the stack walk reaches B, it will succeed even though the permission has been denied before. In other words, it is possible to assert a permission that has been denied.

 

Test 5

using System;

using System.Security.Permissions;

namespace Test5

{

      class Program

      {

            static void Main(){A();}

            static void A ()

            {

                  new FileIOPermission (PermissionState.Unrestricted).Assert();

                  B ();

            }

            static void B ()

            {

                  new EnvironmentPermission (PermissionState.Unrestricted).PermitOnly();

                  C ();

            }

            static void C ()

            {

                  new FileIOPermission (PermissionState.Unrestricted).Demand();

            }

      }

}

 

 

 

 

This one fails when the stack walk reaches B. PermitOnly essentially says “Deny

everything but …”.

 

Test 6

using System;

using System.Security.Permissions;

namespace Test6

{

      class Program

      {

            static void Main(){A();}

            static void A ()

            {

                  new FileIOPermission (PermissionState.Unrestricted).Deny();

                  B ();

                  C ();

            }

            static void B ()

            {

                  new FileIOPermission(PermissionState.Unrestricted).Assert();

            }

            static void C ()

            {

                  new FileIOPermission (PermissionState.Unrestricted).Demand ();

            }

      }

}

 

 

 

 

This one fails. Even though the permission has been asserted in B, B is not part of the stack anymore when we execute C – the caller of C is A, not B and B denies the permission.

 

Test 7

using System;

using System.Security.Permissions;

namespace Test7

{

      class Program

      {

            static void Main(){A();}

            static void A ()

            {

                  new FileIOPermission (PermissionState.Unrestricted).Deny();

                  B ();

            }

            static void B ()

            {

                  new EnvironmentPermission (PermissionState.Unrestricted).Assert();

                  new FileIOPermission(PermissionState.Unrestricted).Assert();

                  C ();

            }

            static void C ()

            {

                  new FileIOPermission (PermissionState.Unrestricted).Demand ();

            }

      }

}

 

 

 

 

It looks like this one should succeed but it fails in B because there can be only one assert for each method on the stack. If you want to assert several permissions, create a permission set and assert it.

 

Test 8

using System;

using System.Security.Permissions;

using System.IO;

[assembly: FileIOPermission (SecurityAction.RequestRefuse)]

namespace Test8

{

      class Program

      {