//****************************************************************************************************** // SecureWindow.cs - Gbtc // // Copyright © 2012, 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://www.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: // ---------------------------------------------------------------------------------------------------- // 06/17/2010 - Pinal C. Patel // Generated original version of source code. // 08/11/2010 - Pinal C. Patel // Made key methods virtual for extensibility. // 02/16/2011 - J. Ritchie Carroll // Added ForceLoginDisplay dependency property to allow application control over pass through // authentication via WPF XAML. // 09/22/2011 - J. Ritchie Carroll // Excluded class from Mono deployments since much of WPF is not currently available. // 12/20/2012 - Starlynn Danyelle Gilliam // Modified Header. // //****************************************************************************************************** #if !MONO using System; using System.ComponentModel; using System.Security.Principal; using System.Threading; using System.Windows; using GSF.Security; namespace GSF.Windows { #region [ Enumerations ] /// /// Defines an enumeration of secure resource accessibility modes. /// public enum ResourceAccessiblityMode { /// /// Resource security is controlled via configuration. /// Configurable, /// /// Resource is always secured. /// AlwaysIncluded, /// /// Resource is never secured. /// AlwaysExcluded } #endregion /// /// Represents a WPF window secured using role-based security. /// /// /// Required config file entries: /// /// /// /// ///
/// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// /// ]]> /// /// XAML to be used for the WPF window that inherits from : /// /// /// /// /// /// /// ]]> /// /// /// public class SecureWindow : Window { #region [ Members ] // Fields private bool m_shutdownRequested; #endregion #region [ Constructors ] /// /// Initializes a new instance of the class. /// public SecureWindow() { this.Initialized += SecureWindow_Initialized; } #endregion #region [ Properties ] /// /// Gets or sets flags to force login display. /// public bool ForceLoginDisplay { get { return (bool)GetValue(ForceLoginDisplayProperty); } set { SetValue(ForceLoginDisplayProperty, value); } } /// /// Gets or sets window's secure . /// public ResourceAccessiblityMode ResourceAccessiblity { get { return (ResourceAccessiblityMode)GetValue(ResourceAccessiblityProperty); } set { SetValue(ResourceAccessiblityProperty, value); } } /// /// Gets or sets applicable roles when == . /// public string IncludedRoles { get { return (string)GetValue(IncludedRolesProperty); } set { SetValue(IncludedRolesProperty, value); } } /// /// Gets or sets the security principal used to test authentication and role membership. /// public SecurityPrincipal SecurityPrincipal { get { return (SecurityPrincipal)GetValue(SecurityPrincipalProperty); } set { SetValue(SecurityPrincipalProperty, value); } } #endregion #region [ Methods ] /// /// Gets the name of resource being accessed. /// /// Name of the resource being accessed. protected virtual string GetResourceName() { if (!string.IsNullOrEmpty(this.Name)) return Name; return GetType().Name; } private void SecureWindow_Initialized(object sender, EventArgs e) { // Don't proceed if the window is opened in design mode if (DesignerProperties.GetIsInDesignMode(this)) return; // Check if the resource is excluded from being secured string resource = GetResourceName(); if (ResourceAccessiblity != ResourceAccessiblityMode.AlwaysIncluded && (ResourceAccessiblity == ResourceAccessiblityMode.AlwaysExcluded || !SecurityProviderUtility.IsResourceSecurable(resource))) return; try { // Setup the security provider for role-based security ISecurityProvider securityProvider = SecurityProviderCache.CreateProvider(WindowsIdentity.GetCurrent().Name); securityProvider.PassthroughPrincipal = new WindowsPrincipal(WindowsIdentity.GetCurrent()); securityProvider.Authenticate(); SecurityIdentity securityIdentity = new SecurityIdentity(securityProvider); SecurityPrincipal = new SecurityPrincipal(securityIdentity); } catch (Exception ex) { ShowSecurityDialog(DisplayType.AccessDenied, "Error loading security provider: " + ex.Message); return; } // Verify that the security principal has been authenticated if (!SecurityPrincipal.Identity.IsAuthenticated || ForceLoginDisplay) { ISecurityProvider securityProvider = SecurityPrincipal.Identity.Provider; // See if user's password has expired if (securityProvider.UserData.IsDefined && securityProvider.UserData.PasswordChangeDateTime <= DateTime.UtcNow) ShowSecurityDialog(DisplayType.ChangePassword, string.Format("Your password has expired. {0} You must change your password to continue.", securityProvider.AuthenticationFailureReason)); else ShowSecurityDialog(DisplayType.Login); } // Perform a top-level permission check on the resource being accessed if (!string.IsNullOrEmpty(resource)) { // Stay in a dialog display loop until either access to resource is available or user exits while (!m_shutdownRequested && !IsResourceAccessible(resource)) { // Access to resource is denied ShowSecurityDialog(DisplayType.AccessDenied); } } } private bool IsResourceAccessible(string resource) { if (ResourceAccessiblity == ResourceAccessiblityMode.AlwaysIncluded) return SecurityPrincipal.IsInRole(IncludedRoles); return SecurityProviderUtility.IsResourceAccessible(resource, SecurityPrincipal); } private void ShowSecurityDialog(DisplayType displayType, string errorMessage = null) { SecurityPortal securityDialog = new SecurityPortal(displayType); ISecurityProvider securityProvider = SecurityPrincipal?.Identity.Provider; // Show authentication failure reason if one was defined and user didn't force another message if ((object)errorMessage == null && (object)securityProvider != null) errorMessage = securityProvider.AuthenticationFailureReason; if (!string.IsNullOrWhiteSpace(errorMessage)) { securityDialog.ProviderFailure = true; securityDialog.DisplayErrorMessage(errorMessage); } // Show the WPF security dialog if (!securityDialog.ShowDialog().GetValueOrDefault()) { // User chose to cancel security action. If the secure window has no parent, // this is root window so exit application, otherwise just close the window if ((object)this.Owner == null) { m_shutdownRequested = true; Application.Current.Shutdown(); } else { this.Close(); } } SecurityPrincipal = securityDialog.SecurityPrincipal; } #endregion #region [ Static ] // Static Fields /// /// Identifies the  dependency property. /// /// identifier for the  dependency property. public static readonly DependencyProperty ForceLoginDisplayProperty = DependencyProperty.Register("ForceLoginDisplay", typeof(bool), typeof(SecureWindow), new PropertyMetadata(false)); /// /// Identifies the  dependency property. /// /// identifier for the  dependency property. public static readonly DependencyProperty ResourceAccessiblityProperty = DependencyProperty.Register("ResourceAccessiblity", typeof(ResourceAccessiblityMode), typeof(SecureWindow), new PropertyMetadata(ResourceAccessiblityMode.Configurable)); /// /// Identifies the  dependency property. /// /// identifier for the  dependency property. public static readonly DependencyProperty IncludedRolesProperty = DependencyProperty.Register("IncludedRoles", typeof(string), typeof(SecureWindow), new PropertyMetadata("*")); /// /// Identifies the  dependency property. /// /// identifier for the  dependency property. public static readonly DependencyProperty SecurityPrincipalProperty = DependencyProperty.Register("SecurityPrincipal", typeof(SecurityPrincipal), typeof(SecureWindow)); #endregion } } #endif