microsoftgraph / msgraph-sdk-powershell

Powershell SDK for Microsoft Graph
https://www.powershellgallery.com/packages/Microsoft.Graph
Other
691 stars 165 forks source link

New-MgRoleManagementDirectoryRoleAssignmentScheduleRequest fails with "The following policy rules failed: ["MfaRule"]" error #1808

Open stukey opened 1 year ago

stukey commented 1 year ago

We are seeing a consistent issue activating AAD PIM roles using the Microsoft Graph SDK PowerShell module (version 2.0.0-Preview4).

We are attempting to enable/active a PIM role via Graph PowerShell module using the ‘New-MgRoleManagementDirectoryRoleAssignmentScheduleRequest’ cmdlet. For some admins (but not all) the request fails with the following error:

Exception             : System.Exception: [RoleAssignmentRequestPolicyValidationFailed] : The following policy rules failed: ["MfaRule"]
TargetObject          : { body = Microsoft.Graph.PowerShell.Models.MicrosoftGraphUnifiedRoleAssignmentScheduleRequest }
CategoryInfo          : InvalidOperation: ({ body = Micros...heduleRequest }:<>f__AnonymousType33`1) [New-MgRoleManag...eRequest_Create], Exception
FullyQualifiedErrorId : RoleAssignmentRequestPolicyValidationFailed,Microsoft.Graph.PowerShell.Cmdlets.NewMgRoleManagementDirectoryRoleAssignmentScheduleRequest_Create
ErrorDetails          : The following policy rules failed: ["MfaRule"]
InvocationInfo        : System.Management.Automation.InvocationInfo
ScriptStackTrace      : at New-MgRoleManagementDirectoryRoleAssignmentScheduleRequest<Process>, C:\ProgramFiles\WindowsPowerShell\Modules\Microsoft.Graph.Identity.Governance\2.0.0\exports\ProxyCmdletDefinitions.ps1: line 38209 at <ScriptBlock>, <No file>: line 1
PipelineIterationInfo : {}
PSMessageDetails      :

This is on Windows 10 with PowerShell 5.1. Our IDP is Okta.

When connecting to Graph via the Connect-MgGraph cmdlet, it does not prompt for MFA. It uses WIA, prompts to select the current user’s UPN and the connects. Then when we try to activate a PIM role, we get the above error. For other users, it also doesn’t prompt for MFA when connecting to MgGraph, but the PIM role activation works fine. Almost like they already have an existing OAuth token cached, that satisfies the ‘MFArule’ claim.

Example code:

$TenantId = "12345678897687876658768768"
$ClientId = "sdfdsfdsfgdsgdsgdsgdsgdsgdsgdsgdsgfdhgfjhgf"
$UserPrincipalName = "ExampleUserUPN"
Connect-MgGraph -TenantId $TenantId -ClientId $ClientId
$tmpRoleDef = Get-MgRoleManagementDirectoryRoleDefinition -Filter "DisplayName eq 'Exchange Administrator'" -ErrorAction Stop
$tmpUserId = Get-MgUser -UserId $UserPrincipalName -ErrorAction Stop
$TicketNumber = ""
$TicketSystem = ""
$Duration = 2
$tmpStartDateTime = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ")
$tmpDuration = "PT" + $Duration + "H"
$Justification = "Testing PowerShell Graph API PIM Role enablement"
$tmpParams = @{
            Action = "selfActivate"
            PrincipalId = "$($tmpUserId.Id)"
            RoleDefinitionId = "$($tmpRoleDef.Id)"
            DirectoryScopeId = "/"
            Justification = "$Justification"
            ScheduleInfo = @{
                  StartDateTime = $tmpStartDateTime
                  Expiration = @{
                        Type = "AfterDuration"
                        Duration = "$tmpDuration"
                  }
            }
            TicketInfo = @{
                  TicketNumber = "$TicketNumber"
                  TicketSystem = "$TicketSystem"
            }
      }

$tmpRoleActivate = New-MgRoleManagementDirectoryRoleAssignmentScheduleRequest -BodyParameter $tmpParams -ErrorAction Stop

Now, if we use the MSAL.PS module to generate our own OAuth token with the ‘MFA’ claim, then we are prompted to authenticate via MFA as expected. And we can pass the OAuth token to Connect-MgGraph via the -AccessToken parameter, and the PIM role enablement works as intended. So that is a good work-around, but of course it means that the Graph connection will stop working after 60 mins since our OAuth token will expire. And I couldn’t find a method to make the Connect-MgGraph cmdlet require MFA when getting an OAuth token, or to pass the "Require MFA" claim requirement.

Example code which works using MSAL.PS module to get our own OAuth token:

msalToken = Get-MSALToken -Scopes @(https://graph.microsoft.com/.default) -ClientId $ClientId -RedirectUri http://localhost -Authority https://login.microsoftonline.com/$TenantId -Interactive -ExtraQueryParameters @{claims='{"access_token" : {"amr": { "values": ["mfa"] }}}'} -LoginHint $UserPrincipalName

Connect-MgGraph -AccessToken (ConvertTo-SecureString -String $($msalToken.AccessToken) -AsPlainText -Force)

Many thanks!

stukey commented 1 year ago

Please note that I have also opened Microsoft Premier Support case # 2302140050000868 for this issue.

peombwa commented 1 year ago

Thanks for bringing this to our attention.

Can you please share a sanitized output of -Debug? The API should ideally fail with an MFA challenge (401-status code and return a WWW-Authenticate header). Our SDK will then handle the claims challenge and open a popup window when MFA is required. See https://learn.microsoft.com/en-us/azure/active-directory/develop/claims-challenge?tabs=dotnet#claims-challenge-header-format.

Are you able to use the command in v1.22.0? v2.x is still in preview, and we currently have a known issue related to how the auth provider handles CAE challenges - https://github.com/microsoftgraph/msgraph-sdk-powershell/issues/1741.

Connect-MgGraph does not support WIA. We only support the interactive browser and device code auth for delegated access.

stukey commented 1 year ago

Hi @peombwa

Here is the debug output from running the cmdlet to activate the PIM role via the MgGraph module. We’ve only just started using the Graph module and only have the v2.0.0 version installed because it supports the -ClientSecretCredential parameter which we require for another use case. I will install the v1.22 version, test and see if we can repo the issue. Unfortunately, it is difficult to test/repo this because as soon as the impacted admin has successfully completed an MFA authentication, the issue stops occurring. Do you know if there is a method to clear/reset any cached oauth tokens to try cause the issue again? We tried signing-out the user from all sessions in the M365 admin centre and forcing a change to the STSRefreshTokens but couldn't force a repo after a successful MFA authentication has already been completed. We are using CAE.

I will also test in Graph Explorer and get back to you.

Here's the debug output:

$tmpRoleActivate = New-MgRoleManagementDirectoryRoleAssignmentScheduleRequest -BodyParameter $tmpParams -ErrorAction Stop -Debug

DEBUG: [CmdletBeginProcessing]: - New-MgRoleManagementDirectoryRoleAssignmentScheduleRequest begin processing with parameterSet 'Create'. Confirm
Continue with this operation?

[Y] Yes  [A] Yes to All  [H] Halt Command  [S] Suspend  [?] Help (default is "Y"): A

DEBUG: [Authentication]: - AuthType: 'Delegated', TokenCredentialType: 'InteractiveBrowser', ContextScope: 'CurrentUser', AppName: 'XXXXX'.

DEBUG: [Authentication]: - Scopes: [AuditLog.Read.All, Device.Read.All, DeviceManagementServiceConfig.Read.All, Directory.Read.All, email, Group.Read.All, Group.ReadWrite.All, GroupMember.Read.All, openid,
Organization.Read.All, profile, Reports.Read.All, RoleAssignmentSchedule.ReadWrite.Directory, RoleEligibilitySchedule.Read.Directory, RoleManagement.Read.All, RoleManagement.Read.Directory, ServiceHealth.Read.All,
User.Read, User.Read.All, User.ReadWrite.All].Confirm

Are you sure you want to perform this action?

Performing the operation "New-MgRoleManagementDirectoryRoleAssignmentScheduleRequest_Create" on target "Call remote 'POST /roleManagement/directory/roleAssignmentScheduleRequests' operation".
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): A

DEBUG: ============================ HTTP REQUEST ============================HTTP Method:
POSTAbsolute Uri:
https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignmentScheduleRequestsHeaders:
SdkVersion                    : graph-powershell/2.0.0,Graph-dotnet-2.0.11
FeatureFlag                   : 00000047
Cache-Control                 : no-store, no-cache
User-Agent                    : Mozilla/5.0,(Windows NT 10.0; Microsoft Windows 10.0.19044; en-US),PowerShell/5.1.19041.2364
Accept-Encoding               : gzipBody:
{
  "action": "selfActivate",
  "directoryScopeId": "/",
  "justification": "Testing PowerShell Graph API PIM Role enablement",
  "principalId": "xxxxxxxxxxxxxxxxx",
  "roleDefinitionId": "xxxxxxxxxxxxx",
  "scheduleInfo": {
    "startDateTime": "2023-02-15T14:38:18.237Z",
    "expiration": {
      "duration": "PT4H",
      "type": "AfterDuration"
    }
  },
  "ticketInfo": {
    "ticketNumber": "",
    "ticketSystem": ""
  }
} DEBUG: ============================ HTTP RESPONSE ============================Status Code:
BadRequestHeaders:
Date                          : Wed, 15 Feb 2023 14:40:16 GMT
Transfer-Encoding             : chunked
Vary                          : Accept-Encoding
Strict-Transport-Security     : max-age=31536000
request-id                    : xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
client-request-id             : xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
x-ms-ags-diagnostic           : {"ServerInfo":{"DataCenter":"West US","Slice":"E","Ring":"4","ScaleUnit":"001","RoleInstance":"xxxxxxxxxxxxx"}}Body:
{
  "error": {
    "code": "RoleAssignmentRequestPolicyValidationFailed",
    "message": "The following policy rules failed: [\"MfaRule\"]",
    "innerError": {
      "date": "2023-02-15T14:40:17",
      "request-id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      "client-request-id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    }
  }
} New-MgRoleManagementDirectoryRoleAssignmentScheduleRequest : The following policy rules failed: ["MfaRule"]
At line:1 char:1
+ $tmpRoleActivate = New-MgRoleManagementDirectoryRoleAssignmentSchedul ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: ({ body = Micros...heduleRequest }:<>f__AnonymousType33`1) [New-MgRoleManag...eRequest_Create], Exception
    + FullyQualifiedErrorId : RoleAssignmentRequestPolicyValidationFailed,Microsoft.Graph.PowerShell.Cmdlets.NewMgRoleManagementDirectoryRoleAssignmentScheduleRequest_Create
