Skip to content

Music Works In Progress

April 5, 2012

Over the last two years or so, I’ve been slowly working on new music.  I mean it’s been literally over 4 years since I released La Famille Du Solénoïde, and that took a good year and a half to wrap up.

I’m struggling to stay with a consistent theme for this one, and I don’t want it to be another Sidetracks release with stuff that just didn’t fit into any one thing.

I have, however, released a couple of singles I felt were ready for prime time, and those were:

Both of the above tunes, just kinda fell into place.

But the others, I’m just not ready to call them done.

One in particular is Sea Dragon.  It’s nearly two years old itself, but I’m just not done with it.

I do plan on getting back in the home studio this weekend and trying to wrap up the following three tunes:

I’d like to get them to a state where I can release them as singles this weekend.  They may change slightly before the full release of the CD, but at least they’ll be at a point where I’d like to call them the “Official” initial versions.

And lastly, one that has potential, but I’m just not sure where to take it

Over the Horizon is turning into more of a long set with at least 2-3 segments.  Starting off mostly ambient, but turning into something a bit more classic Berlin School.  If I finish this monstrosity, it will probably be the CD’s center track.

I’d love to hear your feedback on the current versions of these songs if you have the time. Simply click their links and give them a listen!  These links won’t remain active forever.  So if you’re reading this post 6 months from now, don’t complain that the links are broken.

Keep in mind, I’m not done with them, and know of plenty of spots that need to be “corrected”/reworked/etc., but please make your critique anyways Smile.  Especially Over The Horizon.  It tends to drag on the last 7 minutes, but that’s where I’m stuck with it. Smile

Thanks a million!

– Keith

SharePoint Item Level Security means nothing to the BLOB Cache with anonymous access

April 2, 2012

Now hold your horses, you’re saying “Well duh, it’s anonymous access” but follow closely, I’m talking about item level security on items where you have REMOVED Anonymous access.  I’m going to show you how security is enforced with default SharePoint security, but broken when the BLOB Cache is enabled.

I ran across this issue the other day while working with one of my customers. Initially I was thinking this was a misconfiguration in their environment as it was pretty complex. To eliminate the possibility of it being a configuration issue in their environment, I setup a very simple repro in my lean SharePoint 2010 environment.

In a nutshell, with BLOB Caching enabled, it’s not guaranteed that individually secured items that do NOT have anonymous access won’t be served up to requests if they reside in a list/document library that allows Anonymous access. The steps laid out here, show that someone who does not have rights to a resource can still view documents that they shouldn’t.

Note: If you do NOT have the file types defined in the BlobCache element everything works fine. And, if you DO NOT have the BLOB Cache enabled, normal SharePoint security works just fine.

Let me add the caveat that it’s probably not a good idea to put items such as word/excel/pdf etc in the BLOB Cache, but some people have reason to do so.

