Sunday, August 17, 2008

P2P and WCF: Some Troubleshooting Resources

These are helpful resource when troubleshooting P2P:

Checking cloud status:
netsh p2p pnrp cloud show list

Checking Teredo status:
netsh int teredo show state

Enabling ping over P2P

P2P Traceroute

PNRP Debugging Guide

PNRP and WICN on Server 2008


WCF
8/17/2008 5:47:17 AM UTC  #  Comments [0] 
 Friday, August 15, 2008

Zermatt: Using Forms Authentication in a Passive STS

Since all Zermatt samples use Windows authentication to auth against an STS - the question how to use forms authentication instead popped up several times. It is easy to do that.

Basically a passive STS endpoint is an ASP.NET handler - could be a plain IHttpHandler, an .ashx or a page. All samples simply hook the Page_PreRender event to render the redirect logic. But you could also show a UI before doing that. This means you can put e.g. a login control on your issuing page and manually verify username/password credentials before issuing the token.

My sample issuing page looks like this:

<html xmlns="http://www.w3.org/1999/xhtml">
<
head runat="server">
    <title>Forms Authentication Sign In</title>
</
head>
<
body>
    <form id="form1" runat="server">
    <div>
        <asp:Login runat="server" ID="_login" OnAuthenticate="_login_Authenticate" />
    </div>
    </form>
</
body>
</
html>

In the Authenticate event you verify credentials somehow, and if successful, create a ClaimsIdentity and  issue the token. In my sample I additionally issue a forms auth ticket for the STS domain so that returning users don't have to re-authenticate using the form.

Another approach to make the federation token apply to more than one RP is to modify the cookie domain (if the RPs are in the same domain).

protected void _login_Authenticate(object sender, AuthenticateEventArgs e)
{
    if (ValidateUser(_login.UserName, _login.Password))
    {
        FormsAuthentication.SetAuthCookie(_login.UserName, false);

        ClaimsIdentity identity = new ClaimsIdentity(
            new Claim(System.IdentityModel.Claims.ClaimTypes.Name, _login.UserName),
            "UserName");
        ClaimsPrincipal principal = new ClaimsPrincipal(
            new ClaimsIdentityCollection(identity));

        ProcessFederationMessage(principal);
    }
}

HTH


IdentityModel
8/15/2008 6:58:18 AM UTC  #  Comments [2] 
 Thursday, August 14, 2008

How to build a Development/Test/Demo CA

I often need X509 certificates - but I never really became friendly with makecert. So I ended up running Windows Cerificate Services which proved to be an easy to use, robust solution. You can have one at home or carry it around in a VM. Perfect.

There are some gotchas you can run into and I refined my configuration over the years. I just had to rebuild my Test CA (on Hyper-V) so I thought I'll document the important steps (for self-reference and whoever might be interested)

 

Basic Installation

  1. Install Windows Server (2003 or 2008) - either phyiscally or virtually.
  2. Install Certificate Services.
  3. Select Stand-alone CA.
  4. Choose a reasonable lifetime for the CA cert (like 10 years)
  5. Backup the CA cert. You need this when rebuilding the machine or having several installations act like the same CA.

 

Certificate Lifetimes
By default certificates issued with the CA have a lifetime of one year. They usually expire on the very day where you have to do an important demo. You can configure the lifetime in the registry. See here for details.

 

Revocation Lists
Another common reason why you run into problems with certificates are revocation lists. The location of the revocation list(s) is embedded in certificates in the CDP (CRL Distribution Point) extension. Now by default there is an entry pointing to the CA's Netbios name. Accessing that network location works while you are in your home network and the CA is up and running. If this network location cannot be accessed, many applications and frameworks will fail certificate validation (the default WCF binding security settings e.g.).

Simply removing the complete CDP extension would be one workaround - but some apps don't like that at all. So I wouldn't recommend doing that. A better solution is to create a revocation list once, and store that at a publicly available location. You can also set the lifetime of that revocation list to some high value (like 5 years), so Windows will cache the list. This way you have access to your CRL while on the road and due to the high lifetime value, this will even work when having no network access at all.

