12 Nov 2013

N-Tier Application Architecture

Software application architecture is an interesting and broadly discussed topic. In this presentation, I am discussing N-Tier application architecture. Going to investigate: What is architecture? Kinds of N-Tier application architecture and its advantage and disadvantage. 
There is also a very basic quiz towards the end of the discussion.


Microsoft BizTalk Server Fundamentals

Microsoft BizTalk Server Orchestration Fundamentals

10 Nov 2013

WPF 2 Dimensional Editable Grid

Problem

Two dimensional (2D) grid is not supported out-of-box in WPF. It is also not very trivial to create one. In this article, I will dive into a way we can create reusable generic 2D grid which is bound to object collections. This can be easily customized by setting appropriate attributes.  
Let’s look at the general grid requirements:
  1. Grid should have flexible design / layout.
  2. X-Axis or Y-Axis headers should not scroll with content.
  3. All binding should be done against object collections, so that we have more control over the data which is being displayed and on any user interactions.
  4. Easy to customize the data display and UI look and feel.
  5. Grid can be readonly or editable.
Grid Examples: In short we might need grids like: 
Grid 1: Notebook price (editable) by Brand and City
Grid 2: Notebook price (editable) with readonly notebook details by Brand and City - With auto scroll bars
Let's see how we can create an Editable or ReadOnly 2 D (Two Dimensional) generic grid in WPF which will be bound to objects directly.

Solution

We can design using various WPF controls. As shown in following figure, we can divide grid into 3 major areas – Column Headers, Row Headers, and Body cells. We can use panels to layout these and achieve structure of a grid.
Assuming this layout, let’s see how we can achieve this through code:
For this to demo: I will use following models:
Our final goal is to visualize product (Notebook in this case) information in a 2D grid where product price is shown by Brand name and City name. Product price should be editable. As shown in this grid:
To achieve this grid layout, we would need following collections:
Column Headers: IEnumerable<object> Columns
Row Headers: ObservableCollection<object> RowsHeader
Rows: ObservableDictionary<object, ObservableCollection<object>> RowsByYAxis
*RowsHeader collection will be generated from RowsByYAxis dictionary. So, ideally we would need only 2 collections.
Let's dive into the code:
Solution design:
The solution contains two projects:
WpfGenericGrid: A class library for generic grid (User Control, View Model, Converters, Messages).
WpfGeneric2DGrid: A client WPF application which consumes above class library to demo 2D editable grid.
In this WPF project, I have used GalaSoft.MvvmLight.WPF4 package for making it easy to implement MVVM pattern. It is a light weight solution which supports generic RelayCommand and Asynchronous Messaging to facilitate communication between view models.
Now we can peek into the real code to create this generic grid:
GenericGrid.xaml (User control)


    
        
        
    

    
        
            
            
        
        
            
            
        
        
            
                
                    
                    
                
            
        
        
            
                
                    
                        
                    
                
                
                    
                        
                            
                                
                                
                            
                        
                    
                
            
        
        
            
                
                    
                        
                            
                            
                                
                                
                            
                        
                    
                
            
        
        
            
                
                    
                        
                            
                                
                                    
                                        
                                    
                                
                                
                                    
                                        
                                            
                                                
                                                    
                                                
                                            
                                        
                                    
                                
                            
                        
                    
                
            
        
    
