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 System;
2using System.Collections.Generic;
3using System.Text;
4using System.Threading.Tasks;
5using System.Xml;
10
12{
17 {
19 : base("/MFA")
20 {
21 }
22
26 public override bool HandlesSubPaths => false;
27
31 public override bool UserSessions => false;
32
36 public bool AllowsPOST => true;
37
41 public bool AllowsGET => true;
42
49 public Task GET(HttpRequest Request, HttpResponse Response)
50 {
51 throw new TemporaryRedirectException("/MFATestForm.md");
52 }
53
60 public async Task POST(HttpRequest Request, HttpResponse Response)
61 {
62 if (!Request.HasData)
63 throw new BadRequestException("No data provided in post.");
64
65 object Obj = await Request.DecodeDataAsync();
66 string PNr;
67 string Country;
68 string TimeoutStr;
69 string Reason;
70 string LegalId;
71 string SignatureStr;
72 byte[] Signature = null;
73 int Timeout = 0;
74 bool HasTimeout = false;
75
76 if (Obj is XmlDocument Xml)
77 {
78 PNr = Xml.DocumentElement["PNR"]?.InnerText;
79 Country = Xml.DocumentElement["COUNTRY"]?.InnerText;
80 TimeoutStr = Xml.DocumentElement["Timeout"]?.InnerText;
81 Reason = Xml.DocumentElement["Reason"]?.InnerText;
82 LegalId = Xml.DocumentElement["LegalId"]?.InnerText;
83 SignatureStr = Xml.DocumentElement["Signature"]?.InnerText;
84 }
85 else if (Obj is Dictionary<string, object> Json)
86 {
87 if (Json.TryGetValue("PNR", out object v))
88 PNr = v.ToString();
89 else
90 PNr = null;
91
92 if (Json.TryGetValue("COUNTRY", out v))
93 Country = v.ToString();
94 else
95 Country = null;
96
97 if (Json.TryGetValue("Timeout", out v))
98 {
99 if (v is int i)
100 {
101 Timeout = i;
102 HasTimeout = true;
103 TimeoutStr = null;
104 }
105 else if (v is string s)
106 TimeoutStr = s;
107 else
108 TimeoutStr = v.ToString();
109 }
110 else
111 TimeoutStr = null;
112
113 if (Json.TryGetValue("Reason", out v))
114 Reason = v.ToString();
115 else
116 Reason = null;
117
118 if (Json.TryGetValue("LegalId", out v))
119 LegalId = v.ToString();
120 else
121 LegalId = null;
122
123 if (Json.TryGetValue("Signature", out v))
124 {
125 if (v is byte[] Bin)
126 {
127 Signature = Bin;
128 SignatureStr = null;
129 }
130 else
131 SignatureStr = v.ToString();
132 }
133 else
134 SignatureStr = null;
135 }
136 else if (Obj is Dictionary<string, string> Form)
137 {
138 if (!Form.TryGetValue("PNR", out PNr))
139 PNr = null;
140
141 if (!Form.TryGetValue("COUNTRY", out Country))
142 Country = null;
143
144 if (!Form.TryGetValue("Timeout", out TimeoutStr))
145 TimeoutStr = null;
146
147 if (!Form.TryGetValue("Reason", out Reason))
148 Reason = null;
149
150 if (!Form.TryGetValue("LegalId", out LegalId))
151 LegalId = null;
152
153 if (!Form.TryGetValue("Signature", out SignatureStr))
154 SignatureStr = null;
155
156 if (Form.TryGetValue("g-recaptcha-response", out string RecaptchaResponse))
157 {
158 if (!await Feedback.SiteVerify(RecaptchaResponse, Request.RemoteEndPoint))
159 throw new ForbiddenException("Request not properly verified. Bot?");
160 }
161 else if (string.IsNullOrEmpty(LegalId))
162 throw new ForbiddenException("Request not properly verified. Bot?");
163 }
164 else
165 throw new UnsupportedMediaTypeException("Unsupported Request Content-Type encoding used.");
166
167 if (string.IsNullOrEmpty(PNr))
168 throw new BadRequestException("Invalid PNR.");
169
170 if (string.IsNullOrEmpty(Country))
171 throw new BadRequestException("Invalid COUNTRY.");
172
173 if (string.IsNullOrEmpty(Reason))
174 throw new BadRequestException("Invalid Reason.");
175
176 if (!HasTimeout)
177 {
178 if (TimeoutStr is null || !int.TryParse(TimeoutStr, out Timeout))
179 throw new BadRequestException("Invalid timeout.");
180 }
181
182 if (Timeout <= 0 || Timeout > 300)
183 throw new BadRequestException("Invalid timeout.");
184
185 if (string.IsNullOrEmpty(LegalId))
186 {
187 if (!(Signature is null) || !string.IsNullOrEmpty(SignatureStr))
188 throw new BadRequestException("Missing legal identity.");
189
190 DateTime? Next = await Gateway.LoginAuditor.GetEarliestLoginOpportunity(Request.RemoteEndPoint, "HTTP");
191
192 if (Next.HasValue)
193 {
194 StringBuilder sb = new StringBuilder();
195 DateTime TP = Next.Value;
196 DateTime Today = DateTime.Today;
197
198 if (Next.Value == DateTime.MaxValue)
199 {
200 sb.Append("This endpoint (");
201 sb.Append(Request.RemoteEndPoint);
202 sb.Append(") has been blocked from the system.");
203 }
204 else
205 {
206 sb.Append("Too many failed login attempts in a row registered. Try again after ");
207 sb.Append(TP.ToLongTimeString());
208
209 if (TP.Date != Today)
210 {
211 if (TP.Date == Today.AddDays(1))
212 sb.Append(" tomorrow");
213 else
214 {
215 sb.Append(", ");
216 sb.Append(TP.ToShortDateString());
217 }
218 }
219
220 sb.Append(". Remote Endpoint: ");
221 sb.Append(Request.RemoteEndPoint);
222 }
223
224 throw new TooManyRequestsException(sb.ToString());
225 }
226 }
227 else
228 {
229 if (!XmppClient.BareJidRegEx.IsMatch(LegalId))
230 throw new BadRequestException("Invalid Legal ID reference.");
231
232 if (Signature is null && !string.IsNullOrEmpty(LegalId))
233 {
234 if (string.IsNullOrEmpty(SignatureStr))
235 throw new BadRequestException("Missing signature.");
236
237 try
238 {
239 Signature = Convert.FromBase64String(SignatureStr);
240 }
241 catch (Exception)
242 {
243 throw new BadRequestException("Invalid signature.");
244 }
245 }
246 }
247
248 this.ProcessRequest(Request, Response, PNr, Country, Timeout, Reason, LegalId, Signature);
249 }
250
251 private async void ProcessRequest(HttpRequest Request, HttpResponse Response,
252 string PNr, string Country, int Timeout, string Reason, string LegalId,
253 byte[] Signature)
254 {
255 try
256 {
257 // TODO
258 }
259 catch (Exception ex)
260 {
261 await Response.SendResponse(ex);
262 }
263 }
264
265 }
266}
Static class managing the runtime environment of the IoT Gateway.
Definition: Gateway.cs:126
static LoginAuditor LoginAuditor
Current Login Auditor. Should be used by modules accepting user logins, to protect the system from un...
Definition: Gateway.cs:3033
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:18
string RemoteEndPoint
Remote end-point.
Definition: HttpRequest.cs:195
bool HasData
If the request has data.
Definition: HttpRequest.cs:74
async Task< object > DecodeDataAsync()
Decodes data sent in request.
Definition: HttpRequest.cs:95
Represets a response of an HTTP client request.
Definition: HttpResponse.cs:21
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:59
static readonly Regex BareJidRegEx
Regular expression for Bare JIDs
Definition: XmppClient.cs:188
GET Interface for HTTP resources.
POST Interface for HTTP resources.