Sitecore CMS and everything related RSS 2.0
 Wednesday, August 23, 2006

I have once wrote about a rare security setup, in which there is a parent item that is less visible than a child. To recap, consider this setup:

home (allow read)
|
--news (deny read : browse only item)
   |
   --news_item (allow read)

Now theres another catch if you need to retrieve the 'news item' (in bold) using the api:

database.Items["/sitecore/content/home/news/news_item"] -> OK, news_item
database.Items["{id-of-news_item}"] -> OK, news_item

database.GetRootItem().Axes.SelectItems["/sitecore/content/home/news/news_item/*"]
-> null
database.GetRootItem().Axes.SelectItems["//news_item"] -> null (at least on sqlexpress)
database.GetRootItem().Axes.SelectItems["//{id-of-news-item}"] -> OK, news_item

(Tested on Sitecore 5.3 beta 060731)

Peter Johansson, who has the full credit for spotting this, made the following wrapper around SelectItems to be able to query over hidden items, but still respect security in the end:

public static List<Item> SelectItems(Item RootItem, string Query)
{
   List<
Item> itemsList = new List<Item>();
  
if (RootItem != null)
   {
      
Item[] items = null;
      
using (new Sitecore.SecurityModel.SecurityDisabler())
       {
           items = RootItem.Axes.SelectItems(RootItem.Paths.Path + Query);
       }
      
if (items != null)
       {
          
foreach (Item itm in items)
           {
              
if (itm.Access.CanRead())
               {
                   itemsList.Add(itm);
               }
           }
       }
   }
  
return itemsList;
}
 

As this is tested on beta version of Sitecore, I will followup if anything changes or I discover more. And now, it's time for a little vacation: see you on Monday.

Wednesday, August 23, 2006 5:49:20 PM (FLE Standard Time, UTC+02:00)  #    Comments [0] -
Sitecore | 5.3 | Security
 Wednesday, April 19, 2006
I’m using asp.net 2.0 portal on Sitecore front end in the current project, and personalization features such as portlet drag-n-drop just won’t work unless asp.net understands that the user is logged in and can tell the difference between users.