GenericGrid.xaml.cs (To handle some of the events like synchronize scroll between body and header or validations)
public partial class GenericGrid : UserControl
    {
        public GenericGrid()
        {
            InitializeComponent();
        }

        private void SvGridCells_OnScrollChanged(object sender, ScrollChangedEventArgs e)
        {
            if (e.HorizontalChange != 0.0f)
            {
                try
                {
                    SvColHeaders.ScrollToHorizontalOffset(e.HorizontalOffset);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
            else
            {
                SvRowYAxis.ScrollToVerticalOffset(e.VerticalOffset);
            }
        }

        private void CellTextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            var regex = new Regex("[^0-9.-]+"); //regex that matches disallowed text
            e.Handled = regex.IsMatch(e.Text);
        }
    }
GenericGridViewModel.cs  (View Model for GenericGrid user control) This class contains all the necessary properties like:
CanDelete (True to enable row delete), ReadOnly (True/False, false for editable grid), Columns (XAxis column headers), GridHeight, GridWidth, RowHeight, XAxisHeight, YAxisWidth, ColumnWidth, ScrollBarVisibility. 
public class GenericGridViewModel : ViewModelBase
    {
        private ObservableDictionary<object, ObservableCollection<object>> _rowsByYAxis;
        private double _xAxisColumnWidth = 100;
        private double _yAxisWidth = 150;
        private double _xAxisHeight = 30;
        private double _rowHeight = 30;
        private double _gridWidth = 600;
        private double _gridHeight = 170;
        private string _gridName = string.Empty;
        private bool _isVerticalScrollVisible;
        private bool _isHorizontalScrollVisible;
        private double _gridXAxisHeaderWidth;
        private double _gridYAxisHeaderHeight;
        private double _gridBodyScrollHeight;
        private double _gridBodyScrollWidth;
        private ObservableCollection<object> _rowsHeader;
        private string _gridYAxisHeaderMargin;

        public GenericGridViewModel(string gridName)
        {
            _gridName = gridName;
            HorizontalScrollBarVisible = true;
            VerticalScrollBarVisible = true;
            DeleteRow = new RelayCommand<object>(rowIdentifier =>
            {
                if (!RowsByYAxis.ContainsKey(rowIdentifier)) return;
                var rowHeaderToRemove = RowsByYAxis[rowIdentifier];
                _rowsByYAxis.Remove(rowIdentifier);
                _rowsHeader.Remove(rowIdentifier);
                Messenger.Default.Send(
                    new GenericMessage<GridDataUpdateMessage>(new GridDataUpdateMessage()
                        {
                            RowHeader = rowHeaderToRemove,
                            ActionType = GridAction.RowDelete
                        }));
                RowsByYAxis = _rowsByYAxis;
            });
            Columns = new ObservableCollection<object>();
            RowsByYAxis = new ObservableDictionary<object, ObservableCollection<object>>();
        }

        protected void ComputeGridLayout(int colCount, int rowCount)
        {
            _isVerticalScrollVisible = GridHeight - RowHeight < rowCount * RowHeight;
            _isHorizontalScrollVisible = GridWidth - YAxisWidth < colCount * CellWidth;

            GridXAxisHeaderWidth = HorizontalScrollBarVisible ? _isHorizontalScrollVisible ? GridWidth - YAxisWidth : colCount * CellWidth : GridWidth - YAxisWidth;
            GridYAxisHeaderHeight = VerticalScrollBarVisible ? _isVerticalScrollVisible ? GridHeight - RowHeight : rowCount * RowHeight : GridHeight - RowHeight;

            GridBodyScrollWidth = _isVerticalScrollVisible ? GridXAxisHeaderWidth + 18 : GridXAxisHeaderWidth;
            GridBodyScrollHeight = _isHorizontalScrollVisible ? GridYAxisHeaderHeight + 18 : GridYAxisHeaderHeight;

            GridYAxisHeaderMargin = HorizontalScrollBarVisible || VerticalScrollBarVisible ? _isVerticalScrollVisible || _isHorizontalScrollVisible ? "0 -20 0 0" : "0" : "0";
        }

        public double XAxisColumnWidth
        {
            get { return _xAxisColumnWidth; }
            set { _xAxisColumnWidth = value; }
        }

        public double YAxisWidth
        {
            get { return _yAxisWidth; }
            set { _yAxisWidth = value; }
        }

        public double RowHeight
        {
            get { return _rowHeight; }
            set { _rowHeight = value; }
        }

        public double XAxisHeight
        {
            get { return _xAxisHeight; }
            set { _xAxisHeight = value; }
        }

        public double CellWidth
        {
            get { return XAxisColumnWidth + 1; }
        }
        public double GridWidth
        {
            get { return _gridWidth; }
            set { _gridWidth = value; }
        }

        public double GridHeight
        {
            get { return _gridHeight; }
            set { _gridHeight = value; }
        }

        public double GridXAxisHeaderWidth
        {
            get { return _gridXAxisHeaderWidth; }
            private set { _gridXAxisHeaderWidth = value; RaisePropertyChanged("GridXAxisHeaderWidth"); }
        }

        public double GridYAxisHeaderHeight
        {
            get { return _gridYAxisHeaderHeight; }
            private set { _gridYAxisHeaderHeight = value; RaisePropertyChanged("GridYAxisHeaderHeight"); }
        }

        public double GridBodyScrollHeight
        {
            get { return _gridBodyScrollHeight; }
            private set { _gridBodyScrollHeight = value; RaisePropertyChanged("GridBodyScrollHeight"); }
        }

        public double GridBodyScrollWidth
        {
            get { return _gridBodyScrollWidth; }
            private set { _gridBodyScrollWidth = value; RaisePropertyChanged("GridBodyScrollWidth"); }
        }

        public string YAxisHeaderText { get; set; }
        public bool IsReadOnly { get; set; }
        public bool CanDelete { get; set; }
        public bool HorizontalScrollBarVisible { get; set; }
        public bool VerticalScrollBarVisible { get; set; }
        public RelayCommand<object> DeleteRow { get; protected set; }
        public IEnumerable<object> Columns { get; set; }
        public string GridYAxisHeaderMargin
        {
            get { return _gridYAxisHeaderMargin; }
            private set { _gridYAxisHeaderMargin = value; RaisePropertyChanged("GridYAxisHeaderMargin"); }
        }
        public ObservableCollection<object> RowsHeader
        {
            get { return _rowsHeader; }
            private set { _rowsHeader = value; RaisePropertyChanged("RowsHeader"); }
        }
        public ObservableDictionary<object, ObservableCollection<object>> RowsByYAxis
        {
            get { return _rowsByYAxis; }
            set
            {
                _rowsByYAxis = value;
                if (_rowsByYAxis.Any())
                {
                    ComputeGridLayout(Columns.Count(), _rowsByYAxis.Count);
                    RowsHeader = new ObservableCollection<object>(_rowsByYAxis.Keys);
                }
                RaisePropertyChanged("RowsByYAxis");
            }
        }
    }
Note: You would need ObservableDictionary to implement 2-way binding. This you can find in the linked source code.

GridDataUpdateMessage.cs (It is to communicate data edits or row deletion commands to view model)
public class GridDataUpdateMessage
    {
        public object CellData { get; set; }

        public object RowHeader { get; set; }

        public GridAction ActionType { get; set; }
    }
Few Utility classes: 
GridCellTextBox.cs (Custom text box control with extra bindable properties)
public class GridCellTextBox : TextBox
    {
        public static readonly DependencyProperty UniqueNameProperty =
            DependencyProperty.Register("UniqueName", typeof(string), typeof(GridCellTextBox));
        public static readonly DependencyProperty RowHeaderNameProperty =
            DependencyProperty.Register("RowHeaderName", typeof(string), typeof(GridCellTextBox));

        public string UniqueName
        {
            get { return (string)GetValue(UniqueNameProperty); }
            set { SetValue(UniqueNameProperty, value); }
        }

        public string RowHeaderName
        {
            get { return (string)GetValue(RowHeaderNameProperty); }
            set { SetValue(RowHeaderNameProperty, value); }
        }
    }
ColumnHeader.cs  (A class for binding columns headers)
public class ColumnHeader
    {
        public string Name { get; set; }

        public string Description { get; set; }
    }
RowHeader.cs  (A class for binding row headers)
public class RowHeader
    {
        public string Name { get; set; }

        public string Description { get; set; }
    }
We are done with important pieces of generic grid. If you want to dive more into details. I would advise to look into the source code.

Now let’s  see how to use all these to create grid in a WPF project: We need to add the reference of the WpfGenericGrid assembly to the client project, and then add reference of the user control to the view. As shown below:
MainWindow.xaml (View in the client app)

    
        
                
        
    

MainWindowViewModel.cs : Create sample product data and the view model instance for the grid. Set required properties appropriately.
class MainWindowViewModel : ViewModelBase
    {
        private GenericGridViewModel _gridViewModel;
        
        public MainWindowViewModel()
        {
            List<Product> products = CreateSampleData();

            var colHeaders = products.GroupBy(p => p.City).FirstOrDefault().Select(p => new ColumnHeader {Name = p.BrandName, Description = p.BrandName});
            
            var rowHeaders = products.GroupBy(p => p.BrandName).FirstOrDefault().Select(p => new RowHeader {Name = p.City, Description = p.City});

            var rowByYAxis = products.GroupBy(p => p.City).ToDictionary(p => p.Key, p => p.ToList());
            var observRowByYAxis = new ObservableDictionary<object, ObservableCollection<object>>();

            rowByYAxis.Keys.ToList().ForEach(key => observRowByYAxis.Add(rowHeaders.FirstOrDefault(r => r.Name == key), new ObservableCollection<object>(rowByYAxis[key])));

            GridViewModel = new GenericGridViewModel("productGrid")
            {
                RowHeight = 30,
                XAxisColumnWidth = 100,
                YAxisWidth = 120,
                GridHeight = 200,
                GridWidth = 700,
                Columns = colHeaders,
                RowsByYAxis = observRowByYAxis,
                CanDelete = true,
                HorizontalScrollBarVisible = true,
                VerticalScrollBarVisible = true,
                YAxisHeaderText = "City"
            };

            Messenger.Default.Register<GenericMessage<GridDataUpdateMessage>>(this, (a) =>
            {
                //Updated data
                var message = a.Content;
                if (message.ActionType == GridAction.CellUpdate)
                {
                    //Cell value change
                }
                else if (message.ActionType == GridAction.RowDelete) { 
                    //Row deleted
                }
            });
            Load = new RelayCommand(() =>
                {
                    //Run some logic
                });
        }

        public RelayCommand Load { get; set; }

        public GenericGridViewModel GridViewModel
        {
            get { return _gridViewModel; }
            private set 
            { 
                _gridViewModel = value;
            }
        }
    }
Once everything is put in place correctly, we can see following grid:
In case, if you want to see the running code, I would advise you to download it from the link and play with it.

Source Code

I have developed this generic grid as a class library which can be easily referenced and used in a WPF project. If needed, the same can be copied to any existing WPF project. This sample application demonstrates how to create both of the grids (Grid-1 and Grid-2) discussed in the problem statement. 
To run this application, you would need Visual Studio 2010.

Source code location: https://github.com/manoj-kumar1/WPF-2D-Editable-Grid

Conclusion

In this article, I have tried to demonstrate an easy way to create a 2D grid in WPF. This grid can be easily customized as one or two dimensional; or readonly or editable. Many of the customization can be achieved by setting appropriate properties in grid view model.
Please get in touch with me if you have any questions or you think otherwise @ manoj.kumar[at]neudesic.com.

24 Oct 2013

Visual Studio 2013 - Enhancements and some cool features


Got chance to explore latest Visual Studio 2013 IDE. Although there are many nice enhancements, following sounds good..

  1. Improved web project experience - various components of a complete web application has been separated. Choose ASP.Net with web form, MVC or WebApi or combination and the authentication method to create new web project.
  2. MVC 5 and now there is no "MVC Project Type" or "Web Forms Project Type." There is just one and you can mix and match as you like. hmmmm..
  3. Method Return not read in variable can be viewed in watch
  4. Peek definition - See method without opening file waah..it was very irritating earlier where if we need to check a method and their respective internal method call we needed to open all files and close them (it got improved in 2012 but in 2013 it is better). Still lagging the experience of Resharper..
  5. Enhancement around ASP.Net identity management side.
  6. Support for multiple browser (desktop or mobile browsers) debugging/running.. Good for browser compatibility testing...Cool one..no need to every time change the current browser setting.
  7. Entity Framework has Async Query execution and Save support .. would nice for some logging running save operation which mainly kind of Fire and Forget..
  8. Signal-R enhancements and build over OWin (alternative to OAuth).
The complete list can be reference here: http://www.asp.net/visual-studio/overview/2013/release-notes

VS 2013 download link: http://www.microsoft.com/visualstudio/eng/downloads#d-2013-express

23 Oct 2013

This ScreenCast on "BizTalk Server Messaging Fundamentals" talks about messaging architecture, commonly used terms, message processing, publish and subscribe pattern, pipelines, port and various hands-on demos.


In this Screencast on "BizTalk Server Fundamentals", I talk about what/why BizTalk Server, its architecture, commonly used terms, development environment/tools, and installation/configuration steps.


Authentication against CRM contact using custom STS

Scenario
In claim based scenarios, sometimes we might need to authenticate against CRM contacts. CRM system might be acting more as backend or internal system. We can have a web application or might be a Sharepoint application which wants to authenticate end users against CRM entities. I used this in some application, and I find it interesting and useful to share.
Let’s try to understand the scenario:

Figure 1: Sharepoint system is authenticated against CRM using ADFS 2 and custom STS.
Look into the roles of various components involved here:
Client: Any PC where we want to access a SharePoint application. Client accesses the SharePoint URL. User enters the credentials in the 3rd step.
SharePoint Application: This application is configured as relying party in ADFS. It will request claims from ADFS.
ADFS: Active Directory Federation Service is Optional here. If we need to authenticate against AD and/or we need to federate among various claim/authentication providers then we would need this, otherwise we don’t. We can just use a custom STS with web application configured as relying party.
Custom STS (Security Token Service): A custom STS based on ASP.Net web application or WCF. It is configured as another authentication provider in ADFS. It creates required claims after successful authentication in federation scenario using ADFS.
CRM System: Custom STS accesses CRM using organization service to fetch contact details and authenticate against the details entered by user.

Now we can now go thru the code to achieve this in step by step manner. I am going to create a WCF based STS which can be accessed as service from any exiting STS (Active federation). This can be done using ASP.Net STS with a login page (Passive federation).
Steps to follow (I might give a miss to detailed explanation of claim fundamentals, rather I would like to focus more on custom STS and how to use it to authenticate against CRM contacts:-
Environment: Visual Studio 2010, CRM Dlls, IIS.
1.   Create WCF STS project using Visual Studio 2010:
Go to new website and then select following-


Select Web location as HTTP and URL like: https://localhost/AuthUsingCRM/.
It will create a startup project with basic code for WCF based STS.
Default Project structure:  
It basically generates following:

Some important classes generated:
CustomSecurityTokenService: WCF service for STS (The custom STS class)
public class CustomSecurityTokenService : SecurityTokenService
{
    // TODO: Set enableAppliesToValidation to true to enable only the RP Url's specified in the ActiveClaimsAwareApps array to get a token from this STS
    static bool enableAppliesToValidation = false;

    // TODO: Add relying party Url's that will be allowed to get token from this STS
    static readonly string[] ActiveClaimsAwareApps = { /*"https://localhost/ActiveClaimsAwareWebApp"*/ };

    /// 
    /// Creates an instance of CustomSecurityTokenService.
    /// 
    /// The SecurityTokenServiceConfiguration.
    public CustomSecurityTokenService( SecurityTokenServiceConfiguration configuration )
        : base( configuration )
    {
    }

    /// 
    /// Validates appliesTo and throws an exception if the appliesTo is null or contains an unexpected address.
    /// 
    /// The AppliesTo value that came in the RST.
    /// If 'appliesTo' parameter is null.
    /// If 'appliesTo' is not valid.
    void ValidateAppliesTo( EndpointAddress appliesTo )
    {
        if ( appliesTo == null )
        {
            throw new ArgumentNullException( "appliesTo" );
        }

        // TODO: Enable AppliesTo validation for allowed relying party Urls by setting enableAppliesToValidation to true. By default it is false.
        if ( enableAppliesToValidation )
        {
            bool validAppliesTo = false;
            foreach ( string rpUrl in ActiveClaimsAwareApps )
            {
                if ( appliesTo.Uri.Equals( new Uri( rpUrl ) ) )
                {
                    validAppliesTo = true;
                    break;
                }
            }

            if ( !validAppliesTo )
            {
                throw new InvalidRequestException( String.Format( "The 'appliesTo' address '{0}' is not valid.", appliesTo.Uri.OriginalString ) );
            }
        }
    }

    /// 
    /// This method returns the configuration for the token issuance request. The configuration
    /// is represented by the Scope class. In our case, we are only capable of issuing a token for a
    /// single RP identity represented by the EncryptingCertificateName.
    /// 
    /// The caller's principal.
    /// The incoming RST.
    /// The scope information to be used for the token issuance.
    protected override Scope GetScope( IClaimsPrincipal principal, RequestSecurityToken request )
    {
        ValidateAppliesTo( request.AppliesTo );

        //
        // Note: The signing certificate used by default has a Distinguished name of "CN=STSTestCert",
        // and is located in the Personal certificate store of the Local Computer. Before going into production,
        // ensure that you change this certificate to a valid CA-issued certificate as appropriate.
        //
        Scope scope = new Scope( request.AppliesTo.Uri.OriginalString, SecurityTokenServiceConfiguration.SigningCredentials );

        string encryptingCertificateName = WebConfigurationManager.AppSettings[ "EncryptingCertificateName" ];
        if ( !string.IsNullOrEmpty( encryptingCertificateName ) )
        {
            // Important note on setting the encrypting credentials.
            // In a production deployment, you would need to select a certificate that is specific to the RP that is requesting the token.
            // You can examine the 'request' to obtain information to determine the certificate to use.
            scope.EncryptingCredentials = new X509EncryptingCredentials( CertificateUtil.GetCertificate( StoreName.My, StoreLocation.LocalMachine, encryptingCertificateName ) );
        }
        else
        {
            // If there is no encryption certificate specified, the STS will not perform encryption.
            // This will succeed for tokens that are created without keys (BearerTokens) or asymmetric keys.  Symmetric keys are
            // required to be 'wrapped' and the STS will throw.
            scope.TokenEncryptionRequired = false;

            // Symmetric keys are required to be 'wrapped' or the STS will throw, uncomment the code below to turn off proof key encryption.
            // Turning off proof key encryption is not secure and should not be used in a deployment scenario.

            // scope.SymmetricKeyEncryptionRequired = false;
        }

        return scope;
    }


    /// 
    /// This method returns the claims to be issued in the token.
    /// 
    /// The caller's principal.
    /// The incoming RST, can be used to obtain addtional information.
    /// The scope information corresponding to this request./// 
    /// If 'principal' parameter is null.
    /// The outgoing claimsIdentity to be included in the issued token.
    protected override IClaimsIdentity GetOutputClaimsIdentity( IClaimsPrincipal principal, RequestSecurityToken request, Scope scope )
    {
        if ( null == principal )
        {
            throw new ArgumentNullException( "principal" );
        }

        ClaimsIdentity outputIdentity = new ClaimsIdentity();

        // Issue custom claims.
        // TODO: Change the claims below to issue custom claims required by your application.
        // Update the application's configuration file too to reflect new claims requirement.

        outputIdentity.Claims.Add( new Claim( System.IdentityModel.Claims.ClaimTypes.Name, principal.Identity.Name ) );
        outputIdentity.Claims.Add( new Claim( ClaimTypes.Role, "Manager" ) );

        return outputIdentity;
    }
}
CustomSecurityTokenServiceConfiguration: We can use this class to override some of the default configurations. Later in the article, I will override the default user name token handler behavior.
/// 
/// A custom SecurityTokenServiceConfiguration implementation.
/// 
public class CustomSecurityTokenServiceConfiguration : SecurityTokenServiceConfiguration
{
    /// 
    /// CustomSecurityTokenServiceConfiguration constructor.
    /// 
    public CustomSecurityTokenServiceConfiguration()
        : base( WebConfigurationManager.AppSettings[Common.IssuerName],
                new X509SigningCredentials( CertificateUtil.GetCertificate(
                    StoreName.My, StoreLocation.LocalMachine,
                    WebConfigurationManager.AppSettings[Common.SigningCertificateName] ) ) )
    {
        this.SecurityTokenService = typeof( CustomSecurityTokenService );
    }
}

CertificateUtil: A kind of helper class to access certificates from local store.
FederationMetadata.xml: Default federation metadata definitions which are exposed by this custom STS. It has all the necessary information such as issuer name, certificate info, endpoint address or exposed claims.

Web.config: It plays a major role in setting up this STS correctly. We will discuss this in detail in 2nd step.

2.   Modify default web.config: It should be modified as following –
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <configSections>
    <section name="microsoft.identityModel" type="Microsoft.IdentityModel.Configuration.MicrosoftIdentityModelSection, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
  </configSections>
  <appSettings>
    <add key="IssuerName" value="ActiveSTSForCRM"/>
    <add key="SigningCertificateName" value="CN=DEV01.corp.contoso.com"/>
    <add key="EncryptingCertificateName" value="CN=DEV01.corp.contoso.com"/>
  </appSettings>
  <location path="FederationMetadata">
    <system.web>
      <authorization>
        <allow users="*"/>
      </authorization>
    </system.web>
  </location>
  
  <system.web>
    <compilation debug="true" targetFramework="4.0">
      <assemblies>
        <add assembly="Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
      </assemblies>
    </compilation>
    <authentication mode="None"/>
    <pages>
      <controls>
        <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
      </controls>
    </pages>
  </system.web>
  
  <system.web.extensions>
    <scripting>
      <webServices>
      </webServices>
    </scripting>
  </system.web.extensions>

  <system.serviceModel>
    <services>
      <service name="Microsoft.IdentityModel.Protocols.WSTrust.WSTrustServiceContract" behaviorConfiguration="ServiceBehavior">
        <endpoint address="IWSTrust13" binding="ws2007HttpBinding" contract="Microsoft.IdentityModel.Protocols.WSTrust.IWSTrust13SyncContract" bindingConfiguration="ws2007HttpBindingConfiguration"/>
        <host>
          <baseAddresses>
            <add baseAddress="https://DEV01.corp.contoso.com/AAMCustomSTS/Service.svc"/>
            <add baseAddress="http:// devcrm01.contoso.com/dev
 /XRMServices/2011/Organization.svc"/>
          </baseAddresses>
        </host>
        <endpoint address="mex" binding="ws2007HttpBinding" contract="IMetadataExchange" bindingConfiguration="ws2007HttpBindingConfiguration"/>
      </service>
    </services>
    <bindings>
      <ws2007HttpBinding>
        <binding name="ws2007HttpBindingConfiguration">
          <security mode="TransportWithMessageCredential">
            <transport clientCredentialType="None"/>
            <message clientCredentialType="UserName" establishSecurityContext="false"/>
          </security>
        </binding>
      </ws2007HttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="ServiceBehavior">
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
          <serviceCredentials>
            <serviceCertificate findValue="DEV01.corp.contoso.com" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName"/>
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <diagnostics>
      <messageLogging logEntireMessage="true" logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="true" logMalformedMessages="true" maxMessagesToLog="50000" maxSizeOfMessageToLog="20000"/>
    </diagnostics>
  </system.serviceModel>
  <microsoft.identityModel>
    <service name="Microsoft.IdentityModel.Protocols.WSTrust.WSTrustServiceContract">
      <audienceUris>
        <add value="https://DEV01.corp.contoso.com/AuthUsingCRMClientSite/"/>
      </audienceUris>
      <issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
        <trustedIssuers>
          <add thumbprint="eaa8f8bd2063d55ac083a0907e52b74d8cdb9d07" name="https://DEV01.corp.contoso.com/AuthUsingCRM/Service.svc/IWSTrust13"/>
        </trustedIssuers>
      </issuerNameRegistry>
      <serviceCertificate>
        <certificateReference findValue="DEV01.corp.contoso.com" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName"/>
      </serviceCertificate>      
    </service>
  </microsoft.identityModel>
</configuration>

  We need to make following changes:
     2.1.   AppSettings:
- Mention token issuer name for this STS.
- Token signing certificate: Create a self-signed certificate in IIS and mention the name here.
- Encrypting Certificate name: You can use separate certificate. Or use the same as signing certificate.
<appSettings>
    <add key="IssuerName" value="ActiveSTSForCRM"/>
    <add key="SigningCertificateName" value="CN=DEV01.corp.contoso.com"/>
    <add key="EncryptingCertificateName" value="CN=DEV01.corp.contoso.com"/>
</appSettings>
2.2.  Add a new config section for microsoft.identityModel:
Define section as added in above sample config.
Mention fully qualified name of the system (in place of Localhost). Replace DEV01.corp.contoso.com accordingly and the certificate name or thumbprint.
2.3.  Audience URI: This is the relying party for this STS. In some later step, I will add a test web client to consume this STS. The URI of this application should be mentioned as audient URI on STS web config.
2.4.  Specify service, binding, and service behavior appropriately. Use your domain name.

3.  Add a claim aware web site to test the custom STS created above:
Select new website:   
With claim aware web site, we will have most of the required assemblies automatically added into solution.

4.  Add logic to actively consume WCF based STS in login.aspx.cs:
WSTrustChannelFactory: We will actively consume the WCF STS end point using WSTurst channel factory class as shown in the below method.
protected void btnSubmit_Click( object sender, EventArgs e )
    {
        // Note: Add code to validate user name, password. This code is for illustrative purpose only.
        // Do not use it in production environment.        
        //FormsAuthentication.RedirectFromLoginPage( txtUserName.Text, false );
        GetToken();
    }

    private static void GetToken()
    {
        WSTrustChannelFactory factory = null;
        try
        {
            factory = new WSTrustChannelFactory(
                            new MIB.UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential),                            new EndpointAddress("https://dev01.corp.contoso.com/AuthUsingCRM/Service.svc/IWSTrust13")); //IWSTrust13

            factory.TrustVersion = SSS.TrustVersion.WSTrust13;
            factory.Credentials.SupportInteractive = false;
            factory.Credentials.UserName.UserName = "domain\\username";
            factory.Credentials.UserName.Password = "password";

            factory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = SSS.X509CertificateValidationMode.None;
            factory.Credentials.ServiceCertificate.Authentication.RevocationMode = X509RevocationMode.NoCheck;

            factory.Credentials.ClientCertificate.Certificate = CertificateUtil.GetCertificate(StoreName.My, StoreLocation.LocalMachine, WebConfigurationManager.AppSettings["SigningCertificateName"]);

            RequestSecurityToken rst = new RequestSecurityToken();
            rst.RequestType = RequestTypes.Issue;

            rst.AppliesTo = new EndpointAddress("https:// dev01.corp.contoso.com /AuthUsingCRMClientSite/");
            rst.KeyType = KeyTypes.Bearer;

            IWSTrustChannelContract channel = factory.CreateChannel();

            SecurityToken secToken = channel.Issue(rst);

        }
        finally
        {
            if (factory.State != CommunicationState.Closing)
            {
                factory.Close();
                factory.Abort();
            }
        }
    }
User Name / Password: Set the window’s user account name and password. By default, for username authentication, WindowsUserNameSecurityTokenHandler is used by STS configuration.

5.  Now Set the client web site as startup project and debug it.
Set a breakpoint at following line in GetToken() method in login.aspx.cs: SecurityToken secToken = channel.Issue(rst);

Once it executes, it will return a valid encrypted secToken. So, great job, our STS is working. Now we can modify it to authenticate against CRM.

6.  Add custom security handler to authenticate against CRM:
    We will add 2 classes to App_Code of STS project:
  CRMService: A wrapper around OrganizationService of CRM / XRM.
public class CRMService
{
    private OrganizationService _Service = null;

    public CRMService()
    {
        var connection = new CrmConnection("CRMConn");
        _Service = new OrganizationService(connection);
    }

    public OrganizationService Service
    {
        get
        {
            return _Service;
        }
        set
        {

            _Service = value;
        }
    }

    public Guid CreateEntity(Entity entity)
    {
        return Service.Create(entity);
    }

    public Entity RetreiveEntity(Guid id, string entityName)
    {
        return Service.Retrieve(entityName, id, new ColumnSet(true));
    }

    public EntityCollection RetreiveMultipleRecords(string fetchXml)
    {
        return Service.RetrieveMultiple(new FetchExpression(fetchXml));
    }

    public void UpdateEntity(Entity entity)
    {
        Service.Update(entity);
    }
}
    For this to work, we need to add following Xrm assemblies to Bin folder:
Microsoft.Xrm.Sdk.dll, microsoft.crm.sdk.proxy.dll, and microsoft.xrm.client.dll  
   
7.  CRMUserNameSecurityTokenHandler: A custom user name security token handler which will override the default WindowsUserNameSecurityTokenHandler from STS configuration. Here we need to override ValidateToken() method and access CRM services using CRMService wrapper to authenticate user.
{
public class CRMUserNameSecurityTokenHandler : Microsoft.IdentityModel.Tokens.UserNameSecurityTokenHandler    
public CRMUserNameSecurityTokenHandler()
    {

    }

    public override bool CanValidateToken
    {
        get
        {
            return true;

        }
    }

    public override Microsoft.IdentityModel.Claims.ClaimsIdentityCollection ValidateToken(SecurityToken token)
    {
        System.Diagnostics.Debugger.Launch();

        if (token == null)
        {
            throw new ArgumentNullException("token");
        }
        UserNameSecurityToken userNameToken = token as UserNameSecurityToken;

        if (userNameToken == null)
        {
            throw new SecurityTokenException("Invalid token");
        }
        IClaimsIdentity identity = new ClaimsIdentity();
        EntityCollection contacts = AuthenticateUser(userNameToken.UserName, userNameToken.Password);
        if (contacts != null && contacts.Entities.First() != null)
        {
            Entity contact = contacts.Entities.First();

            identity.Claims.Add(new Claim(Microsoft.IdentityModel.Claims.ClaimTypes.Authentication, "true"));
            identity.Claims.Add(new Claim(Microsoft.IdentityModel.Claims.ClaimTypes.Upn, userNameToken.UserName));
            string name = contact.Attributes["lastname"] != null ? contact.Attributes["lastname"].ToString() + ", " : "" +
                contact.Attributes["middlename"] != null ? contact.Attributes["middlename"].ToString() + " " : "" +
                contact.Attributes["firstname"] != null ? contact.Attributes["firstname"].ToString() : "";
            identity.Claims.Add(new Claim(Microsoft.IdentityModel.Claims.ClaimTypes.Name, name));
            identity.Claims.Add(new Claim(Microsoft.IdentityModel.Claims.ClaimTypes.Email, contact.Attributes["emailaddress1"] != null ? contact.Attributes["emailaddress1"].ToString() : userNameToken.UserName));
            identity.Claims.Add(new Claim(Microsoft.IdentityModel.Claims.ClaimTypes.PrimarySid, contact.Attributes["contactid"] != null ? contact.Attributes["contactid"].ToString() : "InvalidContactID"));
        }

        return new ClaimsIdentityCollection(new IClaimsIdentity[] { identity });
    }

    private EntityCollection AuthenticateUser(string userName, string password)
    {
        //Authentication against CRM
        CRMService svc = new CRMService();
        var fetchXML = @"<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
                                          <entity name='contact'>
                                            <all-attributes/>
                                            <filter type='and'>
                                              <condition attribute='neu_username' operator='eq' value='" + userName + @"' />
                                            </filter>
                                          </entity>
                                        </fetch>";
        EntityCollection contacts = svc.RetreiveMultipleRecords(fetchXML);

        if (contacts.Entities.Count > 0)
        {
            if (password.ToLower() == contacts[0]["new_password_field"].ToString().ToLower())
                return contacts;
        }

        return null;
    }
}
8.  Override default user name security token handler with this custom one:
public class CustomSecurityTokenServiceConfiguration : SecurityTokenServiceConfiguration
{
    /// 
    /// CustomSecurityTokenServiceConfiguration constructor.
    /// 
    public CustomSecurityTokenServiceConfiguration()
        : base( WebConfigurationManager.AppSettings[Common.IssuerName],
                new X509SigningCredentials( CertificateUtil.GetCertificate(
                    StoreName.My, StoreLocation.LocalMachine,
                    WebConfigurationManager.AppSettings[Common.SigningCertificateName] ) ) )
    {
        var removeWinUNHdl = this.SecurityTokenHandlerCollectionManager.SecurityTokenHandlerCollections.ToList()[0].First(x => x is Microsoft.IdentityModel.Tokens.WindowsUserNameSecurityTokenHandler);
        this.SecurityTokenHandlerCollectionManager.SecurityTokenHandlerCollections.ToList()[0].Remove(removeWinUNHdl);
        this.SecurityTokenHandlerCollectionManager.SecurityTokenHandlerCollections.ToList()[0].Add(new CRMUserNameSecurityTokenHandler());
        
        this.SecurityTokenService = typeof( CustomSecurityTokenService );
    }
}
This can be done in web.config under Microsoft.IdentityModel section, but it was not working in my case.
9.  Set CRM connection string in web.config with correct User name and password.
<add name="CRMConn" connectionString="Url=http://devcrm01.contoso.com/Dev/; Username=domain\user_name; Password=password;"/>
   10.  Set CRM user name and password in GetToken() method of test client web site and Debug the application. If all these settings are set correctly, custom token handler will be called and it will authenticate against CRM. Finally it will return the claims which we have configured in custom token handler.

Source Code
I have developed this sample application and attached here with this article. The source code contains two websites (STS and test client) which has to be deployed correctly in IIS with all the configuration and certificate needed (as explained in this article). The source code is not perfect in all sense as its primary focus is to demo authentication using CRM.

Source code (Shared on GitHub): https://github.com/manoj-kumar1/auth-against-crm-using-STS

To run this application, you would need Visual Studio 2010.

Conclusion

In this article, I have demonstrated a technique to consume CRM services using custom STS for authenticating end user. This can be setup as Active or Passive federation with ADFS in advance scenarios as also explained in the beginning of this discussion.

Please get in touch with me if you have any questions or you think otherwise @ manoj.kumar[at]neudesic.com.