Sitecore Security: Roles in Roles – What it is and how it works

The Sitecore Roles-In-Roles is an extension to the basic authorization that have been around ever since Sitecore 5.

WHAT IS ROLES-IN-ROLES?

Roles-In-Roles allows you to have nested roles, so when you add a role to a user, the user is granted that role, including all the nested roles.

WHY ROLES-IN-ROLES?

The roles in Sitecore does not only grant access to content, but also to functions, such as publishing, account managing, translating etc. In an attempt to simplify the process of granting authors access to content AND functions, the idea of embedding function roles into one access role was born.
So with roles-in-roles you can create a super-role that grants access to content and functions at the same time.

WHERE DOES SITECORE STORE ROLES IN ROLES?

In the sitecore.config you will  find the rolesInRolesManager configuration setting that points to the database where the rolesinroles table is defined.

<rolesInRolesManager defaultProvider="sql" enabled="true">
  <providers>
    <clear />
    <add name="sql" type="Sitecore.Security.Accounts.SqlServerRolesInRolesProvider, Sitecore.Kernel" connectionStringName="core" rolesInRolesSupported="true" globalRolesConfigStoreName="globalRoles" raiseEvents="true" />
  </providers>
</rolesInRolesManager>

HOW DOES IT WORK?

Look at the “Developer” roles in the Roles Manager:

Roles Manager

Roles Manager

If you click the “Member Of” button you will see all the roles that is embedded into the “Developer” roles:

Roles Manager - Member Of

Roles Manager – Member Of

That means that when my user is granted the “Developer” role:

User Manager - Select Roles

User Manager – Select Roles

The user will automatically be granted the “Developer” roles, plus any embedded roles within the “Developer” role. Also, if any roles inside the “Developer” role has embedded roles, these roles are also included.

User Manager - Roles

User Manager – Roles

MORE TO READ:

Advertisements
Posted in Sitecore 5, Sitecore 6, Sitecore 7, Sitecore 8, Sitecore 9 | Tagged , , , , | 1 Comment

Azure Application Insights – Multiple services from same server

This trick enables you to have multiple services from the same server log to the same Application Insights instance, and at the same time distinguish between each service.

Application Insights

Application Insights Telemetry data

In the example above, I have 2 services from the same server. Each service have their own instance name. The @LTBP is a web server, and the @CloudDataloggerV1 is a windows console application.

To do this, you need to add a new TelemetryInitializer that sets the RoleInstance name.

STEP 1: CREATE NEW TELEMETRYINITIALIZER

This simple class adds the name of my service to the RoleInstance property:

internal class CloudRoleNameInitializer : ITelemetryInitializer
{
  private readonly string _roleName;

  public CloudRoleNameInitializer()
  {
    _roleName = "CloudDataLoggerV1";
  }

  public void Initialize(Microsoft.ApplicationInsights.Channel.ITelemetry telemetry)
  {
    telemetry.Context.Cloud.RoleInstance = _roleName;
  }
}

STEP 2: ADD THE TELEMETRYINITIALIZER TO THE APPLICATIONINSIGHTS INSTANCE

You can now add the CloudRoleNameInitializer to your ApplicationInsights initializing code. This example is taken from the console application’s setup code:

public static class ApplicationInsights
{
  private static TelemetryClient _telemetryClient;

  public static void Initialize()
  {
    TelemetryConfiguration configuration = TelemetryConfiguration.Active;
    configuration.InstrumentationKey = Settings.ApplicationInsights.InstrumentationKey;
    configuration.TelemetryInitializers.Add(new CloudRoleNameInitializer());
    QuickPulseTelemetryProcessor processor = null;
    configuration.TelemetryProcessorChainBuilder
      .Use((next) =>
      {
        processor = new QuickPulseTelemetryProcessor(next);
        return processor;
      })
      .Build();

    var QuickPulse = new QuickPulseTelemetryModule();
    QuickPulse.Initialize(configuration);
    QuickPulse.RegisterTelemetryProcessor(processor);

    _telemetryClient = new TelemetryClient(configuration);
    Telemetry = _telemetryClient;
  }
  public static TelemetryClient Telemetry { get; private set; }

}

MORE TO READ:

 

Posted in c#, General .NET, Microsoft Azure | Tagged , | Leave a comment

c# Async fire and forget

Often in application development you want a process to call another thread and continue the process flow, without waiting for a response from the called thread. This pattern is called the “fire and forget” pattern.

I myself are oblivious to async coding, but these methods have proven to be functioning in very large scale systems.

THE OLD WAY: USING THREADPOOL 

The System.Threading.ThreadPool method have been around since .NET 1.0. The threadpool is a pool of threads that are available for you to use. The QueueUserWorkItem puts the method into a queue and executes the method when there is an available thread.

Please note that when the async method is called, the parameter is converted into an object, and you need to cast it back to the strong type before you can work with it:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace MyNamespace
{
  public class MessageData
  {
    public string UserName { get; set; }
    public string IpAddress { get; set; }
    public string UserAgent { get; set; }
  }

  public class MyService
  {
    public static void DoWork(MessageData messageData)
    {
      ThreadPool.QueueUserWorkItem(new MyService().DoWorkAsync, messageData);
    }

    private void DoWorkAsync(object context)
    {
      try
      {
        MessageData messageData = (MessageData)context;        
        // Do stuff with the messageData object
      }
      catch (Exception ex)
      {
        // Remember that the Async code needs to handle its own
        // exceptions, as the "DoWork" method will never fail
      }
    }
  }
}

THE NEW WAY: TASK.FACTORY.STARTNEW

The Task class was introduced in .NET 4.something and is part of the new async/await keywords that makes async coding easier. The Task.Factory.StartNew() basically does the same as the TreadPool.QueueUserWorkItem but works with strong types:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace MyNamespace
{
  public class MessageData
  {
    public string UserName { get; set; }
    public string IpAddress { get; set; }
    public string UserAgent { get; set; }
  }

  public class MyService
  {
    public static void DoWork(MessageData messageData)
    {
      Task.Factory.StartNew(() => DoWorkAsync(messageData));
    }

    private void DoWorkAsync(MessageData messageData)
    {
      try
      {
        // Do stuff with the messageData object
      }
      catch (Exception ex)
      {
        // Remember that the Async code needs to handle its own
        // exceptions, as the "DoWork" method will never fail
      }
    }
  }
}

MORE TO READ:

 

Posted in .net, c#, General .NET | Tagged , , | Leave a comment

Sitecore check access and roles programatically

The Sitecore security model have changed over time, but the general API to check security access and roles have been stable for many many years.

CHECK IF USER HAS ACCESS TO AN ITEM:

To check if a user have access to a Sitecore item:

// Get Sitecore item
var item = Sitecore.Context.Database.GetItem("/sitecore/content/home/item");

// Check if the current context user 
// have read access to the item
bool canRead = item.Access.CanRead();

// Check if a named user have read access
// to an item
using (new Sitecore.Security.Accounts.UserSwitcher(@"extranet\username", true))
{
  bool canRead = item.Access.CanRead();
}

CHECK IF USER HAVE A CERTAIN ROLE:

The Sitecore User object has a Roles property, but this property does only list the immediate roles, not the roles obtained from roles-in-roles. To check for all roles, you need to use the IsInRole property:

using Sitecore.Security.Accounts;

// Get the role to check
// Remember to prefix the role name with 
// the domain name
Role role = Role.FromName(@"extranet\rolename");

// Check if user have the role
var isInRole = Sitecore.Context.User.IsInRole(role);

MORE TO READ:

Posted in .net, c#, General .NET, Sitecore 6, Sitecore 7, Sitecore 8, Sitecore 9 | Tagged , , , | 1 Comment

Sitecore 9 Caching – Sitecore.Caching.CacheManager.GetAllCaches() changed from Sitecore 8

With the increased use of dependency injection, in Sitecore, some classes do no longer return concrete classes, but interfaces instead. You therefore need to change your code, if you use the Sitecore.Caching.CacheManager. The Sitecore.Caching.Cache class is retired and have been replaced with Sitecore.Caching.ICacheInfo.

GET A LIST OF ALL CACHES:

// Get all caches, Sitecore 8
IEnumerable<Sitecore.Caching.Cache> Caches
{
  get
  {
    return CacheManager.GetAllCaches().OrderBy(c => c.Name);
  }
}


// Get all caches, Sitecore 9
IEnumerable<Sitecore.Caching.ICacheInfo> Caches
{
  get
  {
    return CacheManager.GetAllCaches().OrderBy(c => c.Name);
  }
}

CLEAR ONE CACHE ONLY:

If you wish to clear one cache only, you can no longer call Sitecore.Caching.CacheManager.FindCacheByName(cacheName), as this method is deprecated, and will result in an exception being thrown:

Unable to cast object of type ‘Sitecore.Caching.Generics.Cache`1[Sitecore.Caching.AccessResultCacheKey]’ to type ‘Sitecore.Caching.Generics.ICache`1[System.String]’.

Instead, iterate the GetAllCaches() collection and find the cache to clear:

// Calling the method from above to find a ICacheInfo object,
// then call the Clear() method
var cache = Caches.SingleOrDefault(c => c.Name == cacheName);
cache.Clear();

MORE TO READ:

Posted in Sitecore 8, Sitecore 9 | Tagged , , | Leave a comment

Solr delete document using UI and querystring

How do you delete a document from Solr?

You can use query string parameters to do the delete:

https://[server]:8983/solr/[core]/update?commit=true&stream.body=<delete><query>[query]</query></delete>
  • server: The name of your Solr server
  • core: The name of the Solr core (the Solr index) to delete from
  • query: The Solr query returning the document to delete

Example:

https://localhost:8983/solr/sitecore_master_index/update?commit=true&stream.body=<delete><query>_group:b74d1721779538ddb695afe69ce5f461</query></delete>

MORE TO READ:

Posted in General .NET | Tagged | Leave a comment

Sitecore 9 Dependency Injection – Extend the Sitecore Logging

With the extended use of Dependency Injection (DI) in Sitecore 9, you have yet another tool to extend the Sitecore functionality. With DI you can basically replace or extend standard Sitecore functionality with your own code.

Dependency Injection is not a replacement for Sitecore Pipelines, but a supplement.

Behold the following case: Replacing the Sitecore.Diagnostics.Log with your own implementation. In this case I will replace the Sitecore.Diagnostics.DefaultLog with my own implementation.

STEP 1: REGISTER THE NEW LOG CLASS

The Sitecore.Diagnostics.DefaultLog inherits from Sitecore.Abstractions.BaseLog, so my ServicesConfigurator needs to register a new class for that:

using Microsoft.Extensions.DependencyInjection;
using Sitecore.DependencyInjection;

namespace MyCode
{
  public class ServicesConfigurator : IServicesConfigurator
  {
    public void Configure(IServiceCollection serviceCollection)
    {
      serviceCollection.AddTransient(typeof(Sitecore.Abstractions.BaseLog), typeof(MyCode.MyLog));
    }
  }
}

The ServicesConfigurator must be registered in Sitecore using a .config file. Make sure your config file is adding your section later than Sitecore. he who registers last, have the DI registration:

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:env="http://www.sitecore.net/xmlconfig/env/">
  <sitecore>
    <services>
      <configurator type="MyCode.ServicesConfigurator, MyDll" />
    </services>
  </sitecore>
</configuration>

STEP 2: IMPLEMENT THE NEW LOG CLASS

That’s basically it.

Now I can replace Sitecore functionality by implementing a class that inherits from Sitecore.Abstractions.BaseLog:

using System;
using Sitecore.Caching;

namespace MyCode
{
  public class MyLog : Sitecore.Abstractions.BaseLog
  {
    public override void Audit(string message, string loggerName)
    {
      // Do something else
    }
	
	...
	...
	...
}

Or I can extend Sitecore functionality by inheriting from Sitecore.Diagnostics.DefaultLog:

using System;
using Sitecore.Diagnostics;

namespace MyCode
{
  public class MyLog: Sitecore.Diagnostics.DefaultLog
  {
    public override void Audit(string message, object owner)
    {
      // Adding the calling type to the message, thus extending the
	  // existing log messages
	  base.Audit(owner.GetType() + " " + message, owner);
    }

	...
	...
	...
  }
}

MORE TO READ:

Posted in .net, c#, General .NET, Sitecore 9 | Tagged , , , | Leave a comment

Sitecore The “placeholder” placeholder was not rendered in the “page” item

Do you get this error in Sitecore 9?

9952 2018:10:23 12:56:42 WARN The “xxxxx” placeholder was not rendered in the “xxxxx” item ({00000000-0000-0000-0000-000000000000}) rendering context.
Possible causes:​
1) Rendering markup was taken from HTML cache, thus no rendering process took place, and diagnostic message can be safely ignored;​
2) Rendering markup was not rendered due to no parent placeholder was found – item rendering settings should be checked;​
You can control the presence of these messages via ‘Rendering.TraceUnusedRenderings’ Sitecore Configuration setting.

Sitecore 9 have upped the tracing of invalid renderings to allow you to clean up the renderings placed in placeholders that do no longer exist. However if you prefer this message in the development environment and not in the production environment, you can mute the message with the following setting:

<setting name="Rendering.TraceUnusedRenderings" value="false" />

MORE TO READ:

Posted in Sitecore 9 | Tagged , , | Leave a comment

Sitecore 8.2 changed maxInvalidPasswordAttempts from 256 to 5

I noticed that some of my users got locked out of my solution after I upgraded from Sitecore 8.0 to Sitecore 9.0.

That’s because Sitecore have decided to change the default value of the membership maxInvalidPasswordAttempts property from 256 attempts to 5 attempts.

The change is effective from Sitecore 8.2 and is the new default value onwards.

The old settings:

<membership defaultProvider="sitecore" hashAlgorithmType="SHA1">
  <providers>
    ...
    <add name="sql" ... maxInvalidPasswordAttempts="256" />
  </providers>
</membership>

The new settings:

<membership defaultProvider="sitecore" hashAlgorithmType="SHA1">
  <providers>
    ...
    <add name="sql" ... maxInvalidPasswordAttempts="5" />
  </providers>
</membership>

MORE TO READ:

Posted in Sitecore 8, Sitecore 9 | Tagged , | 2 Comments

Using Notepad++ to mask email address for GDPR reasons

With the new GDPR rules enforced in Europe, shipping log files containing personal information (including email addresses) to 3rd parties are a no-go. Unless you have a signed controller/processor agreement of course, which no one has, as this gives them legal obligations in case of a security breach.

So always remember to mask your log files before allowing others to read them. You can use Notepad++ search and replace with regular expressions. Here is how to mask the email:

To go Replace (CTRL+H), switch mode to “Regular Expression” and:

  • Find: \b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b
  • Replace with: *****@*****.***

Like this:

Notepad++

Notepad++

MORE TO READ:

Posted in Uncategorized | Tagged , , , , | Leave a comment