mirror of
https://github.com/bitwarden/directory-connector
synced 2025-12-05 23:53:21 +00:00
6.5 KiB
6.5 KiB
Bitwarden Directory Connector
Project Overview
Directory Connector is a TypeScript application that synchronizes users and groups from directory services to Bitwarden organizations. It provides both a desktop GUI (built with Angular and Electron) and a CLI tool (bwdc).
Supported Directory Services:
- LDAP (Lightweight Directory Access Protocol) - includes Active Directory and general LDAP servers
- Microsoft Entra ID (formerly Azure Active Directory)
- Google Workspace
- Okta
- OneLogin
Technologies:
- TypeScript
- Angular (GUI)
- Electron (Desktop wrapper)
- Node
- Jest for testing
Code Architecture & Structure
Directory Organization
src/
├── abstractions/ # Interface definitions (e.g., IDirectoryService)
├── services/ # Business logic implementations for directory services, sync, auth
├── models/ # Data models (UserEntry, GroupEntry, etc.)
├── commands/ # CLI command implementations
├── app/ # Angular GUI components
└── utils/ # Test utilities and fixtures
src-cli/ # CLI-specific code (imports common code from src/)
jslib/ # Legacy folder structure (mix of deprecated/unused and current code - new code should not be added here)
Key Architectural Patterns
- Abstractions = Interfaces: All interfaces are defined in
/abstractions - Services = Business Logic: Implementations live in
/services - Directory Service Pattern: Each directory provider implements
IDirectoryServiceinterface - Separation of Concerns: GUI (Angular app) and CLI (commands) share the same service layer
Development Conventions
Code Organization
File Naming:
- kebab-case for files:
ldap-directory.service.ts - Descriptive names that reflect purpose
Class/Function Naming:
- PascalCase for classes and interfaces
- camelCase for functions and variables
- Descriptive names that indicate purpose
File Structure:
- Keep files focused on single responsibility
- Create new service files for distinct directory integrations
- Separate models into individual files when complex
TypeScript Conventions
Import Patterns:
- Use path aliases (
@/) for project imports@/- project root@/jslib/- jslib folder
- ESLint enforces alphabetized import ordering with newlines between groups
Type Safety:
- Avoid
anytypes - use proper typing orunknownwith type guards - Prefer interfaces for contracts, types for unions/intersections
- Use strict null checks - handle
nullandundefinedexplicitly - Leverage TypeScript's type inference where appropriate
Configuration:
- Use configuration files or environment variables
- Never hardcode URLs or configuration values
Security Best Practices
Credential Handling:
- Never log directory service credentials, API keys, or tokens
- Use secure storage mechanisms for sensitive data
- Credentials should never be hardcoded
- Store credentials encrypted, never in plain text
Sensitive Data:
- User and group data from directories should be handled securely
- Avoid exposing sensitive information in error messages
- Sanitize data before logging
- Be cautious with data persistence
Input Validation:
- Validate and sanitize data from external directory services
- Check for injection vulnerabilities (LDAP injection, etc.)
- Validate configuration inputs from users
API Security:
- Ensure authentication flows are implemented correctly
- Verify SSL/TLS is used for all external connections
- Check for secure token storage and refresh mechanisms
Error Handling
Best Practices:
- Try-catch for async operations - Always wrap external API calls
- Meaningful error messages - Provide context for debugging
- Error propagation - Don't swallow errors silently
- User-facing errors - Separate user messages from developer logs
Performance Best Practices
Large Dataset Handling:
- Use pagination for large user/group lists
- Avoid loading entire datasets into memory at once
- Consider streaming or batch processing for large operations
API Rate Limiting:
- Respect rate limits for Microsoft Graph API, Google Admin SDK, etc.
- Consider batching large API calls where necessary
Memory Management:
- Close connections and clean up resources
- Remove event listeners when components are destroyed
- Be cautious with caching large datasets
Testing
Framework:
- Jest with jest-preset-angular
- jest-mock-extended for type-safe mocks with
mock<Type>()
Test Organization:
- Tests colocated with source files
*.spec.ts- Unit tests for individual components/services*.integration.spec.ts- Integration tests against live directory services- Test helpers located in
utils/directory
Test Naming:
- Descriptive, human-readable test names
- Example:
'should return empty array when no users exist in directory'
Test Coverage:
- New features must include tests
- Bug fixes should include regression tests
- Changes to core sync logic or directory specific logic require integration tests
Testing Approach:
- Unit tests: Mock external API calls using jest-mock-extended
- Integration tests: Use live directory services (Docker containers or configured cloud services)
- Focus on critical paths (authentication, sync, data transformation)
- Test error scenarios and edge cases (empty results, malformed data, connection failures), not just happy paths
Directory Service Patterns
IDirectoryService Interface
All directory services implement this core interface with methods:
getUsers()- Retrieve users from directory and transform them into standard objectsgetGroups()- Retrieve groups from directory and transform them into standard objects- Connection and authentication handling
Service-Specific Implementations
Each directory service has unique authentication and query patterns:
- LDAP: Direct LDAP queries, bind authentication
- Microsoft Entra ID: Microsoft Graph API, OAuth tokens
- Google Workspace: Google Admin SDK, service account credentials
- Okta/OneLogin: REST APIs with API tokens