peombwa commented 1 year ago

@stukey, thanks for the -Debug log!

Got it! Disconnect-MgGraph should clear the auth context, which in turn triggers MSAL to clear the cache on subsequent sign-in.

As per the debug log, the service is returning 400 bad requests instead of the expected 401 status code. The SDK's claims challenge handler will only retry request when the response status code is 401 and www-authenticate header is present. I'll follow up with the API owner to see if the response status code can be changed to 401 with a www-authenticate header when MFA is required as stated in https://learn.microsoft.com/en-us/azure/active-directory/develop/claims-challenge?tabs=dotnet#claims-challenge-header-format.

stukey commented 1 year ago

Thanks for the updates @peombwa. I'm working on getting you the Graph Explorer repo and testing with v1 of the PowerShell Graph SDK. Should have some updates early next week.

Note 'Disconnect-MgGraph' doesn't force a repo of the issue if you have successfully connected with MFA previously. The next time you connect to Graph, MFA is still not required/enforced but the PIM role activation works without issue. I haven't found a way to reset so that the issue can be repo'd at will. Luckily I still have two of my admins that have the issue and I can test with.

stukey commented 1 year ago

Hi @peombwa

I’ve finally been able to test the PIM role activation using Graph Explorer. When signing-in to our tenant in Graph Explorer, it does NOT prompt for MFA and as such the token doesn’t include the required MFA claim. Submitting the 'https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignmentScheduleRequests/' Graph API request via Graph Explorer fails with the same error as the PowerShell Graph SDK module. For example:

{
    "error": {
        "code": "RoleAssignmentRequestPolicyValidationFailed",
        "message": "The following policy rules failed: [\"MfaRule\"]",
        "innerError": {
            "date": "2023-02-28T15:34:55",
            "request-id": "XXXXXXX",
            "client-request-id": "XXXXXXX"
        }
    }
}

I am still working on testing using the v1 Graph PowerShell SDK module. I’ll report back as soon as I can.

stukey commented 1 year ago

Hi @peombwa

Any update on this issue? Many thanks

peombwa commented 1 year ago

@stukey, sorry for the delayed response. Thank you for confirming that the error is also present in Graph Explorer. This confirms my initial assessment:

As per the debug log, the service is returning 400 bad requests instead of the expected 401 status code. The SDK's claims challenge handler will only retry request when the response status code is 401 and www-authenticate header is present. I'll follow up with the API owner to see if the response status code can be changed to 401 with a www-authenticate header when MFA is required as stated in https://learn.microsoft.com/en-us/azure/active-directory/develop/claims-challenge?tabs=dotnet#claims-challenge-header-format.

I don’t have a specific timeline for when the API owner will fix the response status code. Please use the support case # 2302140050000868 to bring awareness to the issue. I’ll also follow up with the API owner internally to understand when the issue will be fixed.

