LedgerEntry.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / infocard / Service / managed / Microsoft / InfoCards / LedgerEntry.cs / 1 / LedgerEntry.cs

                            //------------------------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
namespace Microsoft.InfoCards
{ 
    using System;
    using System.IO; 
    using System.Collections.Generic; 
    using System.Security.Cryptography;
    using System.Security.Cryptography.X509Certificates; 
    using System.Text;
    using System.Threading;

    using Microsoft.InfoCards.Diagnostics; 
    using IDT = Microsoft.InfoCards.Diagnostics.InfoCardTrace;
 
    // 
    // Summary
    //   This class represents a ledger entry 
    //
    internal class LedgerEntry
    {
        const Int32 InvalidRow = 0; 
        const byte Version = 1;
        const byte m_marker = 29; 
 
        bool m_isDirty;
        DateTime m_disclosureDate = DateTime.MinValue; 
        string m_recipientId;
        Recipient m_recipient;
        byte[] m_subjectKey;
        string[] m_disclosedClaims; 
        Uri m_infoCardId;
        string m_immediateRecipientOrgId; 
 
        Int32 m_rowId = InvalidRow;
 

        //
        // Summary
        //  Constructor for creating a ledger entry using the serialized ledger object 
        //
        // Parameters 
        //   stream - Stream containing the serialized object 
        //   connection - Connection to the store.
        // 
        public LedgerEntry( Stream stream, StoreConnection connection )
        {
            IDT.Assert( null != stream, " Null input stream" );
            IDT.Assert( null != connection, "Null storeconnection" ); 

            m_isDirty = false; 
 
            Deserialize( stream );
 
            //
            // Read the recipient from the store
            //
            DataRow row = connection.GetSingleRow( 
                new QueryParameter( SecondaryIndexDefinition.ObjectTypeIndex,
                                  (Int32)StorableObjectType.Recipient ), 
                new QueryParameter( SecondaryIndexDefinition.RecipientIdIndex, 
                                  m_recipientId ) );
 
            IDT.Assert( null != row,
                     "Recipient should always exist in store before a ledger entry is created " );

            if ( null != row ) 
            {
                m_recipient = new Recipient( new MemoryStream( row.GetDataField() ) ); 
            } 

            ThrowIfNotComplete(); 
        }


        // 
        // Summary
        //  Static constructor for creating a ledger entry for a recipient 
        //  Use this factory method to also create the SubjectKey [NewLedgerEntry -- 
        //  as opposed to a constructor signifies doing an expensive operation]
        // 
        // Remarks:
        // Callee must call Array.Clear (if appropriate)
        //
        // Parameters 
        //   infoCardId - Id of the parent infocard.
        //   recipient - Recipient associated with this ledger entry. 
        //   masterkey - The masterkey 
        //
        public static LedgerEntry NewLedgerEntry( Uri infoCardId, Recipient recipient, byte[] masterKey, string immediateTokenRecipientOrganizationIdentifier ) 
        {
            return new LedgerEntry( infoCardId, recipient, masterKey, immediateTokenRecipientOrganizationIdentifier );
        }
 
