//****************************************************************************************************** // 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.Configuration; using GSF.Data; using GSF.Data.Model; using GSF.Identity; using GSF.Security; using GSF.Security.Model; using GSF.Web.Hubs; using GSF.Web.Model; using Microsoft.AspNet.SignalR.Hubs; namespace GSF.Web.Security { /// /// Defines a SignalR security hub for managing users, groups and SID management. /// [AuthorizeHubRole] public class SecurityHub : RecordOperationsHub { #region [ Constructors ] /// /// Creates a new . /// public SecurityHub() : 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 SecurityHub(Action logStatusMessageFunction, Action logExceptionFunction) : this(null, logStatusMessageFunction, logExceptionFunction) { } /// /// Creates a new with the specified and logging functions. /// /// Data context to use for this hub; set to null for default security provider context. /// Delegate to use to log status messages, if any. /// Delegate to use to log exceptions, if any. public SecurityHub(DataContext dataContext, Action logStatusMessageFunction, Action logExceptionFunction) : this(dataContext, 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; } private SecurityHub(DataContext dataContext, Action logStatusMessageFunction, Action logExceptionFunction, bool overload) : base(dataContext ?? new DataContext("securityProvider"), logStatusMessageFunction ?? s_logStatusMessageFunction, logExceptionFunction ?? s_logExceptionFunction) { } #endregion #region [ Static ] // Static Fields private static Action s_logStatusMessageFunction; private static Action s_logExceptionFunction; /// /// Gets current default Node ID for security. /// public static readonly Guid DefaultNodeID; // Static Constructor static SecurityHub() { CategorizedSettingsElementCollection systemSettings = ConfigurationFile.Current.Settings["systemSettings"]; // Retrieve default NodeID DefaultNodeID = Guid.Parse(systemSettings["NodeID"].Value.ToNonNullString(Guid.NewGuid().ToString())); // Determine whether the node exists in the database and create it if it doesn't if (DefaultNodeID != Guid.Empty) { using (AdoDataConnection connection = new AdoDataConnection("securityProvider")) { const string NodeCountFormat = "SELECT COUNT(*) FROM Node"; const string NodeInsertFormat = "INSERT INTO Node(Name, Description, Enabled) VALUES('Default', 'Default node', 1)"; const string NodeUpdateFormat = "UPDATE Node SET ID = {0}"; int nodeCount = connection.ExecuteScalar(NodeCountFormat) ?? 0; if (nodeCount == 0) { connection.ExecuteNonQuery(NodeInsertFormat); connection.ExecuteNonQuery(NodeUpdateFormat, connection.Guid(DefaultNodeID)); } } } } #endregion // Client-side script functionality #region [ Security Functions ] /// /// Finds the specified user account record. /// /// ID of requested user. /// Specified user account record. public UserAccount QueryUserAccount(Guid id) { return DataContext.Table().LoadRecord(id); } /// /// Finds the specified user account record by SID or database account name. /// /// SID or database account name of requested user. /// Specified user account record. public UserAccount QueryUserAccountByName(string accountName) { return DataContext.Table().QueryRecords(restriction: new RecordRestriction("Name = {0}", accountName)).FirstOrDefault(); } /// /// Searches user accounts by resolved names with no limit on total returned records. /// /// Search text to lookup. /// Search results as "IDLabel" instances - serialized as JSON [{ id : "value", label : "name" }, ...]; useful for dynamic lookup lists. public IEnumerable SearchUserAccounts(string searchText) { return SearchUserAccounts(searchText, -1); } /// /// Searches user accounts by resolved names limited to the specified number of records. /// /// Search text to lookup. /// Limit of number of record to return. /// Search results as "IDLabel" instances - serialized as JSON [{ id : "value", label : "name" }, ...]; useful for dynamic lookup lists. public IEnumerable SearchUserAccounts(string searchText, int limit) { if (limit < 1) return DataContext .Table() .QueryRecords() .Select(record => { record.Name = UserInfo.SIDToAccountName(record.Name ?? ""); return record; }) .Where(record => record.Name?.StartsWith(searchText, StringComparison.InvariantCultureIgnoreCase) ?? false) .Select(record => IDLabel.Create(record.ID.ToString(), record.Name)); return DataContext .Table() .QueryRecords() .Select(record => { record.Name = UserInfo.SIDToAccountName(record.Name ?? ""); return record; }) .Where(record => record.Name?.StartsWith(searchText, StringComparison.InvariantCultureIgnoreCase) ?? false) .Take(limit) .Select(record => IDLabel.Create(record.ID.ToString(), record.Name)); } /// /// Finds the specified security group record. /// /// ID of requested group. /// Specified security group record. public SecurityGroup QuerySecurityGroup(Guid id) { return DataContext.Table().LoadRecord(id); } /// /// Finds the specified security group record by SID or database account name. /// /// SID or database account name of requested group. /// Specified security group record. public SecurityGroup QuerySecurityGroupByName(string accountName) { return DataContext.Table().QueryRecords(restriction: new RecordRestriction("Name = {0}", accountName)).FirstOrDefault(); } /// /// Searches security groups by resolved names. /// /// Search text to lookup. /// Search results as "Labels" - serialized as JSON [{ label : "value" }, ...]; useful for dynamic lookup lists. public IEnumerable