23
Nov 11

AD roles and users in Sitecore Roles

Are you tired of Sitecore Security not working the way you would expect when adding Active Directory groups and accounts to Sitecore Roles?

I’ve developed a little class that takes care of that for you.

Here is the code, it’s well documented in-line so following the logic shouldn’t be an issue.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Security = Sitecore.Security;
using Sitecore.Diagnostics;
using Sitecore.Security;
using Sitecore.Security.Accounts;
using System.Web;
using site = Sitecore;
using Sitecore.Security.Domains;

namespace YourCompany.WebHive.Sitecore
{
    public class SwitchingRoleProvider : Security.SwitchingRoleProvider
    {
        public override bool IsUserInRole(string userName, string roleName)
        {
            Assert.ArgumentNotNull(roleName, "roleName");
            RoleProviderWrapper wrapper = this.Wrappers.GetWrapper(roleName);

            try
            {
                //Do this only for SQLRoleProvider as it's not possible to add
                //roles / accounts outside of AD to AD groups.
                if (wrapper.Provider is System.Web.Security.SqlRoleProvider)
                {
                    //Get all members of the Role passed.
                    IEnumerable accts = RolesInRolesManager.GetRoleMembers(Security.Accounts.Role.FromName(roleName),
                        false);

                    //If there are any member roles in other domains possibly other provider types.
                    if (accts.Count() > 0)
                    {
                        //Go through each account
                        foreach (Account account in accts)
                        {
                            //Cast to user.
                            User usr = account as User;
                            //If the account IS a user
                            if (usr != null)
                            {
                                //Does the user equal the passed userName?
                                if (userName.Equals(usr.Name))
                                    return true;
                            }
                            else //If account IS NOT a user
                            {
                                //Cast to Role
                                Role role = account as Role;
                                //If the account IS a role
                                if (role != null)
                                    //use base logic
                                    return base.IsUserInRole(userName, role.Name);
                            }
                        }
                    }
                    else //If there are no roles outside of the domain of the role passed (roleName)
                        return false;
                }
                else
                    //If the role provider for the passed role (roleName) is not of type SqlRoleProvider,
                    //use the base functionality.
                    return base.IsUserInRole(userName, roleName);
            }
            catch (Exception ex)
            {
                //Log any error.
                site.Diagnostics.Log.Error(
                    String.Format("Error trying to find user \"{0}\" in role \"{1}\"",
                        userName, roleName),
                    ex, this);
            }
            //Catch all -- if exception.
            return false;
        }
    }
}

Once you’ve created the class and built the DLL you’ll need to change the web.config

You’ll want to replace this line:


Wtih this one, updated with the new Switching Provider:


This only works when adding AD users / groups ONE 1 level deep, this is for obvious performance reasons. If you want to go deeper in the tree, I’d change the logic to run recursively instead of using the base method.


21
Oct 11

Could not load type ‘Sitecore.Resources.Media.MediaRequestSessionModule’ from assembly ‘Sitecore.Kernel’

If you are getting this error:

Could not load type ‘Sitecore.Resources.Media.MediaRequestSessionModule’ from assembly ‘Sitecore.Kernel’.

I have your solution. Warning the solution will make you want to kick yourself.

Replace the Sitecore.Kernel.dll in the bin directory, because something has overwritten it. If you’re like me, then it was another project’s reference to the same DLL with the “Copy Local” property set to true.

While you’re at it make sure all of the necessary DLLs are in the bin folder.


				

14
Oct 11

rspec Compare arrays without caring about the order

If the order matters:
array_to_test.should == [expected_array]

If the order doesn’t matter:
array_to_test.should =~ [expected_array]


12
Oct 11

Heroku not loading seeds file

Fun story about PostgreSQL – it’s case sensitive… and it assumes table names are lower case.

This means two things.

First – if your Rails seed files use capital letters they won’t load.

Second – if you fail to follow Rails conventions and use capital letters in table field names – your find_by_sql methods will throw errors.

Long story short – sqlite lets you get away with a lot of stuff. Make sure you’re following Rails conventions and you’ll be fine. Going forward I’ll always start development on my target production database server rather than using sqlite.


11
Oct 11

You don’t know JACSHT?!

The front end developers have David Hoerster to thank for the acronym JACSHT.

JAvascript CSs and HTml

Great, give hiring managers yet another acronym to fumble over and loose its meaning.

Who knows JACSHT? I DO!


27
Sep 11

Rails with SqlLite seeds boolean values as strings

Yep. In an odd twist of otherworldly fate – I am now convinced that if you use Rails to seed boolean values into a SqlLite DB they are represented as strings. This is especially odd since SqlLite doesn’t have a boolean storage class – it uses an integer type instead.

Here is the story:

So I have a model called UserProfile with a boolean value for :is_primary (in case there are alternative profiles). The User model creates the UserProfile on after_create setting :is_primary => true. SqlLite saves this value to the database as t as expected (… well sort of expected… I’m still not convinced “t” is an integer… whatever.)

This all worked fine and dandy until I seeded a bunch of profiles. Regardless of what value I used for the boolean value in the seed file (true, 1, t, whatever) Rails saved the value as the string “true” to SqlLite… which magically SqlLite didn’t seem to have a problem with.

Any new records still used t for true as “expected.” So if I created a new User record and typed UserProfile.find_all_by_is_primary(true) I could see the newly created record but none of the seed records returned… to get at those I had to type UserProfile.find_all_by_is_primary("true")… but then the newly created record wouldn’t show up.

Awesome, hungh?

It was actually my partner on this project (Max) who came up with the answer. Essentially we added a file in /lib/tasks/ called cleanup_seeds.rake which rails picks up whenever we reset the seeds. Here is what it looked like:

 "f")
        user_profile.update_attributes(:is_primary => "t")
      elsif user_profile.is_primary == "false"
        user_profile.update_attributes(:is_primary => "f")
        user_profile.update_attributes(:is_primary => "t")
      end
    end
  end
end

namespace :db do
  task :reset => :environment do
    Rake::Task["db:cleanup"].invoke
  end
end

Notice that for “true” we first set the value to “f” before setting it to “t.” If we didn’t do this – Rails would compare “true” to “t,” not notice a difference, assume SqlLite didn’t suck, and not save the change to the record.

Not sure if this issue will pop up again when we start using PostgreSQL in production… if it does I will update this post.


26
Sep 11

OS X Lion sh: make: command not found

After installing Mac OS X Lion I decided to upgrade my version of ruby. Suddenly error abound:

configure: error: no acceptable C compiler found in $PATH

Turns out installing Lion borks xCode 3… meaning you need to acquire xCode 4. Since you most likely don’t have media for the OS – this means slumming to the app store to download around 3 gigs (again). Honestly – I’m a little upset the OS software update didn’t prompt me on this until I was in the zone installing a feature on a project… but whatever.

Anywho – I say all that to illustrate why I got to thinking about how useless a process indicator graphic is on a 3 gig download. Without number (at LEAST the % downloaded) it just kinda sits there without moving. If you wanna see where your download is from the app store – to go the app store and select the “Purchased” icon at the top. The status of any downloads (617 MB of 3.17GB currently) is shown.


20
Sep 11

Session cancels on POST request with AuthLogic

So you have you app. You authenticate a user. You click around to a form. If it’s a GET – you have no problems… current_user is there. But if it’s a POST, PUT or DELETE current_user disappears and you’re suddenly logged out.

I originally assumed this was an AuthLogic issue – but as it turns out it is a security feature in Rails. Specifically – your POST request is not sending the correct CSRF token – which causes request_forgery_protection to politely and quietly log you out like the dirty hacker you look like.

If your form uses form_for this is handled for you. However if it doesn’t (say an ajax request or if for some reason you use create a form element without the Rails helper) you need generate a hidden field to send with your form.

In HAML syntax it looks like this:

%input{:type => "hidden", :name => "authenticity_token", :value => form_authenticity_token }

15
Sep 11

Setting up factory girl association using class_name

Let’s say you have a model where the name of an attribute for an association is not the name of the class it represents:

class FollowedTopic < ActiveRecord::Base
  belongs_to :followed, :class_name => "Topic"
  belongs_to :user, :class_name => "User"
end

If you want to generate this object in Factory Girl you need to essentially do the same thing – reference another factory for that association. Looks like this:

Factory.define :followed_topic do |ft|
  ft.association :followed, :factory => :topic
  ft.association :user
end

14
Sep 11

Using shoulda – ensure_inclusion_of value in array

If you want to validate a boolean value in a Rails model you can’t use validates_presence_of :is_bacon – because the method Rails uses to validate will react to the false value as though the property is missing. Instead you need to supply an array of values to the validates_inclusion_of like this:

validates_inclusion_of :is_bacon, :in => [true, false]

Easy enough – but the problem comes in when you try to test this validation in shoulda – which only allows a range of values for ensure_inclusion_of.

it { should ensure_inclusion_of(:is_bacon).in_range([true, false]) }

returns an error like:

1) BreakfastMeat validations
   Failure/Error: it { should ensure_inclusion_of(:primary_alias).in_range([true, false]) }
   NoMethodError:
     undefined method `-' for true:TrueClass
# ./spec/models/topic_alias_spec.rb:35

I consider this a bug… but the guys from shoulda figure you should test that each item in the array is a valid entry. So your test should looks like this:

it { should allow_value(true).for(:is_bacon) }
it { should allow_value(false).for(:is_bacon) }

Hopefully they fix this – because there are an infinite number of things that my :is_bacon could accept in addition to the two values I expect… so a negative test really isn’t helpful. Not what I consider good code coverage… but apparently will have to do.