Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
QuickLoginRemoteAuthentication.cs
1using Paiwise;
2using System;
4using System.Text;
5using System.Threading.Tasks;
6using Waher.Events;
11
13{
17 internal class QuickLoginRemoteAuthentication : IRemoteAuthentication
18 {
19 private readonly string sessionId;
20 private readonly bool usesChallengeUri;
21 private XmppAddress address;
22 private string serviceId;
23 private string[] domainParts;
24 private string jid;
25 private string legalId;
26 private string domain;
27 private string subject;
28 private bool hasLegalId;
29 private bool hasJid;
30 private EventHandlerAsync<RemoteAuthenticationEventArgs> callback;
31 private object state;
32
38 public QuickLoginRemoteAuthentication(string Jid, string LegalId)
39 {
40 this.jid = Jid;
41 this.legalId = LegalId;
42
43 this.hasLegalId = !string.IsNullOrEmpty(this.legalId);
44 this.hasJid = !string.IsNullOrEmpty(this.jid);
45 this.usesChallengeUri = !(this.hasLegalId || this.hasJid);
46
47 if (this.hasLegalId)
48 {
49 this.sessionId = this.legalId;
50 this.serviceId = null;
51 }
52 else if (this.hasJid)
53 {
54 this.sessionId = this.jid;
55 this.serviceId = null;
56 }
57 else
58 {
59 this.sessionId = Guid.NewGuid().ToString();
60 this.serviceId = QuickLogin.GetServiceID(this.sessionId);
61 }
62 }
63
67 public string Key => this.sessionId;
68
73 public Task<bool> IsValidAddress()
74 {
75 if (this.usesChallengeUri)
76 return Task.FromResult(true);
77
78 if (!(this.hasLegalId || this.hasJid))
79 return Task.FromResult(false);
80
81 this.address = new XmppAddress(this.hasLegalId ? this.legalId : this.jid);
82 if (!this.address.IsBareJID)
83 return Task.FromResult(false);
84
85 this.domain = this.address.Domain;
86
87 int i = this.domain.IndexOf('.');
88 if (i < 0 || i >= this.domain.Length - 1)
89 return Task.FromResult(false);
90
91 if (this.hasLegalId)
92 {
93 if (!Guid.TryParse(this.address.Account, out _))
94 return Task.FromResult(false);
95
96 this.domain = this.domain[(i + 1)..];
97 this.subject = this.legalId;
98 }
99 else
100 this.subject = this.jid;
101
102 this.domainParts = this.domain.Split('.');
103
104 return Task.FromResult(true);
105 }
106
111 public async Task<bool> IsLegalIdAvailable()
112 {
113 if (this.usesChallengeUri)
114 return true;
115
116 if (this.hasLegalId)
117 return true;
118
119 if (this.address is null)
120 return false;
121
122 string[] Identities = await XmppServerModule.Legal.GetIdentityReferences(this.address);
123 if (Identities.Length == 0)
124 return false;
125
126 this.legalId = Identities[0];
127 this.hasLegalId = true;
128
129 return true;
130 }
131
137 public Task<bool> IsPermitted(IUser User)
138 {
139 if (this.usesChallengeUri)
140 return Task.FromResult(true);
141
142 int i, c = this.domainParts?.Length ?? 0;
143
144 StringBuilder sb = new StringBuilder();
145 sb.Append(nameof(RemoteLogin));
146 sb.Append(".Domain");
147
148 for (i = c - 1; i >= 0; i--)
149 {
150 sb.Append('.');
151 sb.Append(this.domainParts[i]);
152 }
153
154 string Privilege = sb.ToString();
155
156 return Task.FromResult(User.HasPrivilege(Privilege));
157 }
158
170 public Task<Uri> GetChallengeUri(string Purpose, string RemoteEndPoint)
171 {
172 if (!this.usesChallengeUri)
173 return Task.FromResult<Uri>(null);
174
175 if (string.IsNullOrEmpty(this.serviceId))
176 this.serviceId = QuickLogin.GetServiceID(this.sessionId);
177
178 string TagSignUrl = QuickLogin.GetTagSignUri(string.Empty,
179 this.serviceId, Purpose, RemoteEndPoint, null, null,
180 this.QuickLoginCallback, null);
181
182 if (string.IsNullOrEmpty(TagSignUrl))
183 return null;
184
185 string Url = Gateway.GetUrl("/QR/" + TagSignUrl);
186
187 if (Uri.TryCreate(Url, UriKind.Absolute, out Uri Result))
188 return Task.FromResult(Result);
189 else
190 return Task.FromResult<Uri>(null);
191 }
192
203 public async Task<string> Start(string Purpose, string RemoteEndPoint,
204 EventHandlerAsync<RemoteAuthenticationEventArgs> Callback, object State)
205 {
206 if (this.usesChallengeUri)
207 {
208 this.callback = Callback;
209 this.state = State;
210
211 return this.sessionId;
212 }
213
214 string PetitionId = await QuickLogin.StartQuickLogin(this.legalId, Purpose,
215 null, null, RemoteEndPoint, async (sender, e) =>
216 {
218
219 if (e.Ok)
220 {
221 if (e.Response && !(e.RequestedIdentity is null))
222 {
223 e2 = new RemoteAuthenticationEventArgs(e.State,
224 new KeyValuePair<string, object>(JwtClaims.ClientId, e.RequestedIdentity.Id),
225 new KeyValuePair<string, object>(JwtClaims.Subject, this.subject));
226
227 if (!this.hasJid)
228 {
229 string Jid = e.RequestedIdentity[PersonalInformation.JidTag];
230
231 if (!string.IsNullOrEmpty(Jid))
232 {
233 this.jid = Jid;
234 this.hasJid = true;
235 }
236 }
237 }
238 else
239 e2 = new RemoteAuthenticationEventArgs(e.State, "Remote API Login rejected.", true);
240 }
241 else
242 {
243 e2 = new RemoteAuthenticationEventArgs(e.State, "Remote API Login failed: " + e.ErrorText,
244 !(e.StanzaError is Networking.XMPP.StanzaErrors.RecipientUnavailableException));
245 }
246
247 await Callback.Raise(this, e2);
248
249 }, State);
250
251 return PetitionId;
252 }
253
254 private async Task QuickLoginCallback(object Sender, QuickLoginResponseEventArgs e)
255 {
256 EventHandlerAsync<RemoteAuthenticationEventArgs> Callback = this.callback;
258 object State = this.state;
259
260 if (Callback is null)
261 return;
262
263 this.callback = null;
264 this.state = null;
265
266 if (e.Ok)
267 {
268 if (e.Response && !(e.RequestedIdentity is null))
269 {
270 this.subject = e.RequestedIdentity.Id;
271
272 e2 = new RemoteAuthenticationEventArgs(e.State,
273 new KeyValuePair<string, object>(JwtClaims.ClientId, e.RequestedIdentity.Id),
274 new KeyValuePair<string, object>(JwtClaims.Subject, this.subject));
275
276 if (!this.hasJid)
277 {
278 string Jid = e.RequestedIdentity[PersonalInformation.JidTag];
279
280 if (!string.IsNullOrEmpty(Jid))
281 {
282 this.jid = Jid;
283 this.hasJid = true;
284 }
285 }
286 }
287 else
288 e2 = new RemoteAuthenticationEventArgs(e.State, "Remote API Login rejected.", true);
289 }
290 else
291 {
292 e2 = new RemoteAuthenticationEventArgs(e.State, "Remote API Login failed: " + e.ErrorText,
293 !(e.StanzaError is Networking.XMPP.StanzaErrors.RecipientUnavailableException));
294 }
295
296 await Callback.Raise(this, e2);
297 }
298 }
299}
Contains personal information found in a legal identity.
Event arguments for Remote Authentication callback methods.
Static class managing the runtime environment of the IoT Gateway.
Definition: Gateway.cs:147
static string GetUrl(string LocalResource)
Gets a URL for a resource.
Definition: Gateway.cs:5079
Contains information about one XMPP address.
Definition: XmppAddress.cs:9
override string ToString()
object.ToString()
Definition: XmppAddress.cs:190
bool IsBareJID
If the address is a Bare JID.
Definition: XmppAddress.cs:159
CaseInsensitiveString Domain
Domain
Definition: XmppAddress.cs:97
Static class containing predefined JWT claim names.
Definition: JwtClaims.cs:10
const string Subject
Subject of the JWT (the user)
Definition: JwtClaims.cs:19
const string ClientId
Client identifier
Definition: JwtClaims.cs:154
Interface for remote authentications.
bool HasPrivilege(string Privilege)
If the object has a given privilege.
Basic interface for a user.
Definition: IUser.cs:7
Definition: ImplTypes.g.cs:58