예제 #1
0
        public void Delete(string target)
        {
            Trace.Entering();
            ArgUtil.NotNullOrEmpty(target, nameof(target));

            try
            {
                UnlockKeyChain();

                List <string> securityOut   = new List <string>();
                List <string> securityError = new List <string>();
                object        outputLock    = new object();

                using (var p = HostContext.CreateService <IProcessInvoker>())
                {
                    p.OutputDataReceived += delegate(object sender, ProcessDataReceivedEventArgs stdout)
                    {
                        if (!string.IsNullOrEmpty(stdout.Data))
                        {
                            lock (outputLock)
                            {
                                securityOut.Add(stdout.Data);
                            }
                        }
                    };

                    p.ErrorDataReceived += delegate(object sender, ProcessDataReceivedEventArgs stderr)
                    {
                        if (!string.IsNullOrEmpty(stderr.Data))
                        {
                            lock (outputLock)
                            {
                                securityError.Add(stderr.Data);
                            }
                        }
                    };

                    int exitCode = p.ExecuteAsync(workingDirectory: HostContext.GetDirectory(WellKnownDirectory.Root),
                                                  fileName: _securityUtil,
                                                  arguments: $"delete-generic-password -s {target} -a VSTSAGENT \"{_agentCredStoreKeyChain}\"",
                                                  environment: null,
                                                  cancellationToken: CancellationToken.None).GetAwaiter().GetResult();
                    if (exitCode == 0)
                    {
                        Trace.Info($"Successfully delete-generic-password for {target} (VSTSAGENT)");
                    }
                    else
                    {
                        if (securityOut.Count > 0)
                        {
                            Trace.Error(string.Join(Environment.NewLine, securityOut));
                        }
                        if (securityError.Count > 0)
                        {
                            Trace.Error(string.Join(Environment.NewLine, securityError));
                        }

                        throw new InvalidOperationException($"'security delete-generic-password' failed with exit code {exitCode}.");
                    }
                }
            }
            finally
            {
                LockKeyChain();
            }
        }
예제 #2
0
        public NetworkCredential Write(string target, string username, string password)
        {
            Trace.Entering();
            ArgUtil.NotNullOrEmpty(target, nameof(target));
            ArgUtil.NotNullOrEmpty(username, nameof(username));
            ArgUtil.NotNullOrEmpty(password, nameof(password));

            try
            {
                UnlockKeyChain();

                // base64encode username + ':' + base64encode password
                // OSX keychain requires you provide -s target and -a username to retrieve password
                // So, we will trade both username and password as 'secret' store into keychain
                string usernameBase64    = Convert.ToBase64String(Encoding.UTF8.GetBytes(username));
                string passwordBase64    = Convert.ToBase64String(Encoding.UTF8.GetBytes(password));
                string secretForKeyChain = $"{usernameBase64}:{passwordBase64}";

                List <string> securityOut   = new List <string>();
                List <string> securityError = new List <string>();
                object        outputLock    = new object();
                using (var p = HostContext.CreateService <IProcessInvoker>())
                {
                    p.OutputDataReceived += delegate(object sender, ProcessDataReceivedEventArgs stdout)
                    {
                        if (!string.IsNullOrEmpty(stdout.Data))
                        {
                            lock (outputLock)
                            {
                                securityOut.Add(stdout.Data);
                            }
                        }
                    };

                    p.ErrorDataReceived += delegate(object sender, ProcessDataReceivedEventArgs stderr)
                    {
                        if (!string.IsNullOrEmpty(stderr.Data))
                        {
                            lock (outputLock)
                            {
                                securityError.Add(stderr.Data);
                            }
                        }
                    };

                    // make sure the 'security' has access to the key so we won't get prompt at runtime.
                    int exitCode = p.ExecuteAsync(workingDirectory: HostContext.GetDirectory(WellKnownDirectory.Root),
                                                  fileName: _securityUtil,
                                                  arguments: $"add-generic-password -s {target} -a VSTSAGENT -w {secretForKeyChain} -T \"{_securityUtil}\" \"{_agentCredStoreKeyChain}\"",
                                                  environment: null,
                                                  cancellationToken: CancellationToken.None).GetAwaiter().GetResult();
                    if (exitCode == 0)
                    {
                        Trace.Info($"Successfully add-generic-password for {target} (VSTSAGENT)");
                    }
                    else
                    {
                        if (securityOut.Count > 0)
                        {
                            Trace.Error(string.Join(Environment.NewLine, securityOut));
                        }
                        if (securityError.Count > 0)
                        {
                            Trace.Error(string.Join(Environment.NewLine, securityError));
                        }

                        throw new InvalidOperationException($"'security add-generic-password' failed with exit code {exitCode}.");
                    }
                }

                return(new NetworkCredential(username, password));
            }
            finally
            {
                LockKeyChain();
            }
        }
예제 #3
0
        public NetworkCredential Read(string target)
        {
            Trace.Entering();
            ArgUtil.NotNullOrEmpty(target, nameof(target));

            try
            {
                UnlockKeyChain();

                string username;
                string password;

                List <string> securityOut   = new List <string>();
                List <string> securityError = new List <string>();
                object        outputLock    = new object();
                using (var p = HostContext.CreateService <IProcessInvoker>())
                {
                    p.OutputDataReceived += delegate(object sender, ProcessDataReceivedEventArgs stdout)
                    {
                        if (!string.IsNullOrEmpty(stdout.Data))
                        {
                            lock (outputLock)
                            {
                                securityOut.Add(stdout.Data);
                            }
                        }
                    };

                    p.ErrorDataReceived += delegate(object sender, ProcessDataReceivedEventArgs stderr)
                    {
                        if (!string.IsNullOrEmpty(stderr.Data))
                        {
                            lock (outputLock)
                            {
                                securityError.Add(stderr.Data);
                            }
                        }
                    };

                    int exitCode = p.ExecuteAsync(workingDirectory: HostContext.GetDirectory(WellKnownDirectory.Root),
                                                  fileName: _securityUtil,
                                                  arguments: $"find-generic-password -s {target} -a VSTSAGENT -w -g \"{_agentCredStoreKeyChain}\"",
                                                  environment: null,
                                                  cancellationToken: CancellationToken.None).GetAwaiter().GetResult();
                    if (exitCode == 0)
                    {
                        string   keyChainSecret = securityOut.First();
                        string[] secrets        = keyChainSecret.Split(':');
                        if (secrets.Length == 2 && !string.IsNullOrEmpty(secrets[0]) && !string.IsNullOrEmpty(secrets[1]))
                        {
                            Trace.Info($"Successfully find-generic-password for {target} (VSTSAGENT)");
                            username = Encoding.UTF8.GetString(Convert.FromBase64String(secrets[0]));
                            password = Encoding.UTF8.GetString(Convert.FromBase64String(secrets[1]));
                            return(new NetworkCredential(username, password));
                        }
                        else
                        {
                            throw new ArgumentOutOfRangeException(nameof(keyChainSecret));
                        }
                    }
                    else
                    {
                        if (securityOut.Count > 0)
                        {
                            Trace.Error(string.Join(Environment.NewLine, securityOut));
                        }
                        if (securityError.Count > 0)
                        {
                            Trace.Error(string.Join(Environment.NewLine, securityError));
                        }

                        throw new InvalidOperationException($"'security find-generic-password' failed with exit code {exitCode}.");
                    }
                }
            }
            finally
            {
                LockKeyChain();
            }
        }
예제 #4
0
        public override void Initialize(IHostContext hostContext)
        {
            base.Initialize(hostContext);

            _securityUtil = WhichUtil.Which("security", true, Trace);

            _agentCredStoreKeyChain = hostContext.GetConfigFile(WellKnownConfigFile.CredentialStore);

            // Create osx key chain if it doesn't exists.
            if (!File.Exists(_agentCredStoreKeyChain))
            {
                List <string> securityOut   = new List <string>();
                List <string> securityError = new List <string>();
                object        outputLock    = new object();
                using (var p = HostContext.CreateService <IProcessInvoker>())
                {
                    p.OutputDataReceived += delegate(object sender, ProcessDataReceivedEventArgs stdout)
                    {
                        if (!string.IsNullOrEmpty(stdout.Data))
                        {
                            lock (outputLock)
                            {
                                securityOut.Add(stdout.Data);
                            }
                        }
                    };

                    p.ErrorDataReceived += delegate(object sender, ProcessDataReceivedEventArgs stderr)
                    {
                        if (!string.IsNullOrEmpty(stderr.Data))
                        {
                            lock (outputLock)
                            {
                                securityError.Add(stderr.Data);
                            }
                        }
                    };

                    // make sure the 'security' has access to the key so we won't get prompt at runtime.
                    int exitCode = p.ExecuteAsync(workingDirectory: HostContext.GetDirectory(WellKnownDirectory.Root),
                                                  fileName: _securityUtil,
                                                  arguments: $"create-keychain -p {_osxAgentCredStoreKeyChainPassword} \"{_agentCredStoreKeyChain}\"",
                                                  environment: null,
                                                  cancellationToken: CancellationToken.None).GetAwaiter().GetResult();
                    if (exitCode == 0)
                    {
                        Trace.Info($"Successfully create-keychain for {_agentCredStoreKeyChain}");
                    }
                    else
                    {
                        if (securityOut.Count > 0)
                        {
                            Trace.Error(string.Join(Environment.NewLine, securityOut));
                        }
                        if (securityError.Count > 0)
                        {
                            Trace.Error(string.Join(Environment.NewLine, securityError));
                        }

                        throw new InvalidOperationException($"'security create-keychain' failed with exit code {exitCode}.");
                    }
                }
            }
            else
            {
                // Try unlock and lock the keychain, make sure it's still in good stage
                UnlockKeyChain();
                LockKeyChain();
            }
        }