Sunday, February 28, 2010

Authentication with Active Directory, ASP.NET MVC, & fluentHtml




I figure since people are starting to really look into MVC and are realizing that it’s going to be around for a while, they’re going to need some decent samples when researching how to do things. I’m hoping this particular post will possibly be one of those examples. I had the same thought when I wrote the Security Questions with ASP.NET MVC & fluentHtml post.

Let’s get started with the view model class for the sign in page. By the way, if you’re not familiar with the way I setup my MVC projects, see this post.

public class SignInView
{
[
ValidateNonEmpty("Username is required.")]
public string Username { get; set; }
[
ValidateNonEmpty("Password is required.")]
public string Password { get; set; }
}

Really simple. The ValidateNonEmpty is an attribute from the Castle project and I’m passing in the error message I want displayed if invalid.

Okay, so let’s go ahead and pass in this view model to our actual view from the AuthenticationController. This will look like this:

public ActionResult Index()
{
return View(new SignInView());
}

Now we’ll create our actual view (html):

<%=Html.DivValidationSummary("All fields are required.") %>
<form action="/authentication/index" method="post">
<
fieldset>
<
legend>Sign In</legend>
<
p><%=this.TextBox(f => f.Username).Label("Username: ")%></p>
<
p><%=this.Password(f => f.Password).Label("Password: ")%></p>
<%=Html.AntiForgeryToken() %>
<%=Html.SubmitButton("Sign In", cssclass=>"sb", accesskey=>"S") %>
</
fieldset>
</
form>

This is our basic html setup with fluentHtml added to it. If you need a tutorial on fluentHtml, here’s a post on it. Basically, I’m using my htmlHelper for a DivValidationSummary, I’m calling the index action on the authentication controller, then I’m setting up my textboxes with fluentHtml, using the antiforgerytoken to prevent csrf, and I’m using my submit button that I blogged about before this post.

Now let’s look at the action that’s being called by the form above.

[AcceptVerbs(HttpVerbs.Post), ValidateModel(typeof(SignInView)), ValidateAntiForgeryToken]
public ViewResult Index(SignInView form)
{
if (!ModelState.IsValid)
return View("index", form);

IUser user = DependencyRegistrar.With<string, IUser>(form.Username);
bool passwordMatches = _authenticationService.PasswordMatches(user, form.Password);

if (passwordMatches)
{
//Sign In – Write Cookie & Redirect most likely through a UserSession
}

ModelState.AddModelError(
"SignIn", "Invalid credentials");
return View("index", form);
}

Okay, so you can see I’m accepting only post, I’m validating the model, and I’m validating the token. I’m also accepting my SignInView model. If the model state is not valid I return the model back to the view. Otherwise, I get an instance of user with my username and then I call my authenticationService. If passwordMatches, sign in and return, otherwise add an error and return.

So let’s look at my IUser real quick. It’s really simple:

public interface IUser
{
string Username { get; set; }
}

Think my AuthenticationService is much more difficult? Of course not!

public interface IAuthenticationService
{
bool PasswordMatches(IUser user, string password);
}

By the way, I’m accepting an instance of IAuthenticationService in the constructor of the controller like so:

public AuthenticationController(IAuthenticationService authenticationService)
{
_authenticationService = authenticationService;
}

I’m using StructureMap to know what to pass in to the constructor. Okay, so my AuthenticationService implementation looks like this:

public class AuthenticationService : IAuthenticationService
{
private readonly IActiveDirectorySettings _adSettings;

public AuthenticationService(IActiveDirectorySettings activeDirectorySettings)
{
_adSettings = activeDirectorySettings;
}

public bool PasswordMatches(IUser user, string password)
{
var authenticated = false;
var domainAndUsername = _adSettings.DomainName + "\\" + user.Username;
var entry = new DirectoryEntry("LDAP://" + _adSettings.LdapPath, domainAndUsername, password);

try
{
var bindToNativeObjectToForceAuthentication = entry.NativeObject;
authenticated =
true;
}
catch (COMException)
{
}

return authenticated;
}
}

Now my IActiveDirectoryCredentials looks like this:

public interface IActiveDirectorySettings
{
string DomainName { get; }
string LdapPath { get; }
}

That’s basically it. There’s not a whole lot to an authentication process, but thought I’d share anyhow.

Thanks for reading!


Shout it

kick it on DotNetKicks.com

Monday, February 22, 2010

Fun with Lambdas & HtmlHelpers




Since I started using fluentHtml, I’ve loved this syntax: this.Textbox(f=>f.Whatever).Styles(display=>”none”)

