Skip Ribbon Commands
Skip to main content

Liam Cleary [SharePoint MVP]

:

Home
April 10
SharePoint 2013 Hosted Apps – Do they really work? Part 3

In our last post we made changes to our SharePoint 2013 Hosted App, to use the REST API to get list items that were selected from a list. When you clicked on the Ribbon button it sent the selected items to the "default.aspx" page of the App Web and rendered them accordingly. The code we used for rendering the selected items was not ideal as we just asked the REST service to give me everything and then filter out the ones that are not in the query string. As you can imagine not the most performing code you could write.

To make this better and faster one of the new features of the REST API is to pass filters directly to the call. Firstly let's look at the syntax, we can use. We can test this by using the following URL against our Office 365 site.

https://demo.sharepoint.com/sites/appdev/_api/web/lists('{List_ID}')/items

This will let you call the REST API directly and see an RSS feed type result come back. Some basic examples would be to specify the fields that come back. To do this the URL would need to be the following:

https://demo.sharepoint.com/sites/appdev/_api/web/lists('%7BB6F5FCC8-5102-4F1B-9F24-D8929162CB51%7D')/items?select=Title,Body

When this is ran you should see the following:

This does not really help us as we would like to see the core XML, I use Fiddler for this, so when you call the URL you are able to inspect the response. You will see a get request similar to this:

If you select that line and then select the "Headers" tab on the right and choose "XML" from the bottom you should see the returned XML response.

This just helps me see that the right XML is being returned. Using the "$select" parameter we can specify as many fields as we wish or simply remove it to show all fields.

Now back to the original issue, we want to only retrieve the selected items form the REST API call, not all of them and filter. So we can now use another parameter "$filter". As a simple example let's retrieve one of the items from our "Announcements" list.

https://demo.sharepoint.com/sites/appdev/_api/web/lists('%7BB6F5FCC8-5102-4F1B-9F24-D8929162CB51%7D')/items?$filter=ID eq 3&$select=Title,Body

This URL will render the following:

And out Fiddler trace shows the following:

So what if we wanted to filter on multiple values, so in our example let's say we had selected items 3 and 2. Our new filter URL would be the following:

https://demo.sharepoint.com/sites/appdev/_api/web/lists('%7BB6F5FCC8-5102-4F1B-9F24-D8929162CB51%7D')/items?$filter=ID eq 3 or ID eq 2&$select=Title,Body

Our fiddler trace will now return the following:

So to tie this all together we need to change out code in the "App.js" to be the following so it only returns the selected items. Firstly we need to modify the following code:

This creates a new variable to contain a dynamic query. We then modify the core document ready code to not run and simply show us an alert box saying the "selectedids" variable is not populated, in the real world you would change this behavior of course. We then wrap a call to the "getSelectedItemIDs" and the rest of the core code to ensure it does not run when nothing has been selected. Now we need to modify the core method "getSelectedList" to contain a filtering option.

We also need to remove the last code we used in the "getListSuccess" method as we are no longer getting all the items and filtering through the loop process.

Lastly we need to create the new method "getSelectedItemIDs" which simply splits the query string that contains the selected IDs from the list, loops through them and creates an output that renders like this:

Now when we run the code, we are able to select values and when we click the ribbon button will render only those, by using the REST API query to just get those items.

So to recap we have looked at using the selected items query string, passing it into the REST API call after dynamically create the filter clause then rendering the values out on the page. In the next post we will look at creating the rest of the user interface such as the grid for the specific fields we want to show.

April 09
SharePoint 2013 Hosted Apps – Do they really work? Part 2

So in part 1​ we looked at some basic concepts of creating a SharePoint 2013 Hosted App. In this post we will continue with our demonstration app and look to expand it further. We left off with a custom ribbon action that redirects to a page within the App Web and simply just uses the default code from the "App.js" to render your display name. As a recap the design we are looking for is to allow a user to select items from a list and then when they click the ribbon be redirected to the App Web and render a grid type view of just the selected items, which we learned from the last post we can get by using query string parameters. So to start we need to open the "App.js" file and look at the existing code.

 

This code is very straight forward, as it simple gets a context for SharePoint using the client object model, grabs the current web which in this case is the SharePoint site you clicked the ribbon button from and then gets the "Current User" which would be you right now. When the document is loaded which is checked with the following code:

 

A custom function called "getUserName()" is called which loads the current user and executes an asynchronous query which on success writes out the name that you see on the page.

 

So let's look at changing this to retrieve data about the SharePoint Site using the REST API that is now available in SharePoint 2013. First off we will need to add the following to the "Default.aspx" page markup.

 