To change the CDP settings, open the Certificate Services MMC snap in. Right click on your CA and then select properties. On the extensions tab you can see the list of CRL locations. The first entry specifies the CA local location where CRLs are published. The last three locations get embedded in the certificate. You can delete them and add you publicly available location. Make sure you check the "Include in the CDP extensions of issued certificates" box for your new location.

Next you have to publish a CRL. First you have to set the CRL lifetime. This is configured in the properties of the 'Revoked Certificates' folder in the snap in. Set it to e.g. five years. Next you publish via right-Click -> All Tasks -> Publish. You can find the CRL at the previously configured local location.

The last step is to copy the CRL to your public location and that's it.

Now you can browse to the CA's web interface (http://server/certsrv) and request certificates. After requesting a certificate you have to go to the CA's MMC console and issue the cert (in 'Pending Requests'). Then you can download the certificate by returning to the web interface.

HTH


Work in Progress
8/14/2008 2:05:12 PM UTC  #  Comments [2] 

Most important bug fix in 3.5 SP1

BradA says:

"We have brought managed executables in line with native code executables in how they behave when run off a network share.  Yea!"

VanceN says:

"Hurray, its finally fixed!  manage code 'just works' from network file share!"

Grats for fixing this bug!

 

(hint: some sarcasm is hidden in this post ;)


Misc
8/14/2008 9:06:21 AM UTC  #  Comments [1] 
 Thursday, July 24, 2008

WCF Claims to "Zermatt" Claims Migration Story

Hey - that's a short post - there is none. thanks. bye...

OK hold on - some background info.

Microsoft introduced their new claims API with .NET 3.0 as part of the System.IdentityModel assembly (with super tight integration into WCF). Needless to say that I really like the claims approach - and I have written quite a lot about it here.

Also since that day we were all waiting for that super secret identity framework that was supposed to extend the claims API and which will finally give us easier support for security token services and Information Card related technologies. Now it is in beta and is called "Zermatt". Cool. Life is good.

After some experiments and proof of concepts - it turns out life is not so good.

