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;
2using System.Collections.Generic;
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
34 public override string GetChallenge()
35 {
36 string Nonce = Convert.ToBase64String(Gateway.NextBytes(128));
37 DateTime Expires = DateTime.Now.AddMinutes(1);
38
39 while (true)
40 {
41 lock (this)
42 {
43 if (!this.nonceByExpiration.ContainsKey(Expires))
44 {
45 this.expirationByNonce[Nonce] = Expires;
46 this.nonceByExpiration[Expires] = Nonce;
47 break;
48 }
49 }
50
51 byte[] b = Gateway.NextBytes(1);
52
53 Expires = Expires.AddTicks(b[0] & 15);
54 }
55
56 return "NeuroFoundation.Sign realm=\"" + this.realm + "\", n=\"" + Nonce + "\"";
57 }
58
59 public override async Task<IUser> IsAuthenticated(HttpRequest Request)
60 {
61 if (!(Request.Session is null) &&
62 Request.Session.TryGetVariable("User", out Variable v) &&
63 v.ValueObject is IUser User &&
64 (User is LegalIdentityUser || User.HasPrivilege("Legal.Attachments")))
65 {
66 return User;
67 }
68
69 HttpFieldAuthorization Authorization = Request.Header.Authorization;
70 if (!(Authorization is null) && Authorization.Value.StartsWith("NeuroFoundation.Sign ", StringComparison.CurrentCultureIgnoreCase))
71 {
72 string FullJid = null;
73 string Realm = null;
74 string NonceStr = null;
75 string SignatureStr = null;
76
77 foreach (KeyValuePair<string, string> P in CommonTypes.ParseFieldValues(Authorization.Value.Substring(21)))
78 {
79 switch (P.Key.ToLower())
80 {
81 case "jid":
82 FullJid = P.Value;
83 break;
84
85 case "realm":
86 Realm = P.Value;
87 break;
88
89 case "n":
90 NonceStr = P.Value;
91 break;
92
93 case "s":
94 SignatureStr = P.Value;
95 break;
96 }
97 }
98
99 if (this.realm != Realm || NonceStr is null || SignatureStr is null || FullJid is null)
100 return null;
101
102 DateTime TP = DateTime.Now;
103
104 lock (this)
105 {
106 LinkedList<DateTime> ToRemove = null;
107
108 foreach (KeyValuePair<DateTime, string> Pair in this.nonceByExpiration)
109 {
110 if (Pair.Key <= TP)
111 {
112 if (ToRemove is null)
113 ToRemove = new LinkedList<DateTime>();
114
115 ToRemove.AddLast(Pair.Key);
116 this.expirationByNonce.Remove(Pair.Value);
117 }
118 else
119 break;
120 }
121
122 if (!(ToRemove is null))
123 {
124 foreach (DateTime ExpiryDate in ToRemove)
125 this.nonceByExpiration.Remove(ExpiryDate);
126 }
127
128 if (!this.expirationByNonce.TryGetValue(NonceStr, out TP))
129 return null;
130
131 if (Request.Header.Method != "HEAD")
132 {
133 this.expirationByNonce.Remove(NonceStr);
134 this.nonceByExpiration.Remove(TP);
135 }
136 }
137
138 XmppAddress From = new XmppAddress(FullJid);
139 byte[] Nonce = Convert.FromBase64String(NonceStr);
140 byte[] Signature = Convert.FromBase64String(SignatureStr);
141 (LegalIdentity Identity, _) = await this.legalComponent.ValidateSenderSignature(From, null, TP, Nonce, Signature, null);
142
143 if (Identity is null)
144 {
145 if (Request.Resource is AttachmentsResource)
146 {
147 string AttachmentId = Request.SubPath.Substring(1);
148
149 foreach (LegalIdentity ID in await Database.Find<LegalIdentity>(new FilterAnd(
150 new FilterFieldEqualTo("Account", From.Account),
151 new FilterFieldEqualTo("State", IdentityState.Created))))
152 {
153 if (ID.Attachments is null)
154 continue;
155
156 foreach (AttachmentReference Attachment in ID.Attachments)
157 {
158 if (Attachment.Id == AttachmentId)
159 {
160 Identity = ID;
161 break;
162 }
163 }
164
165 if (!(Identity is null))
166 break;
167 }
168 }
169 }
170 else if (Identity.State != IdentityState.Approved)
171 Identity = null;
172
173 if (Identity is null)
174 {
175 LoginAuditor.Fail("Login attempt failed.", From.BareJid, Request.RemoteEndPoint, "HTTP");
176 return null;
177 }
178 else
179 {
180 LoginAuditor.Success("Login successful.", From.BareJid, Request.RemoteEndPoint, "HTTP");
181 return await LegalIdentityUser.Create(Identity, From, this.legalComponent);
182 }
183 }
184
185 return null;
186 }
187
188 }
189}
Helps with parsing of commong data types.
Definition: CommonTypes.cs:13
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:472
Static class managing the runtime environment of the IoT Gateway.
Definition: Gateway.cs:126
static byte[] NextBytes(int NrBytes)
Generates an array of random bytes.
Definition: Gateway.cs:3534
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:18
HttpRequestHeader Header
Request header.
Definition: HttpRequest.cs:134
string RemoteEndPoint
Remote end-point.
Definition: HttpRequest.cs:195
Variables Session
Contains session states, if the resource requires sessions, or null otherwise.
Definition: HttpRequest.cs:164
string SubPath
Sub-path. If a resource is found handling the request, this property contains the trailing sub-path o...
Definition: HttpRequest.cs:146
HttpResource Resource
Resource being accessed.
Definition: HttpRequest.cs:173
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:19
static Task< IEnumerable< object > > Find(string Collection, params string[] SortOrder)
Finds objects in a given collection.
Definition: Database.cs:247
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
virtual bool TryGetVariable(string Name, out Variable Variable)
Tries to get a variable object, given its name.
Definition: Variables.cs:52
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 async void Fail(string Message, string UserName, string RemoteEndpoint, string Protocol, params KeyValuePair< string, object >[] Tags)
Handles a failed login attempt.
Basic interface for a user.
Definition: IUser.cs:7