10.17.2006

Roll-your-own login database with SQL and C#.NET

This is all pretty simple really. There's two parts to it: a database to store usernames and passwords, and code to validate the user on the web page or application. This code can be used in C#.NET applications, or in the code-behind files of ASP.NET applications. It will translate to VB fairly simply, but the SQL part would remain the same whether you use VB, C# or anything else.

First, we will create a database table and stored procedures to store new users and validate the existing users. In this example I will not use encryption, but if you wanted to, these same database principles would apply. For SQL Server 2000 and later editions, you can create a case-sensitive column when you declare your table, so to enforce case-sensitivity, we will nip any problems in the bud right here. Here's the code to create the table:

create table user_login (
 rep_id int identity(1,1) NOT NULL,
 username varchar(100) COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL,
 password varchar(100) COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL
)

The COLLATE statements cause SQL server to treat these columns as case-sensitive in all queries from now on. This is a really great feature because programmers can't mess this up, no matter what, these columns will be case-sensitive. In order to increase performance, you should create an index on this table for the username column. You may also consider declaring (username + password) to be the primary key and making that the clustered index. If you have different user levels on your site, you should store the user level in this table, and add it to the stored procedures below as well. This table could also be used to store contact information for the user, but I prefer to store that in another table (using the rep_id to join), which keeps the login table fast, particularly if there are a lot of users. Now that our table is created, we need stored procedures to interact with it. The reasons to use stored procs are too numerous to list, but in this case, we are looking for security, and we want to avoid SQL Injection attacks if at all possible. Using stored procs exclusively is a great first step in the security battle. Another step will be shown later and the third step, encryption, will not be discussed here, but is a great addition to any security model. We need two stored procs, one to create new users, and one to validate existing users.

create proc create_user
 @username varchar(100),
 @password varchar(100)
as
declare @result int
--first make sure this is a valid new user
--username must be unique
if exists (select 1 from user_login where username = @username) begin
 set @result = -1
end else begin
 insert user_login (username, password)
 select @username, @password
 
 set @result = @@identity
end

select result = @result
return @result    
GO

create proc validate_user
 @username varchar(100),
 @password varchar(100)
as
declare @result int

if exists (select 1 from rep where username = @username and password = @password) begin
 select @result = rep_id from rep where username = @username and password = @password
end else begin
 select @result = -1
end
select result = @result
return @result
GO

These procs are fairly straightforward. The first one creates a new user. If the user was not created because of non-unique username, then the proc returns -1, otherwise it will return the ID of the new user. The second procedure is similar. It takes the username and password, and returns the ID of the user who logged in. If the login is incorrect, the proc returns -1. In order to make things easier on the recieving end, I 'select out' the values, as well as 'return' them from both procs. This gives me options in picking up that value in client apps.

In order to prevent SQL Injection attacks, we need to check all user input if it is going to be used in an SQL command string. This should be done with web apps or windows apps, since users may be malicious in either case. The following simple function will negate most attempts at SQL Injection, by replacing all occurences of '(single quote) with ''(two single quotes) and \(blackslash) with \ (two backslashes).

private string sql_fix(string s) {
 return s.Replace("'", "''").Replace("\\", "\\\\");
}

Interestingly enough, this allows usernames or passwords with any number of single quotation marks or backslashes. In order to use our new database, we will need code to create new users. This code can be written very simply in C#. Assuming you have correctly opened your database connection, and you have some form elements with the new username and password, you can create a new user with the following C# code. I've used the sql_fix() function here, since this is user input being passed to SQL Server.

public int create_user(string username, string password) {
 int result = -1;
 SqlCommand cmd = new SqlCommand("exec create_user '" + sql_fix(username) + "', '" + sql_fix(password) + "'", conn);
 SqlDataReader r = c.ExecuteReader();
 if (r.GetInt32(0) > 0) {
  //we got a positive number back, so it worked
  result = r.GetInt32(0);
 } else {
  throw new Exception("User creation failed");
 }
 r.Close();
 return result;
}

