/// <summary> /// Called when a profile requests user authorization /// </summary> /// <param name="authenticating_instance">Authenticating instance</param> /// <param name="e"><see cref="RequestAuthorization"/> event arguments</param> public void OnRequestAuthorization(Instance authenticating_instance, RequestAuthorizationEventArgs e) { RequestAuthorization?.Invoke(authenticating_instance, e); }
/// <summary> /// Gets instance profile list available to the user /// </summary> /// <param name="authenticating_instance">Authenticating instance (can be same as this instance)</param> /// <param name="ct">The token to monitor for cancellation requests</param> /// <returns>Profile list</returns> public ObservableCollection <Profile> GetProfileList(Instance authenticating_instance, CancellationToken ct = default(CancellationToken)) { lock (_profile_list_lock) { if (_profile_list == null) { // Get API endpoints. var api = GetEndpoints(ct); var e = new RequestAuthorizationEventArgs("config"); retry: // Request authentication token. OnRequestAuthorization(authenticating_instance, e); if (e.AccessToken == null) { throw new AccessTokenNullException(); } try { // Get and load profile list. var profile_list = new ObservableCollection <Profile>(); profile_list.LoadJSONAPIResponse(Xml.Response.Get( uri: api.ProfileList, token: e.AccessToken, ct: ct).Value, "profile_list", ct); foreach (var profile in profile_list) { // Bind profile to our instance. profile.Instance = this; // Attach to RequestAuthorization profile events. profile.RequestAuthorization += (object sender_profile, RequestAuthorizationEventArgs e_profile) => OnRequestAuthorization(authenticating_instance, e_profile); } // If we got here, save the profile list. _profile_list = profile_list; } catch (OperationCanceledException) { throw; } catch (WebException ex) { if (ex.Response is HttpWebResponse response && response.StatusCode == HttpStatusCode.Unauthorized) { // Access token was rejected (401 Unauthorized). if (e.TokenOrigin == RequestAuthorizationEventArgs.TokenOriginType.Saved) { // Access token loaded from the settings was rejected. // This might happen when ill-clocked client thinks the token is still valid, but the server expired it already. // Retry with forced access token refresh. e.ForceRefresh = true; } else { // Retry with forced authorization, ignoring saved access token completely. e.SourcePolicy = RequestAuthorizationEventArgs.SourcePolicyType.ForceAuthorization; } goto retry; } else { throw new AggregateException(Resources.Strings.ErrorProfileListLoad, ex); } }
/// <summary> /// Gets server profile list available to the user /// </summary> /// <param name="authenticatingServer">Authenticating server (can be same as this server)</param> /// <param name="ct">The token to monitor for cancellation requests</param> /// <returns>Profile list</returns> public ObservableCollection <Profile> GetProfileList(Server authenticatingServer, CancellationToken ct = default) { lock (ProfilesLock) { if (Profiles != null) { return(Profiles); } // Get API endpoints. var api = GetEndpoints(ct); var e = new RequestAuthorizationEventArgs("config"); retry: // Request authentication token. OnRequestAuthorization(authenticatingServer, e); try { // Parse JSON string and get inner key/value dictionary. Trace.TraceInformation("Loading info {0}", api.Info); var obj = eduJSON.Parser.GetValue <Dictionary <string, object> >( (Dictionary <string, object>)eduJSON.Parser.Parse(Xml.Response.Get( uri: api.Info, token: e.AccessToken, ct: ct).Value, ct), "info"); // Load collection. if (!eduJSON.Parser.GetValue(obj, "profile_list", out List <object> obj2)) { throw new eduJSON.InvalidParameterTypeException(nameof(obj2), typeof(Dictionary <string, object>), obj.GetType()); } // Parse all items listed. Don't do it in parallel to preserve the sort order. var profileList = new ObservableCollection <Profile>(); foreach (var el in obj2) { var profile = new Profile(this); profile.Load(el); // Attach to RequestAuthorization profile events. profile.RequestAuthorization += (object sender_profile, RequestAuthorizationEventArgs e_profile) => OnRequestAuthorization(authenticatingServer, e_profile); profileList.Add(profile); } return(Profiles = profileList); } catch (OperationCanceledException) { throw; } catch (WebException ex) { if (ex.Response is HttpWebResponse response && response.StatusCode == HttpStatusCode.Unauthorized) { // Access token was rejected (401 Unauthorized). if (e.TokenOrigin == RequestAuthorizationEventArgs.TokenOriginType.Saved) { // Access token loaded from the settings was rejected. // This might happen when ill-clocked client thinks the token is still valid, but the server expired it already. // Or the token was revoked on the server side. // Retry with forced access token refresh. e.SourcePolicy = RequestAuthorizationEventArgs.SourcePolicyType.ForceAuthorization; goto retry; } } if (ex is WebExceptionEx exEx && ex.Response.ContentType == "application/json") { var obj = (Dictionary <string, object>)eduJSON.Parser.Parse(exEx.ResponseText, ct); throw new AggregateException(Resources.Strings.ErrorProfileListLoad + "\n" + eduJSON.Parser.GetValue <string>(obj, "error"), ex); } throw new AggregateException(Resources.Strings.ErrorProfileListLoad, ex); } catch (Exception ex) { throw new AggregateException(Resources.Strings.ErrorProfileListLoad, ex); } } }