To enable the "Zermatt" model in WCF you basically have to call the ConfigureServiceHost method on the ExtensibleServiceCredentials class (at least that's how it works with the current bits). As soon as you enable Zermatt the usual places where security happens in WCF don't work anymore - namely ServiceSecurityContext and AuthorizationContext. Interested readers of my blog know that these classes are the entry point into the claims based world in WCF. Also if you have made any investments already into the claims model, your code relies on these classes. If they are "gone", your code is broken.

All the claims functionality found in WCF is now replaced by the Zermatt model and there is no connection whatsoever between them. You'll also find that Zermatt has its own version of a Claim class (and other structural classes too). This basically means that if you have already invested in the WCF claims model but wanna move on to Zermatt, you have to throw away all your code and start from scratch. There is no migration or co-existence story between WCF claims and Zermatt claims.

OK - the next thing I tried is how existing WCF authorization policies work together with Zermatt. The results are quite mixed. First of all external policies only work with certain credential types - and Right.Idenity claims are not supported at all.

Fortunately, there is a forum for Zermatt so I can ask some MSFT people about their take on that. Here's what I got back (I'd love to provide links to the forum posts - but unfortunately this forum is sooo cool and ajaxy that one of the most important features of the web - called URLs - don't work):

"Hi Dominick,
Deeper investigation on my part into what I suspected was a bug turned
out to be by design. The scenario you are attempting (upgrading a
legacy app that depends on the WCF claims model) is not supported in
Zermatt.

Once you opt into Zermatt's claims model, the WCF claims API does not
work anymore. The reason for this behavior is the new claims model in
Zermatt is not backwards compatible with the WCF claims API and it is
not feasible to support both the old and new models at the same time
for WCF applications.

As you have called out earlier in a separate discussion, you have to
choose between staying with the WCF API and not use Zermatt, or move
your application to Zermatt. If you do choose to migrate, any code
that depends on the WCF claims API will need to be rewritten."

Have you also spotted the word "legacy" wrt to WCF??? They must be kidding me!

Here's my answer:

"I don't understand the problem - why can't you take existing authZ
policies and transform them into a ClaimsIdentity - this would be an
easy solution for the migration problem.

Frankly - this sucks.

What do I tell my customers? Sorry for leading you into the
System.IdentityModel direction? Your code will not move forward?

You have a brand new communication framework with a brand new claims
based authZ model - now you are releasing a brand new identity
framework that just disables the technologies used before???? This is
not right.

I don't ask for a full compatibility story between S.IM and Zermat -
but i don't want to throw away all my code (or my customers code)."

Am I asking for too much? Is this a non-issue? I filed a bug for that here. If this is also important for you - feel free to vote.

 

Disclaimer: Don't get me wrong. I don't want to bash Microsoft or the Zermatt team, nor the people on the forum which are really helpful. I just think this is a wrong design decision. And I read somewhere that Microsoft is looking for feedback. So here it is.


IdentityModel
7/24/2008 10:06:31 AM UTC  #  Comments [0] 
 Friday, July 18, 2008

Try "Zermatt" and give Feedback

The last week I spent some time exploring parts of the "Zermatt" framework - some things are really cool - some I have mixed feelings about.

The team is still in a quite early stage where design decisions and directions are (re-) considered. Since "Zermatt" is the main Microsoft identity framework we have to live (and work) with for the next years, take you chance to shape it!

I have already started some discussions, so feel free to contribute.


IdentityModel
7/18/2008 7:35:37 AM UTC  #  Comments [0] 
 Friday, July 11, 2008

CLR Security Site on Codeplex

The CLR security team has a site now on Codeplex - Shawn has all the details here.

Good stuff!


For Your Favourites | FX Security
7/11/2008 6:15:18 AM UTC  #  Comments [0] 
 Wednesday, July 09, 2008

Skiing in "Zermatt"

Today, Microsoft finally announced the first public version of their .NET identity framework code named "Zermatt". The most important things you get from this framework are:

  • APIs for the token/claims related heavy crypto lifting
  • Supporting classes for claims aware applications (including an IIdentity/IPrincipal implementation to give you a common programming model and smooth migration path)
  • ASP.NET plumbing for accepting tokens in web applications
  • ASP.NET controls for adding Information Card support to web applications
  • OM for creating Information Cards
  • Framework and base classes to write security token services (for active and passive scenarios)

If you have already started looking into claims based security, this framework extends the concepts found in System.IdentityModel and makes it much easier to exploit the full power of token/claims based security systems. See here for the official announcement.

You can download the bits and a good whitepaper (written by Keith) here:

https://connect.microsoft.com/site/sitehome.aspx?SiteID=642

Stay tuned ;)


IdentityModel
7/9/2008 10:38:23 PM UTC  #  Comments [0] 
 Wednesday, July 02, 2008

Using IdentityModel: Useful Extension Methods for Serializing Claim Sets

As a follow up to my last post - the following extension methods make it easy to manually serialize claim sets:

public static XElement Serialize(
  this ClaimSet set, IEnumerable<Type> knownTypes)
{
    DataContractSerializer dcs = new DataContractSerializer(
        set.GetType(),
        knownTypes,
        int.MaxValue,
        false,
        true,
        null);
   
    MemoryStream ms = new MemoryStream();
    dcs.WriteObject(ms, set);
    ms.Seek(0, SeekOrigin.Begin);
   
    return XElement.Load(new XmlTextReader(ms));
}

 

public static XElement Serialize(
  this IEnumerable<ClaimSet> claimSets, string rootName,
  string rootNamespace, IEnumerable<Type> knownTypes)
{
    XNamespace ns = XNamespace.Get(rootNamespace);

    return new XElement(ns + rootName,
                    from cs in claimSets
                    select cs.Serialize(knownTypes));
}


IdentityModel
7/2/2008 9:13:54 PM UTC  #  Comments [0] 

Re:MVP

Quoting Brian:

"Microsoft has decided I didn't cause too much trouble over the last 12 months so I get to continue being a {0} MVP. Thanks!", "Developer Security"


Misc
7/2/2008 8:53:58 PM UTC  #  Comments [2] 

Using IdentityModel: Serializing Claim Sets

Both Claim and ClaimSet are decorated with DataContract/DataMember attributes. This means they are made for serialization. And this makes sense - maybe you want to forward a claim set (server to server) or send a claim set from server to client (UI authorization).

