//******************************************************************************************************
// 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