        //
        // Summary 
        //  Constructor for creating a ledger entry for a recipient 
        //
        // Remarks 
        // Callee must call Array.Clear (if appropriate)
        //
        // Parameters
        //   infoCardId - Id of the parent infocard. 
        //   recipient - Recipient associated with this ledger entry.
        //   masterKey - Masterkey of the infoCard, callee must call Array.Clear 
        // 
        public LedgerEntry( Uri infoCardId, Recipient recipient, byte[] masterKey, string immediateTokenRecipientOrganizationIdentifier )
        { 
            IDT.Assert( null != recipient, "Null recipient" );
            IDT.Assert( null != infoCardId, "Null infocard ID" );

            m_isDirty = true; 
            m_infoCardId = infoCardId;
            m_disclosureDate = DateTime.Now; 
            m_recipient = recipient; 
            m_recipientId = recipient.RecipientId;
            m_immediateRecipientOrgId = immediateTokenRecipientOrganizationIdentifier; 

            //
            // Generate a new RSA Key pair for the subject
            // 
            //
            // POR is to use the Public Key of the target recipient 
            // for the target recipient entropy. We could also use the 
            // FQDN for the organization instead. The latter approach will only work
            // if organizational certs started expressing fully qualified and 
            // globally unique org. But this is not the case with SSL certs for example,
            // where only the CN component of the subject DN is really used
            // and specified.
            // 
            m_subjectKey = RsaKeyGen.CreateRsaKeyPairX931(
                masterKey, 
                Convert.FromBase64String( immediateTokenRecipientOrganizationIdentifier ) ); 

            ThrowIfNotComplete(); 
        }


        // 
        // Summary
        //  Update the subjectKey if the immediate token recipient has changed 
        // 
        // Parameters
        //   recipient - Organization id of the immediate recipient of the token being created. 
        //   masterKey - Masterkey of the infoCard, callee must call Array.Clear
        //
        // Returns true if the the subject key was updated
        // 
        public bool CheckAndUpdateSubjectKey( string immediateTokenRecipientOrgId, byte[] masterKey )
        { 
            // 
            // Recreate the RSA key pair if the id has changed
            // 
            if ( m_immediateRecipientOrgId != immediateTokenRecipientOrgId )
            {
                m_immediateRecipientOrgId = immediateTokenRecipientOrgId;
                m_subjectKey = RsaKeyGen.CreateRsaKeyPairX931( 
                masterKey,
                Convert.FromBase64String( immediateTokenRecipientOrgId ) ); 
                return true; 
            }
            return false; 
        }

        public bool IsDirty
        { 
            get { return m_isDirty; }
        } 
 
        public DateTime DisclosureDate
        { 
            //
            // Set by GetTokenRequest
            //
            set 
            {
                m_disclosureDate = value; 
                m_isDirty = true; 
            }
        } 

        public byte[] SubjectKey
        {
            get 
            {
                IDT.Assert( !Utility.ArrayIsNullOrEmpty( m_subjectKey ), "SubjectKey not populated!" ); 
                return m_subjectKey; 
            }
        } 

        public string[] DisclosedClaims
        {
            get 
            {
                return m_disclosedClaims; 
            } 
            set
            { 
                m_disclosedClaims = value;
                m_isDirty = true;
            }
        } 

        public Recipient Recipient 
        { 
            get { return m_recipient; }
        } 


        // See 33231, 33232.
        // Get referenced by agent\LedgerManagement ddsuites. 
        //
        public Uri InfoCardId 
        { 
            get { return m_infoCardId; }
        } 

        //
        // Summary
        //  Throws if ledger entry has not been populated. 
        //
        public void ThrowIfNotComplete() 
        { 
            bool isComplete = (null != m_immediateRecipientOrgId &&
                null != m_recipientId && 
                !Utility.ArrayIsNullOrEmpty( m_subjectKey ) &&
                null != m_infoCardId &&
                DateTime.MinValue != m_disclosureDate);
 
            if ( !isComplete )
            { 
                throw IDT.ThrowHelperError( new SerializationIncompleteException( this.GetType() ) ); 
            }
        } 

        //
        // Summary
        //  Serialize the ledger entry 
        //
        // Parameters 
        //  writer - The binary writer the object is serialized to. 
        //
        public void Serialize( System.IO.BinaryWriter writer ) 
        {
            //
            // Make sure that we don't serialize an incomplete object. Serializing null values will result in a
            // serialization exception or a corrupt signature. 
            //
            ThrowIfNotComplete(); 
 
            //
            // Write each member to binary stream 
            //
            writer.Write( Version );
            writer.Write( m_disclosureDate.ToFileTimeUtc() );
            Utility.SerializeString( writer, m_recipientId ); 
            Utility.SerializeString( writer, m_immediateRecipientOrgId );
            Utility.SerializeBytes( writer, m_subjectKey ); 
            Utility.SerializeUri( writer, m_infoCardId ); 
            writer.Write( (Int32)(null == m_disclosedClaims ? 0 : m_disclosedClaims.Length) );
            if ( null != m_disclosedClaims ) 
            {
                foreach ( string claimId in m_disclosedClaims )
                {
                    Utility.SerializeString( writer, claimId ); 
                }
            } 
 
            writer.Write( m_marker );
        } 

        //
        // Summary
        //  Deserialize the ledger entry 
        //
        // Parameters 
        //  reader - The binary reader the object is serialized to. 
        //
        public void Deserialize( System.IO.Stream stream ) 
        {
            //
            // Populate each member from the stream
            // 
            BinaryReader reader = new InfoCardBinaryReader( stream, Encoding.Unicode );
 
            // 
            // Check the version
            // 
            if ( Version != reader.ReadByte() )
            {
                IDT.Assert( false, "version mismatch deserializing ledger" );
            } 

            // 
            // Read each property from the stream 
            //
            m_disclosureDate = DateTime.FromFileTimeUtc( reader.ReadInt64() ); 
            m_recipientId = Utility.DeserializeString( reader );
            m_immediateRecipientOrgId = Utility.DeserializeString( reader );

            m_subjectKey = reader.ReadBytes( reader.ReadInt32() ); 
            m_infoCardId = Utility.DeserializeUri( reader );
 
            Int32 n = reader.ReadInt32(); 
            if ( n > 0 )
            { 
                m_disclosedClaims = new string[ n ];

                for ( Int32 i = 0; i < n; i++ )
                { 
                    m_disclosedClaims[ i ] = Utility.DeserializeString( reader );
                } 
            } 

            // 
            // Validate the end of the buffer
            //
            if ( m_marker != reader.ReadByte() )
            { 
                IDT.Assert( false, "Invalid stream detected deserializing ledger" );
            } 
 
            //
            // Just a correctness check 
            //
            ThrowIfNotComplete();

            // 
            // The entry is only deserialized when reading from the store therefore mark as not dirty.
            // 
            m_isDirty = false; 
        }
 
        public void Save( StoreConnection con )
        {
            IDT.TraceDebug( "Saving LedgerEntry..." );
            IDT.TraceDebug( ToString() ); 

            // 
            // Write the ledger entry object to the store 
            //
 
            //
            // Try and get the database header information to
            // see if this is an insert or update.
            // 
            // Note: The datafield is not part of the projection
            // in order to avoid unecessary decryption. 
            // 
            DataRow row = TryGetRow( con, QueryDetails.FullHeader );
 
            if ( null == row )
            {
                row = new DataRow();
                row.ObjectType = (Int32)StorableObjectType.LedgerEntry; 
                row.GlobalId = Guid.NewGuid();
            } 
 
            //
            // Populate the parentId index field 
            //
            row.SetIndexValue( SecondaryIndexDefinition.ParentIdIndex,
                GlobalId.DeriveFrom( m_infoCardId.ToString() ) );
            row.SetIndexValue( SecondaryIndexDefinition.RecipientIdIndex, m_recipientId ); 

            // 
            // Populate the data object 
            //
            MemoryStream ms = new MemoryStream(); 
            System.IO.BinaryWriter writer = new BinaryWriter( ms, Encoding.Unicode );
            Serialize( writer );
            row.SetDataField( ms.ToArray() );
 
            //
            // Before saving the ledger, we need to make sure that the recipient has been saved 
            // 

            DataRow recipientRow = con.GetSingleRow( 
                QueryDetails.FullHeader,
                new QueryParameter( SecondaryIndexDefinition.ObjectTypeIndex,
                                  (Int32)StorableObjectType.Recipient ),
                new QueryParameter( SecondaryIndexDefinition.RecipientIdIndex, 
                                  m_recipientId ) );
 
            if ( null != row ) 
            {
                con.Save( row ); 
            }
            else
            {
                IDT.Assert( false, "Currupt store - no recipient found for ledger" ); 
            }
 
 
            //
            // Update the row id in the object in case 
            // this was an insert.
            //
            m_rowId = row.LocalId;
 
            //
            // Mark object as not dirty. 
            // 
            m_isDirty = false;
        } 