But you will most likely run into problems when trying to serialize a claim set using the DataContractSerializer.

Known Types
DCS needs to 'know' all types that are involved in the serialization process. This involves every type in the inheritance chain down to ClaimSet (e.g. DefaultClaimSet or my DeferredLoadClaimSet) as well as all possible resource types. You either supply the known types via attributes/config (KnownType and ServiceKnownType).

Or you supply the types when newing up the DCS manually:

DataContractSerializer dcs = new DataContractSerializer(
    typeof(ClaimSet),
    new List<Type> { typeof(DefaultClaimSet), typeof(UIClaimResource) });

 

Circular References
Typical claim sets will have circular references - e.g. when the last issuer in the chain points to himself. DCS is not made for cyclic reference - but rather object trees (at least with the default settings). When you are trying to serialize objects with cyclic references you will get the following exception : "type contains cycles and cannot be serialized if reference tracking is disabled.". In WCF traces you will see something like "message not logged because its size exceeds configured quota".

When newing up a DCS you can opt for "preserving object references". This will create ID/IDREF pairs in the serialized XML and allows for type references and thus cycles. (Aaron has an explanation of how that works).

DataContractSerializer dcs = new DataContractSerializer(
    typeof(ClaimSet),
    new List<Type> { typeof(DefaultClaimSet), typeof(UIClaimResource) },
    int.MaxValue,
    true,
    true,  // preserveObjectReferences
    null);

 

This is fine when you can control the DCS parameters. But you can't easily do that in WCF. Sowmy has a sample on how to enable reference preserving in WCF. This will solve the problem!

[OperationContract]
[ReferencePreservingDataContractFormat]
ClaimSet GetClaims();

 

3.5 SP1 to the Rescue!?
Starting with 3.5 SP1 you can enable reference preserving on a DataContract like this:

[DataContract(Namespace = "...", IsReference = true)]
public abstract class DeferredLoadClaimSet : ClaimSet

 

But there are two problems with this approach:

  • You actually need access to the DataContract to change the attribute. In the claims case - you would need to change the framework's DefaultClaimSet or your own ClaimSet-derived class.
  • Every DataContract in the inheritance chain needs the IsReference attribute - otherwise you will get the following error: "Derived types must have the same value for IsReference as the base type". Since all custom claim sets ultimately derive from ClaimSet - but this DataContract has no IsReference set, we are back to square one.

 

Conclusion
Keep these things in mind when serializing claim sets:

  • supply all involved types as known types
  • Set preserveObjectReferences to true on the DCS. The new attribute on DataContract in 3.5 SP1 is nice - but does not help with claim sets. Use the [ReferencePreservingDataContractFormat] attribute instead (find the code here).
  • Reference preserving adds ID/IDREF attributes to the resulting XML. These attributes come from a Microsoft namespace. This may be a problem for interop scenarios. If you need full control over the XML, either use the DCS extensibility points for manual serialization, or don't use the DCS at all (and use one of the alternative message generation mechanisms). Another option would be to use a more standardized serialization format for claims like a SAML token.
  • WindowsClaimSet and X509CertificateClaimSet are not marked with [DataContract] at all - they are not intended for serialization.

HTH


IdentityModel
7/2/2008 8:00:28 AM UTC  #  Comments [0] 
 Sunday, June 15, 2008

PowerShell Profile

Putting these three things (and a little bit of this) together - you can build a very nice profile script for PowerShell ;)


Work in Progress
6/15/2008 2:44:38 PM UTC  #  Comments [0] 
 Thursday, June 12, 2008

Advanced Extensions to IIS 7 Configuration

Great article about IIS 7 configuration extensibility:

http://learn.iis.net/page.aspx/241/configuration-extensibility/

Especially infos about the COM backed extensions are hard to find elsewhere...


IIS
6/12/2008 10:55:59 PM UTC  #  Comments [0] 
 Saturday, June 07, 2008

Software Architect 2008

Thanks to everyone who attended my IdentityModel talk at Software Architect.

You can have all the code I showed you during my talk - just send me a private message or leave a comment. Most of the demos are online anyways - have a look at my IdentityModel micro-site.

