From 05f9349f3dd74fee41b7e77cd41a5a5029db9b47 Mon Sep 17 00:00:00 2001 From: bigpjo Date: Sun, 8 Apr 2018 04:38:37 +0100 Subject: [PATCH] Enterprise Mode fixes Now prompt user to change password if password expired. Better reporting of login failure i.e. user locked/disabled or password expired. EnterpriseDBContext changed to use connectionString from app.config of myrtille.service, this allows custom location for data file or using SQL server instead. Fixes invalid URL of enterprise session url where it includes /popup/ --- .gitignore | 355 ++++++++++++++++++ CHANGELOG | 7 +- DOCUMENTATION.md | 2 + Myrtille.Enterprise/ActiveDirectory.cs | 95 ++++- Myrtille.Enterprise/Data/Host.cs | 21 +- Myrtille.Enterprise/Data/HostAccessGroups.cs | 20 +- .../Data/MigrationConfiguration.cs | 19 + .../Data/MyrtilleEnterpriseDBContext.cs | 24 +- Myrtille.Enterprise/Data/Session.cs | 22 +- Myrtille.Enterprise/Data/SessionGroup.cs | 20 +- .../Helpers/DirectoryExceptionHelper.cs | 75 ++++ .../Myrtille.Enterprise.csproj | 4 +- .../Adapters/IEnterpriseAdapter.cs | 2 + .../IEnterpriseService.cs | 23 +- .../IMFAAuthentication.cs | 20 +- .../EnterpriseAuthenticationErrorHelper.cs | 75 ++++ .../Models/EnterpriseConnectionDetails.cs | 21 +- .../Models/EnterpriseHost.cs | 20 +- .../Models/EnterpriseHostEdit.cs | 21 +- .../Models/EnterpriseSession.cs | 22 +- .../Models/SecurityProtocolEnum.cs | 20 +- .../Myrtille.Services.Contracts.csproj | 2 + Myrtille.Services/EnterpriseService.cs | 34 +- Myrtille.Services/MFAAuthentication.cs | 20 +- Myrtille.Services/RemoteSessionProcess.cs | 6 +- Myrtille.Services/app.config | 13 +- Myrtille.Web/Default.aspx.cs | 26 +- Myrtille.Web/Myrtille.Web.csproj | 8 + Myrtille.Web/Web.config | 117 ++++++ Myrtille.Web/css/Default.css | 39 ++ Myrtille.Web/popups/EditHost.aspx.cs | 3 +- Myrtille.Web/popups/EditHostSession.aspx.cs | 5 +- .../popups/EnterpriseChangePassword.aspx | 86 +++++ .../popups/EnterpriseChangePassword.aspx.cs | 109 ++++++ .../EnterpriseChangePassword.aspx.designer.cs | 69 ++++ Myrtille.Web/src/EnterpriseServiceClient.cs | 13 + 36 files changed, 1403 insertions(+), 35 deletions(-) create mode 100644 .gitignore create mode 100644 Myrtille.Enterprise/Helpers/DirectoryExceptionHelper.cs create mode 100644 Myrtille.Services.Contracts/Models/EnterpriseAuthenticationErrorHelper.cs create mode 100644 Myrtille.Web/Web.config create mode 100644 Myrtille.Web/popups/EnterpriseChangePassword.aspx create mode 100644 Myrtille.Web/popups/EnterpriseChangePassword.aspx.cs create mode 100644 Myrtille.Web/popups/EnterpriseChangePassword.aspx.designer.cs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9e4253e --- /dev/null +++ b/.gitignore @@ -0,0 +1,355 @@ +Skip to content +This repository +Search +Pull requests +Issues +Marketplace +Explore + @bigpjo +Sign out +2,481 +63,978 29,350 github/gitignore + Code Pull requests 174 Projects 0 Insights +gitignore/VisualStudio.gitignore +96b153a 27 days ago +@shiftkey shiftkey Merge pull request #2576 from jerzywie/master +@shiftkey @arcresu @aroben @bbodenmiller @Haacked @niik @AArnott @Zenuka @sayedihashimi @saschanaz @LunicLynx @sfhardman @jamiehumphries @OsirisTerje @richorama @RehanSaeed @matma @JSkimming @jamesqo @elerch @cbadke @bdukes @anurse @anderslundsgard @alexanderKhaustov @julienshepherd + +325 lines (260 sloc) 5.36 KB +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser +© 2018 GitHub, Inc. +Terms +Privacy +Security +Status +Help +Contact GitHub +API +Training +Shop +Blog +About +Press h to open a hovercard with more details. \ No newline at end of file diff --git a/CHANGELOG b/CHANGELOG index c0b937a..24830fa 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,9 @@ -2018-04-02 Version 1.8.1 (beta) +2018-04-08 Version 1.8.2 (beta) + enterprise mode now better reporting of login failures and includes change password dialog where user is required to change password + connectionString now in service app.config to allow to specify location for MyrtilleEnterprise.sdf or use SQL server + fixed issue with enterprise host create session including invalid /popup/ path in sessionURL + +2018-04-02 Version 1.8.1 (beta) enterprise mode data folder is now created by the installer (thanks hac) fixed installer error 1001 regarding CERTENROLLLib.CX509PrivateKey updated openssl to version 1.0.2o diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md index ce3ff61..0ce592c 100644 --- a/DOCUMENTATION.md +++ b/DOCUMENTATION.md @@ -204,6 +204,8 @@ To enable enterprise mode, edit the app.config file of Myrtille.Services and unc - `EnterpriseDomain`, this is the name of your domain (i.e. MYDOMAIN or mydomain.local) if myrtille is part of it or the domain controller FQDN or IP otherwise - Restart Myrtille.Services windows service to use the new settings +To specify a customer path for the MyrtilleEnterprise database or use another SQL server amend Myrtille.Services app.config connectionString + If you wish to create your own enterprise adapter (with a different authentication, database or behavior), `Myrtille.Services.Contracts` contains the interfaces you need. ## Notes and limitations diff --git a/Myrtille.Enterprise/ActiveDirectory.cs b/Myrtille.Enterprise/ActiveDirectory.cs index 4e848cf..e577290 100644 --- a/Myrtille.Enterprise/ActiveDirectory.cs +++ b/Myrtille.Enterprise/ActiveDirectory.cs @@ -1,7 +1,9 @@ -/* - Enterprise mode, mimic behaviour of RDP gateways + +/* + Myrtille: A native HTML4/5 Remote Desktop Protocol client. - Copyright(c) 2017-2018 Olive Innovations + Copyright(c) 2014-2018 Cedric Coste + Copyright(c) 2018 Paul Oliver Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,9 +22,11 @@ limitations under the License. using System.Collections.Generic; using System.DirectoryServices; using System.DirectoryServices.AccountManagement; +using System.Runtime.InteropServices; using System.IO; using System.Linq; using System.Security.Cryptography; +using System.Security.Principal; using System.Text; using Myrtille.Helpers; using Myrtille.Services.Contracts; @@ -31,6 +35,7 @@ namespace Myrtille.Enterprise { public class ActiveDirectory : IEnterpriseAdapter { + public void Initialize() { using (var db = new MyrtilleEnterpriseDBContext()) @@ -55,8 +60,46 @@ public EnterpriseSession Authenticate(string username, string password, string a using (var context = new PrincipalContext(ContextType.Domain, domain, username, password)) { UserPrincipal user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, username); + DirectoryEntry entry = (DirectoryEntry)user.GetUnderlyingObject(); + if(user.IsAccountLockedOut()) + { + return new EnterpriseSession + { + AuthenticationErrorCode = EnterpriseAuthenticationErrorCode.USER_ACCOUNT_LOCKED + }; + } + + if(user.Enabled != null && !(bool)user.Enabled) + { + return new EnterpriseSession + { + AuthenticationErrorCode = EnterpriseAuthenticationErrorCode.ACCOUNT_DISABLED + }; + } + + if(user.AccountExpirationDate != null && (DateTime)user.AccountExpirationDate <= DateTime.Now) + { + return new EnterpriseSession + { + AuthenticationErrorCode = EnterpriseAuthenticationErrorCode.ACCOUNT_EXPIRED + }; + } + + if (!user.PasswordNeverExpires )//&& !user.UserCannotChangePassword) + { + var expDate = (DateTime)entry.InvokeGet("PasswordExpirationDate"); + if (expDate <= DateTime.Now) + { + return new EnterpriseSession + { + AuthenticationErrorCode = EnterpriseAuthenticationErrorCode.PASSWORD_EXPIRED + }; + } + } + + var directoryGroups = new List(); try @@ -115,10 +158,27 @@ public EnterpriseSession Authenticate(string username, string password, string a } } } - catch (Exception e) + catch(DirectoryServicesCOMException e) + { + + var formattedError = (DirectoryExceptionHelper)e; + + return new EnterpriseSession + { + AuthenticationErrorCode = formattedError.ErrorCode + }; + } + catch(PrincipalOperationException e) { return null; } + catch (Exception e) + { + return new EnterpriseSession + { + AuthenticationErrorCode = EnterpriseAuthenticationErrorCode.UNKNOWN_ERROR + }; + } } /// @@ -502,7 +562,31 @@ public string CreateUserSession(string sessionID, long hostID, string username, return string.Format("?SI={0}&SD={1}&SK={2}",newSessionID,hostID,sessionKey); } } - + + /// + /// Change password for user + /// + /// + /// + /// + /// + public bool ChangeUserPassword(string username, string oldPassword, string newPassword, string domain) + { + try + { + using (var context = new PrincipalContext(ContextType.Domain, domain, username, oldPassword)) + { + UserPrincipal user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, username); + user.ChangePassword(oldPassword, newPassword); + user.Save(); + } + return true; + }catch(Exception e) + { + return false; + } + } + #region aes encryption private static string AES_Encrypt(string stringToBeEncrypted, string passwordString) @@ -574,6 +658,7 @@ public string AES_Decrypt(string stringToBeDecrypted, string passwordString) return decryptedString; } + #endregion } } \ No newline at end of file diff --git a/Myrtille.Enterprise/Data/Host.cs b/Myrtille.Enterprise/Data/Host.cs index 498d64a..81c70b2 100644 --- a/Myrtille.Enterprise/Data/Host.cs +++ b/Myrtille.Enterprise/Data/Host.cs @@ -1,4 +1,23 @@ -using System.ComponentModel.DataAnnotations; +/* + Myrtille: A native HTML4/5 Remote Desktop Protocol client. + + Copyright(c) 2014-2018 Cedric Coste + Copyright(c) 2014-2018 Paul Oliver + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Myrtille.Services.Contracts; diff --git a/Myrtille.Enterprise/Data/HostAccessGroups.cs b/Myrtille.Enterprise/Data/HostAccessGroups.cs index e5ac73e..2b9d19d 100644 --- a/Myrtille.Enterprise/Data/HostAccessGroups.cs +++ b/Myrtille.Enterprise/Data/HostAccessGroups.cs @@ -1,4 +1,22 @@ -using System.ComponentModel.DataAnnotations; +/* + Myrtille: A native HTML4/5 Remote Desktop Protocol client. + + Copyright(c) 2014-2018 Cedric Coste + Copyright(c) 2014-2018 Paul Oliver + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace Myrtille.Enterprise diff --git a/Myrtille.Enterprise/Data/MigrationConfiguration.cs b/Myrtille.Enterprise/Data/MigrationConfiguration.cs index 197cac2..11b55b9 100644 --- a/Myrtille.Enterprise/Data/MigrationConfiguration.cs +++ b/Myrtille.Enterprise/Data/MigrationConfiguration.cs @@ -1,3 +1,22 @@ +/* + Myrtille: A native HTML4/5 Remote Desktop Protocol client. + + Copyright(c) 2014-2018 Cedric Coste + Copyright(c) 2014-2018 Paul Oliver + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + using System.Data.Entity.Migrations; namespace Myrtille.Enterprise diff --git a/Myrtille.Enterprise/Data/MyrtilleEnterpriseDBContext.cs b/Myrtille.Enterprise/Data/MyrtilleEnterpriseDBContext.cs index 2bbcdf2..1503772 100644 --- a/Myrtille.Enterprise/Data/MyrtilleEnterpriseDBContext.cs +++ b/Myrtille.Enterprise/Data/MyrtilleEnterpriseDBContext.cs @@ -1,11 +1,31 @@ -using System.Data.Entity; +/* + Myrtille: A native HTML4/5 Remote Desktop Protocol client. + + Copyright(c) 2014-2018 Cedric Coste + Copyright(c) 2018 Paul Oliver + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +using System.Data.Entity; using System.Data.SqlServerCe; namespace Myrtille.Enterprise { public class MyrtilleEnterpriseDBContext : DbContext { - public MyrtilleEnterpriseDBContext() : base(new SqlCeConnection(@"Data Source=|DataDirectory|MyrtilleEnterprise.sdf;Persist Security Info=False;"), contextOwnsConnection: true) + public MyrtilleEnterpriseDBContext() : + base("name=enterpriseDBConnection") + //base(new SqlCeConnection(@"Data Source=|DataDirectory|MyrtilleEnterprise.sdf;Persist Security Info=False;"), contextOwnsConnection: true) { Database.SetInitializer(new MigrateDatabaseToLatestVersion()); } diff --git a/Myrtille.Enterprise/Data/Session.cs b/Myrtille.Enterprise/Data/Session.cs index e134788..d76701e 100644 --- a/Myrtille.Enterprise/Data/Session.cs +++ b/Myrtille.Enterprise/Data/Session.cs @@ -1,4 +1,22 @@ -using System; +/* + Myrtille: A native HTML4/5 Remote Desktop Protocol client. + + Copyright(c) 2014-2018 Cedric Coste + Copyright(c) 2018 Paul Oliver + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; @@ -11,7 +29,7 @@ public class Session [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] public long ID { get; set; } - [Index(IsClustered = true), StringLength(100)] + [Index(IsClustered = false), StringLength(100)] public string SessionID { get; set; } [Index, StringLength(250)] diff --git a/Myrtille.Enterprise/Data/SessionGroup.cs b/Myrtille.Enterprise/Data/SessionGroup.cs index ee4f442..a1a38b4 100644 --- a/Myrtille.Enterprise/Data/SessionGroup.cs +++ b/Myrtille.Enterprise/Data/SessionGroup.cs @@ -1,4 +1,22 @@ -using System.ComponentModel.DataAnnotations; +/* + Myrtille: A native HTML4/5 Remote Desktop Protocol client. + + Copyright(c) 2014-2018 Cedric Coste + Copyright(c) 2018 Paul Oliver + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace Myrtille.Enterprise diff --git a/Myrtille.Enterprise/Helpers/DirectoryExceptionHelper.cs b/Myrtille.Enterprise/Helpers/DirectoryExceptionHelper.cs new file mode 100644 index 0000000..e6917e4 --- /dev/null +++ b/Myrtille.Enterprise/Helpers/DirectoryExceptionHelper.cs @@ -0,0 +1,75 @@ +/* + Myrtille: A native HTML4/5 Remote Desktop Protocol client. + + Copyright(c) 2014-2018 Cedric Coste + Copyright(c) 2018 Paul Oliver + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.DirectoryServices; +using Myrtille.Services.Contracts; + +namespace Myrtille.Enterprise +{ + public class DirectoryExceptionHelper + { + public EnterpriseAuthenticationErrorCode ErrorCode { get; private set; } + + public DirectoryExceptionHelper(EnterpriseAuthenticationErrorCode e) + { + ErrorCode = e; + + } + + public static implicit operator DirectoryExceptionHelper(DirectoryServicesCOMException e) + { + var errorDict = e.ExtendedErrorMessage + .Split(',') + .Select(x => x.Trim()) + .ToDictionary(s => s.Split(new[] { ' ' }, 2)[0], s => s); + + var errorCode = errorDict["data"].Split(new[] { ' ' }, 2)[1]; + + switch (errorCode) + { + case "525": + return new DirectoryExceptionHelper(EnterpriseAuthenticationErrorCode.USER_NOT_FOUND); + case "52e": + return new DirectoryExceptionHelper(EnterpriseAuthenticationErrorCode.INVALID_LOGIN_CREDENTIALS); + case "530": + return new DirectoryExceptionHelper(EnterpriseAuthenticationErrorCode.LOGIN_NOT_PERMITTED_AT_THIS_TIME); + case "531": + return new DirectoryExceptionHelper(EnterpriseAuthenticationErrorCode.LOGIN_NOT_PERMITTED_AT_THIS_WORKSTATION); + case "532": + return new DirectoryExceptionHelper(EnterpriseAuthenticationErrorCode.PASSWORD_EXPIRED); + case "533": + return new DirectoryExceptionHelper(EnterpriseAuthenticationErrorCode.ACCOUNT_DISABLED); + case "534": + return new DirectoryExceptionHelper(EnterpriseAuthenticationErrorCode.USER_NOT_GRANTED_LOGIN_AT_THIS_MACHINE); + case "701": + return new DirectoryExceptionHelper(EnterpriseAuthenticationErrorCode.ACCOUNT_EXPIRED); + case "773": + return new DirectoryExceptionHelper(EnterpriseAuthenticationErrorCode.USER_MUST_RESET_PASSWORD); + case "775": + return new DirectoryExceptionHelper(EnterpriseAuthenticationErrorCode.USER_ACCOUNT_LOCKED); + default: + return new DirectoryExceptionHelper(EnterpriseAuthenticationErrorCode.UNKNOWN_ERROR); + } + } + } +} diff --git a/Myrtille.Enterprise/Myrtille.Enterprise.csproj b/Myrtille.Enterprise/Myrtille.Enterprise.csproj index fa7dd52..1c407a8 100644 --- a/Myrtille.Enterprise/Myrtille.Enterprise.csproj +++ b/Myrtille.Enterprise/Myrtille.Enterprise.csproj @@ -44,6 +44,7 @@ + ..\packages\Microsoft.SqlServer.Compact.4.0.8876.1\lib\net40\System.Data.SqlServerCe.dll @@ -51,6 +52,7 @@ + @@ -66,6 +68,7 @@ + @@ -82,7 +85,6 @@ Myrtille.Services.Contracts - diff --git a/Myrtille.Services.Contracts/Adapters/IEnterpriseAdapter.cs b/Myrtille.Services.Contracts/Adapters/IEnterpriseAdapter.cs index e744fb5..f52bb6c 100644 --- a/Myrtille.Services.Contracts/Adapters/IEnterpriseAdapter.cs +++ b/Myrtille.Services.Contracts/Adapters/IEnterpriseAdapter.cs @@ -42,5 +42,7 @@ public interface IEnterpriseAdapter EnterpriseConnectionDetails GetSessionConnectionDetails(string sessionID, long hostID, string sessionKey); string CreateUserSession(string sessionID, long hostID, string username, string password); + + bool ChangeUserPassword(string username, string oldPassword, string newPassword, string domain); } } \ No newline at end of file diff --git a/Myrtille.Services.Contracts/IEnterpriseService.cs b/Myrtille.Services.Contracts/IEnterpriseService.cs index e5f1469..86b836f 100644 --- a/Myrtille.Services.Contracts/IEnterpriseService.cs +++ b/Myrtille.Services.Contracts/IEnterpriseService.cs @@ -1,4 +1,22 @@ -using System.Collections.Generic; +/* + Myrtille: A native HTML4/5 Remote Desktop Protocol client. + + Copyright(c) 2014-2018 Cedric Coste + Copyright(c) 2014-2018 Paul Oliver + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +using System.Collections.Generic; using System.ServiceModel; namespace Myrtille.Services.Contracts @@ -35,5 +53,8 @@ public interface IEnterpriseService [OperationContract] string CreateUserSession(string sessionID, long hostID, string username, string password); + + [OperationContract] + bool ChangeUserPassword(string username, string oldPassword, string newPassword); } } \ No newline at end of file diff --git a/Myrtille.Services.Contracts/IMFAAuthentication.cs b/Myrtille.Services.Contracts/IMFAAuthentication.cs index 57da2b7..fad8abb 100644 --- a/Myrtille.Services.Contracts/IMFAAuthentication.cs +++ b/Myrtille.Services.Contracts/IMFAAuthentication.cs @@ -1,4 +1,22 @@ -using System.ServiceModel; +/* + Myrtille: A native HTML4/5 Remote Desktop Protocol client. + + Copyright(c) 2014-2018 Cedric Coste + Copyright(c) 2014-2018 Paul Oliver + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +using System.ServiceModel; namespace Myrtille.Services.Contracts { diff --git a/Myrtille.Services.Contracts/Models/EnterpriseAuthenticationErrorHelper.cs b/Myrtille.Services.Contracts/Models/EnterpriseAuthenticationErrorHelper.cs new file mode 100644 index 0000000..ae09958 --- /dev/null +++ b/Myrtille.Services.Contracts/Models/EnterpriseAuthenticationErrorHelper.cs @@ -0,0 +1,75 @@ +/* + Myrtille: A native HTML4/5 Remote Desktop Protocol client. + + Copyright(c) 2014-2018 Cedric Coste + Copyright(c) 2014-2018 Paul Oliver + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Myrtille.Services.Contracts +{ + public static class EnterpriseAuthenticationErrorHelper + { + public static string GetErrorDescription(EnterpriseAuthenticationErrorCode errorCode) + { + switch (errorCode) + { + case EnterpriseAuthenticationErrorCode.USER_NOT_FOUND: + return "User not found"; + case EnterpriseAuthenticationErrorCode.INVALID_LOGIN_CREDENTIALS: + return "Invalid credentials"; + case EnterpriseAuthenticationErrorCode.LOGIN_NOT_PERMITTED_AT_THIS_TIME: + return "Not permitted to login at this time"; + case EnterpriseAuthenticationErrorCode.LOGIN_NOT_PERMITTED_AT_THIS_WORKSTATION: + return "Not permitted to login at this workstation"; + case EnterpriseAuthenticationErrorCode.PASSWORD_EXPIRED: + return "Password expired"; + case EnterpriseAuthenticationErrorCode.ACCOUNT_DISABLED: + return "Account disabled"; + case EnterpriseAuthenticationErrorCode.USER_NOT_GRANTED_LOGIN_AT_THIS_MACHINE: + return "The user has not been granted the requested logon type at this machine"; + case EnterpriseAuthenticationErrorCode.ACCOUNT_EXPIRED: + return "Account expired"; + case EnterpriseAuthenticationErrorCode.USER_MUST_RESET_PASSWORD: + return "User must reset password but it cannot be done remotely"; + case EnterpriseAuthenticationErrorCode.USER_ACCOUNT_LOCKED: + return "User account locked"; + case EnterpriseAuthenticationErrorCode.UNKNOWN_ERROR: + default: + return "Unknown error occured"; + } + } + } + + public enum EnterpriseAuthenticationErrorCode + { + NONE, + USER_NOT_FOUND, + INVALID_LOGIN_CREDENTIALS, + LOGIN_NOT_PERMITTED_AT_THIS_TIME, + LOGIN_NOT_PERMITTED_AT_THIS_WORKSTATION, + PASSWORD_EXPIRED, + ACCOUNT_DISABLED, + USER_NOT_GRANTED_LOGIN_AT_THIS_MACHINE, + ACCOUNT_EXPIRED, + USER_MUST_RESET_PASSWORD, + USER_ACCOUNT_LOCKED, + UNKNOWN_ERROR + } +} diff --git a/Myrtille.Services.Contracts/Models/EnterpriseConnectionDetails.cs b/Myrtille.Services.Contracts/Models/EnterpriseConnectionDetails.cs index 49a7854..5063d93 100644 --- a/Myrtille.Services.Contracts/Models/EnterpriseConnectionDetails.cs +++ b/Myrtille.Services.Contracts/Models/EnterpriseConnectionDetails.cs @@ -1,4 +1,23 @@ -namespace Myrtille.Services.Contracts +/* + Myrtille: A native HTML4/5 Remote Desktop Protocol client. + + Copyright(c) 2014-2018 Cedric Coste + Copyright(c) 2014-2018 Paul Oliver + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +namespace Myrtille.Services.Contracts { public class EnterpriseConnectionDetails : EnterpriseHost { diff --git a/Myrtille.Services.Contracts/Models/EnterpriseHost.cs b/Myrtille.Services.Contracts/Models/EnterpriseHost.cs index 5df0af0..deff9a8 100644 --- a/Myrtille.Services.Contracts/Models/EnterpriseHost.cs +++ b/Myrtille.Services.Contracts/Models/EnterpriseHost.cs @@ -1,4 +1,22 @@ -namespace Myrtille.Services.Contracts +/* + Myrtille: A native HTML4/5 Remote Desktop Protocol client. + + Copyright(c) 2014-2018 Cedric Coste + Copyright(c) 2014-2018 Paul Oliver + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +namespace Myrtille.Services.Contracts { public class EnterpriseHost { diff --git a/Myrtille.Services.Contracts/Models/EnterpriseHostEdit.cs b/Myrtille.Services.Contracts/Models/EnterpriseHostEdit.cs index 7f4c920..79a7c16 100644 --- a/Myrtille.Services.Contracts/Models/EnterpriseHostEdit.cs +++ b/Myrtille.Services.Contracts/Models/EnterpriseHostEdit.cs @@ -1,4 +1,23 @@ -namespace Myrtille.Services.Contracts +/* + Myrtille: A native HTML4/5 Remote Desktop Protocol client. + + Copyright(c) 2014-2018 Cedric Coste + Copyright(c) 2014-2018 Paul Oliver + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +namespace Myrtille.Services.Contracts { public class EnterpriseHostEdit { diff --git a/Myrtille.Services.Contracts/Models/EnterpriseSession.cs b/Myrtille.Services.Contracts/Models/EnterpriseSession.cs index d795db1..9619f56 100644 --- a/Myrtille.Services.Contracts/Models/EnterpriseSession.cs +++ b/Myrtille.Services.Contracts/Models/EnterpriseSession.cs @@ -1,9 +1,29 @@ -namespace Myrtille.Services.Contracts +/* + Myrtille: A native HTML4/5 Remote Desktop Protocol client. + + Copyright(c) 2014-2018 Cedric Coste + Copyright(c) 2014-2018 Paul Oliver + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +using System.Runtime.Serialization; +namespace Myrtille.Services.Contracts { public class EnterpriseSession { public bool IsAdmin { get; set; } public string SessionID { get; set; } public string SessionKey { get; set; } + public EnterpriseAuthenticationErrorCode AuthenticationErrorCode { get; set; } } } \ No newline at end of file diff --git a/Myrtille.Services.Contracts/Models/SecurityProtocolEnum.cs b/Myrtille.Services.Contracts/Models/SecurityProtocolEnum.cs index 0ba4f33..d1c704b 100644 --- a/Myrtille.Services.Contracts/Models/SecurityProtocolEnum.cs +++ b/Myrtille.Services.Contracts/Models/SecurityProtocolEnum.cs @@ -1,4 +1,22 @@ -namespace Myrtille.Services.Contracts +/* + Myrtille: A native HTML4/5 Remote Desktop Protocol client. + + Copyright(c) 2014-2018 Cedric Coste + Copyright(c) 2014-2018 Paul Oliver + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +namespace Myrtille.Services.Contracts { public enum SecurityProtocolEnum { diff --git a/Myrtille.Services.Contracts/Myrtille.Services.Contracts.csproj b/Myrtille.Services.Contracts/Myrtille.Services.Contracts.csproj index e1cc9b1..6306ac8 100644 --- a/Myrtille.Services.Contracts/Myrtille.Services.Contracts.csproj +++ b/Myrtille.Services.Contracts/Myrtille.Services.Contracts.csproj @@ -58,6 +58,7 @@ + @@ -72,6 +73,7 @@ + diff --git a/Myrtille.Services/EnterpriseService.cs b/Myrtille.Services/EnterpriseService.cs index f4639fb..8f541d5 100644 --- a/Myrtille.Services/EnterpriseService.cs +++ b/Myrtille.Services/EnterpriseService.cs @@ -1,4 +1,22 @@ -using System; +/* + Myrtille: A native HTML4/5 Remote Desktop Protocol client. + + Copyright(c) 2014-2018 Cedric Coste + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +using System; using System.Collections.Generic; using System.Diagnostics; using Myrtille.Services.Contracts; @@ -127,5 +145,19 @@ public string CreateUserSession(string sessionID, long hostID, string username, return null; } } + + public bool ChangeUserPassword(string username, string oldPassword, string newPassword) + { + try + { + Trace.TraceInformation("Change password for user {0}", username); + return Program._enterpriseAdapter.ChangeUserPassword(username, oldPassword, newPassword, Program._enterpriseDomain); + } + catch (Exception ex) + { + Trace.TraceError("Failed to change password for user {0}, ({1})", username, ex); + return false; + } + } } } \ No newline at end of file diff --git a/Myrtille.Services/MFAAuthentication.cs b/Myrtille.Services/MFAAuthentication.cs index 62c4ffb..ef1cc5d 100644 --- a/Myrtille.Services/MFAAuthentication.cs +++ b/Myrtille.Services/MFAAuthentication.cs @@ -1,4 +1,22 @@ -using Myrtille.Services.Contracts; +/* + Myrtille: A native HTML4/5 Remote Desktop Protocol client. + + Copyright(c) 2014-2018 Cedric Coste + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +using Myrtille.Services.Contracts; namespace Myrtille.Services { diff --git a/Myrtille.Services/RemoteSessionProcess.cs b/Myrtille.Services/RemoteSessionProcess.cs index daf85b0..ce81059 100644 --- a/Myrtille.Services/RemoteSessionProcess.cs +++ b/Myrtille.Services/RemoteSessionProcess.cs @@ -88,7 +88,8 @@ public void StartProcess( // log remote session events into a file (located into \log) var remoteSessionLog = false; - if (bool.TryParse(ConfigurationManager.AppSettings["RemoteSessionLog"], out bool bResult)) + bool bResult = false; + if (bool.TryParse(ConfigurationManager.AppSettings["RemoteSessionLog"], out bResult)) { remoteSessionLog = bResult; } @@ -97,7 +98,8 @@ public void StartProcess( // color depth var bpp = 16; - if (int.TryParse(ConfigurationManager.AppSettings["FreeRDPBpp"], out int iResult)) + int iResult = 16; + if (int.TryParse(ConfigurationManager.AppSettings["FreeRDPBpp"], out iResult)) { bpp = iResult; } diff --git a/Myrtille.Services/app.config b/Myrtille.Services/app.config index 5df90fa..7047afc 100644 --- a/Myrtille.Services/app.config +++ b/Myrtille.Services/app.config @@ -6,7 +6,18 @@
- + + + + + diff --git a/Myrtille.Web/Default.aspx.cs b/Myrtille.Web/Default.aspx.cs index 5d52f7d..82a7f46 100644 --- a/Myrtille.Web/Default.aspx.cs +++ b/Myrtille.Web/Default.aspx.cs @@ -220,7 +220,7 @@ private void SessionFixationHandler() private void UpdateControls() { // hosts list - if (_enterpriseSession != null && (RemoteSession == null || RemoteSession.State == RemoteSessionState.Disconnecting || RemoteSession.State == RemoteSessionState.Disconnected)) + if (_enterpriseSession != null && _enterpriseSession.AuthenticationErrorCode == EnterpriseAuthenticationErrorCode.NONE && (RemoteSession == null || RemoteSession.State == RemoteSessionState.Disconnecting || RemoteSession.State == RemoteSessionState.Disconnected)) { toolbar.Style["visibility"] = "hidden"; toolbar.Style["display"] = "none"; @@ -302,6 +302,7 @@ protected void ConnectButtonClick( { connectError.InnerText = "MFA Authentication failed!"; UpdateControls(); + return; } } @@ -309,6 +310,7 @@ protected void ConnectButtonClick( // enterprise mode from login if (_enterpriseSession == null && _enterpriseClient.GetState()) { + CreateEnterpriseSessionFromLogin(); } // connection from: @@ -387,7 +389,8 @@ private bool ConnectRemoteServer() if (_enterpriseSession != null && Request["SD"] != null) { long hostId = 0; - if (long.TryParse(Request["SD"], out long lResult)) + long lResult = 0; + if (long.TryParse(Request["SD"], out lResult)) { hostId = lResult; } @@ -417,7 +420,8 @@ private bool ConnectRemoteServer() // remote clipboard access var allowRemoteClipboard = true; - if (bool.TryParse(ConfigurationManager.AppSettings["allowRemoteClipboard"], out bool bResult)) + bool bResult = false; + if (bool.TryParse(ConfigurationManager.AppSettings["allowRemoteClipboard"], out bResult)) { allowRemoteClipboard = bResult; } @@ -583,9 +587,19 @@ private void CreateEnterpriseSessionFromLogin() { // authenticate the user against the enterprise active directory _enterpriseSession = _enterpriseClient.Authenticate(user.Value, password.Value); - if (_enterpriseSession == null) + if (_enterpriseSession.AuthenticationErrorCode != EnterpriseAuthenticationErrorCode.NONE) { - connectError.InnerText = "Active Directory Authentication failed!"; + + if (_enterpriseSession.AuthenticationErrorCode == EnterpriseAuthenticationErrorCode.PASSWORD_EXPIRED) + { + Page.ClientScript.RegisterClientScriptBlock(this.GetType(), Guid.NewGuid().ToString(), string.Format("openPopup('changePasswordPopup', 'EnterpriseChangePassword.aspx?userId={0}');", user.Value),true); + } + else + { + connectError.InnerText = EnterpriseAuthenticationErrorHelper + .GetErrorDescription(_enterpriseSession.AuthenticationErrorCode); + + } UpdateControls(); return; } @@ -629,7 +643,7 @@ protected void hostsList_ItemDataBound( hostLink.Attributes["class"] = "hostLink"; var hostName = e.Item.FindControl("hostName") as HtmlGenericControl; - hostName.InnerText = host.HostName; + hostName.InnerText = (_enterpriseSession.IsAdmin ? "Edit " : "") + host.HostName; if (_enterpriseSession.IsAdmin) { hostName.Attributes["class"] = "hostName"; diff --git a/Myrtille.Web/Myrtille.Web.csproj b/Myrtille.Web/Myrtille.Web.csproj index db11135..bad8ba1 100644 --- a/Myrtille.Web/Myrtille.Web.csproj +++ b/Myrtille.Web/Myrtille.Web.csproj @@ -98,6 +98,13 @@ EditHost.aspx + + EnterpriseChangePassword.aspx + ASPXCodeBehind + + + EnterpriseChangePassword.aspx + FileStorage.aspx ASPXCodeBehind @@ -196,6 +203,7 @@ + diff --git a/Myrtille.Web/Web.config b/Myrtille.Web/Web.config new file mode 100644 index 0000000..7fd0881 --- /dev/null +++ b/Myrtille.Web/Web.config @@ -0,0 +1,117 @@ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Myrtille.Web/css/Default.css b/Myrtille.Web/css/Default.css index 94d14f8..200a864 100644 --- a/Myrtille.Web/css/Default.css +++ b/Myrtille.Web/css/Default.css @@ -360,6 +360,45 @@ label, width: 370px; } + +/* change password popup */ + +#changePasswordPopup, +#changePasswordPopupInner +{ + width: 400px; + height: 330px; +} + +#changePasswordPopupInner +{ + color: #000; + background: #fff; +} + +#changePasswordPopupTitle +{ + padding-top: 20px; + padding-left: 10px; +} + +.changePasswordMessage{ + padding-left: 10px; +} + +.changePasswordPopupInput +{ + padding-left: 10px; +} + +#changeError { + padding-left: 10px; + font-size: 10pt; + color: red; + width:380px; +} + + /* remote session display */ #displayDiv diff --git a/Myrtille.Web/popups/EditHost.aspx.cs b/Myrtille.Web/popups/EditHost.aspx.cs index e09462e..cf109e9 100644 --- a/Myrtille.Web/popups/EditHost.aspx.cs +++ b/Myrtille.Web/popups/EditHost.aspx.cs @@ -67,7 +67,8 @@ protected void Page_Load( // retrieve the host if (Request["hostId"] != null) { - if (long.TryParse(Request["hostId"], out long lResult)) + long lResult = 0; + if (long.TryParse(Request["hostId"], out lResult)) { _hostId = lResult; } diff --git a/Myrtille.Web/popups/EditHostSession.aspx.cs b/Myrtille.Web/popups/EditHostSession.aspx.cs index 32fdd19..6263e8b 100644 --- a/Myrtille.Web/popups/EditHostSession.aspx.cs +++ b/Myrtille.Web/popups/EditHostSession.aspx.cs @@ -66,7 +66,8 @@ protected void Page_Load( // retrieve the host if (Request["hostId"] != null) { - if (long.TryParse(Request["hostId"], out long lResult)) + long lResult = 0; + if (long.TryParse(Request["hostId"], out lResult)) { _hostId = lResult; } @@ -103,7 +104,7 @@ protected void CreateSessionUrlButtonClick( var url = _enterpriseClient.CreateUserSession(_enterpriseSession.SessionID, _hostId.Value, userName.Value, userPassword.Value); if (!string.IsNullOrEmpty(url)) { - sessionUrl.Value = Request.Url.Scheme + "://" + Request.Url.Host + (Request.Url.Port != 80 && Request.Url.Port != 443 ? ":" + Request.Url.Port : "") + "/" + Request.Url.Segments[1] + url + "&__EVENTTARGET=&__EVENTARGUMENT=&connect=Connect%21"; + sessionUrl.Value = Request.Url.Scheme + "://" + Request.Url.Host + (Request.Url.Port != 80 && Request.Url.Port != 443 ? ":" + Request.Url.Port : "") + Request.ApplicationPath + "/" + url + "&__EVENTTARGET=&__EVENTARGUMENT=&connect=Connect%21"; } } catch (Exception exc) diff --git a/Myrtille.Web/popups/EnterpriseChangePassword.aspx b/Myrtille.Web/popups/EnterpriseChangePassword.aspx new file mode 100644 index 0000000..64b976f --- /dev/null +++ b/Myrtille.Web/popups/EnterpriseChangePassword.aspx @@ -0,0 +1,86 @@ +<%-- + Myrtille: A native HTML4/5 Remote Desktop Protocol client. + + Copyright(c) 2014-2018 Cedric Coste + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--%> + +<%@ Page Language="C#" Inherits="Myrtille.Web.EnterpriseChangePassword" Codebehind="EnterpriseChangePassword.aspx.cs" AutoEventWireup="true" Culture="auto" UICulture="auto" %> +<%@ OutputCache Location="None" %> + + + + + + + Myrtille + + + + + +
+ +
+ + Change Password + +
+

Your password has expired and must be changed

+ +
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+ +
+
+
+ + +
+
+ +
+ + + + + + \ No newline at end of file diff --git a/Myrtille.Web/popups/EnterpriseChangePassword.aspx.cs b/Myrtille.Web/popups/EnterpriseChangePassword.aspx.cs new file mode 100644 index 0000000..4027e46 --- /dev/null +++ b/Myrtille.Web/popups/EnterpriseChangePassword.aspx.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.UI; +using System.Web.UI.WebControls; + +namespace Myrtille.Web +{ + public partial class EnterpriseChangePassword : System.Web.UI.Page + { + private EnterpriseServiceClient _enterpriseClient; + private string _userName = null; + /// + /// page init + /// + /// + /// + protected void Page_Init( + object sender, + EventArgs e) + { + _enterpriseClient = new EnterpriseServiceClient(); + } + + /// + /// page load (postback data is now available) + /// + /// + /// + protected void Page_Load( + object sender, + EventArgs e) + { + // retrieve the host + if (Request["userId"] != null) + { + userName.Value = Request["userId"]; + _userName = Request["userId"]; + + if (!IsPostBack && Request["edit"] == null) + { + //try + //{ + // var host = _enterpriseClient.GetHost(_hostId.Value, _enterpriseSession.SessionID); + // if (host != null) + // { + // hostName.Value = host.HostName; + // hostAddress.Value = host.HostAddress; + // groupsAccess.Value = host.DirectoryGroups; + // securityProtocol.SelectedIndex = (int)host.Protocol; + // } + //} + //catch (Exception exc) + //{ + // System.Diagnostics.Trace.TraceError("Failed to retrieve host {0}, ({1})", _hostId, exc); + //} + } + } + else + { + changePassword.Disabled = true; + } + } + + /// + /// change a user password + /// + /// + /// + protected void ChangePasswordButtonClick( + object sender, + EventArgs e) + { + if (_enterpriseClient == null && !string.IsNullOrEmpty(_userName)) + return; + + try + { + if(string.IsNullOrEmpty(oldPassword.Value)) + { + changeError.InnerText = "Old password must be specified"; + }else + if (!string.Equals(newPassword.Value, confirmPassword.Value)) + { + changeError.InnerText = "New and confirmed passwords do not match"; + } + else + { + bool bResult = _enterpriseClient.ChangeUserPassword(_userName, oldPassword.Value, newPassword.Value); + + if (bResult) + { + Response.Redirect(Request.RawUrl + (Request.RawUrl.Contains("?") ? "&" : "?") + "change=success"); + } + else + { + changeError.InnerText = "Password change failed"; + } + } + } + catch (Exception exc) + { + System.Diagnostics.Trace.TraceError("Failed to change user password {0} ({1})", _userName, exc); + changeError.InnerText = "Password change failed"; + } + } + } +} \ No newline at end of file diff --git a/Myrtille.Web/popups/EnterpriseChangePassword.aspx.designer.cs b/Myrtille.Web/popups/EnterpriseChangePassword.aspx.designer.cs new file mode 100644 index 0000000..1e86aee --- /dev/null +++ b/Myrtille.Web/popups/EnterpriseChangePassword.aspx.designer.cs @@ -0,0 +1,69 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Myrtille.Web { + + + public partial class EnterpriseChangePassword { + + /// + /// userName control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.HtmlControls.HtmlInputText userName; + + /// + /// oldPassword control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.HtmlControls.HtmlInputPassword oldPassword; + + /// + /// newPassword control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.HtmlControls.HtmlInputPassword newPassword; + + /// + /// confirmPassword control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.HtmlControls.HtmlInputPassword confirmPassword; + + /// + /// changeError control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.HtmlControls.HtmlGenericControl changeError; + + /// + /// changePassword control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.HtmlControls.HtmlInputButton changePassword; + } +} diff --git a/Myrtille.Web/src/EnterpriseServiceClient.cs b/Myrtille.Web/src/EnterpriseServiceClient.cs index 01f1a0c..b4d9840 100644 --- a/Myrtille.Web/src/EnterpriseServiceClient.cs +++ b/Myrtille.Web/src/EnterpriseServiceClient.cs @@ -137,5 +137,18 @@ public string CreateUserSession(string sessionID, long hostID, string username, throw; } } + + public bool ChangeUserPassword(string username, string oldPassword, string newPassword) + { + try + { + return Channel.ChangeUserPassword(username, oldPassword, newPassword); + } + catch (Exception exc) + { + Trace.TraceError("Failed to change user password ({0})", exc); + throw; + } + } } } \ No newline at end of file