using Microsoft.IdentityModel.Clients.ActiveDirectory; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Security.Authentication; using System.Web.Http; using Tango.BL; using Tango.BL.Builders; using Tango.BL.Entities; using Tango.BL.Enumerations; using Tango.Core.Cryptography; using Tango.MachineService.Models; using Tango.MachineStudio.Common.Authentication; using System.Data.Entity; using Tango.MachineStudio.Common.Web; using Tango.Web.Controllers; using Tango.Web.Helpers; using Tango.Web.Storage; using Tango.Web.Authentication; using Tango.Web.ActiveDirectory; using Tango.MachineService.Filters; namespace Tango.MachineService.Controllers { public class MachineStudioController : JsonController { private static List _pendingUploads; private ActiveDirectoryManager _ad_manager; public static TokensManager TokensManager { get; set; } #region Constructors /// /// Initializes the class. /// static MachineStudioController() { TokensManager = new TokensManager(); TokensManager.ExpirationTime = TimeSpan.FromDays(10); _pendingUploads = new List(); } /// /// Initializes a new instance of the class. /// public MachineStudioController() : base() { _ad_manager = new ActiveDirectoryManager(); } #endregion #region Actions /// /// Checks for updates. /// /// The request. /// [HttpPost] [MachineStudioLoginFilter] public CheckForUpdatesResponse CheckForUpdates(CheckForUpdatesRequest request) { LogManager.Log("Request received..."); CheckForUpdatesResponse response = new CheckForUpdatesResponse(); using (ObservablesContext db = ObservablesContextHelper.CreateContext()) { var versions = db.MachineStudioVersions.ToList(); MachineStudioVersion latestVersion = null; latestVersion = versions.OrderByDescending(x => Version.Parse(x.Version)).FirstOrDefault(); Version currentVersion = Version.Parse(request.Version); String comments = String.Join(Environment.NewLine, versions.OrderBy(x => Version.Parse(x.Version)).Where(x => Version.Parse(x.Version) > currentVersion).Select(x => x.Comments)); if (latestVersion != null && Version.Parse(latestVersion.Version) > currentVersion) { var manager = new StorageManager(); var container = manager.GetContainer(MachineServiceConfig.MACHINE_STUDIO_VERSIONS_CONTAINER); var blob = container.GetBlockBlobReference(latestVersion.BlobName); response.BlobAddress = blob.GenerateReadSignature(TimeSpan.FromMinutes(60)); response.IsUpdateAvailable = true; response.Version = latestVersion.Version; response.Comments = latestVersion.Comments; } } return response; } /// /// Downloads the latest version. /// /// The request. /// [HttpPost] [MachineStudioLoginFilter] public DownloadLatestVersionResponse DownloadLatestVersion(DownloadLatestVersionRequest request) { LogManager.Log("Request received..."); DownloadLatestVersionResponse response = new DownloadLatestVersionResponse(); using (ObservablesContext db = ObservablesContextHelper.CreateContext()) { var versions = db.MachineStudioVersions.ToList(); MachineStudioVersion latestVersion = versions.OrderByDescending(x => Version.Parse(x.Version)).FirstOrDefault(); if (latestVersion != null) { var manager = new StorageManager(); var container = manager.GetContainer(MachineServiceConfig.MACHINE_STUDIO_VERSIONS_CONTAINER); var blob = container.GetBlockBlobReference(latestVersion.BlobName); response.BlobAddress = blob.GenerateReadSignature(TimeSpan.FromMinutes(60)); response.Version = latestVersion.Version; } } return response; } /// /// Uploads a version. /// /// The request. /// /// New version must be greater than latest version. /// Invalid user credentials. [HttpPost] [MachineStudioLoginFilter] public UploadVersionResponse UploadVersion(UploadVersionRequest request) { UploadVersionResponse response = new UploadVersionResponse(); using (ObservablesContext db = ObservablesContextHelper.CreateContext()) { //Load relation first... db.Roles.ToList(); db.Permissions.ToList(); db.UsersRoles.ToList(); db.RolesPermissions.ToList(); String userID = TokensManager.GetTokenObject(request.AccessToken); var user = db.Users.SingleOrDefault(x => x.Guid == userID); if (user != null && user.HasPermission(Permissions.PublishMachineStudioVersions)) { var latestVersion = db.MachineStudioVersions.ToList().OrderByDescending(x => Version.Parse(x.Version)).FirstOrDefault(); Version currentVersion = Version.Parse(request.Version); if (latestVersion == null || currentVersion > Version.Parse(latestVersion.Version)) { String newVersionFileName = "Machine Studio Version" + " " + currentVersion.ToString() + ".zip"; var manager = new StorageManager(); var container = manager.GetContainer(MachineServiceConfig.MACHINE_STUDIO_VERSIONS_CONTAINER); var blob = container.CreateEmptyBlob(newVersionFileName); response.Token = Guid.NewGuid().ToString(); response.BlobAddress = blob.GenerateWriteSignature(TimeSpan.FromMinutes(30)); _pendingUploads.Add(new MachineStudioPendingUpload() { UserGuid = user.Guid, Comments = request.Comments, Token = response.Token, Version = request.Version, BlobName = blob.Name, }); } else { throw new ArgumentException("New version must be greater than latest version."); } } else { throw new AuthenticationException("Invalid user credentials."); } } return response; } /// /// Notifies about a version upload completion. /// /// The request. /// /// Invalid Token. [HttpPost] [MachineStudioLoginFilter] public UploadCompletedResponse NotifyUploadCompleted(UploadCompletedRequest request) { MachineStudioPendingUpload upload = _pendingUploads.FirstOrDefault(x => x.Token == request.Token); if (upload != null) { _pendingUploads.RemoveAll(x => x.Token == upload.Token); using (ObservablesContext db = ObservablesContextHelper.CreateContext()) { db.MachineStudioVersions.Add(new MachineStudioVersion() { Comments = upload.Comments, BlobName = upload.BlobName, UserGuid = upload.UserGuid, Version = upload.Version, }); db.SaveChanges(); } return new UploadCompletedResponse(); } else { throw new ArgumentException("Invalid Token."); } } /// /// Gets the latest version. /// /// The request. /// [HttpPost] public LatestVersionResponse GetLatestVersion(LatestVersionRequest request) { using (ObservablesContext db = ObservablesContextHelper.CreateContext()) { var version = db.MachineStudioVersions.ToList().OrderByDescending(x => Version.Parse(x.Version)).FirstOrDefault(); return new LatestVersionResponse() { Version = version != null ? version.Version : "0.0.0.0" }; } } /// /// Login to the service. /// /// The request. /// /// [HttpPost] public LoginResponse Login(LoginRequest request) { var authResult = _ad_manager.ValidateUserCredentials(request.Email, request.Password); if (!_ad_manager.CanUserAccessCurrentEnvironment(request.Email)) { throw new AuthenticationException($"You do not have permissions to access the {MachineServiceConfig.DEPLOYMENT_SLOT.ToDescription()} environment."); } Version client_version; if (!Version.TryParse(request.Version, out client_version)) { client_version = new Version("1.0.0.0"); } bool versionChangeRequired = false; String requiredVersion = null; User user = null; using (ObservablesContext db = ObservablesContextHelper.CreateContext()) { db.Roles.ToList(); db.Permissions.ToList(); db.UsersRoles.ToList(); db.RolesPermissions.ToList(); user = db.Users.SingleOrDefault(x => x.Email.ToLower() == request.Email.ToLower()); IHashGenerator g = new BasicHashGenerator(); if (user == null) { //Than add the user !! User new_user = new User(); new_user.Email = request.Email; new_user.Password = g.Encrypt(request.Password); new_user.Organization = db.Organizations.Include(x => x.Address).Single(x => x.Name == "Twine"); new_user.Address = new_user.Organization.Address.Clone(); new_user.Contact = new Contact() { FirstName = authResult.UserInfo.GivenName, LastName = authResult.UserInfo.FamilyName, FullName = authResult.UserInfo.GivenName + " " + authResult.UserInfo.FamilyName, Email = request.Email, }; db.UsersRoles.Add(new UsersRole() { User = new_user, Role = db.Roles.Single(x => (Roles)x.Code == Roles.User), }); db.UsersRoles.Add(new UsersRole() { User = new_user, Role = db.Roles.Single(x => (Roles)x.Code == Roles.MachineStudioUser), }); new_user.LastLogin = DateTime.UtcNow; db.Users.Add(new_user); } else { user.LastLogin = DateTime.UtcNow; user.Password = g.Encrypt(request.Password); } db.SaveChanges(); if (MachineServiceConfig.ENFORCE_MACHINE_STUDIO_VERSION) { var latest_version = db.MachineStudioVersions.ToList().OrderByDescending(x => Version.Parse(x.Version)).FirstOrDefault(); if (latest_version != null && Version.Parse(latest_version.Version) != client_version) { versionChangeRequired = true; requiredVersion = latest_version.Version; } } } return new LoginResponse() { DataSource = new Core.DataSource() { Address = MachineServiceConfig.DB_ADDRESS, Catalog = MachineServiceConfig.DB_CATALOG, Type = Core.DataSourceType.Azure, IntegratedSecurity = false, UserName = request.Email, Password = request.Password, }, AccessToken = TokensManager.GetOrCreate(user.Guid), VersionChangeRequired = versionChangeRequired, RequiredVersion = requiredVersion, }; } #endregion } }