MVC5 AntiForgeryToken Claims/"Sequence contains more than one element"

antiforgerytoken, asp.net-mvc-5, claims, security

Solution

The behavior is normal as you can see from the following method (called when creating the user identity):

await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie)

in `SignInAsync` method. In the implementation of `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));
}
...

As you can see there are three claims added by default. To them are added your "custom" claims. This is why you'll have duplicated claims, meaning that `SingleOrDefault` call on the claims collection will throw the error that you've mentioned. As a solution you can either use other claims either update them, after the identity creation, it's up to your business need.

Problem

Case: I have an MVC5 application (basically the MVC5 template with a scaffolded view) with the Google authentication method enabled. The application has been configured to accept email as user name and to store the claims assigned from Google like Surname, givenname, email, nameidentifier, etc, to the membership database (AspNetUserClaims). When I register and log in with a "local" user everything is fine. If I log in with a Google user its fine. If I log in with an account set up to have both a local and external login I get the error below. I have tried changing the type for the token to different settings using the AntiForgeryConfig option in Application_Start (example) ``` AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Email; ``` But it seems all the Claims are duplicated when combining local and external logins. The strangest thing is that the claims-collection (which I assumed had the answer) is identical for the combined and the external only login. When logged in as local user these Claims are assigned ``` [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: some@email.com} [2]: {http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider: ASP.NET Identity} ``` When logged in with a remote-only or a combined account the claims-list looks like this ``` [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: some.other@email.com} [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: some.other@email.com} [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} ``` Any help will be much appreciated! Error and stacktrace follows: ``` 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 ```

Original source