English 中文(简体)
图二
原标题:Trouble authenticating to Microsoft Graph API with certificate in PowerShell

我正试图避免使用任何额外的电荷模块(5.1个单元),因此,我正在使用这一文字(用户Id,美元坚挺)。 I和cer是这一职位的随机值:

$thumbprint = "<thumbprint taken from the cert properties>"
$expUnixTime = [math]::truncate(((Get-Date).AddMinutes(30).ToUniversalTime()).Subtract((Get-Date "1970-01-01").ToUniversalTime()).TotalSeconds)

$payload = @{
    iss = "CN=<issuer>"
    sub = "CN=<subject (same as issuer)>"
    aud = "https: //login.microsoftonline.com/<tenant name>.onmicrosoft.com/oauth2/v2.0/token"
    exp = $expUnixTime # Token expiration time (30 minutes from now)
}
$encodedPayload = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(($payload | ConvertTo-Json)))

$cert = Get-Item -Path Cert:CurrentUserMy$thumbprint
$rsaPrivateKey = $cert.PrivateKey
$rsaCryptoProvider = New-Object System.Security.Cryptography.RSACryptoServiceProvider
$rsaCryptoProvider.ImportParameters($rsaPrivateKey.ExportParameters("PKCS8"))
$signatureBytes = $rsaCryptoProvider.SignData([System.Text.Encoding]::UTF8.GetBytes($encodedPayload), "SHA256")
$encodedSignature = [Convert]::ToBase64String($signatureBytes)

$jwtAssertion = "$encodedPayload.$encodedSignature"

$clientId = "<client id guid>"
$tenantId = "<teant id guid>"
$tokenUrl = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"

try {
    $body = @{
        client_id             = $clientId
        tenant_id             = $tenantId
        client_assertion_type = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
        client_assertion      = $jwtAssertion
        scope                 = "https://graph.microsoft.com/.default"
        grant_type            = "client_credentials"
    }

    $bodyQueryString = $(Foreach ($item in $body.GetEnumerator()) {
            "$($item.Key)=$($item.Value)"
        }) -join  & 

    $response = Invoke-RestMethod -Uri $tokenUrl -Method Post -Body $bodyQueryString -ContentType "application/x-www-form-urlencoded"

    $response
} catch {
    Write-Error "Error: $($_.Exception.Message)"
}

我正在回过这个错误:

{"error":"invalid_request","error_description":"AADSTS50027: JWT token is invalid or malformed. Trace ID: Correlation ID: Timestamp: 2024-02-20 20:50:49Z","error_codes":[50027],"timestamp":"2024-02-20 20:50:49Z","trace_id":"","correlation_id":"","error_uri":"https://login.microsoftonline.com/error?code=50027"}

I have looked at a few other questions, but have not identified anything helpful.

问题回答

获取<代码>clsertion<>/code>的过程是漫长的,有误的,这就是为什么大多数民间人士在.MSALbras或围绕它建造的单元,即:

这一过程记录如下:

如果你想全心全意地利用《维也纳条约法公约》,这一类应有助于创造:

class JwtAssertion {
    [System.Security.Cryptography.X509Certificates.X509Certificate2] $Certificate

    hidden [System.Text.Encoding] $encoding = [System.Text.Encoding]::UTF8

    hidden [hashtable] $claims = @{
        # exp: 5-10 minutes after nbf at most
        exp = [System.DateTimeOffset]::UtcNow.AddMinutes($minutes).ToUnixTimeSeconds()
        # jti: a GUID, unique identifier for the request
        jti = [guid]::NewGuid().ToString()
        # nbf: (not before), Using the current time is appropriate
        nbf = [System.DateTimeOffset]::UtcNow.ToUnixTimeSeconds()
        # iat: this is an optional claim, we dont need it here
    }

    hidden [hashtable] $header = @{
        alg =  RS256 
        typ =  JWT 
    }

    JwtAssertion([System.Security.Cryptography.X509Certificates.X509Certificate2] $cert) {
        $this.Certificate = $cert
        # x5t: Base64url-encoded SHA-1 thumbprint of the X.509 certificate s DER encoding.
        $this.header[ x5t ] = [JwtAssertion]::ToBase64UrlEncodedString($cert.GetCertHash())
    }

    [JwtAssertion] WithTenantId([guid] $tenantId) {
        $this.claims[ aud ] =  https://login.microsoftonline.com/{0}/oauth2/v2.0/token  -f $tenantId
        return $this
    }

    [JwtAssertion] WithClientId([guid] $clientId) {
        # iss: GUID application ID
        # sub: Use the same value as iss
        $this.claims[ iss ] = $this.header[ sub ] = $clientId
        return $this
    }

    [JwtAssertion] SetExpirationTime([int] $minutes) {
        $this.claims[ exp ] = [System.DateTimeOffset]::UtcNow.AddMinutes($minutes).ToUnixTimeSeconds()
        return $this
    }

    static [string] ToBase64UrlEncodedString([byte[]] $bytes) {
        return [System.Convert]::ToBase64String($bytes).
            Replace( + ,  - ).Replace( / ,  _ ).TrimEnd( = )
    }

    [string] GetAssertion() {
        $headerAsJson = $this.header | ConvertTo-Json -Compress
        $headerB64 = [JwtAssertion]::ToBase64UrlEncodedString($this.encoding.GetBytes($headerAsJson))

        $claimsAsJson = $this.claims | ConvertTo-Json -Compress
        $claimsB64 = [JwtAssertion]::ToBase64UrlEncodedString($this.encoding.GetBytes($claimsAsJson))

        $provider = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($this.Certificate)
        $signature = [JwtAssertion]::ToBase64UrlEncodedString($provider.SignData(
            $this.encoding.GetBytes("$headerB64.$claimsB64"),
            [Security.Cryptography.HashAlgorithmName]::SHA256,
            [Security.Cryptography.RSASignaturePadding]::Pkcs1))

        if ($provider) {
            $provider.Dispose()
        }

        return "$headerB64.$claimsB64.$signature"
    }
}

使用这一类别,然后取到:

$cert = Get-Item Cert:CurrentUserMyMyThumbprint
$TenantId =  xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 
$clientId =  xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 

$jwtAssertion = [JwtAssertion]::new($cert).
    WithTenantId($tenantId).
    WithClientId($clientId).
    SetExpirationTime(10). # the value is in minutes
    GetAssertion()

$invokeRestMethodSplat = @{
    Uri    =  https://login.microsoftonline.com/{0}/oauth2/v2.0/token  -f $tenantId
    Method =  POST 
    Body   = @{
        client_id             = $clientId
        client_assertion_type =  urn:ietf:params:oauth:client-assertion-type:jwt-bearer 
        client_assertion      = $jwtAssertion
        scope                 =  https://graph.microsoft.com/.default 
        grant_type            =  client_credentials 
    }
}

Invoke-RestMethod @invokeRestMethodSplat




相关问题
ajax login using httpRequest?

I am trying to develop my login script to give feedback to the user if the login is valid or not. Basically if it isn t correct a div box will show saying its wrong, if its correct it will show its ...

Remotely authenticating client Windows user on demand

Suppose I am writing a server for a particular network protocol. If I know that the client is running on a Windows machine, is it possible for my server to authenticate the Windows user that owns the ...

Role/Permission based forms authorizing/authentication?

While looking into forms authorizing/authentication, I found that it is possible to do role based authorizing by adding an array of roles to a FormsAuthenticationTicket. That way I can write User....

热门标签