Skip to content

Commit edc796f

Browse files
authored
Merge pull request #5 from deveel/authentication-refactoring
Authentication refactoring
2 parents 1dae15d + 00918bd commit edc796f

24 files changed

Lines changed: 2386 additions & 1056 deletions
Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
# Enhanced Channel Schema Authentication Configuration
2+
3+
This document demonstrates the new enhanced authentication configuration system for Channel Schemas, which allows precise mapping of connection settings fields to authentication requirements.
4+
5+
## Overview
6+
7+
The new authentication configuration system provides:
8+
9+
- **Explicit Field Mapping**: Specify exactly which connection settings parameters are required for each authentication method
10+
- **Flexible Authentication**: Support multiple alternative field names for the same logical credential
11+
- **Provider-Specific Authentication**: Define custom authentication patterns that match provider APIs
12+
- **Backward Compatibility**: Legacy `AuthenticationType` enum-based validation still works
13+
14+
## Key Classes
15+
16+
### AuthenticationConfiguration
17+
Defines authentication requirements with explicit field mappings:
18+
19+
```csharp
20+
var twilioAuth = new AuthenticationConfiguration(AuthenticationType.Basic, "Twilio Authentication")
21+
.WithRequiredField("AccountSid", DataType.String, field =>
22+
{
23+
field.DisplayName = "Account SID";
24+
field.Description = "Twilio Account SID (acts as username)";
25+
field.AuthenticationRole = "Username";
26+
})
27+
.WithRequiredField("AuthToken", DataType.String, field =>
28+
{
29+
field.DisplayName = "Auth Token";
30+
field.Description = "Twilio Auth Token (acts as password)";
31+
field.AuthenticationRole = "Password";
32+
field.IsSensitive = true;
33+
});
34+
```
35+
36+
### AuthenticationField
37+
Represents a single authentication field with validation:
38+
39+
```csharp
40+
var apiKeyField = new AuthenticationField("ApiKey", DataType.String)
41+
{
42+
DisplayName = "API Key",
43+
Description = "The API key for authentication",
44+
AuthenticationRole = "ApiKey",
45+
IsSensitive = true,
46+
AllowedValues = null // Any value allowed
47+
};
48+
```
49+
50+
### FlexibleAuthenticationConfiguration
51+
Supports "any one of" validation for multiple alternative field names:
52+
53+
```csharp
54+
var flexibleApiKey = new FlexibleAuthenticationConfiguration(AuthenticationType.ApiKey, "Flexible API Key")
55+
.WithOptionalField("ApiKey", DataType.String)
56+
.WithOptionalField("Key", DataType.String)
57+
.WithOptionalField("AccessKey", DataType.String);
58+
// Only one of these fields needs to be present
59+
```
60+
61+
## Usage Examples
62+
63+
### 1. Twilio SMS Channel with Custom Authentication
64+
65+
```csharp
66+
var twilioSmsSchema = new ChannelSchema("Twilio", "SMS", "1.0.0")
67+
.WithDisplayName("Twilio SMS Connector")
68+
.WithCapabilities(ChannelCapability.SendMessages | ChannelCapability.ReceiveMessages)
69+
70+
// Use predefined Twilio authentication configuration
71+
.AddAuthenticationConfiguration(AuthenticationConfigurations.TwilioBasicAuthentication())
72+
73+
// Define required parameters
74+
.AddRequiredParameter("AccountSid", DataType.String)
75+
.AddRequiredParameter("AuthToken", DataType.String, true) // sensitive
76+
.AddParameter("FromNumber", DataType.String, param => param.IsRequired = true)
77+
78+
.AddContentType(MessageContentType.PlainText)
79+
.HandlesMessageEndpoint(EndpointType.PhoneNumber);
80+
81+
// Validation will now check for AccountSid/AuthToken specifically, not generic username/password
82+
var connectionSettings = new ConnectionSettings()
83+
.SetParameter("AccountSid", "AC123456789")
84+
.SetParameter("AuthToken", "token123")
85+
.SetParameter("FromNumber", "+1234567890");
86+
87+
var validationResults = twilioSmsSchema.ValidateConnectionSettings(connectionSettings);
88+
// Returns empty - validation passes
89+
```
90+
91+
### 2. Multi-Authentication Provider
92+
93+
```csharp
94+
var flexibleApiSchema = new ChannelSchema("FlexibleAPI", "API", "1.0.0")
95+
.WithDisplayName("Flexible API Connector")
96+
97+
// Support multiple authentication methods
98+
.AddAuthenticationConfiguration(AuthenticationConfigurations.BasicAuthentication())
99+
.AddAuthenticationConfiguration(AuthenticationConfigurations.FlexibleApiKeyAuthentication("ApiKey", "Key", "AccessKey"))
100+
.AddAuthenticationConfiguration(AuthenticationConfigurations.TokenAuthentication("BearerToken"))
101+
102+
.AddParameter("BaseUrl", DataType.String, param => param.IsRequired = true);
103+
104+
// Any of these connection settings would pass validation:
105+
106+
// Option 1: Basic Authentication
107+
var basicAuth = new ConnectionSettings()
108+
.SetParameter("Username", "user123")
109+
.SetParameter("Password", "pass456")
110+
.SetParameter("BaseUrl", "https://api.example.com");
111+
112+
// Option 2: API Key Authentication (any of the key names)
113+
var apiKeyAuth = new ConnectionSettings()
114+
.SetParameter("AccessKey", "ak_123456789")
115+
.SetParameter("BaseUrl", "https://api.example.com");
116+
117+
// Option 3: Token Authentication
118+
var tokenAuth = new ConnectionSettings()
119+
.SetParameter("BearerToken", "eyJhbGciOiJIUzI1...")
120+
.SetParameter("BaseUrl", "https://api.example.com");
121+
```
122+
123+
### 3. Custom Multi-Tenant Authentication
124+
125+
```csharp
126+
// Define custom authentication fields
127+
var tenantIdField = new AuthenticationField("TenantId", DataType.String)
128+
{
129+
DisplayName = "Tenant ID",
130+
Description = "The tenant identifier for multi-tenant authentication",
131+
AuthenticationRole = "TenantId"
132+
};
133+
134+
var apiSecretField = new AuthenticationField("ApiSecret", DataType.String)
135+
{
136+
DisplayName = "API Secret",
137+
Description = "The secret key for the tenant",
138+
AuthenticationRole = "Secret",
139+
IsSensitive = true
140+
};
141+
142+
var regionField = new AuthenticationField("Region", DataType.String)
143+
{
144+
DisplayName = "Region",
145+
Description = "The deployment region (optional)",
146+
AuthenticationRole = "Region",
147+
AllowedValues = new object[] { "us-east-1", "us-west-2", "eu-west-1" }
148+
};
149+
150+
// Create custom authentication configuration
151+
var multiTenantAuth = AuthenticationConfigurations.CustomAuthentication(
152+
"Multi-Tenant Authentication",
153+
requiredFields: new[] { tenantIdField, apiSecretField },
154+
optionalFields: new[] { regionField }
155+
);
156+
157+
var multiTenantSchema = new ChannelSchema("MultiTenant", "API", "1.0.0")
158+
.AddAuthenticationConfiguration(multiTenantAuth);
159+
160+
// Validation requires TenantId and ApiSecret, allows Region
161+
var settings = new ConnectionSettings()
162+
.SetParameter("TenantId", "tenant123")
163+
.SetParameter("ApiSecret", "secret456")
164+
.SetParameter("Region", "us-east-1"); // Optional but validated if present
165+
166+
var results = multiTenantSchema.ValidateConnectionSettings(settings);
167+
// Passes validation
168+
```
169+
170+
### 4. Advanced Certificate Authentication
171+
172+
```csharp
173+
var certificateSchema = new ChannelSchema("SecureAPI", "API", "1.0.0")
174+
.AddAuthenticationConfiguration(AuthenticationConfigurations.FlexibleCertificateAuthentication());
175+
176+
// Multiple ways to provide certificate authentication:
177+
178+
// Option 1: Certificate thumbprint
179+
var thumbprintAuth = new ConnectionSettings()
180+
.SetParameter("CertificateThumbprint", "1234567890ABCDEF");
181+
182+
// Option 2: PFX file with password
183+
var pfxAuth = new ConnectionSettings()
184+
.SetParameter("PfxFile", "/path/to/cert.pfx")
185+
.SetParameter("PfxPassword", "password123");
186+
187+
// Option 3: Certificate data
188+
var certDataAuth = new ConnectionSettings()
189+
.SetParameter("Certificate", "-----BEGIN CERTIFICATE-----...");
190+
191+
// All would pass validation because FlexibleCertificateAuthentication
192+
// accepts any one of the certificate-related fields
193+
```
194+
195+
## Migration from Legacy Authentication
196+
197+
### Before (Legacy Approach)
198+
```csharp
199+
var oldSchema = new ChannelSchema("Provider", "API", "1.0.0")
200+
.AddAuthenticationType(AuthenticationType.Basic); // Generic validation
201+
202+
// Validation was based on hardcoded field name assumptions
203+
// - For Basic: looked for Username/Password OR AccountSid/AuthToken OR various other combinations
204+
// - Not provider-specific
205+
// - No control over which fields are actually required
206+
```
207+
208+
### After (New Approach)
209+
```csharp
210+
var newSchema = new ChannelSchema("Provider", "API", "1.0.0")
211+
.AddAuthenticationConfiguration(AuthenticationConfigurations.CustomBasicAuthentication(
212+
"ApiUsername", "ApiPassword", "Custom Basic Authentication"));
213+
214+
// Validation is now explicit and provider-specific
215+
// - Exactly specifies which fields are required
216+
// - Provides clear error messages
217+
// - Supports custom field names
218+
```
219+
220+
## Backward Compatibility
221+
222+
The new system maintains full backward compatibility:
223+
224+
```csharp
225+
// This still works exactly as before
226+
var legacySchema = new ChannelSchema("Provider", "API", "1.0.0")
227+
.AddAuthenticationType(AuthenticationType.Basic);
228+
229+
// Validation falls back to legacy hardcoded field name checking
230+
var legacySettings = new ConnectionSettings()
231+
.SetParameter("Username", "user")
232+
.SetParameter("Password", "pass");
233+
234+
var results = legacySchema.ValidateConnectionSettings(legacySettings);
235+
// Still passes validation using legacy logic
236+
```
237+
238+
## Benefits
239+
240+
1. **Provider Specificity**: Define exactly which fields your provider requires
241+
2. **Clear Error Messages**: Authentication errors specify the exact required fields
242+
3. **Flexible Validation**: Support multiple alternative field names for the same credential
243+
4. **Documentation**: Field descriptions and roles provide clear guidance
244+
5. **Type Safety**: Field validation includes data type checking
245+
6. **Security Awareness**: Mark sensitive fields appropriately
246+
7. **Extensibility**: Easy to add new authentication patterns
247+
248+
## Predefined Authentication Configurations
249+
250+
The `AuthenticationConfigurations` static class provides these factory methods:
251+
252+
- `BasicAuthentication()` - Standard username/password
253+
- `TwilioBasicAuthentication()` - AccountSid/AuthToken
254+
- `CustomBasicAuthentication(username, password)` - Custom field names
255+
- `ApiKeyAuthentication(keyField)` - Single API key field
256+
- `FlexibleApiKeyAuthentication(possibleFields...)` - Multiple alternative key fields
257+
- `TokenAuthentication(tokenField)` - Single token field
258+
- `FlexibleTokenAuthentication(possibleFields...)` - Multiple alternative token fields
259+
- `ClientCredentialsAuthentication()` - ClientId/ClientSecret
260+
- `CertificateAuthentication()` - Single certificate field
261+
- `FlexibleCertificateAuthentication()` - Multiple certificate options
262+
- `CustomAuthentication()` - Fully custom field definitions
263+
264+
This enhancement provides the precision and flexibility needed to accurately represent real-world authentication requirements while maintaining the simplicity of the existing API.

0 commit comments

Comments
 (0)