changeset 179:1deccd6c3cb2

Aplicando seguridad x roles en sitio web
author nelopauselli
date Mon, 08 Aug 2011 15:24:26 -0300
parents 33e57fd1a6c9
children 222362c29416
files Agendas/trunk/src/Agendas.Domain/IdentityContext.cs Agendas/trunk/src/Agendas.Factories/Agendas.Factories.csproj Agendas/trunk/src/Agendas.Factories/AttributeFactory.cs Agendas/trunk/src/Agendas.Factories/NHibernateFactory.cs Agendas/trunk/src/Agendas.NHibernate/Agendas.NHibernate.csproj Agendas/trunk/src/Agendas.NHibernate/SessionScope.cs Agendas/trunk/src/Agendas.Tests/Agendas.Tests.csproj Agendas/trunk/src/Agendas.Tests/IdentityContextTests.cs Agendas/trunk/src/Agendas.Web.Tests/Agendas.Web.Tests.csproj Agendas/trunk/src/Agendas.Web.Tests/AutorizationsTests.cs Agendas/trunk/src/Agendas.Web.Tests/Properties/AssemblyInfo.cs Agendas/trunk/src/Agendas.Web/Agendas.Web.csproj Agendas/trunk/src/Agendas.Web/Controllers/AccountController.cs Agendas/trunk/src/Agendas.Web/Controllers/CustomAuthorizeAttribute.cs Agendas/trunk/src/Agendas.Web/Controllers/ErrorController.cs Agendas/trunk/src/Agendas.Web/Controllers/EventoController.cs Agendas/trunk/src/Agendas.Web/Controllers/PerfilController.cs Agendas/trunk/src/Agendas.Web/Controllers/PersonaController.cs Agendas/trunk/src/Agendas.Web/Global.asax.cs Agendas/trunk/src/Agendas.Web/Models/PerfilModel.cs Agendas/trunk/src/Agendas.Web/Views/Perfil/Index.cshtml Agendas/trunk/src/Agendas.Web/Views/Shared/SinPermisos.cshtml Agendas/trunk/src/Agendas.sln
diffstat 23 files changed, 495 insertions(+), 48 deletions(-) [+]
line wrap: on
line diff
--- a/Agendas/trunk/src/Agendas.Domain/IdentityContext.cs	Mon Aug 08 12:30:37 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Domain/IdentityContext.cs	Mon Aug 08 15:24:26 2011 -0300
@@ -1,4 +1,6 @@
 using System;
+using System.Collections.Generic;
+using System.Linq;
 using AltNetHispano.Agendas.Domain.Exceptions;
 using AltNetHispano.Agendas.Domain.Repositories;
 
@@ -46,5 +48,17 @@
 			var cuenta = _personaRepository.GetCuenta(identification.IdentityProvider, identification.LogonName);
 			return cuenta != null ? cuenta.Persona : null;
 		}
+
+		public static bool IsInRole(IEnumerable<string> roles)
+		{
+			var persona = GetUsuario();
+			return IsInRole(persona, roles);
+		}
+
+		public static bool IsInRole(Persona persona, IEnumerable<string> roles)
+		{
+			if (persona == null) return false;
+			return roles.Any(role => persona.Roles.Contains(role));
+		}
 	}
 }
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.Factories/Agendas.Factories.csproj	Mon Aug 08 12:30:37 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Factories/Agendas.Factories.csproj	Mon Aug 08 15:24:26 2011 -0300
@@ -45,7 +45,7 @@
   </ItemGroup>
   <ItemGroup>
     <Compile Include="AgendaFactory.cs" />
-    <Compile Include="AttributeFactory.cs" />
+    <Compile Include="NHibernateFactory.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
   </ItemGroup>
   <ItemGroup>