This method mimics the behavior of the SQL proc it's tied to, returning the ID of the user who was created, or throwing an exception if the user creation failed. You could modify the stored proc and this function to indicate a better error message, by sending an error code or message back from the stored proc. You could also pick up this value and use it in your application to do further interaction with the new user. To validate a user, you simply call our other stored procedure and act accordingly. In this example, I'm just going to throw an exception if the login is incorrect, but you could handle the situation any way you see fit. I've used the sql_fix() function again to avoid any possible SQL Injection attacks.

public int validate_user(string username, string password) {
 int result = -1;
 SqlCommand c = new SqlCommand("exec validate_user '" + sql_fix(username) + "', '" + sql_fix(password) + "'", conn);
 SqlDataReader r = c.ExecuteReader();
 if (r.GetInt32(0) > 0) {
  //we got a positive number back, so they are an authorised user
  result = r.GetInt32(0);
 } else {
  throw new Exception("Incorrect login");
 }
 r.Close();
 return result; //this will be -1 unless updated by a successful login
}

This method again mimics it's SQL proc, returning the ID of the user who logged in. By using these two functions with your database, you should be able to manage user logins simply and effectively. You may wish to add encryption to this, and further validation of the username and password strings (ie: to check for 'strong' passwords in user creation), but this should give you a good basis to get started with. Please leave comments if you have any questions and I will be able to answer them for everyone!

Have fun with it!
Jasmine

10.15.2006

WTF PSA?

So, it's now exactly 2:45AM, and I'm watching a re-run of Saturday Night Live. Not too surprising really, but I just saw the best Public Service Announcement I've ever seen. Everyone wonders about this, but I really need to know... why is this on at 2:45 AM, when nobody is going to see it? Of course, I did see it, so maybe airing these commercials at this time of night isn't completely asinine. Maybe the TV station analysed the options and determined that this time of night was best to hit their target audience for this ad. I don't know, but I do know that running the ad during prime time would help a whole lot more. Why are the ads on prime-time so stupid, and the juicy ones that could help people are on at 2:45AM? This doesn't make any sense, so I'm writing to the TV station and I'll let y'all know what they say.
Stay groovy!
Jasmine

10.05.2006

Boulder, you used to be so cool

Dear Boulder,
Hey what's up with you, man? You used to be so cool, always coming over to hang out and being all about peace and love and groovy stuff. Now we can't even come play footbag on your lawn?! I used to love you, but now you've totally sold out. I can't even stand to see you like this anymore. You suck. Come on, man, get it together.

Your best old friend,
Jasmine

9.23.2006

re: Calling Me Out on Anti-Discrimination Laws

This is my response from someone who thinks my previous blog is dead wrong. Here's what they had to say

*sigh*...Jasmine, hon...I applaud your "standing up" for what you see as right. But *I* have to disagree with you on several points.

First off, legal or political grandstanding aside, I would guess that, in fact, Danielle *was* fired for being transgendered. Does this company employ women? (...As the columnist pointed out; yes, they do.) Are any women employed in the position that Danielle held? We don't know that; and it is cogent to the legal ramifications. However, if they have *ever* employed a female (GG, TG, or Martian Amazon) in such a position (or one of a similar pay grade, or level of responsibility), the case falls apart. It's *very* difficult to assess the ramifications of this court decision, without the facts; yet you (*and* Mr. Harsanyi both) make blithe assumptions based simply on the verdict. We don't know what evidence was presented, or the levels of competence of the Counsels for the Defense and/or Prosecution. It is possible that Lead Counsel for the Defense had an emergency appendectomy, and the "second chair" screwed up the case. Or not. Is there going to be an appeal? This is also an indicitve point.

