< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Security.SecurityUtils
Assembly: CoreWCF.NetNamedPipe
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.NetNamedPipe/src/CoreWCF/Security/SecurityUtils.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 39
Coverable lines: 39
Total lines: 102
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 12
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
GetProcessLogonSid()0%220%
GetProcessLogonSidCore()0%440%
GetTokenInformation(...)0%220%
GetTokenInformationLength(...)0%440%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.NetNamedPipe/src/CoreWCF/Security/SecurityUtils.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System;
 5using System.ComponentModel;
 6using System.Runtime.InteropServices;
 7using System.Runtime.Versioning;
 8using System.Security.Principal;
 9using CoreWCF.Runtime;
 10using Microsoft.Win32.SafeHandles;
 11
 12namespace CoreWCF.Security
 13{
 14    [SupportedOSPlatform("windows")]
 15    internal static class SecurityUtils
 16    {
 17        // The logon sid is generated on process start up so it is unique to this process.
 18        internal static SecurityIdentifier GetProcessLogonSid()
 19        {
 020            if (WindowsIdentity.GetCurrent().ImpersonationLevel == TokenImpersonationLevel.None)
 21            {
 22                // We're not impersonating so we can use WindowsIdentity.GetCurrent().AccessToken to
 23                // get the process logon SID.
 024                return GetProcessLogonSidCore();
 25            }
 26
 27            // We're running impersonated which means WindowsIdentity.AccessToken won't provide us with
 28            // the process logon sid. Runing impersonated with a an invalid access token causes WindowIdentity
 29            // to call the Win32 api RevertToSelf before running the code.
 030            return WindowsIdentity.RunImpersonated(SafeAccessTokenHandle.InvalidHandle, () =>
 031            {
 032                // We're using the undocumented feature of passing an invalid handle to unimpersonate, so validate this 
 033                Fx.Assert(WindowsIdentity.GetCurrent().ImpersonationLevel == TokenImpersonationLevel.None, "RunImpersona
 034                return GetProcessLogonSidCore();
 035            });
 36        }
 37
 38        private static SecurityIdentifier GetProcessLogonSidCore()
 39        {
 040            var processIdentity = WindowsIdentity.GetCurrent(TokenAccessLevels.Query);
 041            GCHandle pinnedArrayHandle = default;
 042            SafeAccessTokenHandle token = processIdentity.AccessToken;
 43            try
 44            {
 045                uint lengthToken = GetTokenInformationLength(token, UnsafeNativeMethods.TOKEN_INFORMATION_CLASS.TokenGro
 046                byte[] tokenInformation = new byte[lengthToken];
 47                // tokenInformation needs to be pinned as it will be populated with structures that have pointers to oth
 48                // within the same buffer. If GC moves it, those pointers will be invalid.
 049                pinnedArrayHandle = GCHandle.Alloc(tokenInformation, GCHandleType.Pinned);
 050                GetTokenInformation(token, UnsafeNativeMethods.TOKEN_INFORMATION_CLASS.TokenGroups, tokenInformation);
 051                Span<byte> tokenInfoSpan = tokenInformation;
 52                // Need to know the size of TOKEN_GROUPS to slice the Span so it will only end up with a single instance
 053                int tokenGroupSize = Marshal.SizeOf<UnsafeNativeMethods.TOKEN_GROUPS>();
 054                var tokenGroups = MemoryMarshal.Cast<byte, UnsafeNativeMethods.TOKEN_GROUPS>(tokenInfoSpan.Slice(0, toke
 055                UnsafeNativeMethods.TOKEN_GROUPS tg = tokenGroups[0];
 56                // Need the offset of Groups as that's where the array of SID_AND_ATTRIBUTES starts. There is more data 
 57                // slice the Span to start at the start of the array, and end after TOKEN_GROUPS.GroupCount number of SI
 058                int offsetOfSids = Marshal.OffsetOf<UnsafeNativeMethods.TOKEN_GROUPS>("Groups").ToInt32(); // Offset of 
 059                var sidsSpan = MemoryMarshal.Cast<byte, UnsafeNativeMethods.SID_AND_ATTRIBUTES>(tokenInfoSpan.Slice(offs
 60                Fx.Assert(sidsSpan.Length == tg.GroupCount, "sidsSpan slice is the wrong size");
 061                for (int i = 0; i < tg.GroupCount; i++)
 62                {
 063                    if ((sidsSpan[i].Attributes & UnsafeNativeMethods.SidAttribute.SE_GROUP_LOGON_ID) == UnsafeNativeMet
 64                    {
 065                        return new SecurityIdentifier(sidsSpan[i].Sid);
 66                    }
 67                }
 068                return new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null);
 69            }
 70            finally
 71            {
 072                pinnedArrayHandle.Free();
 073                processIdentity.Dispose();
 074            }
 075        }
 76
 77        private static void GetTokenInformation(SafeAccessTokenHandle token, UnsafeNativeMethods.TOKEN_INFORMATION_CLASS
 78        {
 079            if (!UnsafeNativeMethods.GetTokenInformation(token.DangerousGetHandle(), tic, tokenInformation, (uint)tokenI
 80            {
 081                int error = Marshal.GetLastWin32Error();
 082                throw new Win32Exception(error);
 83            }
 084        }
 85
 86        private static uint GetTokenInformationLength(SafeAccessTokenHandle token, UnsafeNativeMethods.TOKEN_INFORMATION
 87        {
 88            uint lengthNeeded;
 089            bool success = UnsafeNativeMethods.GetTokenInformation(token.DangerousGetHandle(), tic, null, 0, out lengthN
 090            if (!success)
 91            {
 092                int error = Marshal.GetLastWin32Error();
 093                if (error != UnsafeNativeMethods.ERROR_INSUFFICIENT_BUFFER)
 94                {
 095                    throw new Win32Exception(error);
 96                }
 97            }
 98
 099            return lengthNeeded;
 100        }
 101    }
 102}