Monday, March 08, 2010
The Windows Azure platform AppFabric Access Control service was one aspect of the Windows Azure platform that I found a bit challenging to understand, primarily because identity is not a domain that I regularly work with. This post, the first in a planned series of articles, will explore what the Access Control service is and why it is useful.
Three Geeks Walk Into a Bar…
Let’s examine a common real-world scenario: Ordering a drink from a bartender at a nightclub.
Before the nightclub opens, the bouncers inform the bartenders about the token that customers will bear on that night to indicate that they are of legal age. This could be a stamp on the back of the hand, a colored wristband, etc.
At the door, a customer will present their identification to the bouncer that shows, among other things, their date of birth. This ID could be a state-issued driver's license, a passport, or even a school identification card. The point is that the nightclub didn’t issue that ID, but they recognize the authority that did issue it, and will accept the claim (the birth date) that is displayed on that ID.
If the bouncer determines that the ID is authentic and hasn’t been tampered with, then he will give the customer the token of the night (stamped hand or colored wristband), and the customer is free to enter the bar.
Once inside, the customer only needs to show the token to the bartender in order to buy drinks. They do not need to show their ID.
The next night, the token will change, so a customer cannot use a token obtained the night before.
Federated Access Control
Now let’s look at a similar scenario: Calling a web service from an application. Only, in this case, the web service should not fulfill requests from unauthorized clients. Furthermore, it’s not the web service’s responsibility to authenticate the client; it is simply expecting the client to bear some verifiable proof that it is already authorized to use the service.
Before calling the Web Service, the Service Consumer (application) must first obtain a token that is issued by an Access Control Service (ACS). This is done by sending a number of claims to the ACS, with one of these claims being secrets belonging to an Issuer that the application is associated with.
If the Issuer is recognized and trusted by the ACS, then a token will be created. This token (which is a collection of name/value pairs) will contain claims, an expiration date, and a signature that can be used to ensure that the token was not modified after it was created.
Once the Service Consumer has a valid token, it can then call the Web Service and provide that token in a location where the service expects to find it, such as in a HTTP header. The Web Service validates that the token is well-formed, has not expired, and has not been modified since it was created. If anything fails validation, then the processing aborts. Otherwise, the web service returns data to the Service Consumer, possibly using claims contained in the token as input in the process.
This scenario is considered to be Federated because the ACS doesn’t actually maintain a list of usernames and passwords. Instead, it maintains a list of trusted Issuers with the expectation is that the Issuer is responsible for authenticating its own users.
Correlation
In these examples, the Web Service is analogous to the nightclub’s Bartender: it has something to provide to the Service Consumer (Customer), but the Service Consumer must present an appropriate token that is generated by the Access Control Service (Bouncer).
The web service example above is intentionally vague in the part where a token is obtained. There are a few different ways that an Issuer can be identified in a token request, and while passing the Issuer’s secret in plain text is one of those ways, it certainly shouldn’t be taken lightly. Whoever has the Issuer’s key can spoof any of the claims, and that might prove to be a challenge for the service. In the example where we need a Date of Birth claim to be presented, it would probably be a bad idea to allow the customer themselves to say “I’m from Ohio, here’s a blank driver's license that meets all of the standards of a proper ID, and, oh yeah… I’m writing on here that I am 21 years old.”
Instead, claims should originate from the Issuer in some way that cannot be tampered with by the application (using the assumption that the application itself should not be trusted). With the plain text method, this might require having a separate service that runs within the Issuer’s domain and is aware of its users and also ACS. This service would broker the ACS token request for the application, automatically providing any claim data that might be needed (like the Date of Birth) from the Issuer’s own user database. The application would be provided with the same token, but would never have the Issuer’s secret that is required to obtain the token directly from ACS.
Thursday, February 25, 2010
I was working through some
Windows Azure example code today, and came across a situation where IntelliSense did not show a method that the sample code used (
CreateCloudBlobClient(), in this case):
var storageAccount = Microsoft.WindowsAzure.CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
var blobStorage = storageAccount.CreateCloudBlobClient();
A lot of times, when I'm exploring an API, I will type out the fully qualified class name in code so that I can use IntelliSense to see what the other members exist in the same namespace. And, while I'm exploring, I usually don't bother to include a
using statement at the top of my code because it's so easy to just use the "Remove Type Qualifier" refactoring available in
CodeRush to clean up the code when I'm ready to move on.
Well, something that I guess I didn't remember soon enough was that
using statements are required in order to enable Extension Methods belonging to that namespace. In this case,
CreateClousBlobClient() was not a method of
CloudStorageAccount, but rather an Extension Method (and this fact is not something that is very apparent when typing in sample code that you find in a document).
IntelliSense showed that method (and more!) after adding the following line of code to the top of my file:
using Microsoft.WindowsAzure.StorageClient;
Sunday, February 14, 2010
The Entity Framework does not support using User Defined Types (at least in the SQLCLR sense of the term) as properties of an entity. Yesterday, Julie Lerman contacted me to see if we could find a workaround to this current limitation, particularly for the SQL Server Spatial Types (Geometry and Geography).
Whenever I hear of someone wanting to use Spatial data in their application, my first thought is always “what do they want to do with the data once they have it?” This is because most of the time (in my limited observation), an application does not need the spatial data itself, but rather, it just needs to use that data in the predicate of a query (i.e., the query results contain no spatial information). For example, an application might want all zipcodes that are within 50 km of a point, but the application doesn’t need the actual shapes that define each zip code.
But, assuming that the developer knows what they are doing and has a legitimate reason to include a spatial type in the results, then how can they use the Entity Framework to get the spatial data into their application? That was our quest.
Entity Framework Primitive Types
Admittedly, I know very little about EF. So, my approach to this problem spent a lot of time using .NET Reflector to try to understand what the EF designer was doing behind the scenes (this also proved to be a a good way to understand EF better!). The first thing that I wanted to figure out is how EF determines which primitive type to use for each SQL Server type.
I downloaded and imported the States data from the US Census Data for SQL Server 2008 project on Codeplex. Then, I used the Entity Data Model Designer in VS2010 to generate a model based on my database which resulted in an entity without the geometry property. Looking at the XML for the .edmx file, I saw the following:
<!--Errors Found During Generation: warning 6005: The data type 'geometry' is not supported;
the column 'geom' in table 'Spatial.dbo.State' was excluded. -->
<EntityType Name="State">
<Key>
<PropertyRef Name="StateID" />
</Key>
<Property Name="StateID" Type="int" Nullable="false" />
<Property Name="StateName" Type="nvarchar" Nullable="false" MaxLength="50" />
</EntityType>
I don’t believe that EF is hating on “geometry” specifically (the 6005 warning). Rather, I think that if the SQL Server type cannot be mapped to a .NET type from the BCL, then it simply does not know how to handle it. Certainly, they don’t want to try to map to a type that is not included in the .NET Framework itself (as would be the case for the Spatial data types).
But, what is EF using to determine the mappings?
I looked long and hard, but couldn’t quite figure out the mechanism that gets invoked when the model is generated. But, I think the key might lie in the Microsoft.VisualStudio.Data.Providers.SqlServer.SqlMappedObjectConverter.GetFrameworkTypeFromNativeType() method:
// Disassembly by Reflector protected override Type GetFrameworkTypeFromNativeType(string nativeType)
{
switch (this.GetProviderTypeFromNativeType(nativeType))
{
case 0:
return typeof(long);
case 1:
case 7:
case 0x13:
case 0x15:
return typeof(byte[]);
case 2:
return typeof(bool);
case 3:
case 10:
case 11:
case 12:
case 0x12:
case 0x16:
return typeof(string);
case 4:
case 15:
case 0x1f:
case 0x21:
return typeof(DateTime);
case 5:
case 9:
case 0x11:
return typeof(decimal);
case 6:
return typeof(double);
case 8:
return typeof(int);
case 13:
return typeof(float);
case 14:
return typeof(Guid);
case 0x10:
return typeof(short);
case 20:
return typeof(byte);
case 0x20:
return typeof(TimeSpan);
case 0x22:
return typeof(DateTimeOffset);
}
return typeof(object);
}
For SQL Server, the Native Types come from the System.Data.SqlDbType enumeration:
// Disassembly by Reflector public enum SqlDbType
{
BigInt = 0,
Binary = 1,
Bit = 2,
Char = 3,
Date = 0x1f,
DateTime = 4,
DateTime2 = 0x21,
DateTimeOffset = 0x22,
Decimal = 5,
Float = 6,
Image = 7,
Int = 8,
Money = 9,
NChar = 10,
NText = 11,
NVarChar = 12,
Real = 13,
SmallDateTime = 15,
SmallInt = 0x10,
SmallMoney = 0x11,
Structured = 30,
Text = 0x12,
Time = 0x20,
Timestamp = 0x13,
TinyInt = 20,
Udt = 0x1d,
UniqueIdentifier = 14,
VarBinary = 0x15,
VarChar = 0x16,
Variant = 0x17,
Xml = 0x19
}
My conclusion here was that if the SQL Server type could only be mapped to System.Object in the BCL (using the GetFrameworkTypeFromNativeType() method), then EF will not support using that field as a property of the entity. This coincides with the fact that to ADO.NET, the Geometry (and Geography) type is a User Defined Type (0x1d).
UPDATE: After all of this, I discovered that in System.Data.Entity.dll, there is a method that is probably a better candidate for what is actually used: System.Data.SqlClient.SqlProviderManifest.GetEdmType(). This method contains a similar switch{} as the code listed above, only it is EDM-specific instead of returning BCL types. Feel free to examine it using Reflector if you're curious about its contents.
The Workaround
Having figured out that piece of the puzzle, I was left with trying to figure out a workaround. If ADO.NET was unable to map a Geometry to a type in the BCL, then could we cast the Geometry as something that would be mappable?
SQL Server serializes spatial objects to binary when it saves the data in a table (documented here: http://msdn.microsoft.com/en-us/library/ee320529.aspx):
This binary data can be used to deserialize (“rehydrate”) the object in .NET code, which is exactly what SQL Server does when it needs to use the spatial objects. So, we just need to find a way for EF to pull these down as a byte array.
Looking back at the GetFrameworkTypeFromNativeType function from above, it appears that EF will likely recognize Binary, Image, Timestamp, and Varbinary all as SQL Server types that need to map to byte arrays. Perfect!
So, by creating a view in SQL Server that casts the Geometry column as a Varbinary(MAX), EF would recognize it as a type that could be mapped as an entity’s property.
CREATE VIEW vStates
AS SELECT StateID
, StateName
, CAST(geom AS VARBINARY(MAX)) AS geom
FROM dbo.State
Note: Julie had come up with this same solution at the same time, as our emails crossed paths reporting to one another.
Regenerating the EF model (using this view instead of the table) proved my assumption: the “geom” column now appeared as a Binary property of the vStates entity.
However, we’re not quite done yet. The point of this exercise was to get an instance of the spatial type to use in our .NET application. To do that, the Read(BinaryReader) instance method on SqlGeometry (or SqlGeography) must be invoked (using a MemoryStream as the intermediate between the byte[] and the BinaryReader).
The entire logic to retrieve the contents of the table and instantiate one of the Spatial types is as follows:
var entities = new SpatialEntities();
var vStates = entities.vStates;
// pull one of the entities from the collection var geo2 = vStates.ToArray()[16];
var sqlGeom = new Microsoft.SqlServer.Types.SqlGeometry();
// Deserialize the bytes to rehydrate this Geometry instance using (var stream = new System.IO.MemoryStream(geo2.geom))
{
using (var rdr = new System.IO.BinaryReader(stream))
{
sqlGeom.Read(rdr);
}
}
// Now let's prove that we have it. Dump WKT to Debug.
System.Diagnostics.Debug.Write(sqlGeom.ToString());
Output:
GEOMETRYCOLLECTION (LINESTRING (-99.530670166015625 39.132522583007812, -99.530670166015625 39.13250732421875), LINESTRING (-99.791290283203125 39.131988525390625, -99.791290283203125 39.131973266601562), …
So it worked!
Finally, an extension method would make this code a bit more general purpose:
public static class Extension
{
public static Microsoft.SqlServer.Types.SqlGeometry AsSqlGeometry(this byte[] binary)
{
var ret = new Microsoft.SqlServer.Types.SqlGeometry();
using (var stream = new System.IO.MemoryStream(binary))
{
using (var rdr = new System.IO.BinaryReader(stream))
{
ret.Read(rdr);
}
}
return ret;
}
}
The test code above then becomes a bit more readable after the refactoring:
var entities = new SpatialEntities();
var vStates = entities.vStates;
// pull one of the entities from the collection var geo2 = vStates.ToArray()[16];
var sqlGeom = geo2.geom.AsSqlGeometry();
// Now let's prove that we have it. Dump WKT to Debug.
System.Diagnostics.Debug.Write(sqlGeom.ToString());
Helpful information:
Sunday, November 08, 2009
Over the weekend, I bought a Motorola Droid, a great new Android 2.0 phone on the Verizon network. It's important to note that this is not only my first smart phone, but also my first hand-held device of this type (i.e., a PDA, etc), so I'm pretty stoked at the moment.
The device synchronizes with Google applications extremely well (like GMail, Google Calendars, Google Voice, Contacts, etc). Setting this up is just a matter of creating a new Account on the phone, providing your GMail account and password, and then everything else just magically syncs. And, since I'm primarily a GMail user (who uses multiple Google Calendars to keep our hectic family schedule organized), this was a killer feature for me.
But, I expect that this would be easy for Google content. What about the real world? What about synchronizing to an enterprise email and calendar, like Exchange? And, since I'm a consultant, what about synchronizing to multiple Exchange servers at the same time?
Well, I'm happy to report that there's an application for that... Or, rather, a couple of them: Email (note, not the GMail app) and Corporate Calendar.
My company uses Lotus Notes for email. Thankfully, though, our Microsoft Practice within the company has just started to use Exchange Online (as part of the Microsoft Business Productivity Online Suite, or BPOS), so mail sent to my company account gets forwarded to the Exchange Online server.
Configuring the Droid to synchronize with Exchange Online is probably not much different than synchronizing with any Exchange server. It all starts with creating a new Account on the Droid:
- From the Settings application, touch "Accounts & sync".
- Touch the "Add account" button at the bottom
- Choose "Corporate" as the type of account to create.
- You'll be prompted for a Email Address and Password. Enter the same email account and password that you use to log into BPOS, and then touch the "Next" button.
- The next page is where it tried to be smart about what you entered on the previous page. Basically, only the Password will be correct (at least in my case).
- Replace the Domain\Username with the same email that you entered on the previous screen. It's okay to have the backslash as the first character.
- For the Exchange server, refer to the Mobile Device URLs for your region that are listed on the "URLs for Microsoft Online Services" page. For my account, I had to specify: red001.mail.microsoftonline.com
- I also have "Use secure connections (SSL)" and "Accept all SSL certificates" checked.
- Click Next to go the the Account Options screen.
- Set the "Email checking frequency" and "Amount to synchronize". I used Automatic (Push) and One week, respectively.
- You can also choose to "Send email from this account by default" (I don't), "Notify me when email arrives" (I do), and "Sync contacts from this account" (I do).
- Click Next to go to the final screen. Give the account a friendly name, and enter your name (to be displayed on outgoing email). Then touch the "Done" button.
By default, it doesn't seem that Calendar sync'ing is automatically added to a new account. I had to go into the Corporate Calendar app, after which it detected the new Corporate Account and started sync'ing the calendar (which can be verified by opening the account information from Settings).
Also, I'm sure that this is a bug at the moment, but it seems that only one Corporate Account (only the first one) is able to synchronize its calendar. That is, the Corporate Calendar application does not seem to recognize when additional Corporate Accounts are added. As a test, I deleted my first Corporate Account and then started the Corporate Calendar again, at which time it detected a new account (which was originally the second account) and added the Calendar sync to that. But, recreating the original first account didn't result in an automatic Calendar sync. Definite weirdness!
Wednesday, July 15, 2009
I'm a consultant. I travel from client network to client network, sometimes within the same day. My job involves interacting with various corporate servers using my trusty laptop, solve real-life business problems, and then move on to the next gig. It's not practical for me to have my computer join a Windows Domain only to have to do it again and again with each new environment that I visit. This is also not feasible because I cannot have my different clients become administrators on my company-provided laptop or have domain policies pushed down to my laptop, which is a byproduct of joining a domain.
So, as a result, I'm forced to log onto my laptop as a local user. This proved not to be a problem with Windows XP because I could set up a password rule (within the User Accounts control panel) to associate a username and password to use for each distinct domain that I access.
But, beginning with Windows Vista, Microsoft's security model became what can only described as bi-polar. If your machine was domain-connected, then everything worked fine. But, if your machine was not domain-connected, then a different set of rules seemed to apply, and it suddenly became a frusterating chore to perform simple tasks against domain-protected resources.
Part of the problem stemmed from an apparent bug in the "Manage Network Passwords" interface that would seemingly not accept domain wildcards, either in the classic format (DOMAIN\*) or the FQDN format (*.DOMAIN.COM). So, there was no way to instruct Windows to use a particular set of credentials for "any resource on this domain". The best that you could do was save a password for each individual resource (server) that you needed to access.
I've been experimenting with Windows 7 for a couple of weeks now to see how well it fits into the life of a consultant working within an enterprise environment. I'm happy to report that the "Manage Network Passwords" bug appears to be fixed (using the FQDN wildcard format), so my network password list is not littered with scores of entries. However, other things still remain broken or impossible to do.
As an example, one of the tools that I use the most is SQL Server Management Studio (SSMS). Out of the box, relying on a password rule to connect to a SQL Server protected by domain security simply does not work, and there is no other way to specify a Windows username/password as part of the Connect dialog. I have to resort to using custom RUNAS shortcuts for each environment that I'm in (I previously blogged about this under Vista).
Also, anything that uses Kerberos (i.e., for delegated authentication from a web application to a secondary server) simply does not work if your computer is not domain-connected. Though, to be fair, I think that this was an issue for Windows XP machines that were not domain-connected as well, and is the result of how Microsoft implemented Kerberos security (their design assumes that all of the participating machines are domain members).
Overall, the experience of using a standalone Windows 7 machine as a consultant within a corporate environment has proven to be better than Vista. But, it's still not as good of an experience as XP was, and I totally blame this on the "enhancements" that were made to the underlying security model. This is particularly disheartening because I'm in love with Windows 7 as an operating system and actually want to use it for my day-to-day tasks.
I welcome commentary from the OS team about what can be done to improve this experience!
Friday, July 10, 2009
This morning, I came across this news article about some patents that Bill Gates filed to stop hurricanes.
Sure, I never patented the idea or did any work to further elaborate on it, but I did blog about the same concept in 2005!
http://jasonf-blog.blogspot.com/2005/09/preventing-hurricanes.html
Bill, you can buy me a Diet Pepsi the next time that you see me...
Wednesday, July 01, 2009
Those of you who visit my blog's website will notice a new type of ad in the sidebar, replacing the AdSense skyscraper that was there previously. I'm proud to be associated with the list of other .NET developers who are all part of The Lounge's .NET Small Publishers Room.
Wednesday, May 20, 2009
On June 5th, I'll be in Columbus (Ohio) speaking to the Microsoft SQL Server User Group (Result Data) about using the XML data type in SQL Server.
XML Capabilities of SQL Server 2008
Jason Follas, Microsoft MVP for SQL Server, will lead a discussion on the XML capabilities of SQL Server 2008. XML-based data is very prevalent in today's data world to the point that every database developer should know how to work with XML. Middle-tier translation of XML into relational data may be inflexible, and often leads to a loss of fidelity over time. One solution is to move the XML handling into the database itself in order to improve overall integration. SQL Server 2008 provides powerful XML processing features that allow easy access to data stored within XML without sacrificing any of the original fidelity.
Partitioning in SQL Server 2008
Andy Thissen, Database Administrator at BMW Financial Services, will lead a discussion of the use of partitioning in SQL Server 2008.
Agenda
12:45 Check-In
1:15 Introduction & Announcements
1:30 XML Capabilities of SQL Server 2008
2:30 BREAK
2:45 Partitioning in SQL Server 2008
3:30 Q&A
3:45 Raffle – Door Prize
https://www.resultdata.com/training/schedule/register.aspx?id=198020
Saturday, April 04, 2009
Warning: Only 3 people who read this may actually understand it.
This morning, after actually considering what the effort might be to port lp_solve from C over to .NET, I stumbled upon this:
http://code.msdn.microsoft.com/solverfoundation
About 4-5 years ago, I worked on a project that used a Frankenstein'ed "lp_solve 2.0-ported-to-Java-then-ported-to-C#" solver, which was great because it was free and it was a completely managed solution (no native components). What I was doing wasn't particularly that heavy of a problem, but still required a solver to quickly and reliably minimize a cost given a bunch of user-provided constraints.
Solver Foundation appears to satisfy both of these "requirements" (i.e., being Free and being completely managed).
Now, if I can build a Silverlight 2.0+ app that is able to use MSF, then I essentially get infinite scaleout of my optimizer without requiring infinite server infrastructure. <evil laugh>
Wednesday, March 04, 2009
A quick sample of usage as requested by my friend Jeff McWherter:
Querying for all data in a table where the "zip code polygon" is within 20 miles of a geocode point (must convert 20 miles to meters in the predicate)::
select *
from dbo.fe_2007_us_zcta500
where Boundary.STDistance('POINT(-79.8884595930576 43.2609696686268)') < (20 * 1609.344)