Questions and feedback are more than welcome. Happy identity-ing.


Conferences | IdentityModel
6/7/2008 4:44:43 AM UTC  #  Comments [0] 
 Thursday, June 05, 2008
 Wednesday, May 28, 2008

SQL Server Security Best Practices

Bob wrote me an email as a response to this post. He also directed me to this whitepaper he wrote about SQL Server Security. Interesting read!


For Your Favourites
5/28/2008 8:39:37 AM UTC  #  Comments [0] 
 Monday, May 26, 2008

OpenID Phishing Demo

Funny and educational:

http://idtheft.fun.de/


For Your Favourites | IdentityModel
5/26/2008 8:02:32 PM UTC  #  Comments [1] 

System Accounts and SQL Server 2005

I recently ran into a strange situation - I was expecting an "access denied" but it didn't happen (yes - security guys are strange people ;). Here's the long story:

I was writing some test code for LINQ to SQL (see here) in ASP.NET. Since this was on a freshly installed box I was expecting an access denied since I hadn't created a SQL login for Network Service yet. But it worked - I could successfully query (and update) data in all databases. Shock.

After some investigation I found the reason for this behavior. Since I was using SQL Express, the SQL instance was running as Network Service (the default). Furthermore setup creates a Windows group for SQL Server service accounts (e.g. MACHINE\SQLServer2005MSSQLUser$...) and puts Network Service in there. It turns out that this Windows group is mapped to a SQL login with a server role of sysadmin...

This means (on my machine) that all SQL clients running as Network Service (or can get an impersonation token for that account) have sysadmin privileges in the SQL Server installation. Or more generally - when a client can use the same Windows account as SQL Server itself - it will get sysadmin privileges

I thought I might point this out, since running SQL Server and ASP.NET as Network Service seems to be a pretty common configuration.

The moral of the story: Always create dedicated service accounts for SQL Server (or every service you install).

btw - the full blown SQL Server installation specifically asks you for the account to use (but also gives Network Service as a choice).


Work in Progress
5/26/2008 11:26:37 AM UTC  #  Comments [0] 
 Friday, May 23, 2008

Avoid unhandled Exceptions in WCF Error Handlers

The IErrorHandler interface in WCF allows to write some central error handling code that gets invoked whenever an unhandled exception bubbles up from your service. There are two methods to implement:

  • ProvideFault - called on the request thread to turn the exception into a fault message
  • HandleError - called on a separate thread for error logging and the like

While WCF tries its best to shield the service host from all kinds of error conditions, there are some situations where unhandled exceptions can hurt your hosting process. One of them is the HandleError method on IErrorHandler.

HandleError is called on a background thread to allow doing (kind of) lenghty operations without impacting the request where the error originally occurred. If you have an unhandled exception in HandleError the normal CLR rules for excpetions in background threads apply - which means shutting down the process. Be careful here.


WCF
5/23/2008 8:26:30 AM UTC  #  Comments [1] 
 Sunday, May 18, 2008
 Thursday, May 15, 2008

Two important Security changes in .NET 3.5 SP1

Shawn details the two big security changes in .NET 3.5 SP1 on his blog:

We have discussed both changes internally - and I have mixed feelings about them. I guess the most important thing to be aware of is, that they are not opt-in changes. By installing SP1 - the behavior will change automatically - if you like it or not.


FX Security
5/15/2008 6:53:45 AM UTC  #  Comments [0] 
 Wednesday, May 14, 2008

Improved IisRegMgmt

Thanks to CarlosAg from the IIS team, I was able to improve my tool for registering IIS 7 management modules.

IisRegMgmt01.zip


IIS
5/14/2008 6:34:10 AM UTC  #  Comments [0] 

P2P and WCF: The PeerName Tool

To play around with peer name registration and resolution, I wrote a little tool that makes this easy (yes - I know all this functionality is also available via netsh - but I wanted something more specialized).

Registering

Resolving

PeerName.zip (27.31 KB)

 


WCF
5/14/2008 6:03:31 AM UTC  #  Comments [0] 
 Monday, May 12, 2008

Using IdentityModel: Tracing

