<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Running With Elevated Privileges</title>
	<atom:link href="http://dannyjessee.com/blog/index.php/feed/" rel="self" type="application/rss+xml" />
	<link>http://dannyjessee.com/blog</link>
	<description>Thoughts and observations from a SharePoint solutions architect</description>
	<lastBuildDate>Sat, 18 May 2013 17:07:24 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>Set the Bing maps API key in Office 365 using CSOM to leverage SharePoint 2013 Geolocation features</title>
		<link>http://dannyjessee.com/blog/index.php/2013/05/set-the-bing-maps-api-key-in-office-365-using-csom-to-leverage-sharepoint-2013-geolocation-features/</link>
		<comments>http://dannyjessee.com/blog/index.php/2013/05/set-the-bing-maps-api-key-in-office-365-using-csom-to-leverage-sharepoint-2013-geolocation-features/#comments</comments>
		<pubDate>Sun, 12 May 2013 21:11:45 +0000</pubDate>
		<dc:creator>Danny Jessee</dc:creator>
				<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[2013]]></category>
		<category><![CDATA[Bing]]></category>
		<category><![CDATA[CSOM]]></category>
		<category><![CDATA[geolocation]]></category>
		<category><![CDATA[maps]]></category>
		<category><![CDATA[SharePoint 2013]]></category>

		<guid isPermaLink="false">http://dannyjessee.com/blog/?p=485</guid>
		<description><![CDATA[Much has been written about the new Geolocation capabilities of SharePoint 2013. If you haven&#8217;t already, I would highly recommend reading this overview on MSDN. In short, SharePoint 2013 offers a new field type called Geolocation, which represents point location data (latitude and longitude) that can be automatically plotted on a Bing map. In order [...]]]></description>
				<content:encoded><![CDATA[<p>Much has been written about the new Geolocation capabilities of SharePoint 2013. If you haven&#8217;t already, I would highly recommend reading <a href="http://msdn.microsoft.com/en-us/library/jj163135.aspx" target="_blank">this overview on MSDN</a>. In short, SharePoint 2013 offers a new field type called <strong>Geolocation</strong>, which represents point location data (latitude and longitude) that can be automatically plotted on a Bing map.</p>
<p>In order to take full advantage of the built-in Bing mapping functionality, you must obtain an API key from the <a href="http://www.bingmapsportal.com/" target="_blank">Bing Maps portal</a>. Different API key types are available depending on your needs (<strong>Trial</strong> keys work great for demos and development environments, while <strong>Basic</strong> or <strong>Enterprise</strong> keys may better suit your needs in a production environment).</p>
<p>If you attempt to leverage a Geolocation column in SharePoint 2013 (on-premises or in Office 365) without obtaining and setting a Bing Maps API key, you will receive a subtle reminder that you need to do so:</p>
<p><a href="http://dannyjessee.com/blog/wp-content/uploads/2013/05/noapikey.png"><img class="alignnone size-full wp-image-486" alt="noapikey" src="http://dannyjessee.com/blog/wp-content/uploads/2013/05/noapikey.png" width="586" height="443" /></a></p>
<p>In an on-premises environment, you can use the PowerShell <a href="http://technet.microsoft.com/en-us/library/jj219544.aspx" target="_blank"><strong>Set-SPBingMapsKey </strong>cmdlet</a> to set the Bing maps API key at the farm level. However, it is not possible to use this cmdlet in an Office 365 environment. Fortunately, the Bing maps API key is also stored in the property bag of an<strong> SPWeb </strong>(with key &#8220;<strong>BING_MAPS_KEY</strong>&#8220;). We can set this value via .NET or JavaScript using the client object model.</p>
<p>To set the API key I obtained for my Office 365 site<strong></strong>, I used the following code in a simple .NET console application:</p>
<pre class="brush: csharp; title: ; notranslate">
        static void Main(string[] args)
        {
            var webUrl = new Uri(&quot;&lt;Office 365 site URL&gt;&quot;);
            using (ClientContext ctx = new ClientContext(webUrl))
            {
                var login = &quot;&lt;Office 365 login email&gt;&quot;;
                var password = &quot;&lt;Office 365 password&gt;&quot;;
                var secureStrPwd = new SecureString();
                foreach (char c in password)
                {
                    secureStrPwd.AppendChar(c);
                }

                var creds = new SharePointOnlineCredentials(login, secureStrPwd);
                ctx.Credentials = creds;

                var web = ctx.Web;
                web.AllProperties[&quot;BING_MAPS_KEY&quot;] = &quot;&lt;Bing maps API key&gt;&quot;;
                web.Update();

                ctx.ExecuteQuery();
            }
        }
</pre>
<p>Once the API key has been set, your maps will render without that annoying message!</p>
<p><a href="http://dannyjessee.com/blog/wp-content/uploads/2013/05/apikey.png"><img class="alignnone size-full wp-image-487" alt="apikey" src="http://dannyjessee.com/blog/wp-content/uploads/2013/05/apikey.png" width="587" height="436" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://dannyjessee.com/blog/index.php/2013/05/set-the-bing-maps-api-key-in-office-365-using-csom-to-leverage-sharepoint-2013-geolocation-features/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using JSOM to write (small) files to a SharePoint 2013 document library</title>
		<link>http://dannyjessee.com/blog/index.php/2013/02/using-jsom-to-write-small-files-to-a-sharepoint-2013-document-library/</link>
		<comments>http://dannyjessee.com/blog/index.php/2013/02/using-jsom-to-write-small-files-to-a-sharepoint-2013-document-library/#comments</comments>
		<pubDate>Sat, 16 Feb 2013 02:44:40 +0000</pubDate>
		<dc:creator>Danny Jessee</dc:creator>
				<category><![CDATA[SharePoint]]></category>

		<guid isPermaLink="false">http://dannyjessee.com/blog/?p=447</guid>
		<description><![CDATA[Update 3/3/2013: Problem solved! The culprit: &#8220;Protected View&#8221; in Office 2013. Thanks to this blog post from Tobias Lekman, after disabling protected view in each of the Office 2013 applications (I had to update these settings separately in Word, Excel, and PowerPoint), every document I uploaded using the code below opened without any errors on [...]]]></description>
				<content:encoded><![CDATA[<p><strong><strong>Update 3/3/2013: Problem solved! The culprit: &#8220;Protected View&#8221; in Office 2013. Thanks to <a href="http://blog.lekman.com/2012/10/remove-protected-view-from-office-2013.html" target="_blank">this blog post from Tobias Lekman</a>, after disabling protected view in each of the Office 2013 applications (I had to update these settings separately in Word, Excel, and PowerPoint), every document I uploaded using the code below opened without any errors on my CloudShare VM.</strong></strong></p>
<p><strong>Update 2/16/2013: The issue I had opening files uploaded into SharePoint described below may not be an issue after all. As it turns out, the CloudShare VM where I was doing my development and testing is generating the same error for ANY document I upload, even &#8220;the old fashioned way.&#8221; I accessed the same document library from a remote client and the same products that generated errors when being uploaded using the code above opened just fine, without any issues or errors. I will update this post as I learn more about the root cause of this problem.<br />
</strong></p>
<p>A recent post on Yammer lamented the lack of examples in the SharePoint 2013 API documentation that use the JavaScript Object Model (JSOM) to do anything more than <a href="http://msdn.microsoft.com/en-us/library/jj163201.aspx#BasicOps_FileTasks" target="_blank">create a very basic text file in a SharePoint document library</a>.</p>
<p>After lots of digging and a fair amount of trial and error, I now understand why that is the case.</p>
<p>The use case seems simple enough: allow the user to select a file from his or her local machine using an <a href="http://www.w3schools.com/jsref/dom_obj_fileupload.asp" target="_blank">HTML DOM FileUpload object</a> on a form, then use JSOM to upload this file into a document library. <a href="http://blogs.msdn.com/b/sridhara/archive/2010/03/12/uploading-files-using-client-object-model-in-sharepoint-2010.aspx" target="_blank">It&#8217;s certainly easy enough to do using the Client Script Object Model (CSOM).</a> As it turns out, there are a couple of very good reasons why your document upload capability (whether you package it into an app for SharePoint or something else) should NOT leverage JSOM:</p>
<ul>
<li>Per <a href="http://msdn.microsoft.com/en-us/library/jj163201.aspx" target="_blank">MSDN</a>, you can only work with files up to 1.5 MB when using JSOM. It is recommended that you use <a href="http://msdn.microsoft.com/en-us/library/jj164022.aspx#LargeFiles" target="_blank">REST</a> to deal with larger files. <em>(Incidentally, there is a comment in the article on using the REST endpoints that reads &#8220;See <a href="http://msdn.microsoft.com/en-us/library/jj163201.aspx">How to: Complete basic operations using JavaScript library code in SharePoint 2013</a> for a code example that shows you how to upload a binary file that is smaller than 1.5 MB by using the SharePoint 2013 Javascript object model.&#8221; Unfortunately, the only code example in that article creates a very rudimentary plain text file.)</em></li>
<li>Unless your browser supports the File APIs introduced in HTML5 (specifically the <a href="http://www.w3.org/TR/FileAPI/#dfn-filereader" target="_blank">FileReader API</a>), you are out of luck. As a general rule, browsers will block attempts by JavaScript to access and read files from the local file system for security reasons. If you are using IE, <a href="http://caniuse.com/filereader" target="_blank">only version 10 supports the FileReader API</a>.</li>
</ul>
<p>Although I was somewhat discouraged by this news, I was determined to develop an app for SharePoint 2013 that presented a simple file upload control to the user and stored the file in a document library (as long as it was smaller than 1.5 MB, of course). I figured as long as I could save Office documents to the library (i.e., more than a simple plain text file), I would have succeeded.</p>
<p>To accomplish this, I knew I would need to make use of the HTML5 FileReader API. (Because of that, I also knew I would need to test this solution using IE 10, Firefox, or Chrome!) Based on the MSDN documentation, I knew I would be setting the contents of the file by using a new <strong>SP.Base64EncodedByteArray</strong>. The FileReader API exposes three methods for reading the contents of a file:</p>
<ol>
<li><strong>readAsText()</strong> &#8211; this method reads the plain text contents of a file, but does not properly handle binary files.</li>
<li><strong>readAsArrayBuffer()</strong> &#8211; this seemed to be the most promising option, but no matter how I tried to cast the contents of the <strong>ArrayBuffer</strong> to a Base64-encoded byte array, I was not able to successfully reproduce a file from the file system in a document library. <em>If anyone out there has any suggestions that might enable <strong>readAsArrayBuffer()</strong> to work, please let me know in the comments!</em></li>
<li><strong>readAsDataURL()</strong> &#8211; this method returns the contents of the file using the <a href="http://en.wikipedia.org/wiki/Data_URI_scheme" target="_blank">Data URI scheme</a>. Thanks to a handy utility method I found <a href="https://gist.github.com/borismus/1032746" target="_blank">here</a>, I can convert this Base64-encoded string into a JavaScript <strong>Uint8Array </strong>and use that to populate the <strong>SP.Base64EncodedByteArray</strong><strong> </strong>that the JSOM expects.</li>
</ol>
<p>Here is the JavaScript I ended up using:</p>
<pre class="brush: jscript; title: ; notranslate">
$(document).ready(function ()
{
    // Get the URI decoded host web URL
    // We will use this to get a context here to write data
    hostweburl = decodeURIComponent(getQueryStringParameter(&quot;SPHostUrl&quot;));
});

function CreateFile()
{
    // Ensure the HTML5 FileReader API is supported
    if (window.FileReader)
    {
        input = document.getElementById(&quot;fileinput&quot;);
        if (input)
        {
            file = input.files[0];
            fr = new FileReader();
            fr.onload = receivedBinary;
            fr.readAsDataURL(file);
        }
    }
    else
    {
        alert(&quot;The HTML5 FileSystem APIs are not fully supported in this browser.&quot;);
    }
}

// Callback function for onload event of FileReader
function receivedBinary()
{
    // Get the ClientContext for the app web
    clientContext = new SP.ClientContext.get_current();
    // Use the host web URL to get a parent context - this allows us to get data from the parent
    parentCtx = new SP.AppContextSite(clientContext, hostweburl);
    parentWeb = parentCtx.get_web();
    parentList = parentWeb.get_lists().getByTitle(&quot;Documents&quot;);

    fileCreateInfo = new SP.FileCreationInformation();
    fileCreateInfo.set_url(file.name);
    fileCreateInfo.set_overwrite(true);
    fileCreateInfo.set_content(new SP.Base64EncodedByteArray());

    // Read the binary contents of the base 64 data URL into a Uint8Array
    // Append the contents of this array to the SP.FileCreationInformation
    var arr = convertDataURIToBinary(this.result);
    for (var i = 0; i &lt; arr.length; ++i)
    {
        fileCreateInfo.get_content().append(arr[i]);
    }

    // Upload the file to the root folder of the document library
    this.newFile = parentList.get_rootFolder().get_files().add(fileCreateInfo);

    clientContext.load(this.newFile);
    clientContext.executeQueryAsync(onSuccess, onFailure);
}

function onSuccess()
{
    // File successfully uploaded
    alert(&quot;Success!&quot;);
}

function onFailure()
{
    // Error occurred
    alert(&quot;Request failed: &quot; + arguments[1].get_message());
}

// Utility function to remove base64 URL prefix and store base64-encoded string in a Uint8Array
// Courtesy: https://gist.github.com/borismus/1032746
function convertDataURIToBinary(dataURI)
{
    var BASE64_MARKER = ';base64,';
    var base64Index = dataURI.indexOf(BASE64_MARKER) + BASE64_MARKER.length;
    var base64 = dataURI.substring(base64Index);
    var raw = window.atob(base64);
    var rawLength = raw.length;
    var array = new Uint8Array(new ArrayBuffer(rawLength));

    for (i = 0; i &lt; rawLength; i++)
    {
        array[i] = raw.charCodeAt(i);
    }
    return array;
}
</pre>
<p>This code works!<del>&#8211;mostly.</del> In my environment, Excel Services was able to successfully open my basic test spreadsheet in the browser:</p>
<p><a href="http://dannyjessee.com/blog/wp-content/uploads/2013/02/excelservices.png"><img class="alignnone size-full wp-image-449" alt="excelservices" src="http://dannyjessee.com/blog/wp-content/uploads/2013/02/excelservices.png" width="297" height="229" /></a></p>
<p>I could also use the <strong>Download a Copy </strong>option to save local copies and successfully open files of any type:</p>
<p><a href="http://dannyjessee.com/blog/wp-content/uploads/2013/02/dlcopy.png"><img class="alignnone size-full wp-image-450" alt="dlcopy" src="http://dannyjessee.com/blog/wp-content/uploads/2013/02/dlcopy.png" width="595" height="494" /></a> <a href="http://dannyjessee.com/blog/wp-content/uploads/2013/02/pptx.png"><img class="alignnone size-full wp-image-451" alt="pptx" src="http://dannyjessee.com/blog/wp-content/uploads/2013/02/pptx.png" width="701" height="665" /></a></p>
<p><del>For a simple Word document, though, I was unable to click the link from the document library and have it open successfully in Word. Instead, Word reported an error when trying to open the document:</del></p>
<p>If you receive the error shown below when opening a document from SharePoint, it is due to &#8220;Protected View&#8221; in Office 2013. To disable Protected View, follow the steps outlined <a href="http://blog.lekman.com/2012/10/remove-protected-view-from-office-2013.html" target="_blank">here</a>.</p>
<p><a href="http://dannyjessee.com/blog/wp-content/uploads/2013/02/worderr.png"><img class="alignnone size-full wp-image-452" alt="worderr" src="http://dannyjessee.com/blog/wp-content/uploads/2013/02/worderr.png" width="409" height="215" /></a></p>
<p>Regardless of your Office 2013 Protected View settings, the <strong>Download a Copy </strong>option will open the document without the annoying error message.</p>
<p><a href="http://dannyjessee.com/blog/wp-content/uploads/2013/02/saveas.png"><img class="alignnone size-full wp-image-454" alt="saveas" src="http://dannyjessee.com/blog/wp-content/uploads/2013/02/saveas.png" width="398" height="48" /></a></p>
<p><a href="http://dannyjessee.com/blog/wp-content/uploads/2013/02/testdoc.png"><img class="alignnone size-full wp-image-456" alt="testdoc" src="http://dannyjessee.com/blog/wp-content/uploads/2013/02/testdoc.png" width="679" height="617" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://dannyjessee.com/blog/index.php/2013/02/using-jsom-to-write-small-files-to-a-sharepoint-2013-document-library/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Customize the Default #WIF ASP.NET #STS to Support Multiple #SharePoint Web Applications</title>
		<link>http://dannyjessee.com/blog/index.php/2013/01/customize-the-default-wif-asp-net-sts-to-support-multiple-sharepoint-web-applications/</link>
		<comments>http://dannyjessee.com/blog/index.php/2013/01/customize-the-default-wif-asp-net-sts-to-support-multiple-sharepoint-web-applications/#comments</comments>
		<pubDate>Sun, 27 Jan 2013 21:11:01 +0000</pubDate>
		<dc:creator>Danny Jessee</dc:creator>
				<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[Claims]]></category>
		<category><![CDATA[SharePoint 2010]]></category>
		<category><![CDATA[SharePoint 2013]]></category>
		<category><![CDATA[STS]]></category>
		<category><![CDATA[trusted identity provider]]></category>

		<guid isPermaLink="false">http://dannyjessee.com/blog/?p=393</guid>
		<description><![CDATA[Thanks to Claims-based identity in SharePoint 2010 and 2013, we have the ability to develop our own trusted login providers. These providers take the form of a Security Token Service (STS), an ASP.NET web site that packages and signs SAML tokens containing claims. SharePoint is then configured to trust this STS. In this blog post, [...]]]></description>
				<content:encoded><![CDATA[<p>Thanks to Claims-based identity in SharePoint 2010 and 2013, we have the ability to develop our own trusted login providers. These providers take the form of a Security Token Service (STS), an ASP.NET web site that packages and signs SAML tokens containing claims. SharePoint is then configured to trust this STS. In <a title="Using LinkedIn as an Identity Provider for SharePoint 2010" href="http://dannyjessee.com/blog/index.php/2012/02/using-linkedin-as-an-identity-provider-for-sharepoint-2010/">this blog post</a>, I walk through the steps required to develop a custom STS using the <a href="http://www.microsoft.com/en-us/download/details.aspx?id=4451" target="_blank">Windows Identity Foundation (WIF) SDK 4.0</a> that supports LinkedIn as an identity provider for SharePoint. However, there is one significant shortcoming with the approach I use in that post: it can only be used for a single SharePoint web application, <strong>intranet.contoso.com</strong>. This is due to two factors:</p>
<ul>
<li>The <strong>realm</strong> used by the <strong>SPTrustedIdentityTokenIssuer</strong> is configured as the URL of SharePoint&#8217;s STS within that web application (e.g., <strong>intranet.contoso.com/_trust</strong>).</li>
<li>The default behavior of the WIF STS web site is to forward tokens for authenticated users to the specified <strong>realm </strong>URL. From there, SharePoint&#8217;s STS will forward the logged in user back to the page he or she was trying to access.</li>
</ul>
<p>If you tried to use this trusted identity provider on another web application (such as <strong>hr.contoso.com</strong> or <strong>finance.contoso.com</strong>), you would end up disappointed as your users would be forwarded back to the <strong>intranet.contoso.com</strong> web application no matter which site they were actually trying to access!</p>
<p>In this blog post, I will make some slight modifications to the out-of-the-box WIF STS web site so that:</p>
<ul>
<li>The same trusted identity provider may be used across multiple different web applications, each with different host header URLs.</li>
<li>The <strong>SPTrustedIdentityTokenIssuer</strong> does not need to be updated and can leverage the same <strong>realm</strong> value no matter how many web applications make use of it.</li>
<li>The WIF STS web site I build and customize does not need to be updated and can leverage the same <strong>realm</strong> value no matter how many web applications make use of it.</li>
</ul>
<h2>What is a realm?</h2>
<p>The default behavior of the WIF STS web site is to forward an authenticated user back to the URL specified as the <strong>realm</strong>. According to <a href="http://msdn.microsoft.com/en-us/library/ee748509.aspx" target="_blank">MSDN</a>, the <strong>realm</strong> value is &#8220;used by the STS to identify the relying party instance and to select the corresponding token issuance policy and encryption certificate.&#8221; The <strong>realm </strong>is specified as a URI (which can actually be a <a href="http://en.wikipedia.org/wiki/Uniform_resource_identifier#Relationship_to_URL_and_URN" target="_blank">URL or a URN</a>), but in many walkthroughs (mine included), we specify a value for the <strong>realm</strong> that is tied to a specific host header URL (e.g., <strong>intranet.contoso.com/_trust</strong>).</p>
<h2>Decoupling the realm from a specific host header URL</h2>
<p>In an environment where only one web application needs to use a trusted identity provider, it may make sense to associate the <strong>realm </strong>with the URL of that web application. But in an environment where multiple claims web applications in a SharePoint farm need to use that same trusted identity provider, a different approach must be taken. As Steve Peschka describes in <a href="http://blogs.technet.com/b/speschka/archive/2010/04/27/how-to-create-multiple-claims-auth-web-apps-in-a-single-sharepoint-2010-farm.aspx" target="_blank">this post</a>, we can use a URN (e.g., <strong>urn:linkedin:sts</strong>) instead of a URL to work around this limitation. In the case of ADFS v2 <em>(disclaimer: I have not worked with ADFS v2)</em>, you can define mappings between these URNs and their associated web applications as Steve describes in the blog post linked above.</p>
<h2>Updating the default WIF STS web site</h2>
<p>If I change my <strong>SPTrustedIdentityTokenIssuer </strong>to use the generic realm <strong>urn:linkedin:sts</strong>, but make no changes to my STS web site, what will happen? As it turns out, I will be redirected to this URN, which of course is <strong>not</strong> the URL I want my logged in users to visit. Hilarity ensues:</p>
<p><a href="http://dannyjessee.com/blog/wp-content/uploads/2013/01/sts404.png"><img class="alignnone size-full wp-image-394" alt="sts404" src="http://dannyjessee.com/blog/wp-content/uploads/2013/01/sts404.png" width="491" height="194" /></a></p>
<p>As you can see, the STS redirects the logged in user to <strong>urn:linkedin:sts</strong>, which of course produces a 404 error.<strong></strong></p>
<p>The key to having the STS redirect logged in users to the proper URL is in the <strong>CustomSecurityTokenService</strong> class, which contains a function<strong> GetScope()</strong> that sets the <strong>ReplyToAddress </strong>of the <strong>SecurityTokenService.Scope</strong> object. The default STS web site implementation uses the following code:</p>
<pre class="brush: csharp; title: ; notranslate">
// Set the ReplyTo address for the WS-Federation passive protocol (wreply). This is the address to which responses will be directed.
// In this template, we have chosen to set this to the AppliesToAddress.
scope.ReplyToAddress = scope.AppliesToAddress;
</pre>
<p>The <strong>AppliesToAddress </strong>value is determined from the <a href="http://msdn.microsoft.com/en-us/library/cc236491.aspx" target="_blank"><strong>wtrealm</strong></a> parameter specified as the &#8220;OAuth Accept Redirect URL&#8221; in our LinkedIn application configuration. Remember that we had previously set this value to <strong>intranet.contoso.com/_trust</strong> (which would work as a URL), but have since updated it to <strong>urn:linkedin:sts</strong>.</p>
<h3>How can I fix this?</h3>
<p>The way you choose to work around this behavior depends on your requirements. If you need to use different token encrypting certificates based on the relying party (RP) application, or if you want to potentially execute any custom business logic specific to some (but not all) of your RP applications, you may choose to update the code in the <strong>GetScope()</strong> function to look more like the following:</p>
<pre class="brush: csharp; title: ; notranslate">
if (scope.AppliesToAddress == &quot;urn:linkedin:sts&quot;)
{
    scope.EncryptingCredentials = new X509EncryptingCredentials(CertificateUtil.GetCertificate(StoreName.My, StoreLocation.LocalMachine, &quot;EncryptingCert1&quot;));
    scope.ReplyToAddress = &quot;http://intranet.contoso.com/_trust&quot;;
    // More things specific to the intranet web application and the urn:linkedin:sts realm...
}
else if (scope.AppliesToAddress == &quot;urn:someother:sts&quot;)
{
    scope.EncryptingCredentials = new X509EncryptingCredentials(CertificateUtil.GetCertificate(StoreName.My, StoreLocation.LocalMachine, &quot;EncryptingCert2&quot;));
    scope.ReplyToAddress = &quot;http://extranet.contoso.com/_trust&quot;;
    // More things specific to the extranet web application and the urn:someother:sts realm...
}
</pre>
<p>This approach carries the following &#8220;baggage&#8221; (which may be completely necessary based on your requirements):</p>
<ul>
<li>The STS has to be recompiled and redeployed anytime a new web application needs to be supported.</li>
<li>It still cannot be reused across any host-header named web applications.</li>
</ul>
<p>But what if I don&#8217;t have any special requirements? What if I just want my STS to redirect authenticated users back to whichever web application referred them, even new web applications that I don&#8217;t know about yet? We can do this! The way I chose to accomplish this is as follows:</p>
<ul>
<li>In <strong>Login.aspx.cs</strong> of my STS web site (which is the first page a user will hit prior to being authenticated), I can grab the host header from the <strong>UrlReferrer </strong>property of <strong>HttpContext.Current.Request</strong> and store it in a session variable with <strong>/_trust </strong>appended. This will serve as the <strong>realm</strong> value I want my STS to use and will contain the value of the referring SharePoint web application.</li>
<li>In <strong>Default.aspx.cs</strong> of my STS web site, see if the session variable I created above exists. If it does, pass it in to the constructor for my <strong>CustomSecurityTokenService </strong>class.<strong></strong></li>
<li>In <strong>App_Code/CustomSecurityTokenService.cs</strong>, store the updated <strong>realm</strong> value in a member variable. If the STS was called with a <strong>realm </strong>value of <strong>urn:linkedin:sts</strong> (some minimal validation of the RP), redirect the user to the appropriate <strong>realm</strong> URL in the <strong>GetScope()</strong> function.</li>
</ul>
<p>Here are the relevant code snippets required to accomplish this:</p>
<p><strong>Login.aspx.cs:</strong></p>
<pre class="brush: csharp; title: ; notranslate">
Uri referrer = HttpContext.Current.Request.UrlReferrer;
if (referrer != null)
{
    string defaultRealm = referrer.ToString();
    // From SharePoint, this value will be:
    defaultRealm = defaultRealm.Substring(0, defaultRealm.IndexOf(&quot;_login&quot;)).TrimEnd('/') + &quot;/_trust/&quot;;
    Session[&quot;defaultRealm&quot;] = defaultRealm;
}
</pre>
<p><strong>Default.aspx.cs:</strong></p>
<pre class="brush: csharp; title: ; notranslate">
// Process signin request.
SignInRequestMessage requestMessage = (SignInRequestMessage)WSFederationMessage.CreateFromUri( Request.Url );

string defaultRealm = &quot;&quot;;
if (Session[&quot;defaultRealm&quot;] != null)
{
    defaultRealm = Session[&quot;defaultRealm&quot;] as string;
}

if ( User != null &amp;&amp; User.Identity != null &amp;&amp; User.Identity.IsAuthenticated )
{
    SecurityTokenService sts = new CustomSecurityTokenService( CustomSecurityTokenServiceConfiguration.Current, defaultRealm );
    SignInResponseMessage responseMessage = FederatedPassiveSecurityTokenServiceOperations.ProcessSignInRequest( requestMessage, User, sts );
    FederatedPassiveSecurityTokenServiceOperations.ProcessSignInResponse( responseMessage, Response );
}
</pre>
<p><strong>App_Code/CustomSecurityTokenService.cs:</strong></p>
<pre class="brush: csharp; title: ; notranslate">
private string defaultRealm = string.Empty;

public CustomSecurityTokenService( SecurityTokenServiceConfiguration configuration, string realm = &quot;&quot; )
    : base( configuration )
{
    defaultRealm = realm;
}

protected override Scope GetScope( IClaimsPrincipal principal, RequestSecurityToken request )
{
    ValidateAppliesTo( request.AppliesTo );

    Scope scope = new Scope( request.AppliesTo.Uri.OriginalString, SecurityTokenServiceConfiguration.SigningCredentials );

    string encryptingCertificateName = WebConfigurationManager.AppSettings[ &quot;EncryptingCertificateName&quot; ];
    if ( !string.IsNullOrEmpty( encryptingCertificateName ) )
    {
        // Important note on setting the encrypting credentials.
        // In a production deployment, you would need to select a certificate that is specific to the RP that is requesting the token.
        // You can examine the 'request' to obtain information to determine the certificate to use.
        scope.EncryptingCredentials = new X509EncryptingCredentials( CertificateUtil.GetCertificate( StoreName.My, StoreLocation.LocalMachine, encryptingCertificateName ) );
    }
    else
    {
        // If there is no encryption certificate specified, the STS will not perform encryption.
        // This will succeed for tokens that are created without keys (BearerTokens) or asymmetric keys.
        scope.TokenEncryptionRequired = false;
    }

    // Set the ReplyTo address for the WS-Federation passive protocol (wreply). This is the address to which responses will be directed.
    // In this template, we have chosen to set this to the AppliesToAddress.
    if (scope.AppliesToAddress == &quot;urn:linkedin:sts&quot;)
    {
        scope.ReplyToAddress = defaultRealm;
    }
    else
    {
        scope.ReplyToAddress = scope.AppliesToAddress;
    }

    return scope;
}
</pre>
<h2>Putting it all together</h2>
<p>After deploying this updated STS, any new SharePoint web application I create that leverages the <strong>LinkedIn</strong> trusted identity provider will redirect users back to the appropriate URL after they are authenticated, regardless of whether the new web applications use a different host header, port, or both. To prove this, I created a new web application on port 39668 and set a &#8220;Full Read&#8221; user policy for all LinkedIn users. Upon accessing the site, I choose to sign in using my LinkedIn identity provider:</p>
<p><a href="http://dannyjessee.com/blog/wp-content/uploads/2013/01/newsts1.png"><img class="alignnone size-full wp-image-395" alt="newsts1" src="http://dannyjessee.com/blog/wp-content/uploads/2013/01/newsts1.png" width="391" height="30" /></a></p>
<p><a href="http://dannyjessee.com/blog/wp-content/uploads/2013/01/newsts2.png"><img class="alignnone size-full wp-image-396" alt="newsts2" src="http://dannyjessee.com/blog/wp-content/uploads/2013/01/newsts2.png" width="491" height="154" /></a></p>
<p>After supplying my credentials, LinkedIn will redirect me back to my STS. My STS will then determine where to redirect me based on the code above, and voila, I will be taken to my new SharePoint site, authenticated and signed in!</p>
<p><a href="http://dannyjessee.com/blog/wp-content/uploads/2013/01/newsts3.png"><img class="alignnone size-full wp-image-397" alt="newsts3" src="http://dannyjessee.com/blog/wp-content/uploads/2013/01/newsts3.png" width="392" height="30" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://dannyjessee.com/blog/index.php/2013/01/customize-the-default-wif-asp-net-sts-to-support-multiple-sharepoint-web-applications/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JavaScript to Conditionally Enable a SharePoint Custom Ribbon Button</title>
		<link>http://dannyjessee.com/blog/index.php/2013/01/javascript-to-conditionally-enable-a-sharepoint-custom-ribbon-button/</link>
		<comments>http://dannyjessee.com/blog/index.php/2013/01/javascript-to-conditionally-enable-a-sharepoint-custom-ribbon-button/#comments</comments>
		<pubDate>Sun, 20 Jan 2013 17:49:38 +0000</pubDate>
		<dc:creator>Danny Jessee</dc:creator>
				<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[Apps for SharePoint]]></category>
		<category><![CDATA[custom actions]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[ribbon]]></category>
		<category><![CDATA[SharePoint 2013]]></category>
		<category><![CDATA[Visual Studio 2012]]></category>

		<guid isPermaLink="false">http://dannyjessee.com/blog/?p=363</guid>
		<description><![CDATA[During my session on getting started with apps for SharePoint 2013, I demonstrate how to use the &#8220;extension&#8221; app shape to define a UI custom action that displays a button in the ribbon. When clicked, this button allows the user to view a Bing traffic map centered at the location specified in the selected list [...]]]></description>
				<content:encoded><![CDATA[<p>During <a title="Get Started with Apps for SharePoint 2013! #SPSVB 2013 Recap" href="http://dannyjessee.com/blog/index.php/2013/01/get-started-with-apps-for-sharepoint-2013-spsvb-2013-recap/">my session</a> on getting started with apps for SharePoint 2013, I demonstrate how to use the &#8220;extension&#8221; app shape to define a UI custom action that displays a button in the ribbon. When clicked, this button allows the user to view a Bing traffic map centered at the location specified in the selected list item. This is done using a <strong>CustomAction</strong> in the same declarative manner as it was done in SharePoint 2010, using the following XML:</p>
<p><a href="http://dannyjessee.com/blog/index.php/2013/01/javascript-to-conditionally-enable-a-sharepoint-custom-ribbon-button/customaction1/" rel="attachment wp-att-364"><img class="alignnone size-full wp-image-364" alt="customaction1" src="http://dannyjessee.com/blog/wp-content/uploads/2013/01/customaction1.png" width="581" height="449" /></a></p>
<p>Installing the app adds a button labeled &#8220;Plot on Bing Traffic Map&#8221; to the &#8220;Items&#8221; tab on all custom lists in the host web where the app is installed:</p>
<p><a href="http://dannyjessee.com/blog/index.php/2013/01/javascript-to-conditionally-enable-a-sharepoint-custom-ribbon-button/button0/" rel="attachment wp-att-365"><img class="alignnone size-full wp-image-365" alt="button0" src="http://dannyjessee.com/blog/wp-content/uploads/2013/01/button0.png" width="386" height="129" /></a></p>
<p>In my <strong>CommandAction</strong> of the <strong>CommandUIHandler</strong> for the <strong>CommandUIExtension</strong> I define to create the button, I specify that clicking the button will take the user to the following URL:</p>
<p><code>~appWebUrl/Pages/BingTrafficMap.html?{StandardTokens}&amp;ListID={ListId}&amp;ItemID={SelectedItemId}</code></p>
<p>Note the use of the <strong>SelectedItemId</strong> token in the URL above. This means my <strong>BingTrafficMap.html</strong> page can rightly expect to have an <strong>ItemID</strong> parameter in its query string, which can then be parsed to get the list item and read its properties using JavaScript.</p>
<p>But what if the user hasn&#8217;t selected any items? Or multiple items? Since I can only center a map on one single location, I need to have more control over when this button is enabled. In this case, I only want the button to be enabled when exactly one item in the list is selected. <em>(By default, any ribbon buttons you create through custom actions will always be enabled, regardless of whether or not any items are selected.)</em></p>
<p>As it turns out, there is an <strong>EnabledScript</strong> attribute of the <strong>CommandUIHandler</strong> that will enable or disable the button depending on whether the function returns true or false. I was able to adapt <a href="http://tomaszrabinski.pl/wordpress/2012/02/25/enable-or-disable-custom-ribbon-button-in-sharepoint-2010/" target="_blank">this code from Tomasz Rabiński</a> to add the following logic to my <strong>CommandUIHandler</strong>:</p>
<p><a href="http://dannyjessee.com/blog/index.php/2013/01/javascript-to-conditionally-enable-a-sharepoint-custom-ribbon-button/customaction2/" rel="attachment wp-att-366"><img class="alignnone size-full wp-image-366" alt="customaction2" src="http://dannyjessee.com/blog/wp-content/uploads/2013/01/customaction2.png" width="719" height="114" /></a></p>
<p>Note that the function <strong>EnableDisable</strong>&#8211;which I can define and then call within the <strong>EnabledScript</strong> attribute&#8211;returns <strong>true</strong> only if the number of selected items equals 1.</p>
<p>Now my button behaves exactly as I would expect.</p>
<p>No items selected (disabled):</p>
<p><a href="http://dannyjessee.com/blog/index.php/2013/01/javascript-to-conditionally-enable-a-sharepoint-custom-ribbon-button/button1/" rel="attachment wp-att-367"><img class="alignnone size-full wp-image-367" alt="button1" src="http://dannyjessee.com/blog/wp-content/uploads/2013/01/button1.png" width="256" height="269" /></a></p>
<p>One item selected (enabled):</p>
<p><a href="http://dannyjessee.com/blog/index.php/2013/01/javascript-to-conditionally-enable-a-sharepoint-custom-ribbon-button/button2/" rel="attachment wp-att-368"><img class="alignnone size-full wp-image-368" alt="button2" src="http://dannyjessee.com/blog/wp-content/uploads/2013/01/button2.png" width="256" height="269" /></a></p>
<p>More than one item selected (disabled):</p>
<p><a href="http://dannyjessee.com/blog/index.php/2013/01/javascript-to-conditionally-enable-a-sharepoint-custom-ribbon-button/button3/" rel="attachment wp-att-369"><img class="alignnone size-full wp-image-369" alt="button3" src="http://dannyjessee.com/blog/wp-content/uploads/2013/01/button3.png" width="256" height="279" /></a></p>
<p>I have updated my demo code to include this change. You can download this code <a href="http://sdrv.ms/XbohjT" target="_blank">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://dannyjessee.com/blog/index.php/2013/01/javascript-to-conditionally-enable-a-sharepoint-custom-ribbon-button/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Presenting Apps for SharePoint 2013 at @CapAreaSP!</title>
		<link>http://dannyjessee.com/blog/index.php/2013/01/presenting-apps-for-sharepoint-2013-at-capareasp/</link>
		<comments>http://dannyjessee.com/blog/index.php/2013/01/presenting-apps-for-sharepoint-2013-at-capareasp/#comments</comments>
		<pubDate>Fri, 18 Jan 2013 02:46:15 +0000</pubDate>
		<dc:creator>Danny Jessee</dc:creator>
				<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[SPUG]]></category>
		<category><![CDATA[Apps]]></category>
		<category><![CDATA[SharePoint 2013]]></category>
		<category><![CDATA[Visual Studio 2012]]></category>

		<guid isPermaLink="false">http://dannyjessee.com/blog/?p=360</guid>
		<description><![CDATA[Thanks to everyone who braved the elements (e.g., the winter storm that never materialized) to see me present &#8220;Get Started with Apps for SharePoint 2013!&#8221; at the Capital Area .NET SharePoint Special Interest Group at Knowlogy in Tysons Corner tonight! I was very impressed with the level of audience participation and interaction during the session. [...]]]></description>
				<content:encoded><![CDATA[<p>Thanks to everyone who braved the elements (e.g., the winter storm that never materialized) to see me present &#8220;Get Started with Apps for SharePoint 2013!&#8221; at the <a href="http://www.meetup.com/CapArea-NET-SPSIG/" target="_blank">Capital Area .NET SharePoint Special Interest Group</a> at Knowlogy in Tysons Corner tonight! I was very impressed with the level of audience participation and interaction during the session. Feel free to reach out to me anytime (either in the comments here or on <a href="http://twitter.com/dannyjessee" target="_blank">Twitter</a>) if you have any questions or just want to chat about Apps for SharePoint 2013!</p>
<h1>Slides and code from my session</h1>
<p><iframe style="border: 1px solid #CCC; border-width: 1px 1px 0; margin-bottom: 5px;" src="http://www.slideshare.net/slideshow/embed_code/16048775" height="356" width="427" allowfullscreen="" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe></p>
<p>Code for the sample app I demonstrated can be downloaded <a href="http://sdrv.ms/XbohjT" target="_blank">here</a>.</p>
<p>To learn more about when and when not to use the new app model for SharePoint 2013 development, attend next month&#8217;s <a href="http://twitter.com/CapAreaSP" target="_blank">@CapAreaSP</a> session featuring <a href="http://blogs.msdn.com/b/alex_randall/" target="_blank">Alex Randall</a> from Microsoft!</p>
]]></content:encoded>
			<wfw:commentRss>http://dannyjessee.com/blog/index.php/2013/01/presenting-apps-for-sharepoint-2013-at-capareasp/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Kicking off @RestonSPUG with Apps for SharePoint 2013!</title>
		<link>http://dannyjessee.com/blog/index.php/2013/01/kicking-off-restonspug-with-apps-for-sharepoint-2013/</link>
		<comments>http://dannyjessee.com/blog/index.php/2013/01/kicking-off-restonspug-with-apps-for-sharepoint-2013/#comments</comments>
		<pubDate>Tue, 08 Jan 2013 01:38:02 +0000</pubDate>
		<dc:creator>Danny Jessee</dc:creator>
				<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[SPUG]]></category>
		<category><![CDATA[Apps]]></category>
		<category><![CDATA[SharePoint 2013]]></category>
		<category><![CDATA[Visual Studio 2012]]></category>

		<guid isPermaLink="false">http://dannyjessee.com/blog/?p=347</guid>
		<description><![CDATA[Thanks to everyone who joined me, Scott Hoag, and Dan Usher as we kicked off the new Reston SharePoint User Group today! The group will meet around lunchtime at the Microsoft office in Reston on the first Monday of each month. The group&#8217;s meeting time and location should be ideal for the many SharePoint professionals [...]]]></description>
				<content:encoded><![CDATA[<p>Thanks to everyone who joined me, <a href="http://twitter.com/ciphertxt" target="_blank">Scott Hoag</a>, and <a href="http://twitter.com/usher" target="_blank">Dan Usher</a> as we kicked off the new <a href="http://restonspug.org" target="_blank">Reston SharePoint User Group</a> today! The group will meet around lunchtime at the Microsoft office in Reston on the first Monday of each month. The group&#8217;s meeting time and location should be ideal for the many SharePoint professionals in the Reston area who can&#8217;t make it to the various regional SPUGs that traditionally meet in the evenings.</p>
<p>I had the privilege of being the group&#8217;s inaugural speaker today, presenting my session &#8220;Get Started with Apps for SharePoint 2013!&#8221; Much like <a title="Get Started with Apps for SharePoint 2013! #SPSVB 2013 Recap" href="http://dannyjessee.com/blog/index.php/2013/01/get-started-with-apps-for-sharepoint-2013-spsvb-2013-recap/" target="_blank">the session I led last weekend</a> at SPS Virginia Beach, there was great audience participation and interaction. There were a couple of great questions in particular that I wanted to address further here:</p>
<p><strong>If an app requests the <em>Write</em> right at the <em>List</em> scope, is there any way I can install or configure multiple instances of the app to grant it write permissions against two or more lists on a site?</strong></p>
<p>This was an interesting question because the guidance I gave last weekend was that in order to grant the <em>Write</em> right against multiple lists, your app must request permissions at the next highest scope (in the case of this example, that would be the <em>Web</em> scope). However, it is not possible to install multiple instances of an app for SharePoint to the same site. The UI will not show the app in the &#8220;Apps you can add&#8221; section for that site once an instance of that app is already installed. I even tried forcing my around that by using PowerShell, but was forbidden:</p>
<p><a href="http://dannyjessee.com/blog/index.php/2013/01/kicking-off-restonspug-with-apps-for-sharepoint-2013/powershell/" rel="attachment wp-att-348"><img class="alignnone size-full wp-image-348" alt="powershell" src="http://dannyjessee.com/blog/wp-content/uploads/2013/01/powershell.png" width="677" height="343" /></a></p>
<p><strong>What is the relationship between OAuth and tokens with apps for SharePoint? Is there a token for the user as well as one for the app that factors into authorization decisions?</strong></p>
<p>The OAuth protocol is used to authenticate and authorize apps for SharePoint. Authentication and authorization of users and apps in SharePoint 2013 is a very advanced subject with many potentially complicated scenarios and unique considerations. To learn more about these topics, I strongly encourage you to read the following articles on MSDN:</p>
<ul>
<li><a href="http://msdn.microsoft.com/en-us/library/fp142384.aspx" target="_blank">Authorization and authentication for apps in SharePoint 2013</a></li>
<li><a href="http://msdn.microsoft.com/en-us/library/fp179892.aspx" target="_blank">App authorization policy types in SharePoint 2013</a></li>
<li><a href="http://msdn.microsoft.com/en-us/library/ms457529.aspx" target="_blank">Authentication, authorization, and security in SharePoint 2013</a></li>
</ul>
<h1>Slides and code from my session</h1>
<p><iframe style="border: 1px solid #CCC; border-width: 1px 1px 0; margin-bottom: 5px;" src="http://www.slideshare.net/slideshow/embed_code/15894145" height="356" width="427" allowfullscreen="" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe></p>
<p>Code for the sample app I demonstrated can be downloaded <a href="http://sdrv.ms/XbohjT" target="_blank">here</a>.</p>
<p>Thanks again to everyone who was part of today&#8217;s <a href="http://twitter.com/RestonSPUG" target="_blank">Reston SPUG</a> event. I look forward to working with the group much more in the future!</p>
]]></content:encoded>
			<wfw:commentRss>http://dannyjessee.com/blog/index.php/2013/01/kicking-off-restonspug-with-apps-for-sharepoint-2013/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Get Started with Apps for SharePoint 2013! #SPSVB 2013 Recap</title>
		<link>http://dannyjessee.com/blog/index.php/2013/01/get-started-with-apps-for-sharepoint-2013-spsvb-2013-recap/</link>
		<comments>http://dannyjessee.com/blog/index.php/2013/01/get-started-with-apps-for-sharepoint-2013-spsvb-2013-recap/#comments</comments>
		<pubDate>Sun, 06 Jan 2013 17:49:11 +0000</pubDate>
		<dc:creator>Danny Jessee</dc:creator>
				<category><![CDATA[SPS Events]]></category>
		<category><![CDATA[Apps for SharePoint]]></category>
		<category><![CDATA[SharePoint 2013]]></category>
		<category><![CDATA[Visual Studio 2012]]></category>

		<guid isPermaLink="false">http://dannyjessee.com/blog/?p=339</guid>
		<description><![CDATA[Thanks to everyone who attended my session &#8220;Get Started with Apps for SharePoint 2013!&#8221; at SPSVB yesterday! We had some great discussions and questions about the new app model for SharePoint 2013, and a few questions came up during the session that I wanted to address in more detail here. How are apps for SharePoint [...]]]></description>
				<content:encoded><![CDATA[<p>Thanks to everyone who attended my session &#8220;Get Started with Apps for SharePoint 2013!&#8221; at SPSVB yesterday! We had some great discussions and questions about the new app model for SharePoint 2013, and a few questions came up during the session that I wanted to address in more detail here.</p>
<p><strong>How are apps for SharePoint deployed in a production environment?</strong></p>
<p>We demonstrated how to create a new App for SharePoint project in Visual Studio 2012 (where the app is configured to be automatically deployed to a specific site for debugging). But how do developers hand off an app package for a SharePoint-hosted app to be deployed in production?</p>
<p>Visual Studio will generate the <strong>.app</strong> file in an <strong>app.publish</strong> subdirectory of the bin\Debug, bin\Release, etc. directory of your project. Assuming your system administrators have <a href="http://msdn.microsoft.com/en-us/library/fp123530.aspx" target="_blank">configured an app catalog site</a> (these are configured at the web application level), anyone with permissions to the <strong>Apps for SharePoint</strong> library (automatically configured on the app catalog site) can upload the .app file to make the app available to all sites within that web application.</p>
<p>Uploading the file here:</p>
<p><img class="alignnone size-full wp-image-341" alt="file" src="http://dannyjessee.com/blog/wp-content/uploads/2013/01/file.png" width="718" height="91" /></p>
<p>To the library here:</p>
<p><img class="alignnone size-full wp-image-342" alt="newapp" src="http://dannyjessee.com/blog/wp-content/uploads/2013/01/newapp.png" width="447" height="273" /></p>
<p>Makes the app available to be installed on any site within the web application:</p>
<p><img class="alignnone size-full wp-image-343" alt="addapp" src="http://dannyjessee.com/blog/wp-content/uploads/2013/01/addapp.png" width="302" height="176" /></p>
<p><a href="http://blogs.msdn.com/b/ocarpen/" target="_blank">Olivier Carpentier</a> has also written .NET <a href="http://blogs.msdn.com/b/ocarpen/archive/2012/08/27/how-to-install-programmatically-an-app-in-sharepoint-2013-preview.aspx" target="_blank">code</a> and PowerShell <a href="http://blogs.msdn.com/b/ocarpen/archive/2012/08/15/scripts-to-install-update-or-uninstall-a-sharepoint-2013-app-with-powershell.aspx" target="_blank">scripts</a> to install apps for SharePoint, if that is more your speed.</p>
<p><strong>How do you grant an app the Write right on two or more lists?</strong></p>
<p>In our demo, we had our app request the <em>Write</em> right at the <em>List</em> scope. This corresponds to the following entry in the app&#8217;s AppManifest.xml:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;AppPermissionRequests&gt;
  &lt;AppPermissionRequest Scope=&quot;http://sharepoint/content/sitecollection/web/list&quot; Right=&quot;Write&quot; /&gt;
&lt;/AppPermissionRequests&gt;
</pre>
<p>When the app is installed, the dialog presented to the user allows the selection of a single list to which the app will be granted Write permissions:</p>
<p><img class="alignnone size-full wp-image-340" alt="trustdialog" src="http://dannyjessee.com/blog/wp-content/uploads/2013/01/trustdialog.png" width="509" height="241" /></p>
<p>As you can see, however, this dialog only enables me to select a single list. What if we want our app to be able to write to two or more lists? Unfortunately, there is no mechanism to do this right now. If we want our app to be able to write to multiple lists, we must request the right at the next highest scope (in this case, the <em>Web</em>). This corresponds to the following entry in the app&#8217;s AppManifest.xml:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;AppPermissionRequests&gt;
  &lt;AppPermissionRequest Scope=&quot;http://sharepoint/content/sitecollection/web&quot; Right=&quot;Write&quot; /&gt;
&lt;/AppPermissionRequests&gt;
</pre>
<p>Unfortunately, this will grant your app permission to write to <em>all</em> lists within the host web where the app is installed.</p>
<p><strong>How can apps for SharePoint support workflow?</strong></p>
<p>The Workflow object model has been greatly enhanced in SharePoint 2013. Among these enhancements include a client object model (CSOM), JavaScript object model (JSOM), and REST-based APIs for workflow. In a SharePoint-hosted app, the JSOM or REST APIs can be used to access the Workflow object model without any server-side code. You can download sample code for a Workflow-powered app for SharePoint <a href="http://code.msdn.microsoft.com/SharePoint-2013-workflow-580034f9" target="_blank">from MSDN</a>.</p>
<p>That said, workflow should only be used in an app for SharePoint when the workflow is integral to the app itself. SharePoint Designer 2013 is the recommended tool for authoring workflows in SharePoint 2013.</p>
<p><strong>Can web part connections be set up on .aspx pages within immersive, full-page apps?</strong></p>
<p>Obviously no server-side code is allowed in a SharePoint-hosted app, but every app must contain at least one page (the app&#8217;s Start page). This page may be an .aspx page (referencing server controls, but containing no server-side code). Can we connect web parts on this page? Thus far, I have not been able to do this. I even tried following a similar approach to the one outlined <a href="http://blogs.code-counsel.net/Wouter/Lists/Posts/Post.aspx?ID=161" target="_blank">here</a> where the connection between two web parts is provisioned declaratively, but to no avail. If anyone out there can shed any additional light on this question, please feel free to leave a comment!</p>
<h1>Slides and code from my session</h1>
<p><iframe style="border: 1px solid #CCC; border-width: 1px 1px 0; margin-bottom: 5px;" src="http://www.slideshare.net/slideshow/embed_code/15866543" height="356" width="427" allowfullscreen="" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe></p>
<p>Code for the sample app I demonstrated can be downloaded <a href="http://sdrv.ms/XbohjT" target="_blank">here</a>.</p>
<h1>In conclusion, thank you!</h1>
<p>Thanks again to all the attendees, volunteers, sponsors, speakers, and organizers who continue to make these <a title="SPS Events" href="https://spsevents.org/Pages/home.aspx" target="_blank">SPS Events</a> so great, and a special thanks to Microsoft consultant <a title="Alex Randall" href="http://blogs.msdn.com/b/alex_randall/" target="_blank">Alex Randall</a> who helped answer many of the questions I had about apps for SharePoint 2013 during and after his session yesterday, <a title="When and When Not to Use the New App Model" href="http://blogs.msdn.com/b/alex_randall/archive/2013/01/05/when-and-when-not-to-use-the-new-app-model.aspx" target="_blank">When and When Not to Use the New App Model</a>.</p>
<p>Happy app development!</p>
]]></content:encoded>
			<wfw:commentRss>http://dannyjessee.com/blog/index.php/2013/01/get-started-with-apps-for-sharepoint-2013-spsvb-2013-recap/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Using Azure ACS to Sign In to SharePoint 2013 with Facebook</title>
		<link>http://dannyjessee.com/blog/index.php/2012/11/using-azure-acs-to-sign-in-to-sharepoint-2013-with-facebook/</link>
		<comments>http://dannyjessee.com/blog/index.php/2012/11/using-azure-acs-to-sign-in-to-sharepoint-2013-with-facebook/#comments</comments>
		<pubDate>Wed, 21 Nov 2012 18:03:45 +0000</pubDate>
		<dc:creator>Danny Jessee</dc:creator>
				<category><![CDATA[SharePoint]]></category>

		<guid isPermaLink="false">http://dannyjessee.com/blog/?p=320</guid>
		<description><![CDATA[For those of you who have seen me speak (or read my blog posts) about Claims-based identity, SharePoint 2010, Facebook, and the cloud, you already know that Windows Azure Access Control Service (ACS) can be used to set up identity providers such as Windows Live ID, Google, Yahoo!, and Facebook in SharePoint 2010 through the [...]]]></description>
				<content:encoded><![CDATA[<p>For those of you who have seen me speak (or read my blog posts) about Claims-based identity, SharePoint 2010, Facebook, and the cloud, you already know that <a href="https://www.windowsazure.com/en-us/develop/net/how-to-guides/access-control/">Windows Azure Access Control Service (ACS)</a> can be used to set up identity providers such as Windows Live ID, Google, Yahoo!, and Facebook in SharePoint 2010 through the magic of Claims.</p>
<p>In this blog post, I am pleased to report that all the steps to follow to enable this integration with SharePoint 2010 also work with SharePoint 2013!</p>
<p>For those who are unfamiliar with this integration, I will cover the steps at a high-level below with screenshots from SharePoint 2013. Keep in mind the process to follow is the same for SharePoint 2010.</p>
<h1>Prerequisites</h1>
<ul>
<li>A Facebook account integrated with the <a href="https://developers.facebook.com/apps">Facebook Developers application</a></li>
<li>A <a href="http://go.microsoft.com/fwlink/?LinkID=129428">Windows Azure account</a> with an ACS namespace created (these can be created using the <strong>Service Bus, Access Control &amp; Caching</strong> section of the portal)</li>
<li>SharePoint 2013 (might I recommend <a href="http://cloudshare.com">CloudShare</a>&#8216;s preconfigured <a href="http://t.co/3Lk2pkcU">SharePoint 2013 RTM Small Farm</a> environment?)</li>
<li>An X.509 certificate to be used by Azure ACS to digitally sign tokens (and explicitly trusted by SharePoint)</li>
</ul>
<h1>Procedures</h1>
<p>Setting up this integration requires configuration steps to be performed in three different places:</p>
<ol>
<li>Within Facebook, an application must be created that supports &#8220;Website with Facebook Login.&#8221;</li>
<li>
<div>Within the Azure ACS management portal, a new Identity Provider (IP), Relying Party (RP) application, and Rule Group must be created to inform Azure ACS about:<br />
a. The Facebook application created above.<br />
b. The SharePoint environment to be configured with Azure ACS integration below.</div>
</li>
<li>Within SharePoint, we must create a new web application with Claims (in SharePoint 2013, Claims is the default authentication mechanism) and configure it to point to our Azure ACS setup as a Trusted Identity Provider.</li>
</ol>
<p><strong></strong>We must also inform both Azure ACS and SharePoint about the SSL certificate that will be used to sign the SAML tokens containing a user&#8217;s claims. This is done by uploading the X.509 certificate into the Azure ACS management portal and telling SharePoint to trust this certificate (via the <a href="http://technet.microsoft.com/en-us/library/ff607586%28v=office.14%29.aspx" target="_blank"><strong>New-SPTrustedRootAuthority</strong></a> and <a href="http://technet.microsoft.com/en-us/library/ff607628%28v=office.14%29.aspx" target="_blank"><strong>New-SPTrustedIdentityTokenIssuer</strong></a> cmdlets which we will execute later on). In a demonstration environment, I use a self-signed certificate made via the <a href="http://msdn.microsoft.com/en-us/library/bfsktky3%28v=vs.90%29.aspx" target="_blank"><strong>makecert</strong></a> command. In production, you would obviously want to use a legitimate SSL certificate.</p>
<h2>Facebook Application Setup</h2>
<p>Within the <a href="https://developers.facebook.com/apps">Facebook Developers application</a>, click <strong>Create New App</strong>.</p>
<p><img alt="" src="http://dannyjessee.com/blog/wp-content/uploads/2012/11/112112_1759_UsingAzureA1.png" /></p>
<p>Give the app a <strong>Name </strong>and a <strong>Namespace</strong>. Click <strong>Continue</strong>.</p>
<p><img alt="" src="http://dannyjessee.com/blog/wp-content/uploads/2012/11/112112_1759_UsingAzureA2.png" /></p>
<p>After passing the Captcha check, select <strong>Website with Facebook Login</strong> in the next screen and enter the <strong>URL to your Azure ACS Service Namespace </strong>(e.g., <strong>https://{your namespace}.accesscontrol.windows.net</strong>). Click <strong>Save Changes</strong>.</p>
<p><img alt="" src="http://dannyjessee.com/blog/wp-content/uploads/2012/11/112112_1759_UsingAzureA3.png" /></p>
<p>Take note of the <strong>App ID </strong>and <strong>App Secret </strong>values that appear at the top of this screen. You will need to use these to configure Azure ACS to leverage this application. That&#8217;s all we need to do within Facebook!</p>
<h2>Azure ACS Setup</h2>
<p>Within Azure ACS, we must configure the following four things:</p>
<ol>
<li>Facebook as an <strong>Identity Provider</strong>.</li>
<li>SharePoint as a <strong>Relying Party Application</strong>.</li>
<li>Claims <strong>Rule Groups</strong> to determine how Claims are passed from the identity provider to the relying party application.</li>
<li>The <strong>Token Signing Certificate</strong> that Azure ACS will use to prove that it is indeed the issuer of the SAML token that SharePoint receives.</li>
</ol>
<h3>Identity Provider</h3>
<p>From within your Azure ACS management portal (e.g., <strong>https://{your namespace}.accesscontrol.windows.net</strong>) and select <strong>Identity providers </strong>from the <strong>Trust relationships </strong>section in the left navigation. In the next screen, click <strong>Add</strong>.</p>
<p><img alt="" src="http://dannyjessee.com/blog/wp-content/uploads/2012/11/112112_1759_UsingAzureA4.png" /></p>
<p>In the next screen, choose <strong>Facebook application </strong>and click <strong>Next</strong>.</p>
<p><img alt="" src="http://dannyjessee.com/blog/wp-content/uploads/2012/11/112112_1759_UsingAzureA5.png" /></p>
<p>In the next screen, enter the <strong>Application ID </strong>and <strong>Application secret </strong>values from the Facebook application you created above. You should also provide a <strong>Display name </strong>(for use within the ACS management portal) and a comma-separated list of <strong>Application permissions</strong> (note that <strong>email</strong> is the only required permission to enable Facebook users to sign in to SharePoint). You can, however, request additional permissions to do <a href="http://dannyjessee.com/blog/index.php/2012/01/beyond-authentication-deeper-facebook-integration-with-sharepoint-with-code/">lots of fun and exciting things</a>. Those permission strings are defined <a href="https://developers.facebook.com/docs/reference/login/">here</a>.</p>
<p><img alt="" src="http://dannyjessee.com/blog/wp-content/uploads/2012/11/112112_1759_UsingAzureA6.png" /></p>
<p>You do not need to specify values for <strong>Login link text </strong>or <strong>Image URL</strong> unless you plan to configure more than one Azure ACS identity provider to use with SharePoint. If you have already configured your <strong>Relying party applications </strong>within Azure ACS, you may select them at the bottom of this screen. Otherwise, we will configure SharePoint as an RP in the next step.</p>
<p>Press <strong>Save</strong> to save changes.</p>
<h3>Relying Party Application</h3>
<p>From within your Azure ACS management portal (e.g., <strong>https://{your namespace}.accesscontrol.windows.net</strong>) and select <strong>Relying party applications </strong>from the <strong>Trust relationships </strong>section in the left navigation. In the next screen, click <strong>Add</strong>.</p>
<p><img alt="" src="http://dannyjessee.com/blog/wp-content/uploads/2012/11/112112_1759_UsingAzureA7.png" /></p>
<p>In the next screen, provide a name for the relying party application (I often just use the fully-qualified domain name of my SharePoint web application) and choose to <strong>Enter settings manually</strong>. In the boxes below, enter the following values:</p>
<ul>
<li><strong>Realm</strong> – URL of your SharePoint web application (note that a URN can also be entered here and, in many cases, is the preferred approach)</li>
<li><strong>Return URL </strong>– URL of your SharePoint web application <strong>+ /_trust</strong> – this is the endpoint for SharePoint&#8217;s STS, which is where Azure ACS will send the SAML token it creates<strong><br />
</strong></li>
<li><strong>Token format </strong>– SAML 1.1</li>
<li><strong>Token lifetime </strong>– enter a value greater than the default 600 seconds (Wictor Wilen gives a great explanation why <a href="http://www.wictorwilen.se/Post/Visual-guide-to-Azure-Access-Controls-Services-authentication-with-SharePoint-2010-part-1.aspx">here</a>)</li>
</ul>
<p><img alt="" src="http://dannyjessee.com/blog/wp-content/uploads/2012/11/112112_1759_UsingAzureA8.png" /></p>
<p>In the <strong>Authentication Settings </strong>section, select the <strong>Identity provider </strong>you configured above and choose to <strong>Create a new rule group</strong>. Under <strong>Token Signing Settings</strong>, choose whether to <strong>Use service namespace certificate </strong>(if you have already configured a certificate within Azure ACS) or <strong>Use a dedicated certificate</strong> if you would like to use a different X.509 certificate exclusively for this relying party application.</p>
<p><img alt="" src="http://dannyjessee.com/blog/wp-content/uploads/2012/11/112112_1759_UsingAzureA9.png" /></p>
<p>Click <strong>Save </strong>to save changes.</p>
<h3>Rule Group</h3>
<p>From within your Azure ACS management portal (e.g., <strong>https://{your namespace}.accesscontrol.windows.net</strong>) and select <strong>Rule groups </strong>from the <strong>Trust relationships </strong>section in the left navigation. In the next screen, click <strong>Default Rule Group for {your web application}</strong>.</p>
<p><img alt="" src="http://dannyjessee.com/blog/wp-content/uploads/2012/11/112112_1759_UsingAzureA10.png" /></p>
<p>Note that no rules are added by default. Click <strong>Generate</strong> and select the identity provider you created above.</p>
<p><img alt="" src="http://dannyjessee.com/blog/wp-content/uploads/2012/11/112112_1759_UsingAzureA11.png" /><strong><br />
</strong></p>
<p>Click <strong>Generate </strong>to generate Claims rules for the 5 values Azure ACS can obtain from a logged in Facebook user:</p>
<ol>
<li><strong>AccessToken</strong> – the Facebook Graph API access token</li>
<li><strong>emailaddress </strong>– the email address associated with the user&#8217;s Facebook profile</li>
<li><strong>expiration </strong>– the expiration date/time of the <strong>AccessToken</strong> granted above</li>
<li><strong>name</strong> – the Facebook user&#8217;s display name</li>
<li><strong>nameidentifier </strong>– the Facebook user&#8217;s unique profile ID (integer)</li>
</ol>
<p><img alt="" src="http://dannyjessee.com/blog/wp-content/uploads/2012/11/112112_1759_UsingAzureA12.png" /></p>
<p>Press <strong>Save </strong>to save the rules.</p>
<h3>Upload Token Signing Certificate</h3>
<p>If you haven&#8217;t already, you will need to configure Azure ACS to utilize an X.509 certificate to digitally sign the tokens it generates. Optionally, you can also specify certificates to use for token encryption and decryption. For the purposes of this demonstration, I generated a self-signed certificate using the <strong>makecert </strong>utility. <strong>DO NOT DO THIS IN PR</strong><strong>ODUCTION!</strong> I then uploaded this certificate by going to the <strong>Certificates and Keys </strong>link under <strong>Service settings</strong> in the ACS management portal.</p>
<p><a href="http://dannyjessee.com/blog/wp-content/uploads/2012/11/cert1.png"><img class="alignnone size-full wp-image-389" alt="cert1" src="http://dannyjessee.com/blog/wp-content/uploads/2012/11/cert1.png" width="815" height="213" /></a></p>
<p>Click <strong>Add</strong> to upload your certificate. This page allows you to specify where the certificate should be used, what type of certificate it is, and how to make it the primary token-signing certificate. It even includes the specific <strong>makecert</strong> command you need to run to generate a self-signed certificate (again, I cannot overemphasize how important it is that you <strong>NOT </strong>use a self-signed certificate in production!)</p>
<p><a href="http://dannyjessee.com/blog/wp-content/uploads/2012/11/cert2.png"><img class="alignnone size-full wp-image-390" alt="cert2" src="http://dannyjessee.com/blog/wp-content/uploads/2012/11/cert2.png" width="809" height="667" /></a></p>
<p>That&#8217;s all we need to do within Azure ACS!</p>
<h2>SharePoint 2013 Setup</h2>
<p>Within SharePoint, we must do the following:</p>
<ol>
<li>Create a <strong>new web application</strong> using Claims-based authentication (the default mechanism in SharePoint 2013).</li>
<li>Configure Azure ACS as a new <strong>Trusted Identity Provider</strong> for that web application and tell SharePoint to trust the certificate Azure ACS uses to sign its SAML tokens.</li>
<li>Set a <strong>User Policy </strong>within the web application to allow users who log in via the Trusted Identity Provider to have access to the site.</li>
</ol>
<h3>New Web Application</h3>
<p>From SharePoint 2013 Central Administration, create a new web application. Unlike SharePoint 2010, SharePoint 2013 does not prompt you to choose between Classic and Claims-based authentication. Claims is the default (hooray)!</p>
<p>Make sure the host header matches the host header for the <strong>Return URL </strong>specified in the Azure ACS relying party application setup. Enable <strong>Integrated</strong><br />
<strong>Windows Authentication </strong>with <strong>NTLM </strong>at this step. You&#8217;ll notice no <strong>Trusted Identity providers </strong>exist at this point.</p>
<p><img alt="" src="http://dannyjessee.com/blog/wp-content/uploads/2012/11/112112_1759_UsingAzureA13.png" /></p>
<p>Enjoy the friendly new progress messages in SharePoint 2013:</p>
<p><img alt="" src="http://dannyjessee.com/blog/wp-content/uploads/2012/11/112112_1759_UsingAzureA14.png" /></p>
<p><img alt="" src="http://dannyjessee.com/blog/wp-content/uploads/2012/11/112112_1759_UsingAzureA15.png" /></p>
<p>Create a new site collection at the root of the web application and choose a Windows identity for the primary Site Collection Administrator.</p>
<h3>Configure Azure ACS as a new Trusted Identity Provider</h3>
<p>In order to enable us to select Azure ACS as a trusted identity provider for the web application, we need to run some PowerShell. The script to run appears below.</p>
<pre class="brush: powershell; title: ; notranslate">
$realm = &quot;http://intranet.contoso.com&quot;
$signinurl = &quot;https://dannyjessee.accesscontrol.windows.net:443/v2/wsfederation?wa=wsignin1.0&amp;wtrealm=http%3a%2f%2fintranet.contoso.com%2f&quot;
$certloc = &quot;C:\dannyjessee.cer&quot;
$rootcert = Get-PfxCertificate $certloc
New-SPTrustedRootAuthority &quot;Danny Jessee Azure ACS&quot; -Certificate $rootcert
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($certloc)
$map1 = New-SPClaimTypeMapping -IncomingClaimType &quot;http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress&quot; -IncomingClaimTypeDisplayName &quot;Email&quot; -SameAsIncoming
$map2 = New-SPClaimTypeMapping -IncomingClaimType &quot;http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name&quot; -IncomingClaimTypeDisplayName &quot;Display Name&quot; –LocalClaimType &quot;http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname&quot;
$map3 = New-SPClaimTypeMapping -IncomingClaimType &quot;http://www.facebook.com/claims/AccessToken&quot; -IncomingClaimTypeDisplayName &quot;Access Token&quot; -SameAsIncoming
$map4 = New-SPClaimTypeMapping -IncomingClaimType &quot;http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier&quot; -IncomingClaimTypeDisplayName &quot;Name Identifier&quot; –LocalClaimType &quot;http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn&quot;
$map5 = New-SPClaimTypeMapping -IncomingClaimType &quot;http://schemas.microsoft.com/ws/2008/06/identity/claims/expiration&quot; -IncomingClaimTypeDisplayName &quot;Expiration&quot; -SameAsIncoming
New-SPTrustedIdentityTokenIssuer -Name &quot;Facebook&quot; -Description &quot;Facebook&quot; -Realm $realm -ImportTrustCertificate $cert -ClaimsMappings $map1,$map2,$map3,$map4,$map5 -SignInUrl $signinurl -IdentifierClaim $map1.InputClaimType
</pre>
<p>This script performs the following actions:</p>
<ol>
<li>Establishes a trust relationship between SharePoint and the Azure ACS token signing certificate (this is the equivalent of going to <strong>Security &gt; Manage trust</strong> and uploading this certificate in Central Administration).</li>
<li>Sets up the claim rules to pass the claims returned from Azure ACS to the SharePoint STS at the <strong>_trust </strong>endpoint (in some cases, these claims need to be mapped to different claim type URIs to avoid collisions with claims provided by the SharePoint STS).</li>
<li>Creates a new trusted identity provider associated with the appropriate realm, certificate, claims mappings, and sign in URL (this value can be obtained by going to <strong>Application integration </strong>under <strong>Development </strong>in the Azure ACS management portal, then selecting <strong>Login pages</strong>).</li>
</ol>
<p>Some things to keep in mind as you modify this script to run in your environment:</p>
<ul>
<li>Ensure the value for <strong>$realm</strong> matches the realm value used when creating the relying party application within Azure ACS.</li>
<li>Ensure the X.509 certificate used here is the same as the token signing certificate used when creating the Relying Party application within Azure ACS.</li>
<li>Ensure the value for <strong>$signinurl</strong> is set properly for your SharePoint web application.</li>
</ul>
<p>Run this PowerShell script from the SharePoint 2013 Management Shell (as an Administrator). If you don&#8217;t see <span style="color: red;"><strong>red text</strong></span>, you&#8217;re doing alright!</p>
<p><img alt="" src="http://dannyjessee.com/blog/wp-content/uploads/2012/11/112112_1759_UsingAzureA16.png" /></p>
<p>Return to the list of web applications in SharePoint 2013 Central Administration. Select the web application and press <strong>Authentication Providers</strong>.</p>
<p><img alt="" src="http://dannyjessee.com/blog/wp-content/uploads/2012/11/112112_1759_UsingAzureA17.png" /></p>
<p>Choose the appropriate zone and scroll down. <strong>Facebook </strong>should now appear in the list of trusted identity providers:</p>
<p><img alt="" src="http://dannyjessee.com/blog/wp-content/uploads/2012/11/112112_1759_UsingAzureA18.png" /></p>
<p>Select <strong>Facebook</strong> and press <strong>Save</strong>. You have now configured Azure ACS as a new trusted identity provider, and SharePoint knows it can trust SAML tokens signed with your Azure ACS token-signing certificate.</p>
<h3>Set User Access Policy</h3>
<p>In order for users to access your SharePoint 2013 site once they have authenticated via Facebook, we must grant them the appropriate level of authorization. To do this, I recommend setting a &#8220;Full Read&#8221; policy for all users who authenticate to SharePoint via our &#8220;Facebook&#8221; trusted identity provider. Start by selecting the web application in Central Administration and go to <strong>User Policy</strong>.</p>
<p><img alt="" src="http://dannyjessee.com/blog/wp-content/uploads/2012/11/112112_1759_UsingAzureA19.png" /></p>
<p>Choose <strong>Add Users</strong>, then select the appropriate zone (All zones) and press <strong>Next</strong>.</p>
<p>Select the address book icon beneath the <strong>Users </strong>text box to bring up the <strong>Select People and Groups </strong>dialog.</p>
<p><img alt="" src="http://dannyjessee.com/blog/wp-content/uploads/2012/11/112112_1759_UsingAzureA20.png" /></p>
<p>Select <strong>All Users</strong>, then choose <strong>All Users (Facebook)</strong>. Press <strong>Add </strong>to select the group.</p>
<p><img alt="" src="http://dannyjessee.com/blog/wp-content/uploads/2012/11/112112_1759_UsingAzureA21.png" /></p>
<p>Check the box for <strong>Full Read</strong> in the permissions section and press <strong>Finish</strong>.</p>
<p><img alt="" src="http://dannyjessee.com/blog/wp-content/uploads/2012/11/112112_1759_UsingAzureA22.png" /></p>
<p>The new policy is now displayed at the bottom of the list.</p>
<p><img alt="" src="http://dannyjessee.com/blog/wp-content/uploads/2012/11/112112_1759_UsingAzureA23.png" /></p>
<p>With that, our SharePoint configuration is complete! We are now ready to have our users sign in to SharePoint 2013 with Facebook.</p>
<h1>Signing in to SharePoint 2013 with Facebook</h1>
<p>Navigate to the home page of the web application. The default sign in page will appear.</p>
<p><img alt="" src="http://dannyjessee.com/blog/wp-content/uploads/2012/11/112112_1759_UsingAzureA24.png" /></p>
<p>Choose <strong>Facebook </strong>from the drop down list. The user will be redirected (through the Azure ACS portal) to a Facebook-hosted login page.</p>
<p><img alt="" src="http://dannyjessee.com/blog/wp-content/uploads/2012/11/112112_1759_UsingAzureA25.png" /></p>
<p>Enter your Facebook credentials and press <strong>Log In</strong>. The first time a user attempts to log in to your SharePoint site with Facebook, he or she will be prompted to grant the Facebook application access to the user&#8217;s basic information and email address (this is based on the permissions we set up when we initially defined the Facebook identity provider in the Azure ACS management portal).</p>
<p><img alt="" src="http://dannyjessee.com/blog/wp-content/uploads/2012/11/112112_1759_UsingAzureA26.png" /></p>
<p>Press <strong>Go to App</strong>. The user should be redirected back to Azure ACS, which then redirects the user back to SharePoint…logged in with Facebook credentials!</p>
<p><img alt="" src="http://dannyjessee.com/blog/wp-content/uploads/2012/11/112112_1759_UsingAzureA27.png" /></p>
<p>Note the user&#8217;s display name is the email address associated with the user&#8217;s Facebook account. This is because we set <strong>EmailAddress</strong> as the <strong>IdentifierClaim </strong>in the PowerShell script we ran to configure Azure ACS as a trusted identity provider.</p>
<p>I know this is a <strong>TON </strong>of information to put in a single blog post, so feel free to post any questions in the comments!</p>
]]></content:encoded>
			<wfw:commentRss>http://dannyjessee.com/blog/index.php/2012/11/using-azure-acs-to-sign-in-to-sharepoint-2013-with-facebook/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Slides and Code for my #SPSCincinnati Session</title>
		<link>http://dannyjessee.com/blog/index.php/2012/10/slides-and-code-for-my-spscincinnati-session/</link>
		<comments>http://dannyjessee.com/blog/index.php/2012/10/slides-and-code-for-my-spscincinnati-session/#comments</comments>
		<pubDate>Mon, 29 Oct 2012 11:47:52 +0000</pubDate>
		<dc:creator>Danny Jessee</dc:creator>
				<category><![CDATA[SharePoint]]></category>

		<guid isPermaLink="false">http://dannyjessee.com/blog/?p=287</guid>
		<description><![CDATA[A huge thank you to all the organizers, volunteers, speakers, sponsors, and attendees who made SharePoint Saturday Cincinnati 2012 (also known as &#8220;ScarePoint Saturday Spookinnati&#8221;) such a huge success! I had a great time making new friends and catching up with old ones. I especially wanted to thank everyone who came out early on a [...]]]></description>
				<content:encoded><![CDATA[<p>A huge thank you to all the organizers, volunteers, speakers, sponsors, and attendees who made <a href="http://www.sharepointsaturday.org/cincinnati/default.aspx" target="_blank">SharePoint Saturday Cincinnati 2012</a> (also known as &#8220;ScarePoint Saturday Spookinnati&#8221;) such a huge success! I had a great time making new friends and catching up with old ones.
</p>
<p>I especially wanted to thank everyone who came out early on a rainy, cold Saturday morning to attend my session &#8220;SharePoint 2010, Claims-based Identity, Facebook, and the Cloud.&#8221; The audience was very engaged and we had some of the best discussions and questions of any time I have ever given this session.
</p>
<p>One question I received that I wanted to address specifically here was about how to integrate a Facebook application with a <a href="https://www.facebook.com/about/pages" target="_blank">Facebook Page</a>. <a href="http://webapps.stackexchange.com/questions/23082/why-can-i-not-create-an-application-on-my-facebook-page" target="_blank">Unfortunately, you can&#8217;t create a Facebook application using the identity of your Facebook Page.</a> You MUST use your <a href="https://www.facebook.com/help/117200265032897" target="_blank">&#8220;authentic personal Facebook account&#8221;</a> to create the application that is required to set up Facebook as an identity provider in the Azure ACS management portal (note that this is not a limitation of Azure ACS; it would apply whether you were writing a custom STS to support Facebook login, or even if you were using Facebook to log in to a web site that had nothing to do with SharePoint or IIS). That said, this restriction is something organizations need to keep in mind as they plan the management and governance of the Facebook application required to support logging in to their web site—SharePoint or otherwise.
</p>
<p>Note that it IS possible to post things like status updates from SharePoint to a Facebook Page&#8217;s wall, as long as you <a href="https://developers.facebook.com/docs/reference/login/page-permissions/" target="_blank">request the <strong>manage_pages</strong> permission</a> from users who log in using your application. Note that you would have to write additional code to retrieve a separate <strong>access_token</strong> for the Page (which would require the logged in user to be an administrator of that Page). If anyone out there tries this approach, please let me know how it works for you!
</p>
<p>Here are the slides from my presentation:
</p>
<p><iframe src="http://www.slideshare.net/slideshow/embed_code/14930713" width="427" height="356" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC;border-width:1px 1px 0;margin-bottom:5px" allowfullscreen> </iframe>
<div style="margin-bottom:5px"> <strong> <a href="http://www.slideshare.net/dannyjessee/sharepoint-2010-claimsbased-identity-facebook-and-the-cloud-14930713" title="SharePoint 2010, Claims-Based Identity, Facebook, and the Cloud" target="_blank">SharePoint 2010, Claims-Based Identity, Facebook, and the Cloud</a> </strong> from <strong><a href="http://www.slideshare.net/dannyjessee" target="_blank">Danny Jessee</a></strong> </div>
</p>
<p>Source code and/or a WSP for the web parts I demonstrated can be downloaded from <a href="http://facebookwebparts.codeplex.com">CodePlex</a>.
</p>
<p>To learn more about Azure ACS, check out <a href="https://www.windowsazure.com/en-us/develop/net/how-to-guides/access-control/" target="_blank">this page</a> and sign up for your <a href="https://www.windowsazure.com/en-us/pricing/free-trial/" target="_blank">free Windows Azure trial</a>.
</p>
<p>Thanks again to everyone for such a great event!</p>
]]></content:encoded>
			<wfw:commentRss>http://dannyjessee.com/blog/index.php/2012/10/slides-and-code-for-my-spscincinnati-session/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Programmatically Updating SharePoint User Profiles with Facebook Data</title>
		<link>http://dannyjessee.com/blog/index.php/2012/05/programmatically-updating-sharepoint-user-profiles-with-facebook-data/</link>
		<comments>http://dannyjessee.com/blog/index.php/2012/05/programmatically-updating-sharepoint-user-profiles-with-facebook-data/#comments</comments>
		<pubDate>Sun, 06 May 2012 19:32:40 +0000</pubDate>
		<dc:creator>Danny Jessee</dc:creator>
				<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[Facebook]]></category>
		<category><![CDATA[SharePoint 2010]]></category>
		<category><![CDATA[user profiles]]></category>

		<guid isPermaLink="false">http://dannyjessee.com/blog/?p=274</guid>
		<description><![CDATA[While giving my demo at SharePoint Saturday Boston last weekend, I showed how to populate a Contacts list in SharePoint with data from the currently logged in user&#8217;s Facebook profile. An audience member posed a question about user profiles in SharePoint and how data from Facebook could also be used to populate them. Though I [...]]]></description>
				<content:encoded><![CDATA[<p>While giving <a href="http://dannyjessee.com/blog/index.php/2012/04/slides-code-and-more-for-my-spsbos-session/">my demo</a> at <a href="http://www.sharepointsaturday.org/boston">SharePoint Saturday Boston</a> last weekend, I showed how to populate a Contacts list in SharePoint with data from the currently logged in user&#8217;s Facebook profile. An audience member posed a question about user profiles in SharePoint and how data from Facebook could also be used to populate them. Though I had never considered the potential applications of doing this (one might not think to leverage SharePoint user profiles in a public-facing scenario), it is technically straightforward to do.
</p>
<h2>Prerequisites<br />
</h2>
<p>In order to surface Facebook profile information in a SharePoint user profile, you should have the following in place:
</p>
<ul>
<li>A My Site Host site collection deployed on the same web application where Facebook is configured as an identity provider.
</li>
<li>User Profile properties configured to allow the user to edit values for the properties you wish to set/update programmatically.
</li>
</ul>
<h2>Objective<br />
</h2>
<p>In our scenario, we will take the following information from a user&#8217;s Facebook profile and use it to populate his/her SharePoint user profile:
</p>
<ul>
<li>Given name
</li>
<li>Job title
</li>
<li>Location
</li>
<li>&#8220;About me&#8221; bio
</li>
<li>Birthday
</li>
<li>Profile picture
</li>
</ul>
<h2>Our Starting Point<br />
</h2>
<p>Upon initially configuring Facebook as an identity provider for SharePoint, a very bare bones user profile will appear when selecting &#8220;My Profile&#8221; from the welcome menu.
</p>
<p><img src="http://dannyjessee.com/blog/wp-content/uploads/2012/05/050612_1932_Programmati11.png" alt=""/>
	</p>
<p>The profile page (person.aspx) shows the claims-encoded name for the user, and that&#8217;s about it:
</p>
<p><img src="http://dannyjessee.com/blog/wp-content/uploads/2012/05/050612_1932_Programmati21.png" alt=""/>
	</p>
<h2>The Code<br />
</h2>
<p>The algorithm required to update a user profile for a user logged in via Facebook is the same as it is for any other <strong>SPUser</strong>; however, we will utilize the <a href="http://csharpsdk.org">Facebook C# SDK</a> to encapsulate calls to the Facebook Graph API to get the information we need. For demonstration purposes, I have this code wired up to a button click event handler in a SharePoint web part.
</p>
<p>This code leverages <a href="http://json.codeplex.com/">JSON.NET</a> to parse the JSON-formatted values returned by calls to the Facebook Graph API.</p>
<pre class="brush: csharp; title: ; notranslate">
// Iterate through the Claims we are presented until we find the Facebook AccessToken
// and given name
IClaimsPrincipal claimsPrincipal = Page.User as IClaimsPrincipal;
claimsIdentity = (IClaimsIdentity)claimsPrincipal.Identity;
foreach (Claim c in claimsIdentity.Claims)
{
    if (c.ClaimType.Equals(&quot;http://www.facebook.com/claims/AccessToken&quot;))
    {
        // We will use this Claim to make all calls to the Facebook Graph API
        token = c.Value;
    }
    else if (c.ClaimType.Equals(&quot;http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname&quot;))
    {
        // We will use this Claim to set the proper display name for the user
        givenName = c.Value;
    }
}

// Assuming we have the AccessToken, use it to access the user's Facebook profile
if (!string.IsNullOrEmpty(token))
{
    var client = new Facebook.FacebookClient(token);
    var me = (IDictionary&lt;string, object&gt;)client.Get(&quot;me&quot;);

    Guid siteId = SPContext.Current.Site.ID;
    Guid webId = SPContext.Current.Web.ID;

    // Assume the identity of the application pool - this account is configured as an
    // Administrator of my User Profile Service Application in Central Administration
    SPSecurity.RunWithElevatedPrivileges(delegate()
    {
        using (SPSite site = new SPSite(siteId))
        {
            try
            {
                // Obtain a reference to the UserProfileManager for this SPSite
                SPServiceContext sc = SPServiceContext.GetContext(site);
                UserProfileManager userProfileMangager = new UserProfileManager(sc);

                SPUser currentUser = SPContext.Current.Web.CurrentUser;
                if (currentUser != null)
                {
                    // Get the current user's SharePoint profile
                    UserProfile profile = userProfileMangager.GetUserProfile(true);

                    // Update the display name and preferred name to match given name
                    profile.DisplayName = givenName;
                    profile[PropertyConstants.PreferredName].Value = givenName;
                    profile[PropertyConstants.Birthday].Value = (string)me[&quot;birthday&quot;];
                    profile[PropertyConstants.AboutMe].Value = (string)me[&quot;bio&quot;];
                                    
                    // Get the current job title
                    JsonArray work = me[&quot;work&quot;] as JsonArray;
                    // Most recent/current employer stored in work[0]
                    JsonObject company = work[0] as JsonObject;
                    if (company.ContainsKey(&quot;position&quot;))
                    {
                        JsonObject position = company[&quot;position&quot;] as JsonObject;
                        profile[PropertyConstants.JobTitle].Value = (string)position[&quot;name&quot;];
                        profile[PropertyConstants.Title].Value = (string)position[&quot;name&quot;];
                    }
                                    
                    // Get the current location
                    JsonObject location = me[&quot;location&quot;] as JsonObject;
                    string cityState = (string)location[&quot;name&quot;];
                    profile[PropertyConstants.Location].Value = cityState;

                    // Get the user's current Facebook profile picture
                    // https://graph.facebook.com/[Facebook Profile ID]/picture?type=large
                    profile[PropertyConstants.PictureUrl].Value = &quot;https://graph.facebook.com/&quot; + (string)me[&quot;id&quot;] + &quot;/picture?type=large&quot;;
                                    
                    // Commit all changes to the user's profile
                    profile.Commit();
                }

                lblOutput.Text = &quot;&lt;font color=green&gt;&lt;b&gt;User profile successfully updated.&lt;/b&gt;&lt;/font&gt;&quot;;
            }
            catch (Exception ex)
            {
                lblOutput.Text = &quot;&lt;font color=red&gt;&lt;b&gt;&quot; + ex.Message + &quot;&lt;br/&gt;&quot; + ex.StackTrace + &quot;&lt;/b&gt;&lt;/font&gt;&quot;;
            }                            
        }
    });
}
</pre>
</p>
<h2>The Outcome<br />
</h2>
<p>After executing this code, the user&#8217;s SharePoint profile looks a lot more complete!
</p>
<p><img src="http://dannyjessee.com/blog/wp-content/uploads/2012/05/050612_1932_Programmati31.png" alt=""/>
	</p>
<h2>One Final Thing<br />
</h2>
<p>My demos include a basic &#8220;status update&#8221; web part that allows a user to type a status message in a SharePoint web part. With a few additional lines of code, we can update the <strong>&#8220;What&#8217;s happening?&#8221; </strong>text bubble to include the text of this status update as well:</p>
<pre class="brush: csharp; title: ; notranslate">
SPServiceContext sc = SPServiceContext.GetContext(site);
UserProfileManager userProfileMangager = new UserProfileManager(sc);
UserProfile profile = userProfileMangager.GetUserProfile(true);
profile[PropertyConstants.StatusNotes].Value = txtStatus.Text;
profile.Commit();
</pre>
</p>
<p>Now whenever I post a status update, it will update both my Facebook profile and my SharePoint profile!
</p>
<p><img src="http://dannyjessee.com/blog/wp-content/uploads/2012/05/050612_1932_Programmati41.png" alt=""/>
	</p>
<p><img src="http://dannyjessee.com/blog/wp-content/uploads/2012/05/050612_1932_Programmati51.png" alt=""/></p>
]]></content:encoded>
			<wfw:commentRss>http://dannyjessee.com/blog/index.php/2012/05/programmatically-updating-sharepoint-user-profiles-with-facebook-data/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
