A generic session manager object for a server.
Inheritance: IDisposable
Esempio n. 1
0
 /// <summary>
 /// Initializes a new instance of the <see cref="SystemContext"/> class.
 /// </summary>
 /// <param name="server">The server.</param>
 /// <param name="session">The session.</param>
 public ServerSystemContext(IServerInternal server, Session session)
 {
     OperationContext = null;
     SessionId = session.Id;
     UserIdentity = session.Identity;
     PreferredLocales = session.PreferredLocales;
     NamespaceUris = server.NamespaceUris;
     ServerUris = server.ServerUris;
     TypeTable = server.TypeTree;
     EncodeableFactory = server.Factory;
 }
        /// <summary>
        /// Creates a new queue.
        /// </summary>
        public SessionPublishQueue(IServerInternal server, Session session, int maxPublishRequests)
        {
            if (server == null)  throw new ArgumentNullException("server");
            if (session == null) throw new ArgumentNullException("session");

            m_server              = server;
            m_session             = session;
            m_publishEvent        = new ManualResetEvent(false);
            m_queuedRequests      = new LinkedList<QueuedRequest>();
            m_queuedSubscriptions = new List<QueuedSubscription>();
            m_maxPublishRequests  = maxPublishRequests;
        }
		/// <summary>
		/// Initializes the object with its node type.
		/// </summary>
        public MemoryBufferMonitoredItem(
            IServerInternal     server,
            INodeManager        nodeManager,
            object              mangerHandle,
            uint                offset,
            uint                subscriptionId,
            uint                id,
            Session             session,
            ReadValueId         itemToMonitor,
            DiagnosticsMasks    diagnosticsMasks,
            TimestampsToReturn  timestampsToReturn,
            MonitoringMode      monitoringMode,
            uint                clientHandle,
            MonitoringFilter    originalFilter,
            MonitoringFilter    filterToUse,
            Range               range,
            double              samplingInterval,
            uint                queueSize,
            bool                discardOldest,
            double              minimumSamplingInterval)
        :
            base(
                server,
                nodeManager,
                mangerHandle,
                subscriptionId,
                id,
                session,
                itemToMonitor,
                diagnosticsMasks,
                timestampsToReturn,
                monitoringMode,
                clientHandle,
                originalFilter,
                filterToUse,
                range,
                samplingInterval,
                queueSize,
                discardOldest,
                minimumSamplingInterval)
		{
            m_offset = offset;
        }
        /// <summary>
        /// Initializes the context with a session.
        /// </summary>
        /// <param name="requestHeader">The request header.</param>
        /// <param name="requestType">Type of the request.</param>
        /// <param name="session">The session.</param>
        public OperationContext(RequestHeader requestHeader, RequestType requestType, Session session)
        {
            if (requestHeader == null) throw new ArgumentNullException("requestHeader");
            if (session == null)       throw new ArgumentNullException("session");
            
            m_channelContext     = SecureChannelContext.Current;
            m_session            = session;
            m_identity           = session.EffectiveIdentity;
            m_preferredLocales   = session.PreferredLocales;
            m_diagnosticsMask    = (DiagnosticsMasks)requestHeader.ReturnDiagnostics;
            m_stringTable        = new StringTable();
            m_auditLogEntryId    = requestHeader.AuditEntryId;
            m_requestId          = Utils.IncrementIdentifier(ref s_lastRequestId);
            m_requestType        = requestType;
            m_clientHandle       = requestHeader.RequestHandle;
            m_operationDeadline  = DateTime.MaxValue;

            if (requestHeader.TimeoutHint > 0)
            {
                m_operationDeadline = DateTime.UtcNow.AddMilliseconds(requestHeader.TimeoutHint);
            }
        }