While reading through some of the code of System.IdentityModel, I noticed that there is some diagnostics tracing going on. Just add a trace listener for the source 'System.IdentityModel' to your config file.

HTH


IdentityModel | WCF
5/12/2008 5:28:09 PM UTC  #  Comments [2] 
 Friday, May 02, 2008

P2P and WCF: Some Resources

If you want to know more about P2P and its related protocols and components, here's a list of online resource I found useful while researching:

Have fun!


For Your Favourites | WCF
5/2/2008 4:09:01 AM UTC  #  Comments [0] 
 Thursday, May 01, 2008

P2P and WCF: Exposing a Service

The last post explained how to find a PNRP registered service. What else do you have to do for e.g. exposing a WCF service over the P2P infrastructure?

Code-wise nothing. If the WCF service listens on all NICs (the default), a client can do a resolution via the peer DNS name and connect to it. Easy.

Well - hold on - does that mean that arbitrary clients can now traverse my NAT and connect to my intranet machine? Kind of - yes...

For the service to be accessible you also have to adjust firewall rules:

  • the port the service is listening on must be openend (this will allow normal TCP/IP traffic to the endpoint)
  • to allow Teredo traffic to the service, additionally the "allow edge traversal" option must be checked. This option is only available via the advanced firewall (available via Administrative Tools or MMC). See screenshot:

So to recap - these are the prereqs for a globally reachable service:

  • P2P (PNRP and Teredo) must work properly
  • the service must be registered
  • the client (or peer) must know the peer name
  • the endpoint port must be opened in the firewall
  • Teredo traffic must be allowed for this port

But one thing is very true, you now allow (internet) inbound traffic to an intranet hosted service, which has some implications:

  • there is probably no security around that intranet machine (like a DMZ).
  • intranet machines are typically not hardened for exposing internet services.
  • this means that if the service has some security problem (e.g. directory traversal etc), there are no safe-nets that will stop an attacker e.g. accessing other machines or system resources.
  • your administrators may not like this!

Typical P2P scenarios don't necessarily involve publicly known peer names, so you maybe only have a limited exposure. But still - the traffic bypasses perimeter security and goes directly into the intranet. So be careful.

 


WCF
5/1/2008 9:26:52 AM UTC  #  Comments [0] 

P2P and WCF: Finding a Service

After you have registered a service, the next step is to find it again. The System.Net.PeerToPeer API includes a PeerNameResolver class which does that.

You input the peer name and get back the registration details (IP addresses, port, comment and data):

static void Resolve(string name)
{
    PeerNameResolver resolver = new PeerNameResolver();
    PeerName peerName = new PeerName(name);

    Console.WriteLine("Resolving {0}...", peerName);
    Console.WriteLine();

    PeerNameRecordCollection results = resolver.Resolve(peerName);

    if (results.Count == 0)
    {
        Console.WriteLine("No records found.");
        return;
    }

    int count = 1;
    foreach (PeerNameRecord record in results)
    {
        Console.WriteLine("Record #{0}\n", count);
        Console.WriteLine("DNS Name: {0}", record.PeerName.PeerHostName);

        Console.WriteLine("Endpoints:");
        foreach (IPEndPoint endpoint in record.EndPointCollection)
        {
            Console.WriteLine("\t Endpoint:{0}", endpoint);
        }

        count++;
    }
}

The way you will resolve peer names more commonly is via the DNS format (the PeerHostName property in the above code). A peer name also has DNS name representation (e.g. foo.pnrp.net for an unsecured service named foo). Whenever you use this format (e.g. with ping or any other application that does DNS name resolution), Windows will use the P2P APIs internally to return the corresponding IP address). See here for the details.

This e.g. means that you could make a registration on a web server for port 80 and can use the browser to directly connect to the web server using the DNS format name.


WCF
5/1/2008 6:43:10 AM UTC  #  Comments [0] 

P2P and WCF: Registering a Service

To make a service discoverable using the P2P infrastructure, you first have to do a so called peer name registration.

A peer name registration has the following properties:

  • a name (there are two different flavours: secured and unsecured - more on that later)
  • one or more IP addresses and scope
  • a port number
  • a comment (optional)
  • up to 4KB of binary data (optional)

