This commit is contained in:
Virtuworks 2014-10-10 19:29:39 -04:00
commit 4e01a8c616
6 changed files with 383 additions and 137 deletions

View file

@ -30,6 +30,7 @@ using System;
using System.Collections.Generic;
using System.DirectoryServices.ActiveDirectory;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using WebsitePanel.Providers.FTP.IIs70;
@ -99,6 +100,20 @@ namespace WebsitePanel.Providers.FTP
{
get { return ProviderSettings["ADGroupsOU"]; }
}
protected string AdFtpRoot
{
get { return ProviderSettings["AdFtpRoot"]; }
}
protected Mode UserIsolationMode
{
get
{
var site = GetSite(ProviderSettings["SiteId"]);
return (Mode)Enum.Parse(typeof(Mode), site["UserIsolationMode"]);
}
}
#endregion
#region IFtpServer Members
@ -303,6 +318,12 @@ namespace WebsitePanel.Providers.FTP
return false;
}
switch (UserIsolationMode)
{
case Mode.ActiveDirectory:
return SecurityUtils.UserExists(accountName, ServerSettings, UsersOU);
default:
// check acocunt on FTP server
bool ftpExists = this.ftpSitesService.VirtualDirectoryExists(this.SiteId, accountName);
@ -310,6 +331,7 @@ namespace WebsitePanel.Providers.FTP
bool systemExists = SecurityUtils.UserExists(accountName, ServerSettings, UsersOU);
return (ftpExists || systemExists);
}
}
/// <summary>
/// Gets available ftp accounts.
@ -317,6 +339,11 @@ namespace WebsitePanel.Providers.FTP
/// <returns>List of avaialble accounts.</returns>
public FtpAccount[] GetAccounts()
{
switch (UserIsolationMode)
{
case Mode.ActiveDirectory:
return SecurityUtils.GetUsers(ServerSettings, UsersOU).Select(GetAccount).ToArray();
default:
List<FtpAccount> accounts = new List<FtpAccount>();
foreach (string directory in this.ftpSitesService.GetVirtualDirectoriesNames(this.SiteId))
@ -330,6 +357,7 @@ namespace WebsitePanel.Providers.FTP
return accounts.ToArray();
}
}
/// <summary>
/// Gets account with given name.
@ -338,11 +366,39 @@ namespace WebsitePanel.Providers.FTP
/// <returns>Ftp account.</returns>
public FtpAccount GetAccount(string accountName)
{
switch (UserIsolationMode)
{
case Mode.ActiveDirectory:
var user = SecurityUtils.GetUser(accountName, ServerSettings, UsersOU);
var path = Path.Combine(user.MsIIS_FTPRoot, user.MsIIS_FTPDir);
var permission = GetUserPermission(accountName, path);
var account = new FtpAccount()
{
CanRead = permission.Read,
CanWrite = permission.Write,
CreatedDate = user.CreatedDate,
Enabled = !user.AccountDisabled,
Folder = path,
GroupName = user.GroupName,
Name = user.Name
};
return account;
default:
FtpAccount acc = new FtpAccount();
acc.Name = accountName;
this.FillFtpAccountFromIis(acc);
return acc;
}
}
protected UserPermission GetUserPermission(string accountName, string folder)
{
var userPermission = new UserPermission {AccountName = accountName};
return SecurityUtils.GetGroupNtfsPermissions(folder, new[] {userPermission}, ServerSettings, UsersOU, GroupsOU)[0];
}
/// <summary>
/// Creates ftp account under root ftp site.
@ -350,6 +406,33 @@ namespace WebsitePanel.Providers.FTP
/// <param name="account">Ftp account to create.</param>
public void CreateAccount(FtpAccount account)
{
switch (UserIsolationMode)
{
case Mode.ActiveDirectory:
SecurityUtils.EnsureOrganizationalUnitsExist(ServerSettings, UsersOU, GroupsOU);
var systemUser = SecurityUtils.GetUser(account.Name, ServerSettings, UsersOU);
if (systemUser == null)
{
systemUser = new SystemUser
{
Name = account.Name,
FullName = account.Name,
Password = account.Password,
PasswordCantChange = true,
PasswordNeverExpires = true,
System = true
};
SecurityUtils.CreateUser(systemUser, ServerSettings, UsersOU, GroupsOU);
}
UpdateAccount(account);
break;
default:
// Create user account.
SystemUser user = new SystemUser();
user.Name = account.Name;
@ -377,6 +460,8 @@ namespace WebsitePanel.Providers.FTP
//
this.ftpSitesService.ConfigureConnectAs(account.Folder, this.SiteId, account.VirtualPath,
this.GetQualifiedAccountName(account.Name), account.Password, true);
break;
}
}
/// <summary>
@ -385,13 +470,67 @@ namespace WebsitePanel.Providers.FTP
/// <param name="account">Accoun to update.</param>
public void UpdateAccount(FtpAccount account)
{
var user = SecurityUtils.GetUser(account.Name, ServerSettings, UsersOU);
switch (UserIsolationMode)
{
case Mode.ActiveDirectory:
var ftpRoot = AdFtpRoot.ToLower();
var ftpDir = account.Folder.ToLower().Replace(ftpRoot, "");
var oldDir = user.MsIIS_FTPDir;
user.Password = account.Password;
user.PasswordCantChange = true;
user.PasswordNeverExpires = true;
user.Description = "WebsitePanel FTP Account with AD User Isolation";
user.MemberOf = new[] {FtpGroupName};
user.AccountDisabled = !account.Enabled;
user.MsIIS_FTPRoot = ftpRoot;
user.MsIIS_FTPDir = ftpDir;
user.System = true;
SecurityUtils.UpdateUser(user, ServerSettings, UsersOU, GroupsOU);
// Set NTFS permissions
var userPermission = GetUserPermission(account.Name, account.Folder);
// Do we need to change the NTFS permissions? i.e. is users home dir changed or are permissions changed?
if (oldDir != ftpDir || account.CanRead != userPermission.Read || account.CanWrite != userPermission.Write)
{
// First get sid of user account
var sid = SecurityUtils.GetAccountSid(account.Name, ServerSettings, UsersOU, GroupsOU);
// Remove the permissions set for this account on previous folder
SecurityUtils.RemoveNtfsPermissionsBySid(Path.Combine(ftpRoot, oldDir), sid);
// If no permissions is to be set, exit
if (!account.CanRead && !account.CanWrite)
{
return;
}
// Add the new permissions
var ntfsPermissions = account.CanRead ? NTFSPermission.Read : NTFSPermission.Write;
if (account.CanRead && account.CanWrite)
{
ntfsPermissions = NTFSPermission.Modify;
}
SecurityUtils.GrantNtfsPermissionsBySid(account.Folder, sid, ntfsPermissions, true, true);
}
break;
default:
// Change user account state and password (if required).
SystemUser user = SecurityUtils.GetUser(account.Name, ServerSettings, UsersOU);
user.Password = account.Password;
user.AccountDisabled = !account.Enabled;
SecurityUtils.UpdateUser(user, ServerSettings, UsersOU, GroupsOU);
// Update iis configuration.
this.FillIisFromFtpAccount(account);
break;
}
}
/// <summary>
@ -400,6 +539,21 @@ namespace WebsitePanel.Providers.FTP
/// <param name="accountName">Account's name to be deleted.</param>
public void DeleteAccount(string accountName)
{
switch (UserIsolationMode)
{
case Mode.ActiveDirectory:
var account = GetAccount(accountName);
// Remove the NTFS permissions first
SecurityUtils.RemoveNtfsPermissions(account.Folder, account.Name, ServerSettings, UsersOU, GroupsOU);
if (SecurityUtils.UserExists(accountName, ServerSettings, UsersOU))
{
SecurityUtils.DeleteUser(accountName, ServerSettings, UsersOU);
}
break;
default:
string virtualDirectory = String.Format("/{0}", accountName);
string currentPhysicalPath = this.ftpSitesService.GetSitePhysicalPath(this.SiteId, virtualDirectory);
@ -416,6 +570,8 @@ namespace WebsitePanel.Providers.FTP
{
SecurityUtils.DeleteUser(accountName, ServerSettings, UsersOU);
}
break;
}
}
/// <summary>
@ -519,6 +675,7 @@ namespace WebsitePanel.Providers.FTP
ftpSite.AllowAnonymous = iisFtpSite.Security.Authentication.AnonymousAuthentication.Enabled;
ftpSite.AnonymousUsername = iisFtpSite.Security.Authentication.AnonymousAuthentication.UserName;
ftpSite.AnonymousUserPassword = iisFtpSite.Security.Authentication.AnonymousAuthentication.Password;
ftpSite["UserIsolationMode"] = iisFtpSite.UserIsolation.Mode.ToString();
// Logging settings.
ftpSite[FtpSite.MSFTP7_SITE_ID] = iisFtpSite.SiteServiceId;
if (iisFtpSite.LogFile.Enabled)

View file

@ -511,6 +511,8 @@ namespace WebsitePanel.Providers.Utils
user.PasswordCantChange = ((userFlags & ADAccountOptions.UF_PASSWD_CANT_CHANGE) != 0);
user.PasswordNeverExpires = ((userFlags & ADAccountOptions.UF_DONT_EXPIRE_PASSWD) != 0);
user.AccountDisabled = ((userFlags & ADAccountOptions.UF_ACCOUNTDISABLE) != 0);
user.MsIIS_FTPDir = GetObjectProperty(objUser, "msIIS-FTPDir").ToString();
user.MsIIS_FTPRoot = GetObjectProperty(objUser, "msIIS-FTPRoot").ToString();
// get user groups
user.MemberOf = GetUserGroups(objUser);
@ -727,6 +729,12 @@ namespace WebsitePanel.Providers.Utils
objUser.Properties["description"].Value = String.IsNullOrEmpty(user.Description) ? "WebsitePanel System Account" : user.Description;
if (user.MsIIS_FTPDir != string.Empty)
{
SetObjectProperty(objUser, "msIIS-FTPDir", user.MsIIS_FTPDir);
SetObjectProperty(objUser, "msIIS-FTPRoot", user.MsIIS_FTPRoot);
}
ADAccountOptions userFlags = ADAccountOptions.UF_NORMAL_ACCOUNT;
if (user.PasswordCantChange)

