Block User Cannot Change Password

I'm attempting to rework this KB a little bit:

https://support.oneidentity.com/kb/320795/how-to-enforce-a-specific-value-for-user-must-change-password-at-next-logon-when-using-the-active-roles-web-interface

Original code

function onPreModify($Request)
 
{
    if ($Request.class -ne "user"){ return }
    if ($Request.Attributes.Attributes["edsaPassword"])
    {
        $Request.Put("edsvaUserMustChangePasswordAtNextLogon", $true) #Alternatively, use $false if desired
    }
}
Should I be able to change "edsvaUserMustChangePasswordAtNextLogon" to be "edsaUserCannotChangePassword" ?
Like so:
{
    if ($Request.class -ne "user"){ return }
    if ($Request.Attributes.Attributes["edsaPassword"])
    {
        $Request.Put("edsaUserCannotChangePassword", $false) 
    }
}
This tries using an access template to accomplish limiting access to the password options. But I'm only looking to block UserCannotChangePassword and leave UserMustChangePasswordAtNextLogon available. I tried applying it to only UserCannotChangePassword, but I could still set it to $true.
I also tried using a straight-up property generation and validation policy to force edsaUserCannotChangePassword to always be $false. That didn't stop me from setting it to $true either.
I removed the option from web interface but some of our craftier admins have learned how to use the quest cmdlets and realized they can set UserCannotChangePassword to $true to kind of exempt some accounts from our password policies. Ideally, I'd like an "Administrative Policy Error:  Setting edsaUserCannotChangePassword  to $True defies corporate policy"  Like you get when you set property validation on a normal attribute. 
  • Neither of these worked either:

    I guess useraccountcontrol and edsaUserCannotChangePassword are just too weird to function like normal attributes. 

    function IsAttributeModified($Request, $attrName)
    {
    $prop = $Request.GetPropertyItem($attrName, $Constants.ADSTYPE_CASE_IGNORE_STRING)
    if ($prop -eq $null) { return $false }
    if ($prop.ControlCode -eq $null -OR $prop.ControlCode -eq 0) { return $false }
    return $true
    }
    function onPostModify($Request)
    {
    if($Request.Class -ne "user"){return}
    if ((IsAttributeModified $Request "edsaUserCannotChangePassword") -eq $false){return}
    $Request.Put("edsaUserCannotChangePassword", $false) 
    }

    function IsAttributeModified($Request, $attrName)
    {
    $prop = $Request.GetPropertyItem($attrName, $Constants.ADSTYPE_CASE_IGNORE_STRING)
    if ($prop -eq $null) { return $false }
    if ($prop.ControlCode -eq $null -OR $prop.ControlCode -eq 0) { return $false }
    return $true
    }
    function onPostModify($Request)
    {
    if($Request.Class -ne "user"){return}
    if ((IsAttributeModified $Request "edsaUserCannotChangePassword") -eq $false){return}
    connect-qadservice -proxy localhost
    set-qaduser $Request.GUID -objectattributes @{edsaUserCannotChangePassword=$False}
    }

  • So here's the thing, if you look at the object Change History, it does say that edsaUserCannotChangePassword is getting modified as is the NTSecurityDescriptor.

    I would think that this should work:

    # Check and see if the Cannot Change Password flag is being chenged

    # Note that IsAttributeModified is only telling you if the attribute is being changed and NOT what it is being changed to

    If ((IsAttributeModified $Request "edsaUserCannotChangePassword") -eq $false){return}

    # Check if the property is being set to TRUE, if it is then set it to FALSE

    If ($Request.Get("edsaUserCannotChangePassword") -eq $true)
    {
    $Request.Put("edsaUserCannotChangePassword", $false) 
    }

    As an aside, this use case can also be dealt with in a codeless fashion using a Change Workflow:

    1) Start condition Detects a change to the property edsaUserCannotChangePassword
    2) Uses an Update Activity to force the property value to FALSE

    If you want to prevent native changes to this property (i.e. performed via ADUC), you would need to modify your policy script to watch for changes to the relevant UserAccountControl bit which is somewhat more complicated.


  • Good ole workflows!!!

    That worked so perfectly!

    When I check the box in the console and hit apply I can see it clear. Boom! Done. 

    Thank you!