security asp.net-mvc-5 antiforgerytoken claims

security - MVC5 AntiForgeryToken Claims/"La secuencia contiene más de un elemento"



asp.net-mvc-5 (1)

Caso: Tengo una aplicación MVC5 (básicamente, la plantilla MVC5 con una vista de scaffolded) con el método de autenticación de Google habilitado. La aplicación se ha configurado para aceptar el correo electrónico como nombre de usuario y para almacenar las reclamaciones asignadas de Google como Apellido, Nombre de pila, Correo electrónico, Identificador de nombre, etc. en la base de datos de miembros (AspNetUserClaims).

Cuando me registro e inicio sesión con un usuario "local" todo está bien. Si me conecto con un usuario de Google está bien. Si inicio sesión con una cuenta configurada para tener un inicio de sesión tanto local como externo, aparece el siguiente error.

He intentado cambiar el tipo de token a diferentes configuraciones utilizando la opción AntiForgeryConfig en Application_Start (ejemplo)

AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Email;

Pero parece que todas las Reclamaciones están duplicadas cuando se combinan inicios de sesión locales y externos. Lo más extraño es que la colección de reclamaciones (que supuse que tenía la respuesta) es idéntica para el inicio de sesión combinado y el único externo.

Cuando se inicia sesión como usuario local estas reclamaciones se asignan

[0]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier: a71ff9c0-8dc4-478b-a6f1-2c4cc34b1e46} [1]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name: [email protected]} [2]: {http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider: ASP.NET Identity}

Cuando se inicia sesión con una cuenta remota o una combinada, la lista de reclamaciones se ve así:

[0]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier: 4ab33d77-c2a0-4eff-a759-5cca4323ecbf} [1]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name: [email protected]} [2]: {http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider: ASP.NET Identity} [3]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier: https://www.google.com/accounts/o8/id?id=AitOGoogleIdentifierRemovedForPrivacygwgwgw} [4]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress: [email protected]} [5]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname: Other} [6]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname: Some} [7]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name: Some Other Person}

¡Cualquier ayuda será muy apreciada!

Error y stacktrace sigue:

Server Error in ''/'' Application. Sequence contains more than one matching element Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. Exception Details: System.InvalidOperationException: Sequence contains more than one matching element

Source Error: Line 10: @using (Html.BeginForm()) Line 11: { Line 12: @Html.AntiForgeryToken() Line 13: Line 14: <div class="form-horizontal"> Source File: x:/someweb/Views/someEntity/Create.cshtml Line: 12

Stack Trace: [InvalidOperationException: Sequence contains more than one matching element] System.Linq.Enumerable.SingleOrDefault(IEnumerable`1 source, Func`2 predicate) +2533810 System.Web.Helpers.AntiXsrf.ClaimUidExtractor.GetUniqueIdentifierParameters(ClaimsIdentity claimsIdentity, String uniqueClaimTypeIdentifier) +701 System.Web.Helpers.AntiXsrf.ClaimUidExtractor.ExtractClaimUid(IIdentity identity) +186 System.Web.Helpers.AntiXsrf.TokenValidator.GenerateFormToken(HttpContextBase httpContext, IIdentity identity, AntiForgeryToken cookieToken) +242 System.Web.Helpers.AntiXsrf.AntiForgeryWorker.GetTokens(HttpContextBase httpContext, AntiForgeryToken oldCookieToken, AntiForgeryToken& newCookieToken, AntiForgeryToken& formToken) +174 System.Web.Helpers.AntiXsrf.AntiForgeryWorker.GetFormInputElement(HttpContextBase httpContext) +109 System.Web.Helpers.AntiForgery.GetHtml() +146 System.Web.Mvc.HtmlHelper.AntiForgeryToken() +39 ASP._Page_Views_Bruker_Create_cshtml.Execute() in x:/prosjekter/Laudi/TFS/Laudi/IWeb/Inspector/Inspector/Views/Bruker/Create.cshtml:12 System.Web.WebPages.WebPageBase.ExecutePageHierarchy() +271 System.Web.Mvc.WebViewPage.ExecutePageHierarchy() +120 System.Web.WebPages.StartPage.RunPage() +63 System.Web.WebPages.StartPage.ExecutePageHierarchy() +100 System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage) +131 System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance) +695 System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer) +382 System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context) +431 System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult) +39 System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult) +116 System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult) +529 System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList`1 filters, ActionResult actionResult) +106 System.Web.Mvc.Async.<>c__DisplayClass28.<begininvokeaction> b__19() +321 System.Web.Mvc.Async.<>c__DisplayClass1e.<begininvokeaction> b__1b(IAsyncResult asyncResult) +185 System.Web.Mvc.Async.WrappedAsyncResult`1.CallEndDelegate(IAsyncResult asyncResult) +42 System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +133 System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +56 System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult) +40 System.Web.Mvc.Controller.<beginexecutecore> b__1d(IAsyncResult asyncResult, ExecuteCoreState innerState) +34 System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +70 System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +139 System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +59 System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +40 System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +44 System.Web.Mvc.Controller.<beginexecute> b__15(IAsyncResult asyncResult, Controller controller) +39 System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +62 System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +139 System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +59 System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +40 System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +39 System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult) +39 System.Web.Mvc.MvcHandler.<beginprocessrequest> b__4(IAsyncResult asyncResult, ProcessRequestState innerState) +39 System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +70 System.Web.Mvc.Async.WrappedAsyncResultBase`1.End() +139 System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +59 System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +40 System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +40 System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +38 System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +9688704 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155


El comportamiento es normal, como puede ver en el siguiente método (llamado al crear la identidad del usuario):

await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie)

en el método SignInAsync . En la implementación de CreateIdentityAsync :

... ClaimsIdentity claimsIdentity = new ClaimsIdentity(authenticationType, this.UserNameClaimType, this.RoleClaimType); claimsIdentity.AddClaim(new Claim(this.UserIdClaimType, user.Id, "http://www.w3.org/2001/XMLSchema#string")); claimsIdentity.AddClaim(new Claim(this.UserNameClaimType, user.UserName, "http://www.w3.org/2001/XMLSchema#string")); claimsIdentity.AddClaim(new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", "ASP.NET Identity", "http://www.w3.org/2001/XMLSchema#string")); if (manager.SupportsUserRole) { foreach (string rolesAsync in await manager.GetRolesAsync(user.Id)) { claimsIdentity.AddClaim(new Claim(this.RoleClaimType, rolesAsync, "http://www.w3.org/2001/XMLSchema#string")); } } if (manager.SupportsUserClaim) { claimsIdentity.AddClaims(await manager.GetClaimsAsync(user.Id)); } ...

Como puede ver, hay tres reclamos añadidos por defecto. A ellos se agregan sus reclamos "personalizados". Esta es la razón por la que tendrá reclamaciones duplicadas, lo que significa que la llamada SingleOrDefault en la colección de reclamaciones arrojará el error que ha mencionado. Como solución, puede usar otros reclamos o actualizarlos, después de la creación de la identidad, depende de la necesidad de su negocio.