The fact that it’s SO easy to read is what I love…specifically the Styles() portion. So I downloaded the MvcContrib source to see how they were handling it and it was actually pretty simple. Basically, you setup a param like this:

params Func<string, string>[] values

So let’s do a quick sample for a…submit button. I want to be able to type this below for a basic submit button with the text “Sample Submit”:

<%=Html.SubmitButton("Sample Submit") %>

If I want to add an accesskey attribute, I want to just type this:

<%=Html.SubmitButton("Sample Submit", accesskey=>"S") %>

If I want to add an id to the button, I want to do this:

<%=Html.SubmitButton("Sample Submit", accesskey=>"S", id=>"sampleid") %>

If I want to add a css class, I want to just do this:

<%=Html.SubmitButton("Sample Submit", accesskey=>"S", id=>"sampleid", cssclass=>"sampleclass") %>

Okay, so I think you get the idea. By the way, the reason we can’t put class=>”sampleclass” is because class is a reserved word and throws an error. I’ll show you how I get around the issue.

So what does this extension method look like? Here it is:

public static string SubmitButton(this HtmlHelper htmlHelper, string textValue, params Func<string, string>[] values)
{
var attributes = new StringBuilder();
foreach (var func in values)
attributes.AppendFormat(
"{0}=\"{1}\" "
, func.Method.GetParameters()[0].Name.ToLower().Replace("cssclass", "class"), func(null));

return string.Format("<input type=\"submit\" value=\"{0}\" {1}/>", textValue, attributes);
}

So let’s break this down.


  1. Notice the params keyword in the method signature. What this allows you to do is pass zero or many Func<string,string>s into the method. Note: when using the params keyword, it should be the last argument in the signature and it should be a defined as an array.

  2. If you’re new to StringBuilder, it is generally used when concatenating string together because it performs better than plain ole string.

  3. So I’m appending the format of attributename=”value”, which is represented by the “{0}=\”{1}\” “. (Notice the AppendFormat signature contains a params object[])

  4. The first argument represented by {0} is the name of the parameter of the generic Func<>. So I’m getting the first parameter from the Func<> method and lowering the name and replacing cssclass with class.

  5. The second argument represented by {1} is the value of the lambda, which we get by calling func(null). We don’t have to pass in null, we could pass in anything we want to func because we’re not using it for anything, we’re just returning the value we set after the =>. However, null is the cleanest method :)

  6. Lastly, I return the formatted submit html code, which sets the value and attributes. If there aren’t any, then the {1} is empty and basically ignored.

Well, that’s it. I thought I’d share because I think it’s something that’s pretty useful, cool, and easy to read for the end-user of your code. Thanks for reading!


Shout it

kick it on DotNetKicks.com

Saturday, February 13, 2010

SQL Logging with log4net & ASP.NET MVC








I wanted to get some logging action on my latest project and I’ve heard a lot about log4net so I thought I’d give it a whirl. My goal was to have a simple interface that implements log4net and writes to SQL Server. With that said, my interface ended up looking like this:

public interface ILoggingService    

{
void Log(string message);
}

I told you it was simple :)

Okay, now let’s go ahead and implement the ILoggingService like this:

public class LoggingService : ILoggingService

{
private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public void Log(string message)
{
log.Info(message);
}
}

This particular implementation is only going to log informational type things and not errors or warnings. Basically I want it for auditing purposes. Note: LogManager is part of log4net.

So let’s go on and configure log4net. First we’ll create an IStartUpTask, see this post for more info on the IStartUpTask.

    public class log4netConfigurator : IStartUpTask

{
public void Configure()
{
log4net.Config.XmlConfigurator.Configure();
}
}

I’m going to configure log4net in my web.config. I’ve seen a lot of people have a separate log4net.config file, but I want to just put mine in the web.config. So let’s add a log4net section to the <configSections> like this:

<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,Log4net"/>

Now we can add the section to the web.config like this:

<log4net>

