Friday, July 16, 2010

Authenticating Against Multiple Domains with C# & StructureMap




In my place of work, we had a vendor come in and try to sell us a product that couldn’t authenticate to multiple domains. Well, we have multiple domains. Their suggestion was to consolidate into one…obviously we’re not using their product. So, in an effort to help out, I thought I’d share a method of authenticating to multiple domains.

As always, we start out with our interface…

  public interface IAuthenticationService
{
bool Validate(string username, string password);
string DefaultRedirectUrl { get; }
}

Pretty straightforward so far…I added in a DefaultRedirectUrl in case you want to route to different places depending on which domain you authenticated against.

Okay, let’s implement our interface…

    public class AuthenticationService : IAuthenticationService
{
private readonly IAuthenticationService[] _authenticators;
private string _redirecturl;

public AuthenticationService(IAuthenticationService[] authenticators)
{
_authenticators = authenticators;
}

public bool Validate(string username, string password)
{
var isValid = false;
foreach (var authenticator in _authenticators)
{
if (authenticator.Validate(username, password))
{
isValid =
true;
_redirecturl = authenticator.DefaultRedirectURL;
break;
}
}
return isValid;
}

public string DefaultRedirectUrl
{
get { return _redirecturl; }
}
}

Alrighty…so all this does is takes in an array of authentication services and then loops through them checking if they’re valid and if they are, sets isvalid to true, the redirect url, and returns.

Basically this is our master authentication service. Now, we just need one for each one of our domains. Since they’re both authenticating to AD, we’ll create a base class like this:

    public abstract class ActiveDirectoryAuthenticator : IAuthenticationService
{
private readonly ILDAP _ldap;

protected ActiveDirectoryAuthenticator(ILDAP ldap)
{
_ldap = ldap;
}

public bool Validate(string username, string password)
{
var authenticated = false;
try
{
var entry = new DirectoryEntry(_ldap.URL, username + "@" + _ldap.HostName, password);
object nativeObject = entry.NativeObject;
authenticated =
true;
}
catch (DirectoryServicesCOMException)
{
}
return authenticated;
}

public virtual string DefaultRedirectUrl
{
get { return "/"; }
}
}

So, my ILDAP interface is the same one I blogged about here. The DefaultRedirectUrl here is virtual and meant to be overridden, otherwise it’ll just redirect to the root. Okay so now we need to inherit this authenticator in our domain authentication service classes like this…

Domain #1

public class Domain1AuthenticationService : ActiveDirectoryAuthenticator
{
public Domain1AuthenticationService() : base(DependencyRegistrar.Resolve<ILDAP>(DependencyNames.Domain1LDAP))
{ }

public override string DefaultRedirectUrl
{
get
{
return "/domain1/default.aspx";
}
}
}

Domain #2

public class Domain2AuthenticationService : ActiveDirectoryAuthenticator
{
public Domain2AuthenticationService() : base(DependencyRegistrar.Resolve<ILDAP>(DependencyNames.Domain2LDAP))
{ }

public override string DefaultRedirectUrl
{
get
{
return "/domain2/default.aspx";
}
}
}

Pretty simple right? Basically we’re setting our RedirectUrl and calling our ILDAP from StructureMap. You can read more about how I implement StructureMap here. Now for the good ole StructureMap code that goes in the Registry…

ForRequestedType<ILDAP>()
.AddInstances(x =>
{
x.OfConcreteType<
LDAP>()
.WithName(
DependencyNames.Domain1LDAP)
.SetProperty(y => y.WithBaseDN(ou =>
"Users", dc => "dc1", dc => "domain", dc => "com")
.WithHost(
"dc1.domain.com"));

x.OfConcreteType<
LDAP>()
.WithName(
DependencyNames.Domain2LDAP)
.SetProperty(y => y.WithBaseDN(ou =>
"Users", dc => "dc2", dc => "domain", dc => "com")
.WithHost(
"dc2.domain.com"));
});

