@@ -11,69 +11,81 @@ namespace Microsoft.Azure.SignalR
11
11
internal static class ConnectionStringParser
12
12
{
13
13
private const string AccessKeyProperty = "accesskey" ;
14
+
14
15
private const string AuthTypeProperty = "authtype" ;
16
+
15
17
private const string ClientCertProperty = "clientCert" ;
16
- private const string ClientEndpointProperty = "ClientEndpoint" ;
18
+
19
+ private const string ClientEndpointProperty = "clientEndpoint" ;
20
+
17
21
private const string ClientIdProperty = "clientId" ;
22
+
18
23
private const string ClientSecretProperty = "clientSecret" ;
24
+
19
25
private const string EndpointProperty = "endpoint" ;
20
- private const string ServerEndpoint = "ServerEndpoint" ;
26
+
21
27
private const string InvalidVersionValueFormat = "Version {0} is not supported." ;
28
+
22
29
private const string PortProperty = "port" ;
30
+
31
+ private const string ServerEndpoint = "ServerEndpoint" ;
32
+
23
33
// For SDK 1.x, only support Azure SignalR Service 1.x
24
34
private const string SupportedVersion = "1" ;
25
35
26
36
private const string TenantIdProperty = "tenantId" ;
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
+
27
46
private const string ValidVersionRegex = "^" + SupportedVersion + @"\.\d+(?:[\w-.]+)?$" ;
47
+
28
48
private const string VersionProperty = "version" ;
29
- private static readonly string InvalidPortValue = $ "Invalid value for { PortProperty } property.";
49
+
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)";
30
55
31
56
private static readonly char [ ] KeyValueSeparator = { '=' } ;
32
57
33
58
private static readonly string MissingAccessKeyProperty =
34
59
$ "{ AccessKeyProperty } is required.";
35
60
61
+ private static readonly string MissingClientIdProperty =
62
+ $ "Connection string missing required properties { ClientIdProperty } .";
63
+
36
64
private static readonly string MissingClientSecretProperty =
37
65
$ "Connection string missing required properties { ClientSecretProperty } or { ClientCertProperty } .";
38
66
39
67
private static readonly string MissingEndpointProperty =
40
68
$ "Connection string missing required properties { EndpointProperty } .";
41
69
70
+ private static readonly string MissingTenantIdProperty =
71
+ $ "Connection string missing required properties { TenantIdProperty } .";
72
+
42
73
private static readonly char [ ] PropertySeparator = { ';' } ;
43
74
44
75
internal static ParsedConnectionString Parse ( string connectionString )
45
76
{
46
- var properties = connectionString . Split ( PropertySeparator , StringSplitOptions . RemoveEmptyEntries ) ;
47
- if ( properties . Length < 2 )
48
- {
49
- throw new ArgumentException ( MissingEndpointProperty , nameof ( connectionString ) ) ;
50
- }
51
-
52
- var dict = new Dictionary < string , string > ( StringComparer . OrdinalIgnoreCase ) ;
53
- foreach ( var property in properties )
54
- {
55
- var kvp = property . Split ( KeyValueSeparator , 2 ) ;
56
- if ( kvp . Length != 2 ) continue ;
57
-
58
- var key = kvp [ 0 ] . Trim ( ) ;
59
- if ( dict . ContainsKey ( key ) )
60
- {
61
- throw new ArgumentException ( $ "Duplicate properties found in connection string: { key } .") ;
62
- }
63
-
64
- dict . Add ( key , kvp [ 1 ] . Trim ( ) ) ;
65
- }
77
+ var dict = ToDictionary ( connectionString ) ;
66
78
67
79
// parse and validate endpoint.
68
80
if ( ! dict . TryGetValue ( EndpointProperty , out var endpoint ) )
69
81
{
70
- throw new ArgumentException ( MissingEndpointProperty , nameof ( connectionString ) ) ;
82
+ throw new ArgumentException ( MissingEndpointProperty , nameof ( endpoint ) ) ;
71
83
}
72
84
endpoint = endpoint . TrimEnd ( '/' ) ;
73
85
74
86
if ( ! TryGetEndpointUri ( endpoint , out var endpointUri ) )
75
87
{
76
- throw new ArgumentException ( $ "Endpoint property in connection string is not a valid URI: { dict [ EndpointProperty ] } ." ) ;
88
+ throw new ArgumentException ( InvalidEndpointProperty , nameof ( endpoint ) ) ;
77
89
}
78
90
var builder = new UriBuilder ( endpointUri ) ;
79
91
@@ -83,38 +95,43 @@ internal static ParsedConnectionString Parse(string connectionString)
83
95
{
84
96
if ( ! Regex . IsMatch ( v , ValidVersionRegex ) )
85
97
{
86
- throw new ArgumentException ( string . Format ( InvalidVersionValueFormat , v ) , nameof ( connectionString ) ) ;
98
+ throw new ArgumentException ( string . Format ( InvalidVersionValueFormat , v ) , nameof ( version ) ) ;
87
99
}
88
100
version = v ;
89
101
}
90
102
91
103
// parse and validate port.
92
104
if ( dict . TryGetValue ( PortProperty , out var s ) )
93
105
{
94
- if ( int . TryParse ( s , out var p ) && p > 0 && p <= 0xFFFF )
106
+ if ( int . TryParse ( s , out var port ) && port > 0 && port <= 0xFFFF )
95
107
{
96
- builder . Port = p ;
108
+ builder . Port = port ;
97
109
}
98
110
else
99
111
{
100
- throw new ArgumentException ( InvalidPortValue , nameof ( connectionString ) ) ;
112
+ throw new ArgumentException ( InvalidPortValue , nameof ( port ) ) ;
101
113
}
102
114
}
103
115
104
116
Uri clientEndpointUri = null ;
117
+
105
118
// parse and validate clientEndpoint.
106
119
if ( dict . TryGetValue ( ClientEndpointProperty , out var clientEndpoint ) )
107
120
{
108
121
if ( ! TryGetEndpointUri ( clientEndpoint , out clientEndpointUri ) )
109
122
{
110
- throw new ArgumentException ( $ " { ClientEndpointProperty } property in connection string is not a valid URI: { clientEndpoint } ." ) ;
123
+ throw new ArgumentException ( InvalidClientEndpointProperty , nameof ( clientEndpoint ) ) ;
111
124
}
112
125
}
113
126
127
+ // try building accesskey.
114
128
dict . TryGetValue ( AuthTypeProperty , out var type ) ;
115
129
var accessKey = type ? . ToLower ( ) switch
116
130
{
117
- "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 ) ,
118
135
_ => BuildAccessKey ( builder . Uri , dict ) ,
119
136
} ;
120
137
@@ -180,5 +197,70 @@ private static AccessKey BuildAccessKey(Uri uri, Dictionary<string, string> dict
180
197
}
181
198
throw new ArgumentException ( MissingAccessKeyProperty , AccessKeyProperty ) ;
182
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
+ }
183
265
}
184
266
}
0 commit comments