/// <summary> /// Token request for refresh /// </summary> public OAuthTokenRequest(TokenClaimsPrincipal current, String scope) { this.GrantType = "refresh_token"; this.RefreshToken = current.RefreshToken; this.Scope = scope; }
/// <summary> /// Authenticate the user /// </summary> /// <param name="principal">Principal.</param> /// <param name="password">Password.</param> public System.Security.Principal.IPrincipal Authenticate(System.Security.Principal.IPrincipal principal, string password, String tfaSecret) { AuthenticatingEventArgs e = new AuthenticatingEventArgs(principal.Identity.Name, password) { Principal = principal }; this.Authenticating?.Invoke(this, e); if (e.Cancel) { this.m_tracer.TraceWarning("Pre-Event ordered cancel of auth {0}", principal); return(e.Principal); } var localIdp = new LocalIdentityService(); // Get the scope being requested String scope = "*"; if (principal is ClaimsPrincipal) { scope = (principal as ClaimsPrincipal).Claims.FirstOrDefault(o => o.Type == ClaimTypes.OpenIzScopeClaim)?.Value ?? scope; } else if (principal is SQLitePrincipal && password == null) { return(localIdp.Authenticate(principal, password)); } else { scope = ApplicationContext.Current.GetRestClient("imsi")?.Description.Endpoint[0].Address ?? ApplicationContext.Current.GetRestClient("ami")?.Description.Endpoint[0].Address ?? "*"; } // Authenticate IPrincipal retVal = null; try { using (IRestClient restClient = ApplicationContext.Current.GetRestClient("acs")) { try { // Set credentials restClient.Credentials = new OAuthTokenServiceCredentials(principal); // Create grant information OAuthTokenRequest request = null; if (!String.IsNullOrEmpty(password)) { request = new OAuthTokenRequest(principal.Identity.Name, password, scope); } else if (principal is TokenClaimsPrincipal) { request = new OAuthTokenRequest(principal as TokenClaimsPrincipal, scope); } else { request = new OAuthTokenRequest(principal.Identity.Name, null, scope); } try { restClient.Requesting += (o, p) => { p.AdditionalHeaders.Add("X-OpenIZClient-Claim", Convert.ToBase64String(Encoding.UTF8.GetBytes(String.Format("{0}={1}", ClaimTypes.OpenIzScopeClaim, scope)))); if (!String.IsNullOrEmpty(tfaSecret)) { p.AdditionalHeaders.Add("X-OpenIZ-TfaSecret", tfaSecret); } }; // Invoke if (ApplicationContext.Current.GetService <INetworkInformationService>().IsNetworkAvailable) { if (principal.Identity.Name == ApplicationContext.Current.Configuration.GetSection <SecurityConfigurationSection>().DeviceName) { restClient.Description.Endpoint[0].Timeout = restClient.Description.Endpoint[0].Timeout * 2; } else { restClient.Description.Endpoint[0].Timeout = (int)(restClient.Description.Endpoint[0].Timeout * 0.6666f); } OAuthTokenResponse response = restClient.Post <OAuthTokenRequest, OAuthTokenResponse>("oauth2_token", "application/x-www-urlform-encoded", request); retVal = new TokenClaimsPrincipal(response.AccessToken, response.TokenType, response.RefreshToken); } else { this.m_tracer.TraceWarning("Network unavailable, trying local"); try { retVal = localIdp.Authenticate(principal, password); } catch (Exception ex2) { this.m_tracer.TraceError("Error falling back to local IDP: {0}", ex2); throw new SecurityException(String.Format(Strings.err_offline_use_cache_creds, ex2.Message), ex2); } } this.Authenticated?.Invoke(this, new AuthenticatedEventArgs(principal.Identity.Name, password, true) { Principal = retVal }); } catch (WebException ex) // Raw level web exception { // Not network related, but a protocol level error if (ex.Status == WebExceptionStatus.ProtocolError) { throw; } this.m_tracer.TraceWarning("Original OAuth2 request failed trying local. {0}", ex.Message); try { retVal = localIdp.Authenticate(principal, password); } catch (Exception ex2) { this.m_tracer.TraceError("Error falling back to local IDP: {0}", ex2); throw new SecurityException(String.Format(Strings.err_offline_use_cache_creds, ex2.Message), ex2); } } catch (SecurityException ex) { this.m_tracer.TraceError("Server was contacted however the token is invalid: {0}", ex.Message); throw; } catch (Exception ex) // fallback to local { try { this.m_tracer.TraceWarning("Original OAuth2 request failed trying local. {0}", ex.Message); retVal = localIdp.Authenticate(principal, password); } catch (Exception ex2) { this.m_tracer.TraceError("Error falling back to local IDP: {0}", ex2); throw new SecurityException(String.Format(Strings.err_offline_use_cache_creds, ex2.Message), ex2); } } // We have a match! Lets make sure we cache this data // TODO: Clean this up try { if (!(retVal is SQLitePrincipal)) { ApplicationContext.Current.GetService <IThreadPoolService>().QueueUserWorkItem(o => this.SynchronizeSecurity(password, o as IPrincipal), retVal); } } catch (Exception ex) { try { this.m_tracer.TraceWarning("Failed to fetch remote security parameters - {0}", ex.Message); retVal = localIdp.Authenticate(principal, password); } catch (Exception ex2) { this.m_tracer.TraceError("Error falling back to local IDP: {0}", ex2); throw new SecurityException(String.Format(Strings.err_offline_use_cache_creds, ex2.Message)); } } } catch (RestClientException <OAuthTokenResponse> ex) { this.m_tracer.TraceError("REST client exception: {0}", ex.Message); var se = new SecurityException( String.Format("err_oauth2_{0}", ex.Result.Error), ex ); se.Data.Add("detail", ex.Result); throw se; } catch (SecurityTokenException ex) { this.m_tracer.TraceError("TOKEN exception: {0}", ex.Message); throw new SecurityException( String.Format("err_token_{0}", ex.Type), ex ); } catch (SecurityException ex) { this.m_tracer.TraceError("Security exception: {0}", ex.Message); throw; } catch (Exception ex) { this.m_tracer.TraceError("Generic exception: {0}", ex); throw new SecurityException( Strings.err_authentication_exception, ex); } } } catch { this.Authenticated?.Invoke(this, new AuthenticatedEventArgs(principal.Identity.Name, password, false) { Principal = retVal }); throw; } return(retVal); }