Tuesday, March 30, 2010

Is Linux finally dead?

I really like Linux. You have to understand. When I started in IT, I'd spent a fair amount of time learning to program PCs. I could tell you from memory which was the mouse interrupt (12? wasn't it?) and how PC's allocated hard drive files. When the sat me down at my desk my first day on the job, it was in front of a brown screen wise terminal jacked into an HP Unix server. It wasn't so much a learning curve as a learning cliff. But I managed.

Over the years, I switched from HP UX to Solaris and learned how to do low-level file IO in C and how Unix/Linux/Posix does inodes. Good times. :D

At home, I've almost always run a Linux PC . I love the flexibility in XWindows. I geek out on running different desktop managers. I spent days (days!) changing my splash screen and getting fluxbox correctly configured.

I almost abandoned Linux a few years ago, but Ubuntu brought me back. What an awesome build.

So I got a really nice laptop a few months ago -- quad core, 6gb, 1/2 TB hard drive (with an open bay) and a really kickin' ATI graphics card. In many ways, it's the PC I'd always promised I'd get someday.
It came with Windows and I actually waiting for the latest rev of Ubuntu (Karmic) to set it up for dual boot.

But.... it kinda ... sucks. The audio card works great, unless you plug in the headset, then it plays sound through the headset and the speakers both. The graphics look ok, but the vendor's graphic drivers don't work. They cause the PC to do all kinds of crazy things (like the wifi card just drops when I use the vendor's drivers). I can read CD's but can't seem to burn DVD's -- and the lightscribe feature is totally unavailable because the manufacturer won't support Linux. My phone plugs in but Linux can't read it. Same with my camera.

I've read a lot online that Karmic is buggy. I can live with that. I mean, just between you and me, let's face it, Vista sucked. You upgrade and move on.

But the software for desktop Linux is disappearing. And what's left isn't working very well. Virtual Box (which is a really great product, by the way), has constant graphics issues with the new revisions of Linux. And it's crashed hard on me a few times. Rhythm box crashes if I change the volume twice (I can do it once). Google *finally* added support for Chrome, but it clearly wasn't at the top of their list.

And now I see this:

Basically NVidia is dropping open source support. That means (in effect) Linux wont' be able to really support NVidia cards anymore. As mentioned, my ATI doesn't work either. So that leaves Linux in a pretty bad place.

Add to that the fact that now Sony is dropping the option to (easily) install Linux on a PS3, and you start to see a trend.
Just about all the computer game makers have dropped their Linux support. There was a time when you could get the latest game ported to Linux, and available online or sometimes even at the local computer store. But those days are long gone.

Dell still sells Linux PCs (I think?). But last I looked they had one (count 'em ONE) latitude laptop with Linux and the not-so-stunning , bottom of the line Intel graphics card. And (I think?) Dell is about the only major manufacturer still offering Linux at all.

Does it matter? Well, here's my guess. In 5 years, no one will really own a PC -- I mean, the non-geeks (you'll have to pry my HP laptop out of my cold, dead hands, brotha!) . Everyone will have Netbooks for their day-to-day stuff, and PS3's/Wii's for their games and movies. In some ways, it's a step backward, really, since these will all use proprietary operating systems. That said, in many ways, proprietary OS's make sense. In a very theoretical sense, the one-size-fits-all PC is really a bit much. Windows has gotten pretty bloated as they've tried to put things in there that no one actually uses. Linux has too. The model of a thin client, with a hardware-tight proprietary OS makes a lot of sense, especially given the number of vendors now in the market.

The death of desktop Linux has been predicted a million times and I hate to be the million and first. But I have to say that things are looking dimmer. Sure, there will always be some government office in Botswana or something that uses it. And sure, there will always be hardcore geeks who play world of warcraft through wine.
But I look for desktop Linux to take step back out of the mainstream. Not sure if that's a good thing or not. Maybe it's where it belongs. Going mainstream has its price, too.

--kevin

Tuesday, March 16, 2010

encrypted data store

For a while, I've been struggling with how to persist database connection strings. Some of them have user accounts and passwords, so I don't want them in plain text in the config file. I don't really want them hard coded either. I have played with encryption mechanisms on the config files but can't find anything I like. Using Microsoft's default framework, either the encrytpion is tied to the user id --- so when you move from a dev account to a production one, you can't decrypt --- or it's tied to the machine, which affords the same issue. If you manually encrypt, then you’re just displacing the issue, since you need to find a way to store an encryption key or the like.

So, here’s my solution. I’ve set up an encrypted database repository to store database connection strings. The connection string to this repository is in a plain text config file, but since it is SqlServer, it uses user auth to connect – so, no passwords needed. Since it’s an encrypted table, anyone looking to decrypt needs access to the database, the table, the cert and the symmetric key. Without all those privs, you get nothing. If additional security is needed, you can add certificate enforcement on the connection itself.

Here’s how to set up the basics.

First, you’d need to create a table. I’ll ignore the DDL for this. I used a “database name” for the key. For the value, you’d want something like this:

ALTER TABLE DataConnectionValues

ADD ConnectionString varbinary(255);

GO

It should be a big enough column, of course. I picked 255, since it has to account for an encrypted string, which would be longer than the non-encrypted one. And I picked binary since the encryption may use non-standard characters.

Ok. Next we’ll need a master symmetric key, if one doesn’t exist

IF NOT EXISTS

(SELECT * FROM sys.symmetric_keys WHERE symmetric_key_id = 101)

CREATE MASTER KEY ENCRYPTION BY

PASSWORD = ‘someCleverPassword’

GO

The inner select and existence check are clearly not needed, but I added them anyway.

Now a certificate:

CREATE CERTIFICATE DBConnection

WITH SUBJECT = 'Encryption for database connection strings';

GO

Next, a symmetric key using the cert

CREATE SYMMETRIC KEY DBConnection_01

WITH ALGORITHM = AES_256

ENCRYPTION BY CERTIFICATE DBConnection;

GO

I used AES 256, but SQL Server supports other encryption types.

That’s pretty much it for the set up.

Now you can insert a row into the table, then do an update to add the encrypted value.

To update a value, first open the key:

OPEN SYMMETRIC KEY DBConnection_01

DECRYPTION BY CERTIFICATE DBConnection;

Then do an update, using the EncryptByKey function (it takes a reference to the key just created above):

UPDATE DataConnectionValues

SET ConnectionString = EncryptByKey(Key_GUID('DBConnection_01'), 1234);

GO

The EncryptByKey will encrypt using the key, while the DecryptByKey function will decrypt, of course.

I’d recommend wrapping these in a set of functions or stored procedures so that the developers don’t have to mess with keys and certs. In addition, that means that the user accounts only need execute privs on the procedures, not select privs on the table.

The coolish thing is that the users will get nothing if their accounts don’t have the right privs.

To get that, you need connection and select privs on the table (or execute on the stored procedures), privs on the key and the cert.

You can add these cert and key privs by:

GRANT REFERENCES ON SYMMETRIC KEY::[DBConnection_01] TO [someUserId]

GRANT CONTROL ON CERTIFICATE::DBConnection TO [someUserId]

If you really want to get cool, you can add connection encryption to the initial connection string to get the database values. This is probably a good idea since you’ll be passing passwords across the wire. Doing that does two things: First, it encrypts the connection, second, it secures it via the certificate. Not only does this make it harder to hack the values, it adds an additional layer of authentication, since now, the user not only has to have the correct user credentials, but also has to have the correct certificate installed.

From the developer perspective, this is as simple as changing the initial connection string to something like:

Data Source=someServer;Initial Catalog=myEncryptedData;Integrated Security=SSPI;Encrypt=true

That last part sets the encryption to true, and secures the connection. To do this, you’ll need to set up a server certificate on the connecting server and also on the database server.

I’m out of space to discuss that here, but Google knows everything.


Next time I'd like to blog about how to wrapper this into a data connections library and use an object factory to really abstract the complexity of connecting to databases.



--kevin

Friday, February 26, 2010

case sensitive dictionaries

This is just something I didn't know.
If I create a generic dictionary (a string, object Dictionary , for example), the keys are case sensitive. I'd spent hours of work trying to get around this. UNTIL, I found out that case sensitivity in Dictionaries is configurable.

new Dictionary...(StringComparer.OrdinalIgnoreCase);

solves the issue.

Just something to put on the stack.

Tuesday, February 23, 2010

What does Microsoft have against OOA/D?

My guess is that it's because Object oriented development wasn't invented by Microsoft, but it sure seems that they have it out for OOA&D.
Of course, you can go back a few years and clearly see how they were dragged kicking and screaming into the OO world. Take VB4. I still have the box. It clearly says it's an "Object Oriented RAD" environment.
Forget for a minute that OO and RAD are two (nearly mutually exclusive) different things. RAD is designed to get stuff out the door quick. OO is designed to make what you build more supportable, even though it may take longer to build. But, let's ignore that.
VB4, for all it's "OO" claims was to objects as Donald Trump is to good hair. There was no inheritance, no data protection. About the only thing even vaguely OO was polymorphism but that was an accident due to the fact that VB supported late binding of variables.
Not a shock it was that MS' web platform (ASP) relied on VBScript and JScript. JScript was no more OO than VB. Well, to be fair, it had the keyword "object" but you couldn't inherit them or protect them. In fact, you could "superclass" them -- meaning you could actually change the API of the parent. They also were pretty loosely scoped and properties defined in one were visible in another without even a direct object reference.

But that's all in the past, right?

Well, MS is better. C# is OO, no doubt. But you can tell that the gurus there still don't believe in this whole object junk.
For example. take Windows Workflow Foundation. If you create a new flow, the tool auto-magically creates a code-behind "designer" class for you. You can do all kinds of cool things with this -- you can create input and output properties and nifty methods that actually can change how the flow works at runtime. But you can't inherit it. It's a partial class (*choke*). (I once told my dev team that I'd slap the first on of them to use a partial class, but that's another story. )

So... hypothetical situation. Let's say you want to do something crazy, like, oh, i dunno, standardize the input and output elements in your flows, so that you can write a nice clean "workflow consumer" class that your junior devs can just use without having to mess with the whole delegate and workflow runtime junk. So, you think "aha! C# is OO. So I'll create a parent class with the inputs and outputs and implement a standard that all workflows need to subclass from that."
Nope. Notta. Can't do it. That would mean you'd be using OO. Not allowed.

And don't even try to inherit ASPX pages. Cuz, you know.. you wouldn't want to do that, of course. Heaven forbid that you'd want to pull out some of the common functionality. You can't really even inherit the code behind, since it, too, is a partial class (*grumble*).

To this day, I'm still P.O.'ed at them for the "virtual" keyword. Why on earth, would you want to ever make a method that you *don't* want to inherit and potentially override? Ok, maybe I can see it in a few unusual cases. But as the default?

Seems to me, every OO developer has created a class for some project. Six months later, they needed to extend it. They dutifully subclass only to realize that they forgot to make the parent method virtual . Or they just didn't think of it. Now they have to open up the parent class and change it. Look , isn't that the whole *point* of using OO? So that you *don't* have to change the parent class?

For that matter.. why the heck can't you inherit variables from parent classes? what were they thinking when they disallowed this: protected virtual string _x = ""; ? Oh, ok, i get it, you can do it with a property, but.. wha? Why create a property for one stupid string, just so I can inherit it?

As a side note, the whole property thing confuses me. Ok, I mean I get it. Properties replace the getters and setters in Java and, frankly, they're cool. But I defy anyone to show me the value of

public virtual string X
{get { return _x;}
set {_x = value;}
}
But yet, this is the default. So basically you're saying you need 4 lines of code to update a variable? come on. And it doesn't even help maintenance really. I mean, it takes 3 seconds to add it later if I need it. It's an awesome idea, but they're killing us with it's implementation.
As an example, take a look a workflows again. All input and outputs need to be properties. So you potentially end up with 200 {get...set...} combination that... provide.. which value again?

I think this is true because the reflection objects like properties. It's like the MS developers had a new feature and they wanted to use it everywhere. But sheesh.

Unfortunately, I don't see it changing. MS is stepping away from improvements in the core language and moving to improvements in the tools. Unfortunately, the tools won't support OO either -- they're mostly RAD-based. WCF is cool, but try to inherit the WCF transaction sometime. And going forward, I'd expect more things like SSIS and SSRS, and less things like Spring.Net, which actually makes use of inheritance. I do think it's telling that Java developers came up with Spring, while Microsoft came up with F#.

I don't think Microsoft's developers lack any mental capacity. I think they're smart folks. But I just don't think they've had the occasion to use OO. I think that's why none of their tools really support activity diagrams and sequence diagrams very well. (Well, Visio lets you do a few things with them, but we all know it was an after thought, and not a very full functionality.)

On the other hand, Microsoft has been very kind in adding code snippets to Studio. After all, if you can't inherit, you're left with copy/paste, right?

Sunday, January 24, 2010

The Gap

Less techie-stuff today.
Here's a story. Many years ago a very smart young man went to work in IT. Naturally, he developed software in the language of the future (PL/1, with a bit of assembler thrown in). He worked with the computing gods, and aspired to become one.

But along the way, something happened. Maybe he just didn't have divine attributes, maybe he got bored or outsourced or decided he wanted a life. So he changed his aspirations. Rather than being one of the gods of computing Olympus, he would manage them.

He was good at management. He was hard-working and politically savvy. Over time, he worked his way up from Junior Assistant Lackey Manager to Senior Assistant Lackey. Pretty soon, he found himself in a Vice President's office.

But he had one problem. He had no clue what his employee's did. He didn't remember much about computers, but he knew terms like "libraries" and "frames" and maybe even remembered a bit of JCL. They were talking about EJB's and Ajax (wasn't that a cleaning product?) and SSIS and PCI and data warehouses.

