using System; using System.Collections.Generic; using System.Linq; using System.Security.Authentication; using System.Text; using System.Threading.Tasks; using Tango.Core; using Tango.BL.Entities; using Tango.MachineStudio.Common.Authentication; using Tango.BL; using Tango.BL.Enumerations; using System.Data.Entity; using Tango.Transport.Web; using Tango.Settings; using Tango.MachineStudio.Common; using Tango.MachineStudio.Common.StudioApplication; using Tango.Core.Helpers; using Tango.MachineStudio.Common.Web; using Tango.BL.Builders; using System.Data.Entity.Core; using System.Windows.Threading; using Tango.MachineStudio.Common.Buid; namespace Tango.MachineStudio.UI.Authentication { /// /// Represents the default Machine Studio Authentication provider /// /// /// public class DefaultAuthenticationProvider : ExtendedObject, IAuthenticationProvider { private MachineStudioWebClient _client; private DispatcherTimer _refreshTokenTimer; private IBuildProvider _buildProvider; private User _currentUser; /// /// Gets the current logged-in user. /// public User CurrentUser { get { return _currentUser; } set { _currentUser = value; CurrentUserChanged?.Invoke(this, _currentUser); RaisePropertyChangedAuto(); } } private Machine _machine; public Machine Machine { get { return _machine; } set { _machine = value; RaisePropertyChangedAuto(); } } /// /// Occurs when the current logged-in user has changed. /// public event EventHandler CurrentUserChanged; /// /// Initializes a new instance of the class. /// /// The machine studio web client. public DefaultAuthenticationProvider(MachineStudioWebClient machineStudioWebClient, IBuildProvider buildProvider) { _client = machineStudioWebClient; _buildProvider = buildProvider; _refreshTokenTimer = new DispatcherTimer(); _refreshTokenTimer.Interval = TimeSpan.FromMinutes(30); _refreshTokenTimer.Tick += _refreshTokenTimer_Tick; _refreshTokenTimer.Stop(); } private async void _refreshTokenTimer_Tick(object sender, EventArgs e) { if (ObservablesContext.GetActualDataSource().Type == DataSourceType.AccessToken) { try { LogManager.Log("Refreshing database access token..."); var response = await _client.RefreshToken(new RefreshTokenRequest()); ObservablesContext.UpdateAccessToken(response.AccessToken, response.Expiration); } catch (Exception ex) { LogManager.Log(ex, "Error occurred while trying to refresh the database access token."); } } } /// /// Performs a user login by the specified email and password. /// /// The email. /// The password. /// /// Login failed for user " + email public AuthenticationLoginResult Login(string email, string password, LoginMethod method, bool bypassVersionCheck = false, Action logAction = null, String serialNumber = null) { _refreshTokenTimer.Stop(); var settings = SettingsManager.Default.GetOrCreate(); if (!App.StartupArgs.Contains("-webDebug")) { _client.Environment = settings.DeploymentSlot; } var appVersion = AssemblyHelper.GetCurrentAssemblyVersion().ToString(); if (settings.ForceVersionUpdate) { appVersion = "1.0.0.0"; } LoginResponse response = null; try { logAction?.Invoke("Logging in to machine service..."); response = _client.Login(new LoginRequest() { Email = email, Password = password, Version = appVersion, Method = method, }).Result; } catch (Exception ex) { throw new AggregateException(new AuthenticationException("Error logging in to machine service."), ex); } if (bypassVersionCheck) { response.VersionChangeRequired = false; } if (settings.Environment == MachineStudioSettings.WorkingEnvironment.Remote) { ObservablesContext.OverrideSettingsDataSource(response.DataSource); } if (response.VersionChangeRequired && !bypassVersionCheck) { return new AuthenticationLoginResult() { Response = response }; } if (response.PasswordChangeRequired) { return new AuthenticationLoginResult() { Response = response }; } try { if (_buildProvider.BuildType == MSBuildType.Default) { ObservablesStaticCollections.Instance.Initialize((x) => { logAction.Invoke(x); }); } else { ObservablesStaticCollections.Instance.InitializeLite((x) => { logAction.Invoke(x); }); } } catch (Exception ex) { throw new AggregateException(new MetadataException("Error initializing database connection."), ex); } using (ObservablesContext db = ObservablesContext.CreateDefault()) { logAction.Invoke("Loading user permissions..."); User user = new UserBuilder(db).Set(x => x.Email.ToLower() == email.ToLower()).WithRolesAndPermissions().WithOrganization().Build(); if (user == null) { throw new AuthenticationException("Invalid credentials for " + email); } CurrentUser = user; if (_buildProvider.BuildType == MSBuildType.Lite) { var machine = new MachineBuilder(db).Set(x => x.SerialNumber.ToLower() == serialNumber.ToLower()).WithOrganization().Build(); if (machine == null) { throw new AuthenticationException($"Machine with serial number '{serialNumber}' could not be found."); } if (machine.Organization.Guid != user.Organization.Guid) { throw new AuthenticationException($"You are not authorized to access the specified machine."); } Machine = machine; } _refreshTokenTimer.Start(); logAction.Invoke("Starting application..."); return new AuthenticationLoginResult() { User = user, Response = response }; } } /// /// Logs-out the current logged-in user. /// public void Logout() { CurrentUser = null; _refreshTokenTimer.Stop(); } } }