Config framework implementation (#17545)
* Modified code from Microsot.Extensions.Configuration * implementation of config framework * cmdlet related * test related * changelog; 3rd party license * move PSConfig model to Accounts proj; feedback link * Move preview attribute into child classes * fix get/update by config key * correct cmdlet regex
This commit is contained in:
Родитель
42085ee602
Коммит
7d4bee9535
28
LICENSE.txt
28
LICENSE.txt
|
@ -273,5 +273,33 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
***************
|
||||
|
||||
The software includes Microsoft.Extensions.Configuration. The MIT License set out below is provided for informational purposes only. It is not the license that governs any part of the software.
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) .NET Foundation and Contributors
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
-------------END OF THIRD PARTY NOTICE----------------------------------------
|
||||
|
||||
|
|
|
@ -382,7 +382,8 @@ namespace Microsoft.WindowsAzure.Commands.Common.Test.Mocks
|
|||
() =>
|
||||
{
|
||||
writeLocks[path] = false;
|
||||
virtualStore[path] = Encoding.UTF8.GetString(buffer);
|
||||
// trim \0 otherwise json fails to parse
|
||||
virtualStore[path] = Encoding.UTF8.GetString(buffer).TrimEnd('\0');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -276,6 +276,61 @@
|
|||
</ListEntries>
|
||||
</ListControl>
|
||||
</View>
|
||||
|
||||
<View>
|
||||
<Name>Microsoft.Azure.Commands.Profile.Models.PSConfig</Name>
|
||||
<ViewSelectedBy>
|
||||
<TypeName>Microsoft.Azure.Commands.Profile.Models.PSConfig</TypeName>
|
||||
</ViewSelectedBy>
|
||||
<TableControl>
|
||||
<TableHeaders>
|
||||
<TableColumnHeader>
|
||||
<Alignment>Left</Alignment>
|
||||
<Label>Key</Label>
|
||||
</TableColumnHeader>
|
||||
<TableColumnHeader>
|
||||
<Alignment>Left</Alignment>
|
||||
<Label>Value</Label>
|
||||
</TableColumnHeader>
|
||||
<TableColumnHeader>
|
||||
<Alignment>Left</Alignment>
|
||||
<Label>Applies To</Label>
|
||||
</TableColumnHeader>
|
||||
<TableColumnHeader>
|
||||
<Alignment>Left</Alignment>
|
||||
<Label>Scope</Label>
|
||||
</TableColumnHeader>
|
||||
<TableColumnHeader>
|
||||
<Alignment>Left</Alignment>
|
||||
<Label>Help Message</Label>
|
||||
</TableColumnHeader>
|
||||
</TableHeaders>
|
||||
<TableRowEntries>
|
||||
<TableRowEntry>
|
||||
<TableColumnItems>
|
||||
<TableColumnItem>
|
||||
<Alignment>Left</Alignment>
|
||||
<PropertyName>Key</PropertyName>
|
||||
</TableColumnItem>
|
||||
<TableColumnItem>
|
||||
<Alignment>Left</Alignment>
|
||||
<PropertyName>Value</PropertyName>
|
||||
</TableColumnItem>
|
||||
<TableColumnItem>
|
||||
<Alignment>Left</Alignment>
|
||||
<PropertyName>AppliesTo</PropertyName>
|
||||
</TableColumnItem>
|
||||
<TableColumnItem>
|
||||
<Alignment>Left</Alignment>
|
||||
<PropertyName>Scope</PropertyName>
|
||||
</TableColumnItem>
|
||||
<TableColumnItem>
|
||||
<Alignment>Left</Alignment>
|
||||
<PropertyName>HelpMessage</PropertyName>
|
||||
</TableColumnItem>
|
||||
</TableColumnItems>
|
||||
</TableRowEntry>
|
||||
</TableRowEntries>
|
||||
</TableControl>
|
||||
</View>
|
||||
</ViewDefinitions>
|
||||
</Configuration>
|
||||
|
|
|
@ -108,7 +108,7 @@ CmdletsToExport = 'Disable-AzDataCollection', 'Disable-AzContextAutosave',
|
|||
'Set-AzDefault', 'Get-AzDefault', 'Clear-AzDefault',
|
||||
'Register-AzModule', 'Enable-AzureRmAlias', 'Disable-AzureRmAlias',
|
||||
'Uninstall-AzureRm', 'Invoke-AzRestMethod', 'Get-AzAccessToken',
|
||||
'Open-AzSurveyLink'
|
||||
'Open-AzSurveyLink', 'Get-AzConfig', 'Update-AzConfig', 'Clear-AzConfig'
|
||||
|
||||
# Variables to export from this module
|
||||
# VariablesToExport = @()
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
-->
|
||||
|
||||
## Upcoming Release
|
||||
* Added a preview feature allowing user to control the configurations of Azure PowerShell by using the following cmdlets:
|
||||
- `Get-AzConfig`
|
||||
- `Update-AzConfig`
|
||||
- `Clear-AzConfig`
|
||||
* Upgraded System.Reflection.DispatchProxy on Windows PowerShell [#17856]
|
||||
* Upgraded Azure.Identity to 1.6.0 and Azure.Core to 1.24.0
|
||||
|
||||
|
@ -216,7 +220,7 @@
|
|||
* Updated Add-AzEnvironment and Set-AzEnvironment to accept parameters AzureAttestationServiceEndpointResourceId and AzureAttestationServiceEndpointSuffix
|
||||
|
||||
## Version 1.6.6
|
||||
* Add client-side telemetry info for Az 4.0 preview
|
||||
* Add client-side telemetry info for Az 4.0 `preview`
|
||||
|
||||
## Version 1.6.5
|
||||
* Update references in .psd1 to use relative path
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.PowerShell.Common.Config;
|
||||
using Microsoft.WindowsAzure.Commands.Common.CustomAttributes;
|
||||
using Microsoft.WindowsAzure.Commands.Utilities.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Management.Automation;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config
|
||||
{
|
||||
[Cmdlet("Clear", "AzConfig", SupportsShouldProcess = true)]
|
||||
[OutputType(typeof(bool))]
|
||||
[CmdletPreview(PreviewMessage)]
|
||||
public class ClearConfigCommand : ConfigCommandBase, IDynamicParameters
|
||||
{
|
||||
private const string ClearByKey = "ClearByKey";
|
||||
private const string ClearAll = "ClearAll";
|
||||
|
||||
private const string ProcessMessage = "Clear the configs that apply to \"{0}\" by the following keys: {1}.";
|
||||
|
||||
private string ContinueMessage => $"Clear all the configs that apply to \"{AppliesTo}\" in scope {Scope}?";
|
||||
private string ProcessTarget => $"Configs in scope {Scope}";
|
||||
|
||||
[Parameter(ParameterSetName = ClearAll, Mandatory = true, HelpMessage = "Clear all configs.")]
|
||||
public SwitchParameter All { get; set; }
|
||||
|
||||
[Parameter(ParameterSetName = ClearAll, HelpMessage = "Do not ask for confirmation when clearing all configs.")]
|
||||
public SwitchParameter Force { get; set; }
|
||||
|
||||
[Parameter(HelpMessage = "Returns true if cmdlet executes correctly.")]
|
||||
public SwitchParameter PassThru { get; set; }
|
||||
|
||||
public new object GetDynamicParameters()
|
||||
{
|
||||
return GetDynamicParameters((ConfigDefinition config) =>
|
||||
new RuntimeDefinedParameter(
|
||||
config.Key,
|
||||
typeof(SwitchParameter),
|
||||
new Collection<Attribute>() {
|
||||
new ParameterAttribute {
|
||||
ParameterSetName = ClearByKey,
|
||||
HelpMessage = config.HelpMessage
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public override void ExecuteCmdlet()
|
||||
{
|
||||
switch (ParameterSetName)
|
||||
{
|
||||
case ClearByKey:
|
||||
ClearConfigByKey();
|
||||
break;
|
||||
case ClearAll:
|
||||
ClearAllConfigs();
|
||||
break;
|
||||
}
|
||||
if (PassThru)
|
||||
{
|
||||
WriteObject(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearConfigByKey()
|
||||
{
|
||||
IEnumerable<string> configKeysFromInput = GetConfigsSpecifiedByUser()
|
||||
.Where(x => (SwitchParameter)x.Value)
|
||||
.Select(x => x.Key);
|
||||
if (!configKeysFromInput.Any())
|
||||
{
|
||||
WriteWarning($"Please specify the key(s) of the configs to clear. Run `help {MyInvocation.MyCommand.Name}` for more information.");
|
||||
return;
|
||||
}
|
||||
base.ConfirmAction(
|
||||
string.Format(ProcessMessage, AppliesTo, string.Join(", ", configKeysFromInput)),
|
||||
ProcessTarget,
|
||||
() => configKeysFromInput.ForEach(ClearConfigByKey));
|
||||
}
|
||||
|
||||
private void ClearConfigByKey(string key)
|
||||
{
|
||||
ConfigManager.ClearConfig(new ClearConfigOptions(key, Scope)
|
||||
{
|
||||
AppliesTo = AppliesTo
|
||||
});
|
||||
}
|
||||
|
||||
private void ClearAllConfigs()
|
||||
{
|
||||
ConfirmAction(Force, ContinueMessage, ContinueMessage, ProcessTarget, () =>
|
||||
{
|
||||
ConfigManager.ClearConfig(new ClearConfigOptions(null, Scope)
|
||||
{
|
||||
AppliesTo = AppliesTo
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Exceptions;
|
||||
using Microsoft.Azure.Commands.ResourceManager.Common;
|
||||
using Microsoft.Azure.PowerShell.Common.Config;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Management.Automation;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config
|
||||
{
|
||||
public abstract class ConfigCommandBase : AzureRMCmdlet
|
||||
{
|
||||
protected const string PreviewMessage = "The cmdlet group \"AzConfig\" is in preview. Feedback is welcome: https://aka.ms/azpsissue";
|
||||
|
||||
private readonly RuntimeDefinedParameterDictionary _dynamicParameters = new RuntimeDefinedParameterDictionary();
|
||||
|
||||
protected IConfigManager ConfigManager { get; }
|
||||
protected IEnumerable<ConfigDefinition> ConfigDefinitions
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_configDefinitions == null)
|
||||
{
|
||||
_configDefinitions = ConfigManager.ListConfigDefinitions();
|
||||
}
|
||||
return _configDefinitions;
|
||||
}
|
||||
}
|
||||
private IEnumerable<ConfigDefinition> _configDefinitions;
|
||||
|
||||
public ConfigCommandBase() : base()
|
||||
{
|
||||
if (!AzureSession.Instance.TryGetComponent<IConfigManager>(nameof(IConfigManager), out var configManager))
|
||||
{
|
||||
throw new AzPSApplicationException($"Unexpected error: {nameof(IConfigManager)} has not been registered to the current session.");
|
||||
}
|
||||
ConfigManager = configManager;
|
||||
}
|
||||
|
||||
[Parameter(HelpMessage = "Specifies what part of Azure PowerShell the config applies to. Possible values are:\n- \"" + ConfigFilter.GlobalAppliesTo + "\": the config applies to all modules and cmdlets of Azure PowerShell. \n- Module name: the config applies to a certain module of Azure PowerShell. For example, \"Az.Storage\".\n- Cmdlet name: the config applies to a certain cmdlet of Azure PowerShell. For example, \"Get-AzKeyVault\".\nIf not specified, when getting configs, output will be all of the above; when updating, it defaults to \"" + ConfigFilter.GlobalAppliesTo + "\"; when clearing, configs applying to any targets are cleared.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public string AppliesTo { get; set; }
|
||||
|
||||
[Parameter(HelpMessage = "Determines the scope of config changes, for example, whether changes apply only to the current process, or to all sessions started by this user. By default it is CurrentUser.")]
|
||||
public ConfigScope Scope { get; set; } = ConfigScope.CurrentUser;
|
||||
|
||||
protected override void BeginProcessing()
|
||||
{
|
||||
base.BeginProcessing();
|
||||
ValidateParameters();
|
||||
}
|
||||
|
||||
protected virtual void ValidateParameters()
|
||||
{
|
||||
if (!AppliesToHelper.TryParseAppliesTo(AppliesTo, out _))
|
||||
{
|
||||
throw new AzPSArgumentException($"{nameof(AppliesTo)} must be a valid module name, a cmdlet name, or \"{ConfigFilter.GlobalAppliesTo}\"", nameof(AppliesTo));
|
||||
}
|
||||
}
|
||||
|
||||
protected object GetDynamicParameters(Func<ConfigDefinition, RuntimeDefinedParameter> mapConfigToParameter)
|
||||
{
|
||||
_dynamicParameters.Clear();
|
||||
foreach (var config in ConfigDefinitions)
|
||||
{
|
||||
_dynamicParameters.Add(config.Key, mapConfigToParameter(config));
|
||||
}
|
||||
return _dynamicParameters;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the dynamic parameters and their values if specified.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected IEnumerable<(string Key, object Value)> GetConfigsSpecifiedByUser()
|
||||
{
|
||||
var configs = new Dictionary<string, object>();
|
||||
foreach (var param in _dynamicParameters.Values.Where(p => p.IsSet))
|
||||
{
|
||||
yield return (param.Name, param.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Profile.Models;
|
||||
using Microsoft.Azure.Commands.ResourceManager.Common;
|
||||
using Microsoft.Azure.PowerShell.Common.Config;
|
||||
using Microsoft.WindowsAzure.Commands.Common.CustomAttributes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Management.Automation;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config
|
||||
{
|
||||
[Cmdlet(VerbsCommon.Get, AzureRMConstants.AzureRMPrefix + "Config")]
|
||||
[OutputType(typeof(PSConfig))]
|
||||
[CmdletPreview(PreviewMessage)]
|
||||
public class GetConfigCommand : ConfigCommandBase, IDynamicParameters
|
||||
{
|
||||
public GetConfigCommand() : base()
|
||||
{
|
||||
}
|
||||
|
||||
public new object GetDynamicParameters()
|
||||
{
|
||||
return GetDynamicParameters((ConfigDefinition config) =>
|
||||
new RuntimeDefinedParameter(
|
||||
config.Key,
|
||||
typeof(SwitchParameter),
|
||||
new Collection<Attribute>() {
|
||||
new ParameterAttribute {
|
||||
HelpMessage = config.HelpMessage
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public override void ExecuteCmdlet()
|
||||
{
|
||||
ConfigFilter filter = CreateConfigFilter();
|
||||
|
||||
IEnumerable<ConfigData> configs = ConfigManager.ListConfigs(filter);
|
||||
WriteObject(configs.Select(x => new PSConfig(x)), true);
|
||||
}
|
||||
|
||||
private ConfigFilter CreateConfigFilter()
|
||||
{
|
||||
ConfigFilter filter = new ConfigFilter() { AppliesTo = AppliesTo };
|
||||
IEnumerable<string> configKeysFromInput = GetConfigsSpecifiedByUser()
|
||||
.Where(x => (SwitchParameter)x.Value)
|
||||
.Select(x => x.Key);
|
||||
if (configKeysFromInput.Any())
|
||||
{
|
||||
filter.Keys = configKeysFromInput;
|
||||
}
|
||||
|
||||
return filter;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Profile.Models;
|
||||
using Microsoft.Azure.PowerShell.Common.Config;
|
||||
using Microsoft.WindowsAzure.Commands.Common.CustomAttributes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Management.Automation;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config
|
||||
{
|
||||
[Cmdlet("Update", "AzConfig", SupportsShouldProcess = true)]
|
||||
[OutputType(typeof(PSConfig))]
|
||||
[CmdletPreview(PreviewMessage)]
|
||||
public class UpdateConfigCommand : ConfigCommandBase, IDynamicParameters
|
||||
{
|
||||
private const string ProcessMessage = "Update the configs that apply to \"{0}\" by the following keys: {1}.";
|
||||
private string ProcessTarget => $"Configs in scope {Scope}";
|
||||
|
||||
public new object GetDynamicParameters() => GetDynamicParameters(
|
||||
(ConfigDefinition config) => new RuntimeDefinedParameter(
|
||||
config.Key, config.ValueType,
|
||||
new Collection<Attribute>() { new ParameterAttribute {
|
||||
HelpMessage = config.HelpMessage,
|
||||
ValueFromPipelineByPropertyName = true
|
||||
} }
|
||||
));
|
||||
|
||||
protected override void BeginProcessing()
|
||||
{
|
||||
base.BeginProcessing();
|
||||
if (AppliesTo == null)
|
||||
{
|
||||
AppliesTo = ConfigFilter.GlobalAppliesTo;
|
||||
}
|
||||
}
|
||||
|
||||
public override void ExecuteCmdlet()
|
||||
{
|
||||
var configsFromInput = GetConfigsSpecifiedByUser();
|
||||
if (!configsFromInput.Any())
|
||||
{
|
||||
WriteWarning($"Please specify the key(s) of the configs to update. Run `help {MyInvocation.MyCommand.Name}` for more information.");
|
||||
return;
|
||||
}
|
||||
base.ConfirmAction(
|
||||
string.Format(ProcessMessage, AppliesTo, string.Join(", ", configsFromInput.Select(x => x.Key))),
|
||||
ProcessTarget,
|
||||
() => UpdateConfigs(configsFromInput));
|
||||
}
|
||||
|
||||
private void UpdateConfigs(IEnumerable<(string, object)> configsToUpdate)
|
||||
{
|
||||
foreach ((string key, object value) in configsToUpdate)
|
||||
{
|
||||
ConfigData updated = ConfigManager.UpdateConfig(new UpdateConfigOptions(key, value, Scope)
|
||||
{
|
||||
AppliesTo = AppliesTo
|
||||
});
|
||||
WriteObject(new PSConfig(updated));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,10 @@
|
|||
<Project>
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory).., Directory.Build.targets))\Directory.Build.targets" />
|
||||
<Target Name ="BuildAssemblyLoadContextProject" AfterTargets="Build" Condition="'$(Configuration)' == 'Debug'">
|
||||
<!-- Skip in live unit testing https://docs.microsoft.com/en-us/visualstudio/test/live-unit-testing-faq?view=vs-2022#can-i-customize-my-live-unit-testing-builds- -->
|
||||
<Target Name ="BuildAssemblyLoadContextProject" AfterTargets="Build" Condition="'$(Configuration)' == 'Debug' And '$(BuildingForLiveUnitTesting)' != 'true'">
|
||||
<Exec Command="dotnet build ../AuthenticationAssemblyLoadContext/AuthenticationAssemblyLoadContext.csproj"/>
|
||||
</Target>
|
||||
<Target Name="AddAccountsPsm1Dependency" AfterTargets="Build" Condition="'$(Configuration)' == 'Debug'">
|
||||
<Target Name="AddAccountsPsm1Dependency" AfterTargets="Build" Condition="'$(Configuration)' == 'Debug' And '$(BuildingForLiveUnitTesting)' != 'true'">
|
||||
<Exec Command="pwsh -NonInteractive -NoLogo -NoProfile -Command ". '$(OutDir)../../../tools/AddModulePsm1Dependency.ps1' -ModuleFolder '$(OutDir)' -IgnorePwshVersion "" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.PowerShell.Common.Config;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Profile.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// The output model of config-related cmdlets.
|
||||
/// </summary>
|
||||
public class PSConfig
|
||||
{
|
||||
public string Key { get; }
|
||||
public object Value { get; }
|
||||
public ConfigScope Scope { get; } = ConfigScope.CurrentUser;
|
||||
public string AppliesTo { get; }
|
||||
public string HelpMessage { get; }
|
||||
public object DefaultValue { get; }
|
||||
public PSConfig(ConfigData config)
|
||||
{
|
||||
Value = config.Value;
|
||||
Scope = config.Scope;
|
||||
AppliesTo = config.AppliesTo;
|
||||
|
||||
var def = config.Definition;
|
||||
Key = def.Key;
|
||||
HelpMessage = def.HelpMessage;
|
||||
DefaultValue = def.DefaultValue;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,6 +14,9 @@ Manages credentials and common configuration for all Azure modules.
|
|||
### [Add-AzEnvironment](Add-AzEnvironment.md)
|
||||
Adds endpoints and metadata for an instance of Azure Resource Manager.
|
||||
|
||||
### [Clear-AzConfig](Clear-AzConfig.md)
|
||||
Clears the values of configs that are set by the user.
|
||||
|
||||
### [Clear-AzContext](Clear-AzContext.md)
|
||||
Remove all Azure credentials, account, and subscription information.
|
||||
|
||||
|
@ -56,6 +59,9 @@ Enables AzureRm prefix aliases for Az modules.
|
|||
### [Get-AzAccessToken](Get-AzAccessToken.md)
|
||||
Get raw access token. When using -ResourceUrl, please make sure the value does match current Azure environment. You may refer to the value of `(Get-AzContext).Environment`.
|
||||
|
||||
### [Get-AzConfig](Get-AzConfig.md)
|
||||
Gets the configs of Azure PowerShell.
|
||||
|
||||
### [Get-AzContext](Get-AzContext.md)
|
||||
Gets the metadata used to authenticate Azure Resource Manager requests.
|
||||
|
||||
|
@ -120,3 +126,6 @@ Sets properties for an Azure environment.
|
|||
### [Uninstall-AzureRm](Uninstall-AzureRm.md)
|
||||
Removes all AzureRm modules from a machine.
|
||||
|
||||
### [Update-AzConfig](Update-AzConfig.md)
|
||||
Updates the configs of Azure PowerShell.
|
||||
|
||||
|
|
|
@ -0,0 +1,251 @@
|
|||
---
|
||||
external help file: Microsoft.Azure.PowerShell.Cmdlets.Accounts.dll-Help.xml
|
||||
Module Name: Az.Accounts
|
||||
online version: https://docs.microsoft.com/powershell/module/az.accounts/clear-azconfig
|
||||
schema: 2.0.0
|
||||
---
|
||||
|
||||
# Clear-AzConfig
|
||||
|
||||
## SYNOPSIS
|
||||
Clears the values of configs that are set by the user.
|
||||
|
||||
## SYNTAX
|
||||
|
||||
### ClearAll
|
||||
```
|
||||
Clear-AzConfig [-All] [-Force] [-PassThru] [-AppliesTo <String>] [-Scope <ConfigScope>]
|
||||
[-DefaultProfile <IAzureContextContainer>] [-WhatIf] [-Confirm] [<CommonParameters>]
|
||||
```
|
||||
|
||||
### ClearByKey
|
||||
```
|
||||
Clear-AzConfig [-PassThru] [-AppliesTo <String>] [-Scope <ConfigScope>]
|
||||
[-DefaultProfile <IAzureContextContainer>] [-WhatIf] [-Confirm] [-DefaultSubscriptionForLogin]
|
||||
[-EnableDataCollection] [-EnableInterceptSurvey] [-SuppressWarningMessage] [<CommonParameters>]
|
||||
```
|
||||
|
||||
## DESCRIPTION
|
||||
{{ Fill in the Description }}
|
||||
|
||||
## EXAMPLES
|
||||
|
||||
### Example 1
|
||||
```powershell
|
||||
Clear-AzConfig -Todo
|
||||
```
|
||||
|
||||
```output
|
||||
Todo
|
||||
```
|
||||
|
||||
Todo
|
||||
|
||||
## PARAMETERS
|
||||
|
||||
### -All
|
||||
Clear all configs.
|
||||
|
||||
```yaml
|
||||
Type: System.Management.Automation.SwitchParameter
|
||||
Parameter Sets: ClearAll
|
||||
Aliases:
|
||||
|
||||
Required: True
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -AppliesTo
|
||||
Specifies what part of Azure PowerShell the config applies to.
|
||||
Possible values are:
|
||||
- "Az": the config applies to all modules and cmdlets of Azure PowerShell.
|
||||
- Module name: the config applies to a certain module of Azure PowerShell.
|
||||
For example, "Az.Storage".
|
||||
- Cmdlet name: the config applies to a certain cmdlet of Azure PowerShell.
|
||||
For example, "Get-AzKeyVault".
|
||||
If not specified, when getting configs, output will be all of the above; when updating or clearing configs, it defaults to "Az"
|
||||
|
||||
```yaml
|
||||
Type: System.String
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -DefaultProfile
|
||||
The credentials, account, tenant, and subscription used for communication with Azure.
|
||||
|
||||
```yaml
|
||||
Type: Microsoft.Azure.Commands.Common.Authentication.Abstractions.Core.IAzureContextContainer
|
||||
Parameter Sets: (All)
|
||||
Aliases: AzContext, AzureRmContext, AzureCredential
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -DefaultSubscriptionForLogin
|
||||
Subscription name or GUID.
|
||||
If defined, when logging in Azure PowerShell without specifying the subscription, this one will be used to select the default context.
|
||||
|
||||
```yaml
|
||||
Type: System.Management.Automation.SwitchParameter
|
||||
Parameter Sets: ClearByKey
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -EnableDataCollection
|
||||
todo
|
||||
|
||||
```yaml
|
||||
Type: System.Management.Automation.SwitchParameter
|
||||
Parameter Sets: ClearByKey
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -EnableInterceptSurvey
|
||||
When enabled, a message of taking part in the survey about the user experience of Azure PowerShell will prompt at low frequency.
|
||||
|
||||
```yaml
|
||||
Type: System.Management.Automation.SwitchParameter
|
||||
Parameter Sets: ClearByKey
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -Force
|
||||
Do not ask for confirmation when clearing all configs.
|
||||
|
||||
```yaml
|
||||
Type: System.Management.Automation.SwitchParameter
|
||||
Parameter Sets: ClearAll
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -PassThru
|
||||
Returns true if cmdlet executes correctly.
|
||||
|
||||
```yaml
|
||||
Type: System.Management.Automation.SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -Scope
|
||||
Determines the scope of config changes, for example, whether changes apply only to the current process, or to all sessions started by this user.
|
||||
By default it is CurrentUser.
|
||||
|
||||
```yaml
|
||||
Type: Microsoft.Azure.PowerShell.Common.Config.ConfigScope
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
Accepted values: CurrentUser, Process, Default
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -SuppressWarningMessage
|
||||
Controls if the warning messages of upcoming breaking changes are enabled or suppressed.
|
||||
The messages are typically displayed when a cmdlet that will have breaking change in the future is executed.
|
||||
|
||||
```yaml
|
||||
Type: System.Management.Automation.SwitchParameter
|
||||
Parameter Sets: ClearByKey
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -Confirm
|
||||
Prompts you for confirmation before running the cmdlet.
|
||||
|
||||
```yaml
|
||||
Type: System.Management.Automation.SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases: cf
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -WhatIf
|
||||
Shows what would happen if the cmdlet runs.
|
||||
The cmdlet is not run.
|
||||
|
||||
```yaml
|
||||
Type: System.Management.Automation.SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases: wi
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### CommonParameters
|
||||
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
|
||||
|
||||
## INPUTS
|
||||
|
||||
### None
|
||||
|
||||
## OUTPUTS
|
||||
|
||||
### System.Boolean
|
||||
|
||||
## NOTES
|
||||
|
||||
## RELATED LINKS
|
|
@ -0,0 +1,168 @@
|
|||
---
|
||||
external help file: Microsoft.Azure.PowerShell.Cmdlets.Accounts.dll-Help.xml
|
||||
Module Name: Az.Accounts
|
||||
online version: https://docs.microsoft.com/powershell/module/az.accounts/get-azconfig
|
||||
schema: 2.0.0
|
||||
---
|
||||
|
||||
# Get-AzConfig
|
||||
|
||||
## SYNOPSIS
|
||||
Gets the configs of Azure PowerShell.
|
||||
|
||||
## SYNTAX
|
||||
|
||||
```
|
||||
Get-AzConfig [-AppliesTo <String>] [-Scope <ConfigScope>] [-DefaultProfile <IAzureContextContainer>]
|
||||
[-DefaultSubscriptionForLogin] [-EnableDataCollection] [-EnableInterceptSurvey] [-SuppressWarningMessage]
|
||||
[<CommonParameters>]
|
||||
```
|
||||
|
||||
## DESCRIPTION
|
||||
{{ Fill in the Description }}
|
||||
|
||||
## EXAMPLES
|
||||
|
||||
### Example 1
|
||||
```powershell
|
||||
Get-AzConfig
|
||||
```
|
||||
|
||||
```output
|
||||
Todo
|
||||
```
|
||||
|
||||
Todo
|
||||
|
||||
## PARAMETERS
|
||||
|
||||
### -AppliesTo
|
||||
Specifies what part of Azure PowerShell the config applies to.
|
||||
Possible values are:
|
||||
- "Az": the config applies to all modules and cmdlets of Azure PowerShell.
|
||||
- Module name: the config applies to a certain module of Azure PowerShell.
|
||||
For example, "Az.Storage".
|
||||
- Cmdlet name: the config applies to a certain cmdlet of Azure PowerShell.
|
||||
For example, "Get-AzKeyVault".
|
||||
If not specified, when getting configs, output will be all of the above; when updating or clearing configs, it defaults to "Az"
|
||||
|
||||
```yaml
|
||||
Type: System.String
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -DefaultProfile
|
||||
The credentials, account, tenant, and subscription used for communication with Azure.
|
||||
|
||||
```yaml
|
||||
Type: Microsoft.Azure.Commands.Common.Authentication.Abstractions.Core.IAzureContextContainer
|
||||
Parameter Sets: (All)
|
||||
Aliases: AzContext, AzureRmContext, AzureCredential
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -DefaultSubscriptionForLogin
|
||||
Subscription name or GUID.
|
||||
If defined, when logging in Azure PowerShell without specifying the subscription, this one will be used to select the default context.
|
||||
|
||||
```yaml
|
||||
Type: System.Management.Automation.SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -EnableDataCollection
|
||||
todo
|
||||
|
||||
```yaml
|
||||
Type: System.Management.Automation.SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -EnableInterceptSurvey
|
||||
When enabled, a message of taking part in the survey about the user experience of Azure PowerShell will prompt at low frequency.
|
||||
|
||||
```yaml
|
||||
Type: System.Management.Automation.SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -Scope
|
||||
Determines the scope of config changes, for example, whether changes apply only to the current process, or to all sessions started by this user.
|
||||
By default it is CurrentUser.
|
||||
|
||||
```yaml
|
||||
Type: Microsoft.Azure.PowerShell.Common.Config.ConfigScope
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
Accepted values: CurrentUser, Process, Default
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -SuppressWarningMessage
|
||||
Controls if the warning messages of upcoming breaking changes are enabled or suppressed.
|
||||
The messages are typically displayed when a cmdlet that will have breaking change in the future is executed.
|
||||
|
||||
```yaml
|
||||
Type: System.Management.Automation.SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### CommonParameters
|
||||
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
|
||||
|
||||
## INPUTS
|
||||
|
||||
### None
|
||||
|
||||
## OUTPUTS
|
||||
|
||||
### Microsoft.Azure.Commands.Common.Authentication.Config.PSConfig
|
||||
|
||||
## NOTES
|
||||
|
||||
## RELATED LINKS
|
|
@ -0,0 +1,199 @@
|
|||
---
|
||||
external help file: Microsoft.Azure.PowerShell.Cmdlets.Accounts.dll-Help.xml
|
||||
Module Name: Az.Accounts
|
||||
online version: https://docs.microsoft.com/powershell/module/az.accounts/update-azconfig
|
||||
schema: 2.0.0
|
||||
---
|
||||
|
||||
# Update-AzConfig
|
||||
|
||||
## SYNOPSIS
|
||||
Updates the configs of Azure PowerShell.
|
||||
|
||||
## SYNTAX
|
||||
|
||||
```
|
||||
Update-AzConfig [-AppliesTo <String>] [-Scope <ConfigScope>] [-DefaultProfile <IAzureContextContainer>]
|
||||
[-WhatIf] [-Confirm] [-DefaultSubscriptionForLogin <String>] [-EnableDataCollection <Boolean>]
|
||||
[-EnableInterceptSurvey <Boolean>] [-SuppressWarningMessage <Boolean>] [<CommonParameters>]
|
||||
```
|
||||
|
||||
## DESCRIPTION
|
||||
{{ Fill in the Description }}
|
||||
|
||||
## EXAMPLES
|
||||
|
||||
### Example 1
|
||||
```powershell
|
||||
Update-AzConfig -Todo $true
|
||||
```
|
||||
|
||||
```output
|
||||
Todo
|
||||
```
|
||||
|
||||
Todo
|
||||
|
||||
## PARAMETERS
|
||||
|
||||
### -AppliesTo
|
||||
Specifies what part of Azure PowerShell the config applies to.
|
||||
Possible values are:
|
||||
- "Az": the config applies to all modules and cmdlets of Azure PowerShell.
|
||||
- Module name: the config applies to a certain module of Azure PowerShell.
|
||||
For example, "Az.Storage".
|
||||
- Cmdlet name: the config applies to a certain cmdlet of Azure PowerShell.
|
||||
For example, "Get-AzKeyVault".
|
||||
If not specified, when getting configs, output will be all of the above; when updating or clearing configs, it defaults to "Az"
|
||||
|
||||
```yaml
|
||||
Type: System.String
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -DefaultProfile
|
||||
The credentials, account, tenant, and subscription used for communication with Azure.
|
||||
|
||||
```yaml
|
||||
Type: Microsoft.Azure.Commands.Common.Authentication.Abstractions.Core.IAzureContextContainer
|
||||
Parameter Sets: (All)
|
||||
Aliases: AzContext, AzureRmContext, AzureCredential
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -DefaultSubscriptionForLogin
|
||||
Subscription name or GUID.
|
||||
If defined, when logging in Azure PowerShell without specifying the subscription, this one will be used to select the default context.
|
||||
|
||||
```yaml
|
||||
Type: System.String
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: True (ByPropertyName)
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -EnableDataCollection
|
||||
todo
|
||||
|
||||
```yaml
|
||||
Type: System.Boolean
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: True (ByPropertyName)
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -EnableInterceptSurvey
|
||||
When enabled, a message of taking part in the survey about the user experience of Azure PowerShell will prompt at low frequency.
|
||||
|
||||
```yaml
|
||||
Type: System.Boolean
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: True (ByPropertyName)
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -Scope
|
||||
Determines the scope of config changes, for example, whether changes apply only to the current process, or to all sessions started by this user.
|
||||
By default it is CurrentUser.
|
||||
|
||||
```yaml
|
||||
Type: Microsoft.Azure.PowerShell.Common.Config.ConfigScope
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
Accepted values: CurrentUser, Process, Default
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -SuppressWarningMessage
|
||||
Controls if the warning messages of upcoming breaking changes are enabled or suppressed.
|
||||
The messages are typically displayed when a cmdlet that will have breaking change in the future is executed.
|
||||
|
||||
```yaml
|
||||
Type: System.Boolean
|
||||
Parameter Sets: (All)
|
||||
Aliases:
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: True (ByPropertyName)
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -Confirm
|
||||
Prompts you for confirmation before running the cmdlet.
|
||||
|
||||
```yaml
|
||||
Type: System.Management.Automation.SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases: cf
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### -WhatIf
|
||||
Shows what would happen if the cmdlet runs.
|
||||
The cmdlet is not run.
|
||||
|
||||
```yaml
|
||||
Type: System.Management.Automation.SwitchParameter
|
||||
Parameter Sets: (All)
|
||||
Aliases: wi
|
||||
|
||||
Required: False
|
||||
Position: Named
|
||||
Default value: None
|
||||
Accept pipeline input: False
|
||||
Accept wildcard characters: False
|
||||
```
|
||||
|
||||
### CommonParameters
|
||||
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
|
||||
|
||||
## INPUTS
|
||||
|
||||
### None
|
||||
|
||||
## OUTPUTS
|
||||
|
||||
### Microsoft.Azure.Commands.Common.Authentication.Config.PSConfig
|
||||
|
||||
## NOTES
|
||||
|
||||
## RELATED LINKS
|
|
@ -0,0 +1,214 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Exceptions;
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config;
|
||||
using Microsoft.Azure.PowerShell.Common.Config;
|
||||
using Microsoft.Rest.ClientRuntime.Azure.TestFramework;
|
||||
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Azure.Authentication.Test.Config
|
||||
{
|
||||
public class ClearConfigTests : ConfigTestsBase
|
||||
{
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void CanClearSingleConfig()
|
||||
{
|
||||
string key = "FalseByDefault";
|
||||
IConfigManager icm = GetConfigManager(new SimpleTypedConfig<bool>(key, "{help message}", false));
|
||||
Assert.False(icm.GetConfigValue<bool>(key));
|
||||
|
||||
icm.UpdateConfig(new UpdateConfigOptions(key, true, ConfigScope.Process));
|
||||
Assert.True(icm.GetConfigValue<bool>(key));
|
||||
|
||||
icm.ClearConfig(new ClearConfigOptions(key, ConfigScope.Process));
|
||||
Assert.False(icm.GetConfigValue<bool>(key));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void CannotClearUnknownConfig()
|
||||
{
|
||||
IConfigManager configurationManager = GetConfigManager();
|
||||
|
||||
Assert.Throws<AzPSArgumentException>(() =>
|
||||
{
|
||||
configurationManager.ClearConfig(new ClearConfigOptions("NeverRegistered", ConfigScope.CurrentUser));
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void ShouldNotThrowToClearConfigNeverSet()
|
||||
{
|
||||
string key1 = "key1";
|
||||
var config1 = new SimpleTypedConfig<bool>(key1, "{help message}", false);
|
||||
string key2 = "key2";
|
||||
var config2 = new SimpleTypedConfig<bool>(key2, "{help message}", false);
|
||||
IConfigManager icm = GetConfigManager(config1, config2);
|
||||
|
||||
icm.ClearConfig(key1, ConfigScope.CurrentUser);
|
||||
icm.ClearConfig(key2, ConfigScope.Process);
|
||||
icm.ClearConfig(null, ConfigScope.CurrentUser);
|
||||
icm.ClearConfig(null, ConfigScope.Process);
|
||||
icm.ClearConfig(new ClearConfigOptions(null, ConfigScope.CurrentUser)
|
||||
{
|
||||
AppliesTo = null
|
||||
});
|
||||
icm.ClearConfig(new ClearConfigOptions(null, ConfigScope.Process)
|
||||
{
|
||||
AppliesTo = null
|
||||
});
|
||||
icm.ClearConfig(new ClearConfigOptions(null, ConfigScope.CurrentUser)
|
||||
{
|
||||
AppliesTo = "Az.Accounts"
|
||||
});
|
||||
icm.ClearConfig(new ClearConfigOptions(null, ConfigScope.Process)
|
||||
{
|
||||
AppliesTo = "Az.Accounts"
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void CanClearSingleConfigInJson()
|
||||
{
|
||||
IConfigManager icm = GetConfigManager();
|
||||
string key = "DisableSomething";
|
||||
icm.RegisterConfig(new SimpleTypedConfig<bool>(key, "{help message}", false));
|
||||
icm.BuildConfig();
|
||||
|
||||
Assert.False(icm.GetConfigValue<bool>(key));
|
||||
|
||||
icm.UpdateConfig(new UpdateConfigOptions(key, true, ConfigScope.CurrentUser));
|
||||
Assert.True(icm.GetConfigValue<bool>(key));
|
||||
|
||||
icm.ClearConfig(new ClearConfigOptions(key, ConfigScope.CurrentUser));
|
||||
Assert.False(icm.GetConfigValue<bool>(key));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void CanClearAllConfigsInJson()
|
||||
{
|
||||
string key1 = "key1";
|
||||
var config1 = new SimpleTypedConfig<bool>(key1, "{help message}", false);
|
||||
string key2 = "key2";
|
||||
var config2 = new SimpleTypedConfig<bool>(key2, "{help message}", false);
|
||||
ConfigManager cm = GetConfigManager(config1, config2) as ConfigManager;
|
||||
|
||||
Assert.False(cm.GetConfigValue<bool>(key1));
|
||||
Assert.False(cm.GetConfigValue<bool>(key2));
|
||||
|
||||
// Scenario 1: update the configs, applying to Az
|
||||
cm.UpdateConfig(new UpdateConfigOptions(key1, true, ConfigScope.CurrentUser));
|
||||
Assert.True(cm.GetConfigValue<bool>(key1));
|
||||
cm.UpdateConfig(new UpdateConfigOptions(key2, true, ConfigScope.CurrentUser));
|
||||
Assert.True(cm.GetConfigValue<bool>(key2));
|
||||
|
||||
// clear all configs by specifying `null` as the key, applying to Az
|
||||
cm.ClearConfig(null, ConfigScope.CurrentUser);
|
||||
Assert.False(cm.GetConfigValue<bool>(key1));
|
||||
Assert.False(cm.GetConfigValue<bool>(key2));
|
||||
|
||||
// Scenario 2: update the configs, applying to Az.Accounts
|
||||
cm.UpdateConfig(new UpdateConfigOptions(key1, true, ConfigScope.CurrentUser) { AppliesTo = "Az.Accounts" });
|
||||
Assert.True(cm.GetConfigValueInternal<bool>(key1, new InternalInvocationInfo() { ModuleName = "Az.Accounts" }));
|
||||
cm.UpdateConfig(new UpdateConfigOptions(key2, true, ConfigScope.CurrentUser) { AppliesTo = "Az.Accounts" });
|
||||
Assert.True(cm.GetConfigValueInternal<bool>(key2, new InternalInvocationInfo() { ModuleName = "Az.Accounts" }));
|
||||
|
||||
// clear all configs, applying to Az.Accounts
|
||||
cm.ClearConfig(new ClearConfigOptions(null, ConfigScope.CurrentUser) { AppliesTo = "Az.Accounts" });
|
||||
Assert.False(cm.GetConfigValueInternal<bool>(key1, new InternalInvocationInfo() { ModuleName = "Az.Accounts" }));
|
||||
Assert.False(cm.GetConfigValueInternal<bool>(key2, new InternalInvocationInfo() { ModuleName = "Az.Accounts" }));
|
||||
|
||||
// Scenario 3: update the configs, applying differently
|
||||
cm.UpdateConfig(new UpdateConfigOptions(key1, true, ConfigScope.CurrentUser) { AppliesTo = "Az.Accounts" });
|
||||
Assert.True(cm.GetConfigValueInternal<bool>(key1, new InternalInvocationInfo() { ModuleName = "Az.Accounts" }));
|
||||
cm.UpdateConfig(new UpdateConfigOptions(key2, true, ConfigScope.CurrentUser) { AppliesTo = "Az.KeyVault" });
|
||||
Assert.True(cm.GetConfigValueInternal<bool>(key2, new InternalInvocationInfo() { ModuleName = "Az.KeyVault" }));
|
||||
|
||||
// clear all configs, applying anything
|
||||
cm.ClearConfig(null, ConfigScope.CurrentUser);
|
||||
Assert.False(cm.GetConfigValueInternal<bool>(key1, new InternalInvocationInfo() { ModuleName = "Az.Accounts" }));
|
||||
Assert.False(cm.GetConfigValueInternal<bool>(key2, new InternalInvocationInfo() { ModuleName = "Az.KeyVault" }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void ShouldNotThrowWhenClearConfigNeverSet()
|
||||
{
|
||||
string key = "DisableSomething";
|
||||
var config = new SimpleTypedConfig<bool>(key, "{help message}", false);
|
||||
IConfigManager icm = GetConfigManager(config);
|
||||
|
||||
icm.ClearConfig(key, ConfigScope.CurrentUser);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void CanClearByScope()
|
||||
{
|
||||
const string boolKey = "BoolKey";
|
||||
var boolConfig = new SimpleTypedConfig<bool>(boolKey, "", false);
|
||||
const string intKey = "intKey";
|
||||
var intConfig = new SimpleTypedConfig<int>(intKey, "", 0);
|
||||
var icm = GetConfigManager(boolConfig, intConfig);
|
||||
|
||||
icm.UpdateConfig(new UpdateConfigOptions(boolKey, true, ConfigScope.CurrentUser));
|
||||
icm.UpdateConfig(new UpdateConfigOptions(intKey, 10, ConfigScope.CurrentUser));
|
||||
icm.UpdateConfig(new UpdateConfigOptions(boolKey, true, ConfigScope.Process));
|
||||
icm.UpdateConfig(new UpdateConfigOptions(intKey, 10, ConfigScope.Process));
|
||||
|
||||
icm.ClearConfig(new ClearConfigOptions(boolKey, ConfigScope.Process));
|
||||
icm.ClearConfig(new ClearConfigOptions(intKey, ConfigScope.Process));
|
||||
|
||||
foreach (var configData in icm.ListConfigs())
|
||||
{
|
||||
Assert.NotEqual(ConfigScope.Process, configData.Scope);
|
||||
}
|
||||
|
||||
icm.ClearConfig(boolKey, ConfigScope.CurrentUser);
|
||||
icm.ClearConfig(intKey, ConfigScope.CurrentUser);
|
||||
|
||||
foreach (var configData in icm.ListConfigs())
|
||||
{
|
||||
Assert.NotEqual(ConfigScope.CurrentUser, configData.Scope);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void AppliesToShouldDefaultToAz()
|
||||
{
|
||||
const string boolKey = "BoolKey";
|
||||
var boolConfig = new SimpleTypedConfig<bool>(boolKey, "", false);
|
||||
var icm = GetConfigManager(boolConfig);
|
||||
|
||||
const string appliesTo = "Az.A";
|
||||
icm.UpdateConfig(new UpdateConfigOptions(boolKey, true, ConfigScope.CurrentUser)
|
||||
{
|
||||
AppliesTo = appliesTo
|
||||
});
|
||||
|
||||
icm.ClearConfig(boolKey, ConfigScope.CurrentUser);
|
||||
Assert.Single(icm.ListConfigs(new ConfigFilter() { Keys = new string[] { boolKey }, AppliesTo = appliesTo }));
|
||||
|
||||
icm.ClearConfig(new ClearConfigOptions(boolKey, ConfigScope.CurrentUser) { AppliesTo = appliesTo });
|
||||
Assert.Empty(icm.ListConfigs(new ConfigFilter() { Keys = new string[] { boolKey }, AppliesTo = appliesTo }));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Exceptions;
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config;
|
||||
using Microsoft.Rest.ClientRuntime.Azure.TestFramework;
|
||||
using Microsoft.WindowsAzure.Commands.Common;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Xunit;
|
||||
using Microsoft.Azure.PowerShell.Common.Config;
|
||||
|
||||
namespace Microsoft.Azure.Authentication.Test.Config
|
||||
{
|
||||
public class ConfigDefinitionTests : ConfigTestsBase
|
||||
{
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void CanValidateInput() {
|
||||
const string boolKey = "BoolKey";
|
||||
var boolConfig = new SimpleTypedConfig<bool>(boolKey, "", false);
|
||||
var rangedIntConfig = new RangedConfig();
|
||||
var icm = GetConfigManagerWithInitState(null, null, boolConfig, rangedIntConfig);
|
||||
|
||||
Assert.Throws<AzPSArgumentException>(() => { icm.UpdateConfig(boolKey, 0, ConfigScope.CurrentUser); });
|
||||
Assert.Throws<AzPSArgumentException>(() => { icm.UpdateConfig(rangedIntConfig.Key, true, ConfigScope.CurrentUser); });
|
||||
Assert.Throws<AzPSArgumentException>(() => { icm.UpdateConfig(rangedIntConfig.Key, -1, ConfigScope.CurrentUser); });
|
||||
}
|
||||
|
||||
private class RangedConfig : TypedConfig<int>
|
||||
{
|
||||
public override object DefaultValue => 0;
|
||||
|
||||
public override string Key => "RangedKey";
|
||||
|
||||
public override string HelpMessage => "";
|
||||
|
||||
public override void Validate(object value)
|
||||
{
|
||||
base.Validate(value);
|
||||
int valueAsInt = (int)value;
|
||||
if (valueAsInt < 0 || valueAsInt > 100)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException($"The value of config {Key} must be in between 0 and 100.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config;
|
||||
using Microsoft.Azure.PowerShell.Authentication.Test.Mocks;
|
||||
using Microsoft.Azure.PowerShell.Common.Config;
|
||||
using Microsoft.WindowsAzure.Commands.Common.Test.Mocks;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Microsoft.Azure.Authentication.Test.Config
|
||||
{
|
||||
public class ConfigTestsBase
|
||||
{
|
||||
private readonly Action<MockDataStore, string> _noopFileWriter = (x, y) => { };
|
||||
private readonly Action<MockEnvironmentVariableProvider> _noopEnvVarWriter = (x) => { };
|
||||
|
||||
/// <summary>
|
||||
/// Initializes and returns an <see cref="IConfigManager"/> with the specified configs registered.
|
||||
/// </summary>
|
||||
/// <param name="config">Definitions of configs to be registered to the config manager.</param>
|
||||
/// <returns>A config manager ready to use.</returns>
|
||||
protected IConfigManager GetConfigManager(params ConfigDefinition[] config) => GetConfigManagerWithInitState(null, null, config);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes and returns an <see cref="IConfigManager"/> with the specified configs registered with initial state.
|
||||
/// </summary>
|
||||
/// <param name="configFileWriter">An action to set up the config file before config manager initializes.</param>
|
||||
/// <param name="envVarWriter">An action to set up the environments before config manager initializes.</param>
|
||||
/// <param name="config">Definitions of configs to be registered to the config manager.</param>
|
||||
/// <returns>A config manager with initial state, ready to use.</returns>
|
||||
protected IConfigManager GetConfigManagerWithInitState(Action<MockDataStore, string> configFileWriter, Action<MockEnvironmentVariableProvider> envVarWriter, params ConfigDefinition[] config)
|
||||
{
|
||||
if (configFileWriter == null)
|
||||
{
|
||||
configFileWriter = _noopFileWriter;
|
||||
}
|
||||
|
||||
if (envVarWriter == null)
|
||||
{
|
||||
envVarWriter = _noopEnvVarWriter;
|
||||
}
|
||||
|
||||
string configPath = Path.GetRandomFileName();
|
||||
var mockDataStore = new MockDataStore();
|
||||
configFileWriter(mockDataStore, configPath);
|
||||
var environmentVariables = new MockEnvironmentVariableProvider();
|
||||
envVarWriter(environmentVariables);
|
||||
ConfigInitializer ci = new ConfigInitializer(new List<string>() { configPath })
|
||||
{
|
||||
DataStore = mockDataStore,
|
||||
EnvironmentVariableProvider = environmentVariables
|
||||
};
|
||||
IConfigManager icm = ci.GetConfigManager();
|
||||
foreach (var configDefinition in config)
|
||||
{
|
||||
icm.RegisterConfig(configDefinition);
|
||||
}
|
||||
icm.BuildConfig();
|
||||
return icm;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,339 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Exceptions;
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config;
|
||||
using Microsoft.Azure.PowerShell.Common.Config;
|
||||
using Microsoft.Rest.ClientRuntime.Azure.TestFramework;
|
||||
using System.Linq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Azure.Authentication.Test.Config
|
||||
{
|
||||
public class GetConfigTests : ConfigTestsBase
|
||||
{
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void CanGetAppliesTo()
|
||||
{
|
||||
const string key = "EnableTelemetry";
|
||||
var def = new SimpleTypedConfig<bool>(
|
||||
key,
|
||||
"Enable telemetry",
|
||||
true);
|
||||
IConfigManager icm = GetConfigManager(def);
|
||||
|
||||
var config = icm.ListConfigs().Single();
|
||||
Assert.NotNull(config);
|
||||
Assert.Equal(key, config.Definition.Key);
|
||||
|
||||
icm.UpdateConfig(new UpdateConfigOptions(key, false, ConfigScope.CurrentUser));
|
||||
config = icm.ListConfigs().Single();
|
||||
Assert.Equal(ConfigFilter.GlobalAppliesTo, config.AppliesTo);
|
||||
|
||||
icm.UpdateConfig(new UpdateConfigOptions(key, false, ConfigScope.CurrentUser) { AppliesTo = "Az.KeyVault" });
|
||||
config = icm.ListConfigs(new ConfigFilter() { AppliesTo = "Az.KeyVault" }).Single();
|
||||
Assert.Equal("Az.KeyVault", config.AppliesTo);
|
||||
|
||||
icm.UpdateConfig(new UpdateConfigOptions(key, false, ConfigScope.CurrentUser) { AppliesTo = "Get-AzKeyVault" });
|
||||
config = icm.ListConfigs(new ConfigFilter { AppliesTo = "Get-AzKeyVault" }).Single();
|
||||
Assert.Equal("Get-AzKeyVault", config.AppliesTo);
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void ShouldReturnEmptyWhenFilterIsWrong()
|
||||
{
|
||||
const string key = "EnableTelemetry";
|
||||
var config = new SimpleTypedConfig<bool>(
|
||||
key,
|
||||
"Enable telemetry",
|
||||
true);
|
||||
var icm = GetConfigManager(config);
|
||||
Assert.NotEmpty(icm.ListConfigs());
|
||||
Assert.NotEmpty(icm.ListConfigs(null));
|
||||
Assert.Empty(icm.ListConfigs(new ConfigFilter() { Keys = new string[] { "Never Exist" } }));
|
||||
Assert.Empty(icm.ListConfigs(new ConfigFilter() { AppliesTo = "xxx" }));
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void CanGetAndListRegisteredConfigs()
|
||||
{
|
||||
const string key1 = "EnableTelemetry";
|
||||
var config1 = new SimpleTypedConfig<bool>(
|
||||
key1,
|
||||
"Enable telemetry",
|
||||
true);
|
||||
TestConfig config2 = new TestConfig();
|
||||
IConfigManager configurationManager = GetConfigManager(config1, config2);
|
||||
|
||||
var listResult = configurationManager.ListConfigs();
|
||||
Assert.Equal(2, listResult.Count());
|
||||
|
||||
ConfigData configData = listResult.Where(x => x.Definition.Key == key1).Single();
|
||||
Assert.Equal(true, configData.Value);
|
||||
Assert.True(configurationManager.GetConfigValue<bool>(key1));
|
||||
|
||||
ConfigData tempConfigResult = listResult.Where(x => x.Definition.Key == config2.Key).Single();
|
||||
Assert.Equal(config2.DefaultValue, tempConfigResult.Value);
|
||||
Assert.Equal(config2.HelpMessage, tempConfigResult.Definition.HelpMessage);
|
||||
Assert.Equal(config2.DefaultValue, configurationManager.GetConfigValue<int>(config2.Key));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void CanUpdateAndList()
|
||||
{
|
||||
IConfigManager configurationManager = GetConfigManager();
|
||||
const string key = "EnableTelemetry";
|
||||
configurationManager.RegisterConfig(
|
||||
new SimpleTypedConfig<bool>(
|
||||
key,
|
||||
"Enable telemetry",
|
||||
true));
|
||||
configurationManager.BuildConfig();
|
||||
var updatedConfig = configurationManager.UpdateConfig(new UpdateConfigOptions(key, false, ConfigScope.Process));
|
||||
Assert.Equal(key, updatedConfig.Definition.Key);
|
||||
Assert.False((bool)updatedConfig.Value);
|
||||
Assert.False(configurationManager.GetConfigValue<bool>(key));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void CanGetFromEnvironmentVar()
|
||||
{
|
||||
const string key = "FromEnv";
|
||||
const string envKey = "ENV_VAR_FOR_CONFIG";
|
||||
var config = new SimpleTypedConfig<int>(key, "", -1, envKey);
|
||||
const int value = 20;
|
||||
|
||||
var configurationManager = GetConfigManagerWithInitState(null, (envVar) => { envVar.Set(envKey, value.ToString()); }, config);
|
||||
|
||||
Assert.Equal(value, configurationManager.GetConfigValue<int>(key));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void ShouldNotThrowWhenEnvVarIsWrong()
|
||||
{
|
||||
const string key = "FromEnv";
|
||||
const string envKey = "ENV_VAR_FOR_CONFIG";
|
||||
const int defaultValue = -1;
|
||||
var config = new SimpleTypedConfig<int>(key, "", defaultValue, envKey);
|
||||
const bool valueWithWrongType = true;
|
||||
var configurationManager = GetConfigManagerWithInitState(null, envVar =>
|
||||
{
|
||||
envVar.Set(envKey, valueWithWrongType.ToString());
|
||||
}, config);
|
||||
|
||||
Assert.Equal(defaultValue, configurationManager.GetConfigValue<int>(key));
|
||||
}
|
||||
|
||||
private class TestConfig : TypedConfig<int>
|
||||
{
|
||||
public override object DefaultValue => -1;
|
||||
|
||||
public override string Key => "TempConfig";
|
||||
|
||||
public override string HelpMessage => "temp config";
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void CanGetFromJson()
|
||||
{
|
||||
var config1 = new SimpleTypedConfig<int>("Retry", "", -1);
|
||||
var config2 = new SimpleTypedConfig<string[]>("Array", "", null);
|
||||
IConfigManager icm = GetConfigManagerWithInitState((dataStore, path) =>
|
||||
{
|
||||
dataStore.WriteFile(path,
|
||||
@"{
|
||||
""Az"": {
|
||||
""Retry"": 100
|
||||
},
|
||||
""Az.KeyVault"": {
|
||||
""Array"": [""a"",""b""]
|
||||
},
|
||||
""Get-AzKeyVault"": {
|
||||
""Array"": [""k"",""v""]
|
||||
}
|
||||
}");
|
||||
}, null, config1, config2);
|
||||
ConfigManager cm = icm as ConfigManager;
|
||||
Assert.Equal(100, cm.GetConfigValue<int>("Retry"));
|
||||
Assert.Equal(new string[] { "a", "b" }, cm.GetConfigValueInternal<string[]>("Array", new InternalInvocationInfo() { ModuleName = "Az.KeyVault" }));
|
||||
Assert.Equal(new string[] { "k", "v" }, cm.GetConfigValueInternal<string[]>("Array", new InternalInvocationInfo() { ModuleName = "Az.KeyVault", CmdletName = "Get-AzKeyVault" }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void ThrowWhenGetUnknownConfig()
|
||||
{
|
||||
IConfigManager entry = GetConfigManager();
|
||||
entry.BuildConfig();
|
||||
|
||||
Assert.Throws<AzPSArgumentNullException>(() => { entry.GetConfigValue<int>(null); });
|
||||
Assert.Throws<AzPSArgumentException>(() => { entry.GetConfigValue<int>(""); });
|
||||
|
||||
const string key = "KeyThatIsNotRegistered";
|
||||
Assert.Throws<AzPSArgumentException>(() => { entry.GetConfigValue<int>(key); });
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void CanFilterByKeyAndAppliesTo()
|
||||
{
|
||||
const string key = "key";
|
||||
var config = new SimpleTypedConfig<bool>(key, "", true);
|
||||
var icm = GetConfigManager(config);
|
||||
const string module = "Az.KeyVault";
|
||||
icm.UpdateConfig(new UpdateConfigOptions(key, false, ConfigScope.CurrentUser) { AppliesTo = module });
|
||||
Assert.Single(icm.ListConfigs(new ConfigFilter() { Keys = new[] { key }, AppliesTo = module }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void CanFilterByKey()
|
||||
{
|
||||
const string key = "key";
|
||||
var config = new SimpleTypedConfig<bool>(key, "", true);
|
||||
var icm = GetConfigManager(config);
|
||||
const string module = "Az.KeyVault";
|
||||
icm.UpdateConfig(new UpdateConfigOptions(key, false, ConfigScope.CurrentUser) { AppliesTo = module });
|
||||
var listResults = icm.ListConfigs(new ConfigFilter() { Keys = new[] { key } });
|
||||
Assert.Equal(2, listResults.Count());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void CanFilterByAppliesTo()
|
||||
{
|
||||
const string key1 = "key";
|
||||
var config1 = new SimpleTypedConfig<bool>(key1, "", true);
|
||||
const string key2 = "key2";
|
||||
var config2 = new SimpleTypedConfig<bool>(key2, "", true);
|
||||
var icm = GetConfigManager(config1, config2);
|
||||
|
||||
const string module = "Az.KeyVault";
|
||||
icm.UpdateConfig(new UpdateConfigOptions(key1, false, ConfigScope.CurrentUser) { AppliesTo = module });
|
||||
icm.UpdateConfig(new UpdateConfigOptions(key2, false, ConfigScope.CurrentUser) { AppliesTo = module });
|
||||
|
||||
var listResults = icm.ListConfigs(new ConfigFilter() { AppliesTo = module });
|
||||
Assert.Equal(2, listResults.Count());
|
||||
|
||||
listResults = icm.ListConfigs(new ConfigFilter() { AppliesTo = ConfigFilter.GlobalAppliesTo });
|
||||
Assert.Equal(2, listResults.Count());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void CanFilterByNoFilter()
|
||||
{
|
||||
const string key1 = "key";
|
||||
var config1 = new SimpleTypedConfig<bool>(key1, "", true);
|
||||
const string key2 = "key2";
|
||||
var config2 = new SimpleTypedConfig<bool>(key2, "", true);
|
||||
var icm = GetConfigManager(config1, config2);
|
||||
|
||||
const string module = "Az.KeyVault";
|
||||
icm.UpdateConfig(new UpdateConfigOptions(key1, false, ConfigScope.CurrentUser) { AppliesTo = module });
|
||||
icm.UpdateConfig(new UpdateConfigOptions(key2, false, ConfigScope.CurrentUser) { AppliesTo = module });
|
||||
var listResults = icm.ListConfigs();
|
||||
Assert.Equal(4, listResults.Count()); // default*2, module*2
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void CanListDefinitions()
|
||||
{
|
||||
const string key1 = "key";
|
||||
var config1 = new SimpleTypedConfig<bool>(key1, "", true);
|
||||
const string key2 = "key2";
|
||||
var config2 = new SimpleTypedConfig<bool>(key2, "", true);
|
||||
var config3 = new TestConfig();
|
||||
var icm = GetConfigManager(config1, config2, config3);
|
||||
|
||||
Assert.Equal(3, icm.ListConfigDefinitions().Count());
|
||||
|
||||
const string module = "Az.KeyVault";
|
||||
icm.UpdateConfig(new UpdateConfigOptions(key1, false, ConfigScope.CurrentUser) { AppliesTo = module });
|
||||
Assert.Equal(3, icm.ListConfigDefinitions().Count());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void CanGetScope()
|
||||
{
|
||||
const string key1 = "key";
|
||||
var config1 = new SimpleTypedConfig<bool>(key1, "", true);
|
||||
var config2 = new TestConfig();
|
||||
var icm = GetConfigManager(config1, config2);
|
||||
|
||||
var listResults = icm.ListConfigs();
|
||||
foreach (var config in listResults)
|
||||
{
|
||||
Assert.Equal(ConfigScope.Default, config.Scope);
|
||||
}
|
||||
|
||||
var updated = icm.UpdateConfig(new UpdateConfigOptions(key1, false, ConfigScope.CurrentUser));
|
||||
Assert.Equal(ConfigScope.CurrentUser, updated.Scope);
|
||||
|
||||
updated = icm.UpdateConfig(new UpdateConfigOptions(key1, true, ConfigScope.Process));
|
||||
Assert.Equal(ConfigScope.Process, updated.Scope);
|
||||
|
||||
icm.ClearConfig(new ClearConfigOptions(key1, ConfigScope.Process));
|
||||
updated = icm.ListConfigs(new ConfigFilter() { Keys = new string[] { key1 } }).Single();
|
||||
Assert.Equal(ConfigScope.CurrentUser, updated.Scope);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void AppliesToShouldBeCaseInsensitive()
|
||||
{
|
||||
const string key = "key";
|
||||
var config = new SimpleTypedConfig<int>(key, "", 0);
|
||||
var icm = GetConfigManager(config);
|
||||
|
||||
icm.UpdateConfig(new UpdateConfigOptions(key, 1, ConfigScope.CurrentUser) { AppliesTo = "az.abc" });
|
||||
Assert.Equal(1, icm.ListConfigs(new ConfigFilter() { Keys = new[] { key }, AppliesTo = "az.abc" }).Single().Value);
|
||||
Assert.Equal(1, icm.ListConfigs(new ConfigFilter() { Keys = new[] { key }, AppliesTo = "Az.Abc" }).Single().Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void ListDefinitionsShouldBeDictOrder()
|
||||
{
|
||||
const string key1 = "key1";
|
||||
var config1 = new SimpleTypedConfig<int>(key1, "", 0);
|
||||
const string key2 = "key2";
|
||||
var config2 = new SimpleTypedConfig<int>(key2, "", 0);
|
||||
const string key3 = "key3";
|
||||
var config3 = new SimpleTypedConfig<int>(key3, "", 0);
|
||||
// register using wrong order
|
||||
var icm = GetConfigManager(config2, config1, config3);
|
||||
|
||||
for (int i = 0; i != 10; ++i)
|
||||
{
|
||||
var definitions = icm.ListConfigDefinitions();
|
||||
// expect return with dict order
|
||||
Assert.Equal(key1, definitions.ElementAt(0).Key);
|
||||
Assert.Equal(key2, definitions.ElementAt(1).Key);
|
||||
Assert.Equal(key3, definitions.ElementAt(2).Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config;
|
||||
using Microsoft.Azure.PowerShell.Common.Config;
|
||||
using Microsoft.Rest.ClientRuntime.Azure.TestFramework;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Azure.Authentication.Test.Config
|
||||
{
|
||||
public class PriorityTests : ConfigTestsBase
|
||||
{
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void UserConfigHigherThanSystemUserEnv()
|
||||
{
|
||||
const string retryKey = "Retry";
|
||||
const string envName = "ENV_FOR_RETRY";
|
||||
var config = new SimpleTypedConfig<int>(retryKey, "", -1, envName);
|
||||
IConfigManager icm = GetConfigManagerWithInitState((dataStore, path) =>
|
||||
{
|
||||
dataStore.WriteFile(path,
|
||||
@"{
|
||||
""Az"": {
|
||||
""Retry"": 100
|
||||
}
|
||||
}");
|
||||
}, envVar =>
|
||||
{
|
||||
envVar.Set(envName, "10", System.EnvironmentVariableTarget.User);
|
||||
}, config);
|
||||
Assert.Equal(100, icm.GetConfigValue<int>(retryKey));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void ProcessEnvHigherThanUserConfig()
|
||||
{
|
||||
|
||||
const string retryKey = "Retry";
|
||||
const string envName = "ENV_FOR_RETRY";
|
||||
var config = new SimpleTypedConfig<int>(retryKey, "", -1, envName);
|
||||
IConfigManager icm = GetConfigManagerWithInitState((dataStore, path) =>
|
||||
{
|
||||
dataStore.WriteFile(path,
|
||||
@"{
|
||||
""Az"": {
|
||||
""Retry"": 100
|
||||
}
|
||||
}");
|
||||
}, envVar =>
|
||||
{
|
||||
envVar.Set(envName, "10", System.EnvironmentVariableTarget.Process);
|
||||
}, config);
|
||||
Assert.Equal(10, icm.GetConfigValue<int>(retryKey));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void ProcessConfigHigherThanProcessEnv()
|
||||
{
|
||||
const string retryKey = "Retry";
|
||||
const string envName = "ENV_FOR_RETRY";
|
||||
var config = new SimpleTypedConfig<int>(retryKey, "", -1, envName);
|
||||
IConfigManager icm = GetConfigManagerWithInitState(null, envVar =>
|
||||
{
|
||||
envVar.Set(envName, "10", System.EnvironmentVariableTarget.Process);
|
||||
}, config);
|
||||
|
||||
icm.UpdateConfig(new UpdateConfigOptions(retryKey, 100, ConfigScope.Process));
|
||||
Assert.Equal(100, icm.GetConfigValue<int>(retryKey));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Exceptions;
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config;
|
||||
using Microsoft.Azure.PowerShell.Common.Config;
|
||||
using Microsoft.Rest.ClientRuntime.Azure.TestFramework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Azure.Authentication.Test.Config
|
||||
{
|
||||
public class RegisterConfigTests : ConfigTestsBase
|
||||
{
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void CannotRegisterSameKeyTwice()
|
||||
{
|
||||
IConfigManager entry = GetConfigManager();
|
||||
const string key = "CannotRegisterTwice";
|
||||
entry.RegisterConfig(new SimpleTypedConfig<int>(key, "", -1));
|
||||
Assert.Throws<AzPSArgumentException>(() =>
|
||||
{
|
||||
entry.RegisterConfig(new SimpleTypedConfig<object>(key, "", null));
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void CanRegisterSameConfigTwice()
|
||||
{
|
||||
IConfigManager entry = GetConfigManager();
|
||||
const string key = "CanRegisterTwice";
|
||||
SimpleTypedConfig<int> config = new SimpleTypedConfig<int>(key, "", -1);
|
||||
entry.RegisterConfig(config);
|
||||
entry.RegisterConfig(config);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void CanGetDefaultValue()
|
||||
{
|
||||
IConfigManager entry = GetConfigManager();
|
||||
const string key = "CanGetConfigValue";
|
||||
SimpleTypedConfig<int> config = new SimpleTypedConfig<int>(key, "", -1);
|
||||
entry.RegisterConfig(config);
|
||||
entry.BuildConfig();
|
||||
Assert.Equal(-1, entry.GetConfigValue<int>(key));
|
||||
|
||||
entry.UpdateConfig(new UpdateConfigOptions(key, 10, ConfigScope.Process));
|
||||
Assert.Equal(10, entry.GetConfigValue<int>(key));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(TestData))]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void CanRegisterConfigs(ConfigDefinition config)
|
||||
{
|
||||
ConfigManager manager = GetConfigManager() as ConfigManager;
|
||||
manager.RegisterConfig(config);
|
||||
manager.BuildConfig();
|
||||
Assert.Equal(config.DefaultValue, manager.GetConfigValueInternal(config.Key, null));
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> TestData => new List<object[]>
|
||||
{
|
||||
new object[] { new SimpleTypedConfig<int>("Config", "", -1) },
|
||||
new object[] { new SimpleTypedConfig<int>("Config", "", -1, "ENV_VAR_FOR_CONFIG") },
|
||||
new object[] { new SimpleTypedConfig<int?>("Config", "", null) },
|
||||
new object[] { new SimpleTypedConfig<int?>("Config", "", 1) },
|
||||
new object[] { new SimpleTypedConfig<bool>("Config", "", true) },
|
||||
new object[] { new SimpleTypedConfig<string>("Config", "", "default") },
|
||||
new object[] { new SimpleTypedConfig<double>("Config", "", 3.1415926) },
|
||||
new object[] { new SimpleTypedConfig<int[]>("Config", "", new int[] { 1,2,3 }) },
|
||||
new object[] { new SimpleTypedConfig<string[]>("Config", "", new string[] { "Az.Accounts", "Az.Compute" })},
|
||||
new object[] { new SimpleTypedConfig<DateTime>("Config", "", DateTime.MinValue) },
|
||||
new object[] { new SimpleTypedConfig<bool>("Config", "", true, "env_var", new [] { AppliesTo.Cmdlet }) },
|
||||
new object[] { new TestConfigForDefaultValue() }
|
||||
};
|
||||
|
||||
private class TestConfigForDefaultValue : ConfigDefinition
|
||||
{
|
||||
public override object DefaultValue => (decimal)10;
|
||||
|
||||
public override string Key => nameof(TestConfigForDefaultValue);
|
||||
|
||||
public override string HelpMessage => "";
|
||||
|
||||
public override Type ValueType => typeof(decimal);
|
||||
|
||||
public override void Validate(object value) { base.Validate(value); }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Exceptions;
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config;
|
||||
using Microsoft.Azure.PowerShell.Common.Config;
|
||||
using Microsoft.Rest.ClientRuntime.Azure.TestFramework;
|
||||
using Moq;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Azure.Authentication.Test.Config
|
||||
{
|
||||
public class UpdateConfigTests : ConfigTestsBase
|
||||
{
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void CanUpdateJsonFile()
|
||||
{
|
||||
const string retryKey = "Retry";
|
||||
var intConfig = new SimpleTypedConfig<int>(retryKey, "", -1);
|
||||
const string arrayKey = "Array";
|
||||
var arrayConfig = new SimpleTypedConfig<string[]>(arrayKey, "", null);
|
||||
IConfigManager icm = GetConfigManagerWithInitState((dataStore, path) =>
|
||||
{
|
||||
dataStore.WriteFile(path,
|
||||
@"{
|
||||
""Az"": {
|
||||
""Retry"": 100
|
||||
},
|
||||
""Az.KeyVault"": {
|
||||
""Array"": [""a"",""b""]
|
||||
}
|
||||
}");
|
||||
}, null, intConfig, arrayConfig);
|
||||
ConfigManager cm = icm as ConfigManager;
|
||||
Assert.Equal(100, cm.GetConfigValue<int>(retryKey));
|
||||
Assert.Equal(new string[] { "a", "b" }, cm.GetConfigValueInternal<string[]>(arrayKey, new InternalInvocationInfo() { ModuleName = "Az.KeyVault" }));
|
||||
ConfigData updated = icm.UpdateConfig(new UpdateConfigOptions(retryKey, 10, ConfigScope.CurrentUser));
|
||||
Assert.Equal(10, updated.Value);
|
||||
Assert.Equal(10, icm.GetConfigValue<int>(retryKey));
|
||||
|
||||
string[] updatedArray = new string[] { "c", "d" };
|
||||
ConfigData updated2 = icm.UpdateConfig(new UpdateConfigOptions(arrayKey, updatedArray, ConfigScope.CurrentUser)
|
||||
{
|
||||
AppliesTo = "Az.KeyVault"
|
||||
});
|
||||
Assert.Equal(updatedArray, updated2.Value);
|
||||
Assert.Equal(updatedArray, cm.GetConfigValueInternal<string[]>(arrayKey, new InternalInvocationInfo() { ModuleName = "Az.KeyVault" }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void CanUpdateConfigForCmdlet()
|
||||
{
|
||||
const string warningKey = "DisalbeWarning";
|
||||
var warningConfig = new SimpleTypedConfig<bool>(warningKey, "", false);
|
||||
IConfigManager icm = GetConfigManager(warningConfig);
|
||||
|
||||
Assert.False(icm.GetConfigValue<bool>(warningKey));
|
||||
|
||||
ConfigData updated = icm.UpdateConfig(new UpdateConfigOptions(warningKey, true, ConfigScope.CurrentUser)
|
||||
{
|
||||
AppliesTo = "Get-AzKeyVault"
|
||||
});
|
||||
Assert.Equal(true, updated.Value);
|
||||
Assert.False(icm.GetConfigValue<bool>(warningKey));
|
||||
|
||||
var cm = (ConfigManager)icm;
|
||||
Assert.True(cm.GetConfigValueInternal<bool>(warningKey, new InternalInvocationInfo("Az.KeyVault", "Get-AzKeyVault")));
|
||||
Assert.False(cm.GetConfigValueInternal<bool>(warningKey, new InternalInvocationInfo("Az.Storage", "Get-AzStorageAccount")));
|
||||
Assert.False(cm.GetConfigValueInternal<bool>(warningKey, new InternalInvocationInfo("Az.KeyVault", "Remove-AzKeyVault")));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void ThrowWhenOptionIsInvalid()
|
||||
{
|
||||
const string key1 = "key";
|
||||
var config1 = new SimpleTypedConfig<bool>(key1, "", true);
|
||||
const string key2 = "key2";
|
||||
var config2 = new SimpleTypedConfig<bool>(key2, "", true);
|
||||
var icm = GetConfigManager(config1, config2);
|
||||
|
||||
Assert.Throws<AzPSArgumentNullException>(() => icm.UpdateConfig(null));
|
||||
Assert.Throws<ArgumentNullException>(() => icm.UpdateConfig(new UpdateConfigOptions(null, null, ConfigScope.CurrentUser)));
|
||||
Assert.Throws<AzPSArgumentException>(() => icm.UpdateConfig(new UpdateConfigOptions(key1, "ThisShouldNotBeAString", ConfigScope.CurrentUser)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void AppliesToShouldBeCaseInsensitive()
|
||||
{
|
||||
const string key = "key";
|
||||
var config = new SimpleTypedConfig<int>(key, "", 0);
|
||||
var icm = GetConfigManager(config);
|
||||
|
||||
icm.UpdateConfig(new UpdateConfigOptions(key, 1, ConfigScope.CurrentUser) { AppliesTo = "az.abc" });
|
||||
icm.UpdateConfig(new UpdateConfigOptions(key, 2, ConfigScope.CurrentUser) { AppliesTo = "Az.Abc" });
|
||||
Assert.Equal(2, icm.ListConfigs(new ConfigFilter() { Keys = new[] { key }, AppliesTo = "az.abc" }).Single().Value);
|
||||
Assert.Equal(2, icm.ListConfigs(new ConfigFilter() { Keys = new[] { key }, AppliesTo = "Az.Abc" }).Single().Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void CanUpdateConfigHasSideEffect()
|
||||
{
|
||||
int calls = 0;
|
||||
var mock = new Mock<ConfigDefinition>();
|
||||
mock.Setup(c => c.Key).Returns("key");
|
||||
mock.Setup(c => c.CanApplyTo).Returns(new[] { AppliesTo.Az });
|
||||
mock.Setup(c => c.Apply(It.IsAny<bool>())).Callback((object v) =>
|
||||
{
|
||||
switch (++calls)
|
||||
{
|
||||
case 1:
|
||||
Assert.True((bool)v);
|
||||
break;
|
||||
case 2:
|
||||
Assert.False((bool)v);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
var config = mock.Object;
|
||||
var icm = GetConfigManager(config);
|
||||
icm.UpdateConfig(config.Key, true, ConfigScope.CurrentUser);
|
||||
icm.UpdateConfig(config.Key, false, ConfigScope.CurrentUser);
|
||||
Assert.Equal(2, calls);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void ShouldNotUpdateConfigIfSideEffectThrows()
|
||||
{
|
||||
var config = new ConfigWithSideEffect((bool v) => throw new Exception("oops"));
|
||||
var icm = GetConfigManager(config);
|
||||
Assert.Throws<Exception>(() => icm.UpdateConfig(config.Key, !config.TypedDefaultValue, ConfigScope.CurrentUser));
|
||||
Assert.Equal(config.TypedDefaultValue, icm.GetConfigValue<bool>(config.Key));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void ShouldThrowIfAppliesToIsWrong()
|
||||
{
|
||||
var key = "OnlyAppliesToAz";
|
||||
var config = new SimpleTypedConfig<bool>(key, "", true, null, new AppliesTo[] {AppliesTo.Az});
|
||||
var icm = GetConfigManager(config);
|
||||
Assert.Throws<AzPSArgumentException>(() => icm.UpdateConfig(new UpdateConfigOptions(key, true, ConfigScope.CurrentUser) { AppliesTo = "Az.Accounts" }));
|
||||
}
|
||||
|
||||
internal class ConfigWithSideEffect : TypedConfig<bool>
|
||||
{
|
||||
private readonly Action<bool> _sideEffect;
|
||||
|
||||
public ConfigWithSideEffect(Action<bool> sideEffect)
|
||||
{
|
||||
_sideEffect = sideEffect;
|
||||
}
|
||||
public override object DefaultValue => true;
|
||||
|
||||
public override string Key => "ConfigWithSideEffect";
|
||||
|
||||
public override string HelpMessage => "{HelpMessage}";
|
||||
|
||||
protected override void ApplyTyped(bool value)
|
||||
{
|
||||
base.ApplyTyped(value);
|
||||
_sideEffect(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -376,7 +376,8 @@ namespace Microsoft.WindowsAzure.Commands.Common.Test.Mocks
|
|||
() =>
|
||||
{
|
||||
writeLocks[path] = false;
|
||||
virtualStore[path] = Encoding.Default.GetString(buffer);
|
||||
// trim \0 otherwise json fails to parse
|
||||
virtualStore[path] = Encoding.UTF8.GetString(buffer).TrimEnd('\0');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Interfaces;
|
||||
|
||||
namespace Microsoft.Azure.PowerShell.Authentication.Test.Mocks
|
||||
{
|
||||
public class MockEnvironmentVariableProvider : IEnvironmentVariableProvider
|
||||
{
|
||||
private readonly IDictionary<string, string> _processVariables = new Dictionary<string, string>();
|
||||
private readonly IDictionary<string, string> _userVariables = new Dictionary<string, string>();
|
||||
private readonly IDictionary<string, string> _systemVariables = new Dictionary<string, string>();
|
||||
|
||||
public string Get(string variableName, EnvironmentVariableTarget target = EnvironmentVariableTarget.Process)
|
||||
{
|
||||
GetVariablesByTarget(target).TryGetValue(variableName, out var result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private IDictionary<string, string> GetVariablesByTarget(EnvironmentVariableTarget target)
|
||||
{
|
||||
switch (target)
|
||||
{
|
||||
case EnvironmentVariableTarget.Process:
|
||||
return _processVariables;
|
||||
case EnvironmentVariableTarget.User:
|
||||
return _userVariables;
|
||||
case EnvironmentVariableTarget.Machine:
|
||||
return _systemVariables;
|
||||
default:
|
||||
throw new ArgumentException(nameof(target));
|
||||
}
|
||||
}
|
||||
|
||||
public void Set(string variableName, string value, EnvironmentVariableTarget target = EnvironmentVariableTarget.Process)
|
||||
{
|
||||
GetVariablesByTarget(target)[variableName] = value;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Utilities;
|
||||
using Microsoft.Rest.ClientRuntime.Azure.TestFramework;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Test
|
||||
{
|
||||
public class PSNamingUtilitiesTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("Az.Accounts", true)]
|
||||
[InlineData("aZ.cOMPUTE", true)]
|
||||
[InlineData("az.stackhci", true)]
|
||||
[InlineData("", false)]
|
||||
[InlineData("AzureRM.Profile", false)]
|
||||
[InlineData("Az", false)]
|
||||
[InlineData("AzAccounts", false)]
|
||||
[InlineData("Get-AzContext", false)]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void CanRecognizeModuleName(string name, bool expected)
|
||||
{
|
||||
Assert.Equal(expected, PSNamingUtilities.IsModuleName(name));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Get-AzContext", true)]
|
||||
[InlineData("update-azstorageaccount", true)]
|
||||
[InlineData("Remove-AzEverything", true)]
|
||||
[InlineData("Get-AzDataFactoryV2", true)]
|
||||
[InlineData("", false)]
|
||||
[InlineData("Az.Accounts", false)]
|
||||
[InlineData("Az", false)]
|
||||
[InlineData("NewAzVM", false)]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void CanRecognizeCmdletName(string name, bool expected)
|
||||
{
|
||||
Assert.Equal(expected, PSNamingUtilities.IsCmdletName(name));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Az.Accounts", true)]
|
||||
[InlineData("aZ.cOMPUTE", true)]
|
||||
[InlineData("az.stackhci", true)]
|
||||
[InlineData("Get-AzContext", true)]
|
||||
[InlineData("Remove-AzEverything", true)]
|
||||
[InlineData("Get-AzDataFactoryV2", true)]
|
||||
[InlineData("", false)]
|
||||
[InlineData("Az", false)]
|
||||
[InlineData("NewAzVM", false)]
|
||||
[Trait(TestTraits.AcceptanceType, TestTraits.CheckIn)]
|
||||
public void CanRecognizeModuleOrCmdletName(string name, bool expected)
|
||||
{
|
||||
Assert.Equal(expected, PSNamingUtilities.IsModuleOrCmdletName(name));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,10 +24,11 @@ using Microsoft.Azure.Commands.Common.Authentication.Abstractions.Core;
|
|||
using Microsoft.Azure.Commands.Common.Authentication.Authentication.TokenCache;
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Factories;
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Properties;
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
using TraceLevel = System.Diagnostics.TraceLevel;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication
|
||||
{
|
||||
|
@ -244,12 +245,23 @@ namespace Microsoft.Azure.Commands.Common.Authentication
|
|||
session.TokenCacheDirectory = autoSave.CacheDirectory;
|
||||
session.TokenCacheFile = autoSave.CacheFile;
|
||||
|
||||
InitializeConfigs(session);
|
||||
InitializeDataCollection(session);
|
||||
session.RegisterComponent(HttpClientOperationsFactory.Name, () => HttpClientOperationsFactory.Create());
|
||||
session.TokenCache = session.TokenCache ?? new AzureTokenCache();
|
||||
return session;
|
||||
}
|
||||
|
||||
private static void InitializeConfigs(AzureSession session)
|
||||
{
|
||||
var fallbackList = new List<string>()
|
||||
{
|
||||
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".Azure", "PSConfig.json"),
|
||||
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), ".Azure", "PSConfig.json")
|
||||
};
|
||||
new ConfigInitializer(fallbackList).InitializeForAzureSession(session);
|
||||
}
|
||||
|
||||
public class AdalSession : AzureSession
|
||||
{
|
||||
#if !NETSTANDARD
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Abstractions;
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Interfaces;
|
||||
using Microsoft.Azure.PowerShell.Common.Config;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes the config file and config manager.
|
||||
/// </summary>
|
||||
internal class ConfigInitializer
|
||||
{
|
||||
internal IDataStore DataStore { get; set; } = new DiskDataStore();
|
||||
private static readonly object _fsLock = new object();
|
||||
|
||||
internal IEnvironmentVariableProvider EnvironmentVariableProvider { get; set; } = new DefaultEnvironmentVariableProvider();
|
||||
|
||||
private readonly string _pathToConfigFile;
|
||||
|
||||
public ConfigInitializer(IEnumerable<string> paths)
|
||||
{
|
||||
_ = paths ?? throw new ArgumentNullException(nameof(paths));
|
||||
_pathToConfigFile = GetPathToConfigFile(paths);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loop through the fallback list of paths of the config file. Returns the first usable one.
|
||||
/// </summary>
|
||||
/// <param name="paths">A list of paths to the config file. When one is not usable, it will fallback to the next.</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ApplicationException">When no one in the list is usable.</exception>
|
||||
private string GetPathToConfigFile(IEnumerable<string> paths)
|
||||
{
|
||||
// find first exist path and use it
|
||||
foreach (string path in paths)
|
||||
{
|
||||
if (DataStore.FileExists(path))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
}
|
||||
// if not found, use the first writable path
|
||||
foreach (string path in paths)
|
||||
{
|
||||
try
|
||||
{
|
||||
DirectoryInfo dir = new FileInfo(path).Directory;
|
||||
DataStore.CreateDirectory(dir.FullName); // create directory if not exists
|
||||
using (var _ = DataStore.OpenForExclusiveWrite(path)) { }
|
||||
return path;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
throw new ApplicationException($"Failed to store the config file. Please make sure any one of the following paths is accessible: {string.Join(", ", paths)}");
|
||||
}
|
||||
|
||||
internal IConfigManager GetConfigManager()
|
||||
{
|
||||
lock (_fsLock)
|
||||
{
|
||||
ValidateConfigFile();
|
||||
}
|
||||
return new ConfigManager(_pathToConfigFile, DataStore, EnvironmentVariableProvider);
|
||||
}
|
||||
|
||||
private void ValidateConfigFileContent()
|
||||
{
|
||||
string json = DataStore.ReadFileAsText(_pathToConfigFile);
|
||||
|
||||
bool isValidJson = true;
|
||||
try
|
||||
{
|
||||
JObject.Parse(json);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
isValidJson = false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(json) || !isValidJson)
|
||||
{
|
||||
Debug.Write($"[ConfigInitializer] Failed to parse the config file at {_pathToConfigFile}. Clearing the file.");
|
||||
ResetConfigFileToDefault();
|
||||
}
|
||||
}
|
||||
|
||||
private void ValidateConfigFile()
|
||||
{
|
||||
if (!DataStore.FileExists(_pathToConfigFile))
|
||||
{
|
||||
ResetConfigFileToDefault();
|
||||
}
|
||||
else
|
||||
{
|
||||
ValidateConfigFileContent();
|
||||
}
|
||||
}
|
||||
|
||||
private void ResetConfigFileToDefault()
|
||||
{
|
||||
try
|
||||
{
|
||||
DataStore.WriteFile(_pathToConfigFile, @"{}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// do not halt for IO exception
|
||||
Debug.WriteLine(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
// todo: tests initializes configs in a different way. Maybe there should be an abstraction IConfigInitializer and two concrete classes ConfigInitializer + TestConfigInitializer
|
||||
internal void InitializeForAzureSession(AzureSession session)
|
||||
{
|
||||
IConfigManager configManager = GetConfigManager();
|
||||
session.RegisterComponent(nameof(IConfigManager), () => configManager);
|
||||
RegisterConfigs(configManager);
|
||||
configManager.BuildConfig();
|
||||
}
|
||||
|
||||
private void RegisterConfigs(IConfigManager configManager)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,468 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Abstractions;
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config.Internal;
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Interfaces;
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Providers;
|
||||
using Microsoft.Azure.Commands.Common.Exceptions;
|
||||
using Microsoft.Azure.Commands.ResourceManager.Common;
|
||||
using Microsoft.Azure.PowerShell.Common.Config;
|
||||
using Microsoft.WindowsAzure.Commands.Utilities.Common;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Management.Automation;
|
||||
using System.Threading;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config
|
||||
{
|
||||
/// <summary>
|
||||
/// Default implementation of <see cref="IConfigManager"/>, providing CRUD abilities to the configs.
|
||||
/// </summary>
|
||||
internal class ConfigManager : IConfigManager
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string ConfigFilePath { get; private set; }
|
||||
|
||||
private IConfigurationRoot _root;
|
||||
private readonly ConcurrentDictionary<string, ConfigDefinition> _configDefinitionMap = new ConcurrentDictionary<string, ConfigDefinition>(StringComparer.OrdinalIgnoreCase);
|
||||
private IOrderedEnumerable<KeyValuePair<string, ConfigDefinition>> OrderedConfigDefinitionMap => _configDefinitionMap.OrderBy(x => x.Key);
|
||||
private readonly ConcurrentDictionary<string, string> EnvironmentVariableToKeyMap = new ConcurrentDictionary<string, string>();
|
||||
private readonly IEnvironmentVariableProvider _environmentVariableProvider;
|
||||
private readonly IDataStore _dataStore;
|
||||
private readonly JsonConfigWriter _jsonConfigWriter;
|
||||
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of <see cref="ConfigManager"/>.
|
||||
/// </summary>
|
||||
/// <param name="configFilePath">Path to the config file.</param>
|
||||
/// <param name="dataStore">Provider of file system APIs.</param>
|
||||
/// <param name="environmentVariableProvider">Provider of environment variable APIs.</param>
|
||||
internal ConfigManager(string configFilePath, IDataStore dataStore, IEnvironmentVariableProvider environmentVariableProvider)
|
||||
{
|
||||
_ = dataStore ?? throw new AzPSArgumentNullException($"{nameof(dataStore)} cannot be null.", nameof(dataStore));
|
||||
_ = configFilePath ?? throw new AzPSArgumentNullException($"{nameof(configFilePath)} cannot be null.", nameof(configFilePath));
|
||||
_ = environmentVariableProvider ?? throw new AzPSArgumentNullException($"{nameof(environmentVariableProvider)} cannot be null.", nameof(environmentVariableProvider));
|
||||
ConfigFilePath = configFilePath;
|
||||
_environmentVariableProvider = environmentVariableProvider;
|
||||
_dataStore = dataStore;
|
||||
_jsonConfigWriter = new JsonConfigWriter(ConfigFilePath, _dataStore);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rebuild config hierarchy and load from the providers.
|
||||
/// </summary>
|
||||
public void BuildConfig()
|
||||
{
|
||||
var builder = new ConfigurationBuilder();
|
||||
|
||||
if (SharedUtilities.IsWindowsPlatform())
|
||||
{
|
||||
// User and machine level environment variables are only on Windows
|
||||
builder.AddEnvironmentVariables(Constants.ConfigProviderIds.MachineEnvironment, new EnvironmentVariablesConfigurationOptions()
|
||||
{
|
||||
EnvironmentVariableProvider = _environmentVariableProvider,
|
||||
EnvironmentVariableTarget = EnvironmentVariableTarget.Machine,
|
||||
EnvironmentVariableToKeyMap = EnvironmentVariableToKeyMap
|
||||
})
|
||||
.AddEnvironmentVariables(Constants.ConfigProviderIds.UserEnvironment, new EnvironmentVariablesConfigurationOptions()
|
||||
{
|
||||
EnvironmentVariableProvider = _environmentVariableProvider,
|
||||
EnvironmentVariableTarget = EnvironmentVariableTarget.User,
|
||||
EnvironmentVariableToKeyMap = EnvironmentVariableToKeyMap
|
||||
});
|
||||
}
|
||||
builder.AddJsonStream(Constants.ConfigProviderIds.UserConfig, _dataStore.ReadFileAsStream(ConfigFilePath))
|
||||
.AddEnvironmentVariables(Constants.ConfigProviderIds.ProcessEnvironment, new EnvironmentVariablesConfigurationOptions()
|
||||
{
|
||||
EnvironmentVariableProvider = _environmentVariableProvider,
|
||||
EnvironmentVariableTarget = EnvironmentVariableTarget.Process,
|
||||
EnvironmentVariableToKeyMap = EnvironmentVariableToKeyMap
|
||||
})
|
||||
.AddUnsettableInMemoryCollection(Constants.ConfigProviderIds.ProcessConfig);
|
||||
|
||||
_lock.EnterReadLock();
|
||||
try
|
||||
{
|
||||
_root = builder.Build();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_lock.ExitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void RegisterConfig(ConfigDefinition config)
|
||||
{
|
||||
// check if key already taken
|
||||
if (_configDefinitionMap.ContainsKey(config.Key))
|
||||
{
|
||||
if (_configDefinitionMap[config.Key] == config)
|
||||
{
|
||||
Debug.WriteLine($"Config with key [{config.Key}] was registered twice");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new AzPSArgumentException($"Duplicated config key. [{config.Key}] was already taken.", nameof(config.Key));
|
||||
}
|
||||
return;
|
||||
}
|
||||
// configure environment variable providers
|
||||
if (!string.IsNullOrEmpty(config.EnvironmentVariableName))
|
||||
{
|
||||
EnvironmentVariableToKeyMap[config.EnvironmentVariableName] = ConfigPathHelper.GetPathOfConfig(config.Key);
|
||||
}
|
||||
_configDefinitionMap[config.Key] = config;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public T GetConfigValue<T>(string key, object invocation = null)
|
||||
{
|
||||
if (invocation != null && !(invocation is InvocationInfo))
|
||||
{
|
||||
throw new AzPSArgumentException($"Type error: type of {nameof(invocation)} must be {nameof(InvocationInfo)}", nameof(invocation));
|
||||
}
|
||||
return GetConfigValueInternal<T>(key, new InvocationInfoAdapter((InvocationInfo)invocation));
|
||||
}
|
||||
|
||||
internal T GetConfigValueInternal<T>(string key, InternalInvocationInfo invocation) => (T)GetConfigValueInternal(key, invocation);
|
||||
|
||||
internal object GetConfigValueInternal(string key, InternalInvocationInfo invocation)
|
||||
{
|
||||
_ = key ?? throw new AzPSArgumentNullException($"{nameof(key)} cannot be null.", nameof(key));
|
||||
if (!_configDefinitionMap.TryGetValue(key, out ConfigDefinition definition) || definition == null)
|
||||
{
|
||||
throw new AzPSArgumentException($"Config with key [{key}] was not registered.", nameof(key));
|
||||
}
|
||||
|
||||
foreach (var path in ConfigPathHelper.EnumerateConfigPaths(key, invocation))
|
||||
{
|
||||
IConfigurationSection section = _root.GetSection(path);
|
||||
if (section.Exists())
|
||||
{
|
||||
(object value, _) = GetConfigValueOrDefault(section, definition);
|
||||
WriteDebug($"[ConfigManager] Got [{value}] from [{key}], Module = [{invocation?.ModuleName}], Cmdlet = [{invocation?.CmdletName}].");
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
WriteDebug($"[ConfigManager] Got nothing from [{key}], Module = [{invocation?.ModuleName}], Cmdlet = [{invocation?.CmdletName}]. Returning default value [{definition.DefaultValue}].");
|
||||
return definition.DefaultValue;
|
||||
}
|
||||
|
||||
private void WriteDebug(string message)
|
||||
{
|
||||
WriteMessage(message, AzureRMCmdlet.WriteDebugKey);
|
||||
}
|
||||
|
||||
private void WriteMessage(string message, string eventHandlerKey)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (AzureSession.Instance.TryGetComponent(eventHandlerKey, out EventHandler<StreamEventArgs> writeDebug))
|
||||
{
|
||||
writeDebug.Invoke(this, new StreamEventArgs() { Message = message });
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// do not throw when session is not initialized
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteWarning(string message)
|
||||
{
|
||||
WriteMessage(message, AzureRMCmdlet.WriteWarningKey);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<ConfigDefinition> ListConfigDefinitions()
|
||||
{
|
||||
return OrderedConfigDefinitionMap.Select(x => x.Value);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<ConfigData> ListConfigs(ConfigFilter filter = null)
|
||||
{
|
||||
IList<ConfigData> results = new List<ConfigData>();
|
||||
|
||||
// include all values
|
||||
ISet<string> noNeedForDefault = new HashSet<string>();
|
||||
foreach (var appliesToSection in _root.GetChildren())
|
||||
{
|
||||
foreach (var configSection in appliesToSection.GetChildren())
|
||||
{
|
||||
string key = configSection.Key;
|
||||
if (_configDefinitionMap.TryGetValue(key, out var configDefinition))
|
||||
{
|
||||
(object value, string providerId) = GetConfigValueOrDefault(configSection, configDefinition);
|
||||
ConfigScope scope = ConfigScopeHelper.GetScopeByProviderId(providerId);
|
||||
results.Add(new ConfigData(configDefinition, value, scope, appliesToSection.Key));
|
||||
// if a config is already set at global level, there's no need to return its default value
|
||||
if (string.Equals(ConfigFilter.GlobalAppliesTo, appliesToSection.Key, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
noNeedForDefault.Add(configDefinition.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// include default values
|
||||
IEnumerable<string> keys = filter?.Keys ?? Enumerable.Empty<string>();
|
||||
bool isRegisteredKey(string key) => _configDefinitionMap.Keys.Contains(key, StringComparer.OrdinalIgnoreCase);
|
||||
IEnumerable<ConfigDefinition> configDefinitions = keys.Any() ? keys.Where(isRegisteredKey).Select(key => _configDefinitionMap[key]) : OrderedConfigDefinitionMap.Select(x => x.Value);
|
||||
configDefinitions.Where(x => !noNeedForDefault.Contains(x.Key)).Select(x => GetDefaultConfigData(x)).ForEach(x => results.Add(x));
|
||||
|
||||
|
||||
if (keys.Any())
|
||||
{
|
||||
results = results.Where(x => keys.Contains(x.Definition.Key, StringComparer.OrdinalIgnoreCase)).ToList();
|
||||
}
|
||||
|
||||
string appliesTo = filter?.AppliesTo;
|
||||
if (!string.IsNullOrEmpty(appliesTo))
|
||||
{
|
||||
results = results.Where(x => string.Equals(appliesTo, x.AppliesTo, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the value and the ID of the corresponding provider of the config.
|
||||
/// </summary>
|
||||
/// <param name="section">The section that stores the config.</param>
|
||||
/// <param name="definition">The definition of the config.</param>
|
||||
/// <returns>A tuple containing the value of the config and the ID of the provider from which the value is got.</returns>
|
||||
/// <remarks>Exceptions are handled gracefully in this method.</remarks>
|
||||
private (object value, string providerId) GetConfigValueOrDefault(IConfigurationSection section, ConfigDefinition definition)
|
||||
{
|
||||
try
|
||||
{
|
||||
return section.Get(definition.ValueType);
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
WriteWarning($"[ConfigManager] Failed to get value for [{definition.Key}]. Using the default value [{definition.DefaultValue}] instead. Error: {ex.Message}. {ex.InnerException?.Message}");
|
||||
WriteDebug($"[ConfigManager] Exception: {ex.Message}, stack trace: \n{ex.StackTrace}");
|
||||
return (definition.DefaultValue, Constants.ConfigProviderIds.None);
|
||||
}
|
||||
}
|
||||
|
||||
private ConfigData GetDefaultConfigData(ConfigDefinition configDefinition)
|
||||
{
|
||||
return new ConfigData(configDefinition,
|
||||
configDefinition.DefaultValue,
|
||||
ConfigScope.Default,
|
||||
ConfigFilter.GlobalAppliesTo);
|
||||
}
|
||||
|
||||
// A bulk update API is currently unnecessary as we don't expect users to do that.
|
||||
// But if telemetry data proves it's a demanded feature, we might add it in the future.
|
||||
// public IEnumerable<Config> UpdateConfigs(IEnumerable<UpdateConfigOptions> updateConfigOptions) => updateConfigOptions.Select(UpdateConfig);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConfigData UpdateConfig(string key, object value, ConfigScope scope)
|
||||
{
|
||||
return UpdateConfig(new UpdateConfigOptions(key, value, scope));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConfigData UpdateConfig(UpdateConfigOptions options)
|
||||
{
|
||||
if (options == null)
|
||||
{
|
||||
throw new AzPSArgumentNullException($"{nameof(options)} cannot be null when updating config.", nameof(options));
|
||||
}
|
||||
|
||||
if (!_configDefinitionMap.TryGetValue(options.Key, out ConfigDefinition definition) || definition == null)
|
||||
{
|
||||
throw new AzPSArgumentException($"Config with key [{options.Key}] was not registered.", nameof(options.Key));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
definition.Validate(options.Value);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new AzPSArgumentException(e.Message, e);
|
||||
}
|
||||
|
||||
if (AppliesToHelper.TryParseAppliesTo(options.AppliesTo, out var appliesTo) && !definition.CanApplyTo.Contains(appliesTo))
|
||||
{
|
||||
throw new AzPSArgumentException($"[{options.AppliesTo}] is not a valid value for AppliesTo - it doesn't match any of ({AppliesToHelper.FormatOptions(definition.CanApplyTo)}).", nameof(options.AppliesTo));
|
||||
}
|
||||
|
||||
definition.Apply(options.Value);
|
||||
|
||||
string path = ConfigPathHelper.GetPathOfConfig(options.Key, options.AppliesTo);
|
||||
|
||||
switch (options.Scope)
|
||||
{
|
||||
case ConfigScope.Process:
|
||||
SetProcessLevelConfig(path, options.Value);
|
||||
break;
|
||||
case ConfigScope.CurrentUser:
|
||||
SetUserLevelConfig(path, options.Value);
|
||||
break;
|
||||
}
|
||||
|
||||
WriteDebug($"[ConfigManager] Updated [{options.Key}] to [{options.Value}]. Scope = [{options.Scope}], AppliesTo = [{options.AppliesTo}]");
|
||||
|
||||
return new ConfigData(definition, options.Value, options.Scope, options.AppliesTo);
|
||||
}
|
||||
|
||||
private void SetProcessLevelConfig(string path, object value)
|
||||
{
|
||||
GetProcessLevelConfigProvider().Set(path, value.ToString());
|
||||
}
|
||||
|
||||
private UnsettableMemoryConfigurationProvider GetProcessLevelConfigProvider()
|
||||
{
|
||||
return _root.GetConfigurationProvider(Constants.ConfigProviderIds.ProcessConfig) as UnsettableMemoryConfigurationProvider;
|
||||
}
|
||||
|
||||
private void SetUserLevelConfig(string path, object value)
|
||||
{
|
||||
_lock.EnterWriteLock();
|
||||
try
|
||||
{
|
||||
_jsonConfigWriter.Update(path, value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_lock.ExitWriteLock();
|
||||
}
|
||||
BuildConfig(); // reload the config values
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void ClearConfig(string key, ConfigScope scope) => ClearConfig(new ClearConfigOptions(key, scope));
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void ClearConfig(ClearConfigOptions options)
|
||||
{
|
||||
_ = options ?? throw new AzPSArgumentNullException($"{nameof(options)} cannot be null.", nameof(options));
|
||||
|
||||
bool clearAll = string.IsNullOrEmpty(options.Key);
|
||||
|
||||
if (clearAll)
|
||||
{
|
||||
ClearAllConfigs(options);
|
||||
}
|
||||
else
|
||||
{
|
||||
ClearConfigByKey(options);
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearAllConfigs(ClearConfigOptions options)
|
||||
{
|
||||
switch (options.Scope)
|
||||
{
|
||||
case ConfigScope.Process:
|
||||
ClearProcessLevelAllConfigs(options);
|
||||
break;
|
||||
case ConfigScope.CurrentUser:
|
||||
ClearUserLevelAllConfigs(options);
|
||||
break;
|
||||
default:
|
||||
throw new AzPSArgumentException($"[{options.Scope}] is not a valid scope when clearing configs.", nameof(options.Scope));
|
||||
}
|
||||
WriteDebug($"[ConfigManager] Cleared all the configs. Scope = [{options.Scope}].");
|
||||
}
|
||||
|
||||
private void ClearProcessLevelAllConfigs(ClearConfigOptions options)
|
||||
{
|
||||
var configProvider = GetProcessLevelConfigProvider();
|
||||
if (string.IsNullOrEmpty(options.AppliesTo))
|
||||
{
|
||||
configProvider.UnsetAll();
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var key in _configDefinitionMap.Keys)
|
||||
{
|
||||
configProvider.Unset(ConfigPathHelper.GetPathOfConfig(key, options.AppliesTo));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearUserLevelAllConfigs(ClearConfigOptions options)
|
||||
{
|
||||
_lock.EnterWriteLock();
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(options.AppliesTo))
|
||||
{
|
||||
_jsonConfigWriter.ClearAll();
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var key in _configDefinitionMap.Keys)
|
||||
{
|
||||
_jsonConfigWriter.Clear(ConfigPathHelper.GetPathOfConfig(key, options.AppliesTo));
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_lock.ExitWriteLock();
|
||||
}
|
||||
BuildConfig();
|
||||
}
|
||||
|
||||
private void ClearConfigByKey(ClearConfigOptions options)
|
||||
{
|
||||
if (!_configDefinitionMap.TryGetValue(options.Key, out ConfigDefinition definition))
|
||||
{
|
||||
throw new AzPSArgumentException($"Config with key [{options.Key}] was not registered.", nameof(options.Key));
|
||||
}
|
||||
|
||||
string path = ConfigPathHelper.GetPathOfConfig(definition.Key, options.AppliesTo);
|
||||
|
||||
switch (options.Scope)
|
||||
{
|
||||
case ConfigScope.Process:
|
||||
GetProcessLevelConfigProvider().Unset(path);
|
||||
break;
|
||||
case ConfigScope.CurrentUser:
|
||||
ClearUserLevelConfigByKey(path);
|
||||
break;
|
||||
}
|
||||
|
||||
WriteDebug($"[ConfigManager] Cleared [{options.Key}]. Scope = [{options.Scope}], AppliesTo = [{options.AppliesTo}]");
|
||||
}
|
||||
|
||||
private void ClearUserLevelConfigByKey(string key)
|
||||
{
|
||||
_lock.EnterWriteLock();
|
||||
try
|
||||
{
|
||||
_jsonConfigWriter.Clear(key);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_lock.ExitWriteLock();
|
||||
}
|
||||
BuildConfig();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Utilities;
|
||||
using Microsoft.Azure.PowerShell.Common.Config;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class to deal with AppliesTo (how large is the scope that the config affects Azure PowerShell).
|
||||
/// </summary>
|
||||
public static class AppliesToHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Tries to parse a user-input text to an <see cref="AppliesTo"/> enum.
|
||||
/// </summary>
|
||||
/// <param name="text">Input from user.</param>
|
||||
/// <param name="appliesTo">Result if successful.</param>
|
||||
/// <returns>True if parsed successfully.</returns>
|
||||
public static bool TryParseAppliesTo(string text, out AppliesTo appliesTo)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text) || string.Equals(ConfigFilter.GlobalAppliesTo, text, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
appliesTo = AppliesTo.Az;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (PSNamingUtilities.IsModuleName(text))
|
||||
{
|
||||
appliesTo = AppliesTo.Module;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (PSNamingUtilities.IsCmdletName(text))
|
||||
{
|
||||
appliesTo = AppliesTo.Cmdlet;
|
||||
return true;
|
||||
}
|
||||
|
||||
appliesTo = AppliesTo.Az;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a comma-divided string for human-readable description of the AppliesTo options.
|
||||
/// </summary>
|
||||
/// <param name="options">Options of AppliesTo.</param>
|
||||
/// <returns>The formated string.</returns>
|
||||
internal static string FormatOptions(IReadOnlyCollection<AppliesTo> options)
|
||||
{
|
||||
if (options == null || !options.Any())
|
||||
{
|
||||
throw new ArgumentException($"Make sure the config definition has a non-empty {nameof(ConfigDefinition.CanApplyTo)}.", nameof(options));
|
||||
}
|
||||
var sb = new StringBuilder();
|
||||
bool isFirst = true;
|
||||
foreach (var option in options)
|
||||
{
|
||||
if (!isFirst)
|
||||
{
|
||||
sb.Append(", ");
|
||||
isFirst = false;
|
||||
}
|
||||
switch (option)
|
||||
{
|
||||
case AppliesTo.Az:
|
||||
sb.Append(ConfigFilter.GlobalAppliesTo);
|
||||
break;
|
||||
case AppliesTo.Cmdlet:
|
||||
sb.Append("name of a cmdlet");
|
||||
break;
|
||||
case AppliesTo.Module:
|
||||
sb.Append("name of a module");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config.Internal;
|
||||
using Microsoft.Azure.PowerShell.Common.Config;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class to deal with the full path where configs are stored.
|
||||
/// </summary>
|
||||
internal static class ConfigPathHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a list of paths to check when getting a config value by key and invocation info.
|
||||
/// </summary>
|
||||
/// <param name="key">The key in the config definition.</param>
|
||||
/// <param name="invocation">Command invocation info, containing command name and module name.</param>
|
||||
public static IEnumerable<string> EnumerateConfigPaths(string key, InternalInvocationInfo invocation = null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(invocation?.CmdletName))
|
||||
{
|
||||
yield return GetPathOfConfig(key, invocation.CmdletName);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(invocation?.ModuleName))
|
||||
{
|
||||
yield return GetPathOfConfig(key, invocation.ModuleName);
|
||||
}
|
||||
yield return GetPathOfConfig(key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the path (full key) of a config by its key and what it applies to.
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="appliesTo">Global appliesTo by default.</param>
|
||||
/// <returns></returns>
|
||||
internal static string GetPathOfConfig(string key, string appliesTo = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(appliesTo))
|
||||
{
|
||||
appliesTo = ConfigFilter.GlobalAppliesTo;
|
||||
}
|
||||
return appliesTo + ConfigurationPath.KeyDelimiter + key;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Exceptions;
|
||||
using Microsoft.Azure.PowerShell.Common.Config;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config
|
||||
{
|
||||
internal static class ConfigScopeHelper
|
||||
{
|
||||
public static ConfigScope GetScopeByProviderId(string id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case Constants.ConfigProviderIds.MachineEnvironment:
|
||||
case Constants.ConfigProviderIds.UserEnvironment:
|
||||
case Constants.ConfigProviderIds.UserConfig:
|
||||
return ConfigScope.CurrentUser;
|
||||
case Constants.ConfigProviderIds.ProcessEnvironment:
|
||||
case Constants.ConfigProviderIds.ProcessConfig:
|
||||
return ConfigScope.Process;
|
||||
case Constants.ConfigProviderIds.None:
|
||||
return ConfigScope.Default;
|
||||
default:
|
||||
throw new AzPSArgumentOutOfRangeException($"Unexpected provider ID [{id}]. See {nameof(Constants.ConfigProviderIds)} class for all valid IDs.", nameof(id));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Interfaces;
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config
|
||||
{
|
||||
/// <summary>
|
||||
/// Default implementation of <see cref="IEnvironmentVariableProvider"/> that utilizes the <see cref="System.Environment"/> API.
|
||||
/// </summary>
|
||||
internal class DefaultEnvironmentVariableProvider : IEnvironmentVariableProvider
|
||||
{
|
||||
public string Get(string variableName, EnvironmentVariableTarget target = EnvironmentVariableTarget.Process)
|
||||
{
|
||||
return Environment.GetEnvironmentVariable(variableName, target);
|
||||
}
|
||||
|
||||
public void Set(string variableName, string value, EnvironmentVariableTarget target = EnvironmentVariableTarget.Process)
|
||||
{
|
||||
Environment.SetEnvironmentVariable(variableName, value, target);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config.Internal;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper for updating the config JSON file.
|
||||
/// </summary>
|
||||
internal class JsonConfigWriter
|
||||
{
|
||||
private readonly string _jsonConfigPath;
|
||||
private readonly IDataStore _dataStore;
|
||||
|
||||
public JsonConfigWriter(string jsonConfigPath, IDataStore dataStore)
|
||||
{
|
||||
_jsonConfigPath = jsonConfigPath;
|
||||
_dataStore = dataStore;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update a config value.
|
||||
/// </summary>
|
||||
/// <param name="key">The full path of the config.</param>
|
||||
/// <param name="value">The value to update.</param>
|
||||
internal void Update(string key, object value) => TryUpdate(key, true, (JObject parent, string propertyName) =>
|
||||
{
|
||||
var prop = parent.Property(propertyName);
|
||||
|
||||
if (prop == null)
|
||||
{
|
||||
prop = new JProperty(propertyName, value);
|
||||
|
||||
parent.Add(prop);
|
||||
}
|
||||
else
|
||||
{
|
||||
prop.Value = IsMultiContent(value) ? new JArray(value) : JToken.FromObject(value);
|
||||
}
|
||||
});
|
||||
|
||||
private bool IsMultiContent(object value)
|
||||
{
|
||||
return value is Array;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Locates the node by key in the JSON object, and performs a general update (add, modify or remove a property).
|
||||
/// </summary>
|
||||
/// <param name="key">The full path to the config.</param>
|
||||
/// <param name="createWhenNotExist">Whether to create the JSON node when part of the path is missing.</param>
|
||||
/// <param name="updateAction">The concrete action to perform. First argument is the parent node in the JSON object, second is the name of the property to update.</param>
|
||||
/// <returns>Whether the update is successful.</returns>
|
||||
private bool TryUpdate(string key, bool createWhenNotExist, Action<JObject, string> updateAction)
|
||||
{
|
||||
string json = _dataStore.ReadFileAsText(_jsonConfigPath);
|
||||
JObject root = JObject.Parse(json);
|
||||
|
||||
string[] segments = key.Split(ConfigurationPath.KeyDelimiter.ToCharArray());
|
||||
JObject parent = LocateParentNode(root, segments, createWhenNotExist);
|
||||
if (parent == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string propertyName = segments[segments.Length - 1];
|
||||
|
||||
updateAction(parent, propertyName);
|
||||
|
||||
// hack: to avoid last version of the config remaining in the file, empty it first
|
||||
_dataStore.WriteFile(_jsonConfigPath, string.Empty);
|
||||
|
||||
JsonSerializer serializer = new JsonSerializer
|
||||
{
|
||||
Formatting = Formatting.Indented
|
||||
};
|
||||
using (Stream fs = _dataStore.OpenForExclusiveWrite(_jsonConfigPath))
|
||||
using (StreamWriter sw = new StreamWriter(fs))
|
||||
using (var writer = new JsonTextWriter(sw) { Indentation = 4 })
|
||||
{
|
||||
serializer.Serialize(writer, root);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static JObject LocateParentNode(JObject root, string[] segments, bool createWhenNotExist)
|
||||
{
|
||||
JObject node = root;
|
||||
for (int i = 0; i < segments.Length - 1; ++i)
|
||||
{
|
||||
string segment = segments[i];
|
||||
// JObject.TryGetValue() supports case insensitivity
|
||||
// otherwise we might get duplicated keys with different casing in the config file
|
||||
if (node.TryGetValue(segment, StringComparison.OrdinalIgnoreCase, out JToken match))
|
||||
{
|
||||
node = (JObject)match;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (createWhenNotExist)
|
||||
{
|
||||
node[segment] = new JObject();
|
||||
node = (JObject)node[segment];
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear a config by key.
|
||||
/// </summary>
|
||||
/// <param name="key">The full path to the config.</param>
|
||||
internal void Clear(string key) => TryUpdate(key, false, (parent, propertyName) =>
|
||||
{
|
||||
if (parent.Property(propertyName) != null)
|
||||
{
|
||||
parent.Remove(propertyName);
|
||||
}
|
||||
// if the config is never set, there's no need to clear.
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
/// Clear all the configs.
|
||||
/// </summary>
|
||||
internal void ClearAll()
|
||||
{
|
||||
_dataStore.WriteFile(_jsonConfigPath, @"{}");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Options class used by the <see cref="ConfigurationBinder"/>.
|
||||
/// </summary>
|
||||
internal class BinderOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// When false (the default), the binder will only attempt to set public properties.
|
||||
/// If true, the binder will attempt to set all non read-only properties.
|
||||
/// </summary>
|
||||
public bool BindNonPublicProperties { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,587 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Static helper class that allows binding strongly typed objects to configuration values.
|
||||
/// </summary>
|
||||
internal static class ConfigurationBinder
|
||||
{
|
||||
/// <summary>
|
||||
/// Attempts to bind the configuration instance to a new instance of type T.
|
||||
/// If this configuration section has a value, that will be used.
|
||||
/// Otherwise binding by matching property names against configuration keys recursively.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the new instance to bind.</typeparam>
|
||||
/// <param name="configuration">The configuration instance to bind.</param>
|
||||
/// <returns>The new instance of T if successful, default(T) otherwise.</returns>
|
||||
public static (T, string) Get<T>(this IConfiguration configuration)
|
||||
=> configuration.Get<T>(_ => { });
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to bind the configuration instance to a new instance of type T.
|
||||
/// If this configuration section has a value, that will be used.
|
||||
/// Otherwise binding by matching property names against configuration keys recursively.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the new instance to bind.</typeparam>
|
||||
/// <param name="configuration">The configuration instance to bind.</param>
|
||||
/// <param name="configureOptions">Configures the binder options.</param>
|
||||
/// <returns>The new instance of T if successful, default(T) otherwise.</returns>
|
||||
public static (T, string) Get<T>(this IConfiguration configuration, Action<BinderOptions> configureOptions)
|
||||
{
|
||||
if (configuration == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configuration));
|
||||
}
|
||||
|
||||
(object result, string providerId) = configuration.Get(typeof(T), configureOptions);
|
||||
if (result == null)
|
||||
{
|
||||
return (default(T), providerId);
|
||||
}
|
||||
return ((T)result, providerId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to bind the configuration instance to a new instance of type T.
|
||||
/// If this configuration section has a value, that will be used.
|
||||
/// Otherwise binding by matching property names against configuration keys recursively.
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration instance to bind.</param>
|
||||
/// <param name="type">The type of the new instance to bind.</param>
|
||||
/// <returns>The new instance if successful, null otherwise.</returns>
|
||||
public static (object, string) Get(this IConfiguration configuration, Type type)
|
||||
=> configuration.Get(type, _ => { });
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to bind the configuration instance to a new instance of type T.
|
||||
/// If this configuration section has a value, that will be used.
|
||||
/// Otherwise binding by matching property names against configuration keys recursively.
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration instance to bind.</param>
|
||||
/// <param name="type">The type of the new instance to bind.</param>
|
||||
/// <param name="configureOptions">Configures the binder options.</param>
|
||||
/// <returns>The new instance if successful, null otherwise.</returns>
|
||||
public static (object, string) Get(this IConfiguration configuration, Type type, Action<BinderOptions> configureOptions)
|
||||
{
|
||||
if (configuration == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configuration));
|
||||
}
|
||||
|
||||
var options = new BinderOptions();
|
||||
configureOptions?.Invoke(options);
|
||||
object bound = BindInstance(type, instance: null, config: configuration, options: options);
|
||||
string providerId = (configuration as IConfigurationSection).GetValueWithProviderId().Item2;
|
||||
return (bound, providerId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to bind the given object instance to the configuration section specified by the key by matching property names against configuration keys recursively.
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration instance to bind.</param>
|
||||
/// <param name="key">The key of the configuration section to bind.</param>
|
||||
/// <param name="instance">The object to bind.</param>
|
||||
public static void Bind(this IConfiguration configuration, string key, object instance)
|
||||
=> configuration.GetSection(key).Bind(instance);
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration instance to bind.</param>
|
||||
/// <param name="instance">The object to bind.</param>
|
||||
public static void Bind(this IConfiguration configuration, object instance)
|
||||
=> configuration.Bind(instance, o => { });
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration instance to bind.</param>
|
||||
/// <param name="instance">The object to bind.</param>
|
||||
/// <param name="configureOptions">Configures the binder options.</param>
|
||||
public static void Bind(this IConfiguration configuration, object instance, Action<BinderOptions> configureOptions)
|
||||
{
|
||||
if (configuration == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(configuration));
|
||||
}
|
||||
|
||||
if (instance != null)
|
||||
{
|
||||
var options = new BinderOptions();
|
||||
configureOptions?.Invoke(options);
|
||||
BindInstance(instance.GetType(), instance, configuration, options);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts the value with the specified key and converts it to type T.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type to convert the value to.</typeparam>
|
||||
/// <param name="configuration">The configuration.</param>
|
||||
/// <param name="key">The key of the configuration section's value to convert.</param>
|
||||
/// <returns>The converted value.</returns>
|
||||
public static T GetValue<T>(this IConfiguration configuration, string key)
|
||||
{
|
||||
return GetValue(configuration, key, default(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts the value with the specified key and converts it to type T.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type to convert the value to.</typeparam>
|
||||
/// <param name="configuration">The configuration.</param>
|
||||
/// <param name="key">The key of the configuration section's value to convert.</param>
|
||||
/// <param name="defaultValue">The default value to use if no value is found.</param>
|
||||
/// <returns>The converted value.</returns>
|
||||
public static T GetValue<T>(this IConfiguration configuration, string key, T defaultValue)
|
||||
{
|
||||
return (T)GetValue(configuration, typeof(T), key, defaultValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts the value with the specified key and converts it to the specified type.
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration.</param>
|
||||
/// <param name="type">The type to convert the value to.</param>
|
||||
/// <param name="key">The key of the configuration section's value to convert.</param>
|
||||
/// <returns>The converted value.</returns>
|
||||
public static object GetValue(this IConfiguration configuration, Type type, string key)
|
||||
{
|
||||
return GetValue(configuration, type, key, defaultValue: null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts the value with the specified key and converts it to the specified type.
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration.</param>
|
||||
/// <param name="type">The type to convert the value to.</param>
|
||||
/// <param name="key">The key of the configuration section's value to convert.</param>
|
||||
/// <param name="defaultValue">The default value to use if no value is found.</param>
|
||||
/// <returns>The converted value.</returns>
|
||||
public static object GetValue(this IConfiguration configuration, Type type, string key, object defaultValue)
|
||||
{
|
||||
IConfigurationSection section = configuration.GetSection(key);
|
||||
string value = section.Value;
|
||||
if (value != null)
|
||||
{
|
||||
return ConvertValue(type, value, section.Path);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
private static void BindNonScalar(this IConfiguration configuration, object instance, BinderOptions options)
|
||||
{
|
||||
if (instance != null)
|
||||
{
|
||||
foreach (PropertyInfo property in GetAllProperties(instance.GetType().GetTypeInfo()))
|
||||
{
|
||||
BindProperty(property, instance, configuration, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void BindProperty(PropertyInfo property, object instance, IConfiguration config, BinderOptions options)
|
||||
{
|
||||
// We don't support set only, non public, or indexer properties
|
||||
if (property.GetMethod == null ||
|
||||
(!options.BindNonPublicProperties && !property.GetMethod.IsPublic) ||
|
||||
property.GetMethod.GetParameters().Length > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
object propertyValue = property.GetValue(instance);
|
||||
bool hasSetter = property.SetMethod != null && (property.SetMethod.IsPublic || options.BindNonPublicProperties);
|
||||
|
||||
if (propertyValue == null && !hasSetter)
|
||||
{
|
||||
// Property doesn't have a value and we cannot set it so there is no
|
||||
// point in going further down the graph
|
||||
return;
|
||||
}
|
||||
|
||||
propertyValue = BindInstance(property.PropertyType, propertyValue, config.GetSection(property.Name), options);
|
||||
|
||||
if (propertyValue != null && hasSetter)
|
||||
{
|
||||
property.SetValue(instance, propertyValue);
|
||||
}
|
||||
}
|
||||
|
||||
private static object BindToCollection(TypeInfo typeInfo, IConfiguration config, BinderOptions options)
|
||||
{
|
||||
Type type = typeof(List<>).MakeGenericType(typeInfo.GenericTypeArguments[0]);
|
||||
object instance = Activator.CreateInstance(type);
|
||||
BindCollection(instance, type, config, options);
|
||||
return instance;
|
||||
}
|
||||
|
||||
// Try to create an array/dictionary instance to back various collection interfaces
|
||||
private static object AttemptBindToCollectionInterfaces(Type type, IConfiguration config, BinderOptions options)
|
||||
{
|
||||
TypeInfo typeInfo = type.GetTypeInfo();
|
||||
|
||||
if (!typeInfo.IsInterface)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Type collectionInterface = FindOpenGenericInterface(typeof(IReadOnlyList<>), type);
|
||||
if (collectionInterface != null)
|
||||
{
|
||||
// IEnumerable<T> is guaranteed to have exactly one parameter
|
||||
return BindToCollection(typeInfo, config, options);
|
||||
}
|
||||
|
||||
collectionInterface = FindOpenGenericInterface(typeof(IReadOnlyDictionary<,>), type);
|
||||
if (collectionInterface != null)
|
||||
{
|
||||
Type dictionaryType = typeof(Dictionary<,>).MakeGenericType(typeInfo.GenericTypeArguments[0], typeInfo.GenericTypeArguments[1]);
|
||||
object instance = Activator.CreateInstance(dictionaryType);
|
||||
BindDictionary(instance, dictionaryType, config, options);
|
||||
return instance;
|
||||
}
|
||||
|
||||
collectionInterface = FindOpenGenericInterface(typeof(IDictionary<,>), type);
|
||||
if (collectionInterface != null)
|
||||
{
|
||||
object instance = Activator.CreateInstance(typeof(Dictionary<,>).MakeGenericType(typeInfo.GenericTypeArguments[0], typeInfo.GenericTypeArguments[1]));
|
||||
BindDictionary(instance, collectionInterface, config, options);
|
||||
return instance;
|
||||
}
|
||||
|
||||
collectionInterface = FindOpenGenericInterface(typeof(IReadOnlyCollection<>), type);
|
||||
if (collectionInterface != null)
|
||||
{
|
||||
// IReadOnlyCollection<T> is guaranteed to have exactly one parameter
|
||||
return BindToCollection(typeInfo, config, options);
|
||||
}
|
||||
|
||||
collectionInterface = FindOpenGenericInterface(typeof(ICollection<>), type);
|
||||
if (collectionInterface != null)
|
||||
{
|
||||
// ICollection<T> is guaranteed to have exactly one parameter
|
||||
return BindToCollection(typeInfo, config, options);
|
||||
}
|
||||
|
||||
collectionInterface = FindOpenGenericInterface(typeof(IEnumerable<>), type);
|
||||
if (collectionInterface != null)
|
||||
{
|
||||
// IEnumerable<T> is guaranteed to have exactly one parameter
|
||||
return BindToCollection(typeInfo, config, options);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static object BindInstance(Type type, object instance, IConfiguration config, BinderOptions options)
|
||||
{
|
||||
// if binding IConfigurationSection, break early
|
||||
if (type == typeof(IConfigurationSection))
|
||||
{
|
||||
return config;
|
||||
}
|
||||
|
||||
var section = config as IConfigurationSection;
|
||||
string configValue = section?.Value;
|
||||
object convertedValue;
|
||||
Exception error;
|
||||
if (configValue != null && TryConvertValue(type, configValue, section.Path, out convertedValue, out error))
|
||||
{
|
||||
if (error != null)
|
||||
{
|
||||
throw error;
|
||||
}
|
||||
|
||||
// Leaf nodes are always reinitialized
|
||||
return convertedValue;
|
||||
}
|
||||
|
||||
if (config != null && config.GetChildren().Any())
|
||||
{
|
||||
// If we don't have an instance, try to create one
|
||||
if (instance == null)
|
||||
{
|
||||
// We are already done if binding to a new collection instance worked
|
||||
instance = AttemptBindToCollectionInterfaces(type, config, options);
|
||||
if (instance != null)
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
|
||||
instance = CreateInstance(type);
|
||||
}
|
||||
|
||||
// See if its a Dictionary
|
||||
Type collectionInterface = FindOpenGenericInterface(typeof(IDictionary<,>), type);
|
||||
if (collectionInterface != null)
|
||||
{
|
||||
BindDictionary(instance, collectionInterface, config, options);
|
||||
}
|
||||
else if (type.IsArray)
|
||||
{
|
||||
instance = BindArray((Array)instance, config, options);
|
||||
}
|
||||
else
|
||||
{
|
||||
// See if its an ICollection
|
||||
collectionInterface = FindOpenGenericInterface(typeof(ICollection<>), type);
|
||||
if (collectionInterface != null)
|
||||
{
|
||||
BindCollection(instance, collectionInterface, config, options);
|
||||
}
|
||||
// Something else
|
||||
else
|
||||
{
|
||||
BindNonScalar(config, instance, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
private static object CreateInstance(Type type)
|
||||
{
|
||||
TypeInfo typeInfo = type.GetTypeInfo();
|
||||
|
||||
if (typeInfo.IsInterface || typeInfo.IsAbstract)
|
||||
{
|
||||
throw new InvalidOperationException($"Error: cannot activate abstract class or interface, type: {type}");
|
||||
}
|
||||
|
||||
if (type.IsArray)
|
||||
{
|
||||
if (typeInfo.GetArrayRank() > 1)
|
||||
{
|
||||
throw new InvalidOperationException($"Error: multi-dimensional array is not supported, type: {type})");
|
||||
}
|
||||
|
||||
return Array.CreateInstance(typeInfo.GetElementType(), 0);
|
||||
}
|
||||
|
||||
if (!typeInfo.IsValueType)
|
||||
{
|
||||
bool hasDefaultConstructor = typeInfo.DeclaredConstructors.Any(ctor => ctor.IsPublic && ctor.GetParameters().Length == 0);
|
||||
if (!hasDefaultConstructor)
|
||||
{
|
||||
throw new InvalidOperationException($"Error: missing parameterless constructor in type {type}");
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return Activator.CreateInstance(type);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidOperationException($"Error: failed to activate type [{type}]. {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static void BindDictionary(object dictionary, Type dictionaryType, IConfiguration config, BinderOptions options)
|
||||
{
|
||||
TypeInfo typeInfo = dictionaryType.GetTypeInfo();
|
||||
|
||||
// IDictionary<K,V> is guaranteed to have exactly two parameters
|
||||
Type keyType = typeInfo.GenericTypeArguments[0];
|
||||
Type valueType = typeInfo.GenericTypeArguments[1];
|
||||
bool keyTypeIsEnum = keyType.GetTypeInfo().IsEnum;
|
||||
|
||||
if (keyType != typeof(string) && !keyTypeIsEnum)
|
||||
{
|
||||
// We only support string and enum keys
|
||||
return;
|
||||
}
|
||||
|
||||
PropertyInfo setter = typeInfo.GetDeclaredProperty("Item");
|
||||
foreach (IConfigurationSection child in config.GetChildren())
|
||||
{
|
||||
object item = BindInstance(
|
||||
type: valueType,
|
||||
instance: null,
|
||||
config: child,
|
||||
options: options);
|
||||
if (item != null)
|
||||
{
|
||||
if (keyType == typeof(string))
|
||||
{
|
||||
string key = child.Key;
|
||||
setter.SetValue(dictionary, item, new object[] { key });
|
||||
}
|
||||
else if (keyTypeIsEnum)
|
||||
{
|
||||
object key = Enum.Parse(keyType, child.Key);
|
||||
setter.SetValue(dictionary, item, new object[] { key });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void BindCollection(object collection, Type collectionType, IConfiguration config, BinderOptions options)
|
||||
{
|
||||
TypeInfo typeInfo = collectionType.GetTypeInfo();
|
||||
|
||||
// ICollection<T> is guaranteed to have exactly one parameter
|
||||
Type itemType = typeInfo.GenericTypeArguments[0];
|
||||
MethodInfo addMethod = typeInfo.GetDeclaredMethod("Add");
|
||||
|
||||
foreach (IConfigurationSection section in config.GetChildren())
|
||||
{
|
||||
try
|
||||
{
|
||||
object item = BindInstance(
|
||||
type: itemType,
|
||||
instance: null,
|
||||
config: section,
|
||||
options: options);
|
||||
if (item != null)
|
||||
{
|
||||
addMethod.Invoke(collection, new[] { item });
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Array BindArray(Array source, IConfiguration config, BinderOptions options)
|
||||
{
|
||||
IConfigurationSection[] children = config.GetChildren().ToArray();
|
||||
int arrayLength = source.Length;
|
||||
Type elementType = source.GetType().GetElementType();
|
||||
var newArray = Array.CreateInstance(elementType, arrayLength + children.Length);
|
||||
|
||||
// binding to array has to preserve already initialized arrays with values
|
||||
if (arrayLength > 0)
|
||||
{
|
||||
Array.Copy(source, newArray, arrayLength);
|
||||
}
|
||||
|
||||
for (int i = 0; i < children.Length; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
object item = BindInstance(
|
||||
type: elementType,
|
||||
instance: null,
|
||||
config: children[i],
|
||||
options: options);
|
||||
if (item != null)
|
||||
{
|
||||
newArray.SetValue(item, arrayLength + i);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return newArray;
|
||||
}
|
||||
|
||||
private static bool TryConvertValue(Type type, string value, string path, out object result, out Exception error)
|
||||
{
|
||||
error = null;
|
||||
result = null;
|
||||
if (type == typeof(object))
|
||||
{
|
||||
result = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return TryConvertValue(Nullable.GetUnderlyingType(type), value, path, out result, out error);
|
||||
}
|
||||
|
||||
TypeConverter converter = TypeDescriptor.GetConverter(type);
|
||||
if (converter.CanConvertFrom(typeof(string)))
|
||||
{
|
||||
try
|
||||
{
|
||||
result = converter.ConvertFromInvariantString(value);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = new InvalidOperationException($"Failed to convert value [{value}] to type [{type}].", ex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static object ConvertValue(Type type, string value, string path)
|
||||
{
|
||||
object result;
|
||||
Exception error;
|
||||
TryConvertValue(type, value, path, out result, out error);
|
||||
if (error != null)
|
||||
{
|
||||
throw error;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Type FindOpenGenericInterface(Type expected, Type actual)
|
||||
{
|
||||
TypeInfo actualTypeInfo = actual.GetTypeInfo();
|
||||
if (actualTypeInfo.IsGenericType &&
|
||||
actual.GetGenericTypeDefinition() == expected)
|
||||
{
|
||||
return actual;
|
||||
}
|
||||
|
||||
IEnumerable<Type> interfaces = actualTypeInfo.ImplementedInterfaces;
|
||||
foreach (Type interfaceType in interfaces)
|
||||
{
|
||||
if (interfaceType.GetTypeInfo().IsGenericType &&
|
||||
interfaceType.GetGenericTypeDefinition() == expected)
|
||||
{
|
||||
return interfaceType;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static IEnumerable<PropertyInfo> GetAllProperties(TypeInfo type)
|
||||
{
|
||||
var allProperties = new List<PropertyInfo>();
|
||||
|
||||
do
|
||||
{
|
||||
allProperties.AddRange(type.DeclaredProperties);
|
||||
type = type.BaseType.GetTypeInfo();
|
||||
}
|
||||
while (type != typeof(object).GetTypeInfo());
|
||||
|
||||
return allProperties;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to build key/value based configuration settings for use in an application.
|
||||
/// </summary>
|
||||
internal class ConfigurationBuilder : IConfigurationBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the sources used to obtain configuration values.
|
||||
/// </summary>
|
||||
public IList<IConfigurationSource> Sources { get; } = new List<IConfigurationSource>();
|
||||
|
||||
private IDictionary<IConfigurationSource, string> _ids = new Dictionary<IConfigurationSource, string>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a key/value collection that can be used to share data between the <see cref="IConfigurationBuilder"/>
|
||||
/// and the registered <see cref="IConfigurationProvider"/>s.
|
||||
/// </summary>
|
||||
public IDictionary<string, object> Properties { get; } = new Dictionary<string, object>();
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new configuration source.
|
||||
/// </summary>
|
||||
/// <param name="source">The configuration source to add.</param>
|
||||
/// <returns>The same <see cref="IConfigurationBuilder"/>.</returns>
|
||||
public IConfigurationBuilder Add(string id, IConfigurationSource source)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(source));
|
||||
}
|
||||
|
||||
Sources.Add(source);
|
||||
_ids[source] = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds an <see cref="IConfiguration"/> with keys and values from the set of providers registered in
|
||||
/// <see cref="Sources"/>.
|
||||
/// </summary>
|
||||
/// <returns>An <see cref="IConfigurationRoot"/> with keys and values from the registered providers.</returns>
|
||||
public IConfigurationRoot Build()
|
||||
{
|
||||
var providers = new List<IConfigurationProvider>();
|
||||
foreach (IConfigurationSource source in Sources)
|
||||
{
|
||||
IConfigurationProvider provider = source.Build(this, _ids[source]);
|
||||
providers.Add(provider);
|
||||
}
|
||||
return new ConfigurationRoot(providers);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for configuration classes./>.
|
||||
/// </summary>
|
||||
internal static class ConfigurationExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds a new configuration source.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="IConfigurationBuilder"/> to add to.</param>
|
||||
/// <param name="configureSource">Configures the source secrets.</param>
|
||||
/// <returns>The <see cref="IConfigurationBuilder"/>.</returns>
|
||||
public static IConfigurationBuilder Add<TSource>(this IConfigurationBuilder builder, string id, Action<TSource> configureSource) where TSource : IConfigurationSource, new()
|
||||
{
|
||||
var source = new TSource();
|
||||
configureSource?.Invoke(source);
|
||||
return builder.Add(id, source);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shorthand for GetSection("ConnectionStrings")[name].
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration.</param>
|
||||
/// <param name="name">The connection string key.</param>
|
||||
/// <returns>The connection string.</returns>
|
||||
public static string GetConnectionString(this IConfiguration configuration, string name)
|
||||
{
|
||||
return configuration?.GetSection("ConnectionStrings")?[name];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the enumeration of key value pairs within the <see cref="IConfiguration" />
|
||||
/// </summary>
|
||||
/// <param name="configuration">The <see cref="IConfiguration"/> to enumerate.</param>
|
||||
/// <returns>An enumeration of key value pairs.</returns>
|
||||
public static IEnumerable<KeyValuePair<string, string>> AsEnumerable(this IConfiguration configuration) => configuration.AsEnumerable(makePathsRelative: false);
|
||||
|
||||
/// <summary>
|
||||
/// Get the enumeration of key value pairs within the <see cref="IConfiguration" />
|
||||
/// </summary>
|
||||
/// <param name="configuration">The <see cref="IConfiguration"/> to enumerate.</param>
|
||||
/// <param name="makePathsRelative">If true, the child keys returned will have the current configuration's Path trimmed from the front.</param>
|
||||
/// <returns>An enumeration of key value pairs.</returns>
|
||||
public static IEnumerable<KeyValuePair<string, string>> AsEnumerable(this IConfiguration configuration, bool makePathsRelative)
|
||||
{
|
||||
var stack = new Stack<IConfiguration>();
|
||||
stack.Push(configuration);
|
||||
var rootSection = configuration as IConfigurationSection;
|
||||
int prefixLength = (makePathsRelative && rootSection != null) ? rootSection.Path.Length + 1 : 0;
|
||||
while (stack.Count > 0)
|
||||
{
|
||||
IConfiguration config = stack.Pop();
|
||||
// Don't include the sections value if we are removing paths, since it will be an empty key
|
||||
if (config is IConfigurationSection section && (!makePathsRelative || config != configuration))
|
||||
{
|
||||
yield return new KeyValuePair<string, string>(section.Path.Substring(prefixLength), section.Value);
|
||||
}
|
||||
foreach (IConfigurationSection child in config.GetChildren())
|
||||
{
|
||||
stack.Push(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the section has a <see cref="IConfigurationSection.Value"/> or has children
|
||||
/// </summary>
|
||||
public static bool Exists(this IConfigurationSection section)
|
||||
{
|
||||
if (section == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return section.Value != null || section.GetChildren().Any();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config.Internal
|
||||
{
|
||||
internal class ConfigurationKeyComparer : IComparer<string>
|
||||
{
|
||||
private static readonly string[] _keyDelimiterArray = new[] { ConfigurationPath.KeyDelimiter };
|
||||
|
||||
/// <summary>
|
||||
/// The default instance.
|
||||
/// </summary>
|
||||
public static ConfigurationKeyComparer Instance { get; } = new ConfigurationKeyComparer();
|
||||
|
||||
/// <summary>
|
||||
/// Compares two strings.
|
||||
/// </summary>
|
||||
/// <param name="x">First string.</param>
|
||||
/// <param name="y">Second string.</param>
|
||||
/// <returns>Less than 0 if x is less than y, 0 if x is equal to y and greater than 0 if x is greater than y.</returns>
|
||||
public int Compare(string x, string y)
|
||||
{
|
||||
string[] xParts = x?.Split(_keyDelimiterArray, StringSplitOptions.RemoveEmptyEntries) ?? Array.Empty<string>();
|
||||
string[] yParts = y?.Split(_keyDelimiterArray, StringSplitOptions.RemoveEmptyEntries) ?? Array.Empty<string>();
|
||||
|
||||
// Compare each part until we get two parts that are not equal
|
||||
for (int i = 0; i < Math.Min(xParts.Length, yParts.Length); i++)
|
||||
{
|
||||
x = xParts[i];
|
||||
y = yParts[i];
|
||||
|
||||
int value1 = 0;
|
||||
int value2 = 0;
|
||||
|
||||
bool xIsInt = x != null && int.TryParse(x, out value1);
|
||||
bool yIsInt = y != null && int.TryParse(y, out value2);
|
||||
|
||||
int result;
|
||||
|
||||
if (!xIsInt && !yIsInt)
|
||||
{
|
||||
// Both are strings
|
||||
result = string.Compare(x, y, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
else if (xIsInt && yIsInt)
|
||||
{
|
||||
// Both are int
|
||||
result = value1 - value2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only one of them is int
|
||||
result = xIsInt ? -1 : 1;
|
||||
}
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
// One of them is different
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// If we get here, the common parts are equal.
|
||||
// If they are of the same length, then they are totally identical
|
||||
return xParts.Length - yParts.Length;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Utility methods and constants for manipulating Configuration paths
|
||||
/// </summary>
|
||||
internal static class ConfigurationPath
|
||||
{
|
||||
/// <summary>
|
||||
/// The delimiter ":" used to separate individual keys in a path.
|
||||
/// </summary>
|
||||
public static readonly string KeyDelimiter = ":";
|
||||
|
||||
/// <summary>
|
||||
/// Combines path segments into one path.
|
||||
/// </summary>
|
||||
/// <param name="pathSegments">The path segments to combine.</param>
|
||||
/// <returns>The combined path.</returns>
|
||||
public static string Combine(params string[] pathSegments)
|
||||
{
|
||||
if (pathSegments == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(pathSegments));
|
||||
}
|
||||
return string.Join(KeyDelimiter, pathSegments);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Combines path segments into one path.
|
||||
/// </summary>
|
||||
/// <param name="pathSegments">The path segments to combine.</param>
|
||||
/// <returns>The combined path.</returns>
|
||||
public static string Combine(IEnumerable<string> pathSegments)
|
||||
{
|
||||
if (pathSegments == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(pathSegments));
|
||||
}
|
||||
return string.Join(KeyDelimiter, pathSegments);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts the last path segment from the path.
|
||||
/// </summary>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <returns>The last path segment of the path.</returns>
|
||||
public static string GetSectionKey(string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
int lastDelimiterIndex = path.LastIndexOf(KeyDelimiter, StringComparison.OrdinalIgnoreCase);
|
||||
return lastDelimiterIndex == -1 ? path : path.Substring(lastDelimiterIndex + 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts the path corresponding to the parent node for a given path.
|
||||
/// </summary>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <returns>The original path minus the last individual segment found in it. Null if the original path corresponds to a top level node.</returns>
|
||||
public static string GetParentPath(string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
int lastDelimiterIndex = path.LastIndexOf(KeyDelimiter, StringComparison.OrdinalIgnoreCase);
|
||||
return lastDelimiterIndex == -1 ? null : path.Substring(0, lastDelimiterIndex);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Base helper class for implementing an <see cref="IConfigurationProvider"/>
|
||||
/// </summary>
|
||||
internal abstract class ConfigurationProvider : IConfigurationProvider
|
||||
{
|
||||
public string Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new <see cref="IConfigurationProvider"/>
|
||||
/// </summary>
|
||||
protected ConfigurationProvider(string id)
|
||||
{
|
||||
Id = id;
|
||||
Data = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The configuration key value pairs for this provider.
|
||||
/// </summary>
|
||||
protected IDictionary<string, string> Data { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to find a value with the given key, returns true if one is found, false otherwise.
|
||||
/// </summary>
|
||||
/// <param name="key">The key to lookup.</param>
|
||||
/// <param name="value">The value found at key if one is found.</param>
|
||||
/// <returns>True if key has a value, false otherwise.</returns>
|
||||
public virtual bool TryGet(string key, out string value)
|
||||
=> Data.TryGetValue(key, out value);
|
||||
|
||||
/// <summary>
|
||||
/// Sets a value for a given key.
|
||||
/// </summary>
|
||||
/// <param name="key">The configuration key to set.</param>
|
||||
/// <param name="value">The value to set.</param>
|
||||
public virtual void Set(string key, string value)
|
||||
=> Data[key] = value;
|
||||
|
||||
/// <summary>
|
||||
/// Loads (or reloads) the data for this provider.
|
||||
/// </summary>
|
||||
public virtual void Load()
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the list of keys that this provider has.
|
||||
/// </summary>
|
||||
/// <param name="earlierKeys">The earlier keys that other providers contain.</param>
|
||||
/// <param name="parentPath">The path for the parent IConfiguration.</param>
|
||||
/// <returns>The list of keys for this provider.</returns>
|
||||
public virtual IEnumerable<string> GetChildKeys(
|
||||
IEnumerable<string> earlierKeys,
|
||||
string parentPath)
|
||||
{
|
||||
string prefix = parentPath == null ? string.Empty : parentPath + ConfigurationPath.KeyDelimiter;
|
||||
|
||||
return Data
|
||||
.Where(kv => kv.Key.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
|
||||
.Select(kv => Segment(kv.Key, prefix.Length))
|
||||
.Concat(earlierKeys)
|
||||
.OrderBy(k => k, ConfigurationKeyComparer.Instance);
|
||||
}
|
||||
|
||||
private static string Segment(string key, int prefixLength)
|
||||
{
|
||||
int indexOf = key.IndexOf(ConfigurationPath.KeyDelimiter, prefixLength, StringComparison.OrdinalIgnoreCase);
|
||||
return indexOf < 0 ? key.Substring(prefixLength) : key.Substring(prefixLength, indexOf - prefixLength);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a string representing this provider name and relevant details.
|
||||
/// </summary>
|
||||
/// <returns> The configuration name. </returns>
|
||||
public override string ToString() => $"{GetType().Name}";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// The root node for a configuration.
|
||||
/// </summary>
|
||||
internal class ConfigurationRoot : IConfigurationRoot, IDisposable
|
||||
{
|
||||
private readonly IList<IConfigurationProvider> _providers;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a Configuration root with a list of providers.
|
||||
/// </summary>
|
||||
/// <param name="providers">The <see cref="IConfigurationProvider"/>s for this configuration.</param>
|
||||
public ConfigurationRoot(IList<IConfigurationProvider> providers)
|
||||
{
|
||||
if (providers == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(providers));
|
||||
}
|
||||
|
||||
_providers = providers;
|
||||
foreach (IConfigurationProvider p in providers)
|
||||
{
|
||||
p.Load();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IConfigurationProvider"/>s for this configuration.
|
||||
/// </summary>
|
||||
public IEnumerable<IConfigurationProvider> Providers => _providers;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value corresponding to a configuration key.
|
||||
/// </summary>
|
||||
/// <param name="key">The configuration key.</param>
|
||||
/// <returns>The configuration value.</returns>
|
||||
public string this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetValueWithProviderId(key).Item1;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!_providers.Any())
|
||||
{
|
||||
throw new InvalidOperationException($"Error: none config source is registered.");
|
||||
}
|
||||
|
||||
foreach (IConfigurationProvider provider in _providers)
|
||||
{
|
||||
provider.Set(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public (string, string) GetValueWithProviderId(string key)
|
||||
{
|
||||
for (int i = _providers.Count - 1; i >= 0; i--)
|
||||
{
|
||||
IConfigurationProvider provider = _providers[i];
|
||||
|
||||
if (provider.TryGet(key, out string value))
|
||||
{
|
||||
return (value, provider.Id);
|
||||
}
|
||||
}
|
||||
|
||||
return (null, null);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the immediate children sub-sections.
|
||||
/// </summary>
|
||||
/// <returns>The children.</returns>
|
||||
public IEnumerable<IConfigurationSection> GetChildren() => this.GetChildrenImplementation(null);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a configuration sub-section with the specified key.
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the configuration section.</param>
|
||||
/// <returns>The <see cref="IConfigurationSection"/>.</returns>
|
||||
/// <remarks>
|
||||
/// This method will never return <c>null</c>. If no matching sub-section is found with the specified key,
|
||||
/// an empty <see cref="IConfigurationSection"/> will be returned.
|
||||
/// </remarks>
|
||||
public IConfigurationSection GetSection(string key)
|
||||
=> new ConfigurationSection(this, key);
|
||||
|
||||
/// <summary>
|
||||
/// Force the configuration values to be reloaded from the underlying sources.
|
||||
/// </summary>
|
||||
public void Reload()
|
||||
{
|
||||
foreach (IConfigurationProvider provider in _providers)
|
||||
{
|
||||
provider.Load();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
// dispose providers
|
||||
foreach (IConfigurationProvider provider in _providers)
|
||||
{
|
||||
(provider as IDisposable)?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public IConfigurationProvider GetConfigurationProvider(string id)
|
||||
{
|
||||
return _providers.FirstOrDefault(x => x.Id.Equals(id));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a section of application configuration values.
|
||||
/// </summary>
|
||||
internal class ConfigurationSection : IConfigurationSection
|
||||
{
|
||||
private readonly IConfigurationRoot _root;
|
||||
private readonly string _path;
|
||||
private string _key;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance.
|
||||
/// </summary>
|
||||
/// <param name="root">The configuration root.</param>
|
||||
/// <param name="path">The path to this section.</param>
|
||||
public ConfigurationSection(IConfigurationRoot root, string path)
|
||||
{
|
||||
if (root == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(root));
|
||||
}
|
||||
|
||||
if (path == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(path));
|
||||
}
|
||||
|
||||
_root = root;
|
||||
_path = path;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the full path to this section from the <see cref="IConfigurationRoot"/>.
|
||||
/// </summary>
|
||||
public string Path => _path;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the key this section occupies in its parent.
|
||||
/// </summary>
|
||||
public string Key
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_key == null)
|
||||
{
|
||||
// Key is calculated lazily as last portion of Path
|
||||
_key = ConfigurationPath.GetSectionKey(_path);
|
||||
}
|
||||
return _key;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the section value.
|
||||
/// </summary>
|
||||
public string Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return _root[Path];
|
||||
}
|
||||
set
|
||||
{
|
||||
_root[Path] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public (string, string) GetValueWithProviderId()
|
||||
{
|
||||
return _root.GetValueWithProviderId(Path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value corresponding to a configuration key.
|
||||
/// </summary>
|
||||
/// <param name="key">The configuration key.</param>
|
||||
/// <returns>The configuration value.</returns>
|
||||
public string this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
return _root[ConfigurationPath.Combine(Path, key)];
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_root[ConfigurationPath.Combine(Path, key)] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a configuration sub-section with the specified key.
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the configuration section.</param>
|
||||
/// <returns>The <see cref="IConfigurationSection"/>.</returns>
|
||||
/// <remarks>
|
||||
/// This method will never return <c>null</c>. If no matching sub-section is found with the specified key,
|
||||
/// an empty <see cref="IConfigurationSection"/> will be returned.
|
||||
/// </remarks>
|
||||
public IConfigurationSection GetSection(string key) => _root.GetSection(ConfigurationPath.Combine(Path, key));
|
||||
|
||||
/// <summary>
|
||||
/// Gets the immediate descendant configuration sub-sections.
|
||||
/// </summary>
|
||||
/// <returns>The configuration sub-sections.</returns>
|
||||
public IEnumerable<IConfigurationSection> GetChildren() => _root.GetChildrenImplementation(Path);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Interfaces
|
||||
{
|
||||
internal interface IConfiguration
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a configuration value.
|
||||
/// </summary>
|
||||
/// <param name="key">The configuration key.</param>
|
||||
/// <returns>The configuration value.</returns>
|
||||
string this[string key] { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a configuration sub-section with the specified key.
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the configuration section.</param>
|
||||
/// <returns>The <see cref="IConfigurationSection"/>.</returns>
|
||||
/// <remarks>
|
||||
/// This method will never return <c>null</c>. If no matching sub-section is found with the specified key,
|
||||
/// an empty <see cref="IConfigurationSection"/> will be returned.
|
||||
/// </remarks>
|
||||
IConfigurationSection GetSection(string key);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the immediate descendant configuration sub-sections.
|
||||
/// </summary>
|
||||
/// <returns>The configuration sub-sections.</returns>
|
||||
IEnumerable<IConfigurationSection> GetChildren();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a type used to build application configuration.
|
||||
/// </summary>
|
||||
internal interface IConfigurationBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a key/value collection that can be used to share data between the <see cref="IConfigurationBuilder"/>
|
||||
/// and the registered <see cref="IConfigurationSource"/>s.
|
||||
/// </summary>
|
||||
IDictionary<string, object> Properties { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sources used to obtain configuration values
|
||||
/// </summary>
|
||||
IList<IConfigurationSource> Sources { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new configuration source.
|
||||
/// </summary>
|
||||
/// <param name="source">The configuration source to add.</param>
|
||||
/// <returns>The same <see cref="IConfigurationBuilder"/>.</returns>
|
||||
IConfigurationBuilder Add(string id, IConfigurationSource source);
|
||||
|
||||
/// <summary>
|
||||
/// Builds an <see cref="IConfiguration"/> with keys and values from the set of sources registered in
|
||||
/// <see cref="Sources"/>.
|
||||
/// </summary>
|
||||
/// <returns>An <see cref="IConfigurationRoot"/> with keys and values from the registered sources.</returns>
|
||||
IConfigurationRoot Build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides configuration key/values for an application.
|
||||
/// </summary>
|
||||
internal interface IConfigurationProvider
|
||||
{
|
||||
string Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get a configuration value for the specified key.
|
||||
/// </summary>
|
||||
/// <param name="key">The key.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <returns><c>True</c> if a value for the specified key was found, otherwise <c>false</c>.</returns>
|
||||
bool TryGet(string key, out string value);
|
||||
|
||||
/// <summary>
|
||||
/// Sets a configuration value for the specified key.
|
||||
/// </summary>
|
||||
/// <param name="key">The key.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
void Set(string key, string value);
|
||||
|
||||
/// <summary>
|
||||
/// Loads configuration values from the source represented by this <see cref="IConfigurationProvider"/>.
|
||||
/// </summary>
|
||||
void Load();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the immediate descendant configuration keys for a given parent path based on this
|
||||
/// <see cref="IConfigurationProvider"/>s data and the set of keys returned by all the preceding
|
||||
/// <see cref="IConfigurationProvider"/>s.
|
||||
/// </summary>
|
||||
/// <param name="earlierKeys">The child keys returned by the preceding providers for the same parent path.</param>
|
||||
/// <param name="parentPath">The parent path.</param>
|
||||
/// <returns>The child keys.</returns>
|
||||
IEnumerable<string> GetChildKeys(IEnumerable<string> earlierKeys, string parentPath);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the root of an <see cref="IConfiguration"/> hierarchy.
|
||||
/// </summary>
|
||||
internal interface IConfigurationRoot : IConfiguration
|
||||
{
|
||||
/// <summary>
|
||||
/// Force the configuration values to be reloaded from the underlying <see cref="IConfigurationProvider"/>s.
|
||||
/// </summary>
|
||||
void Reload();
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IConfigurationProvider"/>s for this configuration.
|
||||
/// </summary>
|
||||
IEnumerable<IConfigurationProvider> Providers { get; }
|
||||
|
||||
IConfigurationProvider GetConfigurationProvider(string id);
|
||||
|
||||
(string, string) GetValueWithProviderId(string key);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Interfaces
|
||||
{
|
||||
internal interface IConfigurationSection : IConfiguration
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the key this section occupies in its parent.
|
||||
/// </summary>
|
||||
string Key { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the full path to this section within the <see cref="IConfiguration"/>.
|
||||
/// </summary>
|
||||
string Path { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the section value.
|
||||
/// </summary>
|
||||
string Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the section value and the ID of the provider which provides this value.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
(string, string) GetValueWithProviderId();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a source of configuration key/values for an application.
|
||||
/// </summary>
|
||||
internal interface IConfigurationSource
|
||||
{
|
||||
/// <summary>
|
||||
/// Builds the <see cref="IConfigurationProvider"/> for this source.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="IConfigurationBuilder"/>.</param>
|
||||
/// <returns>An <see cref="IConfigurationProvider"/></returns>
|
||||
IConfigurationProvider Build(IConfigurationBuilder builder, string id);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// An abstraction of the ability to get and set environment variable on various targets.
|
||||
/// </summary>
|
||||
internal interface IEnvironmentVariableProvider
|
||||
{
|
||||
string Get(string variableName, EnvironmentVariableTarget target = EnvironmentVariableTarget.Process);
|
||||
|
||||
void Set(string variableName, string value, EnvironmentVariableTarget target = EnvironmentVariableTarget.Process);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Extensions method for <see cref="IConfigurationRoot"/>
|
||||
/// </summary>
|
||||
internal static class InternalConfigurationRootExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the immediate children sub-sections of configuration root based on key.
|
||||
/// </summary>
|
||||
/// <param name="root">Configuration from which to retrieve sub-sections.</param>
|
||||
/// <param name="path">Key of a section of which children to retrieve.</param>
|
||||
/// <returns>Immediate children sub-sections of section specified by key.</returns>
|
||||
internal static IEnumerable<IConfigurationSection> GetChildrenImplementation(this IConfigurationRoot root, string path)
|
||||
{
|
||||
return root.Providers
|
||||
.Aggregate(Enumerable.Empty<string>(),
|
||||
(seed, source) => source.GetChildKeys(seed, path))
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.Select(key => root.GetSection(path == null ? key : ConfigurationPath.Combine(path, key)));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Interfaces;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Providers
|
||||
{
|
||||
internal static class EnvironmentVariablesConfigurationBuilderExtensions
|
||||
{
|
||||
public static IConfigurationBuilder AddEnvironmentVariables(this IConfigurationBuilder builder,
|
||||
string providerId,
|
||||
EnvironmentVariablesConfigurationOptions options)
|
||||
{
|
||||
builder.Add(providerId, new EnvironmentVariablesConfigurationSource(options));
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Providers
|
||||
{
|
||||
internal class EnvironmentVariablesConfigurationOptions
|
||||
{
|
||||
public IEnvironmentVariableProvider EnvironmentVariableProvider { get; set; }
|
||||
public EnvironmentVariableTarget EnvironmentVariableTarget { get; set; }
|
||||
public IDictionary<string, string> EnvironmentVariableToKeyMap { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Providers
|
||||
{
|
||||
internal class EnvironmentVariablesConfigurationProvider : ConfigurationProvider
|
||||
{
|
||||
private EnvironmentVariableTarget _environmentVariableTarget;
|
||||
private IDictionary<string, string> _environmentVariableNameToKeyMapping;
|
||||
private IEnvironmentVariableProvider _environmentVariableProvider;
|
||||
|
||||
public EnvironmentVariablesConfigurationProvider(string id, EnvironmentVariablesConfigurationOptions options) : base(id)
|
||||
{
|
||||
_environmentVariableTarget = options.EnvironmentVariableTarget;
|
||||
_environmentVariableNameToKeyMapping = options.EnvironmentVariableToKeyMap ?? new Dictionary<string, string>();
|
||||
_environmentVariableProvider = options.EnvironmentVariableProvider;
|
||||
}
|
||||
|
||||
public override void Load()
|
||||
{
|
||||
var data = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var i in _environmentVariableNameToKeyMapping)
|
||||
{
|
||||
string value = _environmentVariableProvider.Get(i.Key, _environmentVariableTarget);
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
data[i.Value] = value;
|
||||
}
|
||||
}
|
||||
|
||||
Data = data;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Interfaces;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Providers
|
||||
{
|
||||
internal class EnvironmentVariablesConfigurationSource : IConfigurationSource
|
||||
{
|
||||
private EnvironmentVariablesConfigurationOptions _options;
|
||||
|
||||
public EnvironmentVariablesConfigurationSource(EnvironmentVariablesConfigurationOptions options)
|
||||
{
|
||||
_options = options;
|
||||
}
|
||||
|
||||
public IConfigurationProvider Build(IConfigurationBuilder builder, string id)
|
||||
{
|
||||
return new EnvironmentVariablesConfigurationProvider(id, _options);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Interfaces;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Providers
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for adding the <see cref="JsonStreamConfigurationProvider"/>.
|
||||
/// </summary>
|
||||
internal static class JsonConfigurationExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds a JSON configuration source to <paramref name="builder"/>.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="IConfigurationBuilder"/> to add to.</param>
|
||||
/// <param name="stream">The <see cref="Stream"/> to read the json configuration data from.</param>
|
||||
/// <returns>The <see cref="IConfigurationBuilder"/>.</returns>
|
||||
public static IConfigurationBuilder AddJsonStream(this IConfigurationBuilder builder, string id, Stream stream)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
return builder.Add<JsonStreamConfigurationSource>(id, s => s.Stream = stream);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Providers
|
||||
{
|
||||
internal class JsonConfigurationFileParser
|
||||
{
|
||||
private JsonConfigurationFileParser() { }
|
||||
|
||||
private readonly IDictionary<string, string> _data = new SortedDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
private readonly Stack<string> _context = new Stack<string>();
|
||||
private string _currentPath;
|
||||
|
||||
public static IDictionary<string, string> Parse(Stream input)
|
||||
=> new JsonConfigurationFileParser().ParseStream(input);
|
||||
|
||||
private IDictionary<string, string> ParseStream(Stream input)
|
||||
{
|
||||
_data.Clear();
|
||||
|
||||
var jsonDocumentOptions = new JsonDocumentOptions
|
||||
{
|
||||
CommentHandling = JsonCommentHandling.Skip,
|
||||
AllowTrailingCommas = true,
|
||||
};
|
||||
|
||||
using (var reader = new StreamReader(input))
|
||||
using (JsonDocument doc = JsonDocument.Parse(reader.ReadToEnd(), jsonDocumentOptions))
|
||||
{
|
||||
if (doc.RootElement.ValueKind != JsonValueKind.Object)
|
||||
{
|
||||
throw new FormatException($"Error: unsupported JSON token [{doc.RootElement.ValueKind}]. Object kind is expected.");
|
||||
}
|
||||
VisitElement(doc.RootElement);
|
||||
}
|
||||
|
||||
return _data;
|
||||
}
|
||||
|
||||
private void VisitElement(JsonElement element)
|
||||
{
|
||||
foreach (JsonProperty property in element.EnumerateObject())
|
||||
{
|
||||
EnterContext(property.Name);
|
||||
VisitValue(property.Value);
|
||||
ExitContext();
|
||||
}
|
||||
}
|
||||
|
||||
private void VisitValue(JsonElement value)
|
||||
{
|
||||
switch (value.ValueKind)
|
||||
{
|
||||
case JsonValueKind.Object:
|
||||
VisitElement(value);
|
||||
break;
|
||||
|
||||
case JsonValueKind.Array:
|
||||
int index = 0;
|
||||
foreach (JsonElement arrayElement in value.EnumerateArray())
|
||||
{
|
||||
EnterContext(index.ToString());
|
||||
VisitValue(arrayElement);
|
||||
ExitContext();
|
||||
index++;
|
||||
}
|
||||
break;
|
||||
|
||||
case JsonValueKind.Number:
|
||||
case JsonValueKind.String:
|
||||
case JsonValueKind.True:
|
||||
case JsonValueKind.False:
|
||||
case JsonValueKind.Null:
|
||||
string key = _currentPath;
|
||||
if (_data.ContainsKey(key))
|
||||
{
|
||||
throw new FormatException($"Error: key [{key}] is duplicated.");
|
||||
}
|
||||
_data[key] = value.ToString();
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new FormatException($"Error: unsupported JSON token [{value.ValueKind}]");
|
||||
}
|
||||
}
|
||||
|
||||
private void EnterContext(string context)
|
||||
{
|
||||
_context.Push(context);
|
||||
_currentPath = ConfigurationPath.Combine(_context.Reverse());
|
||||
}
|
||||
|
||||
private void ExitContext()
|
||||
{
|
||||
_context.Pop();
|
||||
_currentPath = ConfigurationPath.Combine(_context.Reverse());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using System.IO;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Providers
|
||||
{
|
||||
/// <summary>
|
||||
/// Loads configuration key/values from a json stream into a provider.
|
||||
/// </summary>
|
||||
internal class JsonStreamConfigurationProvider : StreamConfigurationProvider
|
||||
{
|
||||
public JsonStreamConfigurationProvider(JsonStreamConfigurationSource source, string id) : base(source, id)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads json configuration key/values from a stream into a provider.
|
||||
/// </summary>
|
||||
/// <param name="stream">The json <see cref="Stream"/> to load configuration data from.</param>
|
||||
public override void Load(Stream stream)
|
||||
{
|
||||
Data = JsonConfigurationFileParser.Parse(stream);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Interfaces;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Providers
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a JSON file as an <see cref="IConfigurationSource"/>.
|
||||
/// </summary>
|
||||
internal class JsonStreamConfigurationSource : StreamConfigurationSource
|
||||
{
|
||||
/// <summary>
|
||||
/// Builds the <see cref="JsonStreamConfigurationProvider"/> for this source.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="IConfigurationBuilder"/>.</param>
|
||||
/// <returns>An <see cref="JsonStreamConfigurationProvider"/></returns>
|
||||
public override IConfigurationProvider Build(IConfigurationBuilder builder, string id)
|
||||
=> new JsonStreamConfigurationProvider(this, id);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Providers
|
||||
{
|
||||
/// <summary>
|
||||
/// Stream based configuration provider
|
||||
/// </summary>
|
||||
internal abstract class StreamConfigurationProvider : ConfigurationProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// The source settings for this provider.
|
||||
/// </summary>
|
||||
public StreamConfigurationSource Source { get; }
|
||||
|
||||
private bool _loaded;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="source">The source.</param>
|
||||
public StreamConfigurationProvider(StreamConfigurationSource source, string id) : base(id)
|
||||
{
|
||||
Source = source ?? throw new ArgumentNullException(nameof(source));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load the configuration data from the stream.
|
||||
/// </summary>
|
||||
/// <param name="stream">The data stream.</param>
|
||||
public abstract void Load(Stream stream);
|
||||
|
||||
/// <summary>
|
||||
/// Load the configuration data from the stream. Will throw after the first call.
|
||||
/// </summary>
|
||||
public override void Load()
|
||||
{
|
||||
if (_loaded)
|
||||
{
|
||||
throw new InvalidOperationException("StreamConfigurationProviders cannot be loaded more than once.");
|
||||
}
|
||||
Load(Source.Stream);
|
||||
_loaded = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Interfaces;
|
||||
using System.IO;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Providers
|
||||
{
|
||||
/// <summary>
|
||||
/// Stream based <see cref="IConfigurationSource" />.
|
||||
/// </summary>
|
||||
internal abstract class StreamConfigurationSource : IConfigurationSource
|
||||
{
|
||||
/// <summary>
|
||||
/// The stream containing the configuration data.
|
||||
/// </summary>
|
||||
public Stream Stream { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Builds the <see cref="StreamConfigurationProvider"/> for this source.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="IConfigurationBuilder"/>.</param>
|
||||
/// <returns>An <see cref="IConfigurationProvider"/></returns>
|
||||
public abstract IConfigurationProvider Build(IConfigurationBuilder builder, string id);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Interfaces;
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Providers
|
||||
{
|
||||
internal static class UnsettableMemoryConfigurationBuilderExtensions
|
||||
{
|
||||
public static IConfigurationBuilder AddUnsettableInMemoryCollection(this IConfigurationBuilder builder, string id)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
builder.Add(id, new UnsettableMemoryConfigurationSource());
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Interfaces;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Providers
|
||||
{
|
||||
/// <summary>
|
||||
/// In-memory implementation of <see cref="IConfigurationProvider"/>
|
||||
/// </summary>
|
||||
internal class UnsettableMemoryConfigurationProvider : ConfigurationProvider, IEnumerable<KeyValuePair<string, string>>
|
||||
{
|
||||
private readonly UnsettableMemoryConfigurationSource _source;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance from the source.
|
||||
/// </summary>
|
||||
/// <param name="source">The source settings.</param>
|
||||
public UnsettableMemoryConfigurationProvider(UnsettableMemoryConfigurationSource source, string id): base(id)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(source));
|
||||
}
|
||||
|
||||
_source = source;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a new key and value pair.
|
||||
/// </summary>
|
||||
/// <param name="key">The configuration key.</param>
|
||||
/// <param name="value">The configuration value.</param>
|
||||
public void Add(string key, string value)
|
||||
{
|
||||
Data.Add(key, value);
|
||||
}
|
||||
|
||||
public void Unset(string key)
|
||||
{
|
||||
Data.Remove(key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates through the collection.
|
||||
/// </summary>
|
||||
/// <returns>An enumerator that can be used to iterate through the collection.</returns>
|
||||
public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
|
||||
{
|
||||
return Data.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates through the collection.
|
||||
/// </summary>
|
||||
/// <returns>An enumerator that can be used to iterate through the collection.</returns>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public void UnsetAll()
|
||||
{
|
||||
Data.Clear();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Interfaces;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config.Internal.Providers
|
||||
{
|
||||
internal class UnsettableMemoryConfigurationSource : IConfigurationSource
|
||||
{
|
||||
public IConfigurationProvider Build(IConfigurationBuilder builder, string id)
|
||||
{
|
||||
return new UnsettableMemoryConfigurationProvider(this, id);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config
|
||||
{
|
||||
/// <summary>
|
||||
/// Abstraction for the PS InvocationInfo.
|
||||
/// </summary>
|
||||
internal class InternalInvocationInfo
|
||||
{
|
||||
public InternalInvocationInfo() : this(null, null)
|
||||
{
|
||||
}
|
||||
|
||||
public InternalInvocationInfo(string moduleName, string cmdletName)
|
||||
{
|
||||
CmdletName = cmdletName;
|
||||
ModuleName = moduleName;
|
||||
}
|
||||
|
||||
public string ModuleName { get; set; } = null;
|
||||
public string CmdletName { get; set; } = null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using System.Management.Automation;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config
|
||||
{
|
||||
internal class InvocationInfoAdapter : InternalInvocationInfo
|
||||
{
|
||||
public InvocationInfoAdapter(InvocationInfo invocationInfo) : base(
|
||||
invocationInfo?.MyCommand?.ModuleName, invocationInfo?.MyCommand?.Name)
|
||||
{ }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.PowerShell.Common.Config;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a simple typed config. For complex configs please define your own type inheriting <see cref="TypedConfig{TValue}"/> or <see cref="ConfigDefinition"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="TValue">Type of the config value.</typeparam>
|
||||
internal class SimpleTypedConfig<TValue> : TypedConfig<TValue>
|
||||
{
|
||||
private readonly string _key;
|
||||
private readonly string _helpMessage;
|
||||
private readonly TValue _defaultValue;
|
||||
private readonly string _environmentVariable;
|
||||
private readonly IReadOnlyCollection<AppliesTo> _canApplyTo = null;
|
||||
|
||||
public SimpleTypedConfig(string key, string helpMessage, TValue defaultValue, string environmentVariable = null, IReadOnlyCollection<AppliesTo> canApplyTo = null)
|
||||
{
|
||||
_key = key;
|
||||
_helpMessage = helpMessage;
|
||||
_defaultValue = defaultValue;
|
||||
_environmentVariable = environmentVariable;
|
||||
_canApplyTo = canApplyTo;
|
||||
}
|
||||
|
||||
public override string Key => _key;
|
||||
public override string HelpMessage => _helpMessage;
|
||||
public override object DefaultValue => _defaultValue;
|
||||
public override string EnvironmentVariableName => _environmentVariable;
|
||||
public override IReadOnlyCollection<AppliesTo> CanApplyTo
|
||||
{
|
||||
get { return _canApplyTo ?? base.CanApplyTo; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Azure.PowerShell.Common.Config;
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Config
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for configs that have a typed value.
|
||||
/// </summary>
|
||||
/// <typeparam name="TValue">The type of the config value.</typeparam>
|
||||
internal abstract class TypedConfig<TValue> : ConfigDefinition
|
||||
{
|
||||
protected TypedConfig()
|
||||
{
|
||||
}
|
||||
|
||||
public TValue TypedDefaultValue => (TValue)DefaultValue;
|
||||
|
||||
/// <summary>
|
||||
/// Validates if the input value is type <see cref="ValueType"/>.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to check.</param>
|
||||
/// <exception cref="ArgumentException">Throws when the value in another type.</exception>
|
||||
public override void Validate(object value)
|
||||
{
|
||||
base.Validate(value);
|
||||
if (!(value is TValue))
|
||||
{
|
||||
throw new ArgumentException($"Unexpected value type [{value.GetType()}]. The value of config [{Key}] should be of type [{ValueType}]", nameof(value));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs side effects before applying the config.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to be applied to this typed config.</param>
|
||||
/// <remarks>
|
||||
/// This method is sealed.
|
||||
/// Derived types should override <see cref="ApplyTyped(TValue)"/>.
|
||||
/// </remarks>
|
||||
public override sealed void Apply(object value)
|
||||
{
|
||||
base.Apply(value);
|
||||
ApplyTyped((TValue)value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generic version of <see cref="Apply(object)"/>.
|
||||
/// Override in child classes to perform side effects before applying the config value.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to be applied to this typed config, cast to the correct type.</param>
|
||||
protected virtual void ApplyTyped(TValue value) { }
|
||||
|
||||
public override Type ValueType => typeof(TValue);
|
||||
}
|
||||
}
|
|
@ -24,5 +24,18 @@ namespace Microsoft.Azure.Commands.Common.Authentication
|
|||
public const string MicrosoftGraphAccessToken = "MicrosoftGraphAccessToken";
|
||||
|
||||
public const string DefaultValue = "Default";
|
||||
|
||||
public class ConfigProviderIds
|
||||
{
|
||||
public const string MachineEnvironment = "Environment (Machine)";
|
||||
public const string UserEnvironment = "Environment (User)";
|
||||
public const string ProcessEnvironment = "Environment (Process)";
|
||||
public const string UserConfig = "Config (User)";
|
||||
public const string ProcessConfig = "Config (Process)";
|
||||
/// <summary>
|
||||
/// Represents that the value is not in any providers.
|
||||
/// </summary>
|
||||
public const string None = "None";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,3 +45,6 @@ using System.Runtime.InteropServices;
|
|||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("2.7.6")]
|
||||
[assembly: AssemblyFileVersion("2.7.6")]
|
||||
#if !SIGN
|
||||
[assembly: InternalsVisibleTo("Microsoft.Azure.PowerShell.Authentication.Test")]
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
// ----------------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright Microsoft Corporation
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Microsoft.Azure.Commands.Common.Authentication.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Utility class about PowerShell naming (cmdlet name, module name).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// All the mothods are within Azure PowerShell context, for example, module name should start with "Az.".
|
||||
/// </remarks>
|
||||
public static class PSNamingUtilities
|
||||
{
|
||||
private static readonly Regex ModulePattern = new Regex(@"^az\.[a-z]+$", RegexOptions.IgnoreCase);
|
||||
private static readonly Regex CmdletPattern = new Regex(@"^[a-z]+-[a-z\d]+$", RegexOptions.IgnoreCase);
|
||||
private static readonly Regex ModuleOrCmdletPattern = new Regex(@"^az\.[a-z]+$|^[a-z]+-[a-z\d]+$", RegexOptions.IgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the given <paramref name="moduleName"/> is a valid module name.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method only does pattern-matching. It does not check if the name is real.
|
||||
/// </remarks>
|
||||
public static bool IsModuleName(string moduleName)
|
||||
{
|
||||
return ModulePattern.IsMatch(moduleName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the given <paramref name="cmdletName"/> is a valid cmdlet name.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method only does pattern-matching. It does not check if the name is real.
|
||||
/// </remarks>
|
||||
public static bool IsCmdletName(string cmdletName)
|
||||
{
|
||||
return CmdletPattern.IsMatch(cmdletName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the given <paramref name="moduleOrCmdletName"/> is a valid module name or cmdlet name.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method only does pattern-matching. It does not check if the name is real.
|
||||
/// </remarks>
|
||||
public static bool IsModuleOrCmdletName(string moduleOrCmdletName)
|
||||
{
|
||||
return ModuleOrCmdletPattern.IsMatch(moduleOrCmdletName);
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче