4using System.Threading.Tasks;
51 private readonly Dictionary<string, bool> pendingPetitions =
new Dictionary<string, bool>();
57 : base(
"/RemoteLogin")
102 return base.OPTIONS(Request, Response);
113 string Location =
"/Documentation/Neuron/RemoteLogin.md";
118 Location =
"https://" + Domain + Location;
133 bool PreviousFailed =
false;
158 if (!(Content.
Decoded is Dictionary<string, object> Json))
164 #region Polling status of Petition
168 if (Json.TryGetValue(
"PetitionId", out
object Obj))
170 if (!(Obj is
string PetitionId2))
176 if (!
XmppServerModule.Legal.TryGetItemFromCache(PetitionId2 +
"|petition", out Obj) ||
177 !(Obj is PetitionInfo PetitionInfo))
183 if (User.
UserName != PetitionInfo.User.UserName)
189 bool Pending =
string.IsNullOrEmpty(PetitionInfo.Token);
191 Dictionary<string, object> ResponseObject =
new Dictionary<string, object>
193 {
"Pending", Pending },
194 {
"Token", PetitionInfo.Token },
199 ChallengeUri = await PetitionInfo.RemoteAuthentication.GetChallengeUri(
200 PetitionInfo.Purpose, PetitionInfo.RemoteEndPoint);
202 if (!(ChallengeUri is
null))
203 ResponseObject[
"ChallengeUri"] = ChallengeUri.ToString();
206 await Response.
Return(ResponseObject);
213 #region LoginAuditor Integration
215 if (!Json.TryGetValue(
"RemoteEndPoint", out Obj) ||
216 !(Obj is
string RemoteEndPoint) ||
217 string.IsNullOrEmpty(RemoteEndPoint) ||
218 RemoteEndPoint.Length > 128)
226 if (Next.Value == DateTime.MaxValue)
229 "Remote Endpoint (" + RemoteEndPoint +
") permanently blocked."));
236 new Dictionary<string, object>()
238 {
"RemoteEndPoint", RemoteEndPoint },
239 {
"Next", Next.Value }
248 #region Validating or Refreshing Token
250 if (Json.TryGetValue(
"Token", out Obj))
252 if (!(Obj is
string Token))
261 if (!Json.TryGetValue(
"Seconds", out Obj) || !IsValid)
263 await Response.
Return(
new Dictionary<string, object>
270 if (!(Obj is
int Seconds2) ||
271 Seconds2 < 1 || Seconds2 > 3600)
278 int IssuedAt = (int)Math.Round(DateTime.UtcNow.Subtract(
JSON.
UnixEpoch).TotalSeconds);
279 int Expires = IssuedAt + Seconds2;
281 foreach (KeyValuePair<string, object> Claim
in ParsedToken.Claims)
299 if (User.
UserName != Claim.Value?.ToString())
309 Claims.Add(
new KeyValuePair<string, object>(
JwtClaims.
Actor, RemoteEndPoint));
320 await Response.
Return(
new Dictionary<string, object>
322 {
"Valid", IsValid },
330 #region Initiating new Petition
332 if (!Json.TryGetValue(
"Seconds", out Obj))
338 if (!(Obj is
int Seconds) ||
339 Seconds < 1 || Seconds > 3600)
345 if (!Json.TryGetValue(
"ResponseMethod", out Obj))
351 if (!(Obj is
string ResponseMethodStr) ||
358 Uri CallbackUrl =
null;
360 string Function =
null;
362 switch (ResponseMethod)
365 if (!Json.TryGetValue(
"CallbackURL", out Obj))
371 if (!(Obj is
string CallbackUrlStr) ||
372 string.IsNullOrEmpty(CallbackUrlStr) ||
373 !Uri.TryCreate(CallbackUrlStr, UriKind.Absolute, out CallbackUrl) ||
374 (
string.Compare(CallbackUrl.Scheme,
"https",
true) != 0 &&
375 string.Compare(CallbackUrl.Scheme,
"httpx",
true) != 0))
383 if (!Json.TryGetValue(
"TabID", out Obj))
389 if (!(Obj is
string TabIDStr) ||
390 string.IsNullOrEmpty(TabIDStr))
396 if (!Json.TryGetValue(
"Function", out Obj))
402 if (!(Obj is
string FunctionStr) ||
403 string.IsNullOrEmpty(FunctionStr))
410 Function = FunctionStr;
414 string Privilege = nameof(
RemoteLogin) +
".Method." + ResponseMethodStr;
421 if (!Json.TryGetValue(
"AddressType", out Obj))
427 if (!(Obj is
string AddressTypeStr))
433 Privilege = nameof(
RemoteLogin) +
".Type." + AddressTypeStr;
440 if (!Json.TryGetValue(
"Address", out Obj))
446 if (!(Obj is
string AddressStr))
455 if (Authenticator is
null)
481 if (!Json.TryGetValue(
"Purpose", out Obj))
487 if (!(Obj is
string Purpose) ||
string.IsNullOrEmpty(Purpose))
493 if (!Purpose.Contains(User.
UserName))
494 Purpose = User.
UserName +
": " + Purpose;
496 ChallengeUri = await RemoteAuthentication.
GetChallengeUri(Purpose, RemoteEndPoint);
506 Key = RemoteEndPoint +
" " + RemoteAuthentication.
Key;
508 lock (this.pendingPetitions)
510 if (this.pendingPetitions.ContainsKey(Key))
511 PreviousFailed =
true;
513 this.pendingPetitions[Key] =
true;
519 User.
UserName, RemoteEndPoint,
"RemoteLogin",
520 new KeyValuePair<string, object>(
"Remote Identifier", RemoteAuthentication.
Key));
525 string PetitionId =
string.Empty;
527 PetitionId = await RemoteAuthentication.
Start(Purpose, RemoteEndPoint,
530 lock (this.pendingPetitions)
532 this.pendingPetitions.Remove(Key);
537 int IssuedAt = (int)Math.Round(DateTime.UtcNow.Subtract(
JSON.
UnixEpoch).TotalSeconds);
538 int Expires = IssuedAt + Seconds;
541 new KeyValuePair<string, object>[]
546 new KeyValuePair<string, object>(
JwtClaims.
Actor, RemoteEndPoint),
549 }.Join(e.JwtClaims));
551 XmppServerModule.Legal.AddItemToCache(PetitionId +
"|petition",
new PetitionInfo()
553 PetitionId = PetitionId,
557 RemoteEndPoint = RemoteEndPoint,
558 RemoteAuthentication = RemoteAuthentication
561 await this.ReturnResponse(ResponseMethod, Response, CallbackUrl,
562 TabID, Function, PetitionId, Token);
565 User.
UserName, RemoteEndPoint,
"RemoteLogin",
566 new KeyValuePair<string, object>(
"Remote Identifier", RemoteAuthentication.
Key));
572 await this.ReturnResponse(ResponseMethod, Response, CallbackUrl,
573 TabID, Function, PetitionId,
null);
575 if (e.LogAuditFailure)
578 User.
UserName, RemoteEndPoint,
"RemoteLogin",
579 new KeyValuePair<string, object>(
"Remote Identifier", RemoteAuthentication.
Key));
587 XmppServerModule.Legal.AddItemToCache(PetitionId +
"|petition",
new PetitionInfo()
589 PetitionId = PetitionId,
593 RemoteEndPoint = RemoteEndPoint,
594 RemoteAuthentication = RemoteAuthentication
597 Dictionary<string, object> ResponseObject =
new Dictionary<string, object>
599 {
"PetitionId", PetitionId }
602 if (!(ChallengeUri is
null))
603 ResponseObject[
"ChallengeUri"] = ChallengeUri.ToString();
605 await Response.
Return(ResponseObject);
613 if (!
string.IsNullOrEmpty(Key))
615 lock (this.pendingPetitions)
617 this.pendingPetitions.Remove(Key);
624 "Authentication service unavailable."));
629 HttpResponse Response, Uri CallbackUrl,
string TabID,
string Function,
630 string PetitionId,
string TokenResult)
635 if (
string.IsNullOrEmpty(TokenResult))
642 await Response.
Return(
new Dictionary<string, object>
644 {
"Pending",
false },
645 {
"Token", TokenResult }
652 new Dictionary<string, object>
654 {
"PetitionId", PetitionId },
655 {
"Rejected",
string.IsNullOrEmpty(TokenResult) },
656 {
"Token", TokenResult }
664 {
"PetitionId", PetitionId },
665 {
"Rejected",
string.IsNullOrEmpty(TokenResult) },
666 {
"Token", TokenResult }
672 private class PetitionInfo
674 public string PetitionId;
677 public string Purpose;
678 public string RemoteEndPoint;
Contains information about a remote identifier.
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 encoding and decoding of internet content.
static Task< ContentResponse > PostAsync(Uri Uri, object Data, params KeyValuePair< string, string >[] Headers)
Posts to a resource, using a Uniform Resource Identifier (or Locator).
Helps with common JSON-related tasks.
static readonly DateTime UnixEpoch
Unix Date and Time epoch, starting at 1970-01-01T00:00:00Z
static string Encode(string s)
Encodes a string for inclusion in JSON.
Static class managing the application event log. Applications and services log events on this static ...
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
The ClientEvents class allows applications to push information asynchronously to web clients connecte...
static Task< int > PushEvent(string[] TabIDs, string Type, object Data)
Puses an event to a set of Tabs, given their Tab IDs.
Static class managing the runtime environment of the IoT Gateway.
static CaseInsensitiveString Domain
Domain name.
static X509Certificate2 Certificate
Domain certificate.
static LoginAuditor LoginAuditor
Current Login Auditor. Should be used by modules accepting user logins, to protect the system from un...
static byte[] NextBytes(int NrBytes)
Generates an array of random bytes.
static bool TryGetLocalResourceFileName(string Resource, string Host, out string FileName)
Tries to get a file name for a resource, if local.
static HttpFolderResource Root
Root folder resource.
The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repe...
The server understood the request, but is refusing to fulfill it. Authorization will not help and the...
static ForbiddenException AccessDenied(string ObjectId, string ActorId)
Returns a ForbiddenException object, and logs a entry in the event log about the event.
The requested resource resides temporarily under a different URI. Since the redirection might be alte...
Base class for all asynchronous HTTP resources. An asynchronous resource responds outside of the meth...
Base class for all HTTP authentication schemes, as defined in RFC-7235: https://datatracker....
void SetDefaultResponseHeaders(HttpResponse Response)
Sets any default response headers registered on the file folder object, to a HTTP Response object.
Represents an HTTP request.
string RemoteEndPoint
Remote end-point.
bool HasData
If the request has data.
IUser User
Authenticated user, if available, or null if not available.
async Task< ContentResponse > DecodeDataAsync()
Decodes data sent in request.
Represets a response of an HTTP client request.
async Task SendResponse()
Sends the response back to the client. If the resource is synchronous, there's no need to call this m...
Task Return(Exception ex)
Returns an error to the client.
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...
Defined in the internet draft "A New HTTP Status Code for Legally-restricted Resources"....
A chunked list is a linked list of chunks of objects of type T .
Static class managing persistent counters.
static Task< long > IncrementCounter(CaseInsensitiveString Key)
Increments a counter.
Static class that dynamically manages types and interfaces available in the runtime environment.
Static class containing predefined JWT claim names.
const string Issuer
Issuer of the JWT
const string Audience
Recipient for which the JWT is intended
const string IssueTime
Time at which the JWT was issued; can be used to determine age of the JWT
const string JwtId
Unique identifier; can be used to prevent the JWT from being replayed (allows a token to be used only...
const string Subject
Subject of the JWT (the user)
const string ExpirationTime
Time after which the JWT expires
Contains information about a Java Web Token (JWT). JWT is defined in RFC 7519: https://tools....
Class that monitors login events, and help applications determine malicious intent....
async Task< DateTime?> GetEarliestLoginOpportunity(string RemoteEndPoint, string Protocol)
Checks when a remote endpoint can login.
static async void Success(string Message, string UserName, string RemoteEndPoint, string Protocol, params KeyValuePair< string, object >[] Tags)
Handles a successful login attempt.
static void Fail(string Message, string UserName, string RemoteEndPoint, string Protocol)
Handles a failed login attempt.
Legal (digital identities, smart contracts) service component.
static Task< string > GetOnboardingNeuronDomainName()
Gets the domain name of the Nnboarding Neuron.
Web resource that permits authentication of users into their remote systems, by triggering a digital ...
bool AllowsGET
If the GET method is allowed.
override Task OPTIONS(HttpRequest Request, HttpResponse Response)
Executes the OPTIONS method on the resource.
async Task GET(HttpRequest Request, HttpResponse Response)
Executes the OPTIONS method on the resource.
async Task POST(HttpRequest Request, HttpResponse Response)
Executes the POST method on the resource.
override bool HandlesSubPaths
If the resource handles sub-paths.
bool AllowsPOST
If the POST method is allowed.
RemoteLogin()
Web resource that allows calling applications to enable Quick-Login using legal identities.
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...
Service Module hosting the XMPP broker and its components.
HttpAuthenticationScheme[] DefaultAuthenticationSchemesAdmin
Default HTTP Authentication schemes for administrative resources.
Interface for remote authentications.
Task< Uri > GetChallengeUri(string Purpose, string RemoteEndPoint)
Gets a Challenge URI to send to the requestor of the remote authentication.
Task< string > Start(string Purpose, string RemoteEndPoint, EventHandlerAsync< RemoteAuthenticationEventArgs > Callback, object State)
Starts the remote authentication process.
string Key
Key identifying the remote authentication.
Task< bool > IsLegalIdAvailable()
Checks if a Legal Id is available for the remote ID.
Task< bool > IsValidAddress()
Checks if the remote address is valid.
Task< bool > IsPermitted(IUser User)
Checks is the remote address is permitted to perform the requested operation.
Interface for remote authenticators.
Task< IRemoteAuthentication > CreateAuthentication(IRemoteIdentifier RemoteIdentifier)
Creates a remote authentication object instance for a remote identifier.
Interface for remote identifiers.
GET Interface for HTTP resources.
POST Interface for HTTP resources.
bool HasPrivilege(string Privilege)
If the object has a given privilege.
Basic interface for a user.
string UserName
User Name.
RemoteLoginResponseMethod
Method used to return a response once the user has identified itself.