Skip to content

Instantly share code, notes, and snippets.

@watahani
Last active April 25, 2021 00:07
Show Gist options
  • Save watahani/d5b6def478b9f6a1fcb815123f537c53 to your computer and use it in GitHub Desktop.
Save watahani/d5b6def478b9f6a1fcb815123f537c53 to your computer and use it in GitHub Desktop.
function Convert-HexToBytes{
[OutputType([Microsoft.PowerShell.Commands.ByteCollection])]
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[string]$hex
)
process {
$hex = $hex.Trim()
$splitStrings = @(":", " ")
foreach ($s in $splitStrings) {
$hex = $hex.replace($s,"")
}
if ($hex.Length % 2 -ne 0){
throw "HEX string lenght should be even"
}
$Bytes = [byte[]]::new($hex.Length / 2)
For($i=0; $i -lt $hex.Length; $i+=2){
$Bytes[$i/2] = [convert]::ToByte($hex.Substring($i, 2), 16)
}
return $bytes
}
}
$certSubject = 'CN=SelfSignedCert'
$cert = Get-ChildItem -path cert:\CurrentUser\My | ? { $_.Subject -eq "$certSubject" }
$base64Thumb = [Convert]::ToBase64String(($cert.Thumbprint | Convert-HexToBytes))
$tenantId = "<tenant-id>"
$clientId = "<client-id>"
$scope = 'https://graph.microsoft.com/.default'
$tokenEndpoint = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"
$jit = (New-Guid).Guid
$UNIX_EPOCH = Get-Date("1970/1/1 0:0:0 GMT")
$iat = [Math]::Floor(((Get-Date) - $UNIX_EPOCH).TotalSeconds)
$nbf = $iat;
$exp = $iat + 60000
$headers = @{
alg = "RS256";
typ = "JWT";
x5t = $base64Thumb;
} | ConvertTo-Json -Compress
$body = @{
aud = "https://login.microsoftonline.com/$tenantId/v2.0";
iss = $clientId;
iat = $iat;
nbf = $nbf;
exp = $exp;
jti = $jit;
appid = $clientId;
sub = $clientId;
tid = $tenantId;
} | ConvertTo-Json -Compress
$jwtHeader = [Convert]::ToBase64String(([System.Text.Encoding]::Default).GetBytes($headers)).TrimEnd('=').Replace('+', '-').Replace('/', '_');
$jwtBody = [Convert]::ToBase64String(([System.Text.Encoding]::Default).GetBytes($body)).TrimEnd('=').Replace('+', '-').Replace('/', '_');
$unsignedToken = "$jwtHeader.$jwtBody"
try {
# なにやってるか意味わからんけど以下のコードを丸パクリ
# https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/d6f2b66d788195b50f2b1f700beb497851194c73/src/Microsoft.IdentityModel.Tokens/RsaCryptoServiceProviderProxy.cs#L75
$rsa = [System.Security.Cryptography.RSACryptoServiceProvider] $cert.PrivateKey;
$csp = New-Object System.Security.Cryptography.CspParameters
$csp.ProviderType = 24
$csp.KeyContainerName = $rsa.CspKeyContainerInfo.KeyContainerName
$csp.KeyNumber = [int]$rsa.CspKeyContainerInfo.KeyNumber;
$privateKey = New-Object System.Security.Cryptography.RSACryptoServiceProvider($csp)
# 署名
$sign = $privateKey.SignData([System.Text.Encoding]::UTF8.GetBytes($unsignedToken), [System.Security.Cryptography.HashAlgorithm]::Create("SHA256"))
$signBase64Url = [Convert]::ToBase64String($sign).TrimEnd('=').Replace('+', '-').Replace('/', '_');
$clientAssertion = "$unsignedToken.$signBase64Url"
$requestBody = @{
client_id=$clientId;
client_assertion=$clientAssertion;
client_assertion_type="urn:ietf:params:oauth:client-assertion-type:jwt-bearer";
grant_type="client_credentials";
scope=$scope;
}
$res = Invoke-RestMethod -Method POST -Uri $tokenEndpoint -Body $requestBody -ContentType "application/x-www-form-urlencoded"
}
catch {
throw
}
finally {
# テキトー
$privateKey.Dispose()
$rsa.Dispose()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment