зеркало из https://github.com/microsoft/Briefcase.git
Add .NET Implementation
This commit is contained in:
Родитель
4167c9a137
Коммит
25ce109ca3
|
@ -105,3 +105,8 @@ venv.bak/
|
|||
|
||||
# VSCode
|
||||
.vscode
|
||||
.vs
|
||||
dotnet/**/bin
|
||||
dotnet/**/obj
|
||||
dotnet/**/packages
|
||||
dotnet/**/*.csproj.user
|
|
@ -1,5 +1,12 @@
|
|||
|
||||
[![Build Status](https://dev.azure.com/ossworkspace/Workspace/_apis/build/status/microsoft.Workspace?branchName=master)](https://dev.azure.com/ossworkspace/Workspace/_build/latest?definitionId=1&branchName=master)
|
||||
[![Build Status](https://dev.azure.com/ossworkspace/Workspace/_apis/build/status/Microsoft.Workspace%20Python?branchName=master)](https://dev.azure.com/ossworkspace/Workspace/_build/latest?definitionId=1&branchName=master)
|
||||
Python
|
||||
|
||||
[![Build Status](https://dev.azure.com/ossworkspace/Workspace/_apis/build/status/Microsoft.Workspace%20DotNet%20Core?branchName=master)](https://dev.azure.com/ossworkspace/Workspace/_build/latest?definitionId=3&branchName=master)
|
||||
.NET Core
|
||||
|
||||
[![Build Status](https://dev.azure.com/ossworkspace/Workspace/_apis/build/status/Microsoft.Workspace%20DotNet%20Desktop?branchName=master)](https://dev.azure.com/ossworkspace/Workspace/_build/latest?definitionId=2&branchName=master)
|
||||
.NET Desktop
|
||||
|
||||
# Contributing
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
using Microsoft.Azure.KeyVault;
|
||||
using Microsoft.Workspace;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Workspace.Azure.KeyVault
|
||||
{
|
||||
public class KeyVault : Resource, ICredentialProvider
|
||||
{
|
||||
private readonly Lazy<KeyVaultClient> client = new Lazy<KeyVaultClient>(() =>
|
||||
null); // new KeyVaultClient(new KeyVaultClient.AuthenticationCallback("abc-securityToken")));
|
||||
|
||||
public async Task<string> GetSecretAsync(string key)
|
||||
{
|
||||
//ClientCredential
|
||||
//// TODO: catch exception
|
||||
var secret = await client.Value.GetSecretAsync(key);
|
||||
|
||||
return secret.Value;
|
||||
}
|
||||
|
||||
[YamlMember(Alias = "dnsname")]
|
||||
public string DNSName { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard1.4</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Azure.KeyVault" Version="3.0.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Workspace\Workspace.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,25 @@
|
|||
using YamlDotNet.Serialization;
|
||||
using Microsoft.WindowsAzure.Storage;
|
||||
|
||||
namespace Microsoft.Workspace.Azure.Storage
|
||||
{
|
||||
public class Account : Resource
|
||||
{
|
||||
[YamlMember(Alias = "accountname")]
|
||||
public string Name { get; set; }
|
||||
|
||||
public CloudStorageAccount Client
|
||||
{
|
||||
get
|
||||
{
|
||||
// TODO: lookup subscriptions
|
||||
// search for storage account
|
||||
// TODO: lookup keyvault
|
||||
// TODO: support service prinicipal
|
||||
// TODO: support env variable
|
||||
// CloudStorageAccount.Parse
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Microsoft.Workspace.Azure.Storage
|
||||
{
|
||||
public class Blob : Resource
|
||||
{
|
||||
[YamlMember(Alias = "containername")]
|
||||
public string ContainerName { get; set; }
|
||||
|
||||
public string Path { get; set; }
|
||||
|
||||
[YamlMember(Alias = "datasource")]
|
||||
public Account DataSource { get; set; }
|
||||
|
||||
public Task DownloadToAsync(Stream target)
|
||||
{
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard1.3</TargetFramework>
|
||||
<AssemblyName>Microsoft.Workspace.Azure.Storage</AssemblyName>
|
||||
<RootNamespace>Microsoft.Workspace.Azure.Storage</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="WindowsAzure.Storage" Version="9.3.3" />
|
||||
<PackageReference Include="YamlDotNet" Version="6.1.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Workspace\Workspace.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Workspace.AzureActiveDirectory.Desktop")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Workspace.AzureActiveDirectory.Desktop")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2019")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("d8934a46-02b3-4f81-b32a-8712d49ca3e0")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -0,0 +1,101 @@
|
|||
using Microsoft.Identity.Client;
|
||||
using System.Threading.Tasks;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.Workspace.AzureActiveDirectory.Desktop
|
||||
{
|
||||
public class SilentAuthentication
|
||||
{
|
||||
private string clientId;
|
||||
private string tenantId;
|
||||
|
||||
public SilentAuthentication()
|
||||
{
|
||||
clientId = "42e402c8-afee-41a0-99f8-ab51ca6c6dce";
|
||||
tenantId = "72f988bf-86f1-41af-91ab-2d7cd011db47";
|
||||
}
|
||||
public async Task<AuthenticationResult> GetATokenForGraphAsync()
|
||||
{
|
||||
// string authority = "https://login.microsoftonline.com/contoso.com";
|
||||
string[] scopes = new string[] { "user.read" };
|
||||
|
||||
// ConfidentialClientApplicationBuilder.Create("abc")
|
||||
|
||||
IPublicClientApplication app = PublicClientApplicationBuilder
|
||||
.Create(clientId)
|
||||
.WithTenantId(tenantId)
|
||||
.Build();
|
||||
|
||||
var accounts = await app.GetAccountsAsync();
|
||||
|
||||
AuthenticationResult result = null;
|
||||
if (accounts.Any())
|
||||
{
|
||||
result = await app
|
||||
.AcquireTokenSilent(scopes, accounts.FirstOrDefault())
|
||||
.ExecuteAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
result = await app
|
||||
.AcquireTokenByIntegratedWindowsAuth(scopes)
|
||||
.ExecuteAsync();
|
||||
}
|
||||
catch (MsalUiRequiredException)
|
||||
{
|
||||
// MsalUiRequiredException: AADSTS65001: The user or administrator has not consented to use the application
|
||||
// with ID '{appId}' named '{appName}'.Send an interactive authorization request for this user and resource.
|
||||
|
||||
// you need to get user consent first. This can be done, if you are not using .NET Core (which does not have any Web UI)
|
||||
// by doing (once only) an AcquireToken interactive.
|
||||
|
||||
// If you are using .NET core or don't want to do an AcquireTokenInteractive, you might want to suggest the user to navigate
|
||||
// to a URL to consent: https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id={clientId}&response_type=code&scope=user.read
|
||||
|
||||
var url = string.Format("https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id={0}&response_type=code&response_mode=query&scope=user.read",
|
||||
clientId);
|
||||
|
||||
System.Diagnostics.Process.Start(url);
|
||||
|
||||
// AADSTS50079: The user is required to use multi-factor authentication.
|
||||
// There is no mitigation - if MFA is configured for your tenant and AAD decides to enforce it,
|
||||
// you need to fallback to an interactive flows such as AcquireTokenAsync or AcquireTokenByDeviceCode
|
||||
}
|
||||
catch (MsalServiceException)
|
||||
{
|
||||
// Kind of errors you could have (in ex.Message)
|
||||
|
||||
// MsalServiceException: AADSTS90010: The grant type is not supported over the /common or /consumers endpoints. Please use the /organizations or tenant-specific endpoint.
|
||||
// you used common.
|
||||
// Mitigation: as explained in the message from Azure AD, the authoriy needs to be tenanted or otherwise organizations
|
||||
|
||||
// MsalServiceException: AADSTS70002: The request body must contain the following parameter: 'client_secret or client_assertion'.
|
||||
// Explanation: this can happen if your application was not registered as a public client application in Azure AD
|
||||
// Mitigation: in the Azure portal, edit the manifest for your application and set the `allowPublicClient` to `true`
|
||||
}
|
||||
catch (MsalClientException)
|
||||
{
|
||||
// Error Code: unknown_user Message: Could not identify logged in user
|
||||
// Explanation: the library was unable to query the current Windows logged-in user or this user is not AD or AAD
|
||||
// joined (work-place joined users are not supported).
|
||||
|
||||
// Mitigation 1: on UWP, check that the application has the following capabilities: Enterprise Authentication,
|
||||
// Private Networks (Client and Server), User Account Information
|
||||
|
||||
// Mitigation 2: Implement your own logic to fetch the username (e.g. john@contoso.com) and use the
|
||||
// AcquireTokenByIntegratedWindowsAuthAsync overload that takes in the username
|
||||
|
||||
// Error Code: integrated_windows_auth_not_supported_managed_user
|
||||
// Explanation: This method relies on an a protocol exposed by Active Directory (AD). If a user was created in Azure
|
||||
// Active Directory without AD backing ("managed" user), this method will fail. Users created in AD and backed by
|
||||
// AAD ("federated" users) can benefit from this non-interactive method of authentication.
|
||||
// Mitigation: Use interactive authentication
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{D8934A46-02B3-4F81-B32A-8712D49CA3E0}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Microsoft.Workspace.AzureActiveDirectory.Desktop</RootNamespace>
|
||||
<AssemblyName>Microsoft.Workspace.AzureActiveDirectory.Desktop</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.Identity.Client, Version=4.3.0.0, Culture=neutral, PublicKeyToken=0a613f4dd989e8ae, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Identity.Client.4.3.0\lib\net45\Microsoft.Identity.Client.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.IdentityModel" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SilentAuthentication.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Identity.Client" version="4.3.0" targetFramework="net46" />
|
||||
</packages>
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Microsoft.Workspace.Azure.AD
|
||||
{
|
||||
public class ServicePrincipal : Resource, ICredentialProvider
|
||||
{
|
||||
[YamlMember(Alias = "clientid")]
|
||||
public string ClientId { get; set; }
|
||||
|
||||
public Task<string> GetSecretAsync(string key)
|
||||
{
|
||||
// ConfidentialClientApplicationBuilder.Create("abc")
|
||||
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
using Microsoft.Identity.Client;
|
||||
using System.Threading.Tasks;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.Workspace.Azure.AD
|
||||
{
|
||||
public class SilentAuthentication
|
||||
{
|
||||
private string clientId;
|
||||
private string tenantId;
|
||||
|
||||
public SilentAuthentication()
|
||||
{
|
||||
clientId = "42e402c8-afee-41a0-99f8-ab51ca6c6dce";
|
||||
tenantId = "72f988bf-86f1-41af-91ab-2d7cd011db47";
|
||||
}
|
||||
|
||||
public string ClientId { get; set; }
|
||||
|
||||
public async Task<AuthenticationResult> GetATokenForGraphAsync()
|
||||
{
|
||||
// string authority = "https://login.microsoftonline.com/contoso.com";
|
||||
string[] scopes = new string[] { "user.read" };
|
||||
|
||||
|
||||
IPublicClientApplication app = PublicClientApplicationBuilder
|
||||
.Create(clientId)
|
||||
.WithTenantId(tenantId)
|
||||
.Build();
|
||||
|
||||
var accounts = await app.GetAccountsAsync();
|
||||
|
||||
AuthenticationResult result = null;
|
||||
if (accounts.Any())
|
||||
{
|
||||
result = await app
|
||||
.AcquireTokenSilent(scopes, accounts.FirstOrDefault())
|
||||
.ExecuteAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
result = await app
|
||||
.AcquireTokenByIntegratedWindowsAuth(scopes)
|
||||
.ExecuteAsync();
|
||||
}
|
||||
catch (MsalUiRequiredException)
|
||||
{
|
||||
// MsalUiRequiredException: AADSTS65001: The user or administrator has not consented to use the application
|
||||
// with ID '{appId}' named '{appName}'.Send an interactive authorization request for this user and resource.
|
||||
|
||||
// you need to get user consent first. This can be done, if you are not using .NET Core (which does not have any Web UI)
|
||||
// by doing (once only) an AcquireToken interactive.
|
||||
|
||||
// If you are using .NET core or don't want to do an AcquireTokenInteractive, you might want to suggest the user to navigate
|
||||
// to a URL to consent: https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id={clientId}&response_type=code&scope=user.read
|
||||
|
||||
var url = string.Format("https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id={0}&response_type=code&response_mode=query&scope=user.read",
|
||||
clientId);
|
||||
|
||||
System.Diagnostics.Process.Start(url);
|
||||
|
||||
// AADSTS50079: The user is required to use multi-factor authentication.
|
||||
// There is no mitigation - if MFA is configured for your tenant and AAD decides to enforce it,
|
||||
// you need to fallback to an interactive flows such as AcquireTokenAsync or AcquireTokenByDeviceCode
|
||||
}
|
||||
catch (MsalServiceException)
|
||||
{
|
||||
// Kind of errors you could have (in ex.Message)
|
||||
|
||||
// MsalServiceException: AADSTS90010: The grant type is not supported over the /common or /consumers endpoints. Please use the /organizations or tenant-specific endpoint.
|
||||
// you used common.
|
||||
// Mitigation: as explained in the message from Azure AD, the authoriy needs to be tenanted or otherwise organizations
|
||||
|
||||
// MsalServiceException: AADSTS70002: The request body must contain the following parameter: 'client_secret or client_assertion'.
|
||||
// Explanation: this can happen if your application was not registered as a public client application in Azure AD
|
||||
// Mitigation: in the Azure portal, edit the manifest for your application and set the `allowPublicClient` to `true`
|
||||
}
|
||||
catch (MsalClientException)
|
||||
{
|
||||
// Error Code: unknown_user Message: Could not identify logged in user
|
||||
// Explanation: the library was unable to query the current Windows logged-in user or this user is not AD or AAD
|
||||
// joined (work-place joined users are not supported).
|
||||
|
||||
// Mitigation 1: on UWP, check that the application has the following capabilities: Enterprise Authentication,
|
||||
// Private Networks (Client and Server), User Account Information
|
||||
|
||||
// Mitigation 2: Implement your own logic to fetch the username (e.g. john@contoso.com) and use the
|
||||
// AcquireTokenByIntegratedWindowsAuthAsync overload that takes in the username
|
||||
|
||||
// Error Code: integrated_windows_auth_not_supported_managed_user
|
||||
// Explanation: This method relies on an a protocol exposed by Active Directory (AD). If a user was created in Azure
|
||||
// Active Directory without AD backing ("managed" user), this method will fail. Users created in AD and backed by
|
||||
// AAD ("federated" users) can benefit from this non-interactive method of authentication.
|
||||
// Mitigation: Use interactive authentication
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard1.3</TargetFramework>
|
||||
<AssemblyName>Microsoft.Workspace.Azure.AD</AssemblyName>
|
||||
<RootNamespace>Microsoft.Workspace.Azure.AD</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Identity.Client" Version="4.3.0" />
|
||||
<PackageReference Include="YamlDotNet" Version="6.1.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Workspace\Workspace.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,55 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.28803.452
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Workspace", "Workspace\Workspace.csproj", "{2207E2F3-3282-417C-B6ED-27D6490051A3}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkspaceTest", "WorkspaceTest\WorkspaceTest.csproj", "{33911FAE-9E30-4ACE-BADB-A4582333D104}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Workspace.Azure.AD", "Workspace.AzureActiveDirectory\Workspace.Azure.AD.csproj", "{CC4AA13B-7FE4-4CC7-AC21-B06558FE157C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkspaceTest.Desktop", "WorkspaceTest.Desktop\WorkspaceTest.Desktop.csproj", "{8B137BFA-8A2E-4A59-89A3-8BC14FE0911D}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Workspace.Azure.Storage", "Workspace.Azure.Storage\Workspace.Azure.Storage.csproj", "{AD55574A-7E7A-4B70-913C-9E3AB2F2E129}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Workspace.Azure.KeyVault", "Workspace.Azure.KeyVault\Workspace.Azure.KeyVault.csproj", "{43912DD2-DDDB-44D0-874B-5E18A3C0B50D}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{2207E2F3-3282-417C-B6ED-27D6490051A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2207E2F3-3282-417C-B6ED-27D6490051A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2207E2F3-3282-417C-B6ED-27D6490051A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2207E2F3-3282-417C-B6ED-27D6490051A3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{33911FAE-9E30-4ACE-BADB-A4582333D104}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{33911FAE-9E30-4ACE-BADB-A4582333D104}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{33911FAE-9E30-4ACE-BADB-A4582333D104}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{33911FAE-9E30-4ACE-BADB-A4582333D104}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{CC4AA13B-7FE4-4CC7-AC21-B06558FE157C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CC4AA13B-7FE4-4CC7-AC21-B06558FE157C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CC4AA13B-7FE4-4CC7-AC21-B06558FE157C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CC4AA13B-7FE4-4CC7-AC21-B06558FE157C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8B137BFA-8A2E-4A59-89A3-8BC14FE0911D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8B137BFA-8A2E-4A59-89A3-8BC14FE0911D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8B137BFA-8A2E-4A59-89A3-8BC14FE0911D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8B137BFA-8A2E-4A59-89A3-8BC14FE0911D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AD55574A-7E7A-4B70-913C-9E3AB2F2E129}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AD55574A-7E7A-4B70-913C-9E3AB2F2E129}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AD55574A-7E7A-4B70-913C-9E3AB2F2E129}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AD55574A-7E7A-4B70-913C-9E3AB2F2E129}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{43912DD2-DDDB-44D0-874B-5E18A3C0B50D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{43912DD2-DDDB-44D0-874B-5E18A3C0B50D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{43912DD2-DDDB-44D0-874B-5E18A3C0B50D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{43912DD2-DDDB-44D0-874B-5E18A3C0B50D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {CAAA81D2-7164-4DA2-86C4-5F17AAD69C5D}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.Workspace
|
||||
{
|
||||
[YamlTag("env")]
|
||||
public class EnvironmentCredentialProvider : Resource, ICredentialProvider
|
||||
{
|
||||
public static readonly EnvironmentCredentialProvider Instance = new EnvironmentCredentialProvider();
|
||||
|
||||
public Task<string> GetSecretAsync(string key)
|
||||
{
|
||||
return Task.FromResult(Environment.GetEnvironmentVariable(key));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.Workspace
|
||||
{
|
||||
public interface ICredentialProvider
|
||||
{
|
||||
Task<string> GetSecretAsync(string key);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
namespace Microsoft.Workspace
|
||||
{
|
||||
public interface IResource
|
||||
{
|
||||
string Name { get; set; }
|
||||
|
||||
string[] Path { get; set; }
|
||||
|
||||
WorkspaceImpl Workspace { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Workspace
|
||||
{
|
||||
public class Resource : IResource
|
||||
{
|
||||
string IResource.Name { get; set; }
|
||||
|
||||
WorkspaceImpl IResource.Workspace { get; set; }
|
||||
|
||||
string[] IResource.Path { get; set; }
|
||||
|
||||
public ICredentialProvider CredentialProvider { get; set; }
|
||||
|
||||
IEnumerable<ICredentialProvider> GetCredentialProviders()
|
||||
{
|
||||
if (CredentialProvider != null)
|
||||
{
|
||||
yield return CredentialProvider;
|
||||
yield break;
|
||||
}
|
||||
|
||||
yield return EnvironmentCredentialProvider.Instance;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using YamlDotNet.Serialization;
|
||||
using YamlDotNet.Serialization.NamingConventions;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.Workspace
|
||||
{
|
||||
public delegate T ResourceSelector<T>(Resource resource, IEnumerable<string> path, string name);
|
||||
public delegate void ResourceAction(Resource resource, IEnumerable<string> path, string name);
|
||||
|
||||
public class WorkspaceImpl
|
||||
{
|
||||
private object root;
|
||||
|
||||
public WorkspaceImpl(string path = ".")
|
||||
{
|
||||
using (var reader = new StreamReader(File.OpenRead(Path.Combine(path, "resources.yaml"))))
|
||||
{
|
||||
Parse(reader);
|
||||
}
|
||||
}
|
||||
|
||||
public WorkspaceImpl(TextReader resourcesYamlReader)
|
||||
{
|
||||
Parse(resourcesYamlReader);
|
||||
}
|
||||
|
||||
private void Parse(TextReader resourcesYamlReader)
|
||||
{
|
||||
var deserializer = new DeserializerBuilder()
|
||||
.WithNamingConvention(new CamelCaseNamingConvention())
|
||||
.WithNodeTypeResolver(new WorkspaceNodeTypeResolver())
|
||||
.Build();
|
||||
|
||||
root = deserializer.Deserialize(resourcesYamlReader);
|
||||
|
||||
// setup path, name and workspace
|
||||
Resources = Select((resource, path, name) =>
|
||||
{
|
||||
IResource res = resource as IResource;
|
||||
res.Workspace = this;
|
||||
res.Path = path.ToArray();
|
||||
res.Name = name;
|
||||
return resource;
|
||||
})
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private IEnumerable<T> SelectImpl<T>(ResourceSelector<T> visitor, List<string> path, object node, string name)
|
||||
{
|
||||
if (node is Resource resource)
|
||||
{
|
||||
var ret = visitor(resource, path, name);
|
||||
|
||||
yield return ret;
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (node is IDictionary<object, object> dict)
|
||||
{
|
||||
if (name != null)
|
||||
path.Add(name);
|
||||
|
||||
foreach (var item in dict)
|
||||
{
|
||||
var ret = SelectImpl(visitor, path, item.Value, item.Key.ToString());
|
||||
|
||||
// if we found something
|
||||
foreach (var r in ret)
|
||||
yield return r;
|
||||
}
|
||||
|
||||
if (name != null)
|
||||
path.RemoveAt(path.Count - 1);
|
||||
|
||||
yield break;
|
||||
}
|
||||
|
||||
throw new ArgumentException("Unknown type in tree: " + node.GetType());
|
||||
}
|
||||
private IEnumerable<T> Select<T>(ResourceSelector<T> visitor)
|
||||
{
|
||||
return SelectImpl(visitor, new List<string>(), root, null);
|
||||
}
|
||||
|
||||
public List<Resource> Resources { get; private set; }
|
||||
|
||||
public IEnumerable<Resource> this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
var components = key.Split('.', '/').ToArray();
|
||||
var path = string.Join(".", components.Take(components.Count() - 1));
|
||||
var name = components.Last();
|
||||
|
||||
// find by name
|
||||
if (path.Length == 0)
|
||||
return Resources
|
||||
.OfType<IResource>()
|
||||
.Where(r => r.Name == name)
|
||||
.OfType<Resource>();
|
||||
|
||||
// find by path
|
||||
return Resources
|
||||
.OfType<IResource>()
|
||||
.Where(r => r.Name == name && string.Join(".", r.Path) == path)
|
||||
.OfType<Resource>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard1.3</TargetFramework>
|
||||
<AssemblyName>Microsoft.Workspace</AssemblyName>
|
||||
<RootNamespace>Microsoft.Workspace</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="YamlDotNet" Version="6.1.2" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,63 @@
|
|||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using YamlDotNet.Core.Events;
|
||||
using YamlDotNet.Serialization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Workspace
|
||||
{
|
||||
public class WorkspaceNodeTypeResolver : INodeTypeResolver
|
||||
{
|
||||
private readonly IDictionary<string, Type> tagToTypeMapping;
|
||||
|
||||
public WorkspaceNodeTypeResolver()
|
||||
{
|
||||
Assembly asm = typeof(YamlTagAttribute).GetTypeInfo().Assembly;
|
||||
|
||||
tagToTypeMapping = asm.DefinedTypes
|
||||
.Select(t => new { Type = t, Attribute = t.GetCustomAttribute<YamlTagAttribute>() })
|
||||
.Where(t => t.Attribute != null)
|
||||
.ToDictionary(t => t.Attribute.Tag, t => t.Type.AsType());
|
||||
|
||||
// TODO: since .NET Standard doesn't have appdomains nor module initializer I'm not sure how to find the other classes
|
||||
|
||||
// difference
|
||||
// tagToTypeMapping.Add("azure.serviceprincipal", Type.GetType("Microsoft.Workspace.Azure.AD.ServicePrincipal"))
|
||||
}
|
||||
|
||||
public bool Resolve(NodeEvent nodeEvent, ref Type currentType)
|
||||
{
|
||||
// ignore non-tagged nodes
|
||||
if (string.IsNullOrEmpty(nodeEvent.Tag))
|
||||
return false;
|
||||
|
||||
// lookup built in tags
|
||||
if (tagToTypeMapping.TryGetValue(nodeEvent.Tag, out currentType))
|
||||
return true;
|
||||
|
||||
// lookup using naming scheme
|
||||
var className = Regex.Replace(nodeEvent.Tag,
|
||||
@"(\b)([a-z])",
|
||||
m => m.Groups[1].Value + m.Groups[2].Value.ToUpperInvariant())
|
||||
.Substring(1);
|
||||
|
||||
// Pattern: first 2 path elements define the package
|
||||
var assemblyName = string.Join(".", className.Split('.').Take(2));
|
||||
|
||||
// e.g. tag name = azure.storage.account
|
||||
// e.g. type name = Microsoft.Workspace.Azure.Storage.Account
|
||||
var typeName = string.Format("Microsoft.Workspace.{0}, Microsoft.Workspace.{1}",
|
||||
className,
|
||||
assemblyName);
|
||||
|
||||
currentType = Type.GetType(typeName);
|
||||
|
||||
if (currentType == null)
|
||||
throw new InvalidOperationException("Unable to find type: " + typeName);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Workspace
|
||||
{
|
||||
[System.AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
|
||||
sealed class YamlTagAttribute : Attribute
|
||||
{
|
||||
public YamlTagAttribute(string tag)
|
||||
{
|
||||
this.Tag = tag;
|
||||
}
|
||||
|
||||
public string Tag
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Microsoft.Workspace;
|
||||
using Microsoft.Workspace.Azure.Storage;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.WorkspaceTest.Desktop
|
||||
{
|
||||
[TestClass]
|
||||
public class AzureStorageTest
|
||||
{
|
||||
[TestMethod]
|
||||
public async Task TestDownload()
|
||||
{
|
||||
var ws = new WorkspaceImpl("yamls/azure/storage");
|
||||
|
||||
var dataset = ws["dataset"].First() as Blob;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
[assembly: AssemblyTitle("WorkspaceTest.Desktop")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("WorkspaceTest.Desktop")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2019")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
[assembly: Guid("8b137bfa-8a2e-4a59-89a3-8bc14fe0911d")]
|
||||
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -0,0 +1,17 @@
|
|||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Microsoft.Workspace.Azure.AD;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WorkspaceTest
|
||||
{
|
||||
[TestClass]
|
||||
public class SilentAuthenticationTest
|
||||
{
|
||||
[TestMethod]
|
||||
public async Task TestSilentAuth()
|
||||
{
|
||||
var silentAuth = new SilentAuthentication();
|
||||
var result = await silentAuth.GetATokenForGraphAsync();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\packages\MSTest.TestAdapter.1.4.0\build\net45\MSTest.TestAdapter.props" Condition="Exists('..\packages\MSTest.TestAdapter.1.4.0\build\net45\MSTest.TestAdapter.props')" />
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{8B137BFA-8A2E-4A59-89A3-8BC14FE0911D}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Microsoft.WorkspaceTest.Desktop</RootNamespace>
|
||||
<AssemblyName>Microsoft.WorkspaceTest.Desktop</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
|
||||
<IsCodedUITest>False</IsCodedUITest>
|
||||
<TestProjectType>UnitTest</TestProjectType>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.Azure.KeyVault, Version=3.0.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Azure.KeyVault.3.0.4\lib\net461\Microsoft.Azure.KeyVault.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Azure.KeyVault.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Azure.KeyVault.Core.1.0.0\lib\net40\Microsoft.Azure.KeyVault.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Azure.KeyVault.WebKey, Version=3.0.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Azure.KeyVault.WebKey.3.0.4\lib\net461\Microsoft.Azure.KeyVault.WebKey.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="Microsoft.Identity.Client, Version=4.3.0.0, Culture=neutral, PublicKeyToken=0a613f4dd989e8ae, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Identity.Client.4.3.0\lib\net45\Microsoft.Identity.Client.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Rest.ClientRuntime, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Rest.ClientRuntime.2.3.20\lib\net461\Microsoft.Rest.ClientRuntime.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Rest.ClientRuntime.Azure, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Rest.ClientRuntime.Azure.3.3.19\lib\net461\Microsoft.Rest.ClientRuntime.Azure.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MSTest.TestFramework.1.4.0\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MSTest.TestFramework.1.4.0\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.WindowsAzure.Storage, Version=9.3.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\WindowsAzure.Storage.9.3.3\lib\net45\Microsoft.WindowsAzure.Storage.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.12.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.IdentityModel" />
|
||||
<Reference Include="System.Net" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Net.Http.WebRequest" />
|
||||
<Reference Include="System.Runtime" />
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="YamlDotNet, Version=6.0.0.0, Culture=neutral, PublicKeyToken=ec19458f3c15af5e, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\YamlDotNet.6.1.2\lib\net45\YamlDotNet.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AzureStorageTest.cs" />
|
||||
<Compile Include="SilentAuthenticationTest.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="yamls\azure\storage\resources.yaml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="yamls\env\resources.yaml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Workspace.Azure.KeyVault\Workspace.Azure.KeyVault.csproj">
|
||||
<Project>{43912dd2-dddb-44d0-874b-5e18a3c0b50d}</Project>
|
||||
<Name>Workspace.Azure.KeyVault</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Workspace.Azure.Storage\Workspace.Azure.Storage.csproj">
|
||||
<Project>{ad55574a-7e7a-4b70-913c-9e3ab2f2e129}</Project>
|
||||
<Name>Workspace.Azure.Storage</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Workspace.AzureActiveDirectory\Workspace.Azure.AD.csproj">
|
||||
<Project>{cc4aa13b-7fe4-4cc7-ac21-b06558fe157c}</Project>
|
||||
<Name>Workspace.Azure.AD</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Workspace\Workspace.csproj">
|
||||
<Project>{2207e2f3-3282-417c-b6ed-27d6490051a3}</Project>
|
||||
<Name>Workspace</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.1.4.0\build\net45\MSTest.TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.1.4.0\build\net45\MSTest.TestAdapter.props'))" />
|
||||
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.1.4.0\build\net45\MSTest.TestAdapter.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.1.4.0\build\net45\MSTest.TestAdapter.targets'))" />
|
||||
</Target>
|
||||
<Import Project="..\packages\MSTest.TestAdapter.1.4.0\build\net45\MSTest.TestAdapter.targets" Condition="Exists('..\packages\MSTest.TestAdapter.1.4.0\build\net45\MSTest.TestAdapter.targets')" />
|
||||
</Project>
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Azure.KeyVault.Core" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.4.0" newVersion="3.0.4.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" /></startup></configuration>
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Azure.KeyVault" version="3.0.4" targetFramework="net472" />
|
||||
<package id="Microsoft.Azure.KeyVault.Core" version="1.0.0" targetFramework="net472" />
|
||||
<package id="Microsoft.Azure.KeyVault.WebKey" version="3.0.4" targetFramework="net472" />
|
||||
<package id="Microsoft.Identity.Client" version="4.3.0" targetFramework="net472" />
|
||||
<package id="Microsoft.Rest.ClientRuntime" version="2.3.20" targetFramework="net472" />
|
||||
<package id="Microsoft.Rest.ClientRuntime.Azure" version="3.3.19" targetFramework="net472" />
|
||||
<package id="MSTest.TestAdapter" version="1.4.0" targetFramework="net46" />
|
||||
<package id="MSTest.TestFramework" version="1.4.0" targetFramework="net46" />
|
||||
<package id="Newtonsoft.Json" version="12.0.2" targetFramework="net46" />
|
||||
<package id="WindowsAzure.Storage" version="9.3.3" targetFramework="net472" />
|
||||
<package id="YamlDotNet" version="6.1.2" targetFramework="net46" />
|
||||
</packages>
|
|
@ -0,0 +1,7 @@
|
|||
dataset:
|
||||
!azure.storage.blob
|
||||
containername: test
|
||||
path: test.csv
|
||||
datasource:
|
||||
!azure.storage.account
|
||||
accountname: workspacetest
|
|
@ -0,0 +1,25 @@
|
|||
myserviceprincipal1: &myserviceprincipal1
|
||||
# created using
|
||||
# Connect-AzureRmAccount
|
||||
# $ServicePrincipal = New-AzureRmADServicePrincipal -DisplayName "Microsoft Workspace " `
|
||||
# -Password (ConvertTo-SecureString "[Enter password]" -AsPlainText -Force)
|
||||
# Out-Host -InputObject $ServicePrincipal.ApplicationId
|
||||
!azure.serviceprincipal
|
||||
clientid: b9a08b0b-2361-46ac-8487-f725c6730f67
|
||||
tenantid: 72f988bf-86f1-41af-91ab-2d7cd011db47
|
||||
|
||||
myvault1: &myvault1
|
||||
!azure.keyvault
|
||||
dnsname: https://workspacetest.vault.azure.net/
|
||||
credential: *myserviceprincipal1
|
||||
|
||||
workspacetest1: &workspacetest1
|
||||
!azure.storage.account
|
||||
accountname: workspacetest
|
||||
credentialstore: *myvault1
|
||||
|
||||
dataset:
|
||||
!azure.storage.blob
|
||||
containername: test
|
||||
path: test.csv
|
||||
datasource: *workspacetest1
|
|
@ -0,0 +1,19 @@
|
|||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Microsoft.Workspace.Azure.AD;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.WorkspaceTest
|
||||
{
|
||||
[TestClass]
|
||||
public class SilentAuthenticationTest
|
||||
{
|
||||
[TestMethod]
|
||||
public async Task TestSilentAuth()
|
||||
{
|
||||
//var silentAuth = new SilentAuthentication();
|
||||
//var result = await silentAuth.GetATokenForGraphAsync();
|
||||
|
||||
//int x = 1;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
|
||||
<AssemblyName>Microsoft.WorkspaceTest</AssemblyName>
|
||||
|
||||
<RootNamespace>Microsoft.WorkspaceTest</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="1.3.2" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="1.3.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Workspace.Azure.Storage\Workspace.Azure.Storage.csproj" />
|
||||
<ProjectReference Include="..\Workspace.AzureActiveDirectory\Workspace.Azure.AD.csproj" />
|
||||
<ProjectReference Include="..\Workspace\Workspace.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,61 @@
|
|||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Microsoft.Workspace;
|
||||
using Microsoft.Workspace.Azure.Storage;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.WorkspaceTest
|
||||
{
|
||||
[TestClass]
|
||||
public class YamlTest
|
||||
{
|
||||
private string yaml = @"
|
||||
datasources: # just convention, support arbitrary structure
|
||||
folder1:
|
||||
myblobsource1: &myblobsource1
|
||||
!azure.storage.account
|
||||
accountname: webscaleai
|
||||
";
|
||||
|
||||
[TestMethod]
|
||||
public void TestTypeResolution()
|
||||
{
|
||||
var ws = new WorkspaceImpl(new StringReader(yaml));
|
||||
|
||||
var resources = ws.Resources.ToList();
|
||||
|
||||
Assert.AreEqual(1, resources.Count);
|
||||
Assert.IsInstanceOfType(resources.First(), typeof(Account));
|
||||
|
||||
var storageAccount = resources.First() as Account;
|
||||
Assert.AreEqual("webscaleai", storageAccount.Name);
|
||||
|
||||
IResource storageAccountResource = storageAccount;
|
||||
Assert.AreEqual("myblobsource1", storageAccountResource.Name);
|
||||
CollectionAssert.AreEqual(new[] { "datasources", "folder1" }, storageAccountResource.Path);
|
||||
Assert.AreSame(ws, storageAccountResource.Workspace);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestLookupByKey()
|
||||
{
|
||||
var ws = new WorkspaceImpl(new StringReader(yaml));
|
||||
|
||||
var q = ws["myblobsource1"];
|
||||
Assert.AreEqual(1, q.Count());
|
||||
|
||||
Assert.IsInstanceOfType(q.First(), typeof(Account));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestLookupByPath()
|
||||
{
|
||||
var ws = new WorkspaceImpl(new StringReader(yaml));
|
||||
|
||||
var q = ws["datasources/folder1/myblobsource1"];
|
||||
Assert.AreEqual(1, q.Count());
|
||||
|
||||
Assert.IsInstanceOfType(q.First(), typeof(Account));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
parameters:
|
||||
operatingSystems: ["ubuntu-16.04", 'macos-10.13', 'vs2017-win2016']
|
||||
|
||||
jobs:
|
||||
- job:
|
||||
displayName: '.NET Core'
|
||||
strategy:
|
||||
matrix:
|
||||
${{ each os in parameters.operatingSystems }}:
|
||||
${{ format('{0}', os) }}:
|
||||
imageName: ${{ os }}
|
||||
|
||||
pool:
|
||||
vmImage: $(imageName)
|
||||
|
||||
steps:
|
||||
- task: DotNetCoreInstaller@0
|
||||
inputs:
|
||||
version: '2.1.300'
|
||||
|
||||
- script: |
|
||||
cd dotnet
|
||||
dotnet restore
|
||||
displayName: NuGet Restore
|
||||
|
||||
- task: DotNetCoreCLI@2
|
||||
displayName: Build
|
||||
inputs:
|
||||
command: build
|
||||
projects: |
|
||||
dotnet/Workspace/*.csproj
|
||||
dotnet/Workspace.Azure.KeyVault/*.csproj
|
||||
dotnet/Workspace.Azure.Storage/*.csproj
|
||||
dotnet/Workspace.AzureActiveDirectory/*.csproj
|
||||
dotnet/WorkspaceTest/*.csproj
|
||||
arguments: '--configuration Release'
|
||||
|
||||
- task: DotNetCoreCLI@2
|
||||
displayName: Test
|
||||
inputs:
|
||||
command: test
|
||||
projects: 'dotnet/WorkspaceTest/*.csproj'
|
||||
# broken on ubuntu/mac --collect "Code coverage"
|
||||
arguments: '--configuration Release '
|
||||
|
||||
# TODO: nuget
|
||||
# - script: dotnet pack /p:PackageVersion=$(version) # define version variable elsewhere in your pipeline
|
||||
# - task: NuGetCommand@2
|
||||
# command: push
|
||||
# nuGetFeedType: external
|
||||
# publishFeedCredentials: '<Name of the NuGet service connection>'
|
||||
# versioningScheme: byEnvVar
|
||||
# versionEnvVar: version
|
|
@ -0,0 +1,42 @@
|
|||
trigger:
|
||||
branches:
|
||||
include:
|
||||
- master
|
||||
paths:
|
||||
include:
|
||||
- dotnet/*
|
||||
|
||||
stages:
|
||||
- stage: Compliance
|
||||
jobs:
|
||||
- job:
|
||||
steps:
|
||||
- task: ComponentGovernanceComponentDetection@0
|
||||
inputs:
|
||||
scanType: 'Register'
|
||||
verbosity: 'Verbose'
|
||||
alertWarningLevel: 'High'
|
||||
|
||||
- stage: DotNetDesktop
|
||||
jobs:
|
||||
- job:
|
||||
pool:
|
||||
vmImage: 'windows-2019'
|
||||
steps:
|
||||
- script: |
|
||||
cd dotnet
|
||||
dotnet restore
|
||||
displayName: NuGet Restore
|
||||
|
||||
- task: VSBuild@1
|
||||
inputs:
|
||||
solution: dotnet/Workspace.sln
|
||||
restoreNugetPackages: true
|
||||
|
||||
- task: VSTest@2
|
||||
inputs:
|
||||
testSelector: 'testAssemblies'
|
||||
testAssemblyVer2: |
|
||||
'**\Microsoft.WorkspaceTest.Desktop.dll'
|
||||
'**\Microsoft.WorkspaceTest.dll'
|
||||
codeCoverageEnabled: True
|
|
@ -0,0 +1,22 @@
|
|||
trigger:
|
||||
branches:
|
||||
include:
|
||||
- master
|
||||
paths:
|
||||
include:
|
||||
- dotnet/*
|
||||
|
||||
stages:
|
||||
- stage: Compliance
|
||||
jobs:
|
||||
- job:
|
||||
steps:
|
||||
- task: ComponentGovernanceComponentDetection@0
|
||||
inputs:
|
||||
scanType: 'Register'
|
||||
verbosity: 'Verbose'
|
||||
alertWarningLevel: 'High'
|
||||
|
||||
- stage: DotNetCore
|
||||
jobs:
|
||||
- template: azure-pipelines-template.yaml
|
|
@ -1,3 +1,11 @@
|
|||
trigger:
|
||||
branches:
|
||||
include:
|
||||
- master
|
||||
paths:
|
||||
include:
|
||||
- python/*
|
||||
|
||||
stages:
|
||||
- stage: Compliance
|
||||
jobs:
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
from .auth import *
|
||||
from .keyvault import *
|
||||
from .storage import *
|
||||
from .storage import *
|
||||
from .subscription import *
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
from .managed_service_identity import *
|
||||
from .serviceprincipal import *
|
||||
from .user_with_device_code import *
|
||||
from .user_with_device_code import *
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
from ...base import Resource
|
||||
|
||||
|
||||
class ManagedServiceIdentity(Resource):
|
||||
yaml_tag = u'!azure.msi'
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def get_client_lazy(self):
|
||||
try:
|
||||
from msrestazure.azure_active_directory import MSIAuthentication
|
||||
|
||||
# TODO: add support for other resource types
|
||||
msi_auth = MSIAuthentication()
|
||||
msi_auth.set_token()
|
||||
|
||||
return msi_auth
|
||||
except Exception as e:
|
||||
return None
|
|
@ -8,7 +8,7 @@ class AzureServicePrincipal(Resource):
|
|||
self.clientid = clientid
|
||||
self.tenantid = tenantid
|
||||
|
||||
def get_client(self):
|
||||
def get_client_lazy(self):
|
||||
from azure.common.credentials import ServicePrincipalCredentials
|
||||
|
||||
# TODO add cloud environment
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
from ..base import Resource
|
||||
from .auth.managed_service_identity import ManagedServiceIdentity
|
||||
|
||||
|
||||
class AzureResource(Resource):
|
||||
def get_subscriptions(self) -> 'List[AzureSubscription]':
|
||||
from .subscription import AzureSubscription
|
||||
|
||||
subscriptions = self.get_workspace().get_all_of_type(AzureSubscription)
|
||||
|
||||
# no subscriptions configured try to auto resolve through MSI
|
||||
if len(subscriptions) == 0:
|
||||
subscriptions.append(AzureSubscription())
|
||||
|
||||
return subscriptions
|
||||
|
||||
def get_resource_group(self):
|
||||
return getattr(self, 'resource_group', None)
|
||||
|
||||
def get_auth_client(self):
|
||||
if not hasattr(self, 'auth_client'):
|
||||
# fallback to MSI
|
||||
self.auth_client = ManagedServiceIdentity()
|
||||
|
||||
# this can also be a service principal or device auth
|
||||
return self.auth_client.get_client()
|
|
@ -1,4 +1,3 @@
|
|||
import yaml
|
||||
from azure.keyvault import KeyVaultClient, KeyVaultAuthentication, KeyVaultId
|
||||
from azure.keyvault.models import KeyVaultErrorException
|
||||
from ..credentialprovider import CredentialProvider
|
||||
|
|
|
@ -3,11 +3,14 @@ import yaml
|
|||
from enum import Enum
|
||||
import datetime
|
||||
# TODO: from workspace.base import ... should work
|
||||
from ..base import Resource
|
||||
from ..base import KeyNotFoundException, Resource
|
||||
from ..datasource import URLDataSource
|
||||
from .azure_resource import AzureResource
|
||||
|
||||
|
||||
class AzureStorage(AzureResource):
|
||||
yaml_tag = u'!azure.storage.account'
|
||||
|
||||
class AzureStorage(Resource):
|
||||
yaml_tag = u'!azure.storage'
|
||||
def __init__(self, accountname, accountkey=None, credentialstore=None):
|
||||
self.accountname = accountname
|
||||
self.accountkey = accountkey
|
||||
|
@ -22,33 +25,82 @@ class AzureStorage(Resource):
|
|||
def is_secret_a_sas_token(self) -> bool:
|
||||
return self.get_secrettype().lower() == 'sas'
|
||||
|
||||
def get_secret(self):
|
||||
# TODO: cache secret
|
||||
try:
|
||||
return super().get_secret()
|
||||
except KeyNotFoundException as ex:
|
||||
try:
|
||||
from azure.mgmt.storage import StorageManagementClient
|
||||
|
||||
auth_client = self.get_auth_client()
|
||||
|
||||
resource_group = self.get_resource_group()
|
||||
|
||||
# loop through subscriptions
|
||||
for sub in self.get_subscriptions():
|
||||
for id in sub.get_ids():
|
||||
storage_client = StorageManagementClient(
|
||||
auth_client, id)
|
||||
|
||||
if resource_group is None:
|
||||
for acc in storage_client.storage_accounts.list():
|
||||
if acc.name == self.accountname:
|
||||
# found the account, let's break out
|
||||
resource_group = acc.id.split('/')[4]
|
||||
break
|
||||
|
||||
# let's check if we found the account, if not let's try the next subscription
|
||||
if resource_group is None:
|
||||
continue
|
||||
|
||||
storage_keys = storage_client.storage_accounts.list_keys(
|
||||
resource_group, self.accountname)
|
||||
# TODO: this seems to be model dependent?
|
||||
return storage_keys.keys[0].value
|
||||
except Exception as e:
|
||||
raise e
|
||||
raise ex
|
||||
|
||||
def get_client_lazy(self):
|
||||
# only import if method is used
|
||||
from azure.storage.common import CloudStorageAccount
|
||||
|
||||
|
||||
# key vs SAS token
|
||||
account_key = sas_token = None
|
||||
if self.is_secret_a_sas_token():
|
||||
sas_token = self.get_secret()
|
||||
else:
|
||||
account_key = self.get_secret()
|
||||
|
||||
|
||||
try:
|
||||
if self.is_secret_a_sas_token():
|
||||
sas_token = self.get_secret()
|
||||
else:
|
||||
account_key = self.get_secret()
|
||||
except KeyNotFoundException as e:
|
||||
# fallback to subscription lookup
|
||||
account_key = self._find_key_through_subscription()
|
||||
|
||||
if account_key is None:
|
||||
raise e
|
||||
|
||||
# TODO: endpoint_suffix
|
||||
return CloudStorageAccount(account_name=self.accountname,
|
||||
account_key=account_key,
|
||||
sas_token=sas_token,
|
||||
is_emulated=getattr(self, "is_emulated", None),
|
||||
endpoint_suffix=getattr(self, "endpoint_suffix", None))
|
||||
account_key=account_key,
|
||||
sas_token=sas_token,
|
||||
is_emulated=getattr(
|
||||
self, "is_emulated", None),
|
||||
endpoint_suffix=getattr(self, "endpoint_suffix", None))
|
||||
|
||||
|
||||
class AzureBlob(URLDataSource):
|
||||
yaml_tag = u'!azure.blob'
|
||||
yaml_tag = u'!azure.storage.blob'
|
||||
|
||||
def __init__(self, datasource, path):
|
||||
self.datasource = datasource
|
||||
self.path = path
|
||||
|
||||
def download(self, target) -> None:
|
||||
block_blob_service = self.datasource.get_client().create_block_blob_service()
|
||||
block_blob_service.get_blob_to_path(self.container_name, target, self.path)
|
||||
block_blob_service.get_blob_to_path(
|
||||
self.container_name, target, self.path)
|
||||
|
||||
def get_url(self) -> str:
|
||||
if not hasattr(self, 'datasource'):
|
||||
|
@ -61,14 +113,17 @@ class AzureBlob(URLDataSource):
|
|||
from azure.storage.blob.models import ContainerPermissions
|
||||
|
||||
# could also get SAS on the fly by getting ADAL context: https://github.com/Azure/azure-storage-python/blob/master/azure-storage-blob/azure/storage/blob/sharedaccesssignature.py
|
||||
sas = BlobSharedAccessSignature(self.datasource.accountname, account_key=self.datasource.get_secret())
|
||||
sas = BlobSharedAccessSignature(
|
||||
self.datasource.accountname, account_key=self.datasource.get_secret())
|
||||
|
||||
now = datetime.datetime.utcnow()
|
||||
sas_token = sas.generate_blob(
|
||||
self.containername,
|
||||
self.containername,
|
||||
self.path,
|
||||
permission=ContainerPermissions(read=True), # TODO: maybe write?
|
||||
start=now - datetime.timedelta(hours=1), # this feels like trouble
|
||||
permission=ContainerPermissions(
|
||||
read=True), # TODO: maybe write?
|
||||
# this feels like trouble
|
||||
start=now - datetime.timedelta(hours=1),
|
||||
expiry=now + datetime.timedelta(hours=12))
|
||||
|
||||
# TODO: secure vs non-secure
|
||||
|
@ -78,4 +133,4 @@ class AzureBlob(URLDataSource):
|
|||
self.datasource.accountname,
|
||||
self.containername,
|
||||
self.path,
|
||||
sas_token)
|
||||
sas_token)
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
from ..base import Resource
|
||||
from .azure_resource import AzureResource
|
||||
from .auth import managed_service_identity
|
||||
from typing import List
|
||||
|
||||
|
||||
class AzureSubscription(AzureResource):
|
||||
yaml_tag = u'!azure.subscription'
|
||||
|
||||
def __init__(self, id=None, ids=[]):
|
||||
self.ids = ids
|
||||
|
||||
if id is not None:
|
||||
self.ids.append(id)
|
||||
|
||||
def get_resource_group(self):
|
||||
return getattr(self, 'resourcegroup', None)
|
||||
|
||||
def get_ids(self) -> List[str]:
|
||||
ret = []
|
||||
|
||||
if hasattr(self, 'id'):
|
||||
ret.append(self.id)
|
||||
|
||||
if hasattr(self, 'ids'):
|
||||
ret.extend(self.ids)
|
||||
|
||||
if len(ret) == 0:
|
||||
# TODO: resolve configured msi
|
||||
auth = self.get_auth_client()
|
||||
if auth is not None:
|
||||
try:
|
||||
# let's try to enumerate subscriptions
|
||||
from azure.mgmt.subscription import SubscriptionClient
|
||||
subscription_client = SubscriptionClient(auth)
|
||||
|
||||
ret.extend(map(lambda s: s.subscription_id,
|
||||
subscription_client.subscriptions.list()))
|
||||
except:
|
||||
pass
|
||||
|
||||
return ret
|
|
@ -33,7 +33,7 @@ class Workspace:
|
|||
|
||||
for name in os.listdir(path):
|
||||
# TODO: allow for different name. global param? ctor param?
|
||||
if name == 'resources.yaml' or name == 'resources.yml':
|
||||
if name == 'resources.yaml':
|
||||
return os.path.join(path, name)
|
||||
|
||||
# going up the directory structure
|
||||
|
|
|
@ -34,6 +34,7 @@ setup(name='pyworkspace',
|
|||
'test': ['azureml-dataprep[pandas]',
|
||||
'azure-keyvault',
|
||||
'azure-storage-blob',
|
||||
'azure-mgmt-subscription',
|
||||
'sqlalchemy',
|
||||
'keyring',
|
||||
'keyrings.alt', # not recommended for production
|
||||
|
|
|
@ -14,7 +14,7 @@ myvault1: &myvault1
|
|||
credential: *myserviceprincipal1
|
||||
|
||||
workspacetest1: &workspacetest1
|
||||
!azure.storage
|
||||
!azure.storage.account
|
||||
accountname: workspacetest
|
||||
credentialstore: *myvault1
|
||||
|
||||
|
@ -22,7 +22,7 @@ csv1:
|
|||
!csv
|
||||
separator: "\t"
|
||||
dataset:
|
||||
!azure.blob
|
||||
!azure.storage.blob
|
||||
containername: test
|
||||
path: test.csv
|
||||
datasource: *workspacetest1
|
||||
|
|
|
@ -12,12 +12,12 @@ credentials:
|
|||
datasources: # just convention, support arbitrary structure
|
||||
folder1:
|
||||
myblobsource1: &myblobsource1
|
||||
!azure.storage
|
||||
!azure.storage.account
|
||||
accountname: webscaleai
|
||||
credentialstore: *myvault1
|
||||
|
||||
myblobsource2: &myblobsource2
|
||||
!azure.storage
|
||||
!azure.storage.account
|
||||
accountname: storage2
|
||||
secrettype: SAS
|
||||
|
||||
|
@ -47,13 +47,13 @@ cogservices:
|
|||
datasets:
|
||||
criteo:
|
||||
day0:
|
||||
!azure.blob
|
||||
!azure.storage.blob
|
||||
datasource: *myblobsource1
|
||||
containername: criteo
|
||||
path: 1_csv/day_0.gz
|
||||
|
||||
all_days: &all_days
|
||||
!azure.blob
|
||||
!azure.storage.blob
|
||||
datasource: *myblobsource1
|
||||
containername: criteo
|
||||
path: 1_csv/*gz
|
||||
|
|
Загрузка…
Ссылка в новой задаче