<root>
<level value="ALL"/>
<appender-ref ref="ADONetAppender"/>
</root>
<appender name="ADONetAppender" type="log4net.Appender.ADONetAppender">
<bufferSize value="1"/>
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<connectionString value="server=serverNAME; uid=userNAME; pwd=passWORD; database=databaseNAME"/>
<commandText value="INSERT INTO ChangePasswordLog ([Date],[Thread],[Level],[Logger],[Message],[Exception]) VALUES (@log_date, @thread, @log_level, @logger, @message, @exception)"/>
<parameter>
<parameterName value="@log_date"/>
<dbType value="DateTime"/>
<layout type="log4net.Layout.RawTimeStampLayout"/>
</parameter>
<parameter>
<parameterName value="@thread"/>
<dbType value="String"/>
<size value="255"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%thread"/>
</layout>
</parameter>
<parameter>
<parameterName value="@log_level"/>
<dbType value="String"/>
<size value="50"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%level"/>
</layout>
</parameter>
<parameter>
<parameterName value="@logger"/>
<dbType value="String"/>
<size value="255"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%logger"/>
</layout>
</parameter>
<parameter>
<parameterName value="@message"/>
<dbType value="String"/>
<size value="4000"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message"/>
</layout>
</parameter>
<parameter>
<parameterName value="@exception"/>
<dbType value="String"/>
<size value="2000"/>
<layout type="log4net.Layout.ExceptionLayout"/>
</parameter>
</appender>
</log4net>

Okay, so I have an appender setup here to write to my DB.I think it’s pretty self explanatory, if you disagree, post me a comment and I’ll go into more detail. One hiccup I ran into was the bufferSize because I kept trying to test to see if it was writing to my DB and nothing was showing up. The reason being…I didn’t have 100 log entries. I changed the bufferSize to 1 and POOF my record showed up :)

So now in my controller, I accept an ILoggingService in the constructor like this:

        private readonly ILoggingService _loggingService;

public HomeController(ILoggingService loggingService)
{
_loggingService = loggingService;
}

So now I can call my Log method from any of my actions like this:

var changePasswordService = DI.ChangePasswordService(username);

changePasswordService.ChangePassword(form.ValidationToken, form.Password);
_loggingService.Log("Password changed for user " + username);

All done! Now I have logging in my app.

Thanks for reading!


Shout it

kick it on DotNetKicks.com

Friday, February 12, 2010

SQL to XML with SSIS




Have you ever had a vendor ask for XML instead of a quick CSV file? Well, if you’re using MSSQL 2005 or 2008, I’m sure you realized just how awesome they are when this request came through. I’m going to walk through exporting an XML file from SQL Server 2005 using SSIS ans SQL.

First we’ll need to write the SQL script to generate the XML. I’m going to write an XML file that exports a list of users to a vendor so we’ll have root » customer » action » user info

Let’s start basic and just get something like this:

<root>
<
customer>demousername</customer>
</
root>

To get this with SQL, it looks like this:

select 'demousername'
for xml path('customer'), root('root')

Really simple so far right? Okay, so I need to add two attributes to my customer element called username and password, which are provided by my vendor. So I’ll want my end XML to look like this:

<root>
<
customer id="demouserid" password="demopassword" />
</
root>

To get this result, I simply write this SQL:

select 'demouserid' as '@id', 'demopassword' as '@password'
for xml path('customer'), root('root')

Okay, so now I need to add my action element like this:

<root>
<
customer id="demouserid" password="demopassword">
<
action ActionType="User_Add"/>
</
customer>
</
root>

The SQL looks like this:

select 'demouserid' as '@id', 'demopassword' as '@password',
(
select 'User_Add' as "@ActionType"
for xml path('action'), type)
for xml path('customer'), root('root')

The only weird thing about this SQL is the “@ActionType”, which represents the attribute name on the action element. The @ sign basically says hey I’m an attribute and not an element. Also, the “type” after (‘action’), says that I’m an element. Without the “type”, you’ll get this:

<root>
<
customer id="demouserid" password="demopassword">&lt;action ActionType="User_Add"/&gt;</customer>
</
root>

Okay, so now I need to add my user info and I’ll end up with this:

<root>
<
customer id="demouserid" password="demopassword">
<
action ActionType="User_Add">
<
FirstName>Deran</FirstName>
<
LastName>Schilling</LastName>
<
UserName>test@demo.com</UserName>
<
Password>demopassword</Password>
<
Email>test@demo.com</Email>
<
JobTitle>Something Awesome</JobTitle>
</
action>
</
customer>
</
root>

So to get this XML, I just add in the columns and names I want like this:

select 'demouserid' as '@id', 'demopassword' as '@password',
(
select 'User_Add' as "@ActionType"
, firstname as FirstName, lastname as LastName
, emailaddress as UserName, 'demopassword' as [Password]
, emailaddress as Email, jobtitle as JobTitle
from demousertable
for xml path('action'), type)
for xml path('customer'), root('root')

One more thing I want to show you is how to add a reference number to the action element. So I’ll end up with something like this:

