public TerminalDO RegisterOrUpdate(TerminalDO terminalDo, bool isUserInitiated) { if (terminalDo == null) { return(null); } if (!IsATandTCacheDisabled) { Initialize(); } // we are going to change activityTemplateDo. It is not good to corrupt method's input parameters. // make a copy var clone = new TerminalDO(); CopyPropertiesHelper.CopyProperties(terminalDo, clone, true); terminalDo = clone; lock (_terminals) { var doRegisterTerminal = false; TerminalDO terminal, existingTerminal; using (var uow = ObjectFactory.GetInstance <IUnitOfWork>()) { if (terminalDo.Id == Guid.Empty) { terminalDo.Id = Guid.NewGuid(); uow.TerminalRepository.Add(terminalDo); doRegisterTerminal = true; existingTerminal = terminalDo; } else { existingTerminal = uow.TerminalRepository.FindOne(x => x.Id == terminalDo.Id); // this is for updating terminal CopyPropertiesHelper.CopyProperties(terminalDo, existingTerminal, false, x => x.Name != "Id"); } uow.SaveChanges(); terminal = Clone(existingTerminal); _terminals[existingTerminal.Id] = terminal; } if (doRegisterTerminal) { if (isUserInitiated) { //add ownership for this new terminal to current user _securityServices.SetDefaultRecordBasedSecurityForObject(Roles.OwnerOfCurrentObject, terminal.Id, nameof(TerminalDO), new List <PermissionType>() { PermissionType.UseTerminal }); } //make it visible for Fr8 Admins _securityServices.SetDefaultRecordBasedSecurityForObject(Roles.Admin, terminal.Id, nameof(TerminalDO), new List <PermissionType>() { PermissionType.UseTerminal }); } return(terminal); } }
public Dictionary <string, string> GetRequestHeaders(TerminalDO terminal, string userId) { return(new Dictionary <string, string>()); }
public TerminalDO RegisterOrUpdate(TerminalDO terminalDo, bool isUserInitiated) { return(_terminal.RegisterOrUpdate(terminalDo, isUserInitiated)); }
public async Task <AuthenticateResponse> VerifyCodeAndGetAccessToken( Fr8AccountDO account, TerminalDO terminal, string phoneNumber, string verificationCode, string clientId, string clientName) { if (terminal.AuthenticationType == AuthenticationType.None) { throw new WrongAuthenticationTypeException(); } var restClient = ObjectFactory.GetInstance <IRestfulServiceClient>(); var credentialsDTO = new PhoneNumberCredentialsDTO() { PhoneNumber = phoneNumber, ClientId = clientId, VerificationCode = verificationCode, Fr8UserId = account?.Id, ClientName = clientName }; var terminalResponse = await restClient.PostAsync(new Uri(terminal.Endpoint + "/authentication/token"), credentialsDTO); var terminalResponseAuthTokenDTO = JsonConvert.DeserializeObject <AuthorizationTokenDTO>(terminalResponse); if (!string.IsNullOrEmpty(terminalResponseAuthTokenDTO.Error)) { return(new AuthenticateResponse() { Error = terminalResponseAuthTokenDTO.Error }); } if (terminalResponseAuthTokenDTO == null) { return(new AuthenticateResponse() { Error = "An error occured while authenticating, please try again." }); } var curTerminal = _terminalService.GetByKey(terminal.Id); using (var uow = ObjectFactory.GetInstance <IUnitOfWork>()) { var curAccount = uow.UserRepository.GetByKey(account.Id); AuthorizationTokenDO authToken = null; if (!string.IsNullOrEmpty(terminalResponseAuthTokenDTO.ExternalAccountId)) { authToken = uow.AuthorizationTokenRepository .GetPublicDataQuery() .FirstOrDefault(x => x.TerminalID == curTerminal.Id && x.UserID == curAccount.Id && x.ExternalDomainId == terminalResponseAuthTokenDTO.ExternalDomainId && x.ExternalAccountId == terminalResponseAuthTokenDTO.ExternalAccountId && x.AdditionalAttributes == terminalResponseAuthTokenDTO.AdditionalAttributes); } var created = false; if (authToken == null) { authToken = new AuthorizationTokenDO() { Token = terminalResponseAuthTokenDTO.Token, ExternalAccountId = terminalResponseAuthTokenDTO.ExternalAccountId, ExternalAccountName = string.IsNullOrEmpty(terminalResponseAuthTokenDTO.ExternalAccountName) ? terminalResponseAuthTokenDTO.ExternalAccountId : terminalResponseAuthTokenDTO.ExternalAccountName, ExternalDomainId = terminalResponseAuthTokenDTO.ExternalDomainId, ExternalDomainName = string.IsNullOrEmpty(terminalResponseAuthTokenDTO.ExternalDomainName) ? terminalResponseAuthTokenDTO.ExternalDomainId : terminalResponseAuthTokenDTO.ExternalDomainName, TerminalID = curTerminal.Id, UserID = curAccount.Id, AdditionalAttributes = terminalResponseAuthTokenDTO.AdditionalAttributes, }; uow.AuthorizationTokenRepository.Add(authToken); created = true; } else { authToken.Token = terminalResponseAuthTokenDTO.Token; authToken.ExternalAccountId = terminalResponseAuthTokenDTO.ExternalAccountId; authToken.ExternalAccountName = string.IsNullOrEmpty(terminalResponseAuthTokenDTO.ExternalAccountName) ? terminalResponseAuthTokenDTO.ExternalDomainId : terminalResponseAuthTokenDTO.ExternalAccountName; authToken.ExternalDomainId = terminalResponseAuthTokenDTO.ExternalDomainId; authToken.ExternalDomainName = string.IsNullOrEmpty(terminalResponseAuthTokenDTO.ExternalDomainName) ? terminalResponseAuthTokenDTO.ExternalDomainId : terminalResponseAuthTokenDTO.ExternalDomainName; } uow.SaveChanges(); if (created) { EventManager.AuthTokenCreated(authToken); } //if terminal requires Authentication Completed Notification, follow the existing terminal event notification protocol //to notify the terminal about authentication completed event if (terminalResponseAuthTokenDTO.AuthCompletedNotificationRequired) { //let's save id of DTO before informing related terminal terminalResponseAuthTokenDTO.Id = authToken.Id.ToString(); EventManager.TerminalAuthenticationCompleted(curAccount.Id, curTerminal, terminalResponseAuthTokenDTO); } return(new AuthenticateResponse() { AuthorizationToken = Mapper.Map <AuthorizationTokenDTO>(authToken), Error = null }); } }
public async Task <PhoneNumberCredentialsDTO> SendAuthenticationCodeToMobilePhone(Fr8AccountDO account, TerminalDO terminal, string phoneNumber) { if (terminal.AuthenticationType == AuthenticationType.None) { throw new WrongAuthenticationTypeException(); } if (terminal.AuthenticationType != AuthenticationType.PhoneNumberWithCode) { throw new WrongAuthenticationTypeException("Terminal support only authentication through phone number"); } var restClient = ObjectFactory.GetInstance <IRestfulServiceClient>(); var credentialsDTO = new PhoneNumberCredentialsDTO { PhoneNumber = phoneNumber, ClientName = account != null ? account.UserName : "******", Fr8UserId = account?.Id }; var terminalResponse = await restClient.PostAsync(new Uri(terminal.Endpoint + "/authentication/send_code"), credentialsDTO); //response provides terminal var terminalResponseContent = JsonConvert.DeserializeObject <PhoneNumberCredentialsDTO>(terminalResponse); return(terminalResponseContent); }
public async Task <AuthenticateResponse> GetOAuthToken(TerminalDO terminal, ExternalAuthenticationDTO externalAuthDTO) { var hasAuthentication = _activityTemplate.GetQuery().Any(x => x.Terminal.Id == terminal.Id); if (!hasAuthentication) { throw new WrongAuthenticationTypeException(); } var restClient = ObjectFactory.GetInstance <IRestfulServiceClient>(); var response = await restClient.PostAsync( new Uri(terminal.Endpoint + "/authentication/token"), externalAuthDTO, null, _terminalService.GetRequestHeaders(terminal, null)); var authTokenDTO = JsonConvert.DeserializeObject <AuthorizationTokenDTO>(response); if (!string.IsNullOrEmpty(authTokenDTO.Error)) { return(new AuthenticateResponse { Error = authTokenDTO.Error }); } using (var uow = ObjectFactory.GetInstance <IUnitOfWork>()) { var authTokenByExternalState = uow.AuthorizationTokenRepository .FindTokenByExternalState(authTokenDTO.ExternalStateToken, terminal.Id); if (authTokenByExternalState == null) { throw new MissingObjectException($"Authorization token with external state '{authTokenDTO.ExternalStateToken}' doesn't exist"); } var authTokenByExternalAccountId = uow.AuthorizationTokenRepository .FindTokenByExternalAccount( authTokenDTO.ExternalAccountId, terminal.Id, authTokenByExternalState.UserID); if (authTokenByExternalAccountId != null) { authTokenByExternalAccountId.Token = authTokenDTO.Token; authTokenByExternalState.ExternalAccountId = authTokenDTO.ExternalAccountId; authTokenByExternalState.ExternalAccountName = string.IsNullOrEmpty(authTokenDTO.ExternalAccountName) ? authTokenDTO.ExternalAccountId : authTokenDTO.ExternalAccountName; authTokenByExternalState.ExternalDomainId = authTokenDTO.ExternalDomainId; authTokenByExternalState.ExternalDomainName = string.IsNullOrEmpty(authTokenDTO.ExternalDomainName) ? authTokenDTO.ExternalDomainId : authTokenDTO.ExternalDomainName; authTokenByExternalAccountId.ExternalStateToken = null; authTokenByExternalState.AdditionalAttributes = authTokenDTO.AdditionalAttributes; authTokenByExternalState.ExpiresAt = authTokenDTO.ExpiresAt; if (authTokenByExternalState != null) { uow.AuthorizationTokenRepository.Remove(authTokenByExternalState); } EventManager.AuthTokenCreated(authTokenByExternalAccountId); } else { authTokenByExternalState.Token = authTokenDTO.Token; authTokenByExternalState.ExternalAccountId = authTokenDTO.ExternalAccountId; authTokenByExternalState.ExternalAccountName = string.IsNullOrEmpty(authTokenDTO.ExternalAccountName) ? authTokenDTO.ExternalAccountId : authTokenDTO.ExternalAccountName; authTokenByExternalState.ExternalDomainId = authTokenDTO.ExternalDomainId; authTokenByExternalState.ExternalDomainName = string.IsNullOrEmpty(authTokenDTO.ExternalDomainName) ? authTokenDTO.ExternalDomainId : authTokenDTO.ExternalDomainName; authTokenByExternalState.ExternalStateToken = null; authTokenByExternalState.AdditionalAttributes = authTokenDTO.AdditionalAttributes; authTokenByExternalState.ExpiresAt = authTokenDTO.ExpiresAt; EventManager.AuthTokenCreated(authTokenByExternalState); } uow.SaveChanges(); return(new AuthenticateResponse { AuthorizationToken = Mapper.Map <AuthorizationTokenDTO>(authTokenByExternalAccountId ?? authTokenByExternalState), Error = null }); } }
public async Task <AuthenticateResponse> AuthenticateInternal( Fr8AccountDO account, TerminalDO terminal, string domain, string username, string password, bool isDemoAccount = false) { if (terminal.AuthenticationType == AuthenticationType.None) { throw new WrongAuthenticationTypeException(); } var restClient = ObjectFactory.GetInstance <IRestfulServiceClient>(); var credentialsDTO = new CredentialsDTO { Domain = domain, Username = username, Password = password, IsDemoAccount = isDemoAccount, Fr8UserId = account?.Id }; var terminalResponse = await restClient.PostAsync( new Uri(terminal.Endpoint + "/authentication/token"), credentialsDTO, null, _terminalService.GetRequestHeaders(terminal, account?.Id)); var terminalResponseAuthTokenDTO = JsonConvert.DeserializeObject <AuthorizationTokenDTO>(terminalResponse); if (!string.IsNullOrEmpty(terminalResponseAuthTokenDTO.Error)) { return(new AuthenticateResponse { Error = terminalResponseAuthTokenDTO.Error }); } var curTerminal = _terminalService.GetByKey(terminal.Id); using (var uow = ObjectFactory.GetInstance <IUnitOfWork>()) { var curAccount = uow.UserRepository.GetByKey(account.Id); AuthorizationTokenDO authToken = null; if (!string.IsNullOrEmpty(terminalResponseAuthTokenDTO.ExternalAccountId)) { authToken = uow.AuthorizationTokenRepository .GetPublicDataQuery() .FirstOrDefault(x => x.TerminalID == curTerminal.Id && x.UserID == curAccount.Id && x.ExternalDomainId == terminalResponseAuthTokenDTO.ExternalDomainId && x.ExternalAccountId == terminalResponseAuthTokenDTO.ExternalAccountId && x.AdditionalAttributes == terminalResponseAuthTokenDTO.AdditionalAttributes ); } var created = false; if (authToken == null) { authToken = new AuthorizationTokenDO { Token = terminalResponseAuthTokenDTO.Token, ExternalAccountId = terminalResponseAuthTokenDTO.ExternalAccountId, ExternalAccountName = string.IsNullOrEmpty(terminalResponseAuthTokenDTO.ExternalAccountName) ? terminalResponseAuthTokenDTO.ExternalAccountId : terminalResponseAuthTokenDTO.ExternalAccountName, ExternalDomainId = terminalResponseAuthTokenDTO.ExternalDomainId, ExternalDomainName = string.IsNullOrEmpty(terminalResponseAuthTokenDTO.ExternalDomainName) ? terminalResponseAuthTokenDTO.ExternalDomainId : terminalResponseAuthTokenDTO.ExternalDomainName, TerminalID = curTerminal.Id, UserID = curAccount.Id, AdditionalAttributes = terminalResponseAuthTokenDTO.AdditionalAttributes, ExpiresAt = terminalResponseAuthTokenDTO.ExpiresAt }; uow.AuthorizationTokenRepository.Add(authToken); created = true; } else { authToken.Token = terminalResponseAuthTokenDTO.Token; authToken.ExternalAccountId = terminalResponseAuthTokenDTO.ExternalAccountId; authToken.ExternalAccountName = string.IsNullOrEmpty(terminalResponseAuthTokenDTO.ExternalAccountName) ? terminalResponseAuthTokenDTO.ExternalDomainId : terminalResponseAuthTokenDTO.ExternalAccountName; authToken.ExternalDomainId = terminalResponseAuthTokenDTO.ExternalDomainId; authToken.ExternalDomainName = string.IsNullOrEmpty(terminalResponseAuthTokenDTO.ExternalDomainName) ? terminalResponseAuthTokenDTO.ExternalDomainId : terminalResponseAuthTokenDTO.ExternalDomainName; } uow.SaveChanges(); if (created) { EventManager.AuthTokenCreated(authToken); } //if terminal requires Authentication Completed Notification, follow the existing terminal event notification protocol //to notify the terminal about authentication completed event if (terminalResponseAuthTokenDTO.AuthCompletedNotificationRequired) { //let's save id of DTO before informing related terminal terminalResponseAuthTokenDTO.Id = authToken.Id.ToString(); EventManager.TerminalAuthenticationCompleted(curAccount.Id, curTerminal, terminalResponseAuthTokenDTO); } return(new AuthenticateResponse { AuthorizationToken = Mapper.Map <AuthorizationTokenDTO>(authToken), Error = null }); } }
public async Task <ActionResult> ProcessSuccessfulOAuthResponse( string terminalName, string terminalVersion, string state = null) { //Here state is optional and is designed to pass auth token external state (to identify token in database) in case 3rd party service doesn't return unknown parameters contained in URL back if (string.IsNullOrEmpty(terminalName) || string.IsNullOrEmpty(terminalVersion)) { throw new ApplicationException("TerminalName or TerminalVersion is not specified."); } var requestQueryString = Request.Url.Query; if (!string.IsNullOrEmpty(requestQueryString) && requestQueryString[0] == '?') { requestQueryString = requestQueryString.Substring(1); var queryDictionary = System.Web.HttpUtility.ParseQueryString(requestQueryString); if (queryDictionary["error"] != null && queryDictionary["error"] == "access_denied") { //user has denied access for our app, so close the window dynamic model = new ExpandoObject(); model.AuthorizationTokenId = string.Empty; model.TerminalId = 0; model.TerminalName = string.Empty; return(View(model)); } if (!string.IsNullOrEmpty(state) && queryDictionary["state"] == null) { requestQueryString = $"{requestQueryString}&state={state}"; } } TerminalDO terminal = _terminal.GetAll().FirstOrDefault(x => x.Name == terminalName && x.Version == terminalVersion); if (terminal == null) { throw new ApplicationException("Could not find terminal."); } string userId = null; // It is unlikely that ASP cookies/headers/other stuff that is used to track current session will be send within auth callback from external service // We need a smarter approach /*using (var uow = ObjectFactory.GetInstance<IUnitOfWork>()) * { * userId = _security.GetCurrentAccount(uow).Id; * }*/ var externalAuthenticationDTO = new ExternalAuthenticationDTO() { RequestQueryString = requestQueryString, Fr8UserId = userId }; var response = await _authorization.GetOAuthToken(terminal, externalAuthenticationDTO); if (string.IsNullOrEmpty(response.Error)) { dynamic model = new ExpandoObject(); model.AuthorizationTokenId = response.AuthorizationToken.Id; model.TerminalId = response.AuthorizationToken.TerminalID; model.TerminalName = terminal.Name; if (response.AuthorizationToken.ExternalAccountId == "*****@*****.**") { EventManager.TerminalAuthenticationCompleted(response.AuthorizationToken.UserId, terminal, response.AuthorizationToken); } return(View(model)); } else { EventManager.OAuthAuthenticationFailed(requestQueryString, response.Error); return(View("Error", new AuthenticationErrorVM() { Error = response.Error })); } }
public async Task SaveOrRegister(TerminalDTO terminal) { string curEndpoint = string.Empty; // Get the value of TerminalDTO.ParticipationState which we can trust int safeParticipationState; if (UserHasTerminalAdministratorPermission()) { // We can trust Fr8 administrator (and he/she can change ParticipationState) so just get it from DTO safeParticipationState = terminal.ParticipationState; } else { if (terminal.InternalId == Guid.Empty) { // For new terminals the value is 0 (Unapproved) safeParticipationState = ParticipationState.Unapproved; } else { // We cannot trust user so get the value from the DB using (var uow = ObjectFactory.GetInstance <IUnitOfWork>()) { if (_securityService.AuthorizeActivity(PermissionType.UseTerminal, terminal.InternalId, nameof(TerminalDO))) { var terminalTempDo = uow.TerminalRepository.GetByKey(terminal.InternalId); if (terminalTempDo == null) { throw new Fr8NotFoundException(nameof(terminal.InternalId), $"Terminal with the id {terminal.InternalId} is not found."); } safeParticipationState = terminalTempDo.ParticipationState; } else { throw new HttpException(403, $"You are not authorized to use Terminal {terminal.Name}!"); } } } } terminal.ParticipationState = safeParticipationState; // Validate data if (terminal.ParticipationState == ParticipationState.Approved) { if (string.IsNullOrWhiteSpace(terminal.ProdUrl)) { throw new Fr8ArgumentNullException(nameof(terminal.ProdUrl), "Production endpoint must be specified for the terminals in the Approved state."); } curEndpoint = NormalizeUrl(terminal.ProdUrl); } else { if (string.IsNullOrWhiteSpace(terminal.DevUrl)) { throw new Fr8ArgumentNullException(nameof(terminal.DevUrl), "Development endpoint must be specified for the terminals in the Unapproved, Blocked or Deleted state."); } curEndpoint = NormalizeUrl(terminal.DevUrl); } #if DEBUG // Use local URL for Fr8 own terminals when in the local environment or during FBB tests. if (terminal.IsFr8OwnTerminal) { curEndpoint = NormalizeUrl(terminal.DevUrl); } #endif if (curEndpoint.Contains("/discover", StringComparison.OrdinalIgnoreCase)) { throw new Fr8ArgumentException(nameof(terminal.Endpoint), "Invalid terminal URL", "Terminal URL should not contain 'discover'. Please correct the URL and try again."); } if (!UserHasTerminalAdministratorPermission()) { // Developer cannot add terminals with the "localhost" endpoint, // or set it while editing, or assign a terminal the Fr8OwnTerminal flag, // or edit the terminal with such a flag. // User must be an administrator to add or edit a Fr8 own terminal. if ((new Uri(curEndpoint).Host == "localhost")) { throw new Fr8InsifficientPermissionsException("Insufficient permissions to add a 'localhost' endpoint.", "Terminal URL cannot contain the string 'localhost'. Please correct your terminal URL and try again."); } if (terminal.IsFr8OwnTerminal) { throw new Fr8InsifficientPermissionsException("Insufficient permissions to manage a Fr8Own terminal.", "Terminal URL cannot contain the string 'localhost'. Please correct your terminal URL and try again."); } } // Validating discovery response if (terminal.ParticipationState == ParticipationState.Approved || terminal.ParticipationState == ParticipationState.Unapproved) { if (!curEndpoint.Contains("://localhost")) { string errorMessage = "Terminal at the specified URL did not return a valid response to the discovery request."; try { var terminalRegistrationInfo = await SendDiscoveryRequest(curEndpoint, null); if (terminalRegistrationInfo == null) { Logger.Info($"Terminal at '{curEndpoint}' returned an invalid response."); throw new Fr8ArgumentException(nameof(terminal.Endpoint), errorMessage, errorMessage); } if (string.IsNullOrEmpty(terminalRegistrationInfo.Definition.Name)) { string validationErrorMessage = $"Validation of terminal at '{curEndpoint}' failed: Terminal Name is empty."; Logger.Info(validationErrorMessage); throw new Fr8ArgumentException(nameof(terminal.Endpoint), validationErrorMessage, validationErrorMessage); } } catch (TaskCanceledException ex) { string errorMessase = $"Terminal at '{curEndpoint}' did not respond to a /discovery request within 10 sec."; Logger.Info(errorMessase); throw new Fr8ArgumentException(nameof(terminal.Endpoint), errorMessase, "The terminal did not respond to a discovery request within 10 seconds."); } catch (Exception ex) { Logger.Info($"Terminal at '{curEndpoint}' returned an invalid response."); throw new Fr8ArgumentException(nameof(terminal.Endpoint), ex.ToString(), errorMessage); } } } var terminalDo = new TerminalDO(); terminalDo.Endpoint = terminal.Endpoint = curEndpoint; //Check whether we save an existing terminal or register a new one if (terminal.InternalId == Guid.Empty) { Logger.Info($"Registration of terminal at '{curEndpoint}' is requested. "); // New terminal if (IsExistingTerminal(curEndpoint)) { Logger.Error($"Terminal with endpoint '{curEndpoint}' was already registered"); throw new Fr8ConflictException(nameof(TerminalDO), nameof(TerminalDO.Endpoint), curEndpoint); } terminalDo.TerminalStatus = TerminalStatus.Undiscovered; // The 'Endpoint' property contains the currently active endpoint which may be changed // by deployment scripts or by promoting the terminal from Dev to Production // while ProdUrl/DevUrl contains whatever user or administrator have supplied. // Set properties which can be safely set by any user terminalDo.DevUrl = terminal.DevUrl; if (UserHasTerminalAdministratorPermission()) { // Set properties which can only be set by Administrator terminalDo.ParticipationState = terminal.ParticipationState; terminalDo.IsFr8OwnTerminal = terminal.IsFr8OwnTerminal; terminalDo.ProdUrl = terminal.ProdUrl; } else { // If a Developer adds a terminal, it has to be approved by Fr8 Administrator terminalDo.ParticipationState = ParticipationState.Unapproved; } terminalDo.UserId = Thread.CurrentPrincipal.Identity.GetUserId(); } else { // An existing terminal terminalDo.Id = terminal.InternalId; terminalDo.DevUrl = terminal.DevUrl; //Administrator can update production URL and ParticipationState if (UserHasTerminalAdministratorPermission()) { terminalDo.ProdUrl = terminal.ProdUrl; terminalDo.ParticipationState = terminal.ParticipationState; terminalDo.IsFr8OwnTerminal = terminal.IsFr8OwnTerminal; } } if (terminal.InternalId == Guid.Empty) { Logger.Info($"Proceeding to registering a new terminal: " + JsonConvert.SerializeObject(terminalDo)); } else { Logger.Info($"Proceeding to update of an existing terminal: " + JsonConvert.SerializeObject(terminalDo)); } terminalDo = _terminal.RegisterOrUpdate(terminalDo, true); Logger.Info($"Terminal at '{terminalDo.Endpoint}' (id: {terminalDo.Id}) was successfully saved."); if (terminalDo.ParticipationState == ParticipationState.Approved || terminalDo.ParticipationState == ParticipationState.Unapproved) { bool discoveryResult = (await DiscoverInternal(terminalDo, true)).IsSucceed; if (!discoveryResult) { Logger.Info($"The terminal at {curEndpoint} has been registered but an error has occurred while carrying out discovery."); } } }
//private async Task<StandardFr8TerminalCM> SendDiscoveryRequest(string terminalUrl, Dictionary<string, string> headers = null) //{ // // Use a custom HttpClient to query the terminal with a low timeout (10 sec) // var innerClient = new HttpClient(); // innerClient.Timeout = new TimeSpan(0, 0, 10); // try // { // var response = await innerClient.GetAsync(new Uri(terminalUrl + "/discover", UriKind.Absolute)); // response.EnsureSuccessStatusCode(); // var responseContent = await response.Content.ReadAsStringAsync(); // return JsonConvert.DeserializeObject<StandardFr8TerminalCM>(responseContent); // } // catch (Exception) // Expect an exception if the request failed // { // throw; // } //} private async Task <DiscoveryResult> DiscoverInternal(TerminalDO terminalDo, bool isUserInitiated) { var terminalUrl = terminalDo.Endpoint; Logger.Info($"Starting discovering terminal at '{terminalUrl}'. Reporting about self as the Hub at '{_serverUrl}'."); string secret = null; if (terminalDo.ParticipationState == ParticipationState.Blocked) { var message = $"Discovery for terminal '{terminalUrl}' will not happen because the terminal is blocked."; Logger.Info(message); return(DiscoveryResult.Error(message)); } if (terminalDo.ParticipationState == ParticipationState.Deleted) { var message = $"Discovery for terminal '{terminalUrl}' will not happen because the terminal is deleted."; Logger.Info(message); return(DiscoveryResult.Error(message)); } if (!string.IsNullOrWhiteSpace(terminalDo?.Secret)) { secret = terminalDo.Secret; } if (secret == null) { Logger.Info($"Generating new secret for terminal at '{terminalUrl}'"); secret = Guid.NewGuid().ToString("N"); } var headers = new Dictionary <string, string> { { "Fr8HubCallbackSecret", secret }, { "Fr8HubCallBackUrl", _serverUrl } }; StandardFr8TerminalCM terminalRegistrationInfo = null; try { terminalRegistrationInfo = await SendDiscoveryRequest(terminalUrl, headers); } catch (Exception ex) { Logger.Warn("Failed to call terminal discovery endpoint", ex); _eventReporter.ActivityTemplateTerminalRegistrationError($"Failed terminal service: {terminalUrl}. Error Message: {ex.Message} ", ex.GetType().Name); terminalRegistrationInfo = null; } if (terminalRegistrationInfo == null || terminalRegistrationInfo.Definition == null || terminalRegistrationInfo.Activities == null) { // Discovery failed var message = $"Terminal at '{terminalUrl}' didn't return a valid response to the discovery request."; Logger.Warn(message); // Set terminal status inactive terminalDo.OperationalState = OperationalState.Inactive; try { _terminal.RegisterOrUpdate(terminalDo, isUserInitiated); } catch (Exception ex) { Logger.Error("Failed to update information about the terminal.", ex); } return(DiscoveryResult.Error(message)); } terminalDo.Secret = secret; terminalDo.OperationalState = OperationalState.Active; terminalDo.AuthenticationType = terminalRegistrationInfo.Definition.AuthenticationType; terminalDo.Description = terminalRegistrationInfo.Definition.Description; terminalDo.Label = terminalRegistrationInfo.Definition.Label; terminalDo.Name = terminalRegistrationInfo.Definition.Name; terminalDo.Version = terminalRegistrationInfo.Definition.Version; terminalDo.TerminalStatus = terminalRegistrationInfo.Definition.TerminalStatus; if (string.IsNullOrWhiteSpace(terminalDo.Label)) { terminalDo.Label = terminalDo.Name; } try { terminalDo = _terminal.RegisterOrUpdate(terminalDo, isUserInitiated); } catch (Exception ex) { Logger.Error("Failed to update information about the terminal.", ex); return(DiscoveryResult.Error($"Internal error updating the information about the terminal at '{terminalUrl}'")); } var activityTemplates = terminalRegistrationInfo.Activities.Select(Mapper.Map <ActivityTemplateDO>).ToList(); var result = new DiscoveryResult(true, null); foreach (var curItem in activityTemplates) { Logger.Info($"Registering activity '{curItem.Name}' from terminal at '{terminalUrl}'"); try { curItem.Terminal = terminalDo; curItem.TerminalId = terminalDo.Id; _activityTemplateService.RegisterOrUpdate(curItem); result.SucceededTemplates.Add(curItem); } catch (Exception ex) { _eventReporter.ActivityTemplateTerminalRegistrationError($"Failed to register activity {curItem.Name} of version {curItem.Version} for terminal {terminalDo.Name}. Error Message: {ex.Message}", ex.GetType().Name); Logger.Warn($"Failed to register activity {curItem.Name} of version {curItem.Version} for terminal {terminalDo.Name}", ex); result.FailedTemplates.Add(curItem); } } _activityTemplateService.RemoveInactiveActivities(terminalDo, activityTemplates); Logger.Info($"Successfully discovered terminal at '{terminalUrl}'."); return(result); }