< Summary

Class:Azure.Identity.MacosNativeMethods
Assembly:Azure.Identity
File(s):C:\Git\azure-sdk-for-net\sdk\identity\Azure.Identity\src\MacosNativeMethods.cs
Covered lines:0
Uncovered lines:51
Coverable lines:51
Total lines:182
Line coverage:0% (0 of 51)
Covered branches:0
Total branches:24
Branch coverage:0% (0 of 24)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
.ctor(...)-0%100%
SecKeychainFindGenericPassword(...)-0%100%
SecKeychainAddGenericPassword(...)-0%100%
SecKeychainItemDelete(...)-0%100%
SecKeychainItemFreeContent(...)-0%100%
CFRelease(...)-0%0%
ThrowIfError(...)-0%0%
GetErrorMessageString(...)-0%0%
GetStringFromCFStringPtr(...)-0%0%

File(s)

C:\Git\azure-sdk-for-net\sdk\identity\Azure.Identity\src\MacosNativeMethods.cs

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License.
 3
 4using System;
 5using System.Runtime.InteropServices;
 6using System.Text;
 7
 8namespace Azure.Identity
 9{
 10    internal static class MacosNativeMethods
 11    {
 12        public const int SecStatusCodeSuccess = 0;
 13        public const int SecStatusCodeNoSuchKeychain = -25294;
 14        public const int SecStatusCodeInvalidKeychain = -25295;
 15        public const int SecStatusCodeAuthFailed = -25293;
 16        public const int SecStatusCodeDuplicateItem = -25299;
 17        public const int SecStatusCodeItemNotFound = -25300;
 18        public const int SecStatusCodeInteractionNotAllowed = -25308;
 19        public const int SecStatusCodeInteractionRequired = -25315;
 20        public const int SecStatusCodeNoSuchAttr = -25303;
 21
 22        public readonly struct CFRange
 23        {
 24            public readonly int Location, Length;
 25            public CFRange (int location, int length)
 26            {
 027                Location = location;
 028                Length = length;
 029            }
 30        }
 31
 32        public static void SecKeychainFindGenericPassword(IntPtr keychainOrArray, string serviceName, string accountName
 33        {
 034            byte[] serviceNameBytes = Encoding.UTF8.GetBytes(serviceName);
 035            byte[] accountNameBytes = Encoding.UTF8.GetBytes(accountName);
 36
 037            ThrowIfError(Imports.SecKeychainFindGenericPassword(keychainOrArray, serviceNameBytes.Length, serviceNameByt
 038        }
 39
 40        public static void SecKeychainAddGenericPassword(IntPtr keychainOrArray, string serviceName, string accountName,
 41        {
 042            byte[] serviceNameBytes = Encoding.UTF8.GetBytes(serviceName);
 043            byte[] accountNameBytes = Encoding.UTF8.GetBytes(accountName);
 044            byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
 45
 046            ThrowIfError(Imports.SecKeychainAddGenericPassword(keychainOrArray, serviceNameBytes.Length, serviceNameByte
 047        }
 48
 049        public static void SecKeychainItemDelete(IntPtr itemRef) => ThrowIfError(Imports.SecKeychainItemDelete(itemRef))
 50
 051        public static void SecKeychainItemFreeContent(IntPtr attrList, IntPtr data) => ThrowIfError(Imports.SecKeychainI
 52
 53        public static void CFRelease(IntPtr cfRef)
 54        {
 055            if (cfRef != IntPtr.Zero)
 56            {
 057                Imports.CFRelease(cfRef);
 58            }
 059        }
 60
 61        private static void ThrowIfError(int status)
 62        {
 063            if (status != SecStatusCodeSuccess)
 64            {
 065                throw new InvalidOperationException(GetErrorMessageString(status));
 66            }
 067        }
 68
 69        private static string GetErrorMessageString(int status)
 70        {
 071            IntPtr messagePtr = IntPtr.Zero;
 72            try
 73            {
 074                messagePtr = Imports.SecCopyErrorMessageString(status, IntPtr.Zero);
 075                return GetStringFromCFStringPtr(messagePtr);
 76            }
 077            catch
 78            {
 079                return status switch
 080                {
 081                    SecStatusCodeNoSuchKeychain => $"The keychain does not exist. [0x{status:x}]",
 082                    SecStatusCodeInvalidKeychain => $"The keychain is not valid. [0x{status:x}]",
 083                    SecStatusCodeAuthFailed => $"Authorization/Authentication failed. [0x{status:x}]",
 084                    SecStatusCodeDuplicateItem => $"The item already exists. [0x{status:x}]",
 085                    SecStatusCodeItemNotFound => $"The item cannot be found. [0x{status:x}]",
 086                    SecStatusCodeInteractionNotAllowed => $"Interaction with the Security Server is not allowed. [0x{sta
 087                    SecStatusCodeInteractionRequired => $"User interaction is required. [0x{status:x}]",
 088                    SecStatusCodeNoSuchAttr => $"The attribute does not exist. [0x{status:x}]",
 089                    _ => $"Unknown error. [0x{status:x}]",
 090                };
 91            }
 92            finally
 93            {
 094                CFRelease(messagePtr);
 095            }
 096        }
 97
 98        private static string GetStringFromCFStringPtr(IntPtr handle)
 99        {
 0100            IntPtr stringPtr = IntPtr.Zero;
 101            try
 102            {
 0103                int length = Imports.CFStringGetLength (handle);
 0104                stringPtr = Imports.CFStringGetCharactersPtr(handle);
 105
 0106                if (stringPtr == IntPtr.Zero)
 107                {
 0108                    var range = new CFRange(0, length);
 0109                    stringPtr = Marshal.AllocCoTaskMem(length * 2);
 0110                    Imports.CFStringGetCharacters(handle, range, stringPtr);
 111                }
 112
 0113                return Marshal.PtrToStringAuto(stringPtr, length);
 114            }
 115            finally
 116            {
 0117                if (stringPtr != IntPtr.Zero)
 118                {
 0119                    Marshal.FreeCoTaskMem (stringPtr);
 120                }
 0121            }
 0122        }
 123
 124        public static class Imports
 125        {
 126            private const string CoreFoundationLibrary = "/System/Library/Frameworks/CoreFoundation.framework/CoreFounda
 127            private const string SecurityLibrary = "/System/Library/Frameworks/Security.framework/Security";
 128
 129            [DllImport (CoreFoundationLibrary, CharSet=CharSet.Unicode)]
 130            [DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory | DllImportSearchPath.SafeDirectories)]
 131            public static extern int CFStringGetLength (IntPtr handle);
 132
 133            [DllImport (CoreFoundationLibrary, CharSet=CharSet.Unicode)]
 134            [DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory | DllImportSearchPath.SafeDirectories)]
 135            public static extern IntPtr CFStringGetCharactersPtr (IntPtr handle);
 136
 137            [DllImport (CoreFoundationLibrary, CharSet=CharSet.Unicode)]
 138            [DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory | DllImportSearchPath.SafeDirectories)]
 139            public static extern IntPtr CFStringGetCharacters (IntPtr handle, CFRange range, IntPtr buffer);
 140
 141            [DllImport (CoreFoundationLibrary, CharSet=CharSet.Unicode)]
 142            [DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory | DllImportSearchPath.SafeDirectories)]
 143            public static extern void CFRelease(IntPtr cfRef);
 144
 145            [DllImport (SecurityLibrary)]
 146            [DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory | DllImportSearchPath.SafeDirectories)]
 147            public static extern int SecKeychainFindGenericPassword (
 148                IntPtr keychainOrArray,
 149                int serviceNameLength,
 150                byte[] serviceName,
 151                int accountNameLength,
 152                byte[] accountName,
 153                out int passwordLength,
 154                out IntPtr passwordData,
 155                out IntPtr itemRef);
 156
 157            [DllImport (SecurityLibrary)]
 158            [DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory | DllImportSearchPath.SafeDirectories)]
 159            public static extern int SecKeychainAddGenericPassword (
 160                IntPtr keychain,
 161                int serviceNameLength,
 162                byte[] serviceName,
 163                int accountNameLength,
 164                byte[] accountName,
 165                int passwordLength,
 166                byte[] passwordData,
 167                out IntPtr itemRef);
 168
 169            [DllImport (SecurityLibrary)]
 170            [DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory | DllImportSearchPath.SafeDirectories)]
 171            public static extern int SecKeychainItemDelete(IntPtr itemRef);
 172
 173            [DllImport (SecurityLibrary)]
 174            [DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory | DllImportSearchPath.SafeDirectories)]
 175            public static extern int SecKeychainItemFreeContent (IntPtr attrList, IntPtr data);
 176
 177            [DllImport (SecurityLibrary)]
 178            [DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory | DllImportSearchPath.SafeDirectories)]
 179            public static extern IntPtr SecCopyErrorMessageString (int status, IntPtr reserved);
 180        }
 181    }
 182}