Conceptually, he kind of got it, being a smart fellow. But the details were all a mixture of magic words and flowcharts. And he couldn't understand why IT had gotten so expensive or why it took so long to get things done. Why not just toss together some JCL and run the silly thing? Why did everything take 4 months?

Enter the vendors. They walk into his office with really spiffy demos. It's not a flow chart, it's something he can see. And it's pretty. The reports are all graphical and the demo shows how easy they are to use. And time to market? Oh, the vendor insists that they have a crack consulting team that can deliver on the fly. Why, as part of the demo, the vendor even builds a really cool report in minutes.

Our hero is hooked. He signs on and spends a zillion dollars.

Then he gets the product to his IT staff and they tell him that they can do the same work already with other tools. Moreover, they insist that the complexity isn't producing the pretty report, but aggregating the data from the 16 different heterogeneous data stores they have, manipulating it to make it actually match, then (this is the really hard part), making it mean something. It's easy to sum a table column. It's a lot harder to know what the data in the column means or what the rules are around summing it.

The problem is that there is a gap between the people who work in IT and the folks who manage it. The vendors and consultants make a ton of money trying to fill that gap. Each year, there's a bevy of products aimed at it. They each hold the promise of being able to close the gap -- and turn the IT systems from a collection of disparate pieces into a contiguous whole. Only, in reality, the vendors don't really care much if they work. Oh, I'm not saying they are sloppy or bad people - although some are, I'm sure. But I'm just saying that in the end, the vendors have very little incentive to really close the gap, since that's basically how they make their living. Without the gap, consulting services have to shift their work to being little more than resource augmentation providers. And they have no real competitive edge. Today, if a consultant can get certified in the latest hot product, they can bill themselves as experts. If the gap closes, that will hold much less value. The vendors are in the same position. If the gap closes, then the only way for them to make a living would be to be truly creative with their products or to build tools that actually provide value for the developers. Don't get me wrong, some companies do that. Microsoft has a bunch of them. Oracle does too, although they have a lot of "gap-closers" too. Sun has a few, although they've been hamstrung by financial issues. But other companies would have to pony up and compete with the IBMs of the world.

