/// <summary>
        /// Initialize an instance of NrpcClientSecurityContext class. 
        /// By calling this constructor, the class will setup a new secure 
        /// channel between client and server.
        /// </summary>
        /// <param name="domainName">
        /// The NRPC domain name.
        /// </param>
        /// <param name="serverName">
        /// The NRPC server name.
        /// </param>
        /// <param name="credential">
        /// The credential to setup the secure channel.
        /// </param>
        /// <param name="requestConfidentiality">
        /// A Boolean setting that indicates that the caller is requiring 
        /// encryption of messages so that they cannot be read while in transit. 
        /// Requesting this service results in Netlogon encrypting the message.
        /// </param>
        /// <param name="clientCapabilities">
        /// The client capability.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// Thrown when domainName, serverName or credential is null.
        /// </exception>
        public NrpcClientSecurityContext(
            string domainName,
            string serverName,
            MachineAccountCredential credential,
            bool requestConfidentiality,
            NrpcNegotiateFlags clientCapabilities)
        {
            if (string.IsNullOrWhiteSpace(domainName))
            {
                throw new ArgumentNullException("domainName cannot be null or empty");
            }
            if (string.IsNullOrWhiteSpace(serverName))
            {
                throw new ArgumentNullException("serverName cannot be null or empty");
            }
            if (credential == null)
            {
                throw new ArgumentNullException("credential cannot be null");
            }

            this.nrpc = NrpcClient.CreateNrpcClient(domainName);
            this.nrpc.Context.PrimaryName = serverName;
            this.nrpc.Context.SealSecureChannel = requestConfidentiality;
            this.nrpc.Context.NegotiateFlags = clientCapabilities;

            this.credential = credential;
            this.secureChannelType = _NETLOGON_SECURE_CHANNEL_TYPE.WorkstationSecureChannel;
        }
        public void APDS_KERBEROS_PAC_VALIDATION()
        {
            base.Logging();

            BaseTestSite.Log.Add(LogEntryKind.Comment, "Construct Kerberos client for testing.");
            client = new KerberosTestClient(
                this.testConfig.LocalRealm.RealmName,
                this.testConfig.LocalRealm.Admin.Username,
                this.testConfig.LocalRealm.Admin.Password,
                KerberosAccountType.User,
                testConfig.LocalRealm.KDC[0].IPAddress,
                testConfig.LocalRealm.KDC[0].Port,
                testConfig.TransportType,
                testConfig.SupportedOid);
            BaseTestSite.Log.Add(LogEntryKind.Comment, "Create and send AS request with no PA data.");
            KdcOptions options = KdcOptions.FORWARDABLE | KdcOptions.CANONICALIZE | KdcOptions.RENEWABLE;
            client.SendAsRequest(options, null);
            //Recieve preauthentication required error
            METHOD_DATA methodData;
            KerberosKrbError krbError = client.ExpectPreauthRequiredError(out methodData);
            //Create sequence of PA data
            string timeStamp = KerberosUtility.CurrentKerberosTime.Value;
            PaEncTimeStamp paEncTimeStamp = new PaEncTimeStamp(timeStamp, 0, this.client.Context.SelectedEType, this.client.Context.CName.Password, this.client.Context.CName.Salt);
            PaPacRequest paPacRequest = new PaPacRequest(true);
            Asn1SequenceOf<PA_DATA> seqOfPaData = new Asn1SequenceOf<PA_DATA>(new PA_DATA[] { paEncTimeStamp.Data, paPacRequest.Data});
            BaseTestSite.Log.Add(LogEntryKind.Comment, "Create and send AS request with PA data.");
            client.SendAsRequest(options, seqOfPaData);
            KerberosAsResponse asResponse = client.ExpectAsResponse();
            BaseTestSite.Assert.IsNotNull(asResponse.Response.ticket, "AS response should contain a TGT.");
            BaseTestSite.Log.Add(LogEntryKind.Comment, "Create and send TGS request.");
            client.SendTgsRequest(this.testConfig.LocalRealm.ClientComputer.DefaultServiceName, options);
            KerberosTgsResponse tgsResponse = client.ExpectTgsResponse();
            EncryptionKey key = testConfig.QueryKey(this.testConfig.LocalRealm.ClientComputer.DefaultServiceName, this.testConfig.LocalRealm.RealmName, this.client.Context.SelectedEType);
            tgsResponse.DecryptTicket(key);

            if (this.testConfig.IsKileImplemented)
            {
                //Get Server and KDC Signatures
                PacServerSignature pacServerSignature = null;
                PacKdcSignature pacKdcSignature = null;
                BaseTestSite.Assert.IsNotNull(tgsResponse.TicketEncPart.authorization_data, "The ticket contains Authorization data.");
                AdWin2KPac adWin2kPac = FindOneInAuthData<AdWin2KPac>(tgsResponse.TicketEncPart.authorization_data.Elements);
                BaseTestSite.Assert.IsNotNull(adWin2kPac, "The Authorization data contains AdWin2KPac.");
                foreach (var buf in adWin2kPac.Pac.PacInfoBuffers)
                {
                    if (buf is PacServerSignature)
                    {
                        pacServerSignature = buf as PacServerSignature;
                    }
                    if (buf is PacKdcSignature)
                    {
                        pacKdcSignature = buf as PacKdcSignature;
                    }
                }

                BaseTestSite.Log.Add(LogEntryKind.Comment, "Establish Secure Channel.");
                NrpcClient nrpcClient = NrpcClient.CreateNrpcClient(this.testConfig.LocalRealm.RealmName);
                ushort[] endPointList = NrpcUtility.QueryNrpcTcpEndpoint(testConfig.LocalRealm.KDC[0].FQDN);
                ushort endPoint = endPointList[0];
                MachineAccountCredential machineCredential = new MachineAccountCredential(
                    this.testConfig.LocalRealm.RealmName,
                    testConfig.LocalRealm.ClientComputer.FQDN.Split('.')[0],
                    testConfig.LocalRealm.ClientComputer.Password);

                nrpcClient.Context.NegotiateFlags = NrpcNegotiateFlags.SupportsAESAndSHA2
                    | NrpcNegotiateFlags.SupportsConcurrentRpcCalls
                    | NrpcNegotiateFlags.SupportsCrossForestTrusts
                    | NrpcNegotiateFlags.SupportsGenericPassThroughAuthentication
                    | NrpcNegotiateFlags.SupportsNetrLogonGetDomainInfo
                    | NrpcNegotiateFlags.SupportsNetrLogonSendToSam
                    | NrpcNegotiateFlags.SupportsNetrServerPasswordSet2
                    | NrpcNegotiateFlags.SupportsRC4
                    | NrpcNegotiateFlags.SupportsRefusePasswordChange
                    | NrpcNegotiateFlags.SupportsRodcPassThroughToDifferentDomains
                    | NrpcNegotiateFlags.SupportsSecureRpc
                    | NrpcNegotiateFlags.SupportsStrongKeys
                    | NrpcNegotiateFlags.SupportsTransitiveTrusts;

                NrpcClientSecurityContext securityContext = new NrpcClientSecurityContext(
                    this.testConfig.LocalRealm.RealmName,
                    testConfig.LocalRealm.KDC[0].FQDN.Split('.')[0],
                    machineCredential,
                    true,
                    nrpcClient.Context.NegotiateFlags);

                nrpcClient.BindOverTcp(testConfig.LocalRealm.KDC[0].FQDN, endPoint, securityContext, TimeSpan.FromMilliseconds(600000));

                _NETLOGON_LOGON_INFO_CLASS logonLevel = _NETLOGON_LOGON_INFO_CLASS.NetlogonGenericInformation;
                _NETLOGON_VALIDATION_INFO_CLASS validationLevel = _NETLOGON_VALIDATION_INFO_CLASS.NetlogonValidationGenericInfo2;
                _NETLOGON_VALIDATION? validationInfomation;
                byte? authoritative;
                NrpcNetrLogonSamLogonExtraFlags? extraFlags = NrpcNetrLogonSamLogonExtraFlags.None;

                BaseTestSite.Log.Add(LogEntryKind.Comment, "Create valid KERB_VERIFY_PAC_REQUEST.");
                KERB_VERIFY_PAC_REQUEST kerberosReq = ApdsUtility.CreateKerbVerifyPacRequest(pacServerSignature.NativePacSignatureData, pacKdcSignature.NativePacSignatureData);
                //Create Kerberos Validation Logon Info
                _NETLOGON_LEVEL netlogonLevel = ApdsUtility.CreatePacLogonInfo(
                    NrpcParameterControlFlags.AllowLogonWithComputerAccount,
                    this.testConfig.LocalRealm.RealmName,
                    this.testConfig.LocalRealm.Admin.Username,
                    testConfig.LocalRealm.KDC[0].FQDN.Split('.')[0],
                    kerberosReq);
                _NETLOGON_LEVEL encryptedLogonLevel = nrpcClient.EncryptNetlogonLevel(
                    (_NETLOGON_LOGON_INFO_CLASS)logonLevel,
                    netlogonLevel);
                BaseTestSite.Log.Add(LogEntryKind.Comment, "Call NetrLogonSamLogonEx for Kerberos pac validation.");
                NtStatus result = nrpcClient.NetrLogonSamLogonEx(
                    nrpcClient.Handle,
                    testConfig.LocalRealm.KDC[0].FQDN.Split('.')[0],
                    testConfig.LocalRealm.ClientComputer.FQDN.Split('.')[0],
                    logonLevel,
                    encryptedLogonLevel,
                    validationLevel,
                    out validationInfomation,
                    out authoritative,
                    ref extraFlags);
                BaseTestSite.Assert.AreEqual(NtStatus.STATUS_SUCCESS, result, "[MS-APDS]3.2.5.2 If the checksum is verified, the DC MUST return STATUS_SUCCESS.");
                BaseTestSite.Assert.IsNull(validationInfomation.Value.ValidationGeneric2[0].ValidationData, "[MS-APDS]3.2.5.2 There is no return message.");

                BaseTestSite.Log.Add(LogEntryKind.Comment, "Create invalid KERB_VERIFY_PAC_REQUEST.");
                kerberosReq = ApdsUtility.CreateKerbVerifyPacRequest(pacKdcSignature.NativePacSignatureData, pacKdcSignature.NativePacSignatureData);
                //Create Kerberos Validation Logon Info
                netlogonLevel = ApdsUtility.CreatePacLogonInfo(
                    NrpcParameterControlFlags.AllowLogonWithComputerAccount,
                    this.testConfig.LocalRealm.RealmName,
                    this.testConfig.LocalRealm.Admin.Username,
                    testConfig.LocalRealm.KDC[0].FQDN.Split('.')[0],
                    kerberosReq);
                encryptedLogonLevel = nrpcClient.EncryptNetlogonLevel(
                    (_NETLOGON_LOGON_INFO_CLASS)logonLevel,
                    netlogonLevel);
                BaseTestSite.Log.Add(LogEntryKind.Comment, "Call NetrLogonSamLogonEx for Kerberos pac validation.");
                result = nrpcClient.NetrLogonSamLogonEx(
                    nrpcClient.Handle,
                    testConfig.LocalRealm.KDC[0].FQDN.Split('.')[0],
                    testConfig.LocalRealm.ClientComputer.FQDN.Split('.')[0],
                    logonLevel,
                    encryptedLogonLevel,
                    validationLevel,
                    out validationInfomation,
                    out authoritative,
                    ref extraFlags);
                BaseTestSite.Assert.AreEqual(NtStatus.STATUS_LOGON_FAILURE, result, "[MS-APDS]3.2.5.2 If the checksum verification fails, the DC MUST return an error code, STATUS_LOGON_FAILURE (section 2.2) as the return value to the Netlogon Generic Pass-through method.");
            }
        }
 /// <summary>
 /// Initialize an instance of NrpcClientSecurityContext class. 
 /// By calling this constructor, the class will setup a new secure 
 /// channel between client and server.
 /// </summary>
 /// <param name="domainName">
 /// The NRPC domain name.
 /// </param>
 /// <param name="serverName">
 /// The NRPC server name.
 /// </param>
 /// <param name="credential">
 /// The credential to setup the secure channel.
 /// </param>
 /// <param name="requestConfidentiality">
 /// A Boolean setting that indicates that the caller is requiring 
 /// encryption of messages so that they cannot be read while in transit. 
 /// Requesting this service results in Netlogon encrypting the message.
 /// </param>
 /// <param name="clientCapabilities">
 /// The client capability.
 /// </param>
 /// <param name="secureChannelType">
 /// the type of secure channel to use in a logon transaction.
 /// </param>
 /// <exception cref="ArgumentNullException">
 /// Thrown when domainName, serverName or credential is null.
 /// </exception>
 public NrpcClientSecurityContext(
     string domainName,
     string serverName,
     MachineAccountCredential credential,
     bool requestConfidentiality,
     NrpcNegotiateFlags clientCapabilities,
     _NETLOGON_SECURE_CHANNEL_TYPE secureChannelType
     )
     : this(domainName,
       serverName,
       credential,
       requestConfidentiality,
       clientCapabilities)
 {
     this.secureChannelType = secureChannelType;
 }