uz-it commented 1 year ago

I can also reproduce the issue: Doing ForgetUser when promting for Authentification.

Disconnect-MgGraph -ErrorAction SilentlyContinue

Connect-MgGraph -Scopes "RoleManagement.ReadWrite.Directory" -ContextScope Process -ForceRefresh

$MgContext = Get-MgContext

$UserObjectId = (Get-MgUser -UserId $MgContext.Account).Id

$params = @{ "RoleDefinitionId" = "xxx-yyy-xxx-zzz-xxx" "PrincipalId" = $UserObjectId "Justification" = "Activated by Script" "DirectoryScopeId" = "/" "Action" = "SelfActivate" "ScheduleInfo" = @{ "StartDateTime" = Get-Date "Expiration" = @{ "Type" = "AfterDuration" "Duration" = "PT8H" } } }

New-MgRoleManagementDirectoryRoleAssignmentScheduleRequest -BodyParameter $params -Debug

Confirm Are you sure you want to perform this action? Performing the operation "New-MgRoleManagementDirectoryRoleAssignmentScheduleRequest_Create1" on target "Call remote 'RoleManagementDirectoryCreateRoleAssignmentScheduleRequests1' operation". [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"): y

` DEBUG: ============================ HTTP REQUEST ============================

HTTP Method: POST

Absolute Uri: https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignmentScheduleRequests

Headers:

Body: { "action": "SelfActivate", "directoryScopeId": "/", "justification": "Activated by Script", "principalId": "xxx-zzz-yyy-xxx-84e438xxx", "roleDefinitionId": "fxxabc-xxx-yyyyy-axx2-xxxyyy", "scheduleInfo": { "expiration": { "type": "AfterDuration", "duration": "PT8H" } } } ` Confirm Continue with this operation? [Y] Yes [A] Yes to All [H] Halt Command [S] Suspend [?] Help (default is "Y"): y

` DEBUG: ============================ HTTP RESPONSE ============================

Status Code: BadRequest

Headers: Transfer-Encoding : chunked Vary : Accept-Encoding Strict-Transport-Security : max-age=31536000 request-id : d7bda55e-9db2-4627-b30c-545879cc346f client-request-id : d7bda55e-9db2-4627-b30c-545879cc346f x-ms-ags-diagnostic : {"ServerInfo":{"DataCenter":"West Europe","Slice":"E","Ring":"5","ScaleUnit":"004","RoleInstance":"AM2PEPF0000BE68"}} Date : Wed, 10 May 2023 12:06:05 GMT

Body: { "error": { "code": "RoleAssignmentRequestPolicyValidationFailed", "message": "The following policy rules failed: [\"MfaRule\"]", "innerError": { "date": "2023-05-10T12:06:06", "request-id": "d7bda55e-9db2-4627-b30c-545879cc346f", "client-request-id": "d7bda55e-9db2-4627-b30c-545879cc346f" } } } `

I've NOT been asked for MFA while reproducing the issue.

aotongarcia commented 11 months ago

I am facing the same issue. Are there any updates on this?

DEBUG: ============================ HTTP RESPONSE ============================

Status Code:
BadRequest

Headers:
Transfer-Encoding             : chunked
Vary                          : Accept-Encoding
Strict-Transport-Security     : max-age=31536000
request-id                    : 066cb088-b398-4fdf-82fc-ba537430806a
client-request-id             : a48ee709-4265-483e-bf3d-7a622a44e337
x-ms-ags-diagnostic           : {"ServerInfo":{"DataCenter":"South Central US","Slice":"E","Ring":"5","ScaleUnit":"004","RoleInstance":"SA2PEPF000000F2"}}
Date                          : Tue, 03 Oct 2023 16:59:39 GMT

Body:
{
  "error": {
    "code": "RoleAssignmentRequestPolicyValidationFailed",
    "message": "The following policy rules failed: [\"MfaRule\"]",
    "innerError": {
      "date": "2023-10-03T16:59:40",
      "request-id": "066cb088-b398-4fdf-82fc-ba537430806a",
      "client-request-id": "a48ee709-4265-483e-bf3d-7a622a44e337"
    }
  }
}

@stukey did you get a response on your premier ticket?

stukey commented 11 months ago

Hi @aotongarcia. Unfortunately I am still experiencing the issue. Didn't get anywhere with Microsoft Premier Support. They asked me to submit a DCR (Design Change Request) and that was done six months ago. They did accept the DCR but I'm still waiting for the Microsoft Product group to fix the issue.

aotongarcia commented 11 months ago

@stukey I can't say I am surprised. I've submitted my own ticket. Thanks for providing a "work around", I'll see if I can implement it on my end.

Question for you, when you get your token using the MSAL.PS Module, are you doing an app based authentication or are you just using the Microsoft Graph app that gets created?

broonstar commented 9 months ago

So this is still an issue, right? I'm getting the "MfaRule" error when trying to run New-MgIdentityGovernancePrivilegedAccessGroupAssignmentScheduleRequest

`New-MgIdentityGovernancePrivilegedAccessGroupAssignmentScheduleRequest : The following policy rules failed: ["MfaRule"] Status: 400 (BadRequest) ErrorCode: RoleAssignmentRequestPolicyValidationFailed Date: 2023-12-14T06:15:57 Headers: Transfer-Encoding : chunked Vary : Accept-Encoding Strict-Transport-Security : max-age=31536000 request-id : 80b79860-ae72-4829-83a8-6634d6450eca client-request-id : 5378c2b5-8ff2-4f0e-8412-d7101a9989ae x-ms-ags-diagnostic : {"ServerInfo":{"DataCenter":"Australia East","Slice":"E","Ring":"5","ScaleUnit":"001","RoleInstance":"SY1PEPF00002279"}} Date : Thu, 14 Dec 2023 06:15:56 GMT At C:\General\AzureRBACcreateActiveGroupAssigment.ps1:18 char:3

stukey commented 9 months ago

Yep, still and issue and still not fixed by Microsoft. I have a support ticket and DCR open with Microsoft about this too and they are still not making any progress on a fix. It's very frustrating.

angrycuban13 commented 9 months ago

@broonstar are you using an Enterprise Application? If so, are you using Delegated or Application permissions?

broonstar commented 8 months ago

@broonstar are you using an Enterprise Application? If so, are you using Delegated or Application permissions?

No, I'm signing in with my own account, interactively.

cassdcgithub commented 7 months ago

Im also facing this issue :(

New-MgRoleManagementDirectoryRoleAssignmentScheduleRequest_Create: The following policy rules failed: ["MfaRule"] Status: 400 (BadRequest)

haydgsky commented 7 months ago

seem to have the same issue where users on the same host get different experiences using the same code

mark3grahams commented 4 months ago

Same for me as well. Has there been any progress? This is over a year old.

stukey commented 4 months ago

No updates and still not fixed. I've had a DCR open with Microsoft about this for over a year now. I ask for updates from our Microsoft CSAM every week and there's nothing. It's very frustrating.

mark3grahams commented 4 months ago

Not surprised. Fits with my experience.

Have you found any workarounds?

stukey commented 4 months ago

The only workaround we've found is to use the MSAL.PS module to generate our own oauth token with the MFA claim (see the bottom of my original post for an example) and then pass that to the Connect-MGGraph cmdlet. However, then the auth token isn't automatically refreshed, which isn't ideal. But usually if you do not that just once, then the MFA error doesn't occur for a couple of weeks.

mark3grahams commented 4 months ago

I am trying something like this. It seems to work so far, but I don't know how the refresh token is working or when I would need to re-MFA.

Write-Host 'Trying to connect using existing Refresh Token...' -ForegroundColor Yellow # Get token for MS Graph by prompting for MFA. '14d82eec-204b-4c2f-b7e8-296a70dab67e' is the app id for 'Microsoft Graph PowerShell SDK' # Get a new access token using the existing refresh token. $MsResponse = Get-MsalToken -ClientId '14d82eec-204b-4c2f-b7e8-296a70dab67e' -TenantId $TenantId -Silent -ForceRefresh -LoginHint $UPN -ErrorAction Stop $AccessTokenDetails = Get-JWTDetails -Token $MsResponse.AccessToken -ErrorAction Stop

# Check if the token has been elevated with MFA and if it has not expired. if (($AccessTokenDetails.amr -contains 'mfa') -and ($AccessTokenDetails.TimeToExpiry -gt 0)) { Write-Host 'Existing token is valid and was elevated with MFA. Connecting...' -ForegroundColor Green Connect-MgGraph -NoWelcome -AccessToken (ConvertTo-SecureString $MsResponse.AccessToken -AsPlainText -Force) -ErrorAction Stop } else { Write-Host 'MFA is required to elevate roles.' -ForegroundColor Red $MsResponse = Get-MsalToken -Scopes @('https://graph.microsoft.com/.default') -ClientId '14d82eec-204b-4c2f-b7e8-296a70dab67e' -RedirectUri http://localhost -Authority https://login.microsoftonline.com/$TenantId -Interactive -ExtraQueryParameters @{claims = '{"access_token" : {"amr": { "values": ["mfa"] }}}' } -ErrorAction Stop $AccessTokenDetails = Get-JWTDetails -Token $MsResponse.AccessToken -ErrorAction Stop

# Checking if the token has been elevated with MFA and if it has not expired. if (($AccessTokenDetails.amr -contains 'mfa') -and ($AccessTokenDetails.TimeToExpiry -gt 0)) { Connect-MgGraph -NoWelcome -AccessToken (ConvertTo-SecureString $MsResponse.AccessToken -AsPlainText -Force) -ErrorAction Stop } else { Throw 'Unable to get a token with MFA. This is required to elevate roles.' } }

Get-JWTDetails can be found at https://blog.darrenjrobinson.com/jwtdetails-powershell-module-for-decoding-jwt-access-tokens-with-readable-token-expiry-time/