0
# Logging and Error Handling
1
2
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.
3
4
## Capabilities
5
6
### Logging Configuration
7
8
Configure the ADAL logger with custom log levels and handlers. The logging system supports correlation IDs for request tracking and PII scrubbing for security.
9
10
```python { .api }
11
def set_logging_options(options=None):
12
"""
13
Configure ADAL logger settings.
14
15
Parameters:
16
- options (dict, optional): Logging configuration with keys:
17
- 'level' (str): Log level ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL')
18
- 'handler' (logging.Handler): Custom log handler instance
19
20
If options is None, resets to default logging configuration.
21
"""
22
```
23
24
**Usage Examples:**
25
26
```python
27
import adal
28
import logging
29
30
# Basic logging to console
31
adal.set_logging_options({
32
'level': 'DEBUG'
33
})
34
35
# Log to file with custom handler
36
adal.set_logging_options({
37
'level': 'INFO',
38
'handler': logging.FileHandler('adal.log')
39
})
40
41
# Custom formatting
42
handler = logging.StreamHandler()
43
formatter = logging.Formatter(
44
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
45
)
46
handler.setFormatter(formatter)
47
48
adal.set_logging_options({
49
'level': 'WARNING',
50
'handler': handler
51
})
52
53
# Reset to defaults
54
adal.set_logging_options()
55
```
56
57
### Get Current Logging Configuration
58
59
Retrieve the current logging configuration for inspection or backup.
60
61
```python { .api }
62
def get_logging_options():
63
"""
64
Get current logging configuration.
65
66
Returns:
67
dict: Current logging options with 'level' key
68
"""
69
```
70
71
**Usage Example:**
72
73
```python
74
# Save current configuration
75
current_config = adal.get_logging_options()
76
print(f"Current log level: {current_config['level']}")
77
78
# Temporarily change logging
79
adal.set_logging_options({'level': 'DEBUG'})
80
81
# Do some debugging work
82
context = adal.AuthenticationContext('https://login.microsoftonline.com/tenant-id')
83
# ... authentication calls with detailed logging
84
85
# Restore original configuration
86
adal.set_logging_options(current_config)
87
```
88
89
### ADAL Logger Name Constant
90
91
The standard logger name used by ADAL for all logging operations.
92
93
```python { .api }
94
ADAL_LOGGER_NAME: str # Value: "adal-python"
95
```
96
97
**Usage Example:**
98
99
```python
100
import logging
101
import adal
102
103
# Get the ADAL logger directly
104
adal_logger = logging.getLogger(adal.ADAL_LOGGER_NAME)
105
106
# Add custom handler to ADAL logger
107
custom_handler = logging.FileHandler('custom_adal.log')
108
custom_handler.setLevel(logging.INFO)
109
adal_logger.addHandler(custom_handler)
110
111
# Configure formatter
112
formatter = logging.Formatter(
113
'%(asctime)s [%(correlation_id)s] %(levelname)s: %(message)s'
114
)
115
custom_handler.setFormatter(formatter)
116
```
117
118
## Error Handling
119
120
### AdalError Exception
121
122
Custom exception class for ADAL-specific authentication and authorization errors. Provides detailed error information and optional response data.
123
124
```python { .api }
125
class AdalError(Exception):
126
def __init__(self, error_msg, error_response=None):
127
"""
128
ADAL-specific exception for authentication errors.
129
130
Parameters:
131
- error_msg (str): Human-readable error message
132
- error_response (dict, optional): Detailed error response from Azure AD
133
134
Attributes:
135
- error_response (dict): Azure AD error response details (if available)
136
"""
137
```
138
139
**Usage Examples:**
140
141
```python
142
import adal
143
144
context = adal.AuthenticationContext('https://login.microsoftonline.com/tenant-id')
145
146
try:
147
token = context.acquire_token_with_client_credentials(
148
resource='https://management.azure.com/',
149
client_id='invalid-client-id',
150
client_secret='invalid-secret'
151
)
152
except adal.AdalError as e:
153
print(f"Authentication failed: {e}")
154
155
# Check for detailed error response
156
if e.error_response:
157
print(f"Error code: {e.error_response.get('error')}")
158
print(f"Error description: {e.error_response.get('error_description')}")
159
print(f"Correlation ID: {e.error_response.get('correlation_id')}")
160
print(f"Timestamp: {e.error_response.get('timestamp')}")
161
```
162
163
### Common Error Scenarios
164
165
Handle different types of authentication errors appropriately:
166
167
```python
168
import adal
169
170
def robust_authentication():
171
context = adal.AuthenticationContext('https://login.microsoftonline.com/tenant-id')
172
173
try:
174
token = context.acquire_token_with_username_password(
175
resource='https://management.azure.com/',
176
username='user@tenant.com',
177
password='user-password',
178
client_id='your-client-id'
179
)
180
return token
181
182
except adal.AdalError as e:
183
error_msg = str(e).lower()
184
185
if 'invalid_client' in error_msg:
186
print("Error: Invalid client ID or client not configured properly")
187
188
elif 'invalid_grant' in error_msg:
189
print("Error: Invalid username/password or account disabled")
190
191
elif 'unauthorized_client' in error_msg:
192
print("Error: Client not authorized for this authentication flow")
193
194
elif 'invalid_resource' in error_msg:
195
print("Error: Invalid resource URI")
196
197
elif 'authority_not_found' in error_msg:
198
print("Error: Invalid tenant ID or authority URL")
199
200
elif 'network' in error_msg or 'timeout' in error_msg:
201
print("Error: Network connectivity issue")
202
203
else:
204
print(f"Unexpected authentication error: {e}")
205
206
# Log detailed error for debugging
207
if e.error_response:
208
print("Detailed error response:")
209
for key, value in e.error_response.items():
210
print(f" {key}: {value}")
211
212
return None
213
```
214
215
## Complete Logging Example
216
217
```python
218
import adal
219
import logging
220
import sys
221
from datetime import datetime
222
223
class AdalLoggingSetup:
224
def __init__(self, log_level='INFO', log_to_file=False, filename=None):
225
self.log_level = log_level
226
self.log_to_file = log_to_file
227
self.filename = filename or f'adal_{datetime.now().strftime("%Y%m%d_%H%M%S")}.log'
228
self.setup_logging()
229
230
def setup_logging(self):
231
"""Configure comprehensive ADAL logging"""
232
233
# Create custom handler
234
if self.log_to_file:
235
handler = logging.FileHandler(self.filename)
236
else:
237
handler = logging.StreamHandler(sys.stdout)
238
239
# Set log level
240
handler.setLevel(getattr(logging, self.log_level.upper()))
241
242
# Create detailed formatter
243
formatter = logging.Formatter(
244
'%(asctime)s - %(name)s - %(levelname)s - %(funcName)s:%(lineno)d - %(message)s'
245
)
246
handler.setFormatter(formatter)
247
248
# Configure ADAL logging
249
adal.set_logging_options({
250
'level': self.log_level,
251
'handler': handler
252
})
253
254
print(f"ADAL logging configured: level={self.log_level}, file={self.filename if self.log_to_file else 'console'}")
255
256
def demo_with_logging():
257
# Setup comprehensive logging
258
logging_setup = AdalLoggingSetup(
259
log_level='DEBUG',
260
log_to_file=True,
261
filename='adal_debug.log'
262
)
263
264
# Create authentication context
265
authority = 'https://login.microsoftonline.com/your-tenant-id'
266
context = adal.AuthenticationContext(authority)
267
268
try:
269
# This will generate detailed debug logs
270
print("Attempting authentication...")
271
token = context.acquire_token_with_client_credentials(
272
resource='https://management.azure.com/',
273
client_id='your-client-id',
274
client_secret='your-client-secret'
275
)
276
277
print("Authentication successful!")
278
print(f"Token type: {token.get('tokenType')}")
279
print(f"Expires on: {token.get('expiresOn')}")
280
281
except adal.AdalError as e:
282
print(f"Authentication failed: {e}")
283
284
# Log error details
285
adal_logger = logging.getLogger(adal.ADAL_LOGGER_NAME)
286
adal_logger.error(f"Authentication error: {e}")
287
288
if e.error_response:
289
adal_logger.error(f"Error response: {e.error_response}")
290
291
# Show current logging configuration
292
config = adal.get_logging_options()
293
print(f"Final logging configuration: {config}")
294
295
if __name__ == '__main__':
296
demo_with_logging()
297
```
298
299
## PII Protection
300
301
ADAL automatically scrubs personally identifiable information (PII) from logs when PII logging is disabled (default). When creating an AuthenticationContext, you can control PII logging:
302
303
```python
304
# PII scrubbing enabled (default)
305
context = adal.AuthenticationContext(
306
'https://login.microsoftonline.com/tenant-id',
307
enable_pii=False
308
)
309
310
# PII logging enabled (for debugging only)
311
context = adal.AuthenticationContext(
312
'https://login.microsoftonline.com/tenant-id',
313
enable_pii=True
314
)
315
```
316
317
**Important**: Only enable PII logging in secure development environments. Never enable PII logging in production systems.
318
319
## Best Practices
320
321
1. **Use appropriate log levels**: DEBUG for development, INFO for production monitoring
322
2. **Secure log files**: Ensure log files have appropriate permissions and are stored securely
323
3. **Rotate logs**: Implement log rotation to prevent disk space issues
324
4. **Monitor errors**: Set up alerts for authentication failures in production
325
5. **Correlation IDs**: Use correlation IDs to track requests across systems
326
6. **PII protection**: Keep PII scrubbing enabled in production environments