Special thanks to Sean McDonough (http://sharepointinterface.com/) and Todd Klindt (http://www.toddklindt.com/blog/default.aspx) for letting me bounce some thoughts off of them, and their assistance with making sure I wasn’t going crazy J.

The Environment

· Windows Server 2008 R2

· SQL 2008 R2

· SharePoint 2010 Server with Service Pack 1 applied.

Steps to reproduce behavior

First we’ll initialize Anonymous access for the web application and site collections we’ll be testing on.

Ensure that you have a web application that has Anonymous Access enabled.

Navigate to Application Management in Central Administration, then Manage web applications under the Web Applications section. Then select the web application of choice and select the Authentication Providers button on the ribbon.

clip_image002

Choose the zone you wish to configure,

clip_image003

Ensure Enable anonymous access is checked on in the Anonymous Access section.

clip_image004

Create a Site Collections and enable Anonymous Access at the site level.

For this example, I utilized the following naming convention on my site.

1 Site collection based on the Team Site ( A plain vanilla SharePoint site) http://extranet.jupiter.local/sites/team

For the site collection perform the following steps. (Note that the screen shots are showing a publishing portal, but the steps are the same for a plain team site.)

Select Site Permissions from the Site Actions button.

clip_image006

Select the Anonymous Access button on the Ribbon.

clip_image008

Select Entire Web site from the choices on the Anonymous Access dialog.

clip_image009

The resulting permissions list for the site will then look similar to the following on a publishing site.

clip_image011

At this point the default document libraries in the sites already have Anonymous Access enabled (since they are inheriting from the site (web) level. For a publishing site, the default document library is called “Documents” for a team site, it’s called “Shared Documents”. Just noting it when we get into the details of the ULS logs etc. My troubleshooting on this issue was initially on a publishing site, so there may be inclusions of that traffic in the details.

Now, it doesn’t matter if you have a folder hierarchy in the document libraries or not, as the root of the problem stems from checking at the list/document library level for Anonymous access, but we’re going to mix it up a bit by creating a subfolder in our document library and breaking inheritance on it as well, just to show the depth of the problem.

Setting up our document/folder hierarchy.

Perform the following steps in the “Shared Documents” folder on the team site.

Navigate to the document library and select Documents from Library Tools. Then select the New Folder button on the ribbon.

clip_image013

Name the new folder “secure” and select save.

clip_image014

From the drop down for the new folder, select Manage Permissions.

clip_image016

Select the Stop Inheriting Permissions button on the ribbon.

clip_image018

The end result of the permissions for the folder will now show that Anonymous users do not have access, and any new documents introduced into this folder will thus use the permissions of the folder for their security.

clip_image020

Important, if you do this on a publishing site, be sure you “APPROVE” the new “secure” folder so it’s visible to authenticated users.

Now let’s create some test files. The type of file doesn’t matter to reproduce the problem. It’s just a matter of that file extension being in the BlobCache setting in the web config. For purposes of my demonstration, I’m just going to create two simple text files. One called “unsecure.txt” and one called “secure.txt”

I have uploaded the unsercure.txt file to the root of the document library, and have uploaded the secure.txt file to the secure folder within the document library.

Important, on a publishing site, be sure you Check In/Publish and Approve the documents!

For the secure.txt document, also stop inheriting permissions from its parent. It’s currently inheriting from the secure folder, but let’s go ahead and give it item level security as well.

Showing how SharePoint Security Works as expected

Now let’s navigate to the site as an anonymous user, and you’ll see that we CAN navigate to the root of the document libraries, but we can NOT navigate to the secure folder in the libraries (nor see them) anonymously.

Now try to browse directly to the individual files. (Yes, you DO need to know the exact url to the file to show the problem, but how many times does that happen in an email forward or copy where you’re given the url to a file you shouldn’t have access too J).

For our test purposes, here are the direct URL’s to the files

http://extranet.jupiter.local/sites/team/Shared%20Documents/unsecure.txt

http://extranet.jupiter.local/sites/team/Shared%20Documents/secure/secure.txt

What you’ll notice is that as an anonymous user, you can browse directly and view/download the unsecure.txt files, but NOT the secure.txt files which are expected behaviors. Everything is working like a charm. You know that your files that do NOT have anonymous access cannot be viewed by folks who should NOT be able to view them. The SharePoint security/authorization structure is working perfectly.

(Note: As I was preparing this, I was UNABLE to even view the root of the “Documents” folder in a Publishing site even though the document library DOES in fact allow anonymous access. This is different from the behavior of the team site, but that’s a whole different problem in itself, and I’ll post on that one separately. The key is that the unsecure.txt file CAN be viewed anonymously.)

Showing how SharePoint Security breaks with the BLOB Cache

Now, let’s completely break our security system by enabling the BlobCache.

If you want to read a good article on using the BLOB Cache in your sharepoint environment, check out Seans’ post here: http://sharepointinterface.com/2012/03/12/do-you-know-whats-going-to-happen-when-you-enable-the-sharepoint-blob-cache/

Edit the web.config for this web application, and find the BlobCache entry, and enable.

By default, the BlobCache element in the web.config will look as so:

<BlobCache location="C:\BlobCache.14" path="\.(gif|jpg|jpeg|jpe|jfif|bmp|dib|tif|tiff|ico|png|wdp|hdp|css|js|asf|avi|flv|m4v|mov|mp3|mp4|mpeg|mpg|rm|rmvb|wma|wmv)$" maxSize="10" enabled="false" />

To enable it, we set the enabled attribute to true rather than false. Now, this alone isn’t going to cause the problem, unless one of the documents you’re trying to keep secure is one of the file types listed in the path attribute. For instance, if the files you are trying to secure are mp3/mov files etc. the problem would in fact present itself. So in order to show our problem, let’s also add the txt file extension to the path attribute. The end result is a BlobCache element that looks similar to the following:

<BlobCache location="C:\BlobCache.14" path="\.(txt|gif|jpg|jpeg|jpe|jfif|bmp|dib|tif|tiff|ico|png|wdp|hdp|css|js|asf|avi|flv|m4v|mov|mp3|mp4|mpeg|mpg|rm|rmvb|wma|wmv)$" maxSize="10" enabled="true" />

Clear your browser cache or use InPrivate browsing, and refresh the file at http://extranet.jupiter.local/sites/team/Shared%20Documents/unsecure.txt

The file should of course open, but if you look at the folder hierarchy in the BlobCache folder you setup in the web.config, you’ll notice the file is now in the cache.

clip_image022

Now let’s browse to the secure.txt file which does NOT allow anonymous users access.

Be sure to clear your browser cache so that it does in fact make a request to the server for the file.

http://extranet.jupiter.local/sites/team/Shared%20Documents/secure/secure.txt

You MAY get prompted initially for credentials, but if so just hit cancel and refresh

Whoa! An anonymous user is now able to see a document you THOUGHT was secure!

clip_image024

Even if you clear the cache and do an iisreset, the problem will still persist.

Run the following commands in powershell to clear the blobcache (Changing the url to your own of course) then do an IIS reset.

$webApp = Get-SPWebApplication "http://extranet.jupiter.local"

[Microsoft.SharePoint.Publishing.PublishingCache]::FlushBlobCache($webApp)

If you now go back and disable the BlobCache (enabled=”false”) everything will start working for you. You’ll get a 401 unauthorized response as you would expect.

Solution/Workaround

Now obviously the quick solution/workaround to this problem is to NOT include document types that may have security on them in the list of document types on the path attribute of the BlobCache. Especially if the performance improvements by using the Blobcache is important to your environment.

After poking around using reflection, it appears that with BLOB Caching, the only check when a resource is requested is at the list level. If the Caching layer sees that the list allows anonymous access, requests to the resource are cached and thus served to the end user.

What’s the correct behavior?

So this begs the question: “Which algorithm is right?”

1. Does SharePoint "officially" support per-item security in a list marked for anonymous access? If so, the BLOB Cache behavior is wrong.

2. If the BLOB Cache behavior is officially "right" according to Microsoft, then SharePoint itself isn’t properly handling permission checks (and should be allowing access).

Either way, something needs to be fixed/changed, and I would highly consider you checking your environment for this little “Gotcha”.

Hope this helps!

- Keith

SharePoint PeopleEditor.ResolvedEntities always zero when control is disabled

March 14, 2012

I’ve been trying to track down this mystery in a project I’m working on for some time.

In a nutshell, we’re using the Microsoft.SharePoint.WebControls.PeopleEditor/picker for resolving SharePoint users in our custom web parts like any good SharePoint dev might want to do.  We collect the user data and various other important stuff, and save our data to a database. We later pull up a page with this same part, edit some data, and update our entries in the database.  Everything is working just great.

Except, sometimes it appears that the User ID’s we’re saving for the users in the people editors are getting lost, but only SOMETIMES.  I would see it, then not be able to reproduce it and move on with other important matters and place it on the backburner.

So let’s start with some code samples of what’s going on.

This section of code is what we use to get the SPUser.ID from the PeopleEditor/Picker before saving it to the database (IF a user is selected of course).

int primaryContactID =0;

if (PrimaryContactEditor.ResolvedEntities.Count > 0); 
{
  Microsoft.SharePoint.WebControls.PickerEntity entity = 
    (Microsoft.SharePoint.WebControls.PickerEntity)PrimaryContactEditor.ResolvedEntities[0];
  acctName = entity.EntityData["AccountName"].ToString();
  SPUser user = SPContext.Current.Web.EnsureUser(acctName);
  primaryContactID = user.ID;
}

When the part is loaded, we load up the editor to show the user as being preselected.

    
private void PopulatePickerControl(Microsoft.SharePoint.WebControls.PeopleEditor pe, int userID)
{
   if (userID > 0)
   {
       SPSecurity.RunWithElevatedPrivileges(delegate()
       {
           SPUser user = 
             SPContext.Current.Web.SiteUsers.GetByID(userID);
           Microsoft.SharePoint.WebControls.PickerEntity entity = 
             new Microsoft.SharePoint.WebControls.PickerEntity();
           entity.Key = user.LoginName;
           entity = pe.ValidateEntity(entity);
           if (entity != null)
           {
               System.Collections.ArrayList list = new System.Collections.ArrayList();
               list.Add(entity);
               pe.UpdateEntities(list);
           }
       });
  }
}

Pretty straight forward stuff. and everything works perfectly.  The same code to get the users account, ensure they are placed into the web, and the ID is retrieved works flawlessly every single time.

Until…

The PeopleEditor is disabled to prevent editing.

And we’ve got good reasons for doing so.  In this case, some users should never be able to change the users selected from the people editors/pickers.  At this point, they are merely there for presentation purposes, but some users can. And those  users may need to change the value.

But, if you set the editor to disabled such as this:

PrimaryContactEditor.Enabled = false;

  

Then the ResolvedEntites array will always be zero.  The editor will surely show you’re resolved entities, but this collection will always be empty.

Why? I have no idea.  It makes no sense to me why it should behave this way.

– Keith

Reorder new Content Type fields on the fly

November 10, 2011

At some point in time you will inevitably need to add a new field to an existing content type programmatically.  For example, adding Lookup column to a Content Type.  You can’t do it within the Content Type CAML if the target list doesn’t exist. It’s common to add the lookup within a FeatureActivated event after the list is created.

This is accomplished quite easily using the Add method of the FieldLinks property on the Content Type itself.  The draw back is that the new field is always added to the end of the list, and from a presentation standpoint, this may not be desired.

For example, adding lookups to the content type like so:

 

       
private void CreateDigitalReleasesList(SPWeb web)
{
  SPList list = web.Lists.TryGetList(Constants.DigitalReleasesList_Name);
  if (list == null)
  {
    Guid listID = web.Lists.Add(Constants.DigitalReleasesList_UrlName,
      "Used to record Digital Distributor Releases", 
      SPListTemplateType.GenericList);
    list = web.Lists[listID];
    list.Title = Constants.DigitalReleasesList_Name;
    list.OnQuickLaunch = true;
    list.Update();

    SPList ddList = web.Lists.TryGetList(DistributorsList_Name);
    SPList relList = web.Lists.TryGetList(ReleasesList_Name);

    if (ddList != null && relList != null)
    {
       SPFieldLookup ddLookup =
         (SPFieldLookup) web.Fields[fieldName_DistributorLookup];
       SPFieldLookup relLookup = 
         (SPFieldLookup) web.Fields[fieldName_ReleaseLookup];

       AddFieldToContentType(web, 
         contentType_DigitalRelease, ddLookup);
       AddFieldToContentType(web, 
         contentType_DigitalRelease, relLookup);
    }


    AssociateContentType(web, Constants.DigitalReleasesList_Name, 
      Types.Constants.contentType_DigitalRelease);
  }
}

public static void AddFieldToContentType(SPWeb web, string contentType, SPField field)
{
  SPContentTypeId ctId = new SPContentTypeId(contentType);
  SPContentType ct = web.ContentTypes[ctId];
  ct.FieldLinks.Add(new SPFieldLink(field));
  ct.Update();
}

Results in the presentation of the fields at the bottom of the form like so:

Capture

 

The solution, is to use the Reorder method on the FieldLinks collection, however this requires you to layout the names of each field in the array in the order that you want.  If you were to construct this array using literals, that could easily result in unnecessary maintenance of the code when you need to make a change to the column names, etc. during development or updates.

It would be easier to just specify the order of the new field at the time that you link it and be completely generic and frankly agnostic of the field names as much as possible.  Therefore here’s a modified version of the sample code exposed above. Pay particular attention to the modification of AddFieldToContentType.

       
private void CreateDigitalReleasesList(SPWeb web)
{
  SPList list = web.Lists.TryGetList(Constants.DigitalReleasesList_Name);
  if (list == null)
  {
    Guid listID = web.Lists.Add(Constants.DigitalReleasesList_UrlName,
      "Used to record Digital Distributor Releases", 
      SPListTemplateType.GenericList);
    list = web.Lists[listID];
    list.Title = Constants.DigitalReleasesList_Name;
    list.OnQuickLaunch = true;
    list.Update();

    SPList ddList = web.Lists.TryGetList(DistributorsList_Name);
    SPList relList = web.Lists.TryGetList(ReleasesList_Name);

    if (ddList != null && relList != null)
    {
       SPFieldLookup ddLookup =
         (SPFieldLookup) web.Fields[fieldName_DistributorLookup];
       SPFieldLookup relLookup = 
         (SPFieldLookup) web.Fields[fieldName_ReleaseLookup];

       AddFieldToContentType(web, 
         contentType_DigitalRelease, ddLookup, 2);
       AddFieldToContentType(web, 
         contentType_DigitalRelease, relLookup, 3);
    }


    AssociateContentType(web, Constants.DigitalReleasesList_Name, 
      Types.Constants.contentType_DigitalRelease);
  }
}

public static void AddFieldToContentType(SPWeb web, string contentType, SPField field, int order)
{
  SPContentTypeId ctId = new SPContentTypeId(contentType);
  SPContentType ct = web.ContentTypes[ctId];

  // Generate a string array with the existing order of the fields.
  List fieldOrder = new List();
  for (int i = 0; i < ct.FieldLinks.Count; i++)
  {
    fieldOrder.Add(ct.FieldLinks[i].Name);
  }

  // Add the new field.
  ct.FieldLinks.Add(new SPFieldLink(field));
  ct.Update();

  // Now insert the new field in the proper order.
  // You might think you want to decrement the value of order,
  // since the generic list array is zero based, but the first 
  // item in the array is the actual "ContentType" field
  // so no decrement is necessary.
  fieldOrder.Insert(order, field.InternalName);
  ct.FieldLinks.Reorder(fieldOrder.ToArray());
  ct.Update();
}

The end result is similar to the following:

Capture

Hope you find this helpful!

- Keith

When death finds you

October 31, 2011

death-ipad-wallpaperI lie waiting throughout the year,

For that one day when I rise, and screams are what I hear.

Rising from my grave; ripping through the webbed mesh,

As worms burrow through my aging dead flesh.

My sinew is your fear, as I wait for you to sleep,

Rotting flesh and dripping blood are the companions that I keep.

I creep to your home, crawling through the night,

I sneak my way in, and slowly turn out the light.

Your fear of things that go bump in the night,

Leads me to you, drawn close by your fright.

Rotting flesh, crackling bones, and all things of gore,

Fill your dreams, as I slip through your darkened door.

A deathly cold breath, a smell rancid and stale,

Your eyes slowly open, your life leaves in your exhale.

I salivate as I drag you back to my hole,

And I savor, the sweet taste of your innocent soul.

 

Happy Halloween!

Be safe folks!

- Keith

La Famille Du Solénoïde –A Review

October 17, 2011

Sean McDonough recently posted a review of my La Famille Du Solénoïde release on Amazon. 

Excerpt:

“I’ve been listening to this release for the last few weeks while I’ve been working, and I’ve enjoyed it greatly. I continue to find myself stopping to listen to sections and segments that catch my attention.”

Thanks for the kind words Sean!

Read the entire review here!

La Famille Du Solénoïde (and other releases) are also available on the majority of Digital Music services such as (but not limited to)

  • Zune
  • iTunes
  • Amazon MP3
  • Spotify
  • Last.FM
  • Rhapsody

Enjoy!

– Keith

Programmatically waiting on SharePoint Solutions to deploy

September 2, 2011

I recently had the need to deploy multiple solutions via the object model, but of course had to wait for each solution to successfully deploy before moving to the next, etc.  Another requirement is that I needed a common code base that would work on either SharePoint 2007 or SharePoint 2010.  And of course, needed to work for a single server installation or a farm.

There are multiple posts out there about interfacing with and examining the running jobs on all servers via the timer service etc., but none of them seemed to work perfectly for me.

One would immediately think just to check SPSolution.Deployed and wait for it to be true before moving on to the next.

In my testing, this works great on SharePoint 2010 in my test environments, but not so well on SharePoint 2007.

For me, I found that not only did I need to check SPSolution.Deployed, but also check SPSolution.JobExists immediately afterwards.  I couldn’t just rely on SPSolution.JobExists, because at times it would be false right after adding the solution (Perhaps because the Job had yet to actually start).

So for me, it was best to first wait until SPSolution.Deployed was true, then wait for SPSolution.JobExists to be false.

This seemed like the simplest method for ensuring the solution was deployed and complete before moving on.

So here’s a bit of a code snippet to show you basically what I’m doing.  The following code assumes you have no specific web application you’re deploying to

SPSolution solution = 
  SPFarm.Local.Solutions.Add("pathtomysolution.wsp");

solution.Deploy(DateTime.Now, true, true);
bool deployed = solution.Deployed;

while (!deployed)
{
  Thread.Sleep(1000);
  deployed = solution.Deployed;
}

bool jobexists = solution.JobExists;

while (jobexists)
{
  Thread.Sleep(1000);
  jobexists = solution.JobExists;
}

 

With this, I don’t have to muck around with poking at the timer job service on every single server in the farm etc.

I’m curious how this might work in your environments and hope this helps!

– Keith

Follow

Get every new post delivered to your Inbox.

Join 627 other followers