Now we need to remove the current code from "App.js and add the following section first.

 

This code declares two variables, then loads them upon document ready from the query strings that are passed in the URL. It then loads a JavaScript files that is used to execute code, and we make a call to a custom method we create called "getSelectedList". The "getSelectedList" method for now is not actually getting a list, it will be retrieving the SharePoint Site Title, confusing I know but easier than changing all the code each time.

 

This method makes a call to the "_api" URL of SharePoint which an endpoint for the web services / WCF for the client object model components of SharePoint 2013. To read more about this, read the details on MSDN here:

http://msdn.microsoft.com/en-us/library/jj860569.aspx

In our custom method you will see that we have a success and error call to two methods shown below:

 

These methods simply either render an error or the SharePoint Site Title onto the "Default.aspx" page. We also have a helper method for parsing the query strings so we can use them through the code.

 

Now we have all the plumbing done we should be able to build and deploy our solution and it should render as shown below once we click the ribbon button.

 

If we debug the code by adding a break point in the "App.js" we can see that we are getting an "Access Denied" error.

 

 

This means that the current account is not allowed to access the root web properties. This is by design and this brings me to another consideration when designing a SharePoint 2013 Hosted App. You need to work out the permission level that you want to assign so when it is deployed the right trust level is set ready for use. To set the permission, double click the "AppManifest.xml" file in Visual Studio. Select the "Permissions" tab and you will be presented with the following screen:

 

Set this screen to the following:

 

Rebuild the solution deploy using "F5" as always from Visual Studio. This time when you deploy you get stopped halfway through and are asked to trust it.

 

Select the "Trust It" button and the page will load as shown below:

 

So the key here is that by design the end user who is accessing your application is NOT allowed to perform certain functions unless the trust level has been set in the App and accepted during installation. So now we have it working with SharePoint Site data, now let's change the code a little to retrieve a specific list from the site. First off ensure you have an announcements list with some items within the SharePoint Site you are using.

Modify the "Default.aspx" page to now have the following code, you can remove the last markup we added.

 

We now need to modify the custom function we wrote to now use the following:

 

The success and failure method also need to be changed slightly too.

 

As before now build and deploy using Visual Studio so we can debug if needed. Accept the "Trust" and it should render as shown below:

 

Now that we are able to render the values let's make some changes to the code so it will work for any list that we decide to click the ribbon button from. To do this lets first look at the URL:

https://demo-5551df50f28634.sharepoint.com/sites/appdev/DemoApp/Pages/Default.aspx?SPHostUrl=https%3A%2F%2Fdemo%2Esharepoint%2Ecom%2Fsites%2Fappdev&SPLanguage=en%2DUS&SPClientTag=0&SPProductNumber=15%2E0%2E4454%2E1034&SPAppWebUrl=https%3A%2F%2Fdemo%2D5551df50f28634%2Esharepoint%2Ecom%2Fsites%2Fappdev%2FDemoApp&SelectedList={B6F5FCC8-5102-4F1B-9F24-D8929162CB51}&SelectedItems=3,2

If we look in the link above we have the query string from the last post already in there, which is "SelectedList={B6F5FCC8-5102-4F1B-9F24-D8929162CB51}", this means we already have the list ID so if we modify the code a little we should be able to use this dynamic value, instead of hard coding "Announcements". To achieve this firstly add the following to "App.js".

 

This will get us the list ID loaded into a variable we can use throughout the code. Now we need to modify the "getSelectedList" method code to be the following:

 

Once complied and deployed you are then able to click any list and it should render details as shown below.

Announcement List

 

Contacts List

 

So now we have the code working for any list now we need to look at restricting the list of items that is renders to the selected items that are passed in the URL. We need to change the code in the "App.js".

 

Next we need to change the rendering code to be the following:

 

Now build and deploy from Visual Studio so you can debug and you should now be able to select items within the list and when the page renders it will only display the selected items. Of course there are better way of doing this but we will save that for another day.

In the next post we will look at the options available for rendering more than just "Title" and "Body" fields and actually create the grid view we need.

April 08
SharePoint 2013 Hosted Apps – Do they really work? Part 1

Recently I have spent some time working through building and converting demonstration code across to SharePoint 2013 Apps and have a fun time learning what can be done and really what can't be done. This post is based my practical experience so far of trying to use "SharePoint Hosted Apps" only. The reason for this was to make an App that would work on-premise and on Office 365 with no dependency on managed code but to use pure JavaScript.

So to create a new SharePoint 2013 Hosted App you need to ensure that when you create the project in Visual Studio you select the correct option.

Once the project is created you should get a structure similar to this:

The basic construct is the following:

  1. Feature Folder – Normal SharePoint Feature dialog you have used in the previous tooling
  2. Content Folder – Any specific content that will reside in the App Web, by default the App.CSS file
  3. Images Folder – Images that will reside in the App Web
  4. Pages Folder – The core pages that will reside in the App Web (Core User Experience)
  5. Scripts Folder – Contains all JavaScript files, such as jQuery and the core App.js, once again all hosted in the App Web
  6. AppManifest File – Base configuration and permission sets for the App

If we deploy this solution as is, it will render values that are called from the App.js file. This will display your current display name.

This page is loaded from the App Web, this is the separate web site that gets stood up as part of the new App Model. A SharePoint 2013 Hosted App when deployed does this automatically and crea6es a URL similar to this:

So the first things to note here is that the code and other assets do not live inside SharePoint, so that changes the overall design considerably. So the user experience becomes slightly more complicated than before. Whereas we would write code either full trust or even sandboxed code it would be deployed directly into SharePoint, so simple things such as deploying files like images, CSS or JavaScript to the style library was still supported, now it is not. Sean McDonough has a great blog post about imaging rendering and SharePoint 2013 Apps in General, I would suggest a read:

http://sharepointinterface.com/2013/01/22/custom-ribbon-button-image-limitations-with-sharepoint-2013-apps/

So let's think about an example app we could build. For this demonstration I would like an end user to access a list, see the list items, press a ribbon button, and then popup a dialog over the top listing out the selected items only and then allow the end user to perform some action. I can hear you thinking this is going to be easy. Write a full trust solution that does the following:

  1. Deploys JavaScript, CSS and Images
  2. Adds a Ribbon Button, maybe as a custom "Additional Page Head" control so it shows up on all Ribbon Bars
  3. Uses C# to get the currently viewed list
  4. Uses JavaScript to get the selected items
  5. Opens the Dialog
  6. Loads a custom page, maybe "_layouts" page
  7. Custom Page uses C# to get the currently selected list, renders only the selected items based on what is passed to it

Of course there are many ways of doing this same thing whether using Full Trust C# or Sandboxed Client Object Model code. So how do we do this for a SharePoint 2013 Hosted App. First off let's look at adding a ribbon button. In the Visual Studio right click he project and select "Add New Item". From the list select the "Ribbon Custom Action".

Once selected you are asked to define the type of Ribbon Action. The first thing is where you wish this custom action to reside. The Host Web is SharePoint, the App Web is the funny website that got created in my Office 365 Tenant when I deployed it. As we need this ribbon button to be in the current SharePoint, we will select the "Host Web" option. We also have the ability to scope the action to one of the following:

The interface does not allow for scoping actions to anything other than List Templates and List Instances. Selecting List Template will populate the second dropdown with the available list templates in the SharePoint site that is connected to Visual Studio. If you select List Instance it will populate the dropdown with available lists that are deployed and active in the SharePoint site. For this example we are going to choose "None" as I would like to associate this action to more than one list or template.

The tooling then let's you select the control location from a predefined list:

This list is great but once again does not list every location you would want to use. You can overtype this with your own values if needed. For this demonstration we will use "Ribbon.List.Actions", with the control navigation set to the default page.

Visual Studio will then create the custom action object in the project and the "elements.xml" file is loaded and will look similar to this:

The code looks fairly straight forward and what you would be used to seeing, however notice that the "CommandUIHandler" is a redirect to the following URL:

~appWebUrl/Pages/Default.aspx?{StandardTokens}

You will notice it is using a token for the URL, the "~appWebUrl" is a unique one that SharePoint 2013 understands and will replace at the build and deployment time into the full URL of the App Web, so it will end up being something like this:

You will also see an appended query string of "StandardTokens", this is one of the replacement tokens that are available. This specific one combines five other tokens. "SPHostUrl", "SPAppWebUrl", "SPLanguage", "SPClientTag" and "SPProductNumber". Sahil Malik has a list of all the tokens that are available in SharePoint 2013 Apps and when they can be used.

http://blah.winsmarts.com/2013-2-SharePoint_2013_apps_replacement_tokens.aspx

Let's say we wanted to change this mechanism to use a simple piece of JavaScript. SO something simple like this: "javascript:alert('Hello World');", we would change the XML to be the following:

Now if we build the application is Visual Studio all is well. Now if we try to deploy it something strange happens.

