SCIM Cross domain Identity Management
System for Cross-domain Identity Management (SCIM) is an open standard that enables the automatic provisioning, management, and deprovisioning of users and groups across different systems. SCIM is particularly useful in environments where applications need to manage large volumes of user identities, such as in cloud-based services or SaaS applications. By using SCIM, organizations can automate user account management, improving consistency, security, and reducing manual work.
SCIM uses RESTful APIs and JSON to represent user identities and allows applications to manage resources such as users, groups, and their attributes.
Specifications and Technical Overview¶
Key Concepts of SCIM¶
- User: The primary resource in SCIM, representing an individual with attributes such as
userName
,email
,phoneNumber
, etc. - Group: A collection of users, often representing roles, departments, or access groups within a system.
- Provisioning: The process of creating, updating, or deleting user accounts on the target system using SCIM APIs.
- Identity Provider (IdP): The system responsible for managing users and providing their identity information, such as Okta, Azure AD, or any SCIM-compliant IdP.
- Service Provider: The system or application that consumes the SCIM data and provisions users, such as a SaaS platform or cloud service.
SCIM Workflow¶
- Provisioning Request: The identity provider sends a request to the service provider to create, update, or delete user accounts or groups.
- User Synchronization: The service provider processes the request and updates its internal system to reflect the changes (e.g., adding new users, updating attributes, or removing users).
- Group Management: SCIM also supports managing groups of users, enabling the assignment of users to roles or teams.
SCIM API Endpoints¶
- GET /Users: Fetches a list of users.
- POST /Users: Creates a new user.
- PUT /Users/{id}: Updates an existing user.
- PATCH /Users/{id}: Modifies a subset of a user’s attributes.
- DELETE /Users/{id}: Deletes a user.
- GET /Groups: Fetches a list of groups.
- POST /Groups: Creates a new group.
- PUT /Groups/{id}: Updates an existing group.
- DELETE /Groups/{id}: Deletes a group.
Python Ecosystem for SCIM¶
Python provides several libraries and frameworks that allow you to implement SCIM-compliant services. While SCIM-specific libraries are less common compared to OAuth or OIDC libraries, SCIM can be implemented using generic libraries like Flask
, FastAPI
, or Django
combined with tools like requests
for HTTP requests. You can also build custom SCIM clients and servers using Python’s robust ecosystem.
Example SCIM Client in Python¶
Here’s an example of how to interact with a SCIM API using Python and the requests
library.
Prerequisites¶
-
Install the
requests
library:
bash pip install requests
-
Use an SCIM-compliant identity provider or service provider (e.g., Okta, Azure AD, or a custom SCIM server).
Example: SCIM Client in Python¶
import requests
import json
SCIM_BASE_URL = "https://your-scim-provider.com/scim/v2"
SCIM_API_TOKEN = "your-api-token"
HEADERS = {
"Authorization": f"Bearer {SCIM_API_TOKEN}",
"Content-Type": "application/scim+json"
}
# Fetch a list of users
def get_users():
url = f"{SCIM_BASE_URL}/Users"
response = requests.get(url, headers=HEADERS)
if response.status_code == 200:
return response.json()
else:
raise Exception(f"Error fetching users: {response.status_code}, {response.text}")
# Create a new user
def create_user(user_data):
url = f"{SCIM_BASE_URL}/Users"
response = requests.post(url, headers=HEADERS, data=json.dumps(user_data))
if response.status_code == 201:
return response.json()
else:
raise Exception(f"Error creating user: {response.status_code}, {response.text}")
# Update an existing user
def update_user(user_id, user_data):
url = f"{SCIM_BASE_URL}/Users/{user_id}"
response = requests.put(url, headers=HEADERS, data=json.dumps(user_data))
if response.status_code == 200:
return response.json()
else:
raise Exception(f"Error updating user: {response.status_code}, {response.text}")
# Delete a user
def delete_user(user_id):
url = f"{SCIM_BASE_URL}/Users/{user_id}"
response = requests.delete(url, headers=HEADERS)
if response.status_code == 204:
print("User deleted successfully")
else:
raise Exception(f"Error deleting user: {response.status_code}, {response.text}")
# Example usage
if __name__ == "__main__":
# Fetch all users
users = get_users()
print(users)
# Create a new user
new_user = {
"userName": "jdoe",
"name": {
"givenName": "John",
"familyName": "Doe"
},
"emails": [
{"value": "jdoe@example.com", "primary": True}
]
}
created_user = create_user(new_user)
print(created_user)
# Update a user
updated_data = {
"name": {
"givenName": "Johnathan"
}
}
updated_user = update_user(created_user['id'], updated_data)
print(updated_user)
# Delete the user
delete_user(created_user['id'])
Flask Example: Building a SCIM Server¶
In this example, we create a simple SCIM server using Flask to handle basic SCIM operations like creating and retrieving users.
Prerequisites¶
- Install Flask:
bash pip install Flask
Flask SCIM Server Example¶
from flask import Flask, request, jsonify
app = Flask(__name__)
# In-memory data store (not suitable for production)
users = {}
# SCIM endpoint to create a new user
@app.route('/scim/v2/Users', methods=['POST'])
def create_user():
user_data = request.json
user_id = len(users) + 1
user_data['id'] = user_id
users[user_id] = user_data
return jsonify(user_data), 201
# SCIM endpoint to fetch all users
@app.route('/scim/v2/Users', methods=['GET'])
def list_users():
return jsonify(list(users.values())), 200
# SCIM endpoint to retrieve a user by ID
@app.route('/scim/v2/Users/<int:user_id>', methods=['GET'])
def get_user(user_id):
user = users.get(user_id)
if user:
return jsonify(user), 200
return jsonify({'error': 'User not found'}), 404
# SCIM endpoint to update a user by ID
@app.route('/scim/v2/Users/<int:user_id>', methods=['PUT'])
def update_user(user_id):
user = users.get(user_id)
if user:
users[user_id].update(request.json)
return jsonify(users[user_id]), 200
return jsonify({'error': 'User not found'}), 404
# SCIM endpoint to delete a user by ID
@app.route('/scim/v2/Users/<int:user_id>', methods=['DELETE'])
def delete_user(user_id):
if user_id in users:
del users[user_id]
return '', 204
return jsonify({'error': 'User not found'}), 404
if __name__ == '__main__':
app.run(debug=True)
Use Cases for SCIM in Python¶
-
User Provisioning in SaaS: SCIM is widely used to automate user provisioning and management across SaaS platforms. For example, when a user is created in an organization’s identity provider, SCIM can automatically provision that user across all associated applications (e.g., Google Workspace, Salesforce, etc.).
-
User Deprovisioning: SCIM also handles deprovisioning (i.e., removing access or deleting users when they leave an organization), which is essential for maintaining security and access control.
-
Role and Group Management: SCIM can manage roles and groups of users, assigning different permissions or access levels based on group membership.
Best Practices and Considerations¶
- Secure API Access: SCIM APIs should be protected with strong authentication mechanisms like OAuth 2.0 to prevent unauthorized access.
- Data Validation: Ensure proper validation of user data, such as email formats and required attributes, before creating or updating users.
- Error Handling: SCIM defines a clear set of error response codes (e.g.,
404
for not found,400
for bad request). Ensure your SCIM server or client handles errors according to the SCIM specification. - Pagination and Filtering: SCIM supports pagination and filtering for retrieving large lists of users or groups. Implementing these features improves scalability.
References¶
- SCIM 2.0 Specification: https://tools.ietf.org/html/rfc7644
- SCIM Overview: https://scim.cloud/
- Flask demo: https://github.com/oktadev/okta-scim-flask-example
Page last modified: 2024-09-25 08:35:47