<root>
<
customer id="demouserid" password="demopassword">
<
action ActionType="User_Add" ref="1">
<
FirstName>Deran</FirstName>
<
LastName>Schilling</LastName>
<
UserName>test@demo.com</UserName>
<
Password>demopassword</Password>
<
Email>test@demo.com</Email>
<
JobTitle>Something Awesome</JobTitle>
</
action>
<
action ActionType="User_Add" ref="2">
<
FirstName>John</FirstName>
<
LastName>Demoed</LastName>
<
UserName>john@demo.com</UserName>
<
Password>demopassword</Password>
<
Email>john@demo.com</Email>
<
JobTitle>Something Okay</JobTitle>
</
action>
</
customer>
</
root>

Notice the ref=”1” and ref=”2” on the action element? The way you get that result is with this SQL:

select 'demouserid' as '@id', 'demopassword' as '@password',
(
select 'User_Add' as "@ActionType", ROW_NUMBER() OVER (ORDER BY username) as '@ref'
, firstname as FirstName, lastname as LastName
, emailaddress as UserName, 'demopassword' as [Password]
, emailaddress as Email, jobtitle as JobTitle
from demousertable
for xml path('action'), type)
for xml path('customer'), root('root')

So the ROW_NUMBER() OVER (ORDER BY uniqueidentifierofsomesort) gets the row number for each returned record. I love that feature.

Alrighty! So now let’s get to the SSIS, which is much simpler!

Step 1:
Create new SSIS package in Visual Studio 2005.

Step 2:
Drag an “Execute SQL Task” over to the “Control Flow” and name it something like “Generate XML” or whatever you prefer.

Step 3:
Double-click it.

  • General Section
    • Change ResultSet to XML
    • Select/Create your Connection
    • Enter the SQL statement, like the one we created above

image

  • Result Set Section
    • Add a new string variable called something like XmlContent

imageimage

Step 4:
Drag a “Script Task” over to the “Control Flow” and name it something like “Save Generated XML” or whatever you prefer.

Step 5:
Double-click it.

  • Script Section
    • Add XmlContent (or whatever you named your variable) in the ReadOnlyVariables
    • Click “Design Script…”

image

Step 6:
Once in the ScriptMain for VB, which I’m not a fan, but appears to be the only option. So you’ll just add this snippet in the Public Sub Main():

Dim sw As New IO.StreamWriter("C:\demo\AddUsers.xml")
sw.Write(Dts.Variables("User::XmlContent").Value.ToString())
sw.Dispose()
Dts.TaskResult = Dts.Results.Success
The red text above represents what you’ll need to change to match what you desire. First item is the file path to the location of your xml file and the second item is the name of your variable with the namespace.

That’s it! Now you have a generated XML file from a SQL DB. I thought it was pretty cool and a LOT easier than I thought it would be when I first started.

Thanks for reading!


Shout it

kick it on DotNetKicks.com

Thursday, February 04, 2010

General Tips & Tricks




I was in a meeting yesterday and one of my co-workers had an issue, while remoted into his desktop, with a window popping up on his secondary monitor. Luckily, I’ve used 2 – 4 monitors a long time and I’ve run into that same issue before. The solution?

1. Press Alt+Space
2. Press M
3. Push and hold the relevant arrow key until you see the window you want

So…after telling him how to solve that issue, I thought I’d post some other tips/tricks that I use quite a bit. Here’s another one:

Ever copy over your clipboard in Visual Studio and think, “Dang! Now I have to go copy that again”…or worse you cut it…then you get to Ctrl Z and then re-copy…HUGE pain. Well luckily for us, Visual Studio remembers your clipboard and you can take advantage of it by using Ctrl+Shift+V to cycle through your previous copies. This has saved me MANY times. NOT that you should copy and paste code...as a general rule...this is not a good thing :)

Ever have to minimize all your open windows to get to your desktop? My solution to this problem was to create a group of toolbars to categorize my apps. I leave the toolbar locked, never hidden, and always on top. When I first started using this method back in 2002, my boss at a startup called Icabob (now closed), hated it because I had the auto-hide enabled so everytime he’d try to go to the file menu, my toolbar would open. I was used to it so I didn’t have the same problem :)

Another nice thing about this is that I typically have all the same software installed on all my different machines, so I can copy and paste my root “toolbars” folder on all the machines and the shortcuts still work. Keep in mind, you only would add apps that you use quite a bit. So I don’t put my entire “All Programs” section in the toolbar. Anyhow, here’s my current toolbar setup, which is docked on the top of my screen:

image

Yes that is a GroupWise icon you see up there…so all you Outlook 2010 people (my pic is already on this page) complaining should remember there are worse things. However, we are going through an Exchange migration right now, so I’ll be joining in on the complaints soon enough I’m sure :)

Here are a couple shortcuts that I don’t see used often, but are handy:

Ctrl + Shift + Esc – Opens Task Manager

Win + Pause Break – Opens Computer Properties

Here’s a couple shortcuts specifically for VS IDE that I use a lot:

Ctrl + K + C – Comment Selected Code

Ctrl + K + U – Uncomment Selected Code

For more VS tips, check out Sara Ford’s book Visual Studio Tips 251 Ways to Improve Your Productivity

Anyhow, I thought I’d share some of the things I use daily that I’ve never seen used. I also want to post my favorite jQuery plugins, favorite Firefox add-ons, and VS plugins. I’m not sure if anyone is interested or not, but if you are, let me know!

Thanks for reading!

kick it on DotNetKicks.com

Tuesday, February 02, 2010

Take Control of Your Web.Config




After reading a Paul Sheriff article in CODE Magazine, I ended up creating a base WebConfig class to handle getting values out of my web.config. I’ve hated the ConfigurationManager.AppSettings since they deprecated it from ConfigurationSettings.AppSettings. So now I have my own GetAppSetting so I never have to worry about it again. 

My base class looks like this:

public class BaseWebConfig
{
protected static string GetAppSetting(string appSettingName)
{
if (ConfigurationManager.AppSettings[appSettingName] == null)
throw new NullReferenceException(appSettingName
+
" AppSettings value cannot be null or empty in the web.config.");

return ConfigurationManager.AppSettings[appSettingName];
}

protected static bool GetBoolAppSetting(string appSettingName)
{
return Convert.ToBoolean(GetAppSetting(appSettingName));
}

protected static string[] GetStringArraySetting(string appSettingName)
{
var values = GetAppSetting(appSettingName).Split(new[] { ',' });
return values;
}

protected static int GetIntAppSetting(string appSettingName)
{
int i;
if (!int.TryParse(GetAppSetting(appSettingName), out i))
throw new InvalidCastException(appSettingName
+
" AppSettings value is an invalid integer.");

return i;
}

protected static DateTime GetDateTimeAppSetting(string appSettingName)
{
DateTime dt;
if (!DateTime.TryParse(GetAppSetting(appSettingName), out dt))
throw new InvalidCastException(appSettingName
+
" AppSettings value is an invalid DateTime.");

return dt;
}

protected static string GetConnectionString(string connectionStringName)
{
if (ConfigurationManager.ConnectionStrings[connectionStringName] == null)
throw new NullReferenceException(connectionStringName
+
" ConnectionStrings value cannot be null in the web.config.");

if (String.IsNullOrEmpty(ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString))
throw new NullReferenceException(connectionStringName
+
" ConnectionStrings value cannot be null or empty in the web.config.");

return ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString;
}
}

Here’s the breakdown:



  • GetAppSetting – Gets a string value

  • GetBoolAppSetting – Gets a bool value

  • GetStringArraySetting – Gets a string[] value

  • GetIntAppSetting – Gets an int value

  • GetDateTimeAppSetting – Gets a DateTime value

  • GetConnectionString – Gets a connection string value

Pretty simple stuff here…well I think it’s self-explanatory. Note they’re all protected so the inheriting class can access them, but nothing else. The reason I do this is because I never want a magic string passed in and risk getting a run-time error with a simple typo.


So with this base class, I inherit it in another WebConfig class in my actual project. Here’s an example of one:

public class WebConfig : BaseWebConfig
{
public static string ReturnEmail
{
get { return GetAppSetting("ReturnEmail"); }
}

public static bool IsTestEnvironment
{
get { return GetBoolAppSetting("IsTestEnvironment"); }
}

public static DateTime ShutOffDate
{
get { return GetDateTimeAppSetting("ShutOffDate"); }
}

public static string DbConnectionString
{
get { return GetConnectionString("DbConnectionString"); }
}
}

You can see above, I can reference my web.config all day long and never worry about mistyping something. If I need to rename something, I can easily do that as well. If you’re a reader of my blog, you know I’m a huge fan of being strongly-typed. I love for intellisense to help me out :)


I really like the simplicity of this method because it’s easy for beginner team members to use. That’s all I got…let me know if you have comments.


Thanks for reading!


Shout it

kick it on DotNetKicks.com

Related Posts Plugin for WordPress, Blogger...