Skip to content
This repository was archived by the owner on Feb 23, 2024. It is now read-only.

Commit 0650237

Browse files
committed
First checkin with GetAccessToken
1 parent 69f8639 commit 0650237

15 files changed

+336
-7
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>netcoreapp2.2</TargetFramework>
6+
</PropertyGroup>
7+
8+
</Project>

src/GetAzureUserToken/Program.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System;
2+
using System.Diagnostics;
3+
4+
namespace GetAzureUserToken
5+
{
6+
class Program
7+
{
8+
static void Main(string[] args)
9+
{
10+
Console.WriteLine("Hello World!");
11+
var p = new Process();
12+
p.StartInfo.FileName = "cmd.exe";
13+
p.StartInfo.Arguments = @"/c az account get-access-token --query accessToken --output json ";
14+
p.StartInfo.CreateNoWindow = true;
15+
p.StartInfo.RedirectStandardError = true;
16+
p.StartInfo.RedirectStandardOutput = true;
17+
p.StartInfo.RedirectStandardInput = false;
18+
p.OutputDataReceived += (a, b) => Console.WriteLine(b.Data);
19+
p.ErrorDataReceived += (a, b) => Console.WriteLine(b.Data);
20+
p.Start();
21+
p.BeginErrorReadLine();
22+
p.BeginOutputReadLine();
23+
p.WaitForExit();
24+
Console.ReadKey();
25+
}
26+
}
27+
}

src/apimtemplate/Commands/Extract.cs

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
using System;
22
using McMaster.Extensions.CommandLineUtils;
3-
using McMaster.Extensions.CommandLineUtils.HelpText;
43
using Colors.Net;
4+
using System.Runtime.InteropServices;
5+
using System.Diagnostics;
6+
using System.Net.Http;
7+
using System.Net.Http.Headers;
8+
59

610
namespace Microsoft.Azure.Management.ApiManagement.ArmTemplates
711
{
@@ -13,16 +17,45 @@ public ExtractCommand()
1317
this.Description = Constants.ExtractDescription;
1418

1519
var apimname = this.Option("--name <apimname>", "API Management name", CommandOptionType.SingleValue).IsRequired();
20+
21+
var auth = new Authentication();
22+
23+
var aztoken = auth.GetAccessToken().Result;
24+
1625
this.HelpOption();
1726

18-
this.OnExecute(() =>
27+
this.OnExecute(async () =>
1928
{
2029
if (apimname.HasValue())
30+
{
2131
Console.WriteLine($"Create command executed with name {apimname.Value()}");
32+
33+
string requestUrl = string.Concat("https://management.azure.com/providers/Microsoft.ApiManagement/operations?api-version=2018-06-01-preview");//, "/groups", "?api-version=", "2018-06-01-preview");
34+
35+
using (HttpClient httpClient = new HttpClient())
36+
{
37+
var request = new HttpRequestMessage(HttpMethod.Get, requestUrl);
38+
39+
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", aztoken);
40+
41+
HttpResponseMessage response = await httpClient.SendAsync(request);
42+
43+
response.EnsureSuccessStatusCode();
44+
45+
string responseBody = await response.Content.ReadAsStringAsync();
46+
47+
ColoredConsole.Write(responseBody.ToString());
48+
Console.ReadKey();
49+
}
50+
}
2251
else
52+
{
2353
ColoredConsole.Error.WriteLine("API Management name passed in");
54+
}
2455
return 0;
2556
});
57+
2658
}
2759
}
28-
}
60+
}
61+

src/apimtemplate/Common/Constants.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ internal static class Constants
1111
public const string CreateDescription = "Create an API Management instance from files";
1212
public const string ExtractName = "extract";
1313
public const string ExtractDescription = "Extract an existing API Management instance";
14-
14+
15+
public const string azParameters = "account get-access-token --query \"accessToken\" --output json";
1516
}
1617
}

