Create MS.SqlTools.Credentials project (#249)

* Initial credential service files

* Clean-up hostloader

* Update build scripts to build credentials archive

* Move hosting files to new assembly

* Add credentials files to MS.SqlTools.Credentials

* Remove duplicate files

* Update namespace in program.cs

* Fix test build breaks

* Update extensions visibility.

* Remove unused resource strings

* Add xproj files to SLN for appveyor builds

* Fix appveyor build break in test project

* Fix extensibility tests

* Fix various typos in latest iteration

* Add settings for Integration build

* Fix codecoverage.bat to use full pdb for new projects

* Fix bug when packing in folder with native images

* Fix typos in xproj

* Reset XLF to fix build.cmd
This commit is contained in:
Karl Burtram
2017-02-23 16:09:58 -08:00
committed by GitHub
parent e79a37bdfe
commit 0af7bef66d
112 changed files with 4887 additions and 1870 deletions

View File

@@ -0,0 +1,124 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol.Contracts;
using Microsoft.SqlTools.ServiceLayer.Utility;
namespace Microsoft.SqlTools.ServiceLayer.Credentials.Contracts
{
/// <summary>
/// A Credential containing information needed to log into a resource. This is primarily
/// defined as a unique <see cref="CredentialId"/> with an associated <see cref="Password"/>
/// that's linked to it.
/// </summary>
public class Credential
{
/// <summary>
/// A unique ID to identify the credential being saved.
/// </summary>
public string CredentialId { get; set; }
/// <summary>
/// The Password stored for this credential.
/// </summary>
public string Password { get; set; }
/// <summary>
/// Default Constructor
/// </summary>
public Credential()
{
}
/// <summary>
/// Constructor used when only <paramref name="credentialId"/> is known
/// </summary>
/// <param name="credentialId"><see cref="CredentialId"/></param>
public Credential(string credentialId)
: this(credentialId, null)
{
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="credentialId"><see cref="CredentialId"/></param>
/// <param name="password"><see cref="Password"/></param>
public Credential(string credentialId, string password)
{
CredentialId = credentialId;
Password = password;
}
internal static Credential Copy(Credential credential)
{
return new Credential
{
CredentialId = credential.CredentialId,
Password = credential.Password
};
}
/// <summary>
/// Validates the credential has all the properties needed to look up the password
/// </summary>
public static void ValidateForLookup(Credential credential)
{
Validate.IsNotNull("credential", credential);
Validate.IsNotNullOrEmptyString("credential.CredentialId", credential.CredentialId);
}
/// <summary>
/// Validates the credential has all the properties needed to save a password
/// </summary>
public static void ValidateForSave(Credential credential)
{
ValidateForLookup(credential);
Validate.IsNotNullOrEmptyString("credential.Password", credential.Password);
}
}
/// <summary>
/// Read Credential request mapping entry. Expects a Credential with CredentialId,
/// and responds with the <see cref="Credential.Password"/> filled in if found
/// </summary>
public class ReadCredentialRequest
{
/// <summary>
/// Request definition
/// </summary>
public static readonly
RequestType<Credential, Credential> Type =
RequestType<Credential, Credential>.Create("credential/read");
}
/// <summary>
/// Save Credential request mapping entry
/// </summary>
public class SaveCredentialRequest
{
/// <summary>
/// Request definition
/// </summary>
public static readonly
RequestType<Credential, bool> Type =
RequestType<Credential, bool>.Create("credential/save");
}
/// <summary>
/// Delete Credential request mapping entry
/// </summary>
public class DeleteCredentialRequest
{
/// <summary>
/// Request definition
/// </summary>
public static readonly
RequestType<Credential, bool> Type =
RequestType<Credential, bool>.Create("credential/delete");
}
}

View File

@@ -0,0 +1,182 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Credentials.Contracts;
using Microsoft.SqlTools.ServiceLayer.Credentials.Linux;
using Microsoft.SqlTools.ServiceLayer.Credentials.OSX;
using Microsoft.SqlTools.ServiceLayer.Credentials.Win32;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.Utility;
namespace Microsoft.SqlTools.ServiceLayer.Credentials
{
/// <summary>
/// Service responsible for securing credentials in a platform-neutral manner. This provides
/// a generic API for read, save and delete credentials
/// </summary>
public class CredentialService
{
internal static string DefaultSecretsFolder = ".sqlsecrets";
internal const string DefaultSecretsFile = "sqlsecrets.json";
/// <summary>
/// Singleton service instance
/// </summary>
private static Lazy<CredentialService> instance
= new Lazy<CredentialService>(() => new CredentialService());
/// <summary>
/// Gets the singleton service instance
/// </summary>
public static CredentialService Instance
{
get
{
return instance.Value;
}
}
private ICredentialStore credStore;
/// <summary>
/// Default constructor is private since it's a singleton class
/// </summary>
private CredentialService()
: this(null, new StoreConfig()
{ CredentialFolder = DefaultSecretsFolder, CredentialFile = DefaultSecretsFile, IsRelativeToUserHomeDir = true})
{
}
/// <summary>
/// Internal for testing purposes only
/// </summary>
internal CredentialService(ICredentialStore store, StoreConfig config)
{
credStore = store != null ? store : GetStoreForOS(config);
}
/// <summary>
/// Internal for testing purposes only
/// </summary>
internal static ICredentialStore GetStoreForOS(StoreConfig config)
{
if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return new Win32CredentialStore();
}
#if !WINDOWS_ONLY_BUILD
else if(RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
return new OSXCredentialStore();
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
return new LinuxCredentialStore(config);
}
#endif
throw new InvalidOperationException("Platform not currently supported");
}
public void InitializeService(IProtocolEndpoint serviceHost)
{
// Register request and event handlers with the Service Host
serviceHost.SetRequestHandler(ReadCredentialRequest.Type, HandleReadCredentialRequest);
serviceHost.SetRequestHandler(SaveCredentialRequest.Type, HandleSaveCredentialRequest);
serviceHost.SetRequestHandler(DeleteCredentialRequest.Type, HandleDeleteCredentialRequest);
}
public async Task HandleReadCredentialRequest(Credential credential, RequestContext<Credential> requestContext)
{
Func<Task<Credential>> doRead = () =>
{
return ReadCredentialAsync(credential);
};
await HandleRequest(doRead, requestContext, "HandleReadCredentialRequest");
}
public async Task<Credential> ReadCredentialAsync(Credential credential)
{
return await Task.Factory.StartNew(() =>
{
return ReadCredential(credential);
});
}
public Credential ReadCredential(Credential credential)
{
Credential.ValidateForLookup(credential);
Credential result = Credential.Copy(credential);
string password;
if (credStore.TryGetPassword(credential.CredentialId, out password))
{
result.Password = password;
}
return result;
}
public async Task HandleSaveCredentialRequest(Credential credential, RequestContext<bool> requestContext)
{
Func<Task<bool>> doSave = () =>
{
return SaveCredentialAsync(credential);
};
await HandleRequest(doSave, requestContext, "HandleSaveCredentialRequest");
}
public async Task<bool> SaveCredentialAsync(Credential credential)
{
return await Task.Factory.StartNew(() =>
{
return SaveCredential(credential);
});
}
public bool SaveCredential(Credential credential)
{
Credential.ValidateForSave(credential);
return credStore.Save(credential);
}
public async Task HandleDeleteCredentialRequest(Credential credential, RequestContext<bool> requestContext)
{
Func<Task<bool>> doDelete = () =>
{
return DeletePasswordAsync(credential);
};
await HandleRequest(doDelete, requestContext, "HandleDeleteCredentialRequest");
}
private async Task<bool> DeletePasswordAsync(Credential credential)
{
return await Task.Factory.StartNew(() =>
{
Credential.ValidateForLookup(credential);
return credStore.DeletePassword(credential.CredentialId);
});
}
private async Task HandleRequest<T>(Func<Task<T>> handler, RequestContext<T> requestContext, string requestType)
{
Logger.Write(LogLevel.Verbose, requestType);
try
{
T result = await handler();
await requestContext.SendResult(result);
}
catch (Exception ex)
{
await requestContext.SendError(ex.ToString());
}
}
}
}

View File

@@ -0,0 +1,41 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.ServiceLayer.Credentials.Contracts;
namespace Microsoft.SqlTools.ServiceLayer.Credentials
{
/// <summary>
/// An <see cref="ICredentialStore"/> support securely saving and retrieving passwords
/// </summary>
public interface ICredentialStore
{
/// <summary>
/// Saves a Password linked to a given Credential
/// </summary>
/// <param name="credential">
/// A <see cref="Credential"/> to be saved.
/// <see cref="Credential.CredentialId"/> and <see cref="Credential.Password"/> are required
/// </param>
/// <returns>True if successful, false otherwise</returns>
bool Save(Credential credential);
/// <summary>
/// Gets a Password and sets it into a <see cref="Credential"/> object
/// </summary>
/// <param name="credentialId">The name of the credential to find the password for. This is required</param>
/// <param name="password">Out value</param>
/// <returns>true if password was found, false otherwise</returns>
bool TryGetPassword(string credentialId, out string password);
/// <summary>
/// Deletes a password linked to a given credential
/// </summary>
/// <param name="credentialId">The name of the credential to find the password for. This is required</param>
/// <returns>True if password existed and was deleted, false otherwise</returns>
bool DeletePassword(string credentialId);
}
}

View File

@@ -0,0 +1,36 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace Microsoft.SqlTools.ServiceLayer.Credentials
{
internal static class InteropUtils
{
/// <summary>
/// Gets the length in bytes for a Unicode string, for use in interop where length must be defined
/// </summary>
public static UInt32 GetLengthInBytes(string value)
{
return Convert.ToUInt32( (value != null ? Encoding.Unicode.GetByteCount(value) : 0) );
}
public static string CopyToString(IntPtr ptr, int length)
{
if (ptr == IntPtr.Zero || length == 0)
{
return null;
}
byte[] pwdBytes = new byte[length];
Marshal.Copy(ptr, pwdBytes, 0, (int)length);
return Encoding.Unicode.GetString(pwdBytes, 0, (int)length);
}
}
}

View File

@@ -0,0 +1,18 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.Collections.Generic;
using Microsoft.SqlTools.ServiceLayer.Credentials.Contracts;
namespace Microsoft.SqlTools.ServiceLayer.Credentials.Linux
{
/// <summary>
/// Simplified class to enable writing a set of credentials to/from disk
/// </summary>
public class CredentialsWrapper
{
public List<Credential> Credentials { get; set; }
}
}

View File

@@ -0,0 +1,93 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.SqlTools.ServiceLayer.Credentials.Contracts;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.Utility;
using Newtonsoft.Json;
namespace Microsoft.SqlTools.ServiceLayer.Credentials.Linux
{
#if !WINDOWS_ONLY_BUILD
public class FileTokenStorage
{
private const int OwnerAccessMode = 384; // Permission 0600 - owner read/write, nobody else has access
private object lockObject = new object();
private string fileName;
public FileTokenStorage(string fileName)
{
Validate.IsNotNullOrEmptyString("fileName", fileName);
this.fileName = fileName;
}
public void AddEntries(IEnumerable<Credential> newEntries, IEnumerable<Credential> existingEntries)
{
var allEntries = existingEntries.Concat(newEntries);
this.SaveEntries(allEntries);
}
public void Clear()
{
this.SaveEntries(new List<Credential>());
}
public IEnumerable<Credential> LoadEntries()
{
if(!File.Exists(this.fileName))
{
return Enumerable.Empty<Credential>();
}
string serializedCreds;
lock (lockObject)
{
serializedCreds = File.ReadAllText(this.fileName);
}
CredentialsWrapper creds = JsonConvert.DeserializeObject<CredentialsWrapper>(serializedCreds, Constants.JsonSerializerSettings);
if(creds != null)
{
return creds.Credentials;
}
return Enumerable.Empty<Credential>();
}
public void SaveEntries(IEnumerable<Credential> entries)
{
CredentialsWrapper credentials = new CredentialsWrapper() { Credentials = entries.ToList() };
string serializedCreds = JsonConvert.SerializeObject(credentials, Constants.JsonSerializerSettings);
lock(lockObject)
{
WriteToFile(this.fileName, serializedCreds);
}
}
private static void WriteToFile(string filePath, string fileContents)
{
string dir = Path.GetDirectoryName(filePath);
if(!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
// Overwrite file, then use ChMod to ensure we have
File.WriteAllText(filePath, fileContents);
// set appropriate permissions so only current user can read/write
Interop.Sys.ChMod(filePath, OwnerAccessMode);
}
}
#endif
}

View File

@@ -0,0 +1,226 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Runtime.InteropServices;
namespace Microsoft.SqlTools.ServiceLayer.Credentials
{
#if !WINDOWS_ONLY_BUILD
internal static partial class Interop
{
/// <summary>Common Unix errno error codes.</summary>
internal enum Error
{
// These values were defined in src/Native/System.Native/fxerrno.h
//
// They compare against values obtained via Interop.Sys.GetLastError() not Marshal.GetLastWin32Error()
// which obtains the raw errno that varies between unixes. The strong typing as an enum is meant to
// prevent confusing the two. Casting to or from int is suspect. Use GetLastErrorInfo() if you need to
// correlate these to the underlying platform values or obtain the corresponding error message.
//
SUCCESS = 0,
E2BIG = 0x10001, // Argument list too long.
EACCES = 0x10002, // Permission denied.
EADDRINUSE = 0x10003, // Address in use.
EADDRNOTAVAIL = 0x10004, // Address not available.
EAFNOSUPPORT = 0x10005, // Address family not supported.
EAGAIN = 0x10006, // Resource unavailable, try again (same value as EWOULDBLOCK),
EALREADY = 0x10007, // Connection already in progress.
EBADF = 0x10008, // Bad file descriptor.
EBADMSG = 0x10009, // Bad message.
EBUSY = 0x1000A, // Device or resource busy.
ECANCELED = 0x1000B, // Operation canceled.
ECHILD = 0x1000C, // No child processes.
ECONNABORTED = 0x1000D, // Connection aborted.
ECONNREFUSED = 0x1000E, // Connection refused.
ECONNRESET = 0x1000F, // Connection reset.
EDEADLK = 0x10010, // Resource deadlock would occur.
EDESTADDRREQ = 0x10011, // Destination address required.
EDOM = 0x10012, // Mathematics argument out of domain of function.
EDQUOT = 0x10013, // Reserved.
EEXIST = 0x10014, // File exists.
EFAULT = 0x10015, // Bad address.
EFBIG = 0x10016, // File too large.
EHOSTUNREACH = 0x10017, // Host is unreachable.
EIDRM = 0x10018, // Identifier removed.
EILSEQ = 0x10019, // Illegal byte sequence.
EINPROGRESS = 0x1001A, // Operation in progress.
EINTR = 0x1001B, // Interrupted function.
EINVAL = 0x1001C, // Invalid argument.
EIO = 0x1001D, // I/O error.
EISCONN = 0x1001E, // Socket is connected.
EISDIR = 0x1001F, // Is a directory.
ELOOP = 0x10020, // Too many levels of symbolic links.
EMFILE = 0x10021, // File descriptor value too large.
EMLINK = 0x10022, // Too many links.
EMSGSIZE = 0x10023, // Message too large.
EMULTIHOP = 0x10024, // Reserved.
ENAMETOOLONG = 0x10025, // Filename too long.
ENETDOWN = 0x10026, // Network is down.
ENETRESET = 0x10027, // Connection aborted by network.
ENETUNREACH = 0x10028, // Network unreachable.
ENFILE = 0x10029, // Too many files open in system.
ENOBUFS = 0x1002A, // No buffer space available.
ENODEV = 0x1002C, // No such device.
ENOENT = 0x1002D, // No such file or directory.
ENOEXEC = 0x1002E, // Executable file format error.
ENOLCK = 0x1002F, // No locks available.
ENOLINK = 0x10030, // Reserved.
ENOMEM = 0x10031, // Not enough space.
ENOMSG = 0x10032, // No message of the desired type.
ENOPROTOOPT = 0x10033, // Protocol not available.
ENOSPC = 0x10034, // No space left on device.
ENOSYS = 0x10037, // Function not supported.
ENOTCONN = 0x10038, // The socket is not connected.
ENOTDIR = 0x10039, // Not a directory or a symbolic link to a directory.
ENOTEMPTY = 0x1003A, // Directory not empty.
ENOTSOCK = 0x1003C, // Not a socket.
ENOTSUP = 0x1003D, // Not supported (same value as EOPNOTSUP).
ENOTTY = 0x1003E, // Inappropriate I/O control operation.
ENXIO = 0x1003F, // No such device or address.
EOVERFLOW = 0x10040, // Value too large to be stored in data type.
EPERM = 0x10042, // Operation not permitted.
EPIPE = 0x10043, // Broken pipe.
EPROTO = 0x10044, // Protocol error.
EPROTONOSUPPORT = 0x10045, // Protocol not supported.
EPROTOTYPE = 0x10046, // Protocol wrong type for socket.
ERANGE = 0x10047, // Result too large.
EROFS = 0x10048, // Read-only file system.
ESPIPE = 0x10049, // Invalid seek.
ESRCH = 0x1004A, // No such process.
ESTALE = 0x1004B, // Reserved.
ETIMEDOUT = 0x1004D, // Connection timed out.
ETXTBSY = 0x1004E, // Text file busy.
EXDEV = 0x1004F, // Cross-device link.
ESOCKTNOSUPPORT = 0x1005E, // Socket type not supported.
EPFNOSUPPORT = 0x10060, // Protocol family not supported.
ESHUTDOWN = 0x1006C, // Socket shutdown.
EHOSTDOWN = 0x10070, // Host is down.
ENODATA = 0x10071, // No data available.
// POSIX permits these to have the same value and we make them always equal so
// that CoreFX cannot introduce a dependency on distinguishing between them that
// would not work on all platforms.
EOPNOTSUPP = ENOTSUP, // Operation not supported on socket.
EWOULDBLOCK = EAGAIN, // Operation would block.
}
// Represents a platform-agnostic Error and underlying platform-specific errno
internal struct ErrorInfo
{
private Error _error;
private int _rawErrno;
internal ErrorInfo(int errno)
{
_error = Interop.Sys.ConvertErrorPlatformToPal(errno);
_rawErrno = errno;
}
internal ErrorInfo(Error error)
{
_error = error;
_rawErrno = -1;
}
internal Error Error
{
get { return _error; }
}
internal int RawErrno
{
get { return _rawErrno == -1 ? (_rawErrno = Interop.Sys.ConvertErrorPalToPlatform(_error)) : _rawErrno; }
}
internal string GetErrorMessage()
{
return Interop.Sys.StrError(RawErrno);
}
public override string ToString()
{
return string.Format(
"RawErrno: {0} Error: {1} GetErrorMessage: {2}", // No localization required; text is member names used for debugging purposes
RawErrno, Error, GetErrorMessage());
}
}
internal partial class Sys
{
internal static Error GetLastError()
{
return ConvertErrorPlatformToPal(Marshal.GetLastWin32Error());
}
internal static ErrorInfo GetLastErrorInfo()
{
return new ErrorInfo(Marshal.GetLastWin32Error());
}
internal static string StrError(int platformErrno)
{
int maxBufferLength = 1024; // should be long enough for most any UNIX error
IntPtr buffer = Marshal.AllocHGlobal(maxBufferLength);
try
{
IntPtr message = StrErrorR(platformErrno, buffer, maxBufferLength);
if (message == IntPtr.Zero)
{
// This means the buffer was not large enough, but still contains
// as much of the error message as possible and is guaranteed to
// be null-terminated. We're not currently resizing/retrying because
// maxBufferLength is large enough in practice, but we could do
// so here in the future if necessary.
message = buffer;
}
string returnMsg = Marshal.PtrToStringAnsi(message);
return returnMsg;
}
finally
{
// Deallocate the buffer we created
Marshal.FreeHGlobal(buffer);
}
}
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_ConvertErrorPlatformToPal")]
internal static extern Error ConvertErrorPlatformToPal(int platformErrno);
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_ConvertErrorPalToPlatform")]
internal static extern int ConvertErrorPalToPlatform(Error error);
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_StrErrorR")]
private static extern IntPtr StrErrorR(int platformErrno, IntPtr buffer, int bufferSize);
}
}
// NOTE: extension method can't be nested inside Interop class.
internal static class InteropErrorExtensions
{
// Intended usage is e.g. Interop.Error.EFAIL.Info() for brevity
// vs. new Interop.ErrorInfo(Interop.Error.EFAIL) for synthesizing
// errors. Errors originated from the system should be obtained
// via GetLastErrorInfo(), not GetLastError().Info() as that will
// convert twice, which is not only inefficient but also lossy if
// we ever encounter a raw errno that no equivalent in the Error
// enum.
public static Interop.ErrorInfo Info(this Interop.Error error)
{
return new Interop.ErrorInfo(error);
}
}
#endif
}

View File

@@ -0,0 +1,47 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Runtime.InteropServices;
namespace Microsoft.SqlTools.ServiceLayer.Credentials
{
#if !WINDOWS_ONLY_BUILD
internal static partial class Interop
{
internal static partial class Sys
{
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_ChMod", SetLastError = true)]
internal static extern int ChMod(string path, int mode);
internal struct Passwd
{
internal IntPtr Name; // char*
internal IntPtr Password; // char*
internal uint UserId;
internal uint GroupId;
internal IntPtr UserInfo; // char*
internal IntPtr HomeDirectory; // char*
internal IntPtr Shell; // char*
};
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetPwUidR", SetLastError = false)]
internal static extern int GetPwUidR(uint uid, out Passwd pwd, IntPtr buf, int bufLen);
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetEUid")]
internal static extern uint GetEUid();
private static partial class Libraries
{
internal const string SystemNative = "System.Native";
}
}
}
#endif
}

View File

@@ -0,0 +1,237 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.SqlTools.ServiceLayer.Credentials.Contracts;
using Microsoft.SqlTools.ServiceLayer.Utility;
namespace Microsoft.SqlTools.ServiceLayer.Credentials.Linux
{
/// <summary>
/// Store configuration struct
/// </summary>
internal struct StoreConfig
{
public string CredentialFolder { get; set; }
public string CredentialFile { get; set; }
public bool IsRelativeToUserHomeDir { get; set; }
}
#if !WINDOWS_ONLY_BUILD
/// <summary>
/// Linux implementation of the credential store.
///
/// <remarks>
/// This entire implementation may need to be revised to support encryption of
/// passwords and protection of them when loaded into memory.
/// </remarks>
/// </summary>
internal class LinuxCredentialStore : ICredentialStore
{
private string credentialFolderPath;
private string credentialFileName;
private FileTokenStorage storage;
public LinuxCredentialStore(StoreConfig config)
{
Validate.IsNotNull("config", config);
Validate.IsNotNullOrEmptyString("credentialFolder", config.CredentialFolder);
Validate.IsNotNullOrEmptyString("credentialFileName", config.CredentialFile);
this.credentialFolderPath = config.IsRelativeToUserHomeDir ? GetUserScopedDirectory(config.CredentialFolder) : config.CredentialFolder;
this.credentialFileName = config.CredentialFile;
string combinedPath = Path.Combine(this.credentialFolderPath, this.credentialFileName);
storage = new FileTokenStorage(combinedPath);
}
public bool DeletePassword(string credentialId)
{
Validate.IsNotNullOrEmptyString("credentialId", credentialId);
IEnumerable<Credential> creds;
if (LoadCredentialsAndFilterById(credentialId, out creds))
{
storage.SaveEntries(creds);
return true;
}
return false;
}
/// <summary>
/// Gets filtered credentials with a specific ID filtered out
/// </summary>
/// <returns>True if the credential to filter was removed, false if it was not found</returns>
private bool LoadCredentialsAndFilterById(string idToFilter, out IEnumerable<Credential> creds)
{
bool didRemove = false;
creds = storage.LoadEntries().Where(cred =>
{
if (IsCredentialMatch(idToFilter, cred))
{
didRemove = true;
return false; // filter this out
}
return true;
}).ToList(); // Call ToList ensures Where clause is executed so didRemove can be evaluated
return didRemove;
}
private static bool IsCredentialMatch(string credentialId, Credential cred)
{
return string.Equals(credentialId, cred.CredentialId, StringComparison.Ordinal);
}
public bool TryGetPassword(string credentialId, out string password)
{
Validate.IsNotNullOrEmptyString("credentialId", credentialId);
Credential cred = storage.LoadEntries().FirstOrDefault(c => IsCredentialMatch(credentialId, c));
if (cred != null)
{
password = cred.Password;
return true;
}
// Else this was not found in the list
password = null;
return false;
}
public bool Save(Credential credential)
{
Credential.ValidateForSave(credential);
// Load the credentials, removing the existing Cred for this
IEnumerable<Credential> creds;
LoadCredentialsAndFilterById(credential.CredentialId, out creds);
storage.SaveEntries(creds.Append(credential));
return true;
}
/// <summary>
/// Internal for testing purposes only
/// </summary>
internal string CredentialFolderPath
{
get { return this.credentialFolderPath; }
}
/// <summary>
/// Concatenates a directory to the user home directory's path
/// </summary>
internal static string GetUserScopedDirectory(string userPath)
{
string homeDir = GetHomeDirectory() ?? string.Empty;
return Path.Combine(homeDir, userPath);
}
/// <summary>Gets the current user's home directory.</summary>
/// <returns>The path to the home directory, or null if it could not be determined.</returns>
internal static string GetHomeDirectory()
{
// First try to get the user's home directory from the HOME environment variable.
// This should work in most cases.
string userHomeDirectory = Environment.GetEnvironmentVariable("HOME");
if (!string.IsNullOrEmpty(userHomeDirectory))
{
return userHomeDirectory;
}
// In initialization conditions, however, the "HOME" environment variable may
// not yet be set. For such cases, consult with the password entry.
// First try with a buffer that should suffice for 99% of cases.
// Note that, theoretically, userHomeDirectory may be null in the success case
// if we simply couldn't find a home directory for the current user.
// In that case, we pass back the null value and let the caller decide
// what to do.
return GetHomeDirectoryFromPw();
}
internal static string GetHomeDirectoryFromPw()
{
string userHomeDirectory = null;
const int BufLen = 1024;
if (TryGetHomeDirectoryFromPasswd(BufLen, out userHomeDirectory))
{
return userHomeDirectory;
}
// Fallback to heap allocations if necessary, growing the buffer until
// we succeed. TryGetHomeDirectory will throw if there's an unexpected error.
int lastBufLen = BufLen;
while (true)
{
lastBufLen *= 2;
if (TryGetHomeDirectoryFromPasswd(lastBufLen, out userHomeDirectory))
{
return userHomeDirectory;
}
}
}
/// <summary>Wrapper for getpwuid_r.</summary>
/// <param name="bufLen">The length of the buffer to use when storing the password result.</param>
/// <param name="path">The resulting path; null if the user didn't have an entry.</param>
/// <returns>true if the call was successful (path may still be null); false is a larger buffer is needed.</returns>
private static bool TryGetHomeDirectoryFromPasswd(int bufLen, out string path)
{
// Call getpwuid_r to get the passwd struct
Interop.Sys.Passwd passwd;
IntPtr buffer = Marshal.AllocHGlobal(bufLen);
try
{
int error = Interop.Sys.GetPwUidR(Interop.Sys.GetEUid(), out passwd, buffer, bufLen);
// If the call succeeds, give back the home directory path retrieved
if (error == 0)
{
Debug.Assert(passwd.HomeDirectory != IntPtr.Zero);
path = Marshal.PtrToStringAnsi(passwd.HomeDirectory);
return true;
}
// If the current user's entry could not be found, give back null
// path, but still return true as false indicates the buffer was
// too small.
if (error == -1)
{
path = null;
return true;
}
var errorInfo = new Interop.ErrorInfo(error);
// If the call failed because the buffer was too small, return false to
// indicate the caller should try again with a larger buffer.
if (errorInfo.Error == Interop.Error.ERANGE)
{
path = null;
return false;
}
// Otherwise, fail.
throw new IOException(errorInfo.GetErrorMessage(), errorInfo.RawErrno);
}
finally
{
// Deallocate the buffer we created
Marshal.FreeHGlobal(buffer);
}
}
}
#endif
}

View File

@@ -0,0 +1,105 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Runtime.InteropServices;
namespace Microsoft.SqlTools.ServiceLayer.Credentials
{
internal static partial class Interop
{
internal static partial class CoreFoundation
{
/// <summary>
/// Tells the OS what encoding the passed in String is in. These come from the CFString.h header file in the CoreFoundation framework.
/// </summary>
private enum CFStringBuiltInEncodings : uint
{
kCFStringEncodingMacRoman = 0,
kCFStringEncodingWindowsLatin1 = 0x0500,
kCFStringEncodingISOLatin1 = 0x0201,
kCFStringEncodingNextStepLatin = 0x0B01,
kCFStringEncodingASCII = 0x0600,
kCFStringEncodingUnicode = 0x0100,
kCFStringEncodingUTF8 = 0x08000100,
kCFStringEncodingNonLossyASCII = 0x0BFF,
kCFStringEncodingUTF16 = 0x0100,
kCFStringEncodingUTF16BE = 0x10000100,
kCFStringEncodingUTF16LE = 0x14000100,
kCFStringEncodingUTF32 = 0x0c000100,
kCFStringEncodingUTF32BE = 0x18000100,
kCFStringEncodingUTF32LE = 0x1c000100
}
/// <summary>
/// Creates a CFStringRef from a 8-bit String object. Follows the "Create Rule" where if you create it, you delete it.
/// </summary>
/// <param name="allocator">Should be IntPtr.Zero</param>
/// <param name="str">The string to get a CFStringRef for</param>
/// <param name="encoding">The encoding of the str variable. This should be UTF 8 for OS X</param>
/// <returns>Returns a pointer to a CFString on success; otherwise, returns IntPtr.Zero</returns>
/// <remarks>For *nix systems, the CLR maps ANSI to UTF-8, so be explicit about that</remarks>
[DllImport(Interop.Libraries.CoreFoundationLibrary, CharSet = CharSet.Ansi)]
private static extern SafeCreateHandle CFStringCreateWithCString(
IntPtr allocator,
string str,
CFStringBuiltInEncodings encoding);
/// <summary>
/// Creates a CFStringRef from a 8-bit String object. Follows the "Create Rule" where if you create it, you delete it.
/// </summary>
/// <param name="str">The string to get a CFStringRef for</param>
/// <returns>Returns a valid SafeCreateHandle to a CFString on success; otherwise, returns an invalid SafeCreateHandle</returns>
internal static SafeCreateHandle CFStringCreateWithCString(string str)
{
return CFStringCreateWithCString(IntPtr.Zero, str, CFStringBuiltInEncodings.kCFStringEncodingUTF8);
}
/// <summary>
/// Creates a pointer to an unmanaged CFArray containing the input values. Follows the "Create Rule" where if you create it, you delete it.
/// </summary>
/// <param name="allocator">Should be IntPtr.Zero</param>
/// <param name="values">The values to put in the array</param>
/// <param name="numValues">The number of values in the array</param>
/// <param name="callbacks">Should be IntPtr.Zero</param>
/// <returns>Returns a pointer to a CFArray on success; otherwise, returns IntPtr.Zero</returns>
[DllImport(Interop.Libraries.CoreFoundationLibrary)]
private static extern SafeCreateHandle CFArrayCreate(
IntPtr allocator,
[MarshalAs(UnmanagedType.LPArray)]
IntPtr[] values,
ulong numValues,
IntPtr callbacks);
/// <summary>
/// Creates a pointer to an unmanaged CFArray containing the input values. Follows the "Create Rule" where if you create it, you delete it.
/// </summary>
/// <param name="values">The values to put in the array</param>
/// <param name="numValues">The number of values in the array</param>
/// <returns>Returns a valid SafeCreateHandle to a CFArray on success; otherwise, returns an invalid SafeCreateHandle</returns>
internal static SafeCreateHandle CFArrayCreate(IntPtr[] values, ulong numValues)
{
return CFArrayCreate(IntPtr.Zero, values, numValues, IntPtr.Zero);
}
/// <summary>
/// You should retain a Core Foundation object when you receive it from elsewhere
/// (that is, you did not create or copy it) and you want it to persist. If you
/// retain a Core Foundation object you are responsible for releasing it
/// </summary>
/// <param name="ptr">The CFType object to retain. This value must not be NULL</param>
/// <returns>The input value</param>
[DllImport(Interop.Libraries.CoreFoundationLibrary)]
internal extern static IntPtr CFRetain(IntPtr ptr);
/// <summary>
/// Decrements the reference count on the specified object and, if the ref count hits 0, cleans up the object.
/// </summary>
/// <param name="ptr">The pointer on which to decrement the reference count.</param>
[DllImport(Interop.Libraries.CoreFoundationLibrary)]
internal extern static void CFRelease(IntPtr ptr);
}
}
}

View File

@@ -0,0 +1,17 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.SqlTools.ServiceLayer.Credentials
{
internal static partial class Interop
{
private static partial class Libraries
{
internal const string CoreFoundationLibrary = "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation";
internal const string CoreServicesLibrary = "/System/Library/Frameworks/CoreServices.framework/CoreServices";
internal const string SecurityLibrary = "/System/Library/Frameworks/Security.framework/Security";
}
}
}

View File

@@ -0,0 +1,459 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Runtime.InteropServices;
namespace Microsoft.SqlTools.ServiceLayer.Credentials
{
internal partial class Interop
{
internal partial class Security
{
[DllImport(Libraries.SecurityLibrary, CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern OSStatus SecKeychainAddGenericPassword(IntPtr keyChainRef, UInt32 serviceNameLength, string serviceName,
UInt32 accountNameLength, string accountName, UInt32 passwordLength, IntPtr password, [Out] IntPtr itemRef);
/// <summary>
/// Find a generic password based on the attributes passed
/// </summary>
/// <param name="keyChainRef">
/// A reference to an array of keychains to search, a single keychain, or NULL to search the user's default keychain search list.
/// </param>
/// <param name="serviceNameLength">The length of the buffer pointed to by serviceName.</param>
/// <param name="serviceName">A pointer to a string containing the service name.</param>
/// <param name="accountNameLength">The length of the buffer pointed to by accountName.</param>
/// <param name="accountName">A pointer to a string containing the account name.</param>
/// <param name="passwordLength">On return, the length of the buffer pointed to by passwordData.</param>
/// <param name="password">
/// On return, a pointer to a data buffer containing the password.
/// Your application must call SecKeychainItemFreeContent(NULL, passwordData)
/// to release this data buffer when it is no longer needed.Pass NULL if you are not interested in retrieving the password data at
/// this time, but simply want to find the item reference.
/// </param>
/// <param name="itemRef">On return, a reference to the keychain item which was found.</param>
/// <returns>A result code that should be in <see cref="OSStatus"/></returns>
/// <remarks>
/// The SecKeychainFindGenericPassword function finds the first generic password item which matches the attributes you provide.
/// Most attributes are optional; you should pass only as many as you need to narrow the search sufficiently for your application's intended use.
/// SecKeychainFindGenericPassword optionally returns a reference to the found item.
/// </remarks>
[DllImport(Libraries.SecurityLibrary, CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern OSStatus SecKeychainFindGenericPassword(IntPtr keyChainRef, UInt32 serviceNameLength, string serviceName,
UInt32 accountNameLength, string accountName, out UInt32 passwordLength, out IntPtr password, out IntPtr itemRef);
/// <summary>
/// Releases the memory used by the keychain attribute list and the keychain data retrieved in a previous call to SecKeychainItemCopyContent.
/// </summary>
/// <param name="attrList">A pointer to the attribute list to release. Pass NULL to ignore this parameter.</param>
/// <param name="data">A pointer to the data buffer to release. Pass NULL to ignore this parameter.</param>
/// <returns>A result code that should be in <see cref="OSStatus"/></returns>
[DllImport(Libraries.SecurityLibrary, SetLastError = true)]
internal static extern OSStatus SecKeychainItemFreeContent([In] IntPtr attrList, [In] IntPtr data);
/// <summary>
/// Deletes a keychain item from the default keychain's permanent data store.
/// </summary>
/// <param name="itemRef">A keychain item reference of the item to delete.</param>
/// <returns>A result code that should be in <see cref="OSStatus"/></returns>
/// <remarks>
/// If itemRef has not previously been added to the keychain, SecKeychainItemDelete does nothing and returns ErrSecSuccess.
/// IMPORTANT: SecKeychainItemDelete does not dispose the memory occupied by the item reference itself;
/// use the CFRelease function when you are completely * * finished with an item.
/// </remarks>
[DllImport(Libraries.SecurityLibrary, SetLastError = true)]
internal static extern OSStatus SecKeychainItemDelete(SafeHandle itemRef);
#region OSStatus Codes
/// <summary>Common Unix errno error codes.</summary>
internal enum OSStatus
{
ErrSecSuccess = 0, /* No error. */
ErrSecUnimplemented = -4, /* Function or operation not implemented. */
ErrSecDskFull = -34,
ErrSecIO = -36, /*I/O error*/
ErrSecParam = -50, /* One or more parameters passed to a function were not valid. */
ErrSecWrPerm = -61, /* write permissions error*/
ErrSecAllocate = -108, /* Failed to allocate memory. */
ErrSecUserCanceled = -128, /* User canceled the operation. */
ErrSecBadReq = -909, /* Bad parameter or invalid state for operation. */
ErrSecInternalComponent = -2070,
ErrSecCoreFoundationUnknown = -4960,
ErrSecNotAvailable = -25291, /* No keychain is available. You may need to restart your computer. */
ErrSecReadOnly = -25292, /* This keychain cannot be modified. */
ErrSecAuthFailed = -25293, /* The user name or passphrase you entered is not correct. */
ErrSecNoSuchKeychain = -25294, /* The specified keychain could not be found. */
ErrSecInvalidKeychain = -25295, /* The specified keychain is not a valid keychain file. */
ErrSecDuplicateKeychain = -25296, /* A keychain with the same name already exists. */
ErrSecDuplicateCallback = -25297, /* The specified callback function is already installed. */
ErrSecInvalidCallback = -25298, /* The specified callback function is not valid. */
ErrSecDuplicateItem = -25299, /* The specified item already exists in the keychain. */
ErrSecItemNotFound = -25300, /* The specified item could not be found in the keychain. */
ErrSecBufferTooSmall = -25301, /* There is not enough memory available to use the specified item. */
ErrSecDataTooLarge = -25302, /* This item contains information which is too large or in a format that cannot be displayed. */
ErrSecNoSuchAttr = -25303, /* The specified attribute does not exist. */
ErrSecInvalidItemRef = -25304, /* The specified item is no longer valid. It may have been deleted from the keychain. */
ErrSecInvalidSearchRef = -25305, /* Unable to search the current keychain. */
ErrSecNoSuchClass = -25306, /* The specified item does not appear to be a valid keychain item. */
ErrSecNoDefaultKeychain = -25307, /* A default keychain could not be found. */
ErrSecInteractionNotAllowed = -25308, /* User interaction is not allowed. */
ErrSecReadOnlyAttr = -25309, /* The specified attribute could not be modified. */
ErrSecWrongSecVersion = -25310, /* This keychain was created by a different version of the system software and cannot be opened. */
ErrSecKeySizeNotAllowed = -25311, /* This item specifies a key size which is too large. */
ErrSecNoStorageModule = -25312, /* A required component (data storage module) could not be loaded. You may need to restart your computer. */
ErrSecNoCertificateModule = -25313, /* A required component (certificate module) could not be loaded. You may need to restart your computer. */
ErrSecNoPolicyModule = -25314, /* A required component (policy module) could not be loaded. You may need to restart your computer. */
ErrSecInteractionRequired = -25315, /* User interaction is required, but is currently not allowed. */
ErrSecDataNotAvailable = -25316, /* The contents of this item cannot be retrieved. */
ErrSecDataNotModifiable = -25317, /* The contents of this item cannot be modified. */
ErrSecCreateChainFailed = -25318, /* One or more certificates required to validate this certificate cannot be found. */
ErrSecInvalidPrefsDomain = -25319, /* The specified preferences domain is not valid. */
ErrSecInDarkWake = -25320, /* In dark wake, no UI possible */
ErrSecACLNotSimple = -25240, /* The specified access control list is not in standard (simple) form. */
ErrSecPolicyNotFound = -25241, /* The specified policy cannot be found. */
ErrSecInvalidTrustSetting = -25242, /* The specified trust setting is invalid. */
ErrSecNoAccessForItem = -25243, /* The specified item has no access control. */
ErrSecInvalidOwnerEdit = -25244, /* Invalid attempt to change the owner of this item. */
ErrSecTrustNotAvailable = -25245, /* No trust results are available. */
ErrSecUnsupportedFormat = -25256, /* Import/Export format unsupported. */
ErrSecUnknownFormat = -25257, /* Unknown format in import. */
ErrSecKeyIsSensitive = -25258, /* Key material must be wrapped for export. */
ErrSecMultiplePrivKeys = -25259, /* An attempt was made to import multiple private keys. */
ErrSecPassphraseRequired = -25260, /* Passphrase is required for import/export. */
ErrSecInvalidPasswordRef = -25261, /* The password reference was invalid. */
ErrSecInvalidTrustSettings = -25262, /* The Trust Settings Record was corrupted. */
ErrSecNoTrustSettings = -25263, /* No Trust Settings were found. */
ErrSecPkcs12VerifyFailure = -25264, /* MAC verification failed during PKCS12 import (wrong password?) */
ErrSecNotSigner = -26267, /* A certificate was not signed by its proposed parent. */
ErrSecDecode = -26275, /* Unable to decode the provided data. */
ErrSecServiceNotAvailable = -67585, /* The required service is not available. */
ErrSecInsufficientClientID = -67586, /* The client ID is not correct. */
ErrSecDeviceReset = -67587, /* A device reset has occurred. */
ErrSecDeviceFailed = -67588, /* A device failure has occurred. */
ErrSecAppleAddAppACLSubject = -67589, /* Adding an application ACL subject failed. */
ErrSecApplePublicKeyIncomplete = -67590, /* The public key is incomplete. */
ErrSecAppleSignatureMismatch = -67591, /* A signature mismatch has occurred. */
ErrSecAppleInvalidKeyStartDate = -67592, /* The specified key has an invalid start date. */
ErrSecAppleInvalidKeyEndDate = -67593, /* The specified key has an invalid end date. */
ErrSecConversionError = -67594, /* A conversion error has occurred. */
ErrSecAppleSSLv2Rollback = -67595, /* A SSLv2 rollback error has occurred. */
ErrSecDiskFull = -34, /* The disk is full. */
ErrSecQuotaExceeded = -67596, /* The quota was exceeded. */
ErrSecFileTooBig = -67597, /* The file is too big. */
ErrSecInvalidDatabaseBlob = -67598, /* The specified database has an invalid blob. */
ErrSecInvalidKeyBlob = -67599, /* The specified database has an invalid key blob. */
ErrSecIncompatibleDatabaseBlob = -67600, /* The specified database has an incompatible blob. */
ErrSecIncompatibleKeyBlob = -67601, /* The specified database has an incompatible key blob. */
ErrSecHostNameMismatch = -67602, /* A host name mismatch has occurred. */
ErrSecUnknownCriticalExtensionFlag = -67603, /* There is an unknown critical extension flag. */
ErrSecNoBasicConstraints = -67604, /* No basic constraints were found. */
ErrSecNoBasicConstraintsCA = -67605, /* No basic CA constraints were found. */
ErrSecInvalidAuthorityKeyID = -67606, /* The authority key ID is not valid. */
ErrSecInvalidSubjectKeyID = -67607, /* The subject key ID is not valid. */
ErrSecInvalidKeyUsageForPolicy = -67608, /* The key usage is not valid for the specified policy. */
ErrSecInvalidExtendedKeyUsage = -67609, /* The extended key usage is not valid. */
ErrSecInvalidIDLinkage = -67610, /* The ID linkage is not valid. */
ErrSecPathLengthConstraintExceeded = -67611, /* The path length constraint was exceeded. */
ErrSecInvalidRoot = -67612, /* The root or anchor certificate is not valid. */
ErrSecCRLExpired = -67613, /* The CRL has expired. */
ErrSecCRLNotValidYet = -67614, /* The CRL is not yet valid. */
ErrSecCRLNotFound = -67615, /* The CRL was not found. */
ErrSecCRLServerDown = -67616, /* The CRL server is down. */
ErrSecCRLBadURI = -67617, /* The CRL has a bad Uniform Resource Identifier. */
ErrSecUnknownCertExtension = -67618, /* An unknown certificate extension was encountered. */
ErrSecUnknownCRLExtension = -67619, /* An unknown CRL extension was encountered. */
ErrSecCRLNotTrusted = -67620, /* The CRL is not trusted. */
ErrSecCRLPolicyFailed = -67621, /* The CRL policy failed. */
ErrSecIDPFailure = -67622, /* The issuing distribution point was not valid. */
ErrSecSMIMEEmailAddressesNotFound = -67623, /* An email address mismatch was encountered. */
ErrSecSMIMEBadExtendedKeyUsage = -67624, /* The appropriate extended key usage for SMIME was not found. */
ErrSecSMIMEBadKeyUsage = -67625, /* The key usage is not compatible with SMIME. */
ErrSecSMIMEKeyUsageNotCritical = -67626, /* The key usage extension is not marked as critical. */
ErrSecSMIMENoEmailAddress = -67627, /* No email address was found in the certificate. */
ErrSecSMIMESubjAltNameNotCritical = -67628, /* The subject alternative name extension is not marked as critical. */
ErrSecSSLBadExtendedKeyUsage = -67629, /* The appropriate extended key usage for SSL was not found. */
ErrSecOCSPBadResponse = -67630, /* The OCSP response was incorrect or could not be parsed. */
ErrSecOCSPBadRequest = -67631, /* The OCSP request was incorrect or could not be parsed. */
ErrSecOCSPUnavailable = -67632, /* OCSP service is unavailable. */
ErrSecOCSPStatusUnrecognized = -67633, /* The OCSP server did not recognize this certificate. */
ErrSecEndOfData = -67634, /* An end-of-data was detected. */
ErrSecIncompleteCertRevocationCheck = -67635, /* An incomplete certificate revocation check occurred. */
ErrSecNetworkFailure = -67636, /* A network failure occurred. */
ErrSecOCSPNotTrustedToAnchor = -67637, /* The OCSP response was not trusted to a root or anchor certificate. */
ErrSecRecordModified = -67638, /* The record was modified. */
ErrSecOCSPSignatureError = -67639, /* The OCSP response had an invalid signature. */
ErrSecOCSPNoSigner = -67640, /* The OCSP response had no signer. */
ErrSecOCSPResponderMalformedReq = -67641, /* The OCSP responder was given a malformed request. */
ErrSecOCSPResponderInternalError = -67642, /* The OCSP responder encountered an internal error. */
ErrSecOCSPResponderTryLater = -67643, /* The OCSP responder is busy, try again later. */
ErrSecOCSPResponderSignatureRequired = -67644, /* The OCSP responder requires a signature. */
ErrSecOCSPResponderUnauthorized = -67645, /* The OCSP responder rejected this request as unauthorized. */
ErrSecOCSPResponseNonceMismatch = -67646, /* The OCSP response nonce did not match the request. */
ErrSecCodeSigningBadCertChainLength = -67647, /* Code signing encountered an incorrect certificate chain length. */
ErrSecCodeSigningNoBasicConstraints = -67648, /* Code signing found no basic constraints. */
ErrSecCodeSigningBadPathLengthConstraint= -67649, /* Code signing encountered an incorrect path length constraint. */
ErrSecCodeSigningNoExtendedKeyUsage = -67650, /* Code signing found no extended key usage. */
ErrSecCodeSigningDevelopment = -67651, /* Code signing indicated use of a development-only certificate. */
ErrSecResourceSignBadCertChainLength = -67652, /* Resource signing has encountered an incorrect certificate chain length. */
ErrSecResourceSignBadExtKeyUsage = -67653, /* Resource signing has encountered an error in the extended key usage. */
ErrSecTrustSettingDeny = -67654, /* The trust setting for this policy was set to Deny. */
ErrSecInvalidSubjectName = -67655, /* An invalid certificate subject name was encountered. */
ErrSecUnknownQualifiedCertStatement = -67656, /* An unknown qualified certificate statement was encountered. */
ErrSecMobileMeRequestQueued = -67657, /* The MobileMe request will be sent during the next connection. */
ErrSecMobileMeRequestRedirected = -67658, /* The MobileMe request was redirected. */
ErrSecMobileMeServerError = -67659, /* A MobileMe server error occurred. */
ErrSecMobileMeServerNotAvailable = -67660, /* The MobileMe server is not available. */
ErrSecMobileMeServerAlreadyExists = -67661, /* The MobileMe server reported that the item already exists. */
ErrSecMobileMeServerServiceErr = -67662, /* A MobileMe service error has occurred. */
ErrSecMobileMeRequestAlreadyPending = -67663, /* A MobileMe request is already pending. */
ErrSecMobileMeNoRequestPending = -67664, /* MobileMe has no request pending. */
ErrSecMobileMeCSRVerifyFailure = -67665, /* A MobileMe CSR verification failure has occurred. */
ErrSecMobileMeFailedConsistencyCheck = -67666, /* MobileMe has found a failed consistency check. */
ErrSecNotInitialized = -67667, /* A function was called without initializing CSSM. */
ErrSecInvalidHandleUsage = -67668, /* The CSSM handle does not match with the service type. */
ErrSecPVCReferentNotFound = -67669, /* A reference to the calling module was not found in the list of authorized callers. */
ErrSecFunctionIntegrityFail = -67670, /* A function address was not within the verified module. */
ErrSecInternalError = -67671, /* An internal error has occurred. */
ErrSecMemoryError = -67672, /* A memory error has occurred. */
ErrSecInvalidData = -67673, /* Invalid data was encountered. */
ErrSecMDSError = -67674, /* A Module Directory Service error has occurred. */
ErrSecInvalidPointer = -67675, /* An invalid pointer was encountered. */
ErrSecSelfCheckFailed = -67676, /* Self-check has failed. */
ErrSecFunctionFailed = -67677, /* A function has failed. */
ErrSecModuleManifestVerifyFailed = -67678, /* A module manifest verification failure has occurred. */
ErrSecInvalidGUID = -67679, /* An invalid GUID was encountered. */
ErrSecInvalidHandle = -67680, /* An invalid handle was encountered. */
ErrSecInvalidDBList = -67681, /* An invalid DB list was encountered. */
ErrSecInvalidPassthroughID = -67682, /* An invalid passthrough ID was encountered. */
ErrSecInvalidNetworkAddress = -67683, /* An invalid network address was encountered. */
ErrSecCRLAlreadySigned = -67684, /* The certificate revocation list is already signed. */
ErrSecInvalidNumberOfFields = -67685, /* An invalid number of fields were encountered. */
ErrSecVerificationFailure = -67686, /* A verification failure occurred. */
ErrSecUnknownTag = -67687, /* An unknown tag was encountered. */
ErrSecInvalidSignature = -67688, /* An invalid signature was encountered. */
ErrSecInvalidName = -67689, /* An invalid name was encountered. */
ErrSecInvalidCertificateRef = -67690, /* An invalid certificate reference was encountered. */
ErrSecInvalidCertificateGroup = -67691, /* An invalid certificate group was encountered. */
ErrSecTagNotFound = -67692, /* The specified tag was not found. */
ErrSecInvalidQuery = -67693, /* The specified query was not valid. */
ErrSecInvalidValue = -67694, /* An invalid value was detected. */
ErrSecCallbackFailed = -67695, /* A callback has failed. */
ErrSecACLDeleteFailed = -67696, /* An ACL delete operation has failed. */
ErrSecACLReplaceFailed = -67697, /* An ACL replace operation has failed. */
ErrSecACLAddFailed = -67698, /* An ACL add operation has failed. */
ErrSecACLChangeFailed = -67699, /* An ACL change operation has failed. */
ErrSecInvalidAccessCredentials = -67700, /* Invalid access credentials were encountered. */
ErrSecInvalidRecord = -67701, /* An invalid record was encountered. */
ErrSecInvalidACL = -67702, /* An invalid ACL was encountered. */
ErrSecInvalidSampleValue = -67703, /* An invalid sample value was encountered. */
ErrSecIncompatibleVersion = -67704, /* An incompatible version was encountered. */
ErrSecPrivilegeNotGranted = -67705, /* The privilege was not granted. */
ErrSecInvalidScope = -67706, /* An invalid scope was encountered. */
ErrSecPVCAlreadyConfigured = -67707, /* The PVC is already configured. */
ErrSecInvalidPVC = -67708, /* An invalid PVC was encountered. */
ErrSecEMMLoadFailed = -67709, /* The EMM load has failed. */
ErrSecEMMUnloadFailed = -67710, /* The EMM unload has failed. */
ErrSecAddinLoadFailed = -67711, /* The add-in load operation has failed. */
ErrSecInvalidKeyRef = -67712, /* An invalid key was encountered. */
ErrSecInvalidKeyHierarchy = -67713, /* An invalid key hierarchy was encountered. */
ErrSecAddinUnloadFailed = -67714, /* The add-in unload operation has failed. */
ErrSecLibraryReferenceNotFound = -67715, /* A library reference was not found. */
ErrSecInvalidAddinFunctionTable = -67716, /* An invalid add-in function table was encountered. */
ErrSecInvalidServiceMask = -67717, /* An invalid service mask was encountered. */
ErrSecModuleNotLoaded = -67718, /* A module was not loaded. */
ErrSecInvalidSubServiceID = -67719, /* An invalid subservice ID was encountered. */
ErrSecAttributeNotInContext = -67720, /* An attribute was not in the context. */
ErrSecModuleManagerInitializeFailed = -67721, /* A module failed to initialize. */
ErrSecModuleManagerNotFound = -67722, /* A module was not found. */
ErrSecEventNotificationCallbackNotFound = -67723, /* An event notification callback was not found. */
ErrSecInputLengthError = -67724, /* An input length error was encountered. */
ErrSecOutputLengthError = -67725, /* An output length error was encountered. */
ErrSecPrivilegeNotSupported = -67726, /* The privilege is not supported. */
ErrSecDeviceError = -67727, /* A device error was encountered. */
ErrSecAttachHandleBusy = -67728, /* The CSP handle was busy. */
ErrSecNotLoggedIn = -67729, /* You are not logged in. */
ErrSecAlgorithmMismatch = -67730, /* An algorithm mismatch was encountered. */
ErrSecKeyUsageIncorrect = -67731, /* The key usage is incorrect. */
ErrSecKeyBlobTypeIncorrect = -67732, /* The key blob type is incorrect. */
ErrSecKeyHeaderInconsistent = -67733, /* The key header is inconsistent. */
ErrSecUnsupportedKeyFormat = -67734, /* The key header format is not supported. */
ErrSecUnsupportedKeySize = -67735, /* The key size is not supported. */
ErrSecInvalidKeyUsageMask = -67736, /* The key usage mask is not valid. */
ErrSecUnsupportedKeyUsageMask = -67737, /* The key usage mask is not supported. */
ErrSecInvalidKeyAttributeMask = -67738, /* The key attribute mask is not valid. */
ErrSecUnsupportedKeyAttributeMask = -67739, /* The key attribute mask is not supported. */
ErrSecInvalidKeyLabel = -67740, /* The key label is not valid. */
ErrSecUnsupportedKeyLabel = -67741, /* The key label is not supported. */
ErrSecInvalidKeyFormat = -67742, /* The key format is not valid. */
ErrSecUnsupportedVectorOfBuffers = -67743, /* The vector of buffers is not supported. */
ErrSecInvalidInputVector = -67744, /* The input vector is not valid. */
ErrSecInvalidOutputVector = -67745, /* The output vector is not valid. */
ErrSecInvalidContext = -67746, /* An invalid context was encountered. */
ErrSecInvalidAlgorithm = -67747, /* An invalid algorithm was encountered. */
ErrSecInvalidAttributeKey = -67748, /* A key attribute was not valid. */
ErrSecMissingAttributeKey = -67749, /* A key attribute was missing. */
ErrSecInvalidAttributeInitVector = -67750, /* An init vector attribute was not valid. */
ErrSecMissingAttributeInitVector = -67751, /* An init vector attribute was missing. */
ErrSecInvalidAttributeSalt = -67752, /* A salt attribute was not valid. */
ErrSecMissingAttributeSalt = -67753, /* A salt attribute was missing. */
ErrSecInvalidAttributePadding = -67754, /* A padding attribute was not valid. */
ErrSecMissingAttributePadding = -67755, /* A padding attribute was missing. */
ErrSecInvalidAttributeRandom = -67756, /* A random number attribute was not valid. */
ErrSecMissingAttributeRandom = -67757, /* A random number attribute was missing. */
ErrSecInvalidAttributeSeed = -67758, /* A seed attribute was not valid. */
ErrSecMissingAttributeSeed = -67759, /* A seed attribute was missing. */
ErrSecInvalidAttributePassphrase = -67760, /* A passphrase attribute was not valid. */
ErrSecMissingAttributePassphrase = -67761, /* A passphrase attribute was missing. */
ErrSecInvalidAttributeKeyLength = -67762, /* A key length attribute was not valid. */
ErrSecMissingAttributeKeyLength = -67763, /* A key length attribute was missing. */
ErrSecInvalidAttributeBlockSize = -67764, /* A block size attribute was not valid. */
ErrSecMissingAttributeBlockSize = -67765, /* A block size attribute was missing. */
ErrSecInvalidAttributeOutputSize = -67766, /* An output size attribute was not valid. */
ErrSecMissingAttributeOutputSize = -67767, /* An output size attribute was missing. */
ErrSecInvalidAttributeRounds = -67768, /* The number of rounds attribute was not valid. */
ErrSecMissingAttributeRounds = -67769, /* The number of rounds attribute was missing. */
ErrSecInvalidAlgorithmParms = -67770, /* An algorithm parameters attribute was not valid. */
ErrSecMissingAlgorithmParms = -67771, /* An algorithm parameters attribute was missing. */
ErrSecInvalidAttributeLabel = -67772, /* A label attribute was not valid. */
ErrSecMissingAttributeLabel = -67773, /* A label attribute was missing. */
ErrSecInvalidAttributeKeyType = -67774, /* A key type attribute was not valid. */
ErrSecMissingAttributeKeyType = -67775, /* A key type attribute was missing. */
ErrSecInvalidAttributeMode = -67776, /* A mode attribute was not valid. */
ErrSecMissingAttributeMode = -67777, /* A mode attribute was missing. */
ErrSecInvalidAttributeEffectiveBits = -67778, /* An effective bits attribute was not valid. */
ErrSecMissingAttributeEffectiveBits = -67779, /* An effective bits attribute was missing. */
ErrSecInvalidAttributeStartDate = -67780, /* A start date attribute was not valid. */
ErrSecMissingAttributeStartDate = -67781, /* A start date attribute was missing. */
ErrSecInvalidAttributeEndDate = -67782, /* An end date attribute was not valid. */
ErrSecMissingAttributeEndDate = -67783, /* An end date attribute was missing. */
ErrSecInvalidAttributeVersion = -67784, /* A version attribute was not valid. */
ErrSecMissingAttributeVersion = -67785, /* A version attribute was missing. */
ErrSecInvalidAttributePrime = -67786, /* A prime attribute was not valid. */
ErrSecMissingAttributePrime = -67787, /* A prime attribute was missing. */
ErrSecInvalidAttributeBase = -67788, /* A base attribute was not valid. */
ErrSecMissingAttributeBase = -67789, /* A base attribute was missing. */
ErrSecInvalidAttributeSubprime = -67790, /* A subprime attribute was not valid. */
ErrSecMissingAttributeSubprime = -67791, /* A subprime attribute was missing. */
ErrSecInvalidAttributeIterationCount = -67792, /* An iteration count attribute was not valid. */
ErrSecMissingAttributeIterationCount = -67793, /* An iteration count attribute was missing. */
ErrSecInvalidAttributeDLDBHandle = -67794, /* A database handle attribute was not valid. */
ErrSecMissingAttributeDLDBHandle = -67795, /* A database handle attribute was missing. */
ErrSecInvalidAttributeAccessCredentials = -67796, /* An access credentials attribute was not valid. */
ErrSecMissingAttributeAccessCredentials = -67797, /* An access credentials attribute was missing. */
ErrSecInvalidAttributePublicKeyFormat = -67798, /* A public key format attribute was not valid. */
ErrSecMissingAttributePublicKeyFormat = -67799, /* A public key format attribute was missing. */
ErrSecInvalidAttributePrivateKeyFormat = -67800, /* A private key format attribute was not valid. */
ErrSecMissingAttributePrivateKeyFormat = -67801, /* A private key format attribute was missing. */
ErrSecInvalidAttributeSymmetricKeyFormat = -67802, /* A symmetric key format attribute was not valid. */
ErrSecMissingAttributeSymmetricKeyFormat = -67803, /* A symmetric key format attribute was missing. */
ErrSecInvalidAttributeWrappedKeyFormat = -67804, /* A wrapped key format attribute was not valid. */
ErrSecMissingAttributeWrappedKeyFormat = -67805, /* A wrapped key format attribute was missing. */
ErrSecStagedOperationInProgress = -67806, /* A staged operation is in progress. */
ErrSecStagedOperationNotStarted = -67807, /* A staged operation was not started. */
ErrSecVerifyFailed = -67808, /* A cryptographic verification failure has occurred. */
ErrSecQuerySizeUnknown = -67809, /* The query size is unknown. */
ErrSecBlockSizeMismatch = -67810, /* A block size mismatch occurred. */
ErrSecPublicKeyInconsistent = -67811, /* The public key was inconsistent. */
ErrSecDeviceVerifyFailed = -67812, /* A device verification failure has occurred. */
ErrSecInvalidLoginName = -67813, /* An invalid login name was detected. */
ErrSecAlreadyLoggedIn = -67814, /* The user is already logged in. */
ErrSecInvalidDigestAlgorithm = -67815, /* An invalid digest algorithm was detected. */
ErrSecInvalidCRLGroup = -67816, /* An invalid CRL group was detected. */
ErrSecCertificateCannotOperate = -67817, /* The certificate cannot operate. */
ErrSecCertificateExpired = -67818, /* An expired certificate was detected. */
ErrSecCertificateNotValidYet = -67819, /* The certificate is not yet valid. */
ErrSecCertificateRevoked = -67820, /* The certificate was revoked. */
ErrSecCertificateSuspended = -67821, /* The certificate was suspended. */
ErrSecInsufficientCredentials = -67822, /* Insufficient credentials were detected. */
ErrSecInvalidAction = -67823, /* The action was not valid. */
ErrSecInvalidAuthority = -67824, /* The authority was not valid. */
ErrSecVerifyActionFailed = -67825, /* A verify action has failed. */
ErrSecInvalidCertAuthority = -67826, /* The certificate authority was not valid. */
ErrSecInvaldCRLAuthority = -67827, /* The CRL authority was not valid. */
ErrSecInvalidCRLEncoding = -67828, /* The CRL encoding was not valid. */
ErrSecInvalidCRLType = -67829, /* The CRL type was not valid. */
ErrSecInvalidCRL = -67830, /* The CRL was not valid. */
ErrSecInvalidFormType = -67831, /* The form type was not valid. */
ErrSecInvalidID = -67832, /* The ID was not valid. */
ErrSecInvalidIdentifier = -67833, /* The identifier was not valid. */
ErrSecInvalidIndex = -67834, /* The index was not valid. */
ErrSecInvalidPolicyIdentifiers = -67835, /* The policy identifiers are not valid. */
ErrSecInvalidTimeString = -67836, /* The time specified was not valid. */
ErrSecInvalidReason = -67837, /* The trust policy reason was not valid. */
ErrSecInvalidRequestInputs = -67838, /* The request inputs are not valid. */
ErrSecInvalidResponseVector = -67839, /* The response vector was not valid. */
ErrSecInvalidStopOnPolicy = -67840, /* The stop-on policy was not valid. */
ErrSecInvalidTuple = -67841, /* The tuple was not valid. */
ErrSecMultipleValuesUnsupported = -67842, /* Multiple values are not supported. */
ErrSecNotTrusted = -67843, /* The trust policy was not trusted. */
ErrSecNoDefaultAuthority = -67844, /* No default authority was detected. */
ErrSecRejectedForm = -67845, /* The trust policy had a rejected form. */
ErrSecRequestLost = -67846, /* The request was lost. */
ErrSecRequestRejected = -67847, /* The request was rejected. */
ErrSecUnsupportedAddressType = -67848, /* The address type is not supported. */
ErrSecUnsupportedService = -67849, /* The service is not supported. */
ErrSecInvalidTupleGroup = -67850, /* The tuple group was not valid. */
ErrSecInvalidBaseACLs = -67851, /* The base ACLs are not valid. */
ErrSecInvalidTupleCredendtials = -67852, /* The tuple credentials are not valid. */
ErrSecInvalidEncoding = -67853, /* The encoding was not valid. */
ErrSecInvalidValidityPeriod = -67854, /* The validity period was not valid. */
ErrSecInvalidRequestor = -67855, /* The requestor was not valid. */
ErrSecRequestDescriptor = -67856, /* The request descriptor was not valid. */
ErrSecInvalidBundleInfo = -67857, /* The bundle information was not valid. */
ErrSecInvalidCRLIndex = -67858, /* The CRL index was not valid. */
ErrSecNoFieldValues = -67859, /* No field values were detected. */
ErrSecUnsupportedFieldFormat = -67860, /* The field format is not supported. */
ErrSecUnsupportedIndexInfo = -67861, /* The index information is not supported. */
ErrSecUnsupportedLocality = -67862, /* The locality is not supported. */
ErrSecUnsupportedNumAttributes = -67863, /* The number of attributes is not supported. */
ErrSecUnsupportedNumIndexes = -67864, /* The number of indexes is not supported. */
ErrSecUnsupportedNumRecordTypes = -67865, /* The number of record types is not supported. */
ErrSecFieldSpecifiedMultiple = -67866, /* Too many fields were specified. */
ErrSecIncompatibleFieldFormat = -67867, /* The field format was incompatible. */
ErrSecInvalidParsingModule = -67868, /* The parsing module was not valid. */
ErrSecDatabaseLocked = -67869, /* The database is locked. */
ErrSecDatastoreIsOpen = -67870, /* The data store is open. */
ErrSecMissingValue = -67871, /* A missing value was detected. */
ErrSecUnsupportedQueryLimits = -67872, /* The query limits are not supported. */
ErrSecUnsupportedNumSelectionPreds = -67873, /* The number of selection predicates is not supported. */
ErrSecUnsupportedOperator = -67874, /* The operator is not supported. */
ErrSecInvalidDBLocation = -67875, /* The database location is not valid. */
ErrSecInvalidAccessRequest = -67876, /* The access request is not valid. */
ErrSecInvalidIndexInfo = -67877, /* The index information is not valid. */
ErrSecInvalidNewOwner = -67878, /* The new owner is not valid. */
ErrSecInvalidModifyMode = -67879, /* The modify mode is not valid. */
ErrSecMissingRequiredExtension = -67880, /* A required certificate extension is missing. */
ErrSecExtendedKeyUsageNotCritical = -67881, /* The extended key usage extension was not marked critical. */
ErrSecTimestampMissing = -67882, /* A timestamp was expected but was not found. */
ErrSecTimestampInvalid = -67883, /* The timestamp was not valid. */
ErrSecTimestampNotTrusted = -67884, /* The timestamp was not trusted. */
ErrSecTimestampServiceNotAvailable = -67885, /* The timestamp service is not available. */
ErrSecTimestampBadAlg = -67886, /* An unrecognized or unsupported Algorithm Identifier in timestamp. */
ErrSecTimestampBadRequest = -67887, /* The timestamp transaction is not permitted or supported. */
ErrSecTimestampBadDataFormat = -67888, /* The timestamp data submitted has the wrong format. */
ErrSecTimestampTimeNotAvailable = -67889, /* The time source for the Timestamp Authority is not available. */
ErrSecTimestampUnacceptedPolicy = -67890, /* The requested policy is not supported by the Timestamp Authority. */
ErrSecTimestampUnacceptedExtension = -67891, /* The requested extension is not supported by the Timestamp Authority. */
ErrSecTimestampAddInfoNotAvailable = -67892, /* The additional information requested is not available. */
ErrSecTimestampSystemFailure = -67893, /* The timestamp request cannot be handled due to system failure. */
ErrSecSigningTimeMissing = -67894, /* A signing time was expected but was not found. */
ErrSecTimestampRejection = -67895, /* A timestamp transaction was rejected. */
ErrSecTimestampWaiting = -67896, /* A timestamp transaction is waiting. */
ErrSecTimestampRevocationWarning = -67897, /* A timestamp authority revocation warning was issued. */
ErrSecTimestampRevocationNotification = -67898, /* A timestamp authority revocation notification was issued. */
}
#endregion
}
}
}

View File

@@ -0,0 +1,165 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Runtime.InteropServices;
using Microsoft.SqlTools.ServiceLayer.Credentials.Contracts;
using Microsoft.SqlTools.ServiceLayer.Utility;
namespace Microsoft.SqlTools.ServiceLayer.Credentials.OSX
{
#if !WINDOWS_ONLY_BUILD
/// <summary>
/// OSX implementation of the credential store
/// </summary>
internal class OSXCredentialStore : ICredentialStore
{
public bool DeletePassword(string credentialId)
{
Validate.IsNotNullOrEmptyString("credentialId", credentialId);
return DeletePasswordImpl(credentialId);
}
public bool TryGetPassword(string credentialId, out string password)
{
Validate.IsNotNullOrEmptyString("credentialId", credentialId);
return FindPassword(credentialId, out password);
}
public bool Save(Credential credential)
{
Credential.ValidateForSave(credential);
bool result = false;
// Note: OSX blocks AddPassword if the credential
// already exists, so for now we delete the password if already present since we're updating
// the value. In the future, we could consider updating but it's low value to solve this
DeletePasswordImpl(credential.CredentialId);
// Now add the password
result = AddGenericPassword(credential);
return result;
}
private bool AddGenericPassword(Credential credential)
{
IntPtr passwordPtr = Marshal.StringToCoTaskMemUni(credential.Password);
Interop.Security.OSStatus status = Interop.Security.SecKeychainAddGenericPassword(
IntPtr.Zero,
InteropUtils.GetLengthInBytes(credential.CredentialId),
credential.CredentialId,
0,
null,
InteropUtils.GetLengthInBytes(credential.Password),
passwordPtr,
IntPtr.Zero);
return status == Interop.Security.OSStatus.ErrSecSuccess;
}
/// <summary>
/// Finds the first password matching this credential
/// </summary>
private bool FindPassword(string credentialId, out string password)
{
password = null;
using (KeyChainItemHandle handle = LookupKeyChainItem(credentialId))
{
if( handle == null)
{
return false;
}
password = handle.Password;
}
return true;
}
private KeyChainItemHandle LookupKeyChainItem(string credentialId)
{
UInt32 passwordLength;
IntPtr passwordPtr;
IntPtr item;
Interop.Security.OSStatus status = Interop.Security.SecKeychainFindGenericPassword(
IntPtr.Zero,
InteropUtils.GetLengthInBytes(credentialId),
credentialId,
0,
null,
out passwordLength,
out passwordPtr,
out item);
if(status == Interop.Security.OSStatus.ErrSecSuccess)
{
return new KeyChainItemHandle(item, passwordPtr, passwordLength);
}
return null;
}
private bool DeletePasswordImpl(string credentialId)
{
// Find password, then Delete, then cleanup
using (KeyChainItemHandle handle = LookupKeyChainItem(credentialId))
{
if (handle == null)
{
return false;
}
Interop.Security.OSStatus status = Interop.Security.SecKeychainItemDelete(handle);
return status == Interop.Security.OSStatus.ErrSecSuccess;
}
}
private class KeyChainItemHandle : SafeCreateHandle
{
private IntPtr passwordPtr;
private int passwordLength;
public KeyChainItemHandle() : base()
{
}
public KeyChainItemHandle(IntPtr itemPtr) : this(itemPtr, IntPtr.Zero, 0)
{
}
public KeyChainItemHandle(IntPtr itemPtr, IntPtr passwordPtr, UInt32 passwordLength)
: base(itemPtr)
{
this.passwordPtr = passwordPtr;
this.passwordLength = (int) passwordLength;
}
public string Password
{
get {
if (IsInvalid)
{
return null;
}
return InteropUtils.CopyToString(passwordPtr, passwordLength);
}
}
protected override bool ReleaseHandle()
{
if (passwordPtr != IntPtr.Zero)
{
Interop.Security.SecKeychainItemFreeContent(IntPtr.Zero, passwordPtr);
}
base.ReleaseHandle();
return true;
}
}
}
#endif
}

View File

@@ -0,0 +1,43 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Runtime.InteropServices;
namespace Microsoft.SqlTools.ServiceLayer.Credentials
{
/// <summary>
/// This class is a wrapper around the Create pattern in OS X where
/// if a Create* function is called, the caller must also CFRelease
/// on the same pointer in order to correctly free the memory.
/// </summary>
[System.Security.SecurityCritical]
internal partial class SafeCreateHandle : SafeHandle
{
internal SafeCreateHandle() : base(IntPtr.Zero, true) { }
internal SafeCreateHandle(IntPtr ptr) : base(IntPtr.Zero, true)
{
this.SetHandle(ptr);
}
[System.Security.SecurityCritical]
protected override bool ReleaseHandle()
{
Interop.CoreFoundation.CFRelease(handle);
return true;
}
public override bool IsInvalid
{
[System.Security.SecurityCritical]
get
{
return handle == IntPtr.Zero;
}
}
}
}

View File

@@ -0,0 +1,42 @@
//
// Code originally from http://credentialmanagement.codeplex.com/,
// Licensed under the Apache License 2.0
//
using System;
using System.Runtime.InteropServices;
using System.Security;
namespace Microsoft.SqlTools.ServiceLayer.Credentials.Win32
{
internal static class SecureStringHelper
{
// Methods
internal static SecureString CreateSecureString(string plainString)
{
SecureString str = new SecureString();
if (!string.IsNullOrEmpty(plainString))
{
foreach (char c in plainString)
{
str.AppendChar(c);
}
}
str.MakeReadOnly();
return str;
}
internal static string CreateString(SecureString value)
{
IntPtr ptr = SecureStringMarshal.SecureStringToGlobalAllocUnicode(value);
try
{
return Marshal.PtrToStringUni(ptr);
}
finally
{
Marshal.ZeroFreeGlobalAllocUnicode(ptr);
}
}
}
}

View File

@@ -0,0 +1,113 @@
//
// Code originally from http://credentialmanagement.codeplex.com/,
// Licensed under the Apache License 2.0
//
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.SqlTools.ServiceLayer.Utility;
namespace Microsoft.SqlTools.ServiceLayer.Credentials.Win32
{
public class CredentialSet: List<Win32Credential>, IDisposable
{
bool _disposed;
public CredentialSet()
{
}
public CredentialSet(string target)
: this()
{
if (string.IsNullOrEmpty(target))
{
throw new ArgumentNullException(nameof(target));
}
Target = target;
}
public string Target { get; set; }
public void Dispose()
{
Dispose(true);
// Prevent GC Collection since we have already disposed of this object
GC.SuppressFinalize(this);
}
~CredentialSet()
{
Dispose(false);
}
private void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
if (Count > 0)
{
ForEach(cred => cred.Dispose());
}
}
}
_disposed = true;
}
public CredentialSet Load()
{
LoadInternal();
return this;
}
private void LoadInternal()
{
uint count;
IntPtr pCredentials = IntPtr.Zero;
bool result = NativeMethods.CredEnumerateW(Target, 0, out count, out pCredentials);
if (!result)
{
Logger.Write(LogLevel.Error, string.Format("Win32Exception: {0}", new Win32Exception(Marshal.GetLastWin32Error()).ToString()));
return;
}
// Read in all of the pointers first
IntPtr[] ptrCredList = new IntPtr[count];
for (int i = 0; i < count; i++)
{
ptrCredList[i] = Marshal.ReadIntPtr(pCredentials, IntPtr.Size*i);
}
// Now let's go through all of the pointers in the list
// and create our Credential object(s)
List<NativeMethods.CriticalCredentialHandle> credentialHandles =
ptrCredList.Select(ptrCred => new NativeMethods.CriticalCredentialHandle(ptrCred)).ToList();
IEnumerable<Win32Credential> existingCredentials = credentialHandles
.Select(handle => handle.GetCredential())
.Select(nativeCredential =>
{
Win32Credential credential = new Win32Credential();
credential.LoadInternal(nativeCredential);
return credential;
});
AddRange(existingCredentials);
// The individual credentials should not be free'd
credentialHandles.ForEach(handle => handle.SetHandleAsInvalid());
// Clean up memory to the Enumeration pointer
NativeMethods.CredFree(pCredentials);
}
}
}

View File

@@ -0,0 +1,16 @@
//
// Code originally from http://credentialmanagement.codeplex.com/,
// Licensed under the Apache License 2.0
//
namespace Microsoft.SqlTools.ServiceLayer.Credentials.Win32
{
public enum CredentialType: uint
{
None = 0,
Generic = 1,
DomainPassword = 2,
DomainCertificate = 3,
DomainVisiblePassword = 4
}
}

View File

@@ -0,0 +1,17 @@
// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
//
// To add a suppression to this file, right-click the message in the
// Code Analysis results, point to "Suppress Message", and click
// "In Suppression File".
// You do not need to add suppressions to this file manually.
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Scope = "member", Target = "CredentialManagement.CredentialSet.#LoadInternal()")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1049:TypesThatOwnNativeResourcesShouldBeDisposable", Scope = "type", Target = "CredentialManagement.NativeMethods+CREDENTIAL")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", MessageId = "7", Scope = "member", Target = "CredentialManagement.NativeMethods.#CredUnPackAuthenticationBuffer(System.Int32,System.IntPtr,System.UInt32,System.Text.StringBuilder,System.Int32&,System.Text.StringBuilder,System.Int32&,System.Text.StringBuilder,System.Int32&)")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", MessageId = "5", Scope = "member", Target = "CredentialManagement.NativeMethods.#CredUnPackAuthenticationBuffer(System.Int32,System.IntPtr,System.UInt32,System.Text.StringBuilder,System.Int32&,System.Text.StringBuilder,System.Int32&,System.Text.StringBuilder,System.Int32&)")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", MessageId = "3", Scope = "member", Target = "CredentialManagement.NativeMethods.#CredUnPackAuthenticationBuffer(System.Int32,System.IntPtr,System.UInt32,System.Text.StringBuilder,System.Int32&,System.Text.StringBuilder,System.Int32&,System.Text.StringBuilder,System.Int32&)")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Scope = "member", Target = "CredentialManagement.SecureStringHelper.#CreateString(System.Security.SecureString)")]
<EFBFBD>

View File

@@ -0,0 +1,110 @@
//
// Code originally from http://credentialmanagement.codeplex.com/,
// Licensed under the Apache License 2.0
//
using System;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.SqlTools.Credentials;
namespace Microsoft.SqlTools.ServiceLayer.Credentials.Win32
{
internal class NativeMethods
{
[StructLayout(LayoutKind.Sequential)]
internal struct CREDENTIAL
{
public int Flags;
public int Type;
[MarshalAs(UnmanagedType.LPWStr)]
public string TargetName;
[MarshalAs(UnmanagedType.LPWStr)]
public string Comment;
public long LastWritten;
public int CredentialBlobSize;
public IntPtr CredentialBlob;
public int Persist;
public int AttributeCount;
public IntPtr Attributes;
[MarshalAs(UnmanagedType.LPWStr)]
public string TargetAlias;
[MarshalAs(UnmanagedType.LPWStr)]
public string UserName;
}
[DllImport("Advapi32.dll", EntryPoint = "CredReadW", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern bool CredRead(string target, CredentialType type, int reservedFlag, out IntPtr CredentialPtr);
[DllImport("Advapi32.dll", EntryPoint = "CredWriteW", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern bool CredWrite([In] ref CREDENTIAL userCredential, [In] UInt32 flags);
[DllImport("Advapi32.dll", EntryPoint = "CredFree", SetLastError = true)]
internal static extern bool CredFree([In] IntPtr cred);
[DllImport("advapi32.dll", EntryPoint = "CredDeleteW", CharSet = CharSet.Unicode)]
internal static extern bool CredDelete(StringBuilder target, CredentialType type, int flags);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool CredEnumerateW(string filter, int flag, out uint count, out IntPtr pCredentials);
[DllImport("ole32.dll")]
internal static extern void CoTaskMemFree(IntPtr ptr);
internal abstract class CriticalHandleZeroOrMinusOneIsInvalid : CriticalHandle
{
protected CriticalHandleZeroOrMinusOneIsInvalid() : base(IntPtr.Zero)
{
}
public override bool IsInvalid
{
get { return handle == new IntPtr(0) || handle == new IntPtr(-1); }
}
}
internal sealed class CriticalCredentialHandle : CriticalHandleZeroOrMinusOneIsInvalid
{
// Set the handle.
internal CriticalCredentialHandle(IntPtr preexistingHandle)
{
SetHandle(preexistingHandle);
}
internal CREDENTIAL GetCredential()
{
if (!IsInvalid)
{
// Get the Credential from the mem location
return (CREDENTIAL)Marshal.PtrToStructure<CREDENTIAL>(handle);
}
else
{
throw new InvalidOperationException(SR.CredentialsServiceInvalidCriticalHandle);
}
}
// Perform any specific actions to release the handle in the ReleaseHandle method.
// Often, you need to use Pinvoke to make a call into the Win32 API to release the
// handle. In this case, however, we can use the Marshal class to release the unmanaged memory.
protected override bool ReleaseHandle()
{
// If the handle was set, free it. Return success.
if (!IsInvalid)
{
// NOTE: We should also ZERO out the memory allocated to the handle, before free'ing it
// so there are no traces of the sensitive data left in memory.
CredFree(handle);
// Mark the handle as invalid for future users.
SetHandleAsInvalid();
return true;
}
// Return false.
return false;
}
}
}
}

View File

@@ -0,0 +1,14 @@
//
// Code originally from http://credentialmanagement.codeplex.com/,
// Licensed under the Apache License 2.0
//
namespace Microsoft.SqlTools.ServiceLayer.Credentials.Win32
{
public enum PersistanceType : uint
{
Session = 1,
LocalComputer = 2,
Enterprise = 3
}
}

View File

@@ -0,0 +1,291 @@
//
// Code originally from http://credentialmanagement.codeplex.com/,
// Licensed under the Apache License 2.0
//
using System;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using Microsoft.SqlTools.Credentials;
namespace Microsoft.SqlTools.ServiceLayer.Credentials.Win32
{
public class Win32Credential: IDisposable
{
bool disposed;
CredentialType type;
string target;
SecureString password;
string username;
string description;
DateTime lastWriteTime;
PersistanceType persistanceType;
public Win32Credential()
: this(null)
{
}
public Win32Credential(string username)
: this(username, null)
{
}
public Win32Credential(string username, string password)
: this(username, password, null)
{
}
public Win32Credential(string username, string password, string target)
: this(username, password, target, CredentialType.Generic)
{
}
public Win32Credential(string username, string password, string target, CredentialType type)
{
Username = username;
Password = password;
Target = target;
Type = type;
PersistanceType = PersistanceType.Session;
lastWriteTime = DateTime.MinValue;
}
public void Dispose()
{
Dispose(true);
// Prevent GC Collection since we have already disposed of this object
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
SecurePassword.Clear();
SecurePassword.Dispose();
}
}
disposed = true;
}
private void CheckNotDisposed()
{
if (disposed)
{
throw new ObjectDisposedException(SR.CredentialServiceWin32CredentialDisposed);
}
}
public string Username {
get
{
CheckNotDisposed();
return username;
}
set
{
CheckNotDisposed();
username = value;
}
}
public string Password
{
get
{
return SecureStringHelper.CreateString(SecurePassword);
}
set
{
CheckNotDisposed();
SecurePassword = SecureStringHelper.CreateSecureString(string.IsNullOrEmpty(value) ? string.Empty : value);
}
}
public SecureString SecurePassword
{
get
{
CheckNotDisposed();
return null == password ? new SecureString() : password.Copy();
}
set
{
CheckNotDisposed();
if (null != password)
{
password.Clear();
password.Dispose();
}
password = null == value ? new SecureString() : value.Copy();
}
}
public string Target
{
get
{
CheckNotDisposed();
return target;
}
set
{
CheckNotDisposed();
target = value;
}
}
public string Description
{
get
{
CheckNotDisposed();
return description;
}
set
{
CheckNotDisposed();
description = value;
}
}
public DateTime LastWriteTime
{
get
{
return LastWriteTimeUtc.ToLocalTime();
}
}
public DateTime LastWriteTimeUtc
{
get
{
CheckNotDisposed();
return lastWriteTime;
}
private set { lastWriteTime = value; }
}
public CredentialType Type
{
get
{
CheckNotDisposed();
return type;
}
set
{
CheckNotDisposed();
type = value;
}
}
public PersistanceType PersistanceType
{
get
{
CheckNotDisposed();
return persistanceType;
}
set
{
CheckNotDisposed();
persistanceType = value;
}
}
public bool Save()
{
CheckNotDisposed();
byte[] passwordBytes = Encoding.Unicode.GetBytes(Password);
if (Password.Length > (512))
{
throw new ArgumentOutOfRangeException(SR.CredentialsServicePasswordLengthExceeded);
}
NativeMethods.CREDENTIAL credential = new NativeMethods.CREDENTIAL();
credential.TargetName = Target;
credential.UserName = Username;
credential.CredentialBlob = Marshal.StringToCoTaskMemUni(Password);
credential.CredentialBlobSize = passwordBytes.Length;
credential.Comment = Description;
credential.Type = (int)Type;
credential.Persist = (int) PersistanceType;
bool result = NativeMethods.CredWrite(ref credential, 0);
if (!result)
{
return false;
}
LastWriteTimeUtc = DateTime.UtcNow;
return true;
}
public bool Delete()
{
CheckNotDisposed();
if (string.IsNullOrEmpty(Target))
{
throw new InvalidOperationException(SR.CredentialsServiceTargetForDelete);
}
StringBuilder target = string.IsNullOrEmpty(Target) ? new StringBuilder() : new StringBuilder(Target);
bool result = NativeMethods.CredDelete(target, Type, 0);
return result;
}
public bool Load()
{
CheckNotDisposed();
IntPtr credPointer;
bool result = NativeMethods.CredRead(Target, Type, 0, out credPointer);
if (!result)
{
return false;
}
using (NativeMethods.CriticalCredentialHandle credentialHandle = new NativeMethods.CriticalCredentialHandle(credPointer))
{
LoadInternal(credentialHandle.GetCredential());
}
return true;
}
public bool Exists()
{
CheckNotDisposed();
if (string.IsNullOrEmpty(Target))
{
throw new InvalidOperationException(SR.CredentialsServiceTargetForLookup);
}
using (Win32Credential existing = new Win32Credential { Target = Target, Type = Type })
{
return existing.Load();
}
}
internal void LoadInternal(NativeMethods.CREDENTIAL credential)
{
Username = credential.UserName;
if (credential.CredentialBlobSize > 0)
{
Password = Marshal.PtrToStringUni(credential.CredentialBlob, credential.CredentialBlobSize / 2);
}
Target = credential.TargetName;
Type = (CredentialType)credential.Type;
PersistanceType = (PersistanceType)credential.Persist;
Description = credential.Comment;
LastWriteTimeUtc = DateTime.FromFileTimeUtc(credential.LastWritten);
}
}
}

View File

@@ -0,0 +1,63 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlTools.ServiceLayer.Credentials.Contracts;
using Microsoft.SqlTools.ServiceLayer.Utility;
namespace Microsoft.SqlTools.ServiceLayer.Credentials.Win32
{
/// <summary>
/// Win32 implementation of the credential store
/// </summary>
internal class Win32CredentialStore : ICredentialStore
{
private const string AnyUsername = "*";
public bool DeletePassword(string credentialId)
{
using (Win32Credential cred = new Win32Credential() { Target = credentialId, Username = AnyUsername })
{
return cred.Delete();
}
}
public bool TryGetPassword(string credentialId, out string password)
{
Validate.IsNotNullOrEmptyString("credentialId", credentialId);
password = null;
using (CredentialSet set = new CredentialSet(credentialId).Load())
{
// Note: Credentials are disposed on disposal of the set
Win32Credential foundCred = null;
if (set.Count > 0)
{
foundCred = set[0];
}
if (foundCred != null)
{
password = foundCred.Password;
return true;
}
return false;
}
}
public bool Save(Credential credential)
{
Credential.ValidateForSave(credential);
using (Win32Credential cred =
new Win32Credential(AnyUsername, credential.Password, credential.CredentialId, CredentialType.Generic)
{ PersistanceType = PersistanceType.LocalComputer })
{
return cred.Save();
}
}
}
}

View File

@@ -0,0 +1,86 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.SqlTools.ServiceLayer.Credentials;
using Microsoft.SqlTools.ServiceLayer.Extensibility;
using Microsoft.SqlTools.ServiceLayer.Hosting;
using Microsoft.SqlTools.ServiceLayer.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.SqlContext;
namespace Microsoft.SqlTools.Credentials
{
/// <summary>
/// Provides support for starting up a service host. This is a common responsibility
/// for both the main service program and test driver that interacts with it
/// </summary>
public static class HostLoader
{
private static object lockObject = new object();
private static bool isLoaded;
internal static ServiceHost CreateAndStartServiceHost(SqlToolsContext sqlToolsContext)
{
ServiceHost serviceHost = ServiceHost.Instance;
lock (lockObject)
{
if (!isLoaded)
{
// Grab the instance of the service host
serviceHost.Initialize();
InitializeRequestHandlersAndServices(serviceHost, sqlToolsContext);
// Start the service only after all request handlers are setup. This is vital
// as otherwise the Initialize event can be lost - it's processed and discarded before the handler
// is hooked up to receive the message
serviceHost.Start().Wait();
isLoaded = true;
}
}
return serviceHost;
}
private static void InitializeRequestHandlersAndServices(ServiceHost serviceHost, SqlToolsContext sqlToolsContext)
{
// Load extension provider, which currently finds all exports in current DLL. Can be changed to find based
// on directory or assembly list quite easily in the future
ExtensionServiceProvider serviceProvider = ExtensionServiceProvider.CreateDefaultServiceProvider();
serviceProvider.RegisterSingleService(sqlToolsContext);
serviceProvider.RegisterSingleService(serviceHost);
CredentialService.Instance.InitializeService(serviceHost);
serviceProvider.RegisterSingleService(CredentialService.Instance);
InitializeHostedServices(serviceProvider, serviceHost);
serviceHost.InitializeRequestHandlers();
}
/// <summary>
/// Internal to support testing. Initializes <see cref="IHostedService"/> instances in the service,
/// and registers them for their preferred service type
/// </summary>
internal static void InitializeHostedServices(RegisteredServiceProvider provider, IProtocolEndpoint host)
{
// Pre-register all services before initializing. This ensures that if one service wishes to reference
// another one during initialization, it will be able to safely do so
foreach (IHostedService service in provider.GetServices<IHostedService>())
{
provider.RegisterSingleService(service.ServiceType, service);
}
foreach (IHostedService service in provider.GetServices<IHostedService>())
{
// Initialize all hosted services, and register them in the service provider for their requested
// service type. This ensures that when searching for the ConnectionService you can get it without
// searching for an IHostedService of type ConnectionService
service.InitializeService(host);
}
}
}
}

View File

@@ -0,0 +1,953 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Microsoft.SqlTools.Credentials.Localization {
using System;
using System.Reflection;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class sr {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
internal sr() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.SqlTools.ServiceLayer.Localization.sr", typeof(sr).GetTypeInfo().Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to File &apos;{0}&apos; recursively included..
/// </summary>
public static string BatchParser_CircularReference {
get {
return ResourceManager.GetString("BatchParser_CircularReference", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Missing end comment mark &apos;*/&apos;..
/// </summary>
public static string BatchParser_CommentNotTerminated {
get {
return ResourceManager.GetString("BatchParser_CommentNotTerminated", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Incorrect syntax was encountered while parsing &apos;{0}&apos;..
/// </summary>
public static string BatchParser_IncorrectSyntax {
get {
return ResourceManager.GetString("BatchParser_IncorrectSyntax", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Unclosed quotation mark after the character string..
/// </summary>
public static string BatchParser_StringNotTerminated {
get {
return ResourceManager.GetString("BatchParser_StringNotTerminated", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Variable {0} is not defined..
/// </summary>
public static string BatchParser_VariableNotDefined {
get {
return ResourceManager.GetString("BatchParser_VariableNotDefined", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Canceling batch parser wrapper batch execution..
/// </summary>
public static string BatchParserWrapperExecutionEngineBatchCancelling {
get {
return ResourceManager.GetString("BatchParserWrapperExecutionEngineBatchCancelling", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Batch parser wrapper execution engine batch message received: Message: {0} Detailed message: {1}.
/// </summary>
public static string BatchParserWrapperExecutionEngineBatchMessage {
get {
return ResourceManager.GetString("BatchParserWrapperExecutionEngineBatchMessage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Batch parser wrapper execution engine batch ResultSet finished..
/// </summary>
public static string BatchParserWrapperExecutionEngineBatchResultSetFinished {
get {
return ResourceManager.GetString("BatchParserWrapperExecutionEngineBatchResultSetFinished", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Batch parser wrapper execution engine batch ResultSet processing: DataReader.FieldCount: {0} DataReader.RecordsAffected: {1}.
/// </summary>
public static string BatchParserWrapperExecutionEngineBatchResultSetProcessing {
get {
return ResourceManager.GetString("BatchParserWrapperExecutionEngineBatchResultSetProcessing", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to SQL Execution error: {0}.
/// </summary>
public static string BatchParserWrapperExecutionEngineError {
get {
return ResourceManager.GetString("BatchParserWrapperExecutionEngineError", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Batch parser wrapper execution: {0} found... at line {1}: {2} Description: {3}.
/// </summary>
public static string BatchParserWrapperExecutionError {
get {
return ResourceManager.GetString("BatchParserWrapperExecutionError", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Connection details object cannot be null.
/// </summary>
public static string ConnectionParamsValidateNullConnection {
get {
return ResourceManager.GetString("ConnectionParamsValidateNullConnection", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to OwnerUri cannot be null or empty.
/// </summary>
public static string ConnectionParamsValidateNullOwnerUri {
get {
return ResourceManager.GetString("ConnectionParamsValidateNullOwnerUri", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to ServerName cannot be null or empty.
/// </summary>
public static string ConnectionParamsValidateNullServerName {
get {
return ResourceManager.GetString("ConnectionParamsValidateNullServerName", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to {0} cannot be null or empty when using SqlLogin authentication.
/// </summary>
public static string ConnectionParamsValidateNullSqlAuth {
get {
return ResourceManager.GetString("ConnectionParamsValidateNullSqlAuth", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Connection parameters cannot be null.
/// </summary>
public static string ConnectionServiceConnectErrorNullParams {
get {
return ResourceManager.GetString("ConnectionServiceConnectErrorNullParams", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Connection canceled.
/// </summary>
public static string ConnectionServiceConnectionCanceled {
get {
return ResourceManager.GetString("ConnectionServiceConnectionCanceled", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Invalid value &apos;{0}&apos; for AuthenticationType. Valid values are &apos;Integrated&apos; and &apos;SqlLogin&apos;..
/// </summary>
public static string ConnectionServiceConnStringInvalidAuthType {
get {
return ResourceManager.GetString("ConnectionServiceConnStringInvalidAuthType", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Invalid value &apos;{0}&apos; for ApplicationIntent. Valid values are &apos;ReadWrite&apos; and &apos;ReadOnly&apos;..
/// </summary>
public static string ConnectionServiceConnStringInvalidIntent {
get {
return ResourceManager.GetString("ConnectionServiceConnStringInvalidIntent", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to SpecifiedUri &apos;{0}&apos; does not have existing connection.
/// </summary>
public static string ConnectionServiceListDbErrorNotConnected {
get {
return ResourceManager.GetString("ConnectionServiceListDbErrorNotConnected", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to OwnerUri cannot be null or empty.
/// </summary>
public static string ConnectionServiceListDbErrorNullOwnerUri {
get {
return ResourceManager.GetString("ConnectionServiceListDbErrorNullOwnerUri", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Win32Credential object is already disposed.
/// </summary>
public static string CredentialServiceWin32CredentialDisposed {
get {
return ResourceManager.GetString("CredentialServiceWin32CredentialDisposed", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Invalid CriticalHandle!.
/// </summary>
public static string CredentialsServiceInvalidCriticalHandle {
get {
return ResourceManager.GetString("CredentialsServiceInvalidCriticalHandle", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The password has exceeded 512 bytes.
/// </summary>
public static string CredentialsServicePasswordLengthExceeded {
get {
return ResourceManager.GetString("CredentialsServicePasswordLengthExceeded", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Target must be specified to delete a credential.
/// </summary>
public static string CredentialsServiceTargetForDelete {
get {
return ResourceManager.GetString("CredentialsServiceTargetForDelete", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Target must be specified to check existance of a credential.
/// </summary>
public static string CredentialsServiceTargetForLookup {
get {
return ResourceManager.GetString("CredentialsServiceTargetForLookup", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to An error occurred while the batch was being processed. The error message is: {0}.
/// </summary>
public static string EE_BatchError_Exception {
get {
return ResourceManager.GetString("EE_BatchError_Exception", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to An error occurred while the batch was being executed..
/// </summary>
public static string EE_BatchExecutionError_Halting {
get {
return ResourceManager.GetString("EE_BatchExecutionError_Halting", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to An error occurred while the batch was being executed, but the error has been ignored..
/// </summary>
public static string EE_BatchExecutionError_Ignoring {
get {
return ResourceManager.GetString("EE_BatchExecutionError_Ignoring", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to ({0} row(s) affected).
/// </summary>
public static string EE_BatchExecutionInfo_RowsAffected {
get {
return ResourceManager.GetString("EE_BatchExecutionInfo_RowsAffected", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Msg {0}, Level {1}, State {2}.
/// </summary>
public static string EE_BatchSqlMessageNoLineInfo {
get {
return ResourceManager.GetString("EE_BatchSqlMessageNoLineInfo", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Msg {0}, Level {1}, State {2}, Line {3}.
/// </summary>
public static string EE_BatchSqlMessageNoProcedureInfo {
get {
return ResourceManager.GetString("EE_BatchSqlMessageNoProcedureInfo", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Msg {0}, Level {1}, State {2}, Procedure {3}, Line {4}.
/// </summary>
public static string EE_BatchSqlMessageWithProcedureInfo {
get {
return ResourceManager.GetString("EE_BatchSqlMessageWithProcedureInfo", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Command {0} is not supported..
/// </summary>
public static string EE_ExecutionError_CommandNotSupported {
get {
return ResourceManager.GetString("EE_ExecutionError_CommandNotSupported", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The variable {0} could not be found..
/// </summary>
public static string EE_ExecutionError_VariableNotFound {
get {
return ResourceManager.GetString("EE_ExecutionError_VariableNotFound", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Execution completed {0} times....
/// </summary>
public static string EE_ExecutionInfo_FinalizingLoop {
get {
return ResourceManager.GetString("EE_ExecutionInfo_FinalizingLoop", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Starting execution loop of {0} times....
/// </summary>
public static string EE_ExecutionInfo_InitilizingLoop {
get {
return ResourceManager.GetString("EE_ExecutionInfo_InitilizingLoop", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to You cancelled the query..
/// </summary>
public static string EE_ExecutionInfo_QueryCancelledbyUser {
get {
return ResourceManager.GetString("EE_ExecutionInfo_QueryCancelledbyUser", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The previous execution is not yet complete..
/// </summary>
public static string EE_ExecutionNotYetCompleteError {
get {
return ResourceManager.GetString("EE_ExecutionNotYetCompleteError", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to A scripting error occurred..
/// </summary>
public static string EE_ScriptError_Error {
get {
return ResourceManager.GetString("EE_ScriptError_Error", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to A fatal error occurred..
/// </summary>
public static string EE_ScriptError_FatalError {
get {
return ResourceManager.GetString("EE_ScriptError_FatalError", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Incorrect syntax was encountered while {0} was being parsed..
/// </summary>
public static string EE_ScriptError_ParsingSyntax {
get {
return ResourceManager.GetString("EE_ScriptError_ParsingSyntax", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Scripting warning..
/// </summary>
public static string EE_ScriptError_Warning {
get {
return ResourceManager.GetString("EE_ScriptError_Warning", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Replacement of an empty string by an empty string..
/// </summary>
public static string ErrorEmptyStringReplacement {
get {
return ResourceManager.GetString("ErrorEmptyStringReplacement", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cannot convert SqlCodeObject Type {0} to Type {1}.
/// </summary>
public static string ErrorUnexpectedCodeObjectType {
get {
return ResourceManager.GetString("ErrorUnexpectedCodeObjectType", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Message header must separate key and value using &apos;:&apos;.
/// </summary>
public static string HostingHeaderMissingColon {
get {
return ResourceManager.GetString("HostingHeaderMissingColon", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Fatal error: Content-Length header must be provided.
/// </summary>
public static string HostingHeaderMissingContentLengthHeader {
get {
return ResourceManager.GetString("HostingHeaderMissingContentLengthHeader", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Fatal error: Content-Length value is not an integer.
/// </summary>
public static string HostingHeaderMissingContentLengthValue {
get {
return ResourceManager.GetString("HostingHeaderMissingContentLengthValue", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to MessageReader&apos;s input stream ended unexpectedly, terminating.
/// </summary>
public static string HostingUnexpectedEndOfStream {
get {
return ResourceManager.GetString("HostingUnexpectedEndOfStream", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Service of type {0} cannot be created by ExtensionLoader&lt;{1}&gt;.
/// </summary>
public static string IncompatibleServiceForExtensionLoader {
get {
return ResourceManager.GetString("IncompatibleServiceForExtensionLoader", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Multiple services found for type {0}, expected only 1.
/// </summary>
public static string MultipleServicesFound {
get {
return ResourceManager.GetString("MultipleServicesFound", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to This feature is currently not supported on Azure SQL DB and Data Warehouse: {0}.
/// </summary>
public static string PeekDefinitionAzureError {
get {
return ResourceManager.GetString("PeekDefinitionAzureError", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to No database object was retrieved..
/// </summary>
public static string PeekDefinitionDatabaseError {
get {
return ResourceManager.GetString("PeekDefinitionDatabaseError", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to An unexpected error occurred during Peek Definition execution: {0}.
/// </summary>
public static string PeekDefinitionError {
get {
return ResourceManager.GetString("PeekDefinitionError", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to No results were found..
/// </summary>
public static string PeekDefinitionNoResultsError {
get {
return ResourceManager.GetString("PeekDefinitionNoResultsError", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Please connect to a server..
/// </summary>
public static string PeekDefinitionNotConnectedError {
get {
return ResourceManager.GetString("PeekDefinitionNotConnectedError", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Operation timed out..
/// </summary>
public static string PeekDefinitionTimedoutError {
get {
return ResourceManager.GetString("PeekDefinitionTimedoutError", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to This object type is currently not supported by this feature..
/// </summary>
public static string PeekDefinitionTypeNotSupportedError {
get {
return ResourceManager.GetString("PeekDefinitionTypeNotSupportedError", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to (1 row affected).
/// </summary>
public static string QueryServiceAffectedOneRow {
get {
return ResourceManager.GetString("QueryServiceAffectedOneRow", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to ({0} rows affected).
/// </summary>
public static string QueryServiceAffectedRows {
get {
return ResourceManager.GetString("QueryServiceAffectedRows", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The query has already completed, it cannot be cancelled.
/// </summary>
public static string QueryServiceCancelAlreadyCompleted {
get {
return ResourceManager.GetString("QueryServiceCancelAlreadyCompleted", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Query successfully cancelled, failed to dispose query. Owner URI not found..
/// </summary>
public static string QueryServiceCancelDisposeFailed {
get {
return ResourceManager.GetString("QueryServiceCancelDisposeFailed", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to (No column name).
/// </summary>
public static string QueryServiceColumnNull {
get {
return ResourceManager.GetString("QueryServiceColumnNull", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Commands completed successfully..
/// </summary>
public static string QueryServiceCompletedSuccessfully {
get {
return ResourceManager.GetString("QueryServiceCompletedSuccessfully", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Maximum number of bytes to return must be greater than zero.
/// </summary>
public static string QueryServiceDataReaderByteCountInvalid {
get {
return ResourceManager.GetString("QueryServiceDataReaderByteCountInvalid", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Maximum number of chars to return must be greater than zero.
/// </summary>
public static string QueryServiceDataReaderCharCountInvalid {
get {
return ResourceManager.GetString("QueryServiceDataReaderCharCountInvalid", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Maximum number of XML bytes to return must be greater than zero.
/// </summary>
public static string QueryServiceDataReaderXmlCountInvalid {
get {
return ResourceManager.GetString("QueryServiceDataReaderXmlCountInvalid", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Msg {0}, Level {1}, State {2}, Line {3}{4}{5}.
/// </summary>
public static string QueryServiceErrorFormat {
get {
return ResourceManager.GetString("QueryServiceErrorFormat", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Could not retrieve an execution plan from the result set .
/// </summary>
public static string QueryServiceExecutionPlanNotFound {
get {
return ResourceManager.GetString("QueryServiceExecutionPlanNotFound", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to FileStreamWrapper must be initialized before performing operations.
/// </summary>
public static string QueryServiceFileWrapperNotInitialized {
get {
return ResourceManager.GetString("QueryServiceFileWrapperNotInitialized", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to This FileStreamWrapper cannot be used for writing.
/// </summary>
public static string QueryServiceFileWrapperReadOnly {
get {
return ResourceManager.GetString("QueryServiceFileWrapperReadOnly", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Access method cannot be write-only.
/// </summary>
public static string QueryServiceFileWrapperWriteOnly {
get {
return ResourceManager.GetString("QueryServiceFileWrapperWriteOnly", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Sender for OnInfoMessage event must be a SqlConnection.
/// </summary>
public static string QueryServiceMessageSenderNotSql {
get {
return ResourceManager.GetString("QueryServiceMessageSenderNotSql", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Query was canceled by user.
/// </summary>
public static string QueryServiceQueryCancelled {
get {
return ResourceManager.GetString("QueryServiceQueryCancelled", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Query failed: {0}.
/// </summary>
public static string QueryServiceQueryFailed {
get {
return ResourceManager.GetString("QueryServiceQueryFailed", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to A query is already in progress for this editor session. Please cancel this query or wait for its completion..
/// </summary>
public static string QueryServiceQueryInProgress {
get {
return ResourceManager.GetString("QueryServiceQueryInProgress", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to This editor is not connected to a database.
/// </summary>
public static string QueryServiceQueryInvalidOwnerUri {
get {
return ResourceManager.GetString("QueryServiceQueryInvalidOwnerUri", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The requested query does not exist.
/// </summary>
public static string QueryServiceRequestsNoQuery {
get {
return ResourceManager.GetString("QueryServiceRequestsNoQuery", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Could not retrieve column schema for result set.
/// </summary>
public static string QueryServiceResultSetNoColumnSchema {
get {
return ResourceManager.GetString("QueryServiceResultSetNoColumnSchema", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cannot read subset unless the results have been read from the server.
/// </summary>
public static string QueryServiceResultSetNotRead {
get {
return ResourceManager.GetString("QueryServiceResultSetNotRead", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Reader cannot be null.
/// </summary>
public static string QueryServiceResultSetReaderNull {
get {
return ResourceManager.GetString("QueryServiceResultSetReaderNull", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Row count must be a positive integer.
/// </summary>
public static string QueryServiceResultSetRowCountOutOfRange {
get {
return ResourceManager.GetString("QueryServiceResultSetRowCountOutOfRange", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Start row cannot be less than 0 or greater than the number of rows in the result set.
/// </summary>
public static string QueryServiceResultSetStartRowOutOfRange {
get {
return ResourceManager.GetString("QueryServiceResultSetStartRowOutOfRange", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Failed to save {0}: {1}.
/// </summary>
public static string QueryServiceSaveAsFail {
get {
return ResourceManager.GetString("QueryServiceSaveAsFail", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to A save request to the same path is in progress.
/// </summary>
public static string QueryServiceSaveAsInProgress {
get {
return ResourceManager.GetString("QueryServiceSaveAsInProgress", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Internal error occurred while starting save task.
/// </summary>
public static string QueryServiceSaveAsMiscStartingError {
get {
return ResourceManager.GetString("QueryServiceSaveAsMiscStartingError", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Result cannot be saved until query execution has completed.
/// </summary>
public static string QueryServiceSaveAsResultSetNotComplete {
get {
return ResourceManager.GetString("QueryServiceSaveAsResultSetNotComplete", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The batch has not completed, yet.
/// </summary>
public static string QueryServiceSubsetBatchNotCompleted {
get {
return ResourceManager.GetString("QueryServiceSubsetBatchNotCompleted", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Batch index cannot be less than 0 or greater than the number of batches.
/// </summary>
public static string QueryServiceSubsetBatchOutOfRange {
get {
return ResourceManager.GetString("QueryServiceSubsetBatchOutOfRange", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Result set index cannot be less than 0 or greater than the number of result sets.
/// </summary>
public static string QueryServiceSubsetResultSetOutOfRange {
get {
return ResourceManager.GetString("QueryServiceSubsetResultSetOutOfRange", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cannot register service for type {0}, one or more services already registered.
/// </summary>
public static string ServiceAlreadyRegistered {
get {
return ResourceManager.GetString("ServiceAlreadyRegistered", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Service {0} was not found in the service provider.
/// </summary>
public static string ServiceNotFound {
get {
return ResourceManager.GetString("ServiceNotFound", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Service of Type {0} is not compatible with registered Type {1}.
/// </summary>
public static string ServiceNotOfExpectedType {
get {
return ResourceManager.GetString("ServiceNotOfExpectedType", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to SetServiceProvider() was not called to establish the required service provider.
/// </summary>
public static string ServiceProviderNotSet {
get {
return ResourceManager.GetString("ServiceProviderNotSet", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to EN_LOCALIZATION.
/// </summary>
public static string TestLocalizationConstant {
get {
return ResourceManager.GetString("TestLocalizationConstant", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to For more information about this error, see the troubleshooting topics in the product documentation..
/// </summary>
public static string TroubleshootingAssistanceMessage {
get {
return ResourceManager.GetString("TroubleshootingAssistanceMessage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Start position ({0}, {1}) must come before or be equal to the end position ({2}, {3}).
/// </summary>
public static string WorkspaceServiceBufferPositionOutOfOrder {
get {
return ResourceManager.GetString("WorkspaceServiceBufferPositionOutOfOrder", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Position is outside of column range for line {0}.
/// </summary>
public static string WorkspaceServicePositionColumnOutOfRange {
get {
return ResourceManager.GetString("WorkspaceServicePositionColumnOutOfRange", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Position is outside of file line range.
/// </summary>
public static string WorkspaceServicePositionLineOutOfRange {
get {
return ResourceManager.GetString("WorkspaceServicePositionLineOutOfRange", resourceCulture);
}
}
}
}

View File

@@ -0,0 +1,117 @@
// WARNING:
// This file was generated by the Microsoft DataWarehouse String Resource Tool 1.37.0.0
// from information in sr.strings
// DO NOT MODIFY THIS FILE'S CONTENTS, THEY WILL BE OVERWRITTEN
//
namespace Microsoft.SqlTools.Credentials
{
using System;
using System.Reflection;
using System.Resources;
using System.Globalization;
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class SR
{
protected SR()
{ }
public static CultureInfo Culture
{
get
{
return Keys.Culture;
}
set
{
Keys.Culture = value;
}
}
public static string CredentialsServiceInvalidCriticalHandle
{
get
{
return Keys.GetString(Keys.CredentialsServiceInvalidCriticalHandle);
}
}
public static string CredentialsServicePasswordLengthExceeded
{
get
{
return Keys.GetString(Keys.CredentialsServicePasswordLengthExceeded);
}
}
public static string CredentialsServiceTargetForDelete
{
get
{
return Keys.GetString(Keys.CredentialsServiceTargetForDelete);
}
}
public static string CredentialsServiceTargetForLookup
{
get
{
return Keys.GetString(Keys.CredentialsServiceTargetForLookup);
}
}
public static string CredentialServiceWin32CredentialDisposed
{
get
{
return Keys.GetString(Keys.CredentialServiceWin32CredentialDisposed);
}
}
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class Keys
{
static ResourceManager resourceManager = new ResourceManager("Microsoft.SqlTools.Credentials.Localization.SR", typeof(SR).GetTypeInfo().Assembly);
static CultureInfo _culture = null;
public const string CredentialsServiceInvalidCriticalHandle = "CredentialsServiceInvalidCriticalHandle";
public const string CredentialsServicePasswordLengthExceeded = "CredentialsServicePasswordLengthExceeded";
public const string CredentialsServiceTargetForDelete = "CredentialsServiceTargetForDelete";
public const string CredentialsServiceTargetForLookup = "CredentialsServiceTargetForLookup";
public const string CredentialServiceWin32CredentialDisposed = "CredentialServiceWin32CredentialDisposed";
private Keys()
{ }
public static CultureInfo Culture
{
get
{
return _culture;
}
set
{
_culture = value;
}
}
public static string GetString(string key)
{
return resourceManager.GetString(key, _culture);
}
}
}
}

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype"><value>text/microsoft-resx</value></resheader><resheader name="version"><value>1.3</value></resheader><resheader name="reader"><value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></resheader><resheader name="writer"><value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></resheader><data name="TestLocalizationConstant"><value>ES_LOCALIZATION</value></data>
</root>

View File

@@ -0,0 +1,140 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype=">text/microsoft-resx</resheader>
<resheader name="version=">2.0</resheader>
<resheader name="reader=">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer=">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1="><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing=">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64=">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64=">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata=">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true=">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded=">
<xsd:element name="metadata=">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly=">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data=">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader=">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="CredentialsServiceInvalidCriticalHandle" xml:space="preserve">
<value>Invalid CriticalHandle!</value>
<comment></comment>
</data>
<data name="CredentialsServicePasswordLengthExceeded" xml:space="preserve">
<value>The password has exceeded 512 bytes</value>
<comment></comment>
</data>
<data name="CredentialsServiceTargetForDelete" xml:space="preserve">
<value>Target must be specified to delete a credential</value>
<comment></comment>
</data>
<data name="CredentialsServiceTargetForLookup" xml:space="preserve">
<value>Target must be specified to check existance of a credential</value>
<comment></comment>
</data>
<data name="CredentialServiceWin32CredentialDisposed" xml:space="preserve">
<value>Win32Credential object is already disposed</value>
<comment></comment>
</data>
</root>

View File

@@ -0,0 +1,34 @@
# String resource file
#
# When processed by the String Resource Tool, this file generates
# both a .CS and a .RESX file with the same name as the file.
# The .CS file contains a class which can be used to access these
# string resources, including the ability to format in
# parameters, which are identified with the .NET {x} format
# (see String.Format help).
#
# Comments below assume the file name is SR.strings.
#
# Lines starting with a semicolon ";" are also treated as comments, but
# in a future version they will be extracted and made available in LocStudio
# Put your comments to localizers _before_ the string they apply to.
#
# SMO build specific comment
# after generating the .resx file, run srgen on it and get the .resx file
# please remember to also check that .resx in, along with the
# .strings and .cs files
[strings]
############################################################################
# Credentials Service
CredentialsServiceInvalidCriticalHandle = Invalid CriticalHandle!
CredentialsServicePasswordLengthExceeded = The password has exceeded 512 bytes
CredentialsServiceTargetForDelete = Target must be specified to delete a credential
CredentialsServiceTargetForLookup = Target must be specified to check existance of a credential
CredentialServiceWin32CredentialDisposed = Win32Credential object is already disposed

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" original="sr.resx" source-language="en">
<body>
<trans-unit id="CredentialsServiceInvalidCriticalHandle">
<source>Invalid CriticalHandle!</source>
<target state="new">Invalid CriticalHandle!</target>
<note></note>
</trans-unit>
<trans-unit id="CredentialsServicePasswordLengthExceeded">
<source>The password has exceeded 512 bytes</source>
<target state="new">The password has exceeded 512 bytes</target>
<note></note>
</trans-unit>
<trans-unit id="CredentialsServiceTargetForDelete">
<source>Target must be specified to delete a credential</source>
<target state="new">Target must be specified to delete a credential</target>
<note></note>
</trans-unit>
<trans-unit id="CredentialsServiceTargetForLookup">
<source>Target must be specified to check existance of a credential</source>
<target state="new">Target must be specified to check existance of a credential</target>
<note></note>
</trans-unit>
<trans-unit id="CredentialServiceWin32CredentialDisposed">
<source>Win32Credential object is already disposed</source>
<target state="new">Win32Credential object is already disposed</target>
<note></note>
</trans-unit>
</body>
</file>
</xliff>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd">
<file datatype="xml" original="sr.es.resx" source-language="en" target-language="es">
<body>
<trans-unit id="TestLocalizationConstant">
<source>ES_LOCALIZATION</source>
<target state="new">ES_LOCALIZATION</target>
<note></note>
</trans-unit>
</body>
</file>
</xliff>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>{1D61DC2B-DA66-441D-B9D0-887798F780F9}</ProjectGuid>
<RootNamespace>Microsoft.SqlTools.Credentials</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'==''">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@@ -0,0 +1,47 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using Microsoft.SqlTools.Credentials.Utility;
using Microsoft.SqlTools.ServiceLayer.Hosting;
using Microsoft.SqlTools.ServiceLayer.SqlContext;
using Microsoft.SqlTools.ServiceLayer.Utility;
namespace Microsoft.SqlTools.Credentials
{
/// <summary>
/// Main application class for Credentials Service Host executable
/// </summary>
internal class Program
{
/// <summary>
/// Main entry point into the Credentials Service Host
/// </summary>
internal static void Main(string[] args)
{
// read command-line arguments
CommandOptions commandOptions = new CommandOptions(args);
if (commandOptions.ShouldExit)
{
return;
}
// turn on Verbose logging during early development
// we need to switch to Normal when preparing for public preview
Logger.Initialize(minimumLogLevel: LogLevel.Verbose, isEnabled: commandOptions.EnableLogging);
Logger.Write(LogLevel.Normal, "Starting SqlTools Credentials Provider");
// set up the host details and profile paths
var hostDetails = new HostDetails(
name: "SqlTools Credentials Provider",
profileId: "Microsoft.SqlTools.Credentials",
version: new Version(1, 0));
SqlToolsContext sqlToolsContext = new SqlToolsContext(hostDetails);
ServiceHost serviceHost = HostLoader.CreateAndStartServiceHost(sqlToolsContext);
serviceHost.WaitForExit();
}
}
}

View File

@@ -0,0 +1,48 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("SqlTools Credentials Library")]
[assembly: AssemblyDescription("Provides SqlTools credential management functionality.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("SqlTools Credentials Services")]
[assembly: AssemblyCopyright("<22> Microsoft Corporation. All rights reserved.")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("131E0A47-C9C9-48E4-8C4F-D3A64B51A2B2")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0.0")]
[assembly: InternalsVisibleTo("Microsoft.SqlTools.ServiceLayer.Test")]
[assembly: InternalsVisibleTo("Microsoft.SqlTools.ServiceLayer.IntegrationTests")]
[assembly: InternalsVisibleTo("Microsoft.SqlTools.ServiceLayer.Test.Common")]

View File

@@ -0,0 +1,89 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
namespace Microsoft.SqlTools.Credentials.Utility
{
/// <summary>
/// The command-line options helper class.
/// </summary>
internal class CommandOptions
{
/// <summary>
/// Construct and parse command line options from the arguments array
/// </summary>
public CommandOptions(string[] args)
{
ErrorMessage = string.Empty;
try
{
for (int i = 0; i < args.Length; ++i)
{
string arg = args[i];
if (arg.StartsWith("--") || arg.StartsWith("-"))
{
switch (arg)
{
case "-enable-logging":
EnableLogging = true;
break;
case "h":
case "-help":
ShouldExit = true;
return;
default:
ErrorMessage += String.Format("Unknown argument \"{0}\"" + Environment.NewLine, arg);
break;
}
}
}
}
catch (Exception ex)
{
ErrorMessage += ex.ToString();
return;
}
finally
{
if (!string.IsNullOrEmpty(ErrorMessage) || ShouldExit)
{
Console.WriteLine(Usage);
ShouldExit = true;
}
}
}
internal string ErrorMessage { get; private set; }
/// <summary>
/// Whether diagnostic logging is enabled
/// </summary>
public bool EnableLogging { get; private set; }
/// <summary>
/// Whether the program should exit immediately. Set to true when the usage is printed.
/// </summary>
public bool ShouldExit { get; private set; }
/// <summary>
/// Get the usage string describing command-line arguments for the program
/// </summary>
public string Usage
{
get
{
var str = string.Format("{0}" + Environment.NewLine +
"Microsoft.SqlTools.Credentials " + Environment.NewLine +
" Options:" + Environment.NewLine +
" [--enable-logging]" + Environment.NewLine +
" [--help]" + Environment.NewLine,
ErrorMessage);
return str;
}
}
}
}

View File

@@ -0,0 +1,67 @@
{
"name": "Microsoft.SqlTools.Credentials",
"version": "1.0.0-*",
"buildOptions": {
"debugType": "portable",
"emitEntryPoint": true,
"embed": [
"../Microsoft.SqlTools.ServiceLayer/Localization/sr.es.resx",
"../Microsoft.SqlTools.ServiceLayer/Localization/sr.resx"
]
},
"configurations": {
"Integration": {
"buildOptions": {
"define": [
"WINDOWS_ONLY_BUILD"
],
"emitEntryPoint": true
}
}
},
"dependencies": {
"Newtonsoft.Json": "9.0.1",
"System.Security.SecureString": "4.0.0",
"System.Collections.Specialized": "4.0.1",
"System.ComponentModel.TypeConverter": "4.1.0",
"System.Diagnostics.Contracts": "4.0.1",
"System.Diagnostics.TraceSource": "4.0.0",
"NETStandard.Library": "1.6.0",
"Microsoft.NETCore.Runtime.CoreCLR": "1.0.2",
"Microsoft.NETCore.DotNetHostPolicy": "1.0.1",
"Microsoft.DiaSymReader.Native": "1.4.1",
"System.Diagnostics.Process": "4.1.0",
"System.Threading.Thread": "4.0.0",
"System.Runtime.Loader": "4.0.0",
"System.Composition.Runtime": "1.0.31",
"System.Composition.Convention": "1.0.31",
"System.Composition.TypedParts": "1.0.31",
"Microsoft.Extensions.DependencyModel": "1.0.0",
"System.Runtime": "4.3.0",
"Microsoft.SqlTools.Hosting": {
"target": "project"
}
},
"frameworks": {
"netcoreapp1.0": {
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.0.0"
}
},
"imports": "dnxcore50"
}
},
"runtimes": {
"win7-x64": {},
"win7-x86": {},
"osx.10.11-x64": {},
"ubuntu.14.04-x64": {},
"ubuntu.16.04-x64": {},
"centos.7-x64": {},
"rhel.7.2-x64": {},
"debian.8-x64": {},
"fedora.23-x64": {},
"opensuse.13.2-x64": {}
}
}