It errors with the deployment saying there are errors in the package. This is because you CANNOT run inline JavaScript inside ribbon actions at all. This is a big difference to the full trust and sandboxed design we currently have in SharePoint 2010. So from a user experience for something like this we would need to explain to the end user that every time they click the ribbon it will take them out of the SharePoint site to perform the task and then we would need to handle through code the redirect back or the end user would be stuck in the app not SharePoint. By default however you will notice that the App Web is styled with a similar chrome to SharePoint itself, along with a link to get back to the site you came from, this will help in the user experience.

So back to performing a redirect, this means we need to write the code in the App Web for getting list items etc. as per our design for this demonstration app. If we change the code back and build and deploy we should be back to the site now. To test the ribbon we can access a list and see in the "Actions" section our new button.

If you click this button it will redirect you to the App Web and show the default page. If we look at the URL we can see the token values:

https://demo-5551df50f2862e.sharepoint.com/sites/appdev/DemoApp/Pages/Default.aspx?SPHostUrl=https%3A%2F%2Fdemo%2Esharepoint%2Ecom%2Fsites%2Fappdev&SPLanguage=en%2DUS&SPClientTag=0&SPProductNumber=15%2E0%2E4454%2E1032&SPAppWebUrl=https%3A%2F%2Fdemo%2D5551df50f2862e%2Esharepoint%2Ecom%2Fsites%2Fappdev%2FDemoApp

This is great as it already passes a lot of information that we would need to us in the App Web, such as the actual site we are in. We can change our Visual Studio solution to also send us further details, such as the ID's of the selected items, the list ID and name. To do this we need to make changes to the "CommandAction" link. Modify the link to be the following:

Now build and deploy the solution and test the link this time. This time access the list and select a few items as shown below and click the ribbon link and the URL should now be similar to this:

https://demo-5551df50f28632.sharepoint.com/sites/appdev/DemoApp/Pages/Default.aspx?SPHostUrl=https%3A%2F%2Fdemo%2Esharepoint%2Ecom%2Fsites%2Fappdev&SPLanguage=en%2DUS&SPClientTag=0&SPProductNumber=15%2E0%2E4454%2E1032&SPAppWebUrl=https%3A%2F%2Fdemo%2D5551df50f28632%2Esharepoint%2Ecom%2Fsites%2Fappdev%2FDemoApp&SelectedList={B6F5FCC8-5102-4F1B-9F24-D8929162CB51}&SelectedItems=3,2

This time you will notice that we get the list ID and the selected ID's of the values we selected in the list, so now we just have to wire up the new page in the App Web to display these items in a list view type grid.

This design now means that we need to allow the end user to perform the required tasks such as selecting items in SharePoint, send that to the App Web and then re-connect to the SharePoint site and list or library using the client object model or the REST API features. This logic will be added to the "App.js" file which is referenced in the "default.aspx" page.

The "App.js" file allows us to add any JavaScript or JSOM code to connect or interrogate SharePoint. Be aware that this is a subset of the core API that is available in SharePoint. In the next post we will look at writing JavaScript code in the "App.js" along with the pro's and con's to this design.

March 25
Thought about speaking at a SharePoint Conference?

So this year has been busy so far for me (not as busy as some people I see while travelling). So far I have presented at the following conferences and SharePoint Saturdays:

SharePoint Saturday Utah, January 19th, 2013

SharePoint Saturday Philadelphia, February 23rd, 2013

SharePoint Saturday Austin, March 2nd, 2013

SPTechCon San Francisco, March 3rd - 6th, 2013

SharePointFest Denver, March 18th - 19th, 2013

SharePoint Saturday Richmond, March 23rd, 2013

My upcoming presentations and attendance as of today are the following:

SharePoint Summit Toronto, May 13th - 16th, 2013

TechEd North America, June 3rd - 6th, 2013

SharePoint Conference.ORG, June 13th - 15th, 2013

SharePointFest Washington DC, August 5th - 7th, 2013

SPTechCon Boston, August 11th - 14th, 2013

As I look at my list and speak with other presenters in the SharePoint Community, I am always intrigued as to what motivates people to travel cross state, or countries on a Saturday to speak for an hour or so at a free event. As always the answer is "we/I want to give back and help the SharePoint Community". This really is what these events are about, giving back, sharing real world experience and hopefully helping someone or some organization see the light at the end of the tunnel for their SharePoint Project.

Being selected to speak at any event is an honor for me and should be for anyone. Being selected to present your experience, knowledge and demonstrate this to a room of 1 to 1000 is exciting and rewarding for anyone that does it. I encourage anyone who has even the smallest desire to present or even just wonders what it would be like to give it a go. The next SharePoint Saturday near you, submit a session that you are comfortable with and see what happens. What's the worst that happens? You don't get selected, or maybe being selected is the worst thing, just kidding.

