Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
OAuth2Environment.cs
1using System;
2using System.IO;
4using System.Security.Cryptography.X509Certificates;
5using System.Threading.Tasks;
6using Waher.Content;
7using Waher.Events;
11using Waher.Security;
13
15{
19 public class OAuth2Environment : IDisposable
20 {
21 private static readonly RandomNumberGenerator rnd = RandomNumberGenerator.Create();
22
23 private OAuthAuthorizeResource? authorizeResource = null;
24 private OAuthTokenResource? tokenResource = null;
25 private OAuthRegistrationResource? registrationResource = null;
26 private OAuthManagementResource? managementResource = null;
27 private OAuthDeviceAuthorizationResource? deviceAuthorizationResource = null;
28 private OAuthIntrospectionResource? introspectionResource = null;
29 private AuthorizationServerMetaData? serverMetaDataResource = null;
30 private ProtectedResourceMetaData? resourceMetaData = null;
31 private IUserSource? userSource = null;
32 private IDynamicUserSource? dynamicUserSource = null;
33 private IThingRegistryUserSource? thingRegistryUserSource = null;
34 private JwtFactory? jwtFactory;
35 private event EventHandlerAsync<CustomizeMarkdownEventArgs>? customizeLoginForm;
36 private event EventHandlerAsync<CustomizeMarkdownEventArgs>? customizeDeviceLoginForm;
37 private event EventHandlerAsync<CustomizeMarkdownEventArgs>? customizeDeviceLoginReceipt;
38 private string? loginMasterFileName;
39 private string? realm;
40 private int minStrength;
41 private bool encrypted;
42 private bool locked = false;
43 private bool disposed = false;
44
49 {
51 UserSource = Security.Users.Users.Source; // Default users source
52
53 this.Register(UserSource);
54 }
55
59 public bool Disposed => this.disposed;
60
64 public void Dispose()
65 {
66 this.disposed = true;
67 }
68
72 public bool HasAuthorizeResource => !(this.authorizeResource is null);
73
77 public bool HasTokenResource => !(this.tokenResource is null);
78
82 public bool HasRegistrationResource => !(this.registrationResource is null);
83
87 public bool HasManagementResource => !(this.managementResource is null);
88
92 public bool HasDeviceAuthorizationResource => !(this.deviceAuthorizationResource is null);
93
97 public bool HasIntrospectionResource => !(this.introspectionResource is null);
98
102 public bool HasServerMetaDataResource => !(this.serverMetaDataResource is null);
103
107 public bool HasResourceMetaData => !(this.resourceMetaData is null);
108
112 public bool HasUserSource => !(this.userSource is null);
113
117 public bool HasDynamicUserSource => !(this.dynamicUserSource is null);
118
122 public bool HasThingRegistryUserSource => !(this.thingRegistryUserSource is null);
123
127 public bool HasLoginMasterFileName => !string.IsNullOrEmpty(this.loginMasterFileName);
128
133 {
134 get
135 {
136 if (this.authorizeResource is null)
137 throw new InvalidOperationException("No authorize resource has been registered.");
138
139 return this.authorizeResource;
140 }
141 }
142
147 {
148 get
149 {
150 if (this.tokenResource is null)
151 throw new InvalidOperationException("No token resource has been registered.");
152
153 return this.tokenResource;
154 }
155 }
156
161 {
162 get
163 {
164 if (this.registrationResource is null)
165 throw new InvalidOperationException("No registration resource has been registered.");
166
167 return this.registrationResource;
168 }
169 }
170
175 {
176 get
177 {
178 if (this.managementResource is null)
179 throw new InvalidOperationException("No management resource has been registered.");
180
181 return this.managementResource;
182 }
183 }
184
189 {
190 get
191 {
192 if (this.deviceAuthorizationResource is null)
193 throw new InvalidOperationException("No device authorization resource has been registered.");
194
195 return this.deviceAuthorizationResource;
196 }
197 }
198
203 {
204 get
205 {
206 if (this.introspectionResource is null)
207 throw new InvalidOperationException("No introspection resource has been registered.");
208
209 return this.introspectionResource;
210 }
211 }
212
217 {
218 get
219 {
220 if (this.serverMetaDataResource is null)
221 throw new InvalidOperationException("No server meta-data resource has been registered.");
222
223 return this.serverMetaDataResource;
224 }
225 }
226
231 {
232 get
233 {
234 if (this.resourceMetaData is null)
235 throw new InvalidOperationException("No resource meta-data resource has been registered.");
236
237 return this.resourceMetaData;
238 }
239 }
240
245 {
246 get
247 {
248 if (this.userSource is null)
249 throw new InvalidOperationException("No user source has been registered.");
250
251 return this.userSource;
252 }
253 }
254
259 {
260 get
261 {
262 if (this.dynamicUserSource is null)
263 throw new InvalidOperationException("No dynamic user source has been registered.");
264
265 return this.dynamicUserSource;
266 }
267 }
268
273 {
274 get
275 {
276 if (this.thingRegistryUserSource is null)
277 throw new InvalidOperationException("No thing registry user source has been registered.");
278
279 return this.thingRegistryUserSource;
280 }
281 }
282
287 {
288 get
289 {
290 if (this.jwtFactory is null)
291 {
294 {
295 this.jwtFactory = JwtFactory;
296 }
297 else
298 this.jwtFactory = JwtFactory.CreateHmacSha256(this.realm);
299 }
300
301 return this.jwtFactory;
302 }
303 }
304
308 public string? LoginMasterFileName
309 {
310 get => this.loginMasterFileName;
311 set
312 {
313 this.AssertUnlocked();
314
315 if (!string.IsNullOrEmpty(value) && !File.Exists(value))
316 throw new FileNotFoundException("Login master file not found.", value);
317
318 this.loginMasterFileName = value;
319 }
320 }
321
325 public bool Locked => this.locked;
326
330 public string? Realm
331 {
332 get
333 {
334 this.CheckDomainParameters();
335 return this.realm;
336 }
337 }
338
342 public int MinStrength
343 {
344 get
345 {
346 this.CheckDomainParameters();
347 return this.minStrength;
348 }
349 }
350
354 public bool Encrypted
355 {
356 get
357 {
358 this.CheckDomainParameters();
359 return this.encrypted;
360 }
361 }
362
363 private void AssertUnlocked()
364 {
365 if (this.locked)
366 throw new UnauthorizedAccessException("OAUTH 2 environment is locked and cannot be modified.");
367 }
368
372 public void Lock()
373 {
374 this.AssertUnlocked();
375 this.locked = true;
376 }
377
383 {
384 this.AssertUnlocked();
385 this.authorizeResource = AuthorizeResource;
386 }
387
393 {
394 this.AssertUnlocked();
395 this.tokenResource = TokenResource;
396 }
397
403 {
404 this.AssertUnlocked();
405 this.registrationResource = RegistrationResource;
406 }
407
413 {
414 this.AssertUnlocked();
415 this.managementResource = ManagementResource;
416 }
417
423 {
424 this.AssertUnlocked();
425 this.deviceAuthorizationResource = DeviceAuthorizationResource;
426 }
427
433 {
434 this.AssertUnlocked();
435 this.introspectionResource = IntrospectionResource;
436 }
437
443 {
444 this.AssertUnlocked();
445 this.serverMetaDataResource = ServerMetaDataResource;
446 }
447
453 {
454 this.AssertUnlocked();
455 this.resourceMetaData = ResourceMetaData;
456 }
457
463 {
464 this.AssertUnlocked();
465 this.userSource = UserSource;
466 this.dynamicUserSource = UserSource as IDynamicUserSource;
467 this.thingRegistryUserSource = UserSource as IThingRegistryUserSource;
468 }
469
475 {
476 this.AssertUnlocked();
477 this.jwtFactory = JwtFactory;
478 }
479
486 public void Register(string Realm, int MinStrength, bool Encrypted)
487 {
488 this.AssertUnlocked();
489 this.realm = Realm;
490 this.minStrength = MinStrength;
491 this.encrypted = Encrypted;
492 }
493
494 private void CheckDomainParameters()
495 {
496 if (this.realm is null)
497 {
498 GetDomainParameters(out string? Domain, out int MinStrength, out bool Encrypted);
499 this.realm = Domain;
500 this.minStrength = MinStrength;
501 this.encrypted = Encrypted;
502 }
503 }
504
511 public static void GetDomainParameters(out string? Domain, out int MinStrength,
512 out bool Encrypted)
513 {
514 if (!Types.TryGetModuleParameter("X509", out object Obj) ||
515 !(Obj is X509Certificate Certificate))
516 {
517 if (Types.TryGetModuleParameter("Realm", out Obj) &&
518 Obj is string Realm)
519 {
520 Domain = Realm;
521 }
522 else
523 Domain = null;
524
525 Encrypted = false;
526 MinStrength = 0;
527 }
528 else
529 {
530 Encrypted = true;
531 Domain = BinaryTcpClient.GetDomainFromSubject(Certificate.Subject);
532 MinStrength = 128;
533 }
534 }
535
541 public static string GenerateRandomCode(int NrBytes)
542 {
543 byte[] Bin = new byte[NrBytes];
544
545 lock (rnd)
546 {
547 rnd.GetBytes(Bin);
548 }
549
550 return Base64Url.Encode(Bin);
551 }
552
556 public event EventHandlerAsync<CustomizeMarkdownEventArgs>? CustomizeLoginForm
557 {
558 add
559 {
560 this.AssertUnlocked();
561 this.customizeLoginForm += value;
562 }
563 remove
564 {
565 this.AssertUnlocked();
566 this.customizeLoginForm -= value;
567 }
568 }
569
576 public async Task<string> RaiseCustomizeLoginForm(string Markdown)
577 {
578 if (this.customizeLoginForm is null)
579 return Markdown;
580
582 await this.customizeLoginForm.Raise(this, e);
583 return e.Markdown;
584 }
585
589 public event EventHandlerAsync<CustomizeMarkdownEventArgs>? CustomizeDeviceLoginForm
590 {
591 add
592 {
593 this.AssertUnlocked();
594 this.customizeDeviceLoginForm += value;
595 }
596 remove
597 {
598 this.AssertUnlocked();
599 this.customizeDeviceLoginForm -= value;
600 }
601 }
602
609 public async Task<string> RaiseCustomizeDeviceLoginForm(string Markdown)
610 {
611 if (this.customizeDeviceLoginForm is null)
612 return Markdown;
613
615 await this.customizeDeviceLoginForm.Raise(this, e);
616 return e.Markdown;
617 }
618
622 public event EventHandlerAsync<CustomizeMarkdownEventArgs>? CustomizeDeviceLoginReceipt
623 {
624 add
625 {
626 this.AssertUnlocked();
627 this.customizeDeviceLoginReceipt += value;
628 }
629 remove
630 {
631 this.AssertUnlocked();
632 this.customizeDeviceLoginReceipt -= value;
633 }
634 }
635
642 public async Task<string> RaiseCustomizeDeviceLoginReceipt(string Markdown)
643 {
644 if (this.customizeDeviceLoginReceipt is null)
645 return Markdown;
646
648 await this.customizeDeviceLoginReceipt.Raise(this, e);
649 return e.Markdown;
650 }
651 }
652}
Static class that does BASE64URL encoding (using URL and filename safe alphabet), as defined in RFC46...
Definition: Base64Url.cs:11
static string Encode(byte[] Data)
Converts a binary block of data to a Base64URL-encoded string.
Definition: Base64Url.cs:48
Implements a binary TCP Client, by encapsulating a TcpClient. It also makes the use of TcpClient safe...
static string GetDomainFromSubject(string Subject)
Extracts the domain name from a certificate subject string.
Provides OAUTH authorization server meta-data, as defined in RFC 8414. https://datatracker....
Event arguments for markdown customization events.
bool HasIntrospectionResource
If the environment has a registered introspection resource
EventHandlerAsync< CustomizeMarkdownEventArgs >? CustomizeDeviceLoginReceipt
Event raised when the device login receipt is to be customized.
EventHandlerAsync< CustomizeMarkdownEventArgs >? CustomizeLoginForm
Event raised when the login form is to be customized.
bool HasResourceMetaData
If the environment has a registered resource meta-data resource
EventHandlerAsync< CustomizeMarkdownEventArgs >? CustomizeDeviceLoginForm
Event raised when the device login form is to be customized.
void Register(ProtectedResourceMetaData? ResourceMetaData)
Registers a resource meta-data resource.
OAuthIntrospectionResource IntrospectionResource
Registered introspection resource
OAuthDeviceAuthorizationResource DeviceAuthorizationResource
Registered device authorization resource
bool HasUserSource
If the environment has a registered user source
bool HasAuthorizeResource
If the environment has a registered authorization resource
static void GetDomainParameters(out string? Domain, out int MinStrength, out bool Encrypted)
Gets domain parameters, based on module parameters defined in the system.
async Task< string > RaiseCustomizeDeviceLoginForm(string Markdown)
Raises the CustomizeDeviceLoginForm event to customize a device login form before being returned to t...
OAuthAuthorizeResource AuthorizeResource
Registered authorization resource
bool Encrypted
If TLS-encryption is enabled.
IUserSource UserSource
Registered user source
bool HasManagementResource
If the environment has a registered client management resource
void Register(OAuthIntrospectionResource? IntrospectionResource)
Registers an introspection resource.
OAuthRegistrationResource RegistrationResource
Registered registration resource
bool HasDynamicUserSource
If the environment has a registered dynamic user source
bool Locked
If the environment has been locked.
OAuthTokenResource TokenResource
Registered token resource
void Register(OAuthAuthorizeResource? AuthorizeResource)
Registers an authorization resource.
bool HasRegistrationResource
If the environment has a registered registration resource
void Register(OAuthDeviceAuthorizationResource? DeviceAuthorizationResource)
Registers a device authorization resource.
ProtectedResourceMetaData ResourceMetaData
Registered resource meta-data resource
OAuth2Environment()
Manages the OAuth 2.0 environment.
void Register(AuthorizationServerMetaData? ServerMetaDataResource)
Registers a server meta-data resource.
void Register(OAuthManagementResource? ManagementResource)
Registers a management resource.
AuthorizationServerMetaData ServerMetaDataResource
Registered server meta-data resource
IDynamicUserSource DynamicUserSource
Registered dynamic user source
static string GenerateRandomCode(int NrBytes)
Generates a random unique code.
void Register(OAuthRegistrationResource? RegistrationResource)
Registers a registration resource.
bool HasDeviceAuthorizationResource
If the environment has a registered device authorization resource
bool Disposed
If the object has been disposed.
void Register(string Realm, int MinStrength, bool Encrypted)
Registers domain parameters such as realm, minimum strength and encryption.
string? LoginMasterFileName
File name to master file to use in generated login pages.
JwtFactory JwtFactory
Registered JWT factory
void Register(JwtFactory JwtFactory)
Registers a JWT factory.
bool HasThingRegistryUserSource
If the environment has a registered thing registry user source
bool HasLoginMasterFileName
If a login master file name has been registered
int MinStrength
Minimum strength of ciphers used in encryption.
bool HasServerMetaDataResource
If the environment has a registered server meta-data resource
void Register(OAuthTokenResource? TokenResource)
Registers a token resource.
void Lock()
Locks the OAUTH 2 environment.
async Task< string > RaiseCustomizeDeviceLoginReceipt(string Markdown)
Raises the CustomizeDeviceLoginReceipt event to customize a device login receipt before being returne...
void Register(IUserSource? UserSource)
Registers a user source.
bool HasTokenResource
If the environment has a registered token resource
IThingRegistryUserSource ThingRegistryUserSource
Registered thing registry user source
async Task< string > RaiseCustomizeLoginForm(string Markdown)
Raises the CustomizeLoginForm event to customize a login form before being returned to the client.
OAuthManagementResource ManagementResource
Registered registration resource
OAUTH authorize resource, as defined in RFC 6749. https://datatracker.ietf.org/doc/html/rfc6749
OAUTH device authorization resource, as defined in RFC 8628. https://datatracker.ietf....
OAUTH introspection resource, as defined in RFCs 7662. https://datatracker.ietf.org/doc/html/rfc7662
OAUTH client management resource, as defined in RFCs 7591. https://datatracker.ietf....
OAUTH dynamic registration resource, as defined in RFCs 7591 and 7592. https://datatracker....
OAUTH token resource, as defined in RFC 6749. https://datatracker.ietf.org/doc/html/rfc6749
Provides OAUTH resource meta-data, as defined in RFC 9728. https://datatracker.ietf....
Static class that dynamically manages types and interfaces available in the runtime environment.
Definition: Types.cs:15
static bool TryGetModuleParameter(string Name, out object Value)
Tries to get a module parameter value.
Definition: Types.cs:607
A factory that can create and validate JWT tokens.
Definition: JwtFactory.cs:66
bool Disposed
If the factory has been disposed.
Definition: JwtFactory.cs:272
static JwtFactory CreateHmacSha256()
Creates a JWT factory that can create and validate JWT tokens using the HMAC-SHA256 algorithm.
Definition: JwtFactory.cs:123
A dynamic user source, supporting registering new users.
A Thing Registry user source, supporting management of devices, with information about ownership.
Interface for data sources containing users.
Definition: IUserSource.cs:9