/// <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); } }
/// <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; } }
/// <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); }
/// <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; }
/// <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); }