My second point involves Mr. Harsanyi's assertion that anyone who hires a TG person, and then fires them, encounters a very real risk of being sued...a point that you categorically deny. Hon, I work for the Federal Government. I have been directly involved in "prejudice" charges involving hiring; and have had the opportunity to observe several other such charges, for terminations, and disciplinary actions. I also happen to be a member of the TG community, Let me be *very* clear on this; TG's are like *everyone* else. *Some* are decent, honest, honorable, and hard-working. *Others* are deceitful, lazy, and manipulative. Have you ever heard the term "playing the Race card"? ...well, it works the same way for us. The columnist has a valid point; and a potential employer has a valid concern. In my experience (and talking to Federal HR personnel, *and* Union members, as well); the observation is that about 70% of such "prejudice" claims are patently fraudulent. But the plaintiff fires from an open choke, and hopes to hit *something*...an overly sympathetic judge, a supervisor or manager who doesn't want the hassle of the endless mediations; or a mistake in the proceedings, that will give them a foot in the door. Such people often file claims over and over, for every possible slight, until they get what they want. I would also point out that, having been a member of the TG community for several years, and hearing many such discussions; I have observed that a lot of "disadvantaged" people or groups (of which we are only one) appear to *enjoy* being "down-trodden"...it makes them Special. When they are treated like everyone else (as they are constantly demanding), all of a sudden it's "unfair.and illegal."

