Solved

Set up AspNetAuth on FTP with IIS7 and FTP service 7.5

Posted on 2010-09-17
10
1,726 Views
Last Modified: 2013-12-02
Hi,

since days I try to set up IIS7 (with ftp services 7.5) to use my AspNetSqlRoleProvider to allow and deny access to the ftp server.

I found some tutorials but with both I cannot get it up and running.

http://learn.iis.net/page.aspx/389/configuring-ftp-with-net-membership-authentication/
http://learn.iis.net/page.aspx/305/configuring-ftp-75-user-isolation/

I set up the connection string, the defaultp Provider, the user role that shall be allowed to connect and the user isolation.

If I allow anonymous access it works. If I try to login with the user credentials that work on the website (and has additionally the role that is setup to allow access) it does not work.

It does only show "530 User cannot log in. Unable to establish connection"

Any help will be apreciated
0
Comment
Question by:HugoHiasl
  • 5
  • 5
10 Comments
 
LVL 13

Expert Comment

by:Greg Hejl
ID: 33711238
your authprovider is failing.

do some packet inspection with wireshark to determine where the failure is occuring

it's either your connection to sql or the query/response

are you getting any events related to this on your sql server?
0
 
LVL 12

Author Comment

by:HugoHiasl
ID: 33714435
You're right. Now It works.

But now there is one other problem.

I use user isolation. When the user "aaa" tries to log in, I get the error "530 User cannot log in. Home directory inaccessible".

The directory structure is

LocalUser
    aaa
    Public


When I set a role base authorization in the user isolation in the way that users with the role "ftpupload" may log in, the user directory "aaa" inherits this setting. With this setting the user "aaa" cannot log in.

When I change the authorization setting for the "aaa" directory from role based to user based and allow the user "aaa" access to it, he can log in and anything works.

But I do this, I need to setup every new user manually. I did not want that because there can be lots of users that register for the web page. I would like to automatically create the home directory when a user registers.

0
 
LVL 13

Expert Comment

by:Greg Hejl
ID: 33715267
set this up in your sign up script

when you create the user also create the home directory.  drop the home directory in the sql db along with user credentials.

have your authprovider pull the home dir
0
 
LVL 12

Author Comment

by:HugoHiasl
ID: 33753927
Hi Greg,

I tried to figure your tips out. But I cannot find any place in the Role- or Membership-Providers where the homepage could be retrieved from the provider.

I also cannot find a setting in the ftp server to pull the home directory from the provider.
0
 
LVL 13

Expert Comment

by:Greg Hejl
ID: 33758485
does the directory exist?
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 12

Author Comment

by:HugoHiasl
ID: 33759827
I can create it when the user gets activated.

I plan to have site where a user register. This site has different roles. One of it is "ftpupload". Users with this role shall be able to upload files with user isolation. They shall not be able to see the files of other users.

I realized that I probably will be able to set up the proper rights using the IIS Management API. At the moment I try to figure out how this works.
0
 
LVL 13

Expert Comment

by:Greg Hejl
ID: 33760232
http://learn.iis.net/page.aspx/598/how-to-use-managed-code-c-to-create-a-simple-ftp-authentication-provider/

i'm sure you've probably been here,

we used this and added code for the connection to sql db and logging
0
 
LVL 12

Author Comment

by:HugoHiasl
ID: 33801768
I'm very close to what I want to achieve :-)

I'm now able to create virtual directories with the Microsoft.Web.Administration assembly.

I found nearly anything here: http://www.iis.net/ConfigReference/system.ftpServer/security/authorization

The only last problem I face is that I can setup authorization only for the main directory. I want to do it for single sub-directories. The attached code show the example for setting it for the main directory. But how to change if I want to set it for /aaa directory?
using System;using System.Text;using Microsoft.Web.Administration;

internal static class Sample

{

   private static void Main()

   {

      using (ServerManager serverManager = new ServerManager())

      {

         Configuration config = serverManager.GetApplicationHostConfiguration();

         ConfigurationSection authorizationSection = config.GetSection("system.ftpServer/security/authorization", "Default Web Site");

         ConfigurationElementCollection authorizationCollection = authorizationSection.GetCollection();



         ConfigurationElement addElement = authorizationCollection.CreateElement("add");

         addElement["accessType"] = @"Allow";

         addElement["roles"] = @"administrators";

         addElement["permissions"] = @"Read, Write";

         authorizationCollection.Add(addElement);



         ConfigurationElement addElement1 = authorizationCollection.CreateElement("add");

         addElement1["accessType"] = @"Deny";

         addElement1["users"] = @"guest";

         addElement1["permissions"] = @"Read, Write";

         authorizationCollection.Add(addElement1);



         serverManager.CommitChanges();

      }

   }

}

Open in new window

0
 
LVL 13

Accepted Solution

by:
Greg Hejl earned 500 total points
ID: 33802500
my assistant wrote this for sql auth and directory isolation.

we already had a db setup for users that sign up
REFERENCES: 

Microsoft.Web.FtpServer
System
System.Data


using System;
using System.IO;
using System.Data;
using System.Data.SqlClient;
using Microsoft.Web.FtpServer;

namespace FtpAuthentication
{

    public class FtpAuth : 
        BaseProvider,
        IFtpAuthenticationProvider,
        IFtpHomeDirectoryProvider
    {
        /* Much of this code is taken from the Microsoft Technet article: How to Use Managed Code (C#) to Create a Simple FTP Authentication Provider
         * Modifications for MorePhotos logic by Adrian  9/25/2009
         * This is his first compiled application
         * 
         * large modification to attempt to resolve periodic iftphomedirectory lockout
         * 9/10/2010 Adrian Maule
         * 
         * 
         * */


        
        private string strHomeDir;
        private string strRole;
        SqlDataReader reader;

        public static SqlConnection getConn()
        {
            string strConn = "Server=db1;Initial Catalog=sitekeys;User Id=ftp_auth;Password=9ah3n8$*;Trusted_Connection=false";
            SqlConnection cn = new SqlConnection(strConn);
            return cn;
        }
        
        public static void WriteToFile(String strMessage)
        {
            // define the logfile name, new log file each day

            string strLogFileName = "c:\\logfiles\\FTP\\" + DateTime.Today.DayOfYear.ToString() + ".txt";
            StreamWriter w = File.AppendText(strLogFileName);

            w.Write("{0} {1}", 
                    DateTime.Now.ToLongTimeString(),
                    DateTime.Now.ToLongDateString());
            w.WriteLine(":" 
                    + strMessage);

             //Update the underlying file.
            w.Flush();
            w.Close();            
        }
       
        #region iftpAuthenticationProvider

        bool IFtpAuthenticationProvider.AuthenticateUser(
            string sessionId,
            string siteName,
            string userName,
            string userPassword,
            out string canonicalUserName)
            {
            canonicalUserName = userName;
            

            // First check to see if they are in the database
            //WriteToFile(strConn);

            WriteToFile("ftp_login: " + userName + ", password: " + userPassword);
            bool blnStatus = false;
            /*
             * we need to check for a usename/password match to both xxxxxxmanager and website.
             * */

            string sqlStatement = ""
                + "SELECT "
                    + "a.sitename, "
                    + "a.siteFTPHomeDir, "
                    + "a.FTPhomeDir, "
                    + "a.siteFTPUsername, "
                    + "a.FTPUsername "
                + "FROM userkeys a "
                + "WHERE "
                    + "(a.siteFTPusername = '" + userName + "' "
                    + "and a.siteFTPpassword = '" + userPassword + "')"
                + "OR  "
                    + "(a.FTPusername = '" + userName + "' "
                    + "and a.FTPpassword = '" + userPassword + "')";

           //WriteToFile(sqlStatement);

            try
            {
                // Verify that the user name and password are valid.

                /* I had some problems with the objects being open with the sql calls, 
                 * so I'm making sure that they are closed
                 * before I open them again 
                 * */
                
                //WriteToFile("SqlConnection Coming Up");

                SqlCommand cmd = new SqlCommand(sqlStatement);
                SqlConnection cn = getConn();
                if (cn.State != ConnectionState.Open)
                {
                    cn.Close();
                }
                cn.Open();

                cmd.Connection = cn;
                cmd.CommandText = sqlStatement;
                reader = cmd.ExecuteReader();

                if (reader.IsClosed != true)
                {
                    while (reader.Read())
                    {
                        blnStatus = true;
                    }
                    reader.Close();
                }
                cn.Close();

            }
            catch (Exception e)
            {
                WriteToFile("SQL FAIL " + e.ToString() + "\r\n" + sqlStatement);
                blnStatus = false;
            }
            finally
            {
                    reader.Close();
            }
            // Note: In this example, the user name is case-insensitive

            if (blnStatus != true)
            {
                WriteToFile("BAD AUTH: " + userName);
            }
            else
            {
                WriteToFile("AUTH OK : " + userName);
            }          
            return blnStatus;
        }
    #endregion

    

    #region IFtpHomeDirectoryProvider Members

    string IFtpHomeDirectoryProvider.GetUserHomeDirectoryData(
     string sessionId,
     string siteName,
     string userName)
        {
            WriteToFile("ftp_getDir: " + userName);
            string strOutput;
            string sqlStatement = ""
                    + "SELECT "
                       + "a.sitename, "
                        + "a.siteFTPHomeDir, "
                        + "a.FTPhomeDir, "
                        + "a.siteFTPUsername, "
                        + "a.FTPUsername, "
                        + "b.servername as webservername, "
                        + "c.servername as ftpservername "
                    + "FROM userkeys a "
                    + "LEFT JOIN servers b on a.webserver = b.id "
                    + "LEFT JOIN servers c on a.ftpserver = c.id "
                    + "WHERE "
                        + "(siteFTPusername = '" + userName + "' ) "
                    + "OR  "
                        + "(FTPusername = '" + userName + "' )";
           //WriteToFile(sqlStatement);
            try
            {
                /* I had some problems with the objects being open with the sql calls, 
                * so I'm making sure that they are closed
                * before I open them again 
                * */
               
                
                // Find which type of user it is.
                SqlConnection cn = getConn();
                if (cn.State != ConnectionState.Closed)
                {
                    cn.Close();
                }
                cn.Open();

                SqlCommand cmd = new SqlCommand(sqlStatement);
                cmd.Connection = cn;
                cmd.CommandText = sqlStatement;
                reader = cmd.ExecuteReader();
                string strWebUser="";
                string strPmUser="";
                string strWebDir="";
                string strWebServerName="";
                string strFtpServerName="";
                string strServerName="";

                while (reader.Read())
                {
                     strWebUser = reader["siteFTPUsername"].ToString();
                     strPmUser = reader["FTPUsername"].ToString();
                     strWebDir = reader["SiteFTPHomeDir"].ToString();
                     strWebServerName = reader["webservername"].ToString();
                     strFtpServerName = reader["ftpservername"].ToString();
                     strServerName = "";
                
                }
                reader.Close();
                if (userName == strWebUser)
                {
                    strHomeDir = strWebDir;
                    strRole = "Web";
                    strServerName = strWebServerName; WriteToFile("ftp_dir: " + userName + "; " + sessionId.ToString() + ":" + strRole + "HomeDir =  " + strHomeDir);
                }
                else if (userName == strPmUser)
                {
                    // this homedir needs to be the root of images to allow xxxxxmanager to path correctly
                    // we are using a DFS from mpfilemscsfs.
                    strHomeDir = "\\\\mpfilemscsfs\\images\\";
                    strRole = "xxxxxManager";
                    strServerName = strFtpServerName; WriteToFile("AUTHENTICATED: " + userName + "; " + sessionId.ToString() + ":" + strRole + "HomeDir =  " + strHomeDir);
                }
                else
                {
                    WriteToFile("NO USERTYPE FOUND FOR: " + userName);
                    strRole = "No Match";
                }
                reader.Close();
                cn.Close();
            }
            catch (Exception e)
            {

                WriteToFile("SQL FAIL: " + e.ToString() + "\r\n" + sqlStatement);
                strOutput="Failed";

            }
            finally
            {
            }

           
            /*
             * this area is a little insurance that we're going to path right on the servers
             * because there is a lot of D:\ and E:\ in userkeys
             * ALL PATHS LEAD TO \\mpfilemscsfs\
             * */
            
            string strEDrive = "e:\\";
            string strDDrive = "d:\\";
            string strCDrive = "c:\\";
            string strPath = "\\\\mpfilemscsfs\\";
            strHomeDir = strHomeDir.Replace(strDDrive, strPath);
            strHomeDir = strHomeDir.Replace(strEDrive, strPath);
            strHomeDir = strHomeDir.Replace(strCDrive, strPath);

            WriteToFile("ftp_dir: " + userName + ":" + strHomeDir);
            strOutput = strHomeDir;
            string strNow = System.DateTime.Now.ToString();

            return strOutput;
           // return "true";
        }
    #endregion
    }
}

Open in new window

0
 
LVL 12

Author Closing Comment

by:HugoHiasl
ID: 33803038
Perfect... thanks a lot.. I'll try tomorrow.

If I have further questions I will open a new question with new points :-)
0

Featured Post

Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

Join & Write a Comment

Logparser is the smartest tool I have ever used in parsing IIS log files and there are many interesting things I wanted to share with everyone one of the  real-world  scenario from my current project. Let's get started with  scenario - How do w…
Samba is the de-facto standard program (or, more correctly: suite of programs) that UNIX and Linux systems use to share files with Microsoft Windows (and more recently, Mac OS-X) systems. Currently, there are 2 common versions of Samba available,…
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.

757 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

23 Experts available now in Live!

Get 1:1 Help Now