Skip to content

Instantly share code, notes, and snippets.

@buchizo
Created April 23, 2019 08:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save buchizo/4e4745a0e514571476503575e8afc81b to your computer and use it in GitHub Desktop.
Save buchizo/4e4745a0e514571476503575e8afc81b to your computer and use it in GitHub Desktop.
get role assignments and userinfo using ARM and Graph API on Functions (2)
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System.Net.Http;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace FunctionApp7
{
public static class Function1
{
static Function1()
{
var builder = new ConfigurationBuilder()
.AddJsonFile("local.settings.json", true, false)
.AddJsonFile("secret.settings.json", true, false)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
private static async Task<AuthenticationResult> GetS2SAccessToken(string authority, string resource, string clientId, string clientSecret)
{
var clientCredential = new ClientCredential(clientId, clientSecret);
AuthenticationContext context = new AuthenticationContext(authority, false);
AuthenticationResult authenticationResult = await context.AcquireTokenAsync(
resource,
clientCredential);
return authenticationResult;
}
private static IConfigurationRoot Configuration { get; }
private static HttpClient Client = new HttpClient();
[FunctionName("Function1")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequest req,
ILogger log)
{
try
{
// トークンの期限は考慮してないので注意
var token = await GetS2SAccessToken(
string.Format("https://login.microsoftonline.com/{0}/", Configuration["Tenant"]),
"https://management.azure.com/",
Configuration["AppId"],
Configuration["AppSecret"]
);
var tokengraph = await GetS2SAccessToken(
string.Format("https://login.microsoftonline.com/{0}/", Configuration["Tenant"]),
"https://graph.microsoft.com/",
Configuration["AppId"],
Configuration["AppSecret"]
);
var subscriptionId = req.Query["subscriptionid"];
// ロール割り当ての取得
var roleassignments = Utf8Json.JsonSerializer.Deserialize<dynamic>(await GetRoleAssignment(subscriptionId, token.CreateAuthorizationHeader()));
var assingments = roleassignments["value"] as List<dynamic>;
if (assingments == null) return new JsonResult( new { message = "role assignment is none, or not found" });
var roledefs = await Task.WhenAll(
assingments
.Select(x => x["properties"]["roleDefinitionId"])
.Distinct()
.AsParallel()
.Select(async roleid =>
{
var roledef = Utf8Json.JsonSerializer.Deserialize<dynamic>(await GetRoleDefine(roleid, token.CreateAuthorizationHeader()));
return new
{
id = roleid,
displayName = roledef["properties"]["roleName"]
};
})
);
// 割り当てユーザー・グループの情報取得
var assignmentusers = assingments?
.Select(x => x["properties"]["principalId"] as string)
.Distinct()
.ToList();
var dirobjjson = Utf8Json.JsonSerializer.Deserialize<dynamic>(await GetObjectInformation(assignmentusers, tokengraph.CreateAuthorizationHeader()));
var dirobjs = (dirobjjson["value"] as List<dynamic>)?
.Select(x => new {
displayName = x["displayName"],
mail = x["mail"],
id = x["id"],
upn = HasPropertyExist(x, "userPrincipalName") ? x["userPrincipalName"] : "",
objectType = x["@odata.type"]
})
.ToList();
return new JsonResult(assingments.Select(x => new
{
role = roledefs.FirstOrDefault(r => r.id == x["properties"]["roleDefinitionId"]),
user = dirobjs.FirstOrDefault(u => u.id == x["properties"]["principalId"])
})
.Where(x=>x.user != null)
);
}
catch (Exception ex)
{
log.LogError(ex.Message);
throw;
}
}
static async Task<string> InvokeApi(string requesturi, string authheader)
{
var request = new HttpRequestMessage()
{
Method = HttpMethod.Get,
RequestUri = new Uri(requesturi),
};
request.Headers.Add("Authorization", authheader);
var res = await Client.SendAsync(request);
if (res.StatusCode != System.Net.HttpStatusCode.OK) return null;
return await res.Content.ReadAsStringAsync();
}
static async Task<string> InvokePostApi(string requesturi, string authheader, string postbody)
{
var request = new HttpRequestMessage()
{
Method = HttpMethod.Post,
RequestUri = new Uri(requesturi),
};
request.Headers.Add("Authorization", authheader);
request.Content = new StringContent(postbody, Encoding.UTF8, "application/json");
var res = await Client.SendAsync(request);
if (res.StatusCode != System.Net.HttpStatusCode.OK) return null;
return await res.Content.ReadAsStringAsync();
}
static async Task<string> GetRoleAssignment(string subscriptionId, string authheader)
{
return await InvokeApi(
$"https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Authorization/roleAssignments?api-version=2015-07-01",
authheader
);
}
static async Task<string> GetRoleDefine(string roleId, string authheader)
{
return await InvokeApi(
$"https://management.azure.com/{roleId}?api-version=2015-07-01",
authheader
);
}
static async Task<string> GetUserInformation(string userid, string authheader)
{
return await InvokeApi(
$"https://graph.microsoft.com/v1.0/users/{userid}",
authheader
);
}
static async Task<string> GetObjectInformation(List<string> ids, string authheader)
{
return await InvokePostApi(
$"https://graph.microsoft.com/v1.0/directoryObjects/getByIds",
authheader,
Utf8Json.JsonSerializer.ToJsonString(new { ids = ids })
);
}
public static bool HasPropertyExist(dynamic obj, string name)
{
if (obj is Dictionary<string, object>)
return ((IDictionary<string, object>)obj).ContainsKey(name);
try
{
return obj[name] != null;
}
catch (KeyNotFoundException)
{
return false;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment