Sunday, December 4, 2011

Remove BDC Models in PowerShell

I needed a PowerShell script to enumerate over all the installed BDC Models (and delete them), but couldn't find the example on TechNet or MSDN. After trying some things, I found the following script:


$context = "http://sharepoint.local"
$bdc = Get-SPBusinessDataCatalogMetadataObject -BdcObjectType Catalog -ServiceContext $context
foreach ($model in $bdc.GetModels("*") ) {
    Remove-SPBusinessDataCatalogModel –Identity $model
}

Thursday, August 11, 2011

SharePoint File Upload

For some little functionality, I wanted to do a file upload to a document library by some custom .NET only code:


ListsSoapClient client = new ListsSoapClient();
XElement result = client.GetListItems("{642DF480-74CB-4EDC-865C-CA009054998F}", null, null, null, null, null, null);
XNamespace rs = "urn:schemas-microsoft-com:rowset";
XNamespace z = "#RowsetSchema";
var data = result.Descendants(rs + "data").Descendants(z+"row");

CopySoapClient copyClient = new CopySoapClient();
FieldInformation[] fields;
byte[] output;
uint result2 = copyClient.GetItem(Uri.EscapeUriString("http://example.hostname/"+"Documents/Report.xls"), out fields, out output);

string destinationUrl = "http://example.hostname/Documents/Test.xls";
string[] destinationUrls = { Uri.EscapeUriString(destinationUrl) };
List<fieldinformation> fieldsList = new List<fieldinformation>();

CopyResult[] copyResults;

uint result3 = copyClient.CopyIntoItems("+", destinationUrls, fieldsList.ToArray(), output, out copyResults);
WebRequest request = WebRequest.Create(destinationUrl);
request.Method = "PUT";
request.Credentials = CredentialCache.DefaultCredentials;
// Write the contents of the local file to the request stream.
using (Stream stream = request.GetRequestStream())
{
//Load the content from local file to stream
stream.Write(output, 0, output.Length);
}
WebResponse response = request.GetResponse();
response.Close();

Friday, August 5, 2011

Tips while working with SharePoint projects in VS2010

  • Install the CSKDev tools
  • Use quick deploy on the project to test small changes in markup and code
  • Page layouts don't support Intellisense when double clicking the aspx (VS2010 opens the file in textmode). Right-click and use 'View Code' or 'View Markup' will open the file as a webpage, with fill Intellisense support.
  • To start with already filled page layouts based on the content type, use the CSKDev 'Create page layout' on the content type in the Server Explorer.

Thursday, August 4, 2011

Get Taxonomy terms from the user while configuring a WebPart

In my current SharePoint 2010 project we make use of Managed Metadata terms a lot. We want to be able to select taxonomy terms while configuring WebParts, but the setup of the taxonomy field isn't quite straightforward. For the configuration of WebParts with exotic controls, you need to implement a custom ToolPart and link it to your WebPart. Because I think we will create a lot of custom ToolParts, I created a base class for displaying these taxonomy fields.

   1:  /// <summary>
   2:  /// This class makes it easier to work with Taxonomy data in a <see cref="Microsoft.SharePoint.WebPartPages.ToolPart">ToolPart</see>
   3:  /// </summary>
   4:  public class TaxonomyToolPart : ToolPart
   5:  {
   6:      /// <summary>
   7:      /// Gets or sets the name of the term store.
   8:      /// </summary>
   9:      /// <value>
  10:      /// The name of the term store.
  11:      /// </value>
  12:      public string TermStoreName { get; protected set; }
  13:      /// <summary>
  14:      /// Gets or sets the name of the term group.
  15:      /// </summary>
  16:      /// <value>
  17:      /// The name of the term group.
  18:      /// </value>
  19:      public string TermGroupName { get; protected set; }
  20:      /// <summary>
  21:      /// Gets or sets the name of the term set.
  22:      /// </summary>
  23:      /// <value>
  24:      /// The name of the term set.
  25:      /// </value>
  26:      public string TermSetName { get; protected set; }
  27:      /// <summary>
  28:      /// Gets or sets a value indicating whether multiple terms can be selected.
  29:      /// </summary>
  30:      /// <value>
  31:      ///   <c>true</c> if multiple terms can be selected; otherwise, <c>false</c>.
  32:      /// </value>
  33:      public bool MultiSelect { get; protected set; }
  34:   
  35:      private TaxonomyWebTaggingControl TaxonomyControl { get; set; }
  36:   
  37:      /// <summary>
  38:      /// Called by the ASP.NET page framework to notify server controls that use composition-based 
  39:      /// implementation to create any child controls they contain in preparation for posting back or rendering.
  40:      /// </summary>
  41:      protected override void CreateChildControls()
  42:      {
  43:          // create a panel that will hold all of our controls 
  44:          Panel toolPartPanel = new Panel();
  45:   
  46:          // create the actual control 
  47:          SPContext context = SPContext.Current;
  48:          SPSite site = context.Site;
  49:          TaxonomySession session = new TaxonomySession(site);
  50:          TermStore termStore = session.TermStores[TermStoreName];
  51:          Group group = termStore.Groups[TermGroupName];
  52:          TermSet productsTermSet = group.TermSets[TermSetName];
  53:   
  54:   
  55:          TaxonomyControl = new TaxonomyWebTaggingControl();
  56:          TaxonomyControl.ID = "taxonomyControl";
  57:          TaxonomyControl.SspId.Add(termStore.Id);
  58:          TaxonomyControl.TermSetId.Add(productsTermSet.Id);
  59:          TaxonomyControl.IsAddTerms = false;
  60:          TaxonomyControl.AllowFillIn = true;
  61:          TaxonomyControl.IsMulti = MultiSelect;
  62:   
  63:          TaxonomyControl.Text = GetTextFromWebPart(this.ParentToolPane.SelectedWebPart);
  64:   
  65:          toolPartPanel.Controls.Add(TaxonomyControl);
  66:   
  67:          // finally add the panel to the controls collection of the tool part 
  68:          Controls.Add(toolPartPanel);
  69:   
  70:          base.CreateChildControls();
  71:      }
  72:   
  73:      /// <summary>
  74:      /// Gets the textual representation of the selected terms from the WebPart and sets it on the Taxonomy control.
  75:      /// </summary>
  76:      /// <param name="webPart">The web part.</param>
  77:      /// <returns>a value from the webpart to select in the TaxonomywebTaggingControl</returns>
  78:      /// <remarks>Override this method in your child class to link the webpart property with the taxonomy field.</remarks>
  79:      /// <example>the term string has a value like 'Term 1|db61b704-cf1d-490d-bfc3-4cbcd8d2f453;Term 2|66b5696d-94a2-4299-ae34-63d3072ca357</example>
  80:      protected virtual string GetTextFromWebPart(WebPart webPart) { return string.Empty; }
  81:   
  82:      /// <summary>
  83:      /// Sets the textual representation of the selected terms from the Taxonomy control to the WebPart.
  84:      /// </summary>
  85:      /// <param name="webPart">The parent web part.</param>
  86:      /// <param name="selectedTerms">The selected terms.</param>
  87:      /// <remarks>Override this method in yout child class to link the taxonomy filed with the webpart property</remarks>
  88:      /// <example>the term string has a value like 'Term 1|db61b704-cf1d-490d-bfc3-4cbcd8d2f453;Term 2|66b5696d-94a2-4299-ae34-63d3072ca357</example>
  89:      protected virtual void SetTextToWebPart(WebPart webPart, string selectedTerms) { }
  90:   
  91:      /// <summary>
  92:      /// Called when the user clicks the OK or the Apply button in the tool pane.
  93:      /// </summary>
  94:      public override void ApplyChanges()
  95:      {
  96:          WebPart webPart = this.ParentToolPane.SelectedWebPart;
  97:          SetTextToWebPart(webPart, TaxonomyControl.Text);
  98:      }
  99:  }

This base class can now be used in a new class, where the configuration of the ToolPart and the linking with the WebPart needs to be implemented:

   1:  public class TestToolPart : TaxonomyToolPart
   2:  {
   3:      public TestToolPart()
   4:      {
   5:          this.TermStoreName = "Managed Metadata";
   6:          this.TermGroupName = "NL";
   7:          this.TermSetName = "Brand";
   8:          this.MultiSelect = true;
   9:          this.Title = "Taxonomy Example";
  10:      }
  11:   
  12:     protected override string GetTextFromWebPart(Microsoft.SharePoint.WebPartPages.WebPart webPart)
  13:      {
  14:          return ((TestWebPart)webPart).Text;
  15:      }
  16:   
  17:      protected override void SetTextToWebPart(Microsoft.SharePoint.WebPartPages.WebPart webPart, string selectedTerms)
  18:      {
  19:          ((TestWebPart)webPart).Text = selectedTerms;
  20:      }
  21:  }        

The only thing you need to do is override the GetToolParts() in your WebPart to inject your custom ToolPart in the ToolPart array, and your ToolPart should work.

Sunday, January 23, 2011

Enhanced ASP.NET input sanitation with AntiXSS

Need for input sanitation

The applications you build for the internet can have quite a big audience. It is possible for the whole connected world to visit your website and use the app you built on it. But with these visitors, you will attract dark forces who can misuse your application for their own agenda. It is therefore needed to harden your application, and be sure no-one can send email, inject custom HTML and javascript and hijack user information. It is needed you built secure code and protect yourself.

The main characteristic of an application is that it needs input data from the end user. With this input data, something is done. If this data is sent back to the user, is can be displayed on the screen. In it most simple form, this looks like:


<div>
<asp:TextBox ID="inputBox" runat="server" TextMode="MultiLine" />
<br />
<asp:Button ID="submitButton" runat="server" Text="Submit"
onclick="submitButton_Click" />
<br />
<asp:Label runat="server" EnableViewState="True" AssociatedControlID="resultLiteral" Text="Html output:" />
<asp:Literal ID="resultLiteral" runat="server"></asp:Literal>
</div>



With the following button_click code:


protected void submitButton_Click(object sender, EventArgs e)
{
string input = inputBox.Text;
string output = input;
resultLiteral.Text = output;
}


With this example code, it is possible to inject javascript into the response. Try pasting <script language="javascript">alert('Hello World!');</script> in the input box and see.

Out of the box ASP.NET functionality

With the standard ASP.NET setup, the last script example didn’t worked, but threw an exception with the message ‘A potentially dangerous Request.Form value was detected from the client (inputBox="<script language="ja...").’. This is because out of the box, ASP.NET will scan each input parameter to dangerous characters. But don’t let this filter mislead you. The default characters will be the less than character (<) and some ampersand-hash encoded characters. There are also scenario’s you will be switching off the request validation. Simply because some business scenario (maybe you want some html from your user).

You can switch your validation off for all your pages in ASP.NET in the web.config, or specify ValidateRequest="false" in the page directive for the specific page you want to disable this check (note that in ASP.NET 4, there are some additional steps needed). But don’t rely on request validation to heavily, because there are situations in can’t detect malicious input.

Shortcomings of Request Validation

Think about the following situation. You want the user of your site to specify the background color of an element on your page, and you use the following submit event:

protected void submitButton_Click(object sender, EventArgs e)
{
string color = inputBox.Text;
string output = "<div style=\"width:200px;height:200px;background-color:" + color + ";\">Colored Box</div>";
resultLiteral.Text = output;
}


Because the input is directly pasted into an attribute of the div tag, you don’t need HTML directly to inject javascript. The following line will pass through input validation, and inject the page with some potentially evil javascript:
red;" onclick="alert('Hello World!');" "
/



Filtering input

The first thing to prevent the injection of those unwanted code, is to filter the user input if used for generating output. Standard built-in in ASP.NET is the HttpUtility class with some Encoding methods. They can help with the above two attacks, but it is still possible to inject URL backgrounds in the second example. Because these filters are limited in usage, Microsoft started a new library quite some time ago.

AntiXSS library

The two main features in the AntiXSS library are the Encoder and Sanitizer classes. Like the HttpUtility, the encoder class has several specific Encoding methods. These methods are a lot more specific than HttpUtility though. In the second example, it is possible filter the color input with a call to Encoder.CssEncode. The output will be CSS encoded into ‘red\00003B\000022\000020onclick\00003D\000022alert\000028\000027Hello\000020World\000021\000027\000029\00003B\000022\000020\000022’.

The Sanitizer class is even more powerful. It can strip certain HTML tags out of the input. It can transform <script language="javascript">alert('Hello World!');</script><strong>bla</strong><img src="bla.gif" /><ul><li>one<li>Two<li>Three</ul> into <strong>bla</strong><img src="bla.gif"> <ul> <li>one</li><li>Two</li><li>Three</li></ul>


Install AntiXSS with NuGet

AntiXSS used to be a very hidden gem somewhere deep on Microsoft Download or CodePlex. But with the new NuGet, it is on page one of packages. First you need to install NuGet into your Visual Studio. After that, right click your project and choose ‘Add Library Package Reference’.



imageimage


As of today, AntiXSS is the eighth package in the list. If you click install, all assemblies for AntiXSS will be automatically downloaded and added to your solution. So it won’t be very hard anymore to write really secure code!