As I have traveled around at these events, I am always able to learn something new, learn a new way of doing something or just make friends that you will see again and again at other events. The community of speakers is very close and is a great group of people to be with. And if you don't speak, don't want to speak, attend the event anyway and offer advice or just sit and take it all in.

For me the real benefit of the community is about each other, bouncing ideas off each other and just talking through issues, concerns or just sharing what has been done before. This is more valuable I feel than sitting on a course for a week to learn what to do with SharePoint. So take the time to attend some events, present at events and hopefully I will see you around the community very soon J

March 02
SharePoint 2013 – Health Analyzer

By now like me I am sure you have done a few SharePoint 2013 Installs, whether manual or scripted. When I perform the installation and run all then health monitoring rules I always end up with a couple of little things that need to be fixed. The same ones I get each time are the following:

So to resolve this issue let's look at what they are complaining about:

Missing server side dependencies

This was one issue that we saw in SharePoint 2010 and seems to persist in 2013 too.

To resolve this you simply need to perform the following tasks:

  1. Visit the Search Service Application

     

     

  2. Visit the "SearchFarmDashboard" page

     

     

  3. Re-analyze the rule and it should disappear, if not go back to the service application and click through more pages of the search then re-run the analyzer and it will clear itself.

 

Built-in Accounts are used as application pool or service identities

This one is all about setting services to the correct accounts. In my scripted installation I am performing as best as I can, a least privilege configuration. However SharePoint complains about the following:

Now I am not going to outline the steps to resolve this one, head over to the following links and read the conversation and then get the TechNet document.

http://social.technet.microsoft.com/forums/en-US/sharepointadminprevious/thread/b61864cd-0054-4bfc-9ef5-938c11418337/

http://go.microsoft.com/fwlink/?LinkId=196600

 

People search relevance is not optimized when the Active Directory has errors in the manager reporting structure

This well know too and can be resolved with the following:

http://technet.microsoft.com/en-us/library/hh867937(v=office.14).aspx

http://www.harbar.net/archive/2011/07/06/329.aspx

 

It might seem a little silly to aim for the clean health analyzer but if you want your SharePoint Farm to work as expected and needed then you have to take time to sort out all of the issues you see.

February 12
SharePoint 2013 and ADFS with Multiple Domains

While working with ADFS you may hit a requirement where you own multiple Active Directories or need to federate with another ADFS implementation to allow access to SharePoint. To achieve this we need to perform some very specific configuration. First off for my environment we need to get the service communication certificate and the certificate being used for the ADFS web site and trust them on each side of the server:

  1. ADFS Server A certificates added to ADFS Server B
  2. ADFS Server B certificates added to ADFS Server A

My certificates are all created using "SelfSSL" but would recommend for real world using an internally deployed Certificate Authority or purchasing proper certificates as needed.

ADFS Server A

 

ADFS Server B

 

These certificates needs to be added to the "Trusted Root" container within the certificate store.

 

 

Now that we have the certificates running you should be able to browse to:

https://{ADFS Server URL}/Federationmetadata/2007-06/federationmetadata.xml

This should load correctly in the browser and show without any SSL Errors.

To start out configuration we will start with "ADFS Server A" which is the one that contains the SharePoint Relying Party configuration.

 

We need to select the "Claims Provider Trust" node and choose to add a new claim provider trust.

 

 

You will need to get the URL for the External ADFS Federation Metadata XML file and add this into the wizard. This will allow the wizard to get the claim types and configuration automatically from the endpoint/

 

Set the name as you want it to be displayed in the ADFS Management tool.

 

The confirmation page should have retrieved all the core settings from the ADFS metadata file, you can check the values by going through the tabs.

 

When prompted to save, ensure the checkbox for edit claims is checked which will allow you to add the following (this needs to be changed to match your claims):

 

If we want to add these click the "Add Rule" button. Select "Pass Through or Filter an Incoming Claim", this is so we simply accept the claims being passed from the external domain directly into the core internal ADFS and through to SharePoint.

 

We now need to specify claim rule name and choose the incoming claim type. You are then able to specify how you want the claims to be passed through, for this example I have set it to "Pass through all claim values".

 

This completes the "ADFS Server A" configuration piece. Now we need to go to "ADFS Server B" and perform the following. Select the "Relying Party Trusts" and select to add a new one.

 

 

This time when adding the federation URL, use the internal ADFS URL not the External.

 

The confirmation page should have retrieved all the core settings from the ADFS metadata file, you can check the values by going through the tabs.

 

When prompted to save, ensure the checkbox for edit claims is checked which will allow you to add the following (this needs to be changed to match your claims):

 

We create a single rule with the following claims (once again this is just for the demonstration you may have others).

 

Now that was have this the last piece is to modify the SharePoint relying party to add the specific pass through claims that we will get from "ADFS Server B". Go to "ADFS Server A" and select the "SharePoint Relying Party", right click and choose "Edit Claim Rules".

You will see the core claim rule you setup the first time, but now you need to add pass through rules for the claims coming from the external domain.

Use the same approach as last time to add the pass through claim rules.

You need to make this change on all the relying parties you have configured in order for the pass through to work from the external claims all the way through to SharePoint, or you will get the following errors in the event log and be stuck in a loop.

Once saved we now have an end to end ADFS solution. To test this you can now from "ADFS Server B", this being the external ADFS server, with the correct DNS entries or host entries should be able to browse to the SharePoint URL, which should redirect to the realm picker to the following:

 

This page is presented from the internal ADFS, hosted on "ADFS Server A". If the names do not look as nice as these you can use PowerShell to modify them by using the following commands:

 

This will list out the core properties for the current ADFS setup. Using the following commands you can update the display name.

 

This will then be reflected directly within the realm picker. So to test we can now select the external ADFS from the picker. Based on SharePoint not being configured for permission yet you should see the following error:

 

To resolve this we can now go to the SharePoint Site logged in with credentials on the internal domain and set permissions as normal.

February 02
SharePoint 2010/2013 and ADFS with Encryption

While working with SharePoint 2013 and ADFS I needed to perform encryption during the process. This is very easy to setup within ADFS, by editing the properties of the Relying Party to set the encryption certificate.

 

Once this is set and ADFS is enabled on the site, when you access the site you get an error with no error message. Upon looking in the event log I saw the following error.

 

This error is saying that SharePoint is unable to use the encryption key as it is unaware of the key itself. To resolve this we need to modify the web.config for SharePoint with the following:

<add type="Microsoft.SharePoint.IdentityModel.SPSaml11SecurityTokenHandler, Microsoft.SharePoint.IdentityModel, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c">

<samlSecurityTokenRequirement>

<nameClaimType value="http://schemas.microsoft.com/sharepoint/2009/08/claims/userid" />

</samlSecurityTokenRequirement>

</add>

<add type="Microsoft.SharePoint.IdentityModel.SPTokenCache, Microsoft.SharePoint.IdentityModel, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />

<add type="Microsoft.IdentityModel.Tokens.EncryptedSecurityTokenHandler, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

</securityTokenHandlers>

<federatedAuthentication>

<wsFederation passiveRedirectEnabled="false" issuer="https://none" realm="https://none" />

<cookieHandler mode="Custom" path="/">

<customCookieHandler type="Microsoft.SharePoint.IdentityModel.SPChunkedCookieHandler, Microsoft.SharePoint.IdentityModel, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />

</cookieHandler>

</federatedAuthentication>

<serviceCertificate>

<certificateReference x509FindType="FindByThumbprint"

findValue="1BF5AF5E09DE6C2FC3FB3C0DD9B4FCACE73CCBFE"

storeLocation="LocalMachine" storeName="My"/>

</serviceCertificate>

</service>

</microsoft.identityModel>

</configuration>

The first line is to ensure that SharePoint now had a "TokenHandler" to handle encrypted traffic.

<add type="Microsoft.IdentityModel.Tokens.EncryptedSecurityTokenHandler, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

The second is actually the certificate that is being used for the encryption in ADFS. The thumbprint should be replaced with the correct one from the ADFS encryption certificate. You can get this by doing the following:

  1. Launch ADFS Management Console
  2. Clicking the properties for the Relying Party and selecting the Encryption Tab

     

     

     

  3. Click "View", then select the "Details" tab and scroll to "Thumbprint".

     

     

     

  4. Copy out the thumbprint, remove all spaces and then use that.

<serviceCertificate>

<certificateReference x509FindType="FindByThumbprint"

findValue="1BF5AF5E09DE6C2FC3FB3C0DD9B4FCACE73CCBFE"

storeLocation="LocalMachine" storeName="My"/>

</serviceCertificate>

 

Now you have it completed, you need to have the certificate in the manage trust and installed on the SharePoint Server so it will trust it. When you test the login it should work, but for my testing it gave me the following error:

 

Now SharePoint is complaining that the application pool account does not have permission to get the private key for the encryption certificate. To resolve this the easiest way is to use "WinHttpCertCfg" which can be downloaded from here:

http://www.microsoft.com/en-us/download/details.aspx?id=19801

Once it is installed you will need to launch a command window as an Administrator and navigation to the location you installed it in which by default is:

C:\Program Files (x86)\Windows Resource Kits\Tools

Once there you need to run the following command:

This will check what accounts have permissions to the certificate:

winhttpcertcfg -l -c LOCAL_MACHINE\Root -s {CertName}

NOTE: You need to replace "{CertName}" with the issued to name.

Then run this command to set the permission on the certificate for the application pool mentioned in the error log.

winhttpcertcfg -g -c LOCAL_MACHINE\My -s {CertName} –a "DOMAIN\AppPool"

Once set you will then be able to log into the site using ADFS without any errors and have the whole process encrypted via ADFS using your certificate. Hope this helps.

January 11
SharePoint Attack Surface

As part of the security posts I have been doing I thought it would be good to run through a tool from Microsoft called the "Attack Surface Analyzer". This is a free tool currently that you can get from the following link:

http://blogs.msdn.com/b/sdl/archive/2012/08/02/attack-surface-analyzer-1-0-released.aspx

This tool enables Developers and IT Administrators to see what the custom application, code or installed applications have changed to the original baseline installation. This particularly useful when you are installing a windows application and want to see what changes it makes to the server from the baseline scan you originally had. The tool also looks for security weaknesses caused by installed applications.

The usage of this tool is very straight forward:

  1. Build your baseline SharePoint Server with everything you need
  2. Perform the first scan

     

     

     

  3. This will scan everything on the server and when each item is completed it will inform you

     

     

     

  4. Once this is completed you will now have a baseline for the server

     

     

     

  5. Now install, or update your server with the software or code changes you need
  6. You will then need to re-run the scan again and save the output to a different "cab" file
  7. Now you are ready to perform a comparison between the baseline and your updated one

     

     

     

  8. Clicking "Generate" will then output a report comparing the two scans

     

     

     

  9. Once completed you will end up with a report that looks similar to the following

     

     

     

Now that you have the report you can see the base information, security issues and an overview of the attack surface.

 

 

As you can see this report can be very useful in reviewing the security of a server with roles, services, applications and even custom code enabled. It will allow you to make changes then re-run the scans and compare the results until you get a solid secure server.

January 08
What will 2013 hold?

So customary this time of the year is to review the past and say what you want to do for the coming year. Well for me what can I say, as a family we enjoyed a great year living in the USA, had a new edition to our family and really just enjoyed everything one day at a time.

Work is great, SusQtech is now owned by Protiviti so plenty of changes to come I am sure. And of course the SharePoint community, what can I say, I was honored to speak at a whole bunch of events from SharePoint Saturdays, SPTechCon, SharePoint Fest, SHarePointConference.ORG and of course the SPC12. All in all it has been a great year.

So what will 2013 bring for me?

For my family life we will have the same attitude as before, enjoying life day by day and just spending time together. All go at the end of year, as my daughter starts High School, Son starts Middle School and other son starts Kindergarten, all fun coming up.

 

For the SharePoint Community I am scheduled to speak at quite a few events starting with SharePoint Saturday Utah in two weeks, followed by a whole bunch more. My goal is to share the knowledge that I have, hopefully this will help in some small way. My big push is to make sure everyone makes the right choices when thinking about security with SharePoint and of course don't forget the hackers who of course are just waiting to hack your site J

 

Hopefully this year I will have the time and be able to speak at other location not just in the US. I would love to visit and speak in places such as Dubai, Australia, South America, Arab States and if we could swing it maybe a SharePoint Event in Tahiti J

 

Just kidding events are great but we have to work too. Hopefully in the future I will be able to travel and visit the places on my list and see what the rest of the SharePoint Community are up to.

 

Outside of the community efforts I am going on a health kick again, time to get back into a shape a little bit since my last injury last year that put out of running for a while. Now I am going to mix things up and mountain bike in-between running and see if that helps with my injury curse I have.

 

All in all I am planning on a great year with Family, Work and with everything in my life. Let's see how it goes, I am a great believer in "You are what you sow" and as I tell my kids you get no-one in life without a hard work and effort. Sometime I may just get lucky, here's hoping for that. J

December 18
Is Your SharePoint Secure – Server Security Part 4

In the last post we looked at using the security configuration wizard and how we can lock the server down. This is effective and should be on everyone's list for securing servers. The first line of attack is to narrow the surface attack vector so only allowed and required services and ports are open to the servers.

In this post we will look at securing SharePoint using SharePoint and some basic configuration. To begin with let's remind our self of the attack locations.

 

 

These locations are what we used in the first post using Google (for these) to find exposed SharePoint sites.

