Showing posts with label Sitecore. Show all posts
Showing posts with label Sitecore. Show all posts

Sitecore Language Fallback

Finally, Sitecore v. 8.1 support Language fallback out of the box.

The language fallback supports both at Item level and at field level and supports a chained fallback mode, where languages can fall back multiple times based on the associated langauges versions.

How does it work
The language fallback allows a developer to specify a default fallback language (for each of the language setting item in Sitecore) to use, when a visitor at the website request content that have not been created for the requested language version.

Template level
The “Tempalte Item” contains two new checkboks fields for handling the fallback language at item-level. The first checkbox “Enable Item Fallback” managing whether to use the fallback language, if the current item has no language version created for the requested language. The second checkbox “Enforce Version Presence” controls whether Sitecore should treat the specific item as non-existent, if the specific item has no versions created at the requested language.


Template Field level
The “Template Field Item” contains two new checkbox fields for handling the fallback language at field level, both placed at the “Data” field section. The first checkbox field “Enable Versioned Language Fallback” enables field-level fallback for only the current language version of the specific field. The second checkbox field “Enable Shared Language Fallback” enables the field-level fallback for the specific field in all languages. 


Specify the fallback language
To specify a fallback language for a specific language, Sitecore has added a field at the Language Setting Item in Sitecore (placed at: Sitecore/system/Languages/) called “Fallback Langauge”. If none is selected, the language has no fallback language. 

Enabling the fallback language features
Sitecore has added a new config file handling the language fallback settings. It is located at /App_Config/Sitecore.LangauageFallback.config. By default, the fallback language feature is disabled. To enable the fallback language, open the config file, find the two new site attributes, “enableItemLanguageFallback” and “EnableFieldLanguageFallback” respectively and set the attribute value to “true” (notice, the fallback feature is site specific):

<!-- ENABLE ITEM AND LANGUAGE FALLBACK PER SITE
         Using attribute patching below you can pick which fallback mode to enable (item-level or field-level or both) for each site 
         Consult official documentation on how to enable fallback feature in complex multi-site environments.
    -->
    <sites>
      <site name="shell">
        <patch:attribute name="enableItemLanguageFallback">false</patch:attribute>
        <patch:attribute name="enableFieldLanguageFallback">false</patch:attribute>
      </site>
      <site name="website">
        <patch:attribute name="enableItemLanguageFallback">true</patch:attribute>
        <patch:attribute name="enableFieldLanguageFallback">true</patch:attribute>
      </site>
    </sites>

Alphanumeric Characters in "Generate New Password" - Sitecore

A couple of month ago, a customer asked me to change the way Sitecore normally handles the “Generate new password” in the Security Manager. Change it so it only use alphanumeric Characters. I tried convincing the customer not to do so, but I failed …

To change the “Generate new password” in the Security Manager you only need to follow these 5 steps:
  1. Create your own GeneratePassword().It should do exactly the same as System.Web.Security.SqlMembershipProvider.GeneratePassword(), but instead of using modulo 87 (line number 39), it should use modulo 62 or 87 depending on whether to use alphanumeric characters or nonalphanumeric characters, respectively (it will make sense later in this post).
  2. Create your own SqlMembershipProvider and let it inherit from System.Web.Security.SqlMembershipProvider. The only thing this provider should do is to return your own GeneratePassword() (from step 1) instead of returning from System.Web.Security.Membership.GenereatePassword().
  3. In the web.config fil, add your new SqlMembershipProvider (from step 2) into .
  4. In the web.config file, change the SitecoreMembershipProvider to use your own provider (from step 3) instead of Sitecore.Security.SitecoreMembershipProvider
  5. Test the Generate New Password from the Security Manager in Sitecore Desktop

Create your own GeneratePassword()

Your own GeneratePassword() should do almost the same as the System.Web.Security.Membership.GeneratePassword(). But, instead of using modulo 87 you should use modulo 62 in the case, where only alphanumeric characters should be used. This is done where the “int num2” is initiated (you will find the full code in the end of this post).
 

NOTE: Making it work, you should also add the following five methods from the System.Web.Security.Membership (you find the code in the bottom of this post):
  1. Private static char[] punctations
  2. Private static bool IsAtoZ(char c)
  3. Internal static bool IsDangerousUrl(string s)
  4. Private static char[] stratingChars = new char[]
  5. Internal static bool IsDangerousString(strings, out int matchIndex


Override the System.Web.Security.SqlMembershipProvider.GeneratePassword()

Your own SQLMembershipProvider should inherit from System.Web.Security.SqlMembershipProvider and only overriding the public string GeneratePassword() to return your own GeneratePassword() method.



Add your own SQLMembershipProvider in the web.config file

In the web.config file navigate to section and add the new provider. Let all the settings be as the original SQL provider, but changing the use of System.Web.Security.SqlMembershipProvider to your own MyProject.Security.MembershipExtensions.MySQLMembershipProvider. 

Instead of adding a new attribute defining whether to use alphanumeric or non alphanumeric characters, I let the [minRequiredNonalphanumericCharacters] do the trick. If this attribute is equal to zero only alphanumeric characters will be used, if greater than zero – the number of non alphanumeric characters will respect the specified number.



Change the SitecoreMembershipProvider to use your own

Changing the SitecoreeMembershipProvider to use your own SQL provider is a simple task. Navigate to the section in the web.config file and change the existing Sitecore provider to use your own.


Test the Generate New Password

Verify that the Generate New Password only uses alphanumeric characters if the [minRequiredNonalphanumericCharacters] is set to “0” and the use of non alphanumeric characters if the [minRequiredNonalphanumericCharacters] is set to greater than 0



The Code:

Create your own GeneratePassword()


 
using System;
using System.Security.Cryptography;

namespace MyProject.Security.MembershipExtensions
{
 public static class MyMembership
 {
  
  public static string GeneratePassword(int length, int numberOfNonAlphanumericCharacters)
  {
   if (length < 1 || length > 128)
   {
    throw new ArgumentException("Membership_password_length_incorrect");
   }
   if (numberOfNonAlphanumericCharacters > length || numberOfNonAlphanumericCharacters < 0)
   {
    throw new ArgumentException("Membership_min_required_non_alphanumeric_characters_incorrect");
   }
   string text;
   int num4;
   do
   {
    byte[] array = new byte[length];
    char[] array2 = new char[length];
    int num = 0;
    new RNGCryptoServiceProvider().GetBytes(array);

    //Start: Added to change the standard behavior
                int numModulo = 87;
                if (numberOfNonAlphanumericCharacters == 0)
                {
                    numModulo = 62;
                }
                //End: Added to change the standard behavior
 
       for (int i = 0; i < length; i++)
    {
     //int num2 = (int)(array[i] % 87);
                    int num2 = (int)(array[i] % numModulo);
     if (num2 < 10)
     {
      array2[i] = (char)(48 + num2);
     }
     else
     {
      if (num2 < 36)
      {
       array2[i] = (char)(65 + num2 - 10);
      }
      else
      {
       if (num2 < 62)
       {
        array2[i] = (char)(97 + num2 - 36);
       }
       else
       {
        array2[i] = AlphanumericCharacters[num2 - 62];
        num++;
       }
      }
     }
    }
    if (num < numberOfNonAlphanumericCharacters)
    {
     Random random = new Random();
     for (int j = 0; j < numberOfNonAlphanumericCharacters - num; j++)
     {
      int num3;
      do
      {
       num3 = random.Next(0, length);
      } while (!char.IsLetterOrDigit(array2[num3]));
 
      array2[num3] = punctuations[random.Next(0, punctuations.Length)];
     }
    }
    text = new string(array2);
   } while (IsDangerousString(text, out num4));
   return text;
 }
 private static char[] punctuations = "!@#$%^&*()_-+=[{]};:>|./?".ToCharArray();

  private static bool IsAtoZ(char c)
  {
   return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
  }
 
  internal static bool IsDangerousUrl(string s)
  {
   if (string.IsNullOrEmpty(s))
   {
    return false;
   }
   s = s.Trim();
   int length = s.Length;
   if (length > 4 && (s[0] == 'h' || s[0] == 'H') && (s[1] == 't' || s[1] == 'T') &&
    (s[2] == 't' || s[2] == 'T') && (s[3] == 'p' || s[3] == 'P') &&
    (s[4] == ':' || (length > 5 && (s[4] == 's' || s[4] == 'S') && s[5] == ':')))
   {
    return false;
   }
   int num = s.IndexOf(':');
   return num != -1;
  }
 
  private static char[] startingChars = new char[]
              {
               '<',
               '&'
              };
 
  internal static bool IsDangerousString(string s, out int matchIndex)
  {
   matchIndex = 0;
   int startIndex = 0;
   while (true)
   {
    int num = s.IndexOfAny(startingChars, startIndex);
 
    if (num < 0)
    {
     break;
    }
    if (num == s.Length - 1)
    {
     return false;
    }
    matchIndex = num;
    char c = s[num];
    if (c != '&')
    {
     if (c == '<' && (IsAtoZ(s[num + 1]) || s[num + 1] == '!' || s[num + 1] == '/' || s[num + 1] == '?'))
     {
      return true;
     }
    }
    else
    {
     if (s[num + 1] == '#')
     {
      return true;
     }
    }
    startIndex = num + 1;
   }
   return false;
  }
 }


Overriding the System.Web.Security.SqlMembershipProvider.GeneratePassword


 
namespace MyProject.Security.MembershipExtensions
{
 internal class MySQLMembershipProvider : System.Web.Security.SqlMembershipProvider
 {
  public override string GeneratePassword()
  {
               return MyMembership.GeneratePassword(
                    (this.MinRequiredPasswordLength < 14) ? 14 : this.MinRequiredPasswordLength,
                    this.MinRequiredNonAlphanumericCharacters);
  }
 }
}





Auto remove language content

You remember from the SCD1 trainings that if you delete a language in Sitecore, you will also delete the content at the deleted language. Though, it is possible to maintain the content at the deleted language - and if you afterwards add the deleted language, Sitecore will replace the content into the language. How to do so - simply change the value attribute from true to false... more to come...


< !-- AUTO REMOVE ITEM DATA Indicates if item data is automatically removed from a database when a language is deleted. Default value: true -->
<setting name="Languages.AutoRemoveItemData" value="false" />

I DoRender or Render, I Do?

When creating webcontrols, you will be able to use the Render() or DoRender() method. Both methods will work and output value from the webcontrol. But in the case of Sitecore webcontrols, when using the Render method, it would bypass important Sitecore pipelines, so it would have a negative result on the implementation. Therefore, always use (override) the DoRender() method if you are creating Sitecore webcontrols...

More to come... (I hope)

Check In and Check Out

I'm often asked to remove the edit command. Most of the costumers doesn't find it useful - Especially if the costumer only have a few content authors. Well knowing the the power of the Editing command, still it is straight forward to remove/disable the "required lock before editing".

What you have to do is to change the "value" attribute from "true" to "false" in the "RequireLockBeforeEditing" setting in the Web.Config; Illustrated below.

< !-- REQUIRE LOCK BEFORE EDITING If true, the user must have a lock on a document before he can edit it, otherwise it is always ready for editing -->
<setting
name="RequireLockBeforeEditing" value="false" />

Sitecore

This is only a test