Peer Name
The name of the service you want to register. Names have the following format: 'authorityId.Name'. Unsecured Names use a '0' as the authorityId and are easy to spoof/squat. When using a secured name, a key/pair is generated on the fly (the first time only) to sign the registration request. The public key hash becomes the authorityId in this case.

IP addresses and scope
That's the most fascinating (and complicated) part. The peer name registration can have local and/or a global scope. A global scope means that the service can be discovered and contacted - well - globally. How can that work, given the service is behind a NAT device? IPv6 is the answer.

Now you may ask yourself: "but my network/router hardware is not IPv6 enabled, can this still work?". Yes it does - making the transition between IPv4 and IPv6 is the job of so called transition or tunneling protocols. Teredo is the name of the protocol that is typically used here. Teredo has several jobs - one is to provide a globally unique IPv6 address, the other is to enable NAT traversal. I won't go into the Teredo details here, but this document describes how it works.

When you do a 'ipconfig' on the command line you may already see a bunch of IPv6 addresses. The one that is directly associated with your NIC is the local address. You may also see a "Tunnel Adapter" interface - that would be the global Teredo provided address.

You can check the status/health of the Teredo protocol by using this command: 'netsh int teredo show state'. This article helps you with troubleshooting if Teredo should not be enabled on your machine.

You can also have a look at the scope of your registration by checking the clouds to which your machine has access. This is done by doing a 'netsh p2p pnrp cloud show list'. You should see one or more LinkLocal_ clouds and a Global_ cloud.

Again this article has all the details on clouds and their background.

So to wrap it up - by default a peer name registration will use all available NICs/IP addresses. If you have a global IPv6 address (which means that Teredo is working properly and you can 'see' the global cloud) this one is used also. This in turn means that the service can be used by every client that also has a global address.

The remaining properties are self explaining I think.