Esempio n. 5
0
        /// <summary>
        /// Called when a client tries to change its user identity.
        /// </summary>
        private void SessionManager_ImpersonateUser(Session session, ImpersonateEventArgs args)
        {
            // check for a user name token.
            UserNameIdentityToken userNameToken = args.NewIdentity as UserNameIdentityToken;

            if (userNameToken != null)
            {
                VerifyPassword(userNameToken.UserName, userNameToken.DecryptedPassword);
                args.Identity = new UserIdentity(userNameToken);
                return;
            }
        }
        /// <summary>
        /// Called when a client tries to change its user identity.
        /// </summary>
        private void SessionManager_ImpersonateUser(Session session, ImpersonateEventArgs args)
        {
            // check for a WSS token.
            IssuedIdentityToken wssToken = args.NewIdentity as IssuedIdentityToken;

            if (wssToken != null)
            {
                SecurityToken kerberosToken = ParseAndVerifyKerberosToken(wssToken.DecryptedTokenData);
                args.Identity = new UserIdentity(kerberosToken);
                Utils.Trace("Kerberos Token Accepted: {0}", args.Identity.DisplayName);
                return;
            }

            // check for a user name token.
            UserNameIdentityToken userNameToken = args.NewIdentity as UserNameIdentityToken;

            if (userNameToken != null)
            {
                VerifyPassword(userNameToken.UserName, userNameToken.DecryptedPassword);
                args.Identity = new UserIdentity(userNameToken);
                Utils.Trace("UserName Token Accepted: {0}", args.Identity.DisplayName);
                return;
            }

            // check for x509 user token.
            X509IdentityToken x509Token = args.NewIdentity as X509IdentityToken;

            if (x509Token != null)
            {
                VerifyCertificate(x509Token.Certificate);
                args.Identity = new UserIdentity(x509Token);
                Utils.Trace("X509 Token Accepted: {0}", args.Identity.DisplayName);
                return;
            }
        }
Esempio n. 7
0
        /// <summary>
        /// Creates a copy of the context that can be used with the specified session.
        /// </summary>
        /// <param name="session">The session to use.</param>
        /// <returns>
        /// A copy of the system context that references the new operation context.
        /// </returns>
        public ServerSystemContext Copy(Session session)
        {
            ServerSystemContext copy = (ServerSystemContext)MemberwiseClone();

            OperationContext = null;

            if (session != null)
            {
                SessionId = session.Id;
                UserIdentity = session.Identity;
                PreferredLocales = session.PreferredLocales;
            }
            else
            {
                SessionId = null;
                UserIdentity = null;
                PreferredLocales = null;
            }

            return copy;
        }
        /// <summary>
        /// Periodically checks if the sessions have timed out.
        /// </summary>
        private void MonitorSessions(object data)
        {
            try
            {
                Utils.Trace("Server: Session Monitor Thread Started.");

                int sleepCycle = Convert.ToInt32(data, CultureInfo.InvariantCulture);

                do
                {
                    Session[] sessions = null;

                    lock (m_lock)
                    {
                        sessions = new Session[m_sessions.Count];
                        m_sessions.Values.CopyTo(sessions, 0);
                    }

                    for (int ii = 0; ii < sessions.Length; ii++)
                    {
                        if (sessions[ii].HasExpired)
                        {
                            // update diagnostics.
                            lock (m_server.DiagnosticsLock)
                            {
                                m_server.ServerDiagnostics.SessionTimeoutCount++;
                            }
                         
                            m_server.CloseSession(null, sessions[ii].Id, false);
                        }
                    }

                    if (m_shutdownEvent.WaitOne(sleepCycle))
                    {
                        Utils.Trace("Server: Session Monitor Thread Exited Normally.");
                        break;
                    }
                }
                while (true);
            }
            catch (Exception e)
            {
                Utils.Trace(e, "Server: Session Monitor Thread Exited Unexpectedly");
            }
        }
        /// <summary>
        /// Activates an existing session
        /// </summary>
        public virtual bool ActivateSession(
            OperationContext context,
            NodeId authenticationToken,
            SignatureData clientSignature,
            List <SoftwareCertificate> clientSoftwareCertificates,
            ExtensionObject userIdentityToken,
            SignatureData userTokenSignature,
            StringCollection localeIds,
            out byte[] serverNonce)
        {
            serverNonce = null;

            Session           session         = null;
            UserIdentityToken newIdentity     = null;
            UserTokenPolicy   userTokenPolicy = null;

            lock (m_lock)
            {
                // find session.
                if (!m_sessions.TryGetValue(authenticationToken, out session))
                {
                    throw new ServiceResultException(StatusCodes.BadSessionClosed);
                }

                // create new server nonce.
                serverNonce = Utils.Nonce.CreateNonce((uint)m_minNonceLength);

                // validate before activation.
                session.ValidateBeforeActivate(
                    context,
                    clientSignature,
                    clientSoftwareCertificates,
                    userIdentityToken,
                    userTokenSignature,
                    localeIds,
                    serverNonce,
                    out newIdentity,
                    out userTokenPolicy);
            }

            IUserIdentity identity          = null;
            IUserIdentity effectiveIdentity = null;
            ServiceResult error             = null;

            try
            {
                // check if the application has a callback which validates the identity tokens.
                lock (m_eventLock)
                {
                    if (m_ImpersonateUser != null)
                    {
                        ImpersonateEventArgs args = new ImpersonateEventArgs(newIdentity, userTokenPolicy);
                        m_ImpersonateUser(session, args);

                        if (ServiceResult.IsBad(args.IdentityValidationError))
                        {
                            error = args.IdentityValidationError;
                        }
                        else
                        {
                            identity          = args.Identity;
                            effectiveIdentity = args.EffectiveIdentity;
                        }
                    }
                }

                // parse the token manually if the identity is not provided.
                if (identity == null)
                {
                    identity = new UserIdentity(newIdentity);
                }

                // use the identity as the effectiveIdentity if not provided.
                if (effectiveIdentity == null)
                {
                    effectiveIdentity = identity;
                }
            }
            catch (Exception e)
            {
                if (e is ServiceResultException)
                {
                    throw e;
                }

                throw ServiceResultException.Create(
                          StatusCodes.BadIdentityTokenInvalid,
                          e,
                          "Could not validate user identity token: {0}",
                          newIdentity);
            }

            // check for validation error.
            if (ServiceResult.IsBad(error))
            {
                throw new ServiceResultException(error);
            }

            // activate session.
            bool contextChanged = session.Activate(
                context,
                clientSoftwareCertificates,
                newIdentity,
                identity,
                effectiveIdentity,
                localeIds,
                serverNonce);

            // raise session related event.
            if (contextChanged)
            {
                RaiseSessionEvent(session, SessionEventReason.Activated);
            }

            // indicates that the identity context for the session has changed.
            return(contextChanged);
        }