View file

@ -112,10 +112,10 @@
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="chkBuildUncFilesPath.Text" xml:space="preserve">
<value>Yes</value>
@ -138,4 +138,7 @@
<data name="Text.SelectSite" xml:space="preserve">
<value>&lt;Select FTP Site&gt;</value>
</data>
<data name="lblAdFtpRoot.Text" xml:space="preserve">
<value>FTP RootDir:</value>
</data>
</root>

View file

@ -1,25 +1,42 @@
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="MSFTP70_Settings.ascx.cs" Inherits="WebsitePanel.Portal.ProviderControls.MSFTP70_Settings" %>
<%@ Register Src="Common_ActiveDirectoryIntegration.ascx" TagName="ActiveDirectoryIntegration" TagPrefix="uc1" %>
<%@ Register Src="../UserControls/SelectIPAddress.ascx" TagName="SelectIPAddress" TagPrefix="uc1" %>
<table cellpadding="4" cellspacing="0" width="100%">
<table width="100%">
<tr>
<td class="Normal" width="200" nowrap>
<td class="SubHead" width="150">
<asp:Label ID="lblSharedIP" runat="server" meta:resourcekey="lblSharedIP" Text="Web Sites Shared IP Address:"></asp:Label>
</td>
<td width="100%">
<td class="Normal">
<uc1:SelectIPAddress ID="ipAddress" runat="server" ServerIdParam="ServerID" />
</td>
</tr>
</table>
<asp:UpdatePanel runat="server" UpdateMode="Conditional">
<ContentTemplate>
<table width="100%">
<tr>
<td class="SubHead" width="200" nowrap>
<td class="SubHead" width="150">
<asp:Label ID="lblSite" runat="server" meta:resourcekey="lblSite" Text="FTP Accounts Site:"></asp:Label>
</td>
<td width="100%">
<asp:TextBox ID="txtSiteId" runat="server" CssClass="NormalTextBox" Width="200px"></asp:TextBox>
<td class="Normal">
<asp:DropDownList runat="server" ID="ddlSite" AutoPostBack="True" OnSelectedIndexChanged="ddlSite_SelectedIndexChanged" />
</td>
</tr>
<tr>
<tr runat="server" id="FtpRootRow" visible="False">
<td class="SubHead">
<asp:Label ID="lblAdFtpRoot" runat="server" meta:resourcekey="lblAdFtpRoot" Text="FTP RootDir:"></asp:Label>
</td>
<td class="Normal">
<asp:TextBox ID="txtAdFtpRoot" runat="server" CssClass="NormalTextBox" Width="200px"></asp:TextBox>
<asp:RequiredFieldValidator runat="server" ID="txtAdFtpRootReqValidator" ControlToValidate="txtAdFtpRoot" Enabled="False" ErrorMessage="*"></asp:RequiredFieldValidator>
</td>
</tr>
</table>
</ContentTemplate>
</asp:UpdatePanel>
<table width="100%">
<tr>
<td class="SubHead" width="150">
<asp:Label ID="lblGroupName" runat="server" meta:resourcekey="lblGroupName" Text="FTP Users Group Name:"></asp:Label>
</td>
<td class="Normal">
@ -39,7 +56,6 @@
</td>
<td class="Normal">
<uc1:ActiveDirectoryIntegration ID="ActiveDirectoryIntegration" runat="server" />
</td>
</tr>
</table>

View file

@ -27,10 +27,12 @@
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using System;
using System.Collections.Generic;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Collections.Specialized;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
@ -51,7 +53,8 @@ namespace WebsitePanel.Portal.ProviderControls
{
int selectedAddressid = this.FindAddressByText(settings["SharedIP"]);
ipAddress.AddressId = (selectedAddressid > 0) ? selectedAddressid : 0;
txtSiteId.Text = settings["SiteId"];
BindSiteId(settings);
txtAdFtpRoot.Text = settings["AdFtpRoot"];
txtFtpGroupName.Text = settings["FtpGroupName"];
chkBuildUncFilesPath.Checked = Utils.ParseBool(settings["BuildUncFilesPath"], false);
ActiveDirectoryIntegration.BindSettings(settings);
@ -75,7 +78,11 @@ namespace WebsitePanel.Portal.ProviderControls
{
settings["SharedIP"] = String.Empty;
}
settings["SiteId"] = txtSiteId.Text.Trim();
settings["SiteId"] = ddlSite.SelectedValue;
if (!string.IsNullOrWhiteSpace(txtAdFtpRoot.Text))
{
settings["AdFtpRoot"] = txtAdFtpRoot.Text.Trim();
}
settings["FtpGroupName"] = txtFtpGroupName.Text.Trim();
settings["BuildUncFilesPath"] = chkBuildUncFilesPath.Checked.ToString();
ActiveDirectoryIntegration.SaveSettings(settings);
@ -92,5 +99,31 @@ namespace WebsitePanel.Portal.ProviderControls
}
return 0;
}
private void BindSiteId(StringDictionary settings)
{
var sites = ES.Services.FtpServers.GetFtpSites(PanelRequest.ServiceId);
foreach (var site in sites)
{
var item = new ListItem(site.Name + " (User Isolation Mode: " + site["UserIsolationMode"] + ")", site.Name);
if (item.Value == settings["SiteId"])
{
item.Selected = true;
}
ddlSite.Items.Add(item);
}
ddlSite_SelectedIndexChanged(this, null);
}
protected void ddlSite_SelectedIndexChanged(object sender, EventArgs e)
{
var isActiveDirectoryUserIsolated = ddlSite.SelectedItem.Text.Contains("ActiveDirectory");
FtpRootRow.Visible = isActiveDirectoryUserIsolated;
txtAdFtpRootReqValidator.Enabled= isActiveDirectoryUserIsolated;
}
}
}

View file

@ -1,7 +1,6 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:2.0.50727.1378
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@ -11,12 +10,6 @@
namespace WebsitePanel.Portal.ProviderControls {
/// <summary>
/// MSFTP70_Settings class.
/// </summary>
/// <remarks>
/// Auto-generated class.
/// </remarks>
public partial class MSFTP70_Settings {
/// <summary>
@ -47,13 +40,49 @@ namespace WebsitePanel.Portal.ProviderControls {
protected global::System.Web.UI.WebControls.Label lblSite;
/// <summary>
/// txtSiteId control.
/// ddlSite control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.TextBox txtSiteId;
protected global::System.Web.UI.WebControls.DropDownList ddlSite;
/// <summary>
/// FtpRootRow control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.HtmlControls.HtmlTableRow FtpRootRow;
/// <summary>
/// lblAdFtpRoot control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Label lblAdFtpRoot;
/// <summary>
/// txtAdFtpRoot control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.TextBox txtAdFtpRoot;
/// <summary>
/// txtAdFtpRootReqValidator control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.RequiredFieldValidator txtAdFtpRootReqValidator;
/// <summary>
/// lblGroupName control.