--- a/Agendas/trunk/src/Agendas.Factories/AttributeFactory.cs	Mon Aug 08 12:30:37 2011 -0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-using System.Web.Mvc;
-using Agendas.NHibernate;
-
-namespace AltNetHispano.Agendas.Factories
-{
-	public class AttributeFactory
-	{
-		public static ActionFilterAttribute GetNHibernateSessionPerAction()
-		{
-			return new NHibernateSessionPerActionAttribute(NhHelper.GetSessionFactory());
-		}
-	}
-}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Factories/NHibernateFactory.cs	Mon Aug 08 15:24:26 2011 -0300
@@ -0,0 +1,19 @@
+using System;
+using System.Web.Mvc;
+using Agendas.NHibernate;
+
+namespace AltNetHispano.Agendas.Factories
+{
+	public static class NHibernateFactory
+	{
+		public static ActionFilterAttribute GetNHibernateSessionPerAction()
+		{
+			return new NHibernateSessionPerActionAttribute(NhHelper.GetSessionFactory());
+		}
+
+		public static IDisposable GetSessionScope()
+		{
+			return new SessionScope(NhHelper.GetSessionFactory());
+		}
+	}
+}
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.NHibernate/Agendas.NHibernate.csproj	Mon Aug 08 12:30:37 2011 -0300
+++ b/Agendas/trunk/src/Agendas.NHibernate/Agendas.NHibernate.csproj	Mon Aug 08 15:24:26 2011 -0300
@@ -58,6 +58,7 @@
     <Compile Include="NhHelper.cs" />
     <Compile Include="NHibernateSessionPerActionAttribute.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="SessionScope.cs" />
   </ItemGroup>
   <ItemGroup>
     <None Include="packages.config" />
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.NHibernate/SessionScope.cs	Mon Aug 08 15:24:26 2011 -0300
@@ -0,0 +1,27 @@
+using System;
+using NHibernate;
+using NHibernate.Context;
+
+namespace Agendas.NHibernate
+{
+	public class SessionScope : IDisposable
+	{
+		private readonly ISessionFactory _sessionFactory;
+
+		public SessionScope(ISessionFactory sessionFactory)
+		{
+			_sessionFactory = sessionFactory;
+
+			var session = _sessionFactory.OpenSession();
+			CurrentSessionContext.Bind(session);
+		}
+
+		public void Dispose()
+		{
+			var session = _sessionFactory.GetCurrentSession();
+
+			session.Flush();
+			session.Close();
+		}
+	}
+}
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.Tests/Agendas.Tests.csproj	Mon Aug 08 12:30:37 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Tests/Agendas.Tests.csproj	Mon Aug 08 15:24:26 2011 -0300
@@ -87,6 +87,7 @@
     <Compile Include="DateTimeFormattingTests.cs" />
     <Compile Include="EventoStateTests.cs" />
     <Compile Include="Eventos_y_patrocinadores_tests.cs" />
