// This method will be invoked as a call-back from an authentication service (e.g., https://login.windows.net/). // It is not intended to be called directly, only as a redirect from the authorization request. // On completion, the method will cache the refresh token and access tokens, and redirect to the URL // specified in the state parameter. public async Task <HttpResponseMessage> Get(string code, string state) // TODO async here is not being awaited anywhere... { using (var system = CreateRequestSystemExecutionContext()) { // NOTE: In production, OAuth must be done over a secure HTTPS connection. if (Request.RequestUri.Scheme != "https" && !Request.RequestUri.IsLoopback) { return(Get("Endpoint is not HTTPS")); } // Ensure there is a state value on the response. If there is none, stop OAuth processing and display an error. if (state == null) { return(Get("No state was returned from authenticator")); } if (code == null) { return(Get("No code was returned from authenticator")); } var stateObject = ValidateState(system, state); if (stateObject == null) { system.Log.Error(new { code, state }, () => "No state found in CluedIn"); return(Get("No state found in CluedIn")); } // Try to exchange code for accessToken try { // setup and execute request var consumerKey = ConfigurationManager.AppSettings["Providers.Crawlers.GoToMeeting.ConsumerKey"]; // "jY1OXMsPFncSNL0X2sgx0nAg8V6102OY" var consumerSecret = ConfigurationManager.AppSettings["Providers.Crawlers.GoToMeeting.ConsumerSecret"]; // "ImnwFc5ARzKTpirn" var oauth2api = new OAuth2Api(consumerKey, consumerSecret); var responseKey = code; var tokenResponse = oauth2api.GetAccessTokenResponse(responseKey); var accessToken = tokenResponse.access_token; var refreshToken = tokenResponse.refresh_token; var expires = tokenResponse.expires_in; using (var context = this.CreateRequestExecutionContext(stateObject.OrganizationId)) { var tokenStore = context.Organization.DataStores.GetDataStore <Token>(); if (tokenStore == null) { return(Get("Could not access token store")); } var GoToMeetingProviderId = GoToMeetingConstants.ProviderId; //////////////// // Token check 1 //////////////// NoAccountIdCheck(tokenStore, context, GoToMeetingProviderId, stateObject); //////////////// // Token check 2 //////////////// var accountId = string.Empty; CheckForExistingToken(tokenStore, context, GoToMeetingProviderId, stateObject, accountId); bool reAuthenticated = false; //Check if you are just needing to re-authenticate var reAuthenticateCheck = tokenStore.Select(context, t => t.ProviderId == GoToMeetingProviderId && t.AccountId == accountId && t.UserId == stateObject.UserId).ToList(); if (reAuthenticateCheck.Any()) { var newTokenResponse = oauth2api.GetAccessTokenUsingRefreshToken(refreshToken); var token = tokenStore.GetById(context, reAuthenticateCheck.First().Id); token.AccessToken = newTokenResponse.access_token; token.RefreshToken = newTokenResponse.refresh_token; token.ExpiresIn = int.Parse(expires); token.AccessTokenCreationDate = DateTimeOffset.UtcNow; tokenStore.Update(context, token); reAuthenticated = true; context.Organization.Providers.ClearProviderDefinitionAuthenticationError(context, token.ConfigurationId.Value); context.Log.Info(() => "ReAuthentication Token for GoToMeeting", reAuthenticateCheck.First().Id); } else { tokenStore.Insert(context, new Token(context) { Id = Guid.NewGuid(), OrganizationId = stateObject.OrganizationId, UserId = stateObject.UserId, AccessToken = accessToken, RefreshToken = refreshToken, ExpiresIn = int.Parse(expires), ProviderId = GoToMeetingProviderId, AccessTokenCreationDate = DateTimeOffset.UtcNow, AccountId = accountId, ConfigurationId = null }); context.Log.Info(() => "Inserting Token for GoToMeeting", accountId); } // Return to the originating page where the user triggered the sign-in var response = Request.CreateResponse(HttpStatusCode.OK); var organization = context.Organization; // TODO: Get base url from config if (ConfigurationManager.AppSettings.GetFlag("NewRedirectUrl", false)) { response.Content = new StringContent(string.Format("<script>window.location = \"https://{0}.{1}/admin/integrations/callback/gotomeeting\";</script>", organization.ApplicationSubDomain, ConfigurationManager.AppSettings["Domain"]), Encoding.UTF8, "text/html"); if (reAuthenticated) { response.Content = new StringContent(string.Format("<script>window.location = \"https://{0}.{1}/\";</script>", organization.ApplicationSubDomain, ConfigurationManager.AppSettings["Domain"]), Encoding.UTF8, "text/html"); return(response); } } else { // TODO: Get base url from config response.Content = new StringContent(string.Format("<script>window.location = \"https://{0}.{1}/admin/#/administration/integration/gotomeeting/callback\";</script>", context.Organization.ApplicationSubDomain, ConfigurationManager.AppSettings["Domain"]), Encoding.UTF8, "text/html"); if (reAuthenticated) { response.Content = new StringContent(string.Format("<script>window.location = \"https://{0}.{1}/\";</script>", organization.ApplicationSubDomain, ConfigurationManager.AppSettings["Domain"]), Encoding.UTF8, "text/html"); return(response); } } return(response); } } catch (Exception exception) { system.Log.Warn(() => "Could not exchange the GoToMeeting code for an Access Token", exception); return(Get("Could not exchange the GoToMeeting code for an Access Token")); } } }