ForRequestedType<
IAuthenticationService>()
.TheDefault.Is.OfConcreteType<
AuthenticationService>()
.TheArrayOf<
IAuthenticationService>().Contains(x =>
{
x.OfConcreteType<
Domain1AuthenticationService>();
x.OfConcreteType<
Domain2AuthenticationService>();
});

So, how to use this in your code? Like this…

 var adService = DependencyRegistrar.Resolve<IAuthenticationService>();

if (adService.Validate(tbUsername.Text, tbPassword.Text))
{
FormsAuthentication.SetAuthCookie(tbUsername.Text, true /*persist cookie*/);

if (Request.QueryString["ReturnUrl"] == null)
Response.Redirect(adService.DefaultRedirectUrl);
else
Response.Redirect(Request.QueryString["ReturnUrl"]);
}
else
//Display Error

There it is…authenticating against multiple domains. Please let me know if you know of better ways or you see ways to improve. Thanks for reading!

Shout it

kick it on DotNetKicks.com

Wednesday, July 14, 2010

Slow Down Filter for Throttling Requests with ASP.NET MVC




I’ve been looking for a good filter to play with and finally found one today. Basically, I want to slow down requests to prevent people and/or other mechanisms from submitting a form.

I saw a post by the guy’s at stackoverflow.com and ended up using a couple of their ideas in my filter attribute. Stackoverflow’s stops the execution of a request and I only want to slow it down. Generally speaking, I want to deter people/things from attempting to submit multiple times in a row after a specified amount of requests.

So…here’s the filter attribute:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class SlowDownAfterAttribute : ActionFilterAttribute
{
public const string AttemptsExceeded = "AttemptsExceeded";
private readonly int _numberOfAttemptsAllowed;
public string Name { get; set; }

public SlowDownAfterAttribute(int numberOfAttemptsAllowed)
{
_numberOfAttemptsAllowed = numberOfAttemptsAllowed;
}

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.Controller.ViewData[AttemptsExceeded] =
false;

var key = string.Concat(Name, "-", filterContext.HttpContext.Request.UserHostAddress);
var numberofattempts = Convert.ToInt32(HttpRuntime.Cache[key]);
numberofattempts++;

HttpRuntime.Cache.Insert(key,
numberofattempts,
null,
DateTime.Now.AddMinutes(2),
Cache.NoSlidingExpiration,
CacheItemPriority.Low,
null);

if (numberofattempts <= _numberOfAttemptsAllowed)
return;

filterContext.Controller.ViewData[AttemptsExceeded] =
true;
System.Threading.
Thread.Sleep(numberofattempts * 1000);
}
}

Here’s how you could use it:

[HttpPost, ValidateModel(typeof(Form)), ValidateAntiForgeryToken, SlowDownAfter(5 /*attempts*/)]
public ActionResult Validate(Form form)
{
if (!ModelState.IsValid)
//Display Error

if ((bool)ViewData[SlowDownAfterAttribute.AttemptsExceeded])
//Display Message or something

return View(form);
}

If you want to use the SlowDownAfter() attribute on multiple methods, you’d want to name it like this:

SlowDownAfter(5 /*attempts*/, Name="ValidateForm")

So basically the way this thing works is like this:

  • Sets the AttemptsExceeded flag on the ViewData to false
  • Sets the key (I got the naming convention from the StackOverflow response on stackoverflow.com)
  • Gets the number of attempts from cache
  • Incremements by 1
  • Adds the value to cache with an absolute expiration of now + 2 minutes
  • Checks if number of attempts is less than or equal to the number of attempts allowed
  • If number of attempts allowed was exceeded, it writes the ViewData AttemptsExceeded flag to true and sleeps for the number of attempts in seconds

Let me know what you think. Thanks for reading!


Shout it

kick it on DotNetKicks.com

Related Posts Plugin for WordPress, Blogger...