+    <Compile Include="IdentityContextTests.cs" />
     <Compile Include="PersonaServiceTests.cs" />
     <Compile Include="PonentesTests.cs" />
     <Compile Include="PropuestasTests.cs" />
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Tests/IdentityContextTests.cs	Mon Aug 08 15:24:26 2011 -0300
@@ -0,0 +1,19 @@
+using AltNetHispano.Agendas.Domain;
+using NUnit.Framework;
+
+namespace AltNetHispano.Agendas.Tests
+{
+	[TestFixture]
+	public class IdentityContextTests : TestBase
+	{
+		[Test]
+		public void IsInRole()
+		{
+			var persona = new Persona("Nelo");
+			persona.Roles.Add(Roles.Usuario);
+
+			Assert.IsTrue(IdentityContext.IsInRole(persona, new[] { Roles.Usuario }));
+			Assert.IsFalse(IdentityContext.IsInRole(persona, new[] { Roles.Administrador }));
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Web.Tests/Agendas.Web.Tests.csproj	Mon Aug 08 15:24:26 2011 -0300
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{10FECBBD-F07F-4721-87DA-D3184CF86C90}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Agendas.Web.Tests</RootNamespace>
+    <AssemblyName>Agendas.Web.Tests</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="nunit.framework">
+      <HintPath>..\packages\NUnit.2.5.10.11092\lib\nunit.framework.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="AutorizationsTests.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Agendas.Domain\Agendas.Domain.csproj">
+      <Project>{A14907DF-02E4-4FA7-BE27-4292AF50AA22}</Project>
+      <Name>Agendas.Domain</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\Agendas.Web\Agendas.Web.csproj">
+      <Project>{319A8E3D-C61E-455F-A1BF-A6B1B1636BAB}</Project>
+      <Name>Agendas.Web</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Web.Tests/AutorizationsTests.cs	Mon Aug 08 15:24:26 2011 -0300
@@ -0,0 +1,141 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Web.Mvc;
+using AltNetHispano.Agendas.Domain;
+using AltNetHispano.Agendas.Web.Controllers;
+using NUnit.Framework;
+
+namespace Agendas.Web.Tests
+{
+	[TestFixture]
+	public class Autorizaciones
+	{
+		private IEnumerable<MethodInfo> _methods;
+
+		[TestFixtureSetUp]
+		public void ReadMethods()
+		{
+			var types = typeof (HomeController).Assembly.GetTypes().ToList();
+			var controllers = types.Where(t => typeof (Controller).IsAssignableFrom(t)).ToList();
+
+			var methods = new List<MethodInfo>();
+			foreach (var controller in controllers)
+			{
+				var temp =
+					controller.GetMethods(BindingFlags.Public | BindingFlags.Instance | ~BindingFlags.FlattenHierarchy).Where(
+						m => typeof (ActionResult).IsAssignableFrom(m.ReturnType));
+				
+				methods.AddRange(temp);
+			}
+
+			_methods = methods;
+		}
+
+		[Test]
+		public void Acciones_publicas()
+		{
+			var acciones = new[]
+			               	{
+			               		"HomeController.Index", "HomeController.About", "EventoController.Index", "AccountController.LogOn",
+			               		"AccountController.LogOff", "AccountController.TwitterLogOn", "HistoricoController.Index",
+			               		"PersonaController.Index", "ErrorController.NoAutorizado"
+			               	};
+
+			#region Asserts
+
+			bool fail = false;
+			foreach (var method in _methods)
+			{
+				var action = method.DeclaringType.Name + "." + method.Name;
+				if (acciones.Contains(action))
+				{
+					if (method.GetCustomAttributes(typeof (CustomAuthorizeAttribute), false).Any())
+					{
+						fail = true;
+						Console.WriteLine(action + " debe ser público");
+					}
+				}
+				else
+				{
+					if (!method.GetCustomAttributes(typeof (CustomAuthorizeAttribute), false).Any())
+					{
+						fail = true;
+						Console.WriteLine(action + " debe ser seguro");
+					}
+				}
+			}
+
+			Assert.IsFalse(fail);
+
+			#endregion
+		}
+
+		[Test]
+		public void Acciones_privadas()
+		{
+			var acciones = new[]
+			               	{
+			               		"PerfilController.Index", "PerfilController.AddGoogleAccount", "PerfilController.AddTwitterAccount",
+			               		"PerfilController.Remove", "PerfilController.Modificar"
+			               	};
+
+			VerficarAccionesSeguras(acciones, Roles.Usuario, "debe ser privado");
+		}
+
+		[Test]
+		public void Acciones_del_administrador()
+		{
+			var acciones = new[]
+			               	{
+			               		"EventoController.Agendar", "EventoController.Confirmar", "EventoController.Nuevo",
+			               		"EventoController.Publicar", "EventoController.Modificar", "EventoController.Proponer",
+			               		"EventoController.Cancelar", "EventoController.Descartar", "EventoController.ReAgendar",
+			               		"EventoController.ReProponer", "PersonaController.Nueva", "PersonaController.Modificar"
+			               	};
+
+			VerficarAccionesSeguras(acciones, Roles.Administrador, "debe ser de uso exclusivo de los administradores");
+		}
+
+		private void VerficarAccionesSeguras(IEnumerable<string> acciones, string rol, string mensaje)
+		{
+			bool fail = false;
+			foreach (var method in _methods)
+			{
+				var action = method.DeclaringType.Name + "." + method.Name;
+				if (acciones.Contains(action))
+				{
+					if (method.GetCustomAttributes(typeof (CustomAuthorizeAttribute), false).Any())
+					{
+						var found =
+							method.GetCustomAttributesData().Any(d => d.NamedArguments.Any(a => rol.Equals(a.TypedValue.Value)));
+
+						if (!found)
+						{
+							fail = true;
+							Console.WriteLine(action + " " + mensaje);
+						}
+					}
+					else
+					{
+						fail = true;
+						Console.WriteLine(action + " debe ser seguro");
+					}
+				}
+				else if (method.GetCustomAttributes(typeof (CustomAuthorizeAttribute), false).Any())
+				{
+					var found =
+						method.GetCustomAttributesData().Any(d => d.NamedArguments.Any(a => rol.Equals(a.TypedValue.Value)));
+
+					if (found)
+					{
+						fail = true;
+						Console.WriteLine(action + " no " + mensaje);
+					}
+				}
+			}
+			Assert.IsFalse(fail);
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Web.Tests/Properties/AssemblyInfo.cs	Mon Aug 08 15:24:26 2011 -0300
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Agendas.Web.Tests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("Agendas.Web.Tests")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2011")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("8464a0e5-fb7f-4b26-a0cd-5f86655f13f1")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
--- a/Agendas/trunk/src/Agendas.Web/Agendas.Web.csproj	Mon Aug 08 12:30:37 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Agendas.Web.csproj	Mon Aug 08 15:24:26 2011 -0300
@@ -62,6 +62,8 @@
   <ItemGroup>
     <Compile Include="Controllers\AccountController.cs" />
     <Compile Include="Controllers\ControllerMessageExtensions.cs" />
+    <Compile Include="Controllers\CustomAuthorizeAttribute.cs" />
+    <Compile Include="Controllers\ErrorController.cs" />
     <Compile Include="Controllers\EventoController.cs" />
     <Compile Include="Controllers\HistoricoController.cs" />
     <Compile Include="Controllers\HomeController.cs" />
@@ -228,6 +230,9 @@
   <ItemGroup>
     <Content Include="Views\Shared\EditorTemplates\Url.cshtml" />
   </ItemGroup>
+  <ItemGroup>
+    <Content Include="Views\Shared\SinPermisos.cshtml" />
+  </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
--- a/Agendas/trunk/src/Agendas.Web/Controllers/AccountController.cs	Mon Aug 08 12:30:37 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Controllers/AccountController.cs	Mon Aug 08 15:24:26 2011 -0300
@@ -1,24 +1,21 @@
 using System.Web.Mvc;
 using System.Web.Routing;
-using System.Web.Security;
 using AltNetHispano.Agendas.Domain;
 using AltNetHispano.Agendas.Factories;
 using AltNetHispano.Agendas.Twitter;
-using AltNetHispano.Agendas.Web.Models;
 using AltNetHispano.Agendas.Web.Services;
 
 namespace AltNetHispano.Agendas.Web.Controllers
 {
     public class AccountController : Controller
     {
-
-        public IFormsAuthenticationService FormsService { get; set; }
+    	private IFormsAuthenticationService _formsService;
 
         protected override void Initialize(RequestContext requestContext)
         {
-            if (FormsService == null) { FormsService = new FormsAuthenticationService(); }
-
-            base.Initialize(requestContext);
+            if (_formsService == null) { _formsService = new FormsAuthenticationService(); }
+            
+			base.Initialize(requestContext);
         }
 
         public ActionResult LogOn()
@@ -60,7 +57,7 @@
 				var personaService = AgendaFactory.GetPersonaService();
 				personaService.CreateIfNotExist(IdentityProviderEnum.Twitter, username, nombre);
 
-				FormsService.SignIn(Identification.Map[(int)IdentityProviderEnum.Twitter]+username, false);
+				_formsService.SignIn(Identification.Map[(int)IdentityProviderEnum.Twitter]+username, false);
 				return RedirectToAction("Index", "Home");
 			}
 
@@ -71,7 +68,7 @@
 
         public ActionResult LogOff()
         {
-            FormsService.SignOut();
+            _formsService.SignOut();
             return RedirectToAction("Index", "Home");
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Web/Controllers/CustomAuthorizeAttribute.cs	Mon Aug 08 15:24:26 2011 -0300
@@ -0,0 +1,47 @@
+using System.Net;
+using System.Web;
+using System.Web.Mvc;
+using AltNetHispano.Agendas.Domain;
+using AltNetHispano.Agendas.Factories;
+
+namespace AltNetHispano.Agendas.Web.Controllers
+{
+	public class CustomAuthorizeAttribute : AuthorizeAttribute
+	{
+		public string RedirectResultUrl { get; set; }
+
+		public CustomAuthorizeAttribute()
+		{
+			RedirectResultUrl = "~/Error/NoAutorizado";
+		}
+
+		protected override bool AuthorizeCore(HttpContextBase httpContext)
+		{
+			if (!httpContext.User.Identity.IsAuthenticated || !IdentityContext.IsAuthenticated())
+				return false;
+
+			if (!string.IsNullOrWhiteSpace(Roles))
+			{
+				using (NHibernateFactory.GetSessionScope())
+				{
+					var roles = Roles.Split(',');
+					if (!IdentityContext.IsInRole(roles))
+					{
+						httpContext.Response.StatusCode = 403;
+						return false;
+					}
+				}
+			}
+
+			return true;
+		}
+
+		protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
+		{
+			if (filterContext.HttpContext.Response.StatusCode == 403)
+				filterContext.Result = new RedirectResult(RedirectResultUrl);
+			else
+				base.HandleUnauthorizedRequest(filterContext);
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Web/Controllers/ErrorController.cs	Mon Aug 08 15:24:26 2011 -0300
@@ -0,0 +1,12 @@
+using System.Web.Mvc;
+
+namespace AltNetHispano.Agendas.Web.Controllers
+{
+	public class ErrorController : Controller
+	{
+		public ActionResult NoAutorizado()
+		{
+			return View("SinPermisos");
+		}
+	}
+}
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.Web/Controllers/EventoController.cs	Mon Aug 08 12:30:37 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Controllers/EventoController.cs	Mon Aug 08 15:24:26 2011 -0300
@@ -36,7 +36,7 @@
 			return View(model);
 		}
 
-		[Authorize]
+		[CustomAuthorize(Roles = Roles.Administrador)]
 		public ActionResult Nuevo()
 		{
 		    var model = new EventoNewModel {Fecha = DateTime.Now};
@@ -44,7 +44,7 @@
 		}
 
 		[HttpPost]
-		[Authorize]
+		[CustomAuthorize(Roles = Roles.Administrador)]
 		public ActionResult Nuevo(EventoNewModel model)
 		{
 			if (ModelState.IsValid)
@@ -63,7 +63,7 @@
             return View("Defaulteditor", model);
 		}
 
-		[Authorize]
+		[CustomAuthorize(Roles = Roles.Administrador)]
 		public ActionResult Confirmar(string id)
 		{
 			var agenda = AgendaFactory.GetAgenda();
@@ -77,7 +77,7 @@
 			return RedirectToAction("Index");
 		}
 
-    	[Authorize]
+		[CustomAuthorize(Roles = Roles.Administrador)]
 		public ActionResult Publicar(string id)
 		{
 			var agenda = AgendaFactory.GetAgenda();
@@ -95,7 +95,7 @@
 		}
 
 		[HttpPost]
-		[Authorize]
+		[CustomAuthorize(Roles = Roles.Administrador)]
 		public ActionResult Publicar(EventoPublicarModel model)
 		{
 			if (ModelState.IsValid)
@@ -113,7 +113,7 @@
 			return View("Defaulteditor", model);
 		}
 
-		[Authorize]
+		[CustomAuthorize(Roles = Roles.Administrador)]
 		public ActionResult Modificar(string id)
 		{
 			var agenda = AgendaFactory.GetAgenda();
@@ -131,7 +131,7 @@
 		}
 		
 		[HttpPost]
-		[Authorize]
+		[CustomAuthorize(Roles = Roles.Administrador)]
 		public ActionResult Modificar(EventoEditModel model)
 		{
 			if (ModelState.IsValid)
@@ -149,7 +149,7 @@
             return View("Defaulteditor", model);
 		}
 
-		[Authorize]
+		[CustomAuthorize(Roles = Roles.Administrador)]
 		public ActionResult Agendar(string id)
 		{
 			var agenda = AgendaFactory.GetAgenda();
@@ -167,7 +167,7 @@
 		}
 
 		[HttpPost]
-		[Authorize]
+		[CustomAuthorize(Roles = Roles.Administrador)]
 		public ActionResult Agendar(EventoAgendarModel model)
 		{
 			if (ModelState.IsValid)
@@ -185,7 +185,7 @@
             return View("Defaulteditor", model);
 		}
 
-		[Authorize]
+		[CustomAuthorize(Roles = Roles.Administrador)]
 		public ActionResult Proponer()
 		{
 			throw new NotImplementedException();
@@ -194,7 +194,7 @@
 		}
 
 		[HttpPost]
-		[Authorize]
+		[CustomAuthorize(Roles = Roles.Administrador)]
 		public ActionResult Proponer(PropuestaNewModel model)
 		{
 			throw new NotImplementedException();
@@ -212,8 +212,8 @@
 			}
             return View("Defaulteditor", model);
 		}
-        
-        [Authorize]
+
+		[CustomAuthorize(Roles = Roles.Administrador)]
 	    public ActionResult Cancelar(string id)
 	    {
             var agenda = AgendaFactory.GetAgenda();
@@ -223,7 +223,7 @@
             return RedirectToAction("Index");
 	    }
 
-        [Authorize]
+		[CustomAuthorize(Roles = Roles.Administrador)]
 	    public ActionResult Descartar(string id)
 	    {
             var agenda = AgendaFactory.GetAgenda();
@@ -233,7 +233,7 @@
             return RedirectToAction("Index");
 	    }
 
-        [Authorize]
+		[CustomAuthorize(Roles = Roles.Administrador)]
 	    public ActionResult ReAgendar(string id)
 	    {
             var agenda = AgendaFactory.GetAgenda();
@@ -243,7 +243,7 @@
             return RedirectToAction("Index");
 	    }
 
-        [Authorize]
+		[CustomAuthorize(Roles = Roles.Administrador)]
 	    public ActionResult ReProponer(string id)
 	    {
             var agenda = AgendaFactory.GetAgenda();
--- a/Agendas/trunk/src/Agendas.Web/Controllers/PerfilController.cs	Mon Aug 08 12:30:37 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Controllers/PerfilController.cs	Mon Aug 08 15:24:26 2011 -0300
@@ -10,7 +10,8 @@
 {
     public class PerfilController : Controller
     {
-        public ActionResult Index()
+		[CustomAuthorize(Roles = Roles.Usuario)]
+		public ActionResult Index()
         {
         	var persona = IdentityContext.GetUsuario();
 
@@ -35,12 +36,14 @@
         	return View(model);
         }
 
-        public ActionResult AddGoogleAccount()
+		[CustomAuthorize(Roles = Roles.Usuario)]
+		public ActionResult AddGoogleAccount()
         {
             throw new NotImplementedException();
         }
 
-        public ActionResult AddTwitterAccount()
+		[CustomAuthorize(Roles = Roles.Usuario)]
+		public ActionResult AddTwitterAccount()
 		{
 			var oAuth = new OAuthTwitter();
 
@@ -66,6 +69,7 @@
 			return RedirectToAction("Index");
 		}
 
+		[CustomAuthorize(Roles = Roles.Usuario)]
 		public ActionResult Remove(string identityProvider, string username)
 		{
 			var personaService = AgendaFactory.GetPersonaService();
@@ -81,5 +85,47 @@
 
 			return RedirectToAction("Index");
 		}
-    }
+
+		[CustomAuthorize(Roles = Roles.Usuario)]
+		public ActionResult Modificar()
+		{
+			var persona = IdentityContext.GetUsuario();
+			if (persona == null)
+			{
+				this.AddError("No se encontró la persona que intenta modificar");
+				return RedirectToAction("Index");
+			}
+
+			var model = new PerfilEditModel
+			{
+				Nombre = persona.Nombre,
+				Twitter = persona.Twitter,
+				EMail = persona.Mail,
+				Blog = persona.Blog
+			};
+
+			return View("Defaulteditor", model);
+		}
+
+		[HttpPost]
+		[CustomAuthorize(Roles = Roles.Usuario)]
+		public ActionResult Modificar(PerfilEditModel model)
+		{
+			if (ModelState.IsValid)
+			{
+				var persona = IdentityContext.GetUsuario();
+
+				var personas = AgendaFactory.GetPersonaService();
+				var r = personas.Update(persona.Id, model.Nombre, model.Twitter, model.EMail, model.Blog);
+				if (r.Succeful)
+				{
+					this.AddNotification("Los datos fueron guardados");
+					return RedirectToAction("Index");
+				}
+				this.AddError(r.Message);
+			}
+
+			return View("Defaulteditor", model);
+		}
+	}
 }
--- a/Agendas/trunk/src/Agendas.Web/Controllers/PersonaController.cs	Mon Aug 08 12:30:37 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Controllers/PersonaController.cs	Mon Aug 08 15:24:26 2011 -0300
@@ -1,6 +1,7 @@
 using System;
 using System.Linq;
 using System.Web.Mvc;
+using AltNetHispano.Agendas.Domain;
 using AltNetHispano.Agendas.Factories;
 using AltNetHispano.Agendas.Web.Models;
 
@@ -17,13 +18,15 @@
             return View(model);
         }
 
-        public ActionResult Nueva()
+		[CustomAuthorize(Roles = Roles.Administrador)]
+		public ActionResult Nueva()
         {
             var model = new PersonaNewModel();
             return View("Defaulteditor", model);
         }
 
         [HttpPost]
+		[CustomAuthorize(Roles = Roles.Administrador)]
         public ActionResult Nueva(PersonaNewModel model)
         {
             if (ModelState.IsValid)
@@ -41,7 +44,8 @@
             return View("Defaulteditor", model);
         }
 
-        public ActionResult Modificar(string id)
+		[CustomAuthorize(Roles = Roles.Administrador)]
+		public ActionResult Modificar(string id)
         {
             var personas = AgendaFactory.GetPersonaService();
 
@@ -65,7 +69,8 @@
         }
 
         [HttpPost]
-        public ActionResult Modificar(PersonaEditModel model)
+		[CustomAuthorize(Roles = Roles.Administrador)]
+		public ActionResult Modificar(PersonaEditModel model)
         {
             if (ModelState.IsValid)
             {
--- a/Agendas/trunk/src/Agendas.Web/Global.asax.cs	Mon Aug 08 12:30:37 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Global.asax.cs	Mon Aug 08 15:24:26 2011 -0300
@@ -15,7 +15,7 @@
     	private static void RegisterGlobalFilters(GlobalFilterCollection filters)
         {
             filters.Add(new HandleErrorAttribute());
-			filters.Add(AttributeFactory.GetNHibernateSessionPerAction());
+			filters.Add(NHibernateFactory.GetNHibernateSessionPerAction());
         }
 
     	private static void RegisterRoutes(RouteCollection routes)
--- a/Agendas/trunk/src/Agendas.Web/Models/PerfilModel.cs	Mon Aug 08 12:30:37 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Models/PerfilModel.cs	Mon Aug 08 15:24:26 2011 -0300
@@ -24,6 +24,21 @@
 		public IEnumerable<CuentaDto> Cuentas { get; set; }
 	}
 
+	public class PerfilEditModel
+	{
+		[Required]
+		public string Nombre { get; set; }
+
+		[Required]
+		public string Twitter { get; set; }
+
+		[Required]
+		public string EMail { get; set; }
+
+		[DataType(DataType.Url)]
+		public string Blog { get; set; }
+	}
+
 	public class CuentaDto
 	{
 		public string IdentityProvider { get; set; }
--- a/Agendas/trunk/src/Agendas.Web/Views/Perfil/Index.cshtml	Mon Aug 08 12:30:37 2011 -0300
+++ b/Agendas/trunk/src/Agendas.Web/Views/Perfil/Index.cshtml	Mon Aug 08 15:24:26 2011 -0300
@@ -33,6 +33,6 @@
 	<br/>
 	@Html.ActionLink("Asociar cuenta de Google", "AddGoogleAccount")
 	-->
-	@Html.ActionLink("Modificar datos", "Modificar", "Persona", new {id=Model.Id}, null)
+	@Html.ActionLink("Modificar datos", "Modificar")
 </div>
 <br/>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Agendas/trunk/src/Agendas.Web/Views/Shared/SinPermisos.cshtml	Mon Aug 08 15:24:26 2011 -0300
@@ -0,0 +1,1 @@
+<h2>Usted no tiene permisos para realizar la acción solicitada</h2>
\ No newline at end of file
--- a/Agendas/trunk/src/Agendas.sln	Mon Aug 08 12:30:37 2011 -0300
+++ b/Agendas/trunk/src/Agendas.sln	Mon Aug 08 15:24:26 2011 -0300
@@ -38,6 +38,8 @@
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Agendas.Configurations.Tests", "Agendas.Configurations.Tests\Agendas.Configurations.Tests.csproj", "{BBE36765-6AAB-4689-B2F3-6D18E3F11746}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Agendas.Web.Tests", "Agendas.Web.Tests\Agendas.Web.Tests.csproj", "{10FECBBD-F07F-4721-87DA-D3184CF86C90}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -104,6 +106,10 @@
 		{BBE36765-6AAB-4689-B2F3-6D18E3F11746}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{BBE36765-6AAB-4689-B2F3-6D18E3F11746}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{BBE36765-6AAB-4689-B2F3-6D18E3F11746}.Release|Any CPU.Build.0 = Release|Any CPU
+		{10FECBBD-F07F-4721-87DA-D3184CF86C90}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{10FECBBD-F07F-4721-87DA-D3184CF86C90}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{10FECBBD-F07F-4721-87DA-D3184CF86C90}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{10FECBBD-F07F-4721-87DA-D3184CF86C90}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE