/// <summary> /// Activates the session and binds it to the current secure channel. /// </summary> /// <param name="context"></param> /// <param name="clientSignature"></param> /// <param name="clientSoftwareCertificates"></param> /// <param name="userIdentityToken"></param> /// <param name="userTokenSignature"></param> /// <param name="serverNonce"></param> /// <returns></returns> internal bool Activate(RequestContextModel context, SignatureData clientSignature, List <SoftwareCertificate> clientSoftwareCertificates, ExtensionObject userIdentityToken, SignatureData userTokenSignature, byte[] serverNonce) { lock (_lock) { var changed = ValidateActivation(context, clientSignature, clientSoftwareCertificates, userIdentityToken, userTokenSignature); if (!_activated) { _activated = true; } else { // Reactivation = bind to the new secure channel. _secureChannelId = context.ChannelContext.SecureChannelId; } // update server nonce. _serverNonce = serverNonce; // build list of signed certificates for audit event. var signedSoftwareCertificates = new List <SignedSoftwareCertificate>(); if (clientSoftwareCertificates != null) { foreach (var softwareCertificate in clientSoftwareCertificates) { var item = new SignedSoftwareCertificate { CertificateData = softwareCertificate.SignedCertificate.RawData }; signedSoftwareCertificates.Add(item); } } _timeoutTimer.Change(_timeout, Timeout.InfiniteTimeSpan); return(changed); } }
/// <summary> /// Create session /// </summary> /// <param name="manager"></param> /// <param name="context"></param> /// <param name="id"></param> /// <param name="endpoint"></param> /// <param name="serverCertificate"></param> /// <param name="clientNonce"></param> /// <param name="timeout"></param> /// <param name="serverNonce"></param> /// <param name="clientCertificate"></param> /// <param name="maxRequestAge"></param> /// <param name="validator"></param> public GatewaySession(SessionServices manager, RequestContextModel context, NodeId id, EndpointDescription endpoint, X509Certificate2 clientCertificate, byte[] clientNonce, X509Certificate2 serverCertificate, byte[] serverNonce, TimeSpan timeout, TimeSpan maxRequestAge, UserIdentityHandler validator) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (context.ChannelContext == null) { throw new ServiceResultException(StatusCodes.BadSecureChannelIdInvalid); } _validator = validator; _secureChannelId = context.ChannelContext.SecureChannelId; _serverNonce = serverNonce; _serverCertificate = serverCertificate; _clientCertificate = clientCertificate; _maxRequestAge = maxRequestAge; Endpoint = endpoint; Identities = new List <IUserIdentity>(); Id = id; ClientNonce = clientNonce; MessageContext = new ServiceMessageContext(); _cts = new CancellationTokenSource(); _timeout = timeout; _timeoutTimer = new Timer(o => OnTimeout(manager), null, timeout, Timeout.InfiniteTimeSpan); }
/// <summary> /// Called when a new request arrives. /// </summary> /// <param name="context"></param> public void RequestReceived(RequestContextModel context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } _requests.TryAdd(context.RequestId, context); }
/// <summary> /// Called when a request completes (normally or abnormally). /// </summary> public void RequestCompleted(RequestContextModel context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } // remove the request. _requests.TryRemove(context.RequestId, out context); }
/// <summary> /// Validate before activation /// </summary> /// <param name="context"></param> /// <param name="clientSignature"></param> /// <param name="clientSoftwareCertificates"></param> /// <param name="userIdentityToken"></param> /// <param name="userTokenSignature"></param> /// <returns></returns> private bool ValidateActivation(RequestContextModel context, SignatureData clientSignature, List <SoftwareCertificate> clientSoftwareCertificates, ExtensionObject userIdentityToken, SignatureData userTokenSignature) { // verify that a secure channel was specified. if (context.ChannelContext == null) { throw new ServiceResultException(StatusCodes.BadSecureChannelIdInvalid); } // verify that the same security policy has been used. var endpoint = context.ChannelContext.EndpointDescription; if (endpoint.SecurityPolicyUri != Endpoint.SecurityPolicyUri || endpoint.SecurityMode != Endpoint.SecurityMode) { throw new ServiceResultException(StatusCodes.BadSecurityPolicyRejected); } // verify the client signature. if (_clientCertificate != null) { VerifyClientSignature(clientSignature); } if (!_activated) { // must active the session on the channel that was used to create it. if (_secureChannelId != context.ChannelContext.SecureChannelId) { throw new ServiceResultException(StatusCodes.BadSecureChannelIdInvalid); } } else { // cannot change the certificates after activation. if (clientSoftwareCertificates != null && clientSoftwareCertificates.Count > 0) { throw new ServiceResultException(StatusCodes.BadInvalidArgument); } } // validate the user identity token. return(ValidateUserIdentityToken(userIdentityToken, userTokenSignature)); }
/// <inheritdoc/> public virtual bool ActivateSession(RequestContextModel context, NodeId authenticationToken, SignatureData clientSignature, List <SoftwareCertificate> clientSoftwareCertificates, ExtensionObject userIdentityToken, SignatureData userTokenSignature, StringCollection localeIds, out byte[] serverNonce) { // find session. GatewaySession session = null; lock (_lock) { if (!_sessions.TryGetValue(authenticationToken, out session)) { throw new ServiceResultException(StatusCodes.BadSessionClosed); } } if (session.IsClosed) { throw new ServiceResultException(StatusCodes.BadSessionClosed); } // Activate session. var nonceLength = (uint)_configuration.NonceLength; serverNonce = Utils.Nonce.CreateNonce(nonceLength); var contextChanged = session.Activate(context, clientSignature, clientSoftwareCertificates, userIdentityToken, userTokenSignature, serverNonce); if (contextChanged) { _sessionActivated?.Invoke(session, null); } // indicates that the identity context for the session has changed. return(contextChanged); }
/// <inheritdoc/> public IServerSession CreateSession(RequestContextModel context, EndpointDescription endpoint, X509Certificate2 serverCertificate, byte[] clientNonce, X509Certificate2 clientCertificate, double requestedTimeout, out NodeId sessionId, out NodeId authenticationToken, out byte[] serverNonce, out double revisedTimeout) { GatewaySession session = null; lock (_lock) { // check session count. if (_configuration.MaxSessionCount > 0 && _sessions.Count >= _configuration.MaxSessionCount) { throw new ServiceResultException(StatusCodes.BadTooManySessions); } // check for same Nonce in another session if (clientNonce != null) { foreach (var sessionIterator in _sessions.Values) { if (Utils.CompareNonce(sessionIterator.ClientNonce, clientNonce)) { throw new ServiceResultException(StatusCodes.BadNonceInvalid); } } } // Create session sessionId = new NodeId(Guid.NewGuid()); authenticationToken = new NodeId(Utils.Nonce.CreateNonce(kDefaultNonceLength)); var nonceLength = (uint)_configuration.NonceLength; serverNonce = Utils.Nonce.CreateNonce(nonceLength == 0 ? kDefaultNonceLength : nonceLength); var maxSessionTimeout = _configuration.MaxSessionTimeout.TotalMilliseconds; var minSessionTimeout = _configuration.MinSessionTimeout.TotalMilliseconds; if (requestedTimeout > maxSessionTimeout) { revisedTimeout = maxSessionTimeout; } else if (requestedTimeout < minSessionTimeout) { revisedTimeout = minSessionTimeout; } else { revisedTimeout = requestedTimeout; } // Add session to list session = new GatewaySession(this, context, sessionId, endpoint, clientCertificate, clientNonce, serverCertificate, serverNonce, TimeSpan.FromMilliseconds(revisedTimeout), _configuration.MaxRequestAge, _validateUser); if (!_sessions.TryAdd(authenticationToken, session)) { throw new ServiceResultException(StatusCodes.BadInternalError); } } _sessionCreated?.Invoke(session, null); return(session); }