/// <summary>
        /// Creates the vault management instance based on provided Vaults Config dictionary
        /// </summary>
        /// <param name="vaultsConfig">Vaults Config dictionary</param>
        /// <param name="accessType">ReadOnly or ReadWrite</param>
        /// <param name="vaultNames">Single or Dual</param>
        public Vault(VaultsConfig vaultsConfig, VaultAccessTypeEnum accessType, params string[] vaultNames)
        {
            Guard.ArgumentNotNull(vaultsConfig, nameof(vaultsConfig));
            Guard.ArgumentCollectionNotEmpty(vaultNames, nameof(vaultNames));
            VaultsConfig = vaultsConfig;
            VaultNames   = (from v in vaultNames where !string.IsNullOrEmpty(v) select v).ToArray();
            switch (VaultNames.Length)
            {
            case 1:
                _keyVaultClients = new KeyVaultClientEx[1]
                {
                    CreateKeyVaultClientEx(accessType, VaultNames[0]),
                };
                break;

            case 2:
                string primaryVaultName   = VaultNames[0];
                string secondaryVaultName = VaultNames[1];
                if (0 == string.Compare(primaryVaultName, secondaryVaultName, true))
                {
                    throw new ArgumentException($"Primary vault name {primaryVaultName} is equal to secondary vault name {secondaryVaultName}");
                }
                _keyVaultClients = new KeyVaultClientEx[2]
                {
                    CreateKeyVaultClientEx(accessType, primaryVaultName),
                    CreateKeyVaultClientEx(accessType, secondaryVaultName),
                };
                break;

            default:
                throw new ArgumentException($"Vault names length must be 1 or 2 only", nameof(VaultNames));
            }
        }
        private KeyVaultClientEx CreateKeyVaultClientEx(VaultAccessTypeEnum accessType, string vaultName) =>
        new KeyVaultClientEx(vaultName, (authority, resource, scope) =>
        {
            lock (Lock)
            {
                Utils.GuardVaultName(vaultName);
                if (false == VaultsConfig.ContainsKey(vaultName))
                {
                    throw new KeyNotFoundException($"{vaultName} is not found in {VaultsConfigFile}");
                }
                VaultAccessType vat = VaultsConfig[vaultName];
                VaultAccess[] vas   = (accessType == VaultAccessTypeEnum.ReadOnly) ? vat.ReadOnly : vat.ReadWrite;

                // Order possible VaultAccess options by Order property
                IEnumerable <VaultAccess> vaSorted = from va in vas orderby va.Order select va;

                // In case VaultAccessUserInteractive is in the list, we will use our FileTokenCache with provided domainHint, otherwise use MemoryTokenCache
                string domainHint    = (from va in vaSorted where va is VaultAccessUserInteractive select(VaultAccessUserInteractive) va).FirstOrDefault()?.DomainHint;
                string userAliasType = (from va in vaSorted where va is VaultAccessUserInteractive select(VaultAccessUserInteractive) va).FirstOrDefault()?.UserAliasType;

                // Token cache name is unique per login credentials as it uses alias type or env user name and domain hint.
                string tokenCacheName = $"{(userAliasType ?? Environment.UserName)}@{domainHint ?? "microsoft.com"}";

                // If either user alias or domain hint are empty, cache in memory instead.
                var authenticationContext = new AuthenticationContext(authority, string.IsNullOrEmpty(domainHint) && string.IsNullOrEmpty(userAliasType) ? new MemoryTokenCache() : (TokenCache) new FileTokenCache(tokenCacheName));

                Queue <Exception> exceptions = new Queue <Exception>();
                string vaultAccessTypes      = "";
                foreach (VaultAccess va in vaSorted)
                {
                    try
                    {
                        // If user alias type is different from environment, force login prompt, otherwise silently login
                        var authResult        = va.AcquireToken(authenticationContext, resource, userAliasType == Environment.UserName ? Environment.UserName:"");
                        AuthenticatedUserName = authResult.UserInfo?.DisplayableId ?? $"{Environment.UserDomainName}\\{Environment.UserName}";
                        return(Task.FromResult(authResult.AccessToken));
                    }
                    catch (Exception e)
                    {
                        vaultAccessTypes += $" {va}";
                        exceptions.Enqueue(e);
                    }
                }
                throw new VaultAccessException($"Failed to get access to {vaultName} with all possible vault access type(s){vaultAccessTypes}", exceptions.ToArray());
            }
        });
Beispiel #3
0
        private KeyVaultClientEx CreateKeyVaultClientEx(VaultAccessTypeEnum accessType, string vaultName) =>
        new KeyVaultClientEx(vaultName, (authority, resource, scope) =>
        {
            Utils.GuardVaultName(vaultName);
            if (false == VaultsConfig.ContainsKey(vaultName))
            {
                throw new KeyNotFoundException($"{vaultName} is not found in {VaultsConfigFile}");
            }
            VaultAccessType vat = VaultsConfig[vaultName];
            VaultAccess[] vas   = (accessType == VaultAccessTypeEnum.ReadOnly) ? vat.ReadOnly : vat.ReadWrite;

            // Order possible VaultAccess options by Order property
            IEnumerable <VaultAccess> vaSorted = from va in vas orderby va.Order select va;

            // In case VaultAccessUserInteractive is in the list, we will use our FileTokenCache with provided domainHint, otherwise use MemoryTokenCache
            string domainHint = (from va in vaSorted where va is VaultAccessUserInteractive select(VaultAccessUserInteractive) va).FirstOrDefault()?.DomainHint;

            var authenticationContext = new AuthenticationContext(authority, string.IsNullOrEmpty(domainHint) ? new MemoryTokenCache() : (TokenCache) new FileTokenCache(domainHint));

            Queue <Exception> exceptions = new Queue <Exception>();
            string vaultAccessTypes      = "";
            foreach (VaultAccess va in vaSorted)
            {
                try
                {
                    var authResult        = va.AcquireToken(authenticationContext, resource);
                    AuthenticatedUserName = authResult.UserInfo?.DisplayableId ?? $"{Environment.UserDomainName}\\{Environment.UserName}";
                    return(Task.FromResult(authResult.AccessToken));
                }
                catch (Exception e)
                {
                    vaultAccessTypes += $" {va}";
                    exceptions.Enqueue(e);
                }
            }
            throw new VaultAccessException($"Failed to get access to {vaultName} with all possible vault access type(s){vaultAccessTypes}", exceptions.ToArray());
        });
 /// <summary>
 /// Dual (primary and secondary) vault management constructor
 /// </summary>
 /// <param name="accessType">ReadOnly or ReadWrite</param>
 /// <param name="primaryVaultName">Primary vault name</param>
 /// <param name="secondaryVaultName">Secodnary vault name</param>
 public Vault(VaultAccessTypeEnum accessType, string primaryVaultName, string secondaryVaultName)
     : this(accessType, new string[] { primaryVaultName, secondaryVaultName })
 {
 }
 /// <summary>
 /// Single (primary) or Dual (primary and secondary) vault management constructor
 /// </summary>
 /// <param name="accessType">ReadOnly or ReadWrite</param>
 /// <param name="vaultName">Vault name</param>
 public Vault(VaultAccessTypeEnum accessType, string vaultName)
     : this(accessType, new string[] { vaultName })
 {
 }
 /// <summary>
 /// Single (primary) vault management constructor
 /// </summary>
 /// <param name="accessType">ReadOnly or ReadWrite</param>
 /// <param name="vaultNames">Single or pair</param>
 public Vault(VaultAccessTypeEnum accessType, params string[] vaultNames)
     : this(string.Empty, accessType, vaultNames)
 {
 }
 /// <summary>
 /// Load specified Vaults.json configuration file and creates the vault management instance
 /// </summary>
 /// <param name="vaultsConfigFile">
 /// Optional path to Vaults.json file, if NULL or empty default Vaults.json will be used, in such case Vaults.json location will be resolved in the following order:
 /// 1. Side-by-side with the current process location
 /// 2. Side-by-side with the current (executing) assembly
 /// </param>
 /// <param name="accessType">ReadOnly or ReadWrite</param>
 /// <param name="vaultNames">Single or Dual</param>
 public Vault(string vaultsConfigFile, VaultAccessTypeEnum accessType, params string[] vaultNames)
     : this(DeserializeVaultsConfigFromFile(ref vaultsConfigFile), accessType, vaultNames)
 {
     VaultsConfigFile = vaultsConfigFile;
 }