My third point is the basic concept of Personal Rights...and that is that *your* rights end where *mine* (or anyone else's) begin. Mr. Harsanyi pointed this out obliquely in his column. If I believe that keeping animals penned up is cruelty; do I have the right to run around, releasing all the dogs in town from their yards? If I believed in nudity; don't I have the right to walk down the street naked? *shrug*...some would say that there is a world of difference between dressing in clothing of the "opposite" gender, and walking around with your Tallywhacker (or your Bewbies) hanging out. Others would say that it's exactly the same thing. Who is right? That is a delicate decision, for the courts to decide. And courts are swayed by public opinion.

SO....until-and-unless a majority of the American (or at least the State) population recognise (and *accept*) TGs and their lifestyle as mainstream; it will continue to be a point of contention. I am glad that there is discussion on this subject; it makes the topic more accessible to mainstream America. But it is *not* as plain and obvious as you make it out. Want to change it? Then go downtown to your local Redneck bar, and convince 'em. *Shrug*...Change is a slow process.

We would *all* do better with a bit of tolerance. Would we be better of *without* the Carrie Nation's, the Rosa Parks'es, the Dr King's? ...probably not. But I think that your reaction was way out of proportion to what appeared (to me) to be a fairly well-balanced opinion article. You are entitled to your opinion, but Mr Harsanyi is entitled to his, as well; and I don't think that it was terribly out-of-line.

And that's *my* opnion...worth what you paid for it.

judy

(anyone want this soapbox?...I think I'm done with it...)

Below is my response

I realise there is an element of realism missing from my opinion, but realism won't help advance our cause. Idealistic thinking is what causes political progress. The arguments must be polarized. If we all went around being realistic all the time, there wouldn't be any need for the democratic process... we would all be in agreement already since there is only one reality.

This is a case of someone being treated correctly by the law, and someone else complaining about it due to his irrational fears and ignorance of the situation. That is what really burns me up - that people irrationally fear us because they choose to be ignorant about the situation. I am aware that people file frivoulous lawsuits, but that's not the situation here, and the point is that having the law doesn't cause the cases. The immoral people (including the lawyers) who file the lawsuits are the problem, not the law. The problem of unfounded lawsuits is not specific to the discrimination issue, and it really needs to be considered separately. Every new law could potentially increase the amount of unfounded lawsuits. That factor can not be considered when examining the validity of a new law.

The article implies that Danielle somehow received 'special treatment' because she is transgender, but the ruling makes it perfectly clear that this is not the case. We don't need to be privy to every iota of the evidence to understand that. People need to understand that while there are good reasons for firing employees, there are also ILLEGAL reasons for doing it, and those reasons are illegal no matter who the person is - even if they are not from a marginalized minority group. This case would have been an illegal firing regardless of the transgender issue. That's an important point because it means that this person wasn't given any special treatment.

I don't think anyone should be given special treatment, but people should be restrained, legally, from acting on their hate. That is the purpose of anti-discrimination laws in the first place, not to provide 'special rights' to any group, but to ensure the same rights for groups that are targetted unfairly by the majority. If this person was fired for being a poor employee, then the case would have gone the other way. I'm fairly confident in that, regardless of your observations. As a manager for Domino's Pizza, I have been through the frivoulous lawsuit before. It was a simple matter for us to show documentaion that the employee was fired for being consistently late (time cards), being rude (customer complaints), and breaking the law (theft of company property, with police reports). That stuff didn't keep the person from whining to the court about fired for being Russian, but the company was acting legally and we could prove it. The case was a minor pain in the ass for us, but there was absolutely no chance of it going the wrong way.

In the vast majority of cases employers are not that responsible. At that point, it's one word against another, because we can't read someone's mind and figure out the real reasons for the firing. There were no unbiased observers of the situation, so we are left to look at the evidence. In most legal cases, it is possible to prove that a crime occured and who committed it, but in discrimination cases, it's usually not that explicit. In this case, the court found that Danielle was a good employee, and should not have been fired due to job performance. They also found that the company had no grounds for randomly downsizing its workforce - that the business is healthy and not failing. When the court looked at the possible reasons for firing this person, every reason was eliminated except one. Therefore, we are forced to assume that the remaining reason is the correct one, unless it can also be proven false. This is not the way we normally prove criminal intent in our court system, leaving the whole thing open to interpretation. It's not clear why this person was fired, and it never will be. The legal system is not perfect, but that doesn't mean it's flawed either. In this case, things probably went the way they are supposed to.

I am insulted by the article's suggestion that, regardless of employment-related factors, keeping your job may be as easy as putting on a dress. People who transition at work don't do it to keep their jobs. Many of us delay our transitions because we fear firing, or because we respect our co-workers and don't want to disrupt company operations. We take this decision seriously. Current laws on the books in some counties in Colorado require documentation of transgender status if you wish to 'crossdress' at work. Without that documentation, you are violating the dress code, and should be let go. These laws provide conscientious transgender people who are honest about their transitions with a vehicle for ensuring that their transition doesn't result in unfair treatment. We need laws like that on a national scale. This is the same as anti-discrimination laws regarding races, disabilities and so on.

The vast majority of people think transitioning is a choice that a person doesn't have to make, and therefore, if they make that choice, they deserve whatever smack-down society wants to throw at them. The public needs to realize that transitioning, for many of us, is no more a choice than being African, Mexican, or a paraplegic. It's something we have to do, and we don't deserve to get fired for it, any more than a Mexican person deserves to get fired for being born that way. Editorial articles that ignore this FACT are irresponsible, and serve no other purpose than to hurt our community by reinforcing these false assumptions in the collective public mind.

I could go on forever about this, but the point is, regardless of the specifics of this case, we don't need articles in the newspaper spreading lies and distrust about our community. If the editorial opinion was based on the truth, and the reporter still had the same conclusion, then I wouldn't have a leg to stand on, but this argument has been attempted before. Read that article again and replace every instance of 'transgender' with 'african', and tell me that's not irresponsible journalism. These are the same arguments that people were making years ago about the racial discrimination problem. The argument is as wrong now as it was then.

Jasmine

PS: If the employer had said "we fired her because we are in the construction business and it's bad for our reputation to have transsexual people working here. Customers won't call us for fear that 'the freak' will show up to do the job, and they don't want that in their business," then they would have won the case, but instead they tried to show that they had a business-related reason, and they failed. For more insight into that technicality, contrast "Ulane vs. Eastern Airlines" (court found that transgender people ARE protected from sex discrimination under Title VII) and "Holloway vs. Arthur Andersen" where the court found that:

"Transsexuals claiming discrimination because of their sex, male or female, would clearly state a cause of action under Title VII. Holloway has not claimed to have been treated discriminatorily because she is male or female, but rather because she is a transsexual who chose to change her sex. This type of claim is not actionable under Title VII and is certainly not in violation of the doctrines of Due Process and Equal Protection."

 
hit counter script