        //
        // Summary
        //  Write the object to a string 
        //
        public override string ToString() 
        { 
#if DEBUG
            StringBuilder sb = new StringBuilder(); 
            sb.AppendFormat( "InfoCard Id:\t{0}\n", m_infoCardId.ToString() );
            sb.AppendFormat( "Disclosure Date:\t{0}\n", m_disclosureDate );
            sb.AppendFormat( "Recipient RecipientId:\t{0}\n", m_recipientId );
            sb.AppendFormat( "Recipient ImmediateRecipientOrgId:\t{0}\n", m_immediateRecipientOrgId ); 
            sb.AppendFormat( "Subject Key: not shown\n" );
            sb.AppendFormat( "Disclosed Claims:\n" ); 
 
            if ( null != m_disclosedClaims )
            { 
                foreach ( string uri in m_disclosedClaims )
                {
                    sb.AppendFormat( "{0}\n", uri );
                } 
            }
 
            return sb.ToString(); 
#else
            return base.ToString(); 
#endif
        }

        // 
        // Summary
        //  Retrieve the datarow for the ledger entry from the store for the specified query 
        // 
        // Parameters
        //  con - store connection 
        //  details - Query to be used.
        //
        // Return
        //  The datarow retrieved from the store. 
        //
        protected DataRow TryGetRow( StoreConnection con, QueryDetails details ) 
        { 
            IDT.Assert( null != m_infoCardId, "populate infocard before retrieving ledger" );
 
            //
            // Retrieve a single object from the database
            //
            DataRow row = con.GetSingleRow( 
                QueryDetails.FullHeader,
                new QueryParameter( SecondaryIndexDefinition.ObjectTypeIndex, 
                                  (Int32)StorableObjectType.LedgerEntry ), 
                new QueryParameter( SecondaryIndexDefinition.RecipientIdIndex,
                                  m_recipientId ), 
                new QueryParameter( SecondaryIndexDefinition.ParentIdIndex,
                     GlobalId.DeriveFrom( m_infoCardId.ToString() ) ) );
            return row;
        } 
    }
} 
 

////////////////////////////////////////////////////////////////////////////// 
// Functions that could potentially be useful in future:
//////////////////////////////////////////////////////////////////////////////
//
// Summary 
//  Retrieve the datarow for the ledger entry from the store for the specified query.
//  Checks if the returned row is a ledger entry. 
// 
// Parameters
//  con - store connection 
//  details - Query to be used.
//
// Return
//  The datarow retrieved from the store. 
//
//protected DataRow GetRow( StoreConnection con, QueryDetails details ) 
//{ 
//    DataRow row = TryGetRow( con, details );
 
//    //
//    // Verify that an infocard row was returned
//    //
//    if( null != row || (Int32)StorableObjectType.LedgerEntry != row.ObjectType  ) 
//    {
//        throw IDT.ThrowHelperError( new InvalidOperationException( 
//            SR.GetString( SR.LedgerEntryIncorrectType ) ) ); 
//    }
 
//    return row;
//}

 
//public void Get( StoreConnection con )
//{ 
//    // Retrieve the row for the object from the database 
//    DataRow row = GetRow( con, QueryDetails.FullRow );
 
//    // Populate the infocard using the byte array
//    Deserialize( new MemoryStream( row.GetDataField() ) );

//    // Update the row id from the database 
//    m_rowId = row.LocalId;
//} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK