IdentityServer use IdentityModel to get user token and user info

Using IdentityServer have been made easier with the IdentityModel helper library. The library implements extension methods that maps the input and output to classes.

GET ACCESS TOKEN:

Use the PasswordTokenRequest and RequestPasswordTokenAsync to get the access token. replace your_domain, your_clientid and your_secret with the values from your Identity Server:

using IdentityModel.Client;

public string LoginUsingIdentityServer(string username, string password)
{
  var client = new HttpClient();
  PasswordTokenRequest tokenRequest = new PasswordTokenRequest() 
  { 
    Address = "http://your_domain/connect/token",
    ClientId = "your_clientid",
    ClientSecret = "your_secret",
    UserName = username,
    Password = password
  };
  
  var response = client.RequestPasswordTokenAsync(tokenRequest).Result;
  if (!response.IsError)
  {
     response.AccessToken;
  }
  else
  {
    throw new Exception("Invalid username or password");
  }
}

GET USERINFO:

First you need to ensure that the Identity Resource in Identity Server can return the claims from the user (claims is the fancy word for properties). If you use the Identity Server Admin interface, you can choose OPENID from the Resources/Identity Resources menu and select the claims visually:

Identity Server Claims

Identity Server Claims

Use the UserInfoRequest and pass your access token to GetUserInfoAsync to get the user claims:

using IdentityModel.Client;
using Newtonsoft.Json;
using System.Collections;
using System.Net.Http;

public void GetUserInfo(string accessToken)
{
  var client = new HttpClient();
  var userInfoRequest = new UserInfoRequest()
  {
    Address = "http://your_server/connect/userinfo",
    Token = accessToken
  };

  var response = client.GetUserInfoAsync(userInfoRequest).Result;
  if (response.IsError)
    throw new Exception("Invalid accessToken");

  dynamic responseObject = JsonConvert.DeserializeObject(response.Raw);
  if (responseObject.given_name != null && responseObject.family_name != null)
  {
    // do something with the name
    string name = responseObject.given_name.ToString() 
	              + " " 
				  + responseObject.family_name.ToString();
    }

    // If there is one role, the role property is a string.
	// There there is more roles, the role property is an array
	// To handle this, I use this clumsy statement:
    if (responseObject.role.Type == Newtonsoft.Json.Linq.JTokenType.String)
	{
      // do something with the roles
	string role = responseObject.role.ToString();
	}	
    else
    {
      foreach (var role in responseObject.role)
      {
        // do something with the roles
        string role = role.ToString();
      }
    }
  }
}

FOR SITECORE USERS:

If you use Sitecore, you can create a Virtual User based on the user info, and log into Sitecore using this virtual user.

using IdentityModel.Client;
using Newtonsoft.Json;
using Sitecore.Security.Authentication;
using System.Collections;
using System.Net.Http;

namespace MyCode
{
  public class VirtualUserFactory
  {
    public static Sitecore.Security.Accounts.User Create(string identityServerAccessToken)
    {
      var client = new HttpClient();
      var userInfoRequest = new UserInfoRequest()
      {
        Address = "http://your_server/connect/userinfo",
        Token = identityServerAccessToken
      };

      var response = client.GetUserInfoAsync(userInfoRequest).Result;
      if (response.IsError)
        throw new Sitecore.Exceptions.AccessDeniedException();

      dynamic responseObject = JsonConvert.DeserializeObject(response.Raw);

      Sitecore.Security.Accounts.User virtualUser = AuthenticationManager.BuildVirtualUser("extranet\\" + responseObject.preferred_username.ToString(), true);

      if (responseObject.given_name != null && responseObject.family_name != null)
        virtualUser.Profile.FullName = responseObject.given_name.ToString() + " " + responseObject.family_name.ToString();

      if (responseObject.email != null)
        virtualUser.Profile.Email = responseObject.email.ToString();

      if (responseObject.role.Type == Newtonsoft.Json.Linq.JTokenType.String)
        virtualUser.Roles.Add(Sitecore.Security.Accounts.Role.FromName(responseObject.role.ToString()));
      else
      {
        foreach (var role in responseObject.role)
        {
          virtualUser.Roles.Add(Sitecore.Security.Accounts.Role.FromName(role.ToString()));
        }
      }

      if (responseObject.sub != null)
        virtualUser.Profile.ProfileItemId = responseObject.sub.ToString();

      return virtualUser;
    }
  }
}

Logging into Sitecore uisng a virtual user is simple:

// Login the virtual user
Sitecore.Security.Authentication.AuthenticationManager.LoginVirtualUser(virtualUser);

MORE TO READ:

Advertisements
Posted in .net, .NET Core, c#, General .NET, Sitecore 6, Sitecore 7, Sitecore 8, Sitecore 9 | Tagged , , , , | Leave a comment

Sitecore use Application Insights Metrics and Telemetry

Although Sitecore have an integration for Application Insights (which is part of Azure Monitor), you can implement the TelemetryClient yourself. This is useful if you wish to log Metrics or Trace your own code, without involving the complete Sitecore solution. There is no need for configuration changes if all you want is to get some metrics for your own subsystem within Sitecore.

Application Insights is very easy to work with. First you need to install the Microsoft.ApplicationInsights NuGet Package.

In order to use Application Insights you must create a TelemetryClient:

using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.Extensibility;

namespace MyCode
{
  public static class TelemetryFactory
  {
    /// <summary>
    /// Create a new TelemetryClient
    /// </summary>
    /// <param name="instrumentationKey">The Application Insights key</param>
    /// <param name="roleInstance">The name of your instance</param>
    /// <param name="roleName">The name of your role</param>
    /// <returns></returns>
    public static TelemetryClient GetTelemetryClient(string instrumentationKey, string roleInstance, string roleName)
    {
      var telemetryConfiguration = new TelemetryConfiguration {InstrumentationKey = instrumentationKey};
      telemetryConfiguration.TelemetryInitializers.Add(new OperationCorrelationTelemetryInitializer());
      telemetryConfiguration.TelemetryInitializers.Add(new CloudRoleInitializer(roleInstance, roleName));
      return new TelemetryClient(telemetryConfiguration);
    }
  }
}

With the TelemetryClient in hand, it’s easy to track metrics:

TelemetryClient _telemetryClient = 
  TelemetryFactory.GetTelemetryClient("my-key", "Application Name", "Application Name");

_telemetryClient.GetMetric(
  new MetricIdentifier("MySystem", $"Deleted Users")
).TrackValue(1);

The tracked telemetry will appear in Application Insights shortly after:

Application Insights Metrics

Application Insights Metrics

If you wish to log traces, it is equally easy:

var trace = new TraceTelemetry
{
  SeverityLevel = SeverityLevel.Information,
  Message = $"xxx Deleted User xxx"
};

_telemetryClient.TrackTrace(trace);

The traces appear as log lines in Application Insights:

Application Insights Trace

Application Insights Trace

MORE TO READ:

Posted in .net, c#, Microsoft Azure, Sitecore 7, Sitecore 8, Sitecore 9 | Tagged , , | Leave a comment

Sitecore logging – Create new log file every day

Sitecore have since forever used Log4Net as it’s logging platform. Log4Net is nicely extensible and can be configured to log in many ways.

As per default, Sitecore is configured to start writing to a new log file every time Sitecore starts. And (in some versions of Sitecore) it will continue to write to that file until you restart Sitecore.

You can change that configuration. This configuration will create one and only one log file per day, even if the instance is restarted several times, or never:

<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
    <file value="$(dataFolder)/logs/log" patch:instead="file" />
    <rollingStyle value="Date" patch:instead="rollingStyle" />
    <preserveLogFileNameExtension value="true" patch:instead="preserveLogFileNameExtension" />
    <datePattern value="'.'yyyyMMdd'.txt'" patch:instead="datePattern" />
    <staticLogFileName value="false" patch:instead="staticLogFileName" />
</appender>

Differences from standard Sitecore configuration are:

  • rollingStyle have been changed from Size to Date.
  • The folder name and file date pattern is now split. Property “file” contains the folder and file prefix, and the datePattern property contains the file suffix.
  • staticLogFileName is false, allowing Log4Net to use the datePattern property as file name.

When the configuration is added to a logging.config file, the resulting merge is this:

<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender" patch:source="logging.config">
    <file value="$(dataFolder)/logs/log" patch:source="logging.config"/>
    <appendToFile value="true" patch:source="logging.config"/>
    <rollingStyle value="Date" patch:source="logging.config"/>
    <maxSizeRollBackups value="-1"/>
    <maximumFileSize value="10MB"/>
    <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%4t %d{ABSOLUTE} %-5p %m%n"/>
    </layout>
    <encoding value="utf-8" patch:source="logging.config"/>
    <preserveLogFileNameExtension value="true" patch:source="logging.config"/>
    <staticLogFileName value="false" patch:source="logging.config"/>
    <datePattern value="'.'yyyyMMdd'.txt'" patch:source="logging.config"/>
</appender>

MORE TO READ:

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

Sitecore remove “Job started” and “Job ended” from log files

In large Sitecore installations with many background tasks you will find the following log lines over and over again:

ManagedPoolThread #1 10:26:05 INFO  Job started: xxxxx
ManagedPoolThread #5 10:26:05 INFO  Job ended: xxxxx (units processed: )

This is the Sitecore Agents that write this line by default. You can disable the logging for each running agent by setting the “LogActivity” property to FALSE:

<agent type="Sitecore.Tasks.UrlAgent" method="Run" interval="00:15:00">
  <param desc="url">/sitecore/service/keepalive.aspx</param>
  <LogActivity>false</LogActivity>
</agent>

If you would like to know when your own tasks have been run by an agent, simply add a log line when your code starts:

Log.Info(string.Format("Task started: [taskname]", this);

Please note that you cannot disable all “Job started” log lines in one place, you need to disable them for each agent. You will find agents in the following config files:

  • Sitecore.config
    Sitecore.Tasks.UrlAgent
    Sitecore.Tasks.TaskDatabaseAgent
    and more…
  • Sitecore.Diagnostics.config
    Sitecore.Tasks.CleanupAgent
  • Sitecore.Processing.config
    Sitecore.Tasks.DatabaseAgent
  • Sitecore.WebDAV.config
    Sitecore.Tasks.CleanupFDAObsoleteMediaData, Sitecore.Tasks.WebDAVOptionsCleanupAgent
  • Sitecore.ContentSearch.config
    Sitecore.ContentSearch.Tasks.Optimize
  • Sitecore.ContentSearch.Solr.DefaultIndexConfiguration.config
    Sitecore.ContentSearch.SolrProvider.Agents.IsSolrAliveAgent
    Sitecore.ContentSearch.SolrProvider.Agents.IndexingStateSwitcher
  • Sitecore.ContentTesting.config
    Sitecore.Tasks.CleanupAgent
  • Sitecore.EDS.Providers.CustomSMTP.config
    Sitecore.EDS.Providers.CustomSmtp.Tasks.ConnectionPoolAgent
  • Sitecore.EDS.Providers.CustomSMTP.Sync.config
    Sitecore.EDS.Providers.CustomSmtp.Tasks.PullPop3BouncesAgent
  • Sitecore.EDS.Providers.SparkPost.Sync.config
    Sitecore.EDS.Providers.SparkPost.Tasks.SuppressionSyncAgent
    Sitecore.EDS.Providers.SparkPost.Tasks.PullBouncesAgent
    Sitecore.EDS.Providers.SparkPost.Tasks.PullComplaintsAgent
    Sitecore.EDS.Providers.SparkPost.Tasks.ConnectionPoolAgent
  • Sitecore.EmailExperience.ContentManagementPrimary.config
    Sitecore.Tasks.DatabaseAgent
  • Sitecore.ListManagement.config
    Sitecore.ListManagement.Operations.UpdateListOperationsAgent
  • Sitecore.PathAnalyzer.Client.config
    Sitecore.PathAnalyzer.Client.Tasks.HelpUpdateAgent
    Sitecore.PathAnalyzer.Client.Tasks.HelpUpdateAgent

As an untested side note, Log4Net contains filters that should deny certain string patterns. Adding the following to the LogFileAppender in the Sitecore.config file should remove all lines containing “Job started:” and “Job ended:“:

<filter type="log4net.Filter.StringMatchFilter">
  <stringToMatch value="Job started:" />
  <acceptOnMatch value="false" />
</filter>
<filter type="log4net.Filter.StringMatchFilter">
  <stringToMatch value="Job ended:" />
  <acceptOnMatch value="false" />
</filter>

MORE TO READ:

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

200 OK vs 202 Accepted – Whats the difference?

When working with Azure cloud services like Azure Logic Apps or Azure Automation (Runbooks), you often come across that service endpoints return 202 Accepted instead of 200 OK on success. But why do they do that, and what is the difference between the two?

202 Accepted

202 Accepted

200 OK means that the request has succeeded and the processing of our request is done. The response is the final payload and the service will not take further actions.

202 Accepted on the other hand means that the request have been accepted for processing, and the service will now start. This does not mean that the processing itself is a success, nor that the process have ended.

The 202 accepted is therefor the equivalent of a fire-and-forget, and all you know is that the fire was a success. With 200 OK you should expect the processing not only to be done but also be successful.

MORE TO READ:

Posted in General .NET | Leave a comment

Change date format using .NET Regular Expressions

You can use Regex.Replace to change the format of a date string. For example if your input string is YYYY/MM/DD but you need to change it to YYYY-MM-DD, you can use this small method:

public static string ReformatDate(string input) 
{
   try {
      return Regex.Replace(input, 
            "\\b(?<year>\\d{2,4})/(?<month>\\d{1,2})/(?<day>\\d{1,2})\\b",
            "${year}-${month}-${day}", 
            RegexOptions.IgnoreCase,
            TimeSpan.FromMilliseconds(1000));
   }         
   catch (RegexMatchTimeoutException) {
      return input;
   }
}

Regular expressions are unreadable as usual, but the trick here lies in the way the year, month and day parts are grabbed and stored in “variables” to be used in the replacement part of the Regex.Replace:

  • Pattern: (?\\d{2,4}) grabs 2-4 digits and places them in a variable called “year”. The same goes for month and day.
  • Replacement: ${year} places the value grabbed from the input and places it into the output of the replace function.

With this in mind we can create lots of different search/replace patters:

  • Input: DD/MM/YYYY Output: YYYY-MM-DD
    Pattern: \\b(?<day>\\d{1,2})/(??<month>\\d{1,2})/(??<year>\\d{2,4})\\b
    Replacement: ${year}-${month}-${day}
  • Input: YYYY-MM-DD Output: MM/DD/YYYY
    Patern: \\b(??<year>\\d{2,4})-(??<month>\\d{1,2})-(??<day>\\d{1,2})\\b
    Replacement: ${month}/${day}/${year}

Would you like to change multiple dates from your input? Add RegexOptions.Multiline to the options:

public static string ReformatDate(string input) 
{
   try {
      return Regex.Replace(input, 
            "\\b(?<year>\\d{2,4})/(?<month>\\d{1,2})/(?<day>\\d{1,2})\\b",
            "${year}-${month}-${day}", 
            RegexOptions.Multiline | RegexOptions.IgnoreCase,
            TimeSpan.FromMilliseconds(1000));
   }         
   catch (RegexMatchTimeoutException) {
      return input;
   }
}

Or how about changing dates from within an XML document?

<item>
 <start_date>2019/06/11</start_date>
 <expiration_date>2019/06/17</g:expiration_date>
</item>

Add the < > to the pattern and replacement variables:

public static string ReformatDate(string input) 
{
   try {
      return Regex.Replace(input, 
            ">\\b(?<year>\\d{2,4})/(?<month>\\d{1,2})/(?<day>\\d{1,2})\\b<", 
            ">${year}-${month}-${day}<", 
            RegexOptions.Multiline | RegexOptions.IgnoreCase,
            TimeSpan.FromMilliseconds(1000));
   }         
   catch (RegexMatchTimeoutException) {
      return input;
   }
}

MORE TO READ:

 

Posted in .net, .NET Core, c#, General .NET | Tagged , , | 1 Comment

Calling Azure Functions from JavaScript – The CORS configuration

You cannot call Azure Functions from JavaScript unless you configure the CORS settings for your Function Apps:

Azure Functions CORS Settings

Azure Functions CORS Settings

This is because Microsoft have by default enabled CORS and only allows only some azure domains to access the Function Apps:

Default CORS Settings

Default CORS Settings

So to enable access from your JavaScript you have to add your domain to the list of allowed origins.

If you wish to allow every domain to access your apps, you must remove all domains from the list and add a “*” to the list as the only entry:

Allow all

Allow all

However, this is widely regarded as a bad move, as all security is thrown out of the window. Azure Functions only security measurements are security tokens passed a parameters, and when calling the Azure Function from JavaScript, this token is exposed to the entire world. You should carefully consider the security implications before allowing every hacker access to your Azure Functions.

Happy coding!

MORE TO READ:

Posted in Microsoft Azure | Tagged , , | Leave a comment

Azure Functions CRON expressions

When creating Microsoft Azure Functions, you can have a timer that triggers your function. The time for when the function should run is specified in a CRON expression:

Microsoft Azure CRON Expression

Microsoft Azure CRON Expression

The CRON format is widely used in UNIX environments, so therefore a wide variety of CRON expression validators exist. Unfortunately most of these do not work on the Microsoft Azure version of CRON, as Microsoft decided to add “second” column and to support only a set of the expressions available.

WHICH CRON VALIDATOR DOES WORK?

http://cronexpressiondescriptor.azurewebsites.net/ by Brady Holt will work.

HOW DO YOU BUILD YOUR CRON EXPRESSION:

The expression is a string where each time specification is separated with a space:

{second} {minute} {hour} {day} {month} {day-of-week}

The CRON expression describes both the time when a timer is triggered AND the interval in between the triggers:

  • numbers = The time when a timer is triggered. For example “0” or “30”
  • number/number = The interval between the triggers. For example “0/1” or “*/1”
  • number-number = The exact interval between the triggers. For example “0-5”
  • A * = The asterisk is your “any” or “i don’t care” descriptor.

WHY IS THE EXPRESSION SO HARD TO UNDERSTAND?

Because the CRON expression both describes the time and the interval in one section, you need to understand the difference between the two:

  • “0” means that the section is run when the second/minute/hour/etc is 0.
  • “0/1” means that the section is run when the second/minute/hour/etc is 0 AND every 1 second/minute/hour/…
  • “*” and “*/1” means the same.
  • “0-1” means that the section is run within this interval.
  • Combinations are allowed: 0-12/1 means to run ever 1 between 0 and 12.

EXAMPLES:

0 * * * * * Once every minute, at xx:xx:00
0 0 * * * * Once every hour, at xx:00:00
0 0 0 * * * Once every day, at 00:00:00
0 0 0 0 * * Once every month at 00:00:00 on the first day of the month
0 0 5-7/1 * * * Every hour between 5 and 06:59. Notice this will run 2 times a day, not 3
0 0 0/6 * * * Every 6 hours, at xx:00:00 (00:00:00, 00:06:00, 00:12:00, 00:18:00)

MORE TO READ:

Posted in Microsoft Azure | Tagged , , , | Leave a comment

Sitecore Item Clones is only a thing in the master database

The Sitecore item cloning is a technique in which you can create a copy of an item that inherits the field values of the original items.

In the latest versions of Sitecore (at least from 9.0 and forward) you can ask if an item is a clone:

Database master = Database.GetDatabase("master");
Item item = master.GetItem(someGuid);
bool isClone = item.IsItemClone;

But please notice that the Item.IsItemClone will always return FALSE if you request the item from the WEB database:

Database web = Database.GetDatabase("web");
Item item = web.GetItem(someGuid);
// This value is always false
bool isClone = item.IsItemClone;

This is because the Source and __Source Item fields of an item are the fields on the original item that tells Sitecore that this item is cloned:

Clone from Master database

Clone from Master database

… is not copied to the WEB database when published:

Clone from Web database

Clone from Web database

This is by design. If you would like to know if an item is a clone (to avoid duplicate items in your sitemap, of when creating canonical URL’s, for example), you will need to code a solution yourself.

MORE TO READ:

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

Sitecore start scheduled task manually

Sitecore scheduled tasks are background tasks running on a schedule. But never when you need it, especially when developing the tasks. You can trigger these tasks manually if you please.

THE EASY WAY: INSTALL SITECORE POWERSHELL

The Sitecore PowerShell module have a built in task runner. When installed, you can right click the task you wish to run and click “Run Task Schedule

Powrshell Run Task

Powrshell Run Task

THE FUN WAY: PROGRAM YOUR OWN TASK STARTER:

You can, of course, write your own task runner, create a nice scheduled task page, and display all possible tasks where you can start them individually:

Scheduled Tasks List

Scheduled Tasks List

To get a list of all scheduled tasks:

private const string SCHEDULED_PATH = "/sitecore/system/Tasks//*[@@templatename='Schedule']";
  
foreach (Item item in Sitecore.Context.Database
  .SelectItems(SCHEDULED_PATH)
  .OrderBy(t => t.Parent.Name)
  .ThenBy(t => t.Name))
{
  ScheduleItem scheduleItem = new ScheduleItem(item);
  // Do stuff with the scheduleItem
}

To start a scheduled task:

Sitecore.Tasks.ScheduleItem scheduleItem = new Sitecore.Tasks.ScheduleItem(item);
scheduleItem.Execute();

MORE TO READ:

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