The following code snippet would register a secured peer name in all available clouds (you can find the APIs in the System.Net assembly (v3.5):

private void Register(string name, int port, string comment)
{
    PeerName peerName = new PeerName(name, PeerNameType.Secured);
    PeerNameRegistration reg = new PeerNameRegistration();
   
    reg.PeerName = peerName;
    reg.Port = port;
    reg.Cloud = Cloud.Available;
    reg.Comment = _cl.Comment;

    reg.Start();
}

The next posts will deal with peer name resolution and how to host a WCF service over this infrastructure.


WCF
5/1/2008 5:42:58 AM UTC  #  Comments [0] 
 Wednesday, April 30, 2008

P2P, PNRP, Teredo...the Motivation

Since I started playing around with computers, communication of machines over a "wire" has been fascinating to me. This is probably why I ended up in the distributed applications space.

Typically clients talk to servers and servers to servers - but less common clients directly to clients. But applications like MSN Messenger or Skype show useful use cases of client to client communication. With Vista and Server 2008 (and XP SP2 + some components) peer to peer networking has become part of the operating system. There is also a peer channel in WCF that sits on top of these core components. Time to have a closer look.

So what features is the P2P infrastructure supposed to give you?

  • Global/local registration of services
  • Global/local connectivity between peers which includes the capability to traverse NAT devices
  • Global/local virtual broadcasting networks
  • Peer/Service Discovery
  • Invitation/activation of P2P enabled applications

All of these capabilities are as fascinating as they are scary. More importantly I really think that P2P communication patterns will be a "big" thing and will also change the way we have to think about network/perimeter security.

In the next posts I will write about some of my findings. Stay tuned.


WCF
4/30/2008 6:18:56 AM UTC  #  Comments [0] 
 Monday, April 28, 2008

Using IdentityModel: Converting ADFS Security Properties to Claims

This little helper might be useful when you are working with ADFS, but want to use the IdentityModel types in your app:

public static ClaimSet ToClaimSet(this SingleSignOnIdentity identity)
{
    List<Claim> claims = new List<Claim>();

    claims.Add(new Claim(identity.NameType, identity.Name, Rights.Identity));

    foreach (SecurityProperty property in identity.SecurityPropertyCollection)
    {
        string claimType = property.Uri;
        if (claimType.EndsWith("NameValue"))
        {
            claimType = property.Name;
        }

        claims.Add(new Claim(claimType, property.Value, Rights.PossessProperty));
    }

    return new DefaultClaimSet(ClaimSet.System, claims);
}


IdentityModel
4/28/2008 5:39:21 AM UTC  #  Comments [0] 
 Tuesday, April 22, 2008

Ein Session Abstract ganz genau nach meinem Geschmack

Gesehen auf der JAX2008 Webseite:

Security Last – Sicherheitsentscheidungen spät treffen
Sicherheitsanforderungen wie Logins und Berechtigung sind wichtig – aber müssen diese wirklich gleich am Anfang umgesetzt werden? Das nachträgliche Hinzufügen dieser Anforderungen mit reinem Java und OOP ist sehr schwierig, weshalb dies meistens mit „Ja“ beantwortet wird. Erfahren Sie hier, wie mithilfe von Tools wie Spring Security, AspectJ und CAS auch spät in Anwendungen integriert werden kann.

Ohne Worte...

 


Microsoft Deutschland Security Portal
4/22/2008 11:49:20 AM UTC  #  Comments [1] 
 Sunday, April 20, 2008

Token Kidnapping

Interesting...and shocking.

Read more here:
http://www.argeniss.com/research/TokenKidnapping.pdf


For Your Favourites
4/20/2008 7:15:28 AM UTC  #  Comments [0] 

Installing an IIS 7 Extension

Related to cleaning up my authentication module for Codeplex, I needed a way to (semi) automatically install a complete IIS extension (including schema, config sections and management extensions). I came up with a batch file that does the necessary steps (anybody out there that wants to write a real installer?).

1. Register all assemblies in the GAC
Usually an IIS 7 extension consists of at least three assemblies (module/handler, server extensions, client extensions). Gacutil.exe is your friend here (use the /if option). Also take into account, that IIS loads GACed assemblies domain neutral. That means that you have to recycle the worker process when you update e.g. your GACed module.

2. Register schema and config section
This involves copying your schema to the IIS' schema directory and add a <configSection> registration to applicationHost.config. Mike Volodarsky from the IIS team has written a nice tool call IisSchema that automates this step.

3. Registering the management extension
This involves adding the module to administration.config (in two different places). I haven't found an automated way of doing this, so I wrote a little tool to accomplish this task.

IisRegMgmt [install/uninstall] [assembly_to_register]

This will find all Microsoft.Web.Management.Server.ConfigurationModuleProvider derived classes in the specified assembly and register them in administration.config.

The code to do the registration is as follows:

private static void RegisterAdministration(string name, string type, string assembly)
{
    // get access to administration.config
    Configuration administration = _manager.GetAdministrationConfiguration();

    // get access to <moduleProviders>
    ConfigurationSection moduleProvidersSection =
        administration.GetSection("moduleProviders");
    ConfigurationElementCollection moduleProviders =
        moduleProvidersSection.GetCollection();

    // check for existing elements first
    Clean(name, moduleProviders);

    // create new element
    ConfigurationElement newModuleProvider =
        moduleProviders.CreateElement();

    // set attributes
    newModuleProvider.SetAttributeValue("name", name);
    newModuleProvider.SetAttributeValue("type", type + ", " + assembly);

    // add element
    moduleProviders.Add(newModuleProvider);


    // get access to <modules>
    ConfigurationSection modulesSection =
        administration.GetSection("modules");
    ConfigurationElementCollection modules = modulesSection.GetCollection();

    // check for existing element first
    Clean(name, modules);

    // create new element
    ConfigurationElement newModule = modules.CreateElement();

    // set attributes
    newModule.SetAttributeValue("name", name);

    // add element
    modules.Add(newModule);

    // save changes
    _manager.CommitChanges();
}

Don't forget to clean up the sections before you add the new module, otherwise you might end up with double entries:

private static void Clean(string name, ConfigurationElementCollection elements)
{
    var hits = from e in elements
               where (string)e.GetAttributeValue("name") == name
               select e;

    hits.ToList().ForEach(e => elements.Remove(e));
}

For completeness sake, here's how you can find the right management classes in the assembly (and because I was amused about 'Linq to Reflection' ;)