So how do we lock down the above list then?

Firstly if you are using an internal web site the first question to ask is if you really need to lock these down. Most of these pages are inherently set to require authentication which is inherited from the web application and IIS settings. Some of the page are set to specific permission sets which SharePoint handles perfectly and we don't need to worry about (for now anyway). So firstly SharePoint comes with the lockdown feature. This is available in SharePoint 2007, 2010 and 2013, and is enabled by default normally in 2010 upwards. In SharePoint 2010 we can find this feature by typing the following commands:

To see if the feature is enabled on a specific site you can use the following PowerShell.

 

This command will list a full table of activated features. Look down the list and see if the feature "ViewFormPagesLockdown" is listed.

 

So what is the purpose of this feature?

This feature when enabled ensures that Anonymous Users are not able to access pages such as these:

http://site.url/_layouts/Viewlsts.aspx

http://site.url/Pages/Forms/AllItems.aspx

These are often left open and allows a potential hacker to access content that should not be open such as this:

Randomly named List that is on a site not locked down:

 

If we go into the list we can see the following details (blurred for obvious reasons):

 

You can see that as an Anonymous User I can access details of users such as email address and phone numbers because the "ViewFormPagesLockdown" feature is not enabled. When it is enabled a redirect is performed such as this:

https://site.url/_login/default.aspx?ReturnUrl=%2f_layouts%2fAuthenticate.aspx%3fSource%3d%252F%255Flayouts%252Fviewlsts%252Easpx&Source=%2F%5Flayouts%2Fviewlsts%2Easpx

This sends the end user to an authentication process, whatever the site is configured for. The feature itself does nothing major if we look at the code of the feature it resets a permission for those objecting by grabbing the "Guest" role type which would be the Anonymous Users.



The code then removes permission for this guest role



The "SPBasePermission" Enumeration contains a value that gets set to "ViewFormPages" which restricts users from browsing pages under "_layouts" directory. This only works on pages that derive from the "LayoutsPageBase" class. If you want to circumvent this for some pages you will need to derive from "UnsecuredLayoutsPageBase" class instead.

Now this feature is great but still does not completely stop access to everything. We must ensure at this point that when enabling this feature we disable then re-enable the anonymous setting within SharePoint. For example even with this lockdown feature enabled I can still access the following:

http://site.url/_vti_bin/spdisco.aspx

As you know this file contains links to all the web service end points which could be compromised.

 

So to resolve this we need to look at using web.config changes such as "Path Location" mappings. Details of this can be found here: http://msdn.microsoft.com/en-us/library/ms178692(v=vs.85).aspx

For SharePoint if we open the web.config we can see the following path locations:

Paths with Permissions

 

Paths without Permissions

 

 

 

These locations allow the administrator and native SharePoint to set various properties for these specific locations and endpoints. The first set of permission based are the most important ones.

As a note, I am not advocating changing the default ones just adding to the list.

Permission based location paths can be set with the following syntax:

Deny All Anonymous Users (Unauthenticated Users)

 

Deny All Users

 

Deny Specific Role

 

Deny Specific User

 

Allow All Anonymous Users (Unauthenticated Users)

 

Allow All Users

 

Allow Specific Role

 

Allow Specific User

 

The syntax is very straight forward to configure so we need to set the following example location paths:

 

These locations will stop anonymous users from accessing not just the "_vti_bin" where the web service endpoints are but also lock a few others. You can add to the list also to lock further locations down. Before doing this is it best to use a network sniffer and potentially fiddler to see what Anonymous users get access to when just browsing the site. You don't want to inadvertently block access to functionality that is needed.

To ensure nothing is overriding our new setting we can adding it to the bottom of the web.config and using the following syntax to ensure that they are not override.

 

See the following article for examples:

http://www.iis.net/learn/get-started/planning-for-security/how-to-use-locking-in-iis-configuration

With the new location paths added when an Anonymous User tries to access for an example the http://site.url/_vti_bin/spdisco.aspx page it will perform a redirect prompting for authentication.

https://site.url/_login/default.aspx?ReturnUrl=%2f_layouts%2fAuthenticate.aspx%3fSource%3d%252F%255Fvti%255Fbin%252Fspdisco%252Easpx&Source=%2F%5Fvti%5Fbin%2Fspdisco%2Easpx

With the "ViewFormPagesLockdown" and location path mapping enabled this will ensure that the core pages that are often visible to the internet for Anonymous Users to see are not. One more defense in protecting your content and site from a malicious attack.

 

1 - 10Next
Come See Me Speak @ SharePoint Summit

 

 

 

 

 

 

​ ​​
Looking Cool!!