Azure Active Directory Authentication Library for Python that provides OAuth2/OpenID Connect authentication flows and token management for accessing Azure AD protected resources
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Comprehensive logging system with PII scrubbing capabilities and custom exception handling for authentication errors. ADAL provides detailed logging for debugging authentication issues while protecting sensitive information.
Configure the ADAL logger with custom log levels and handlers. The logging system supports correlation IDs for request tracking and PII scrubbing for security.
def set_logging_options(options=None):
"""
Configure ADAL logger settings.
Parameters:
- options (dict, optional): Logging configuration with keys:
- 'level' (str): Log level ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL')
- 'handler' (logging.Handler): Custom log handler instance
If options is None, resets to default logging configuration.
"""Usage Examples:
import adal
import logging
# Basic logging to console
adal.set_logging_options({
'level': 'DEBUG'
})
# Log to file with custom handler
adal.set_logging_options({
'level': 'INFO',
'handler': logging.FileHandler('adal.log')
})
# Custom formatting
handler = logging.StreamHandler()
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
handler.setFormatter(formatter)
adal.set_logging_options({
'level': 'WARNING',
'handler': handler
})
# Reset to defaults
adal.set_logging_options()Retrieve the current logging configuration for inspection or backup.
def get_logging_options():
"""
Get current logging configuration.
Returns:
dict: Current logging options with 'level' key
"""Usage Example:
# Save current configuration
current_config = adal.get_logging_options()
print(f"Current log level: {current_config['level']}")
# Temporarily change logging
adal.set_logging_options({'level': 'DEBUG'})
# Do some debugging work
context = adal.AuthenticationContext('https://login.microsoftonline.com/tenant-id')
# ... authentication calls with detailed logging
# Restore original configuration
adal.set_logging_options(current_config)The standard logger name used by ADAL for all logging operations.
ADAL_LOGGER_NAME: str # Value: "adal-python"Usage Example:
import logging
import adal
# Get the ADAL logger directly
adal_logger = logging.getLogger(adal.ADAL_LOGGER_NAME)
# Add custom handler to ADAL logger
custom_handler = logging.FileHandler('custom_adal.log')
custom_handler.setLevel(logging.INFO)
adal_logger.addHandler(custom_handler)
# Configure formatter
formatter = logging.Formatter(
'%(asctime)s [%(correlation_id)s] %(levelname)s: %(message)s'
)
custom_handler.setFormatter(formatter)Custom exception class for ADAL-specific authentication and authorization errors. Provides detailed error information and optional response data.
class AdalError(Exception):
def __init__(self, error_msg, error_response=None):
"""
ADAL-specific exception for authentication errors.
Parameters:
- error_msg (str): Human-readable error message
- error_response (dict, optional): Detailed error response from Azure AD
Attributes:
- error_response (dict): Azure AD error response details (if available)
"""Usage Examples:
import adal
context = adal.AuthenticationContext('https://login.microsoftonline.com/tenant-id')
try:
token = context.acquire_token_with_client_credentials(
resource='https://management.azure.com/',
client_id='invalid-client-id',
client_secret='invalid-secret'
)
except adal.AdalError as e:
print(f"Authentication failed: {e}")
# Check for detailed error response
if e.error_response:
print(f"Error code: {e.error_response.get('error')}")
print(f"Error description: {e.error_response.get('error_description')}")
print(f"Correlation ID: {e.error_response.get('correlation_id')}")
print(f"Timestamp: {e.error_response.get('timestamp')}")Handle different types of authentication errors appropriately:
import adal
def robust_authentication():
context = adal.AuthenticationContext('https://login.microsoftonline.com/tenant-id')
try:
token = context.acquire_token_with_username_password(
resource='https://management.azure.com/',
username='user@tenant.com',
password='user-password',
client_id='your-client-id'
)
return token
except adal.AdalError as e:
error_msg = str(e).lower()
if 'invalid_client' in error_msg:
print("Error: Invalid client ID or client not configured properly")
elif 'invalid_grant' in error_msg:
print("Error: Invalid username/password or account disabled")
elif 'unauthorized_client' in error_msg:
print("Error: Client not authorized for this authentication flow")
elif 'invalid_resource' in error_msg:
print("Error: Invalid resource URI")
elif 'authority_not_found' in error_msg:
print("Error: Invalid tenant ID or authority URL")
elif 'network' in error_msg or 'timeout' in error_msg:
print("Error: Network connectivity issue")
else:
print(f"Unexpected authentication error: {e}")
# Log detailed error for debugging
if e.error_response:
print("Detailed error response:")
for key, value in e.error_response.items():
print(f" {key}: {value}")
return Noneimport adal
import logging
import sys
from datetime import datetime
class AdalLoggingSetup:
def __init__(self, log_level='INFO', log_to_file=False, filename=None):
self.log_level = log_level
self.log_to_file = log_to_file
self.filename = filename or f'adal_{datetime.now().strftime("%Y%m%d_%H%M%S")}.log'
self.setup_logging()
def setup_logging(self):
"""Configure comprehensive ADAL logging"""
# Create custom handler
if self.log_to_file:
handler = logging.FileHandler(self.filename)
else:
handler = logging.StreamHandler(sys.stdout)
# Set log level
handler.setLevel(getattr(logging, self.log_level.upper()))
# Create detailed formatter
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(funcName)s:%(lineno)d - %(message)s'
)
handler.setFormatter(formatter)
# Configure ADAL logging
adal.set_logging_options({
'level': self.log_level,
'handler': handler
})
print(f"ADAL logging configured: level={self.log_level}, file={self.filename if self.log_to_file else 'console'}")
def demo_with_logging():
# Setup comprehensive logging
logging_setup = AdalLoggingSetup(
log_level='DEBUG',
log_to_file=True,
filename='adal_debug.log'
)
# Create authentication context
authority = 'https://login.microsoftonline.com/your-tenant-id'
context = adal.AuthenticationContext(authority)
try:
# This will generate detailed debug logs
print("Attempting authentication...")
token = context.acquire_token_with_client_credentials(
resource='https://management.azure.com/',
client_id='your-client-id',
client_secret='your-client-secret'
)
print("Authentication successful!")
print(f"Token type: {token.get('tokenType')}")
print(f"Expires on: {token.get('expiresOn')}")
except adal.AdalError as e:
print(f"Authentication failed: {e}")
# Log error details
adal_logger = logging.getLogger(adal.ADAL_LOGGER_NAME)
adal_logger.error(f"Authentication error: {e}")
if e.error_response:
adal_logger.error(f"Error response: {e.error_response}")
# Show current logging configuration
config = adal.get_logging_options()
print(f"Final logging configuration: {config}")
if __name__ == '__main__':
demo_with_logging()ADAL automatically scrubs personally identifiable information (PII) from logs when PII logging is disabled (default). When creating an AuthenticationContext, you can control PII logging:
# PII scrubbing enabled (default)
context = adal.AuthenticationContext(
'https://login.microsoftonline.com/tenant-id',
enable_pii=False
)
# PII logging enabled (for debugging only)
context = adal.AuthenticationContext(
'https://login.microsoftonline.com/tenant-id',
enable_pii=True
)Important: Only enable PII logging in secure development environments. Never enable PII logging in production systems.
Install with Tessl CLI
npx tessl i tessl/pypi-adal