And it's so much easier to simply pull together a good demo.


Friday, January 15, 2010

CORRECTION

My mistake.
Some days I just struggle to tie my own shoes.

In my last blog post, I talked about how to create an audit trigger. And I made a mistake that I found badly when I tried to run an update.

Here's the issue.
SET @OldValue = (SELECT B FROM deleted);
SET @NewValue = (SELECT B FROM inserted);

this is great if there's exactly one row in the tables. This means that if you're updating only one row at a time, everything's dandy. But if you do an update that will impact more than one row, this will fail and crash hard.

How do you get around it?
Basically, you need to open a cursor for each row in the update tables, then step through the cursor one row at a time.

So in this case, first you would
build out a cursor
DECLARE cur_inserted CURSOR FOR
SELECT B, A FROM inserted
OPEN cur_inserted
FETCH NEXT FROM cur_inserted INTO @B, @A
WHILE @@FETCH_STATUS = 0
BEGIN


SET @B= (SELECT B FROM deleted WHERE A = @A);

INSERT INTO MyAudit (Value, AuditType)
Select B, 'OLD' from deleted WHERE A=@A; (assuming A is a unique key).

Basically, it does the same thing, but uses a cursor to walk through the modified rows, then pulls the corresponding values from deleted that correspond to the cursor row. In this case, it will pull the "old" values into the log table while walking through the "new" ones. Of course, you can still add conditional statements on this as before.
but this will actually work for mass updates.
Sorry for the confusion.


