Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
MultiFactorAuthentication.cs
1using Paiwise;
2using System;
4using System.Text;
5using System.Threading.Tasks;
6using System.Xml;
7using Waher.Content;
12
14{
19 {
21 : base("/MFA")
22 {
23 }
24
28 public override bool HandlesSubPaths => false;
29
33 public override bool UserSessions => false;
34
38 public bool AllowsPOST => true;
39
43 public bool AllowsGET => true;
44
51 public Task GET(HttpRequest Request, HttpResponse Response)
52 {
53 return Response.SendResponse(new TemporaryRedirectException("/MFATestForm.md"));
54 }
55
62 public async Task POST(HttpRequest Request, HttpResponse Response)
63 {
64 if (!Request.HasData)
65 {
66 await Response.SendResponse(new BadRequestException("No data provided in post."));
67 return;
68 }
69
70 ContentResponse Content = await Request.DecodeDataAsync();
71 string PNr;
72 string Country;
73 string TimeoutStr;
74 string Reason;
75 string LegalId;
76 string SignatureStr;
77 byte[] Signature = null;
78 int Timeout = 0;
79 bool HasTimeout = false;
80
81 if (Content.HasError)
82 {
83 await Response.SendResponse(Content.Error);
84 return;
85 }
86
87 if (Content.Decoded is XmlDocument Xml)
88 {
89 PNr = Xml.DocumentElement[PersonalInformation.PersonalNumberTag]?.InnerText;
90 Country = Xml.DocumentElement[PersonalInformation.CountryTag]?.InnerText;
91 TimeoutStr = Xml.DocumentElement["Timeout"]?.InnerText;
92 Reason = Xml.DocumentElement["Reason"]?.InnerText;
93 LegalId = Xml.DocumentElement["LegalId"]?.InnerText;
94 SignatureStr = Xml.DocumentElement["Signature"]?.InnerText;
95 }
96 else if (Content.Decoded is Dictionary<string, object> Json)
97 {
98 if (Json.TryGetValue(PersonalInformation.PersonalNumberTag, out object v))
99 PNr = v.ToString();
100 else
101 PNr = null;
102
103 if (Json.TryGetValue(PersonalInformation.CountryTag, out v))
104 Country = v.ToString();
105 else
106 Country = null;
107
108 if (Json.TryGetValue("Timeout", out v))
109 {
110 if (v is int i)
111 {
112 Timeout = i;
113 HasTimeout = true;
114 TimeoutStr = null;
115 }
116 else if (v is string s)
117 TimeoutStr = s;
118 else
119 TimeoutStr = v.ToString();
120 }
121 else
122 TimeoutStr = null;
123
124 if (Json.TryGetValue("Reason", out v))
125 Reason = v.ToString();
126 else
127 Reason = null;
128
129 if (Json.TryGetValue("LegalId", out v))
130 LegalId = v.ToString();
131 else
132 LegalId = null;
133
134 if (Json.TryGetValue("Signature", out v))
135 {
136 if (v is byte[] Bin)
137 {
138 Signature = Bin;
139 SignatureStr = null;
140 }
141 else
142 SignatureStr = v.ToString();
143 }
144 else
145 SignatureStr = null;
146 }
147 else if (Content.Decoded is Dictionary<string, string> Form)
148 {
149 if (!Form.TryGetValue(PersonalInformation.PersonalNumberTag, out PNr))
150 PNr = null;
151
152 if (!Form.TryGetValue(PersonalInformation.CountryTag, out Country))
153 Country = null;
154
155 if (!Form.TryGetValue("Timeout", out TimeoutStr))
156 TimeoutStr = null;
157
158 if (!Form.TryGetValue("Reason", out Reason))
159 Reason = null;
160
161 if (!Form.TryGetValue("LegalId", out LegalId))
162 LegalId = null;
163
164 if (!Form.TryGetValue("Signature", out SignatureStr))
165 SignatureStr = null;
166
167 if (Form.TryGetValue("g-recaptcha-response", out string RecaptchaResponse))
168 {
169 if (!await Feedback.SiteVerify(RecaptchaResponse, Request.RemoteEndPoint))
170 {
171 await Response.SendResponse(new ForbiddenException(Request, "Request not properly verified. Bot?"));
172 return;
173 }
174 }
175 else if (string.IsNullOrEmpty(LegalId))
176 {
177 await Response.SendResponse(new ForbiddenException(Request, "Request not properly verified. Bot?"));
178 return;
179 }
180 }
181 else
182 {
183 await Response.SendResponse(new UnsupportedMediaTypeException("Unsupported Request Content-Type encoding used."));
184 return;
185 }
186
187 if (string.IsNullOrEmpty(PNr))
188 {
189 await Response.SendResponse(new BadRequestException("Invalid PNR."));
190 return;
191 }
192
193 if (string.IsNullOrEmpty(Country))
194 {
195 await Response.SendResponse(new BadRequestException("Invalid COUNTRY."));
196 return;
197 }
198
199 if (string.IsNullOrEmpty(Reason))
200 {
201 await Response.SendResponse(new BadRequestException("Invalid Reason."));
202 return;
203 }
204
205 if (!HasTimeout)
206 {
207 if (TimeoutStr is null || !int.TryParse(TimeoutStr, out Timeout))
208 {
209 await Response.SendResponse(new BadRequestException("Invalid timeout."));
210 return;
211 }
212 }
213
214 if (Timeout <= 0 || Timeout > 300)
215 {
216 await Response.SendResponse(new BadRequestException("Invalid timeout."));
217 return;
218 }
219
220 if (string.IsNullOrEmpty(LegalId))
221 {
222 if (!(Signature is null) || !string.IsNullOrEmpty(SignatureStr))
223 {
224 await Response.SendResponse(new BadRequestException("Missing legal identity."));
225 return;
226 }
227
228 DateTime? Next = await Gateway.LoginAuditor.GetEarliestLoginOpportunity(Request.RemoteEndPoint, "HTTP");
229
230 if (Next.HasValue)
231 {
232 StringBuilder sb = new StringBuilder();
233 DateTime TP = Next.Value;
234 DateTime Today = DateTime.Today;
235
236 if (Next.Value == DateTime.MaxValue)
237 {
238 sb.Append("This endpoint (");
239 sb.Append(Request.RemoteEndPoint);
240 sb.Append(") has been blocked from the system.");
241 }
242 else
243 {
244 sb.Append("Too many failed login attempts in a row registered. Try again after ");
245 sb.Append(TP.ToLongTimeString());
246
247 if (TP.Date != Today)
248 {
249 if (TP.Date == Today.AddDays(1))
250 sb.Append(" tomorrow");
251 else
252 {
253 sb.Append(", ");
254 sb.Append(TP.ToShortDateString());
255 }
256 }
257
258 sb.Append(". Remote Endpoint: ");
259 sb.Append(Request.RemoteEndPoint);
260 }
261
262 await Response.SendResponse(new TooManyRequestsException(sb.ToString()));
263 return;
264 }
265 }
266 else
267 {
268 if (!XmppClient.BareJidRegEx.IsMatch(LegalId))
269 {
270 await Response.SendResponse(new BadRequestException("Invalid Legal ID reference."));
271 return;
272 }
273
274 if (Signature is null && !string.IsNullOrEmpty(LegalId))
275 {
276 if (string.IsNullOrEmpty(SignatureStr))
277 {
278 await Response.SendResponse(new BadRequestException("Missing signature."));
279 return;
280 }
281
282 try
283 {
284 Signature = Convert.FromBase64String(SignatureStr);
285 }
286 catch (Exception)
287 {
288 await Response.SendResponse(new BadRequestException("Invalid signature."));
289 return;
290 }
291 }
292 }
293
294 this.ProcessRequest(Request, Response, PNr, Country, Timeout, Reason, LegalId, Signature);
295 }
296
297 private async void ProcessRequest(HttpRequest Request, HttpResponse Response,
298 string PNr, string Country, int Timeout, string Reason, string LegalId,
299 byte[] Signature)
300 {
301 try
302 {
303 // TODO
304 }
305 catch (Exception ex)
306 {
307 await Response.SendResponse(ex);
308 }
309 }
310
311 }
312}
Contains personal information found in a legal identity.
const string CountryTag
COUNTRY
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 LoginAuditor LoginAuditor
Current Login Auditor. Should be used by modules accepting user logins, to protect the system from un...
Definition: Gateway.cs:3860
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...
Base class for all asynchronous HTTP resources. An asynchronous resource responds outside of the meth...
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
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...
The requested resource resides temporarily under a different URI. Since the redirection MAY be altere...
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...
Manages an XMPP client connection. Implements XMPP, as defined in https://tools.ietf....
Definition: XmppClient.cs:58
static readonly Regex BareJidRegEx
Regular expression for Bare JIDs
Definition: XmppClient.cs:187
static async Task< bool > SiteVerify(string RecaptchaResponse, string RemoteEndPoint)
Allows web pages and web services to verify that Google reCaptcha responses are valid.
Definition: Feedback.cs:166
GET Interface for HTTP resources.
POST Interface for HTTP resources.