Presentation downloads are (finally) up!
The PLINQO presentation will be up some time next week.
Enjoy!
Tom
Presentation downloads are (finally) up!
The PLINQO presentation will be up some time next week.
Enjoy!
Tom
OAuth 1.0 was one complicated beast. The OAuth 2.0 spec greatly simplified things, but that also had the wonderful side effect of rending all of our old OAuth 1.0 code obsolete. They say that "the only thing a pioneer gets is an arrow in the back," I disagree, I say "the thing that only a pioneer gets to have is an adventure."
For example, I got to help write this wonderful, cutting edge, open source, OAuth 2.0 implementation for MVC!
OAuth 2.0 Overview
OAuth is all about tokens. You start by getting a Request Token from the server, and then using that to secure your login information. When you have successfully logged in you will be given a role/permission specific Access Token, you will then submit this token with all of your future requests. You will also get a Refresh Token with your Access Token. Once your Access Token has expired, you can then submit your Refresh Token to get a new pair of Access and Request Tokens.
Two Legged vs Three Legged
A two legged implementation is rather straight forward, you log into the server you are trying to access. A three legged implementation allows you to gain access to a resource by authentication with a third party server. For the time being this project only supports two legged authentication.
Implementation
You must implement four classes to use this library:
The first three are very small classes, requiring only a few short lines of code. The Service is the work horse where most of your code will go, but even then it only requires the implementation of four methods.
public abstract class OAuthServiceBase : ProviderBase, IOAuthService
{
public static IOAuthService Instance { get; set; }
public abstract OAuthResponse RequestToken();
public abstract OAuthResponse AccessToken(string requestToken,
string grantType, string userName, string password, bool persistent);
public abstract OAuthResponse RefreshToken(string refreshToken);
public abstract bool UnauthorizeToken(string token);
}
Then of course you will need to update your Web.config:
<configuration>
<configSections>
<section name="oauth" type="OAuth2.Mvc.Configuration.OAuthSection, OAuth2.Mvc, Version=1.0.0.0, Culture=neutral"/>
</configSections>
<oauth defaultProvider="DemoProvider" defaultService="DemoService">
<providers>
<add name="DemoProvider" type="OAuth2.Demo.OAuth.DemoProvider, OAuth2.Demo" />
</providers>
<services>
<add name="DemoService" type="OAuth2.Demo.OAuth.DemoService, OAuth2.Demo" />
</services>
</oauth>
<system.web>
<httpModules>
<add name="OAuthAuthentication" type="OAuth2.Mvc.Module.OAuthAuthenticationModule, OAuth2.Mvc, Version=1.0.0.0, Culture=neutral"/>
</httpModules>
</system.web>
</configuration>
Securing Your Pages
That's the easy part, just add the MVC Authorize Attribute to any actions or controllers that you want to secure.
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[Authorize]
public ActionResult Secure()
{
return View();
}
}
The Demo API in Action
Additional Resources
Happy authenticating!
~ Tom
The CodeSmith Tools are hitting the road (and even the skies) to talk about .NET technology all around the US!
Want us to speak at your local user group? Just drop me a line!
We will post again each month with updates and additional details, so stay tuned!
Dates
Topics
Hope to see you soon!
~ Tom
As my Uncle Ben once said, "with great insomnia comes great responsibility." Or maybe that was Spiderman, I don't remember. All I know is that I couldn't go to sleep last night, and when I came to this morning there was a proof of concept PLINQO for NHibernate architecture on my screen.
I am not saying we are working on PLINQO for NHibernate...yet.
NHibernate is a well established ORM that is backed by a great community, and frankly, they have their own way of doing things. NHibernate is built on some great principals: patterns, testability, and openness. Also, things like Fluent NHibernate and Sharp Architecture are examples of some superb extensions to the base NHibernate framework, and they are perfectly tailored to fit NHibernate needs.
Originally we had thought that creating PLINQO templates for NHibernate would be going against the grain of the NHibernate community. The architecture of PLINQO, specifically it's query extension pattern, is a bit of an anti-pattern. Also PLINQO is based on LINQ to SQL, and not all of it's features are needed in the more mature NHibernate framework.
So if we were to make PLINQO for NHibernate, what value would it provide?
First and foremost, simplicity.
A major goal of PLINQO is to get the end user up and running as fast as possible. A major complaint of NHibernate is that it can be very complex to setup. It seems that simplifying the start up process would be a major advantage to new users.
This could provide a migration path to NHibernate.
Using LINQ to SQL or PLINQO and want to switch to NHibernate? Maybe you need more DB Providers, maybe you like open source components, or maybe you have converted to the church of Rhino; in any case, this would be a great way to make that transition quick and easy.
PLINQO for NHibernate means more PLINQO.
...and I LOVE PLINQO! I certainly don't think more PLINQO could hurt anyone, heck, I'm pretty sure that it will help someone! Also, on a personal note, I would get to code more PLINQO! If you can't tell from all the exclamation points, I find that prospect to be freak'n exciting!
What would PLINQO for NHibernate look like?
Remember back when you were in grade school and your teacher told you that there were no stupid questions? That was a stupid question.
Ideally the PLINQO NHibernate templates would generate you a matching data layer. You would swap out your templates, update your namespaces, and you're back in business.
[Test] public void ByQueries() { // This DataContext is powered by a NHibernate ISession using (var db = new PetshopDataContext()) { var x = db.Product .ByName(ContainmentOperator.NotEquals, "A") .ByDescn("B") .FirstOrDefault(); var y = db.Product .ByName(ContainmentOperator.StartsWith, "B") .ByDescn("B"); var z = y.ToList(); Assert.AreEqual(1, z.Count); Assert.AreEqual(x.Id, z[0].Id); } }
So by the way, that code snippet is real, and that test succeeds.
So, what else is new in MVC 3?
MVC 3 now has a GlobalFilterCollection that is automatically populated with a HandleErrorAttribute. This default FilterAttribute brings with it a new way of handling errors in your web applications. In short, you can now handle errors inside of the MVC pipeline.
What does that mean?
This gives you direct programmatic control over handling your 500 errors in the same way that ASP.NET and CustomErrors give you configurable control of handling your HTTP error codes.
How does that work out?
Think of it as a routing table specifically for your Exceptions, it's pretty sweet!
The new Global.asax file now has a RegisterGlobalFilters method that is used to add filters to the new GlobalFilterCollection, statically located at System.Web.Mvc.GlobalFilter.Filters. By default this method adds one filter, the HandleErrorAttribute.
public class MvcApplication : System.Web.HttpApplication { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); }
The HandleErrorAttribute is pretty simple in concept: MVC has already adjusted us to using Filter attributes for our AcceptVerbs and RequiresAuthorization, now we are going to use them for (as the name implies) error handling, and we are going to do so on a (also as the name implies) global scale.
The HandleErrorAttribute has properties for ExceptionType, View, and Master. The ExceptionType allows you to specify what exception that attribute should handle. The View allows you to specify which error view (page) you want it to redirect to. Last but not least, the Master allows you to control which master page (or as Razor refers to them, Layout) you want to render with, even if that means overriding the default layout specified in the view itself.
public class MvcApplication : System.Web.HttpApplication { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute { ExceptionType = typeof(DbException), // DbError.cshtml is a view in the Shared folder. View = "DbError", Order = 2 }); filters.Add(new HandleErrorAttribute()); }
All of your views still work like they did in the previous version of MVC (except of course that they can now use the Razor engine). However, a view that is used to render an error can not have a specified model! This is because they already have a model, and that is System.Web.Mvc.HandleErrorInfo
@model System.Web.Mvc.HandleErrorInfo @{ ViewBag.Title = "DbError"; } <h2>A Database Error Has Occurred</h2> @if (Model != null) { <p>@Model.Exception.GetType().Name<br /> thrown in @Model.ControllerName @Model.ActionName</p> }
The HandleErrorAttribute will only handle errors that happen inside of the MVC pipeline, better known as 500 errors. Errors outside of the MVC pipeline are still handled the way they have always been with ASP.NET. You turn on custom errors, specify error codes and paths to error pages, etc.
It is important to remember that these will happen for anything and everything outside of what the HandleErrorAttribute handles. Also, these will happen whenever an error is not handled with the HandleErrorAttribute from inside of the pipeline.
<system.web> <customErrors mode="On" defaultRedirect="~/error"> <error statusCode="404" redirect="~/error/notfound"></error> </customErrors>
public class ExampleController : Controller { public ActionResult Exception() { throw new ArgumentNullException(); } public ActionResult Db() { // Inherits from DbException throw new MyDbException(); } } public class ErrorController : Controller { public ActionResult Index() { return View(); } public ActionResult NotFound() { return View(); } }
If we have all the code above included in our MVC 3 project, here is how the following scenario's will play out:
But don't take my word for it, download the sample project and try it yourself.
For the most part this is all pretty straight forward, but there are a few gotcha's that you should remember to watch out for:
1) Error views have models, but they must be of type HandleErrorInfo.
It is confusing at first to think that you can't control the M in an MVC page, but it's for a good reason. Errors can come from any action in any controller, and no redirect is taking place, so the view engine is just going to render an error view with the only data it has: The HandleError Info model. Do not try to set the model on your error page or pass in a different object through a controller action, it will just blow up and cause a second exception after your first exception!
2) When the HandleErrorAttribute renders a page, it does not pass through a controller or an action.
The standard web.config CustomErrors literally redirect a failed request to a new page. The HandleErrorAttribute is just rendering a view, so it is not going to pass through a controller action. But that's ok! Remember, a controller's job is to get the model for a view, but an error already has a model ready to give to the view, thus there is no need to pass through a controller.
That being said, the normal ASP.NET custom errors still need to route through controllers. So if you want to share an error page between the HandleErrorAttribute and your web.config redirects, you will need to create a controller action and route for it. But then when you render that error view from your action, you can only use the HandlerErrorInfo model or ViewData dictionary to populate your page.
3) The HandleErrorAttribute obeys if CustomErrors are on or off, but does not use their redirects.
If you turn CustomErrors off in your web.config, the HandleErrorAttributes will stop handling errors. However, that is the only configuration these two mechanisms share. The HandleErrorAttribute will not use your defaultRedirect property, or any other errors registered with customer errors.
The HandleErrorAttribute is for displaying 500 errors that were caused by exceptions inside of the MVC pipeline. The custom errors are for redirecting from error pages caused by other HTTP codes.
Also, if you are going to be handling all these errors, why not report them too?