Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
LegalSignature.cs
1using System;
3using System.Threading.Tasks;
4using Waher.Content;
11using Waher.Script;
12using Waher.Security;
15
17{
19 {
20 private readonly Dictionary<string, DateTime> expirationByNonce = new Dictionary<string, DateTime>();
21 private readonly SortedDictionary<DateTime, string> nonceByExpiration = new SortedDictionary<DateTime, string>();
22 private readonly LegalComponent legalComponent;
23 private readonly string realm;
24
25 public LegalSignature(string Realm, LegalComponent LegalComponent)
26 : base(false, 0)
27 {
28 this.realm = Realm;
29 this.legalComponent = LegalComponent;
30 }
31
32 public override bool UserSessions => true;
33
37 public override string DisplayName => "Legal Signature";
38
39 public override string[] GetChallenges(HttpRequest Request)
40 {
41 string Nonce = Convert.ToBase64String(Gateway.NextBytes(128));
42 DateTime Expires = DateTime.Now.AddMinutes(1);
43
44 while (true)
45 {
46 lock (this)
47 {
48 if (!this.nonceByExpiration.ContainsKey(Expires))
49 {
50 this.expirationByNonce[Nonce] = Expires;
51 this.nonceByExpiration[Expires] = Nonce;
52 break;
53 }
54 }
55
56 byte[] b = Gateway.NextBytes(1);
57
58 Expires = Expires.AddTicks(b[0] & 15);
59 }
60
61 return new string[] { "NeuroFoundation.Sign realm=\"" + this.realm + "\", n=\"" + Nonce + "\"" };
62 }
63
64 public override async Task<IUser> IsAuthenticated(HttpRequest Request)
65 {
66 if (!(Request.Session is null) &&
67 Request.Session.TryGetVariable("User", out Variable v) &&
68 v.ValueObject is IUser User &&
69 (User is LegalIdentityUser || User.HasPrivilege("Legal.Attachments")))
70 {
71 return User;
72 }
73
74 HttpFieldAuthorization Authorization = Request.Header.Authorization;
75 if (!(Authorization is null) && Authorization.Value.StartsWith("NeuroFoundation.Sign ", StringComparison.CurrentCultureIgnoreCase))
76 {
77 string FullJid = null;
78 string Realm = null;
79 string NonceStr = null;
80 string SignatureStr = null;
81
82 foreach (KeyValuePair<string, string> P in CommonTypes.ParseFieldValues(Authorization.Value[21..]))
83 {
84 switch (P.Key.ToLower())
85 {
86 case "jid":
87 FullJid = P.Value;
88 break;
89
90 case "realm":
91 Realm = P.Value;
92 break;
93
94 case "n":
95 NonceStr = P.Value;
96 break;
97
98 case "s":
99 SignatureStr = P.Value;
100 break;
101 }
102 }
103
104 if (this.realm != Realm || NonceStr is null || SignatureStr is null || FullJid is null)
105 return null;
106
107 DateTime TP = DateTime.Now;
108
109 lock (this)
110 {
111 LinkedList<DateTime> ToRemove = null;
112
113 foreach (KeyValuePair<DateTime, string> Pair in this.nonceByExpiration)
114 {
115 if (Pair.Key <= TP)
116 {
117 ToRemove ??= new LinkedList<DateTime>();
118 ToRemove.AddLast(Pair.Key);
119 this.expirationByNonce.Remove(Pair.Value);
120 }
121 else
122 break;
123 }
124
125 if (!(ToRemove is null))
126 {
127 foreach (DateTime ExpiryDate in ToRemove)
128 this.nonceByExpiration.Remove(ExpiryDate);
129 }
130
131 if (!this.expirationByNonce.TryGetValue(NonceStr, out TP))
132 return null;
133
134 if (Request.Header.Method != "HEAD")
135 {
136 this.expirationByNonce.Remove(NonceStr);
137 this.nonceByExpiration.Remove(TP);
138 }
139 }
140
141 XmppAddress From = new XmppAddress(FullJid);
142 byte[] Nonce = Convert.FromBase64String(NonceStr);
143 byte[] Signature = Convert.FromBase64String(SignatureStr);
144 (LegalIdentity Identity, _) = await this.legalComponent.ValidateSenderSignature(From, null, TP, Nonce, Signature, null);
145
146 if (Identity is null)
147 {
148 if (Request.Resource is AttachmentsResource)
149 {
150 string AttachmentId = Request.SubPath[1..];
151
152 foreach (LegalIdentity ID in await Database.Find<LegalIdentity>(new FilterAnd(
153 new FilterFieldEqualTo("Account", From.Account),
154 new FilterFieldEqualTo("State", IdentityState.Created))))
155 {
156 if (ID.Attachments is null)
157 continue;
158
160 {
161 if (Attachment.Id == AttachmentId)
162 {
163 Identity = ID;
164 break;
165 }
166 }
167
168 if (!(Identity is null))
169 break;
170 }
171 }
172 }
173 else if (Identity.State != IdentityState.Approved)
174 Identity = null;
175
176 if (Identity is null)
177 {
178 LoginAuditor.Fail("Login attempt failed.", From.BareJid, Request.RemoteEndPoint, "HTTP");
179 return null;
180 }
181 else
182 {
183 LoginAuditor.Success("Login successful.", From.BareJid, Request.RemoteEndPoint, "HTTP");
184 return await LegalIdentityUser.Create(Identity, From, this.legalComponent);
185 }
186 }
187
188 return null;
189 }
190
191 }
192}
Helps with parsing of commong data types.
Definition: CommonTypes.cs:15
static KeyValuePair< string, string >[] ParseFieldValues(string Value)
Parses a set of comma or semicolon-separated field values, optionaly delimited by ' or " characters.
Definition: CommonTypes.cs:474
Static class managing the runtime environment of the IoT Gateway.
Definition: Gateway.cs:147
static byte[] NextBytes(int NrBytes)
Generates an array of random bytes.
Definition: Gateway.cs:4335
Authorization HTTP Field header. (RFC 2616, §14.8)
Base class for all HTTP authentication schemes, as defined in RFC-7235: https://datatracker....
string Value
HTTP Field Value
Definition: HttpField.cs:31
HttpFieldAuthorization Authorization
Authorization HTTP Field header. (RFC 2616, §14.8)
Represents an HTTP request.
Definition: HttpRequest.cs:22
HttpRequestHeader Header
Request header.
Definition: HttpRequest.cs:182
string RemoteEndPoint
Remote end-point.
Definition: HttpRequest.cs:243
SessionVariables Session
Contains session states, if the resource requires sessions, or null otherwise.
Definition: HttpRequest.cs:212
string SubPath
Sub-path. If a resource is found handling the request, this property contains the trailing sub-path o...
Definition: HttpRequest.cs:194
HttpResource Resource
Resource being accessed.
Definition: HttpRequest.cs:221
override bool TryGetVariable(string Name, out Variable Variable)
Tries to get a variable object, given its name.
Contains information about one XMPP address.
Definition: XmppAddress.cs:9
CaseInsensitiveString BareJid
Bare JID
Definition: XmppAddress.cs:45
CaseInsensitiveString Account
Account
Definition: XmppAddress.cs:124
Static interface for database persistence. In order to work, a database provider has to be assigned t...
Definition: Database.cs:21
static Task< IEnumerable< object > > Find(string Collection, params string[] SortOrder)
Finds objects in a given collection.
Definition: Database.cs:238
This filter selects objects that conform to all child-filters provided.
Definition: FilterAnd.cs:10
This filter selects objects that have a named field equal to a given value.
Contains information about a variable.
Definition: Variable.cs:10
Class that monitors login events, and help applications determine malicious intent....
Definition: LoginAuditor.cs:26
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.
Basic interface for a user.
Definition: IUser.cs:7
Definition: ImplTypes.g.cs:58