Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
AgentResource.cs
1using System;
3using System.Text;
4using System.Threading.Tasks;
5using Waher.Content;
14using Waher.Script;
17using Waher.Security;
20
22{
27 {
31 public const string AgentNamespace = "https://waher.se/Schema/BrokerAgent.xsd";
32
33 private readonly Dictionary<Type, Expression> patternMatches;
34 private AgentApi api;
35
41 public AgentResource(string AgentResourceName,
42 params KeyValuePair<Type, Expression>[] PatternMatches)
43 : base("/Agent/" + AgentResourceName)
44 {
45 this.patternMatches = new Dictionary<Type, Expression>();
46
47 foreach (KeyValuePair<Type, Expression> P in PatternMatches)
48 this.patternMatches[P.Key] = P.Value;
49 }
50
56 public Task Register(HttpServer WebServer, AgentApi AgentApi)
57 {
58 this.api = AgentApi;
59 WebServer?.Register(this);
60 return Task.CompletedTask;
61 }
62
67 public Task Unregister(HttpServer WebServer)
68 {
69 WebServer.Unregister(this);
70 return Task.CompletedTask;
71 }
72
76 public override bool HandlesSubPaths => false;
77
81 public override bool UserSessions => false;
82
91 {
92 return this.AuthenticationSchemes;
93 }
94
99 {
100 get
101 {
102 if (this.authenticationSchemes is null)
103 {
104 if (accounts is null)
105 {
106 PersistenceLayer PersistenceLayer = XmppServerModule.PersistenceLayer ?? new PersistenceLayer();
107 accounts = new Accounts(PersistenceLayer);
108 }
109
110 this.authenticationSchemes = this.CreateAuthenticationSchemes(accounts);
111 }
112
113 return this.authenticationSchemes;
114 }
115 }
116
123 {
125
126 this.AddAuthenticationSchemes(Users, Schemes);
127
128 if (XmppServerModule.PersistenceLayer is null)
129 return Schemes.ToArray();
130
131 return Schemes.ToArray();
132 }
133
140 {
141 bool RequireEncryption = !(DomainConfiguration.Instance is null) &&
143 !string.IsNullOrEmpty(DomainConfiguration.Instance.Domain);
144 int MinStrength = RequireEncryption ? 128 : 0;
145
146 Schemes.Add(new JwtAuthentication(RequireEncryption, MinStrength, Gateway.Domain, Users, Factory));
147
148 if (!(Gateway.HttpServer is null) &&
149 Gateway.HttpServer.ClientCertificates != ClientCertificates.NotUsed)
150 {
151 Schemes.Add(new MutualTlsAuthentication(Users));
152 }
153
154 Schemes.Add(new BasicAuthentication(RequireEncryption, MinStrength, Gateway.Domain, Users));
155 Schemes.Add(new DigestAuthentication(RequireEncryption, MinStrength, DigestAlgorithm.MD5, Gateway.Domain, Users));
156 Schemes.Add(new DigestAuthentication(RequireEncryption, MinStrength, DigestAlgorithm.SHA256, Gateway.Domain, Users));
157 Schemes.Add(new DigestAuthentication(RequireEncryption, MinStrength, DigestAlgorithm.SHA3_256, Gateway.Domain, Users));
158 }
159
160 private static Accounts accounts = null;
161 private static JwtFactory factory = null;
162 private HttpAuthenticationScheme[] authenticationSchemes = null;
163
167 protected AgentApi Api => this.api;
168
172 public static JwtFactory Factory
173 {
174 get
175 {
176 if (factory is null)
177 {
180 {
181 factory = JwtFactory;
182 }
183 else if (Gateway.HasDomain)
184 {
186 factory = JwtFactory.CreateHmacSha256("https://" + Gateway.Domain);
187 else
188 factory = JwtFactory.CreateHmacSha256("http://" + Gateway.Domain);
189 }
190 else
191 factory = JwtFactory.CreateHmacSha256(string.Empty);
192 }
193
194 return factory;
195 }
196
197 set => factory = value;
198 }
199
203 protected static Accounts Accounts => accounts;
204
214 protected async Task<Dictionary<string, IElement>> CheckInput(HttpRequest Request, HttpResponse Response)
215 {
216 if (!Request.HasData)
217 {
218 await Response.SendResponse(new BadRequestException("No content is request."));
219 return null;
220 }
221
222 ContentResponse Content = await Request.DecodeDataAsync();
223
224 if (Content.HasError)
225 {
226 await Response.SendResponse(Content.Error);
227 return null;
228 }
229
230 Type T = Content.Decoded.GetType();
231
232 if (!this.patternMatches.TryGetValue(T, out Expression Pattern))
233 {
234 await Response.SendResponse(new UnsupportedMediaTypeException("Unhandled content type in request."));
235 return null;
236 }
237
239 Dictionary<string, IElement> Matches = new Dictionary<string, IElement>();
240
241 if (Pattern.Root.PatternMatch(E, Matches) == PatternMatchResult.Match)
242 return Matches;
243 else
244 {
245 await Response.SendResponse(new BadRequestException("Content does not match specification."));
246 return null;
247 }
248 }
249
257 {
258 return AssertUserAuthenticated(Request, true);
259 }
260
269 bool MustBeEnabled)
270 {
271 if (!(Request.User is AccountUser User))
272 throw new ForbiddenException(Request, "User not authenticated.");
273
274 if (MustBeEnabled && !User.Account.Enabled)
275 throw new ForbiddenException(Request, "Account not enabled.");
276
277 return User;
278 }
279
286 {
287 return GetAuthenticatedUser(Request, true);
288 }
289
296 protected static AccountUser GetAuthenticatedUser(HttpRequest Request, bool MustBeEnabled)
297 {
298 if (!(Request.User is AccountUser User))
299 return null;
300
301 if (MustBeEnabled && !User.Account.Enabled)
302 return null;
303
304 return User;
305 }
306
313 protected async Task CheckBlocks(HttpRequest Request)
314 {
315 DateTime? Next = await this.api.Auditor.GetEarliestLoginOpportunity(Request.RemoteEndPoint, "HTTPS");
316
317 if (Next.HasValue)
318 {
319 DateTime TP = Next.Value;
320 DateTime Today = DateTime.Today;
321 StringBuilder sb = new StringBuilder();
322
323 if (Next.Value == DateTime.MaxValue)
324 {
325 sb.Append("This endpoint (");
326 sb.Append(Request.RemoteEndPoint);
327 sb.Append(") has been blocked from the system.");
328 }
329 else
330 {
331 sb.Append("Too many failed login attempts in a row registered. Try again after ");
332 sb.Append(TP.ToLongTimeString());
333
334 if (TP.Date != Today)
335 {
336 if (TP.Date == Today.AddDays(1))
337 sb.Append(" tomorrow");
338 else
339 {
340 sb.Append(", ");
341 sb.Append(TP.ToShortDateString());
342 }
343 }
344
345 sb.Append(". Remote Endpoint: ");
346 sb.Append(Request.RemoteEndPoint);
347 }
348
349 throw new TooManyRequestsException(sb.ToString());
350 }
351 }
352
360 protected static Exception ToHttpException(HttpRequest Request, XmppException ex)
361 {
362 if (ex is null)
363 return null;
364
365 if (ex is Networking.XMPP.StanzaErrors.BadRequestException)
366 return new BadRequestException(ex.Message);
367 else if (ex is Networking.XMPP.StanzaErrors.ConflictException)
368 return new ConflictException(ex.Message);
369 else if (ex is Networking.XMPP.StanzaErrors.ForbiddenException)
370 return new ForbiddenException(Request, ex.Message);
371 else if (ex is Networking.XMPP.StanzaErrors.FeatureNotImplementedException)
372 return new Networking.HTTP.NotImplementedException(ex.Message);
373 else if (ex is Networking.XMPP.StanzaErrors.GoneException)
374 return new GoneException(ex.Message);
375 else if (ex is Networking.XMPP.StanzaErrors.InternalServerErrorException)
376 return new InternalServerErrorException(ex);
377 else if (ex is Networking.XMPP.StanzaErrors.ItemNotFoundException)
378 return new NotFoundException(ex.Message);
379 else if (ex is Networking.XMPP.StanzaErrors.NotAllowedException)
380 return new MethodNotAllowedException(Array.Empty<string>(), ex.Message);
381 else if (ex is Networking.XMPP.StanzaErrors.ResourceConstraintException)
382 return new TooManyRequestsException(ex.Message);
383 else if (ex is Networking.XMPP.StanzaErrors.ServiceUnavailableException)
384 return new ServiceUnavailableException(ex.Message);
385 else if (ex is Networking.XMPP.StanzaErrors.NotAuthorizedException)
386 return new NetworkAuthenticationRequiredException(ex.Message);
387 else
388 return ex;
389 }
390
391 }
392}
Contains information about a response to a content request.
bool HasError
If an error occurred.
object Decoded
Decoded object.
Exception Error
Error response.
Static class managing the runtime environment of the IoT Gateway.
Definition: Gateway.cs:147
static CaseInsensitiveString Domain
Domain name.
Definition: Gateway.cs:3087
static HttpServer HttpServer
HTTP Server
Definition: Gateway.cs:4118
static bool HasDomain
If a domain name is configured.
Definition: Gateway.cs:3093
static DomainConfiguration Instance
Current instance of configuration.
bool UseEncryption
If the server uses server-side encryption.
Basic authentication mechanism, as defined in RFC 2617: https://tools.ietf.org/html/rfc2617
Digest authentication mechanism, as defined in RFC 2617: https://tools.ietf.org/html/rfc2617
mTLS authentication mechanism, where identity is taken from a valid client certificate.
The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repe...
The request could not be completed due to a conflict with the current state of the resource....
The server understood the request, but is refusing to fulfill it. Authorization will not help and the...
The requested resource is no longer available at the server and no forwarding address is known....
Base class for all HTTP authentication schemes, as defined in RFC-7235: https://datatracker....
Represents an HTTP request.
Definition: HttpRequest.cs:22
string RemoteEndPoint
Remote end-point.
Definition: HttpRequest.cs:243
bool HasData
If the request has data.
Definition: HttpRequest.cs:113
IUser User
Authenticated user, if available, or null if not available.
Definition: HttpRequest.cs:203
async Task< ContentResponse > DecodeDataAsync()
Decodes data sent in request.
Definition: HttpRequest.cs:139
Represets a response of an HTTP client request.
Definition: HttpResponse.cs:23
async Task SendResponse()
Sends the response back to the client. If the resource is synchronous, there's no need to call this m...
Implements an HTTP server.
Definition: HttpServer.cs:41
HttpResource Register(HttpResource Resource)
Registers a resource with the server.
Definition: HttpServer.cs:1568
bool Unregister(HttpResource Resource)
Unregisters a resource from the server.
Definition: HttpServer.cs:1743
Base class for all synchronous HTTP resources. A synchronous resource responds within the method hand...
The server encountered an unexpected condition which prevented it from fulfilling the request.
The server has not found anything matching the Request-URI. No indication is given of whether the con...
The client needs to authenticate to gain network access. Intended for use by intercepting proxies use...
The server has not found anything matching the Request-URI. No indication is given of whether the con...
The server is currently unable to handle the request due to a temporary overloading or maintenance of...
The user has sent too many requests in a given amount of time. Intended for use with rate limiting sc...
The server is refusing to service the request because the entity of the request is in a format not su...
Base class of XMPP exceptions
A chunked list is a linked list of chunks of objects of type T .
Definition: ChunkedList.cs:54
void Add(T Item)
Adds an item to the collection.
Definition: ChunkedList.cs:272
T[] ToArray()
Returns an array containing all elements of the collection.
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
Class managing a script expression.
Definition: Expression.cs:41
static IElement Encapsulate(object Value)
Encapsulates an object.
Definition: Expression.cs:5241
Use JWT tokens for authentication. The Bearer scheme defined in RFC 6750 is used: https://tools....
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
Collection of broker accounts
Definition: Accounts.cs:12
Abstract base class for agent resources
async Task< Dictionary< string, IElement > > CheckInput(HttpRequest Request, HttpResponse Response)
Checks if content matches specification in resource.
Task Register(HttpServer WebServer, AgentApi AgentApi)
Registers the resource on a web server.
static Accounts Accounts
Reference to available accounts.
Task Unregister(HttpServer WebServer)
Unregisters the resource from a web server.
static AccountUser AssertUserAuthenticated(HttpRequest Request)
Makes sure the request is made by an authenticated API user.
override bool UserSessions
If the resource uses user sessions.
override HttpAuthenticationScheme[] GetAuthenticationSchemes(HttpRequest Request)
Any authentication schemes used to authenticate users before access is granted to the corresponding r...
const string AgentNamespace
https://waher.se/Schema/BrokerAgent.xsd
HttpAuthenticationScheme[] CreateAuthenticationSchemes(IUserSource Users)
Creates a set of authentication schemes for the resource.
virtual void AddAuthenticationSchemes(IUserSource Users, ChunkedList< HttpAuthenticationScheme > Schemes)
Adds authentication schemes to the resource.
static AccountUser GetAuthenticatedUser(HttpRequest Request, bool MustBeEnabled)
Gets the authenticated user object, if one exists.
override bool HandlesSubPaths
If the resource handles sub-paths.
static AccountUser AssertUserAuthenticated(HttpRequest Request, bool MustBeEnabled)
Makes sure the request is made by an authenticated API user.
static AccountUser GetAuthenticatedUser(HttpRequest Request)
Gets the authenticated user object, if one exists.
AgentResource(string AgentResourceName, params KeyValuePair< Type, Expression >[] PatternMatches)
Abstract base class for agent resources
HttpAuthenticationScheme[] AuthenticationSchemes
Array of authentication schemes used for the resource.
async Task CheckBlocks(HttpRequest Request)
Checks if the client is blocked.
static Exception ToHttpException(HttpRequest Request, XmppException ex)
Tries to convert an XMPP Exception to an HTTP Exception.
Service Module hosting the XMPP broker and its components.
Basic interface for all types of elements.
Definition: IElement.cs:21
Interface for data sources containing users.
Definition: IUserSource.cs:9
ClientCertificates
Client Certificate Options
PatternMatchResult
Status result of a pattern matching operation.
Definition: ScriptNode.cs:17