Friday, April 19, 2013

Debugging IIS 7.5 FTP Custom Authentication Provider

A customers need was to have quickly an ftp server to share large files with some third party. The security restrictrions in our company need a two-factor autentication.

So I had the idea to create a custom authentication provider where the user can provider his password and token in the ftp password field like password#token.

In this post I will not explain how you create a custom authetication provider. This is explained very well on the links I'll post.

I found this great blog post of Robert MyMurray where he describes how to create a custom provider with multiple examples. I followed his steps and realized that I couldn't debug the code I wrote with Visual Studio.

Then I found this post on iis.net, which finally helped me to debug my code.

Steps to debug:

I assume that:

  • You already created a solution and implemeted one of the examples of Rober McMurray or your own one.
  • You signed your dll and deployed it to your Global Assembly Cache
  • You installed and configured a ftp site on your IIS
  • You registered your provider. This is little bit tricky. There is no check when you register your provider. Please be sure to enter the correct format:
    Namespace.Classname,DLL Name,Version,Culture,PublixKeyToken
    (e.g FTP.Authentication.FtpLdapAuthentication,FTP.Authentication,Version=1.0.0.0,Culture=neutral,PublicKeyToken=e1729a8537bc265b)
    You must register the provider on server level not on site.
  • You changed the FTP Authentication Provider to your custom one.

1.) Load Process

First you have to start the process which loads your assembly. Go to your ftp server open a dos command prompt and type:

C:\>ftp localhost

Now type something. If your login was unsuccessful type quit

ftp>quit.

Now the ftp service must have loaded your assembly if you registered it correctly. Type now following command into the dos command to find the process id of the process which loaded your assembly.

C:\>tasklist /M <Name of your dll>.dll


Now attach your Visual Studio to the process. Open Visual Studio > Debug > Attach to process and select the process dllhost.exe with the found PID:

Now set a breakpoint somewhere in your AuthenticateUser method. Somehow the initialize method is called prior.

Now type again in your command prompt:

C:\>ftp localhost

Enter your crendetials. Now the debugger should popup.


2.) Deploy a new dll

If you changed your code and build a new dll and you want to debug it, you have to kill the process whic hosts your dll.

Follow these steps to deploy and debug a new dll
  1. Quit the ftp prompt with "quit"
  2. Kill the process with: 
    1. C:\>taskkill /pid 12308 /f
  3. stop the ftpserver with :
    1. C:\>net stop ftpsvc
  4. Browse to C:\Windows\assembly
  5. Right click on your assembly and uninstall
  6. Move your new assembly to C:\windows\assembly (You cant copy you have to drag it with your mouse or gacutil tool)
  7. Start your ftp server
    1. C:\>net start ftpsvc
  8. Login to your ftp server and enter some crendentials
    1. C:\>ftp localhost
  9. Quit the ftp server
  10. Find the Process ID (PID) of the dllhost:
    1. C:\>tasklist /M <your dll name>.dll
  11. Attach to the new dllhost.exe
  12. Login to your ftp server again


Sources:




Tuesday, April 16, 2013

Offline Metadata Instances in SharePoint 2010 & OfflineTermstoreNames

If you're using powershell to add metadata to your termstore and you see only an entry in the OfflineTermstoreNames property, then it seems that some of your Metadata Services are offline.

C:\> $site = Get-SPSite http://mysharepoint/sites/project
C:\> $session = new-object Microsoft.SharePoint.Taxonomy.TaxonomySession($site) 
C:\> $session

To activate all instances open the SharePoint Management Shell and type:

C:\>$instance = Get-SPServiceInstance | ? {$_.TypeName -eq "Managed Metadata Service"}
C:\>$instace

It will now display all your instances. If the e.g. first and second are disabled, start it with:

C:\>$instance[0] | Start-SPServiceInstance #Start First
C:\>$instance[1] | Start-SPServiceInstance #Start Second

Wait few minutes. Grab the instance again and check if they are enabled:

C:\>$instance = Get-SPServiceInstance | ? {$_.TypeName -eq "Managed Metadata Service"}
C:\>$instace

Now all Termstores should be online.

Friday, April 12, 2013

Migrate a SharePoint Team Wiki to an Enterprise Wiki

Perhaps someone has also migrated his old SharePoint 2007 Team Wiki to SharePoint 2010 and wants to have the cool features from an Enterprise Wiki.

I searched a while and I think the best way to do this is to migrate with PowerShell. The List Wiki and the Enterprise Wiki are using different fields so there will be no other way I thing but PowerShell or manually.

So the great script for your use. Just adapt the settings for your environment.

 <# PowerShell Script to migrate Team Wikis into Enterprise Wiki Pages #>  
   
 # Setup Basic sites and pages  
 $webappURL     = "http://sharepoint-uat"  
 $wikiSiteURL  = "$webappURL/sites/serverplatforms"        
 $wikiWebURL    = "$wikiSiteURL/wiki"              
 $pageFolder    = "/Seiten/"  
   
 $oldWikiWeb   = "$webappURL/sites/serverplatforms"  
 $wikiListName  = "Team Wiki"  
   
 try   
 {  
   Write-Host " >> STARTING MIGRATION ..." -foregroundcolor green  
   Write-Host "   1. GETTING SiteColletion: $wikiSiteURL" -foregroundcolor green   
   $wikiSite   = Get-SPSite $wikiSiteURL  
   $psite     = New-Object Microsoft.SharePoint.Publishing.PublishingSite($wikiSite)   
   
   Write-Host "   2. GETTING ENTERPRISE WIKI WEB: $wikiWebURL" -foregroundcolor green   
   $web     = Get-SPWeb $wikiWebURL  
   $pweb     = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPublishingWeb($web)  
   $pages     = $pweb.GetPublishingPages($pweb)  
   
   Write-Host "   3. GETTING WIKI PAGE LAYOUT" -foregroundcolor green   
   $ctype     = $web.AvailableContentTypes | ? { $_.Name -eq "Enterprise Wiki Page"}  
   $layouts   = $psite.GetPageLayouts($ctype, $true)  
   $layout   = $layouts[0]  
   
   # OLD WIKI  
   Write-Host "   4. GETTING OLD WIKI" -foregroundcolor green   
   $wikiWeb  = Get-SPWeb $oldWikiWeb  
   $wiki     = $wikiWeb.Lists[$wikiListName]  
   
   Write-Host "   5. LOOPING THROUGH THE WIKI LIST ITEMS" -foregroundcolor green   
   $i = 0;  
   foreach ($oldItem in $wiki.Items) {  
     Write-Host ""  
   
     # Create a new page in the enterprise wiki  
     $name     = $oldItem["ows_BaseName"]  
     if ($name -eq "home") {  
       continue;  
     }  
     Write-Host "     >> MIGRATING ITEM: $name" -foregroundcolor yellow    
     $strDestURL = $wikiWebURL + $pageFolder + $name + ".aspx"  
       
     Write-Host "     >> NEW URL IS: $strDestURL" -foregroundcolor yellow  
     $page     = $pages.Add($strDestURL, $layout)  
       
     Write-Host "     >> CHANGING PAGE PROPERTIES" -foregroundcolor yellow  
     $item       = $page.ListItem      
     $author     = $oldItem["ows_Created_x0020_By"]  
     $userID     = $web.EnsureUser($author).ID  
     $item["Title"]   = $name  
     $item["Editor"] = $userID  
     $item["Author"] = $userID      
       
     # Replace the links in the new content  
     $content   = $oldItem["ows_WikiField"]  
     $newContent = $content -replace "/Team%20Wiki/", "/wiki/Seiten/"    
       
     # Add new content to the page  
     $item["ows_PublishingPageContent"] = $newContent  
     $item.SystemUpdate($false)  
     $i++;  
   }  
   
   Write-Host "   6. MIGRATION FINISHED !!" -foregroundcolor green   
   Write-Host "     >> MIGRATED $i SITES." -foregroundcolor yellow  
   $site.Dispose()  
   $web.Dispose()  
 }  
 catch [System.Exception] {  
   Write-Host "Error while migration Wiki List...`n" -foregroundcolor red  
   $_.Exception.ToString();    
   exit  
 }   

Wednesday, April 10, 2013

Using WebDav on IIS 7 to access UNC Paths

In this post I want to show you step by step how to connect to a file share using webdav on IIS 7. For this post I assume:
  • that you have already an IIS installed on the server 
  • that you have installed WebDav or enabled the WebDav Feature on IIS.
  • the server on which is IIS installed can reach the file share.

1: CREATE APPLICATION POOL

The first step is to create a seperate application pool on the IIS.
  • Open the program "Internet Information Services Manager".
  • Click on "Application Pools"
  • Click on "Add Application Pool" on the right menu
  • Name it "WebDav". Let the rest as it.
  • Right click on the new created Application Pool "WebDav" and select "Advanced Settings". Pay attention to the following attributes:
    • .Net Framework Version: No Managed Code
    • Identity: The identity of the Application Pool should be an account which has permissions to read the file share.
    • Load User Profile: Should be set to "False"


2: CREATE WEB SITE

The second step is to create a site.

  • Click on "Sites"
  • Click on "Add Web Site" on the right menu
  • Use following properties  
    • Name : WebDav
    • Application Pool: WebDav
    • Physical Path: A Path on the server
    • Host Name: The URL to connect to the webdav
Settings when creating a new web site

3: ADD WEBDAV AUTHORING RULE

Now we have to allow everybody to use WebDav.

  • Click on the Website "WebDav" and open "WebDav Authoring Rules" in the Features list (This Feature is only visible if you installed WebDav).
  • Click on "Add Authoring Rule" on the right pane.
  • Check following boxes and click OK.


4: CREATE A VIRTUAL PATH (APPLICATION)

In this step you have to add a virtual path to a file share. A virtual path is something like a symbolic link in linux. You define an alias path which can show to a local path on the server or even to a network path.

  • Right click on the Web Site "WebDav"
  • Click on "Add Virtual Directory"
  • Enter an alias and the path to the file share
  • Click on "Test Settings" to check the connection.
  • Now right click on the new created virtual path and select "Convert to an application". Applications in IIS can have their own application pool and authentications.


5: KERBEROS AND DOUBLE HOP

We have to use Kerberos authetication because the user credential must be delegated by the IIS Server to the file share. NTLM cannot delegate credentials and therefore we have to use Kerberos. Because there is a server in the middle you often have to deal with the double hop issue.

First let us check the authetication setting in our application.

  • Click on your new virtual application "J" and select the feature "Authentication"
  • You'll see a lot of authentication methods. Disable all except "Windows Authentication"
  • Richt click on "Windows Authetication" and select "Advanced Settings". Ensure that the checkbox for "Enable kernel-mode Authetication" is checked. Close the dialog.
  • Right click on "Windows Authetication" again and select "Providers". Ensure that "Negotiate" sits  on the top of "NTLM".


Now you've to check some requirements for Kerberos

  1. The computer must have the rights to delegate Kerberos Tickets. Therefore activate in your Active Directory the option "Trust this computer for delegation to any service".
  2. The the SPNs for your computer, your application pool account. When you try to connect to the WebDav and a login prompt appears, than you can be sure that the SPNs are not set correctly. Ask your Domain Admin to set the SPNs correctly.

    We have enabled the "kernel-mode" option so I think that it would be enough to set the SPNs for your computer account, but I haven't tested it yet.

    To set the SPNs the Domain Admins are using the SetSPN command. The paramters shoul be:

    Web application: http://webserver.mydomain.com
    Server Name: WIN1001

    SetSPN -s HOST/WIN1001
    SetSPN -s HOST/WIN1001.mydomain.com
    SetSPN -s HTTP/webserver.mydomain.com
    SetSPN -s HTTP/webserver


6: TESTING THE ACCESS

If all settings are done you should now be able to access the share via webdav. Go to a client and open the windows explorer.

If you already have a dns entry for webdav try to connect via \\webdav\J. J was our virtual path.


If you don't have a dny entry you can try to use the server name like \\WIN1010\J. To use this you have to change the bindings in the IIS Website.

To change the bindings:

  1. Go to your IIS Server and open the Internet Information Services Manager.
  2. Right Click on the website "WebDav". Select "Edit Bindings"
  3. Click on "Add"
  4. Don't change anything in the dialog and click on OK.
  5. Now your Website is listening to all request coming to your server. 
  6. If you have other web site it can be that the binding exists anywhere else. If so than enter the Server Name as Host Name in the bindings or delete the other binding.