@@ -16,7 +16,7 @@ internal static class ConnectionStringParser
16
16
17
17
private const string ClientCertProperty = "clientCert" ;
18
18
19
- private const string ClientEndpointProperty = "ClientEndpoint " ;
19
+ private const string ClientEndpointProperty = "clientEndpoint " ;
20
20
21
21
private const string ClientIdProperty = "clientId" ;
22
22
@@ -35,58 +35,57 @@ internal static class ConnectionStringParser
35
35
36
36
private const string TenantIdProperty = "tenantId" ;
37
37
38
+ private const string TypeAzure = "azure" ;
39
+
40
+ private const string TypeAzureAD = "aad" ;
41
+
42
+ private const string TypeAzureApp = "azure.app" ;
43
+
44
+ private const string TypeAzureMsi = "azure.msi" ;
45
+
38
46
private const string ValidVersionRegex = "^" + SupportedVersion + @"\.\d+(?:[\w-.]+)?$" ;
39
47
40
48
private const string VersionProperty = "version" ;
41
49
42
- private static readonly string InvalidPortValue = $ "Invalid value for { PortProperty } property.";
50
+ private static readonly string InvalidClientEndpointProperty = $ "Invalid value for { ClientEndpointProperty } property, it must be a valid URI.";
51
+
52
+ private static readonly string InvalidEndpointProperty = $ "Invalid value for { EndpointProperty } property, it must be a valid URI.";
53
+
54
+ private static readonly string InvalidPortValue = $ "Invalid value for { PortProperty } property, it must be an positive integer between (0, 65536)";
43
55
44
56
private static readonly char [ ] KeyValueSeparator = { '=' } ;
45
57
46
58
private static readonly string MissingAccessKeyProperty =
47
59
$ "{ AccessKeyProperty } is required.";
48
60
61
+ private static readonly string MissingClientIdProperty =
62
+ $ "Connection string missing required properties { ClientIdProperty } .";
63
+
49
64
private static readonly string MissingClientSecretProperty =
50
65
$ "Connection string missing required properties { ClientSecretProperty } or { ClientCertProperty } .";
51
66
52
67
private static readonly string MissingEndpointProperty =
53
68
$ "Connection string missing required properties { EndpointProperty } .";
54
69
70
+ private static readonly string MissingTenantIdProperty =
71
+ $ "Connection string missing required properties { TenantIdProperty } .";
72
+
55
73
private static readonly char [ ] PropertySeparator = { ';' } ;
56
74
57
75
internal static ParsedConnectionString Parse ( string connectionString )
58
76
{
59
- var properties = connectionString . Split ( PropertySeparator , StringSplitOptions . RemoveEmptyEntries ) ;
60
- if ( properties . Length < 2 )
61
- {
62
- throw new ArgumentException ( MissingEndpointProperty , nameof ( connectionString ) ) ;
63
- }
64
-
65
- var dict = new Dictionary < string , string > ( StringComparer . OrdinalIgnoreCase ) ;
66
- foreach ( var property in properties )
67
- {
68
- var kvp = property . Split ( KeyValueSeparator , 2 ) ;
69
- if ( kvp . Length != 2 ) continue ;
70
-
71
- var key = kvp [ 0 ] . Trim ( ) ;
72
- if ( dict . ContainsKey ( key ) )
73
- {
74
- throw new ArgumentException ( $ "Duplicate properties found in connection string: { key } .") ;
75
- }
76
-
77
- dict . Add ( key , kvp [ 1 ] . Trim ( ) ) ;
78
- }
77
+ var dict = ToDictionary ( connectionString ) ;
79
78
80
79
// parse and validate endpoint.
81
80
if ( ! dict . TryGetValue ( EndpointProperty , out var endpoint ) )
82
81
{
83
- throw new ArgumentException ( MissingEndpointProperty , nameof ( connectionString ) ) ;
82
+ throw new ArgumentException ( MissingEndpointProperty , nameof ( endpoint ) ) ;
84
83
}
85
84
endpoint = endpoint . TrimEnd ( '/' ) ;
86
85
87
86
if ( ! TryGetEndpointUri ( endpoint , out var endpointUri ) )
88
87
{
89
- throw new ArgumentException ( $ "Endpoint property in connection string is not a valid URI: { dict [ EndpointProperty ] } ." ) ;
88
+ throw new ArgumentException ( InvalidEndpointProperty , nameof ( endpoint ) ) ;
90
89
}
91
90
var builder = new UriBuilder ( endpointUri ) ;
92
91
@@ -96,21 +95,21 @@ internal static ParsedConnectionString Parse(string connectionString)
96
95
{
97
96
if ( ! Regex . IsMatch ( v , ValidVersionRegex ) )
98
97
{
99
- throw new ArgumentException ( string . Format ( InvalidVersionValueFormat , v ) , nameof ( connectionString ) ) ;
98
+ throw new ArgumentException ( string . Format ( InvalidVersionValueFormat , v ) , nameof ( version ) ) ;
100
99
}
101
100
version = v ;
102
101
}
103
102
104
103
// parse and validate port.
105
104
if ( dict . TryGetValue ( PortProperty , out var s ) )
106
105
{
107
- if ( int . TryParse ( s , out var p ) && p > 0 && p <= 0xFFFF )
106
+ if ( int . TryParse ( s , out var port ) && port > 0 && port <= 0xFFFF )
108
107
{
109
- builder . Port = p ;
108
+ builder . Port = port ;
110
109
}
111
110
else
112
111
{
113
- throw new ArgumentException ( InvalidPortValue , nameof ( connectionString ) ) ;
112
+ throw new ArgumentException ( InvalidPortValue , nameof ( port ) ) ;
114
113
}
115
114
}
116
115
@@ -121,14 +120,18 @@ internal static ParsedConnectionString Parse(string connectionString)
121
120
{
122
121
if ( ! TryGetEndpointUri ( clientEndpoint , out clientEndpointUri ) )
123
122
{
124
- throw new ArgumentException ( $ " { ClientEndpointProperty } property in connection string is not a valid URI: { clientEndpoint } ." ) ;
123
+ throw new ArgumentException ( InvalidClientEndpointProperty , nameof ( clientEndpoint ) ) ;
125
124
}
126
125
}
127
126
127
+ // try building accesskey.
128
128
dict . TryGetValue ( AuthTypeProperty , out var type ) ;
129
129
var accessKey = type ? . ToLower ( ) switch
130
130
{
131
- "aad" => BuildAadAccessKey ( builder . Uri , dict ) ,
131
+ TypeAzureAD => BuildAadAccessKey ( builder . Uri , dict ) ,
132
+ TypeAzure => BuildAzureAccessKey ( builder . Uri , dict ) ,
133
+ TypeAzureApp => BuildAzureAppAccessKey ( builder . Uri , dict ) ,
134
+ TypeAzureMsi => BuildAzureMsiAccessKey ( builder . Uri , dict ) ,
132
135
_ => BuildAccessKey ( builder . Uri , dict ) ,
133
136
} ;
134
137
@@ -194,5 +197,70 @@ private static AccessKey BuildAccessKey(Uri uri, Dictionary<string, string> dict
194
197
}
195
198
throw new ArgumentException ( MissingAccessKeyProperty , AccessKeyProperty ) ;
196
199
}
200
+
201
+ private static AccessKey BuildAzureAccessKey ( Uri uri , Dictionary < string , string > dict )
202
+ {
203
+ return new AadAccessKey ( uri , new DefaultAzureCredential ( ) ) ;
204
+ }
205
+
206
+ private static AccessKey BuildAzureAppAccessKey ( Uri uri , Dictionary < string , string > dict )
207
+ {
208
+ if ( ! dict . TryGetValue ( ClientIdProperty , out var clientId ) )
209
+ {
210
+ throw new ArgumentException ( MissingClientIdProperty , ClientIdProperty ) ;
211
+ }
212
+
213
+ if ( ! dict . TryGetValue ( TenantIdProperty , out var tenantId ) )
214
+ {
215
+ throw new ArgumentException ( MissingTenantIdProperty , TenantIdProperty ) ;
216
+ }
217
+
218
+ if ( dict . TryGetValue ( ClientSecretProperty , out var clientSecret ) )
219
+ {
220
+ return new AadAccessKey ( uri , new ClientSecretCredential ( tenantId , clientId , clientSecret ) ) ;
221
+ }
222
+ else if ( dict . TryGetValue ( ClientCertProperty , out var clientCertPath ) )
223
+ {
224
+ return new AadAccessKey ( uri , new ClientCertificateCredential ( tenantId , clientId , clientCertPath ) ) ;
225
+ }
226
+ throw new ArgumentException ( MissingClientSecretProperty , ClientSecretProperty ) ;
227
+ }
228
+
229
+ private static AccessKey BuildAzureMsiAccessKey ( Uri uri , Dictionary < string , string > dict )
230
+ {
231
+ if ( dict . TryGetValue ( ClientIdProperty , out var clientId ) )
232
+ {
233
+ return new AadAccessKey ( uri , new ManagedIdentityCredential ( clientId ) ) ;
234
+ }
235
+ return new AadAccessKey ( uri , new ManagedIdentityCredential ( ) ) ;
236
+ }
237
+
238
+ private static Dictionary < string , string > ToDictionary ( string connectionString )
239
+ {
240
+ var properties = connectionString . Split ( PropertySeparator , StringSplitOptions . RemoveEmptyEntries ) ;
241
+ if ( properties . Length < 2 )
242
+ {
243
+ throw new ArgumentException ( MissingEndpointProperty , nameof ( connectionString ) ) ;
244
+ }
245
+
246
+ var dict = new Dictionary < string , string > ( StringComparer . OrdinalIgnoreCase ) ;
247
+ foreach ( var property in properties )
248
+ {
249
+ var kvp = property . Split ( KeyValueSeparator , 2 ) ;
250
+ if ( kvp . Length != 2 )
251
+ {
252
+ continue ;
253
+ }
254
+
255
+ var key = kvp [ 0 ] . Trim ( ) ;
256
+ if ( dict . ContainsKey ( key ) )
257
+ {
258
+ throw new ArgumentException ( $ "Duplicate properties found in connection string: { key } .") ;
259
+ }
260
+
261
+ dict . Add ( key , kvp [ 1 ] . Trim ( ) ) ;
262
+ }
263
+ return dict ;
264
+ }
197
265
}
198
266
}
0 commit comments