Scenario Overview:

We recently encountered a situation where users were provisioned into OCI Identity Domains using the AD Bridge. During the provisioning process, the option to enable local authentication was selected in the Authentication Settings. Consequently, the users provisioned through this approach can authenticate into the OCI console using either their OCI IAM password or their Microsoft Active Directory password to access IAM-protected resources.

Issue Identified:

The problem the customer has with this setup is that it provisions all users as non-federated and assigns them a local password. To address this, we needed a method to update the federated user attribute for all affected users. To resolve this issue on a bulk set of users, we developed a sample script. This script allows us to search for users within a specified Identity Domain, check certain conditions for each user, and then modify the user’s federated status and console password capability based on user input. Below is the sample code:

import oci
import json
from oci.identity import IdentityClient
from oci.exceptions import ServiceError
import logging
import requests
from oci.signer import Signer
 
config = oci.config.from_file("./config")
 
auth = Signer(
   tenancy=config['tenancy'],
   user=config['user'],
   fingerprint=config['fingerprint'],
   private_key_file_location=config['key_file'],
   pass_phrase=config['pass_phrase']
   )
 
domain_url='https://idcs-xxxxxx.identity.oraclecloud.com' ## your test domain url
#domain_url = input("Please enter your the domain URL: ") #pass the domain url in the format: https://idcs-xxxxxxxxxxxx.identity.oraclecloud.com

identity_domains_client = oci.identity_domains.IdentityDomainsClient(config,domain_url)
 
users_list = [] # Initialize a list to hold user details
 
valTrue = True # Provide this for the capabilites that the user can have
valFalse = False # Provide this for the capabilites we want to disable for the user
uc_body = { "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"], # Here are the attributes that will be changed
           "Operations": [
              {"op": "replace",
               "path": "urn:ietf:params:scim:schemas:oracle:idcs:extension:user:User:isFederatedUser",
               "value": valTrue
               },
               {
                  "op": "replace",
                  "path": "urn:ietf:params:scim:schemas:oracle:idcs:extension:capabilities:User:canUseConsolePassword",
                  "value": valFalse
                  }
                  ]
                  }
 
def list_federatedusers_in_domain():
  try:
   
    list_users_response = identity_domains_client.list_users ()
 
    while True:
        users_list.extend(list_users_response.data.resources)
        if list_users_response.has_next_page:
           list_users_response = identity_domains_client.list_users(page=list_users_response.next_page)
        else:
           break
 
    for user in users_list:
       if user.urn_ietf_params_scim_schemas_oracle_idcs_extension_user_user.is_federated_user== False & user.urn_ietf_params_scim_schemas_oracle_idcs_extension_capabilities_user.canUseConsolePassword== True : # Filtering Users with Federated set to false, inaddition we can add an addtional condition for the filter user.urn_ietf_params_scim_schemas_oracle_idcs_extension_capabilities_user.canUseConsolePassword set to True
          print(f" Found Non-Federated Users " + user.user_name )
          user_input = input("Do we want to modify the Federated attribute for " + user.user_name + " to proceed say? (yes/no): ") # For testing purpose I have this script as interactive, once tested, we can run it against the domain.
          user_input = user_input.strip().lower()
          if user_input == "yes":
             uc_url = domain_url + '/admin/v1/Users/' + user.id
             uc_response = requests.patch(uc_url, json=uc_body, auth=auth)
             print (uc_response._content)
             print(f'Federated attribute and Local password have been modified for {user.user_name }')
          elif user_input == "no":
             print(f'Federated and Local password attribute have not been modified for {user.name.formatted}')
          else:
             print("Invalid input. Please enter 'yes' or 'no'.")
  except ServiceError as error:
    print(f"Error getting users: {error}")
    return []  # Return empty list on error   
 
list_federatedusers_in_domain()

Important Notes:

  • Sample Code Disclaimer: This script is provided as a sample. Please ensure thorough testing and modify the code as necessary to meet your specific requirements.

  • Domain URL Input: The domain URL can be passed as an input parameter or hardcoded directly into the script, as shown.

  • Authentication: The script uses a config file for authentication. This file contains the credentials needed to authenticate your script with OCI, including:

    • User OCID: Unique identifier for the OCI user.
    • Tenancy OCID: Unique identifier for the OCI tenancy.
    • Fingerprint: Fingerprint of the public key uploaded to OCI.
    • Private Key Path: Path to the private key file corresponding to the public key uploaded to OCI.
    • Region: The OCI region where your resources are located.

    Using a config file to manage credentials helps to keep sensitive information secure. This method avoids hardcoding credentials into the script, reducing security risks.

  • Script Functionality: This interactive script allows you to decide whether to modify each user’s attributes. Once tested, the interactive prompts can be removed or automated for batch processing. The script identifies and modifies specific user attributes related to federation and console password capabilities within OCI Identity Domains. It filters users who are non-federated (is_federated_user set to False) and who have the console password capability enabled (canUseConsolePassword set to True), targeting users set up incorrectly before applying updates.

    • isFederatedUser: Indicates whether the user is federated.
    • canUseConsolePassword: Indicates whether the user can use a console password.
  • Patch Operation: If the administrator chooses to update a user’s attributes, a PATCH request is sent to the Identity Domain using the requests.patch method. The user’s profile is updated according to the defined uc_body JSON structure.

While this is not the only approach we could take, this script offers a flexible and powerful tool for managing user attributes in Oracle Cloud Infrastructure Identity Domains. It simplifies the enforcement of security changes, making it particularly valuable for administrators who manage large numbers of users in OCI, especially in environments where federation and console password policies need to be consistently enforced or updated. By automating the identification of non-compliant users and providing an easy way to update their settings, the script helps maintain consistent security policies across the cloud environment.