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();
}
}
}