//******************************************************************************************************
// SecurityHub.cs - Gbtc
//
// Copyright © 2016, Grid Protection Alliance. All Rights Reserved.
//
// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
// the NOTICE file distributed with this work for additional information regarding copyright ownership.
// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this
// file except in compliance with the License. You may obtain a copy of the License at:
//
// http://opensource.org/licenses/MIT
//
// Unless agreed to in writing, the subject software distributed under the License is distributed on an
// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
// License for the specific language governing permissions and limitations.
//
// Code Modification History:
// ----------------------------------------------------------------------------------------------------
// 03/03/2016 - Ritchie Carroll
// Generated original version of source code.
//
//******************************************************************************************************
using System;
using System.Collections.Generic;
using System.Linq;
using GSF.Data.Model;
using GSF.Security;
using GSF.Web.Hubs;
using GSF.Web.Model;
using GSF.Web.Security;
using System.Threading.Tasks;
using GSF.Collections;
using GSF.Data;
using GSF.Diagnostics;
using GSF.TimeSeries.Statistics;
using GSF.Web.Shared.Model;
using Newtonsoft.Json.Linq;
namespace GSF.Web.Shared
{
///
/// Defines a SignalR security hub for managing users, groups and SID management.
///
[AuthorizeHubRole]
public class SharedHub : RecordOperationsHub
{
#region [ Constructors ]
///
/// Creates a new .
///
public SharedHub() :
this(null, null, null)
{
}
///
/// Creates a new with the specified logging functions.
///
/// Delegate to use to log status messages, if any.
/// Delegate to use to log exceptions, if any.
public SharedHub(Action logStatusMessageFunction, Action logExceptionFunction) :
this(null, logStatusMessageFunction, logExceptionFunction)
{
}
///
/// Creates a new with the specified and logging functions.
///
/// Setting category that contains the connection settings. Defaults to "securityProvider".
/// Delegate to use to log status messages, if any.
/// Delegate to use to log exceptions, if any.
public SharedHub(string settingsCategory, Action logStatusMessageFunction, Action logExceptionFunction) :
this(settingsCategory, logStatusMessageFunction, logExceptionFunction, true)
{
// Capture initial defaults
if ((object)logStatusMessageFunction != null && (object)s_logStatusMessageFunction == null)
s_logStatusMessageFunction = logStatusMessageFunction;
if ((object)logExceptionFunction != null && (object)s_logExceptionFunction == null)
s_logExceptionFunction = logExceptionFunction;
}
// ReSharper disable once UnusedParameter.Local
private SharedHub(string settingsCategory, Action logStatusMessageFunction, Action logExceptionFunction, bool overload) :
base(settingsCategory ?? "systemSettings", logStatusMessageFunction ?? s_logStatusMessageFunction, logExceptionFunction ?? s_logExceptionFunction)
{
}
#endregion
#region [ Methods ]
///
/// Overrides base OnConnected method to provide logging
///
///
public override Task OnConnected()
{
LogStatusMessage($"SharedHub connect by {Context.User?.Identity?.Name ?? "Undefined User"} [{Context.ConnectionId}] - count = {ConnectionCount}", UpdateType.Information, false);
return base.OnConnected();
}
///
/// Overrides base OnDisconnected method to provide logging
///
///
///
public override Task OnDisconnected(bool stopCalled)
{
if (stopCalled)
{
// Dispose any associated hub operations associated with current SignalR client
LogStatusMessage($"SharedHub disconnect by {Context.User?.Identity?.Name ?? "Undefined User"} [{Context.ConnectionId}] - count = {ConnectionCount}", UpdateType.Information, false);
}
return base.OnDisconnected(stopCalled);
}
#endregion
#region [ Static ]
// Static Fields
private static Action s_logStatusMessageFunction;
private static Action s_logExceptionFunction;
private static readonly LogPublisher s_log;
private static readonly Dictionary s_statisticReferences;
private static Statistic[] s_statistics;
// Static Constructor
static SharedHub()
{
s_log = Logger.CreatePublisher(typeof(SharedHub), MessageClass.Component);
s_statisticReferences = new Dictionary();
}
// Static Properties
///
/// Gets current default Node ID for security.
///
public static readonly Guid DefaultNodeID = AdoSecurityProvider.DefaultNodeID;
// Static Methods
private void InitializeStatistics()
{
if (s_statistics?.Length > 0)
return;
try
{
using (AdoDataConnection connection = new AdoDataConnection("systemSettings"))
{
TableOperations statistics = new TableOperations(connection);
s_statistics = statistics.QueryRecords().ToArray();
}
}
catch (Exception ex)
{
s_log.Publish(MessageLevel.Error, "InitializeStatistics", exception: ex);
}
}
#endregion
// Client-side script functionality
#region [ Company Table Operations ]
///
/// Queries company table counts
///
/// Text to filter search down to.
/// The count of the rows in the table matching the query.
[RecordOperation(typeof(Company), RecordOperation.QueryRecordCount)]
public int QueryCompanyCount(string filterText)
{
return DataContext.Table().QueryRecordCount(filterText);
}
///
/// Queries company table.
///
/// Table field label to sort on.
/// Boolean denoting direction of sort.
/// The page number to return.
/// The size of the page.
/// Text to filter search down to.
/// The rows in the table matching the query.
[RecordOperation(typeof(Company), RecordOperation.QueryRecords)]
public IEnumerable QueryCompanies(string sortField, bool ascending, int page, int pageSize, string filterText)
{
return DataContext.Table().QueryRecords(sortField, ascending, page, pageSize, filterText);
}
///
/// Deletes record from company table.
///
/// The id of the record to delete.
[AuthorizeHubRole("Administrator, Editor")]
[RecordOperation(typeof(Company), RecordOperation.DeleteRecord)]
public void DeleteCompany(int id)
{
DataContext.Table().DeleteRecord(id);
}
///
/// Creates a new Company object.
///
/// A new company instance
[RecordOperation(typeof(Company), RecordOperation.CreateNewRecord)]
public Company NewCompany()
{
return DataContext.Table().NewRecord();
}
///
/// Adds new record to company table.
///
/// The record to add.
[AuthorizeHubRole("Administrator, Editor")]
[RecordOperation(typeof(Company), RecordOperation.AddNewRecord)]
public void AddNewCompany(Company company)
{
DataContext.Table().AddNewRecord(company);
}
///
/// Updates a record in company table.
///
/// The record to update.
[AuthorizeHubRole("Administrator, Editor")]
[RecordOperation(typeof(Company), RecordOperation.UpdateRecord)]
public void UpdateCompany(Company company)
{
DataContext.Table().UpdateRecord(company);
}
#endregion
#region [ Vendor Table Operations ]
///
/// Queries vendor table count.
///
/// Text to filter search down to.
/// The count of the rows in the table matching the query.
[RecordOperation(typeof(Vendor), RecordOperation.QueryRecordCount)]
public int QueryVendorCount(string filterText)
{
return DataContext.Table().QueryRecordCount(filterText);
}
///
/// Queries vendor table records.
///
/// Table field label to sort on.
/// Boolean denoting direction of sort.
/// The page number to return.
/// The size of the page.
/// Text to filter search down to.
/// The rows in the table matching the query.
[RecordOperation(typeof(Vendor), RecordOperation.QueryRecords)]
public IEnumerable QueryVendors(string sortField, bool ascending, int page, int pageSize, string filterText)
{
return DataContext.Table().QueryRecords(sortField, ascending, page, pageSize, filterText);
}
///
/// Deletes vendor table record.
///
/// The id of the record to delete.
[AuthorizeHubRole("Administrator, Editor")]
[RecordOperation(typeof(Vendor), RecordOperation.DeleteRecord)]
public void DeleteVendor(int id)
{
DataContext.Table().DeleteRecord(id);
}
///
/// Creates new vendor object.
///
/// A new Vendor model instance.
[RecordOperation(typeof(Vendor), RecordOperation.CreateNewRecord)]
public Vendor NewVendor()
{
return DataContext.Table().NewRecord();
}
///
/// Adds new vendor record to table.
///
/// The record to add.
[AuthorizeHubRole("Administrator, Editor")]
[RecordOperation(typeof(Vendor), RecordOperation.AddNewRecord)]
public void AddNewVendor(Vendor vendor)
{
DataContext.Table().AddNewRecord(vendor);
}
///
/// Updates record in vendor table.
///
/// The record to update.
[AuthorizeHubRole("Administrator, Editor")]
[RecordOperation(typeof(Vendor), RecordOperation.UpdateRecord)]
public void UpdateVendor(Vendor vendor)
{
DataContext.Table().UpdateRecord(vendor);
}
#endregion
#region [ VendorDevice Table Operations ]
///
/// Queries vendor device table count.
///
/// Text to filter search down to.
/// The count of the rows in the table matching the query.
[RecordOperation(typeof(VendorDevice), RecordOperation.QueryRecordCount)]
public int QueryVendorDeviceCount(string filterText)
{
return DataContext.Table().QueryRecordCount(filterText);
}
///
/// Queries vendor device table records.
///
/// Table field label to sort on.
/// Boolean denoting direction of sort.
/// The page number to return.
/// The size of the page.
/// Text to filter search down to.
/// The rows in the table matching the query.
[RecordOperation(typeof(VendorDevice), RecordOperation.QueryRecords)]
public IEnumerable QueryVendorDevices(string sortField, bool ascending, int page, int pageSize, string filterText)
{
return DataContext.Table().QueryRecords(sortField, ascending, page, pageSize, filterText);
}
///
/// Deletes record from vendor device table.
///
/// The id of the record to delete.
[AuthorizeHubRole("Administrator, Editor")]
[RecordOperation(typeof(VendorDevice), RecordOperation.DeleteRecord)]
public void DeleteVendorDevice(int id)
{
DataContext.Table().DeleteRecord(id);
}
///
/// Creates new VendorDevice object.
///
/// A new VendorDevice model instance.
[RecordOperation(typeof(VendorDevice), RecordOperation.CreateNewRecord)]
public VendorDevice NewVendorDevice()
{
return DataContext.Table().NewRecord();
}
///
/// Adds new record to vendor device table.
///
/// The record to add.
[AuthorizeHubRole("Administrator, Editor")]
[RecordOperation(typeof(VendorDevice), RecordOperation.AddNewRecord)]
public void AddNewVendorDevice(VendorDevice vendorDevice)
{
DataContext.Table().AddNewRecord(vendorDevice);
}
///
/// Updates record in vendor device table.
///
/// The record to update.
[AuthorizeHubRole("Administrator, Editor")]
[RecordOperation(typeof(VendorDevice), RecordOperation.UpdateRecord)]
public void UpdateVendorDevice(VendorDevice vendorDevice)
{
DataContext.Table().UpdateRecord(vendorDevice);
}
#endregion
#region [ Statistic Formatting Operations ]
///
/// If measurement is a statistic, returns the associated Statistic record; otherwise, returns null.
///
/// Record of measurement metadata used to lookup Statistic record.
/// Associated Statistic record, if measurement is a statistic; otherwise, returns null.
///
/// For best results, this function should be called after all statistic engine sources have been registered.
/// object expected to contain a "signalid" and "signalreference" property.
///
public Statistic GetStatistic(dynamic metadataRecord)
{
Guid signalID = metadataRecord.signalid;
return s_statisticReferences.GetOrAdd(signalID, _ =>
{
string signalReference = metadataRecord.signalreference;
if (string.IsNullOrWhiteSpace(signalReference))
return null;
if (!StatisticsEngine.TryLookupStatisticSource(signalReference, out string source, out int signalIndex))
return null;
InitializeStatistics();
foreach (Statistic statistic in s_statistics)
{
if (statistic.Source.Equals(source, StringComparison.OrdinalIgnoreCase) && statistic.SignalIndex == signalIndex)
return statistic;
}
return null;
});
}
///
/// Gets the format records for statistics associated with the .
///
/// Collection of measurement metadata.
/// Array of statistical records for the .
///
/// This is usually used in conjunction with a call to
/// or applied to the "FormatRecords" property of a Json subscriptionInfo object.
/// Records in array expected to contain a "SignalID" and "SignalReference" property.
///
public IEnumerable