Here’s my hack-n-slash solution: it envolves shim classes implementing IPrincipal and IIdentity, delegating everything to Sitecore. User id is returned as user name to asp.net, so that each user gets own personalization data (actually user names would also work, since they're unique). On each request, a custom processor in HttpBeginRequest pipeline (named AspnetUserSetter) puts the Sitecore principal in asp.net context.

And since I'm humble enough to allow asp.net do the rest, using default personalization database and provider - it just works. Now I wish it was easier to create custom frames around web parts.

public class SitecorePrincipal : IPrincipal
{
  
private IIdentity identity;
  
public IIdentity Identity
   {
      
get { return identity; }
   }
  
  
public SitecorePrincipal()
   {
      identity =
new SitecoreIdentity();
   }

  
/// <summary>
   /// Checks whether Sitecore user is in the given role. Supports both role names and ids.
   /// </summary>
   public bool IsInRole(string role)
   {
      
if (MainUtil.IsID(role))
        
return Sitecore.Context.User.IsInRole(ID.Parse(role));

      
RoleItem roleItem = Sitecore.Context.Domain.GetRole(role);
      
if (roleItem != null)
        
return Sitecore.Context.User.IsInRole(roleItem.ID);
      
else
         return false;
   }
}

public class SitecoreIdentity : IIdentity
{
  
public string Name
   {
      
get { return Sitecore.Context.User.ID.ToString(); }
   }

  
public string AuthenticationType
   {
      
get { return "Sitecore Authentication"; }
   }

  
public bool IsAuthenticated
   {
      
get { return Sitecore.Context.IsLoggedIn; }
   }
}

public class AspnetUserSetter
{
  
public void Process(PipelineArgs args)
   {
      
HttpContext.Current.User = new SitecorePrincipal();
   }
}
Wednesday, April 19, 2006 9:41:41 AM (FLE Standard Time, UTC+02:00)  #    Comments [0] -
Sitecore | Security
 Friday, March 24, 2006

I think its quite common for various pieces of code in Sitecore to climb the item hierarchy up, seeking some inherited wisdom. A less common scenario, however, is to have a parent which is less visible than its child.

home
|
--news
   |
   --news item

(please bear with my advanced graph engine)

Imagine that you're not allowed to see the news section, but individual news items are just fine - either by mistake, or deliberately. So what happens if you have a code that goes up the tree ? (think breadcrumb)

Item item = this;
while (item != null)
{
   Collect(item.Fields["Menu Title"].Value);
   item = item.Parent;
}

You'll start with news item, which is fine. Then you go up to the news section, trying to read its field.. and get an exception, with a pretty clear message. That item that you don't have access to is considered to be "BrowseOnly", and reading fields of browse only items is bad.

To avoid seeing that exception in future, you need to add a guard clause looking for item.RuntimeSettings.BrowseOnly.

Hopefully this one stops biting me now.

Friday, March 24, 2006 12:48:20 AM (FLE Standard Time, UTC+02:00)  #    Comments [4] -
Sitecore | Security
 Monday, February 20, 2006
Beware of Credential Cache

As I've told before, we're now using Microsoft CRM system to manage extranet users. When you log in, the user data is being fetched from sql table, a virtual user is assembled using the ID from CRM and given the Sitecore security roles based on CRM permissions.

There's one catch though - Sitecore maintains a credential cache (since around 5.1 I think), so that it doesn't have to repeatedly calculate effective permissions for a given user to a given item. Once the user accesses the item the first time, permissions are calculated and stored in cache. Sitecore also makes sure to clear the cache when required. In our case, however, the user is changed inside the CRM system, and its our responsibility to let Sitecore know about it. Failing to do so might result in permission changes only taking effect after application restart.

There are several options to handle that:

1) Clear the cache once any entities affecting access permissions were changed.

In the case with Microsoft CRM that would mean registering a callout on 'account' or 'contact' entities change. The web service on Sitecore side listens for notifications and clears the cache on demand.

Pro: Security updates are in effect immediately
Con: More complicated, requires an outgoing connection from CRM to Sitecore web server

2) Clear the credential cache for a user each time he logs in

Overriding Sitecore.SecurityModel.Domain.Login(string, string) will hook you up right in there - it gets called each time the user tries to log in suppling her login and password

Pro: Simple
Con: Security might not be updated until user session times out. Cache is clearead unconditionally

To be honest I've wasted time on both. The CRM callout didn't fit in because of the need of active outgoing connection, and we're now using the second one.

[CredentialCacheController]

Monday, February 20, 2006 7:34:47 PM (FLE Standard Time, UTC+02:00)  #    Comments [2] -
Sitecore | Security
 Wednesday, December 21, 2005
Sitecore 4 developers are familiar with the login rendering concept: It is possible for any rendering to have its counterpart login rendering which gets shown if the user doesn't have required permission to access content.

I'll use SDN as an example - try to access an item that anonymous user is not allowed to read, like http://sdn.sitecore.net/articles.ascx. You can still see the layout. Moreover, top menu renders items accessible to the current user (Documentation is a public section) and the breadcrumb shows your correct location (home / articles) even though you cannot see the item itself.

The main content rendering (the one in the centre) shows the 'please login' info because it has the login rendering set, and Sitecore layout engine knows that the current user (anonymous) is not allowed to access the current item (/home/articles).

The concept is fundamentally changed in Sitecore 5 because of one difference: if the current user is not allowed to access the current page, he is redirected to:

1. Login page if the login page is specified for the current site, controlled by the loginPage property of each individual site.
2. No access page, controlled by NoAccessUrl setting in web.config.

in any way, he won't be able the access the item as he used to in Sitecore 4 at SDN, even without the content.

This logic is baked in the ExecuteRequest processor in httpRequestBegin pipeline. It’s not easy to change it though (I've moved the explanation to the end of the post to avoid clutter). And it's not a good idea to modify bunch of processors only to make things as they were before anyway. Two common requirements for scenarios when user is not allowed to access content he tries to are:

1. User is presented with a friendly message explaining what happened.
2. Along with the friendly message, user can login and see the page he's trying to access.

Login page supports both:

1. Create a new item, and allow 'read' for everyone. Locate your site in the <sites> section of web.config, and set a loginPage property:
<sites>
  <website loginPage="/home/login.aspx" .. />
</sites>


This item will probably have the default layout of the site, but instead of the content rendering it should have a 'login rendering' explaining that a user has to login to access the item.

2. When redirecting to login page, Sitecore will fill two query string parameters: 'item' and 'login'. This solves the last requirement - how to redirect user back to the requested item.

I've made a little class to handle this for sdn/spn sites, here's how it can be used:

DomainAccessResult result = new LoginManager().Login(emailTextBox.Value, passwordTextBox.Value);


It performs the usual Sitecore.Context.Domain.Login() and
a) redirects user back to the requested item if any
b) redirects user to 'login failed page' if it’s specified either in web.config or class property.

download link: LoginManager.cs

--
If you allow all users to see restricted pages and allow ItemResolver processor (earlier in the same pipeline) to set the Sitecore.Context.Item property - you're creating a possible security hole. Renderings do not perform explicit permission check every time they need to output some content - having the Sitecore.Context.Item set is enough to know that the item meets all criteria and can be shown.

The other option is to leave standard ItemResolver processor but still modify ExecuteRequest: this way user will be redirected to layout but Sitecore.Context.item will remain null. Security is ok this way, but because context item is not set Sitecore layout engine has no clue which item user wanted to access (and wasn't able to) - therefore it cannot decide (among other things) whether it should show the login rendering or not.

Wednesday, December 21, 2005 1:00:57 PM (FLE Standard Time, UTC+02:00)  #    Comments [0] -
Sitecore | Security | Upgrading to Sitecore 5
 Monday, November 07, 2005

Handy Sitecore.Contex is thread-local storage, so as soon as leave you leave sweet and warm asp.net request thread, you need to set it up for yourself. Fortunately, it is an easy task: you should pass a Sitecore site name to your child thread  (available as Sitecore.Site.Name in the parent thread if you want to execute in the same site context), and then do a Sitecore.Context.SetActiveSite(aSiteName).

Optionally you might choose to either switch the security checks off
  Sitecore.Context.Security.EnterState(SecurityState.Disabled)
or leave the security intact, pass a user name or id to your thread and do a
  UserItem user = Sitecore.Context.Domain.GetUser(aUserName);
 Sitecore.Context.Security.EnterUser(user);

Sites are setup in <sites> section of the web.config file, so if you want your thread to execute in specific context with its own settings (own database, perhaps) - set up another site in web.config and use its name instead.

Setting up context when you spawn a new thread is rather important - even if you don't use it directly, most of the higher-level API does.
Monday, November 07, 2005 11:23:40 AM (FLE Standard Time, UTC+02:00)  #    Comments [0] -
Sitecore | Security
Archive
<November 2008>
SunMonTueWedThuFriSat
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456
Blogroll
 Alex de Groot
Few words about SiteCore from Holland
 Alexander Shyba
Sitecore Support
 Anders Dreyer
Anders Dreyer on Sitecore Development
 Jakob Christensen
Sitecore Core Development
 Lars Fløe Nielsen
Lars's ramblings about development and business processes
 Ole Thrane
Sitecore API
 Runi Thomsen
Runi Thomsen Sitecore Toughts
 The Sitecore Experience
The Sitecore Experience
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2008
Alexey Rusakov
Sign In
Statistics
Total Posts: 199
This Year: 49
This Month: 3
This Week: 0
Comments: 0
Themes
Pick a theme:
All Content © 2008, Alexey Rusakov
DasBlog theme 'Business' created by Christoph De Baene (delarou)