- credentials: sifrovani AES-GCM/HKDF odstraneno, tri hlavicky se berou
tak, jak jsou; bez hlavicek se pouziji hodnoty z prostredi
- zrusena promenna MS365_CREDENTIAL_ENCODING_SECRET a zavislost cryptography
- novy endpoint GET /users/{user_id}/calendar (objekt kalendare schranky,
id a name) pro read-only overeni pristupu pres e-mail schranky
- C# ukazka posila hodnoty primo, CredentialEncoder smazan
- README: sekce o hlavickach vcetne PowerShell ukazky, zaznam zmen
- .gitignore: bin/ a obj/, zaverzovane obj/ soubory ukazky odstraneny z gitu
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
75 lines
2.8 KiB
C#
75 lines
2.8 KiB
C#
// Ukazka volani microsoft-365-service: vypis prvnich 10 uzivatelu z GET /users.
|
|
//
|
|
// Sluzba: https://services.csbot.cz/apps/microsoft-365-service
|
|
// Dokumentace (Swagger): https://services.csbot.cz/apps/microsoft-365-service/docs
|
|
//
|
|
// Credentials se posilaji v hlavickach X-MS365-* jako obycejne hodnoty.
|
|
//
|
|
// Spusteni:
|
|
// set MS365_SERVICE_BASE_URL=https://services.csbot.cz/apps/microsoft-365-service
|
|
// set MS365_TENANT_ID=<tenant id klienta>
|
|
// set MS365_CLIENT_ID=<client id aplikace CSBOT>
|
|
// set MS365_CLIENT_SECRET=<client secret VALUE, ne secret id>
|
|
// dotnet run
|
|
|
|
using System.Net.Http.Headers;
|
|
using System.Text.Json;
|
|
|
|
var baseUrl = Env("MS365_SERVICE_BASE_URL", "https://services.csbot.cz/apps/microsoft-365-service");
|
|
var tenantId = Env("MS365_TENANT_ID");
|
|
var clientId = Env("MS365_CLIENT_ID");
|
|
var clientSecret = Env("MS365_CLIENT_SECRET");
|
|
|
|
const int top = 10;
|
|
|
|
using var http = new HttpClient { BaseAddress = new Uri(baseUrl.TrimEnd('/') + "/") };
|
|
http.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
|
|
|
using var request = new HttpRequestMessage(HttpMethod.Get, $"users?top={top}");
|
|
request.Headers.Add("X-MS365-Tenant-Id", tenantId);
|
|
request.Headers.Add("X-MS365-Client-Id", clientId);
|
|
request.Headers.Add("X-MS365-Client-Secret", clientSecret);
|
|
|
|
using var response = await http.SendAsync(request);
|
|
var body = await response.Content.ReadAsStringAsync();
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
{
|
|
// 400 = neuplne hlavicky, 502 = chyba z Microsoft Graph (detail je v tele),
|
|
// 403 text/plain = request neprosel pres reverzni proxy (IP allowlist pro GET).
|
|
Console.Error.WriteLine($"HTTP {(int)response.StatusCode} {response.ReasonPhrase}");
|
|
Console.Error.WriteLine(body);
|
|
return 1;
|
|
}
|
|
|
|
// Sluzba vraci odpoved Microsoft Graph beze zmeny: { "value": [ { ...user... } ], "@odata.nextLink": "..." }
|
|
using var json = JsonDocument.Parse(body);
|
|
var users = json.RootElement.GetProperty("value");
|
|
|
|
Console.WriteLine($"Nacteno uzivatelu: {users.GetArrayLength()}");
|
|
foreach (var user in users.EnumerateArray())
|
|
{
|
|
var displayName = user.TryGetProperty("displayName", out var dn) ? dn.GetString() : null;
|
|
var upn = user.TryGetProperty("userPrincipalName", out var up) ? up.GetString() : null;
|
|
var mail = user.TryGetProperty("mail", out var m) && m.ValueKind == JsonValueKind.String ? m.GetString() : null;
|
|
var id = user.GetProperty("id").GetString();
|
|
|
|
Console.WriteLine($"{displayName} | {upn} | {mail ?? "-"} | {id}");
|
|
}
|
|
|
|
return 0;
|
|
|
|
static string Env(string name, string? fallback = null)
|
|
{
|
|
var value = Environment.GetEnvironmentVariable(name);
|
|
if (!string.IsNullOrWhiteSpace(value))
|
|
{
|
|
return value;
|
|
}
|
|
if (fallback is not null)
|
|
{
|
|
return fallback;
|
|
}
|
|
throw new InvalidOperationException($"Chybi environment promenna {name}.");
|
|
}
|