Esempio n. 10
0
        /// <summary>
        /// Initializes the object.
        /// </summary>
        public Subscription(
            IServerInternal  server,
            Session          session,
            uint             subscriptionId,
			double           publishingInterval,
            uint             maxLifetimeCount,
			uint             maxKeepAliveCount,
            uint             maxNotificationsPerPublish,
            byte             priority,
			bool             publishingEnabled,
            uint             maxMessageCount)
        {       
            if (server == null)  throw new ArgumentNullException("server");
            if (session == null) throw new ArgumentNullException("session");

            m_server                      = server;
            m_session                     = session;
            m_id                          = subscriptionId;
            m_publishingInterval          = publishingInterval;
            m_maxLifetimeCount            = maxLifetimeCount;
            m_maxKeepAliveCount           = maxKeepAliveCount;
            m_maxNotificationsPerPublish  = maxNotificationsPerPublish;
            m_publishingEnabled           = publishingEnabled;
            m_priority                    = priority;
            m_publishTimerExpiry          = HiResClock.UtcNow.Ticks/TimeSpan.TicksPerMillisecond + (long)publishingInterval;
            m_keepAliveCounter            = maxKeepAliveCount;
            m_lifetimeCounter             = 0;
            m_waitingForPublish           = false;
            m_maxMessageCount             = maxMessageCount;
            m_sentMessages                = new List<NotificationMessage>();
            
            m_monitoredItems              = new Dictionary<uint,LinkedListNode<IMonitoredItem>>();
            m_itemsToCheck                = new LinkedList<IMonitoredItem>();
            m_itemsToPublish              = new LinkedList<IMonitoredItem>();
            m_itemsToTrigger              = new Dictionary<uint,List<ITriggeredMonitoredItem>>();

            // m_itemsReadyToPublish         = new Queue<IMonitoredItem>();
            // m_itemsNotificationsAvailable = new LinkedList<IMonitoredItem>();
            m_sequenceNumber              = 1;
            
            // initialize diagnostics.
            m_diagnostics = new SubscriptionDiagnosticsDataType();

            m_diagnostics.SessionId = m_session.Id;
            m_diagnostics.SubscriptionId = m_id;
            m_diagnostics.Priority = priority;
            m_diagnostics.PublishingInterval = publishingInterval;
            m_diagnostics.MaxKeepAliveCount = maxKeepAliveCount;
            m_diagnostics.MaxLifetimeCount = maxLifetimeCount;
            m_diagnostics.MaxNotificationsPerPublish = maxNotificationsPerPublish;
            m_diagnostics.PublishingEnabled = publishingEnabled;
            m_diagnostics.ModifyCount = 0;
            m_diagnostics.EnableCount = 0;
            m_diagnostics.DisableCount = 0;
            m_diagnostics.RepublishMessageRequestCount = 0;
            m_diagnostics.RepublishMessageCount = 0;
            m_diagnostics.TransferRequestCount = 0;
            m_diagnostics.TransferredToSameClientCount = 0;
            m_diagnostics.TransferredToAltClientCount = 0;
            m_diagnostics.PublishRequestCount = 0;
            m_diagnostics.DataChangeNotificationsCount = 0;
            m_diagnostics.EventNotificationsCount = 0;
            m_diagnostics.NotificationsCount = 0;
            m_diagnostics.LatePublishRequestCount = 0;
            m_diagnostics.CurrentKeepAliveCount = 0;
            m_diagnostics.CurrentLifetimeCount = 0;
            m_diagnostics.UnacknowledgedMessageCount = 0;
            m_diagnostics.DiscardedMessageCount = 0;
            m_diagnostics.MonitoredItemCount = 0;
            m_diagnostics.DisabledMonitoredItemCount = 0;
            m_diagnostics.MonitoringQueueOverflowCount = 0;
            m_diagnostics.NextSequenceNumber = (uint)m_sequenceNumber;

            ServerSystemContext systemContext = m_server.DefaultSystemContext.Copy(session);

            m_diagnosticsId = server.DiagnosticsNodeManager.CreateSubscriptionDiagnostics(
                systemContext,
                m_diagnostics,
                OnUpdateDiagnostics);
            
            // TraceState("CREATED");
        }
        /// <summary>
        /// Called when a client tries to change its user identity.
        /// </summary>
        private void SessionManager_ImpersonateUser(Session session, ImpersonateEventArgs args)
        {
            // check for a user name token.
            UserNameIdentityToken userNameToken = args.NewIdentity as UserNameIdentityToken;

            if (userNameToken != null)
            {
                VerifyPassword(userNameToken.UserName, userNameToken.DecryptedPassword);
                args.Identity = new UserIdentity(userNameToken);
                return;
            }

            // check for x509 user token.
            X509IdentityToken x509Token = args.NewIdentity as X509IdentityToken;

            if (x509Token != null)
            {
                VerifyCertificate(x509Token.Certificate);
                args.Identity = new UserIdentity(x509Token);
                Utils.Trace("X509 Token Accepted: {0}", args.Identity.DisplayName);
                return;
            }

        }
 void PrintSessionStatus(Session session, string reason, bool lastContact = false)
 {
     lock (session.DiagnosticsLock)
     {
         string item = String.Format("{0,9}:{1,20}:", reason, session.SessionDiagnostics.SessionName);
         if (lastContact)
         {
             item += String.Format(":{0:HH:mm:ss}", session.SessionDiagnostics.ClientLastContactTime.ToLocalTime());
         }
         else
         {
             if (session.Identity != null)
             {
                 item += String.Format(":{0,20}", session.Identity.DisplayName);
             }
             item += String.Format(":{0}", session.Id);
         }
         Console.WriteLine(item);
     }
 }
 private void EventStatus(Session session, SessionEventReason reason)
 {
     lastEventTime = DateTime.UtcNow;
     PrintSessionStatus(session, reason.ToString());
 }
 /// <summary>
 /// Initializes the context with a session.
 /// </summary>
 /// <param name="session">The session.</param>
 /// <param name="diagnosticsMasks">The diagnostics masks.</param>
 public OperationContext(Session session, DiagnosticsMasks diagnosticsMasks)
 {
     if (session == null) throw new ArgumentNullException("session");
     
     m_channelContext    = null;
     m_session           = session;
     m_identity          = session.EffectiveIdentity;
     m_preferredLocales  = session.PreferredLocales;
     m_diagnosticsMask   = diagnosticsMasks;
     m_stringTable       = new StringTable();
     m_auditLogEntryId   = null;
     m_requestId         = 0;
     m_requestType       = RequestType.Unknown;
     m_clientHandle      = 0;
     m_operationDeadline = DateTime.MaxValue;
 }
Esempio n. 15
0
        /// <summary>
        /// Check whether it is an acceptable session.
        /// </summary>
        /// <param name="session">The session.</param>
        /// <param name="args">IdentityToken.</param>
        void SessionManager_ImpersonateUser(Session session, ImpersonateEventArgs args)
        {
            switch (args.UserTokenPolicy.TokenType)
            {
                case UserTokenType.UserName:

                    UserNameIdentityToken token = args.NewIdentity as UserNameIdentityToken;

                    if (!m_userNameValidator.Validate(token))
                    {   // Bad user access denied.
                        // construct translation object with default text.
                        TranslationInfo info = new TranslationInfo(
                            "InvalidUserInformation",
                            "en-US",
                            "Specified user information are not valid.  UserName='******'.",
                            token.UserName);

                        // create an exception with a vendor defined sub-code.
                        throw new ServiceResultException(new ServiceResult(
                            StatusCodes.BadUserAccessDenied,
                            "InvalidUserInformation",
                            "http://opcfoundation.org",
                            new LocalizedText(info)));
                    }
                    break;
                default:
                    break;
            }
        }
        /// <summary>
        /// Validates request header and returns a request context.
        /// </summary>
        /// <remarks>
        /// This method verifies that the session id valid and that it uses secure channel id
        /// associated with with current thread. It also verifies that the timestamp is not too
        /// and that the sequence number is not out of order (update requests only).
        /// </remarks>
        public virtual OperationContext ValidateRequest(RequestHeader requestHeader, RequestType requestType)
        {
            if (requestHeader == null)
            {
                throw new ArgumentNullException("requestHeader");
            }

            Session session = null;

            try
            {
                lock (m_lock)
                {
                    // check for create session request.
                    if (requestType == RequestType.CreateSession || requestType == RequestType.ActivateSession)
                    {
                        return(new OperationContext(requestHeader, requestType));
                    }

                    // find session.
                    if (!m_sessions.TryGetValue(requestHeader.AuthenticationToken, out session))
                    {
                        var Handler = m_ValidateSessionLessRequest;

                        if (Handler != null)
                        {
                            var args = new ValidateSessionLessRequestEventArgs(requestHeader.AuthenticationToken, requestType);
                            Handler(this, args);

                            if (ServiceResult.IsBad(args.Error))
                            {
                                throw new ServiceResultException(args.Error);
                            }

                            return(new OperationContext(requestHeader, requestType, args.Identity));
                        }

                        throw new ServiceResultException(StatusCodes.BadSessionIdInvalid);
                    }

                    // validate request header.
                    session.ValidateRequest(requestHeader, requestType);

                    // return context.
                    return(new OperationContext(requestHeader, requestType, session));
                }
            }
            catch (Exception e)
            {
                ServiceResultException sre = e as ServiceResultException;

                if (sre != null && sre.StatusCode == StatusCodes.BadSessionNotActivated)
                {
                    if (session != null)
                    {
                        CloseSession(session.Id);
                    }
                }

                throw new ServiceResultException(e, StatusCodes.BadUnexpectedError);
            }
        }
        /// <summary>
        /// Creates a new instance of a session.
        /// </summary>
        protected virtual Session CreateSession(
            OperationContext          context,
            IServerInternal           server,
            X509Certificate2          serverCertificate,
            NodeId                    sessionCookie,
            byte[]                    serverNonce,
            string                    sessionName, 
            ApplicationDescription    clientDescription,
            string                    endpointUrl,
            X509Certificate2          clientCertificate,
            double                    sessionTimeout,
            uint                      maxResponseMessageSize,
            int                       maxRequestAge, // TBD - Remove unused parameter.
            int                       maxContinuationPoints) // TBD - Remove unused parameter.
        {
            Session session = new Session(
                context,
                m_server,
                serverCertificate,
                sessionCookie,
                serverNonce,
                sessionName,
                clientDescription,
                endpointUrl,
                clientCertificate,
                sessionTimeout,
                maxResponseMessageSize,
                m_maxRequestAge,
                m_maxBrowseContinuationPoints,
                m_maxHistoryContinuationPoints);

            return session;
        }
        /// <summary>
        /// Raises an event related to a session.
        /// </summary>
        protected virtual void RaiseSessionEvent(Session session, SessionEventReason reason)
        { 
            lock (m_eventLock)
            {
                SessionEventHandler handler = null;

                switch (reason)
                {
                    case SessionEventReason.Created:   { handler = m_SessionCreated;   break; }
                    case SessionEventReason.Activated: { handler = m_SessionActivated; break; }
                    case SessionEventReason.Closing:   { handler = m_SessionClosing;   break; }
                }

                if (handler != null)
                {
                    try
                    {
                        handler(session, reason);
                    }
                    catch (Exception e)
                    {
                        Utils.Trace(e, "Session event handler raised an exception.");
                    }
                }
            } 
        }
		/// <summary>
		/// Initializes the object with its node type.
		/// </summary>
        public MonitoredItem(
            IServerInternal     server,
            INodeManager        nodeManager,
            object              mangerHandle,
            uint                subscriptionId,
            uint                id,
            Session             session,
            ReadValueId         itemToMonitor,
            DiagnosticsMasks    diagnosticsMasks,
            TimestampsToReturn  timestampsToReturn,
            MonitoringMode      monitoringMode,
            uint                clientHandle,
            MonitoringFilter    originalFilter,
            MonitoringFilter    filterToUse,
            Range               range,
            double              samplingInterval,
            uint                queueSize,
            bool                discardOldest,
            double              sourceSamplingInterval)
		{
            if (itemToMonitor == null) throw new ArgumentNullException("itemToMonitor");
            
			Initialize();
            
            m_server                  = server;
            m_nodeManager             = nodeManager;
            m_managerHandle           = mangerHandle;
            m_subscriptionId          = subscriptionId;
            m_id                      = id;
            m_session                 = session;
            m_nodeId                  = itemToMonitor.NodeId;
            m_attributeId             = itemToMonitor.AttributeId;
            m_indexRange              = itemToMonitor.IndexRange;
            m_parsedIndexRange        = itemToMonitor.ParsedIndexRange;
            m_encoding                = itemToMonitor.DataEncoding;
            m_diagnosticsMasks        = diagnosticsMasks;
            m_timestampsToReturn      = timestampsToReturn;
            m_monitoringMode          = monitoringMode;
            m_clientHandle            = clientHandle;
            m_originalFilter          = originalFilter;
            m_filterToUse             = filterToUse;
            m_range                   = 0;
            m_samplingInterval        = samplingInterval;
            m_queueSize               = queueSize;
            m_discardOldest           = discardOldest;
            m_sourceSamplingInterval  = (int)sourceSamplingInterval;
            m_calculator              = null;
            m_nextSamplingTime        = DateTime.UtcNow.Ticks;
            m_alwaysReportUpdates     = false;
            
            m_typeMask = MonitoredItemTypeMask.DataChange;

            if (originalFilter is EventFilter)
            {
                m_typeMask = MonitoredItemTypeMask.Events;

                if (itemToMonitor.NodeId == Objects.Server)
                {
                    m_typeMask |= MonitoredItemTypeMask.AllEvents;
                }
            }

            // create aggregate calculator.
            ServerAggregateFilter aggregateFilter = filterToUse as ServerAggregateFilter;

            if (filterToUse is ServerAggregateFilter)
            {
                m_calculator = m_server.AggregateManager.CreateCalculator(
                    aggregateFilter.AggregateType,
                    aggregateFilter.StartTime,
                    DateTime.MaxValue,
                    aggregateFilter.ProcessingInterval,
                    aggregateFilter.Stepped,
                    aggregateFilter.AggregateConfiguration);
            }

            if (range != null)
            {
                m_range = range.High - range.Low;
            }

            // report change to item state.
            ServerUtils.ReportCreateMonitoredItem(
                m_nodeId,
                m_id,
                m_samplingInterval,
                m_queueSize,
                m_discardOldest,
                m_filterToUse,
                m_monitoringMode);

            InitializeQueue();
		}
        /// <summary>
        /// Creates a new session.
        /// </summary>
        public virtual Session CreateSession(
            OperationContext context,
            X509Certificate2 serverCertificate,
            string sessionName,
            byte[] clientNonce,
            ApplicationDescription clientDescription,
            string endpointUrl,
            X509Certificate2 clientCertificate,
            double requestedSessionTimeout,
            uint maxResponseMessageSize,
            out NodeId sessionId,
            out NodeId authenticationToken,
            out byte[] serverNonce,
            out double revisedSessionTimeout)
        {
            sessionId             = 0;
            revisedSessionTimeout = requestedSessionTimeout;

            Session session = null;

            lock (m_lock)
            {
                // check session count.
                if (m_maxSessionCount > 0 && m_sessions.Count >= m_maxSessionCount)
                {
                    throw new ServiceResultException(StatusCodes.BadTooManySessions);
                }

                // check for same Nonce in another session
                if (clientNonce != null)
                {
                    foreach (Session sessionIterator in m_sessions.Values)
                    {
                        if (Utils.CompareNonce(sessionIterator.ClientNonce, clientNonce))
                        {
                            throw new ServiceResultException(StatusCodes.BadNonceInvalid);
                        }
                    }
                }
                // can assign a simple identifier if secured.
                authenticationToken = null;

                if (!String.IsNullOrEmpty(context.ChannelContext.SecureChannelId))
                {
                    if (context.ChannelContext.EndpointDescription.SecurityMode != MessageSecurityMode.None)
                    {
                        authenticationToken = Utils.IncrementIdentifier(ref m_lastSessionId);
                    }
                }

                // must assign a hard-to-guess id if not secured.
                if (authenticationToken == null)
                {
                    byte[] token = Utils.Nonce.CreateNonce(32);
                    authenticationToken = new NodeId(token);
                }

                // determine session timeout.
                if (requestedSessionTimeout > m_maxSessionTimeout)
                {
                    revisedSessionTimeout = m_maxSessionTimeout;
                }

                if (requestedSessionTimeout < m_minSessionTimeout)
                {
                    revisedSessionTimeout = m_minSessionTimeout;
                }

                // create server nonce.
                serverNonce = Utils.Nonce.CreateNonce((uint)m_minNonceLength);

                // assign client name.
                if (String.IsNullOrEmpty(sessionName))
                {
                    sessionName = Utils.Format("Session {0}", sessionId);
                }

                // create instance of session.
                session = CreateSession(
                    context,
                    m_server,
                    serverCertificate,
                    authenticationToken,
                    clientNonce,
                    serverNonce,
                    sessionName,
                    clientDescription,
                    endpointUrl,
                    clientCertificate,
                    revisedSessionTimeout,
                    maxResponseMessageSize,
                    m_maxRequestAge,
                    m_maxBrowseContinuationPoints);

                // get the session id.
                sessionId = session.Id;

                // save session.
                m_sessions.Add(authenticationToken, session);
            }

            // raise session related event.
            RaiseSessionEvent(session, SessionEventReason.Created);

            // return session.
            return(session);
        }