// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.IO; using System.Linq; using System.Security.Principal; using System.Xml.Linq; using Microsoft.AspNetCore.InternalTesting; using Microsoft.Win32; namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests; [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method)] public sealed class RequiresIISAttribute : Attribute, ITestCondition { private static readonly (IISCapability Capability, string DllName)[] Modules = { (IISCapability.Websockets, "iiswsock.dll"), (IISCapability.WindowsAuthentication, "authsspi.dll"), (IISCapability.DynamicCompression, "compdyn.dll"), (IISCapability.ApplicationInitialization, "warmup.dll"), (IISCapability.TracingModule, "iisetw.dll"), (IISCapability.FailedRequestTracingModule, "iisfreb.dll"), (IISCapability.BasicAuthentication, "authbas.dll"), }; private static readonly bool _isMetStatic; private static readonly string _skipReasonStatic; private static readonly bool _poolEnvironmentVariablesAvailable; private static readonly IISCapability _modulesAvailable; static RequiresIISAttribute() { if (Environment.GetEnvironmentVariable("ASPNETCORE_TEST_SKIP_IIS") == "true") { _skipReasonStatic = "Test skipped using ASPNETCORE_TEST_SKIP_IIS environment variable"; return; } if (!OperatingSystem.IsWindows()) { _skipReasonStatic = "IIS tests can only be run on Windows"; return; } var identity = WindowsIdentity.GetCurrent(); var principal = new WindowsPrincipal(identity); if (!principal.IsInRole(WindowsBuiltInRole.Administrator) && !SkipInVSTSAttribute.RunningInVSTS) { _skipReasonStatic += "The current console is not running as admin."; return; } if (!File.Exists(Path.Combine(Environment.SystemDirectory, "inetsrv", "w3wp.exe")) && !SkipInVSTSAttribute.RunningInVSTS) { _skipReasonStatic += "The machine does not have IIS installed."; return; } var ancmConfigPath = Path.Combine(Environment.SystemDirectory, "inetsrv", "config", "schema", "aspnetcore_schema.xml"); if (!File.Exists(ancmConfigPath)) { ancmConfigPath = Path.Combine(Environment.SystemDirectory, "inetsrv", "config", "schema", "aspnetcore_schema_v2.xml"); } if (!File.Exists(ancmConfigPath) && !SkipInVSTSAttribute.RunningInVSTS) { _skipReasonStatic = "IIS Schema is not installed."; return; } XDocument ancmConfig; try { ancmConfig = XDocument.Load(ancmConfigPath); } catch { _skipReasonStatic = "Could not read ANCM schema configuration"; return; } _isMetStatic = ancmConfig .Root .Descendants("attribute") .Any(n => "hostingModel".Equals(n.Attribute("name")?.Value, StringComparison.Ordinal)); _skipReasonStatic = _isMetStatic ? null : "IIS schema needs to be upgraded to support ANCM."; foreach (var module in Modules) { if (File.Exists(Path.Combine(Environment.SystemDirectory, "inetsrv", module.DllName)) || SkipInVSTSAttribute.RunningInVSTS) { _modulesAvailable |= module.Capability; } } var iisRegistryKey = Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\InetStp", writable: false); if (iisRegistryKey == null) { _poolEnvironmentVariablesAvailable = false; } else { var majorVersion = (int)iisRegistryKey.GetValue("MajorVersion", -1); var minorVersion = (int)iisRegistryKey.GetValue("MinorVersion", -1); var version = new Version(majorVersion, minorVersion); _poolEnvironmentVariablesAvailable = version >= new Version(10, 0); } } public RequiresIISAttribute() : this(IISCapability.None) { } public RequiresIISAttribute(IISCapability capabilities) { IsMet = _isMetStatic; SkipReason = _skipReasonStatic; if (capabilities.HasFlag(IISCapability.PoolEnvironmentVariables)) { IsMet &= _poolEnvironmentVariablesAvailable; if (!_poolEnvironmentVariablesAvailable) { SkipReason += "The machine does allow for setting environment variables on application pools."; } } foreach (var module in Modules) { if (capabilities.HasFlag(module.Capability)) { var available = _modulesAvailable.HasFlag(module.Capability); IsMet &= available; if (!available) { SkipReason += $"The machine does have {module.Capability} available."; } } } } public bool IsMet { get; } public string SkipReason { get; } } |