diff --git a/src/Microsoft.NetFramework.Analyzers/Core/MarkVerbHandlersWithValidateAntiforgeryTokenAnalyzer.cs b/src/Microsoft.NetFramework.Analyzers/Core/MarkVerbHandlersWithValidateAntiforgeryTokenAnalyzer.cs index 74d35bf135..fa5d21b656 100644 --- a/src/Microsoft.NetFramework.Analyzers/Core/MarkVerbHandlersWithValidateAntiforgeryTokenAnalyzer.cs +++ b/src/Microsoft.NetFramework.Analyzers/Core/MarkVerbHandlersWithValidateAntiforgeryTokenAnalyzer.cs @@ -122,10 +122,9 @@ public override void Initialize(AnalysisContext analysisContext) || methodSymbol.IsStatic || !methodSymbol.IsPublic() || !(methodSymbol.ReturnType.Inherits(actionResultSymbol) // FxCop implementation only looked at ActionResult-derived return types. - || (methodSymbol.IsAsync - && wellKnownTypeProvider.IsTaskOfType( - methodSymbol.ReturnType, - (ITypeSymbol typeArgument) => typeArgument.Inherits(actionResultSymbol)))) + || wellKnownTypeProvider.IsTaskOfType( + methodSymbol.ReturnType, + (ITypeSymbol typeArgument) => typeArgument.Inherits(actionResultSymbol))) || (!methodSymbol.ContainingType.Inherits(mvcControllerSymbol) && !methodSymbol.ContainingType.Inherits(mvcControllerBaseSymbol))) { diff --git a/src/Microsoft.NetFramework.Analyzers/UnitTests/Security/MarkVerbHandlersWithValidateAntiforgeryTokenTests.cs b/src/Microsoft.NetFramework.Analyzers/UnitTests/Security/MarkVerbHandlersWithValidateAntiforgeryTokenTests.cs index ed43a39ccb..9cb61003bc 100644 --- a/src/Microsoft.NetFramework.Analyzers/UnitTests/Security/MarkVerbHandlersWithValidateAntiforgeryTokenTests.cs +++ b/src/Microsoft.NetFramework.Analyzers/UnitTests/Security/MarkVerbHandlersWithValidateAntiforgeryTokenTests.cs @@ -849,6 +849,73 @@ public async Task DoSomethingAsync(string input) return null; } } +}" + ); + } + + [Fact] + public async Task MissingVerbsAndTokenTaskButNotAsync_CSharp_Diagnostic() + { + await VerifyCS.VerifyAnalyzerAsync(SystemWebMvcNamespaceCSharp + @" +namespace Blah +{ + using System.Threading.Tasks; + using System.Web.Mvc; + + public class ApiController : Controller + { + public Task DoSomethingAsync(string input) + { + return null; + } + } +} +", + GetCA3147CSharpNoVerbsNoToken(SystemWebMvcNamespaceCSharpLineCount + 9, 35, "DoSomethingAsync")); + } + + [Fact] + public async Task AcceptVerbsNoTokenTaskButNotAsync_CSharp_Diagnostic() + { + await VerifyCS.VerifyAnalyzerAsync(SystemWebMvcNamespaceCSharp + @" +namespace Blah +{ + using System.Threading.Tasks; + using System.Web.Mvc; + + public class AcceptVerbsNoTokenController : Controller + { + private const HttpVerbs AllowedVerbs = HttpVerbs.Post | HttpVerbs.Put; + + [AcceptVerbs(AllowedVerbs)] + public Task DoSomethingAsync() + { + return null; + } + } +} +", + GetCA3147CSharpVerbsAndNoToken(SystemWebMvcNamespaceCSharpLineCount + 12, 35, "DoSomethingAsync")); + } + + [Fact] + public async Task HaveAcceptStringPutAndTokenTaskButNotAsync_CSharp_NoDiagnostic() + { + await VerifyCS.VerifyAnalyzerAsync(SystemWebMvcNamespaceCSharp + @" +namespace Blah +{ + using System.Threading.Tasks; + using System.Web.Mvc; + + public class ApiController : Controller + { + [AcceptVerbs(""Put"")] + [ValidateAntiForgeryToken] + public Task DoSomethingAsync(string input) + { + return null; + } + } }" ); }