src/apimtemplate/Common/Executable.cs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
using System;
2+
using System.ComponentModel;
3+
using System.Diagnostics;
4+
using System.IO;
5+
using System.Threading.Tasks;
6+
7+
namespace Microsoft.Azure.Management.ApiManagement.ArmTemplates
8+
{
9+
internal class Executable
10+
{
11+
private string _arguments;
12+
private string _exeName;
13+
private bool _shareConsole;
14+
private bool _streamOutput;
15+
private readonly bool _visibleProcess;
16+
private readonly string _workingDirectory;
17+
18+
public Executable(string exeName, string arguments = null, bool streamOutput = true, bool shareConsole = false, bool visibleProcess = false, string workingDirectory = null)
19+
{
20+
_exeName = exeName;
21+
_arguments = arguments;
22+
_streamOutput = streamOutput;
23+
_shareConsole = shareConsole;
24+
_visibleProcess = visibleProcess;
25+
_workingDirectory = workingDirectory;
26+
}
27+
28+
public Process Process { get; private set; }
29+
30+
public async Task<int> RunAsync(Action<string> outputCallback = null, Action<string> errorCallback = null, TimeSpan? timeout = null)
31+
{
32+
var processInfo = new ProcessStartInfo
33+
{
34+
FileName = _exeName,
35+
Arguments = _arguments,
36+
CreateNoWindow = !_visibleProcess,
37+
UseShellExecute = _shareConsole,
38+
RedirectStandardError = _streamOutput,
39+
RedirectStandardInput = _streamOutput,
40+
RedirectStandardOutput = _streamOutput,
41+
WorkingDirectory = _workingDirectory ?? Environment.CurrentDirectory
42+
};
43+
44+
try
45+
{
46+
Process = Process.Start(processInfo);
47+
}
48+
catch (Win32Exception ex)
49+
{
50+
if (ex.Message == "The system cannot find the file specified")
51+
{
52+
throw new FileNotFoundException(ex.Message, ex);
53+
}
54+
throw ex;
55+
}
56+
57+
if (_streamOutput)
58+
{
59+
Process.OutputDataReceived += (s, e) => outputCallback?.Invoke(e.Data);
60+
Process.BeginOutputReadLine();
61+
Process.ErrorDataReceived += (s, e) => errorCallback?.Invoke(e.Data);
62+
Process.BeginErrorReadLine();
63+
Process.EnableRaisingEvents = true;
64+
}
65+
66+
var exitCodeTask = Process.WaitForExitAsync();
67+
68+
if (timeout == null)
69+
return await exitCodeTask;
70+
else
71+
{
72+
await Task.WhenAny(exitCodeTask, Task.Delay(timeout.Value));
73+
74+
if (exitCodeTask.IsCompleted)
75+
return exitCodeTask.Result;
76+
else
77+
{
78+
Process.Kill();
79+
throw new Exception("Process didn't exit within specified timeout");
80+
}
81+
}
82+
}
83+
}
84+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using System.Diagnostics;
2+
using System.Threading;
3+
using System.Threading.Tasks;
4+
5+
namespace Microsoft.Azure.Management.ApiManagement.ArmTemplates
6+
{
7+
internal static class ProcessExtensions
8+
{
9+
// http://stackoverflow.com/a/19104345
10+
public static Task<int> WaitForExitAsync(this Process process, CancellationToken cancellationToken = default(CancellationToken))
11+
{
12+
var tcs = new TaskCompletionSource<int>();
13+
process.EnableRaisingEvents = true;
14+
15+
process.Exited += (sender, args) => tcs.TrySetResult(process.ExitCode);
16+
17+
if (cancellationToken != default(CancellationToken))
18+
cancellationToken.Register(tcs.SetCanceled);
19+
20+
return tcs.Task;
21+
}
22+
}
23+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Globalization;
4+
using System.Security.Cryptography;
5+
using System.Text;
6+
7+
namespace Microsoft.Azure.Management.ApiManagement.ArmTemplates
8+
{
9+
public class SASAuthentication
10+
{
11+
// api-version query parameter - https://aka.ms/smapi#VersionQueryParameter
12+
static string apiVersion = "2014-02-14-preview";
13+
14+
static string serviceName = "contoso5";
15+
static string baseUrl = string.Format("https://{0}.management.azure-api.net", serviceName);
16+
17+
#region [TBI] SAS from Portal
18+
// You can get an access token from the API Management portal or you can programmatically generate it. For
19+
// more instructions on both approaches, see http://aka.ms/smapi#Authentication
20+
// One common cause of 401 Unauthorized response codes is when the Expiry date of the token that was
21+
// generated in the publisher portal has passed. If that happens, regenerate the token using the directions
22+
// in the link above. If you programmatically generate the token this typically does not happen.
23+
// To use a token generated in the publisher portal, follow the "To manually create an access token" instructions
24+
// at http://aka.ms/smapi#Authentication and paste in the token using the following format.
25+
static string sharedAccessSignature = "uid=...&ex=...";
26+
27+
// To programmatically generate the token, call the CreateSharedAccessToken method below.
28+
#endregion
29+
30+
public void GetSAStoken(string id, string key)
31+
{
32+
DateTime expiry = DateTime.UtcNow.AddDays(1);
33+
34+
sharedAccessSignature = CreateSharedAccessToken(id, key, expiry);
35+
36+
}
37+
static private string CreateSharedAccessToken(string id, string key, DateTime expiry)
38+
{
39+
using (var encoder = new HMACSHA512(Encoding.UTF8.GetBytes(key)))
40+
{
41+
string dataToSign = id + "\n" + expiry.ToString("O", CultureInfo.InvariantCulture);
42+
string x = string.Format("{0}\n{1}", id, expiry.ToString("O", CultureInfo.InvariantCulture));
43+
var hash = encoder.ComputeHash(Encoding.UTF8.GetBytes(dataToSign));
44+
var signature = Convert.ToBase64String(hash);
45+
string encodedToken = string.Format("uid={0}&ex={1:o}&sn={2}", id, expiry, signature);
46+
return encodedToken;
47+
}
48+
}
49+
}
50+
}

src/apimtemplate/Common/Util.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using Newtonsoft.Json;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Text;
5+
6+
namespace Microsoft.Azure.Management.ApiManagement.ArmTemplates
7+
{
8+
class Util
9+
{
10+
private static string FormatJSON(string json)
11+
{
12+
dynamic parsedJson = JsonConvert.DeserializeObject(json);
13+
return JsonConvert.SerializeObject(parsedJson, Formatting.Indented);
14+
}
15+
}
16+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using Colors.Net;
2+
using Microsoft.Azure.Management.ApiManagement.ArmTemplates;
3+
using System;
4+
using System.Runtime.InteropServices;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
8+
namespace Microsoft.Azure.Management.ApiManagement.ArmTemplates
9+
{
10+
public class Authentication
11+
{
12+
public async Task<string> GetAccessToken()
13+
{
14+
(bool cliSucceeded, string cliToken) = await TryGetAzCliToken();
15+
16+
if (cliSucceeded) return cliToken;
17+
18+
throw new Exception("Unable to connect to Azure. Make sure you have the `az` CLI or Azure PowerShell installed and logged in and try again");
19+
}
20+
21+
private async Task<(bool succeeded, string token)> TryGetAzCliToken()
22+
{
23+
var az = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
24+
? new Executable("cmd", "/c az " + Constants.azParameters)
25+
: new Executable("az", Constants.azParameters);
26+
27+
var stdout = new StringBuilder();
28+
var stderr = new StringBuilder();
29+
var completed = az.RunAsync(o => stdout.AppendLine(o), e => stderr.AppendLine(e));
30+
31+
if (await completed == 0)
32+
return (true, stdout.ToString().Trim(' ', '\n', '\r', '"'));
33+
else
34+
{
35+
ColoredConsole.WriteLine(($"Unable to fetch access token from az cli. Error: {stderr.ToString().Trim(' ', '\n', '\r')}"));
36+
return (false, stdout.ToString().Trim(' ', '\n', '\r', '"'));
37+
}
38+
}
39+
40+
}
41+
42+
}

src/apimtemplate/Program.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System;
2-
using System.Threading.Tasks;
32
using Colors.Net;
43
using McMaster.Extensions.CommandLineUtils;
54

@@ -16,7 +15,7 @@ class Program
1615
public static int Main(string[] args)
1716
{
1817
try
19-
{
18+
{
2019
var app = new CommandLineApplication()
2120
{
2221
Name = Constants.AppShortName,
@@ -30,7 +29,7 @@ public static int Main(string[] args)
3029

3130
app.OnExecute(() => {
3231
ColoredConsole.Error.WriteLine("No commands specified, please specify a command");
33-
app.ShowHelp();
32+
app.ShowHelp();
3433
return 1;
3534
});
3635

@@ -39,8 +38,11 @@ public static int Main(string[] args)
3938
catch (Exception e)
4039
{
4140
ColoredConsole.Error.WriteLine(e.Message);
41+
Console.ReadKey();
4242
return 1;
4343
}
4444
}
45+
46+
4547
}
4648
}

0 commit comments

Comments
 (0)