Thursday, December 24, 2009

audit tracking on Sql Server

Here's the challenge. You've got a database. In that database, you've got a table (say T). In that table, there are some columns -- say A, B, & C. If column B changes, you want to log that change somewhere.

You've got a couple issues. First, you don't care about columns A or C. If they change, you don't want to log the change. So how do you know when it's column B that changes?

Next, you only want to log the change if it actually *changes*. So if the value of B is x and someone does "UPDATE T SET B='x'", you don't want to log that, since it's not really changing the value ,but just setting it to what it already was.

In Sql Server, you can do this easily with a table trigger, but how you do it is a bit whacked.

First you need to create the trigger, of course. Then we'll need 2 variables -- one for the old value and one for the new:

CREATE TRIGGER somename
ON T
AFTER UPDATE
AS
BEGIN
DECLARE @OldValue integer
DECLARE @NewValue integer

Note that the trigger actually fires after the update. I did this because, in this case, the trigger need not be transactional -- I don't want to rollback the change just because I can't audit it. There may be cases where this isn't true, of course, but it will due for what I need.


Next, you'll need to use this: COLUMNS_UPDATED()
COLUMNS_UPDATED() will show you the columns that got updated by the update statement that fired the trigger, but the weird part is that it returns it as a bit mask. If you don't know what a bit mask is and don't want to learn, you can use a built in function to help. The column I'm looking for (B) has a corresponding bit in the bitmask. You can look to see if it gets set, but the way bit masks work, it's not quite that simple. Changing columns A or C at the same time as B, will create a different bit mask value. So it's not as simple as " if COLUMNS_UPDATED() == x20000" or something.

Because it's been like a hundred years since I've had to bit shift, I' m going to suggest using Microsoft's built in function to look for this value. It is:
sys.fn_IsBitSetInBitmask()

So, the syntax:
IF (sys.fn_IsBitSetInBitmask(COLUMNS_UPDATED(), 2) >0 )

will return true if the 2nd column (in this case "B") has been set, regardless of whether A or C have.

But what it doesn't tell is if the value was actually *changed*. This if statement will return true anytime the column is "Set" in an update statement.

But it's pretty easy to check, although it takes a few extra lines:

SET @OldValue = (SELECT B FROM deleted);
SET @NewValue = (SELECT B FROM inserted);

"deleted" and "inserted" are in-memory tables that hold the values of the update before and after the update itself. "Inserted" holds the new values, "deleted" holds the old ones. Since it's in memory, it's pretty quick. In my case, updates to the table will only happen one row at a time. If you're talking about mass-updates, you need to be careful that performance won't suffer. On the other hand, it is an in-memory query, so the numbers have to get pretty big before that's an issue. If you're doing such bulk transactions, you probably have other issues anyway.

With this, the old and new values can just be compared:
IF (@OldDisp <> @NewDisp)

To insert them into the audit table, just pull the values from either "inserted", "deleted" or both, depending on what it is you're looking to audit.

INSERT INTO MyAudit (Value, AuditType)
Select B, 'OLD' from deleted;
or
INSERT INTO yAudit (Value, AuditType)
Select B, 'NEW' from deleted;

for the old and new values.

That's pretty much it.
You'll want to add some error handling. And be careful about this. If the error gets thrown, it probably means that you can't insert into a database table. If that's the case, you may not be able to insert into any (out of space or whatever). So you may want to log the issue to system logs
(EXEC XP_LOGEVENT @ErrorNumber, @ErrorMessage, @ErrorSeverity )

or RAISE the error.

What's cool about this, is that it's database centric. If anyone modifies anything, you have it -- whether it's a service that does it, a scheduled task, or even an individual user with database privs. You can pull off the user id that initiated the update, if that's helpful, but keep in mind that the scheduled tasks and services probably all have a shared account.

--kevin