//******************************************************************************************************
// SecurityPolicy.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:
// ----------------------------------------------------------------------------------------------------
// 04/22/2010 - Pinal C. Patel
// Generated original version of source code.
// 05/27/2010 - Pinal C. Patel
// Added usage example to code comments.
// Modified Evaluate() to make use of IncludedResources and ExcludedResources config file settings.
// 06/02/2010 - Pinal C. Patel
// Added authentication check to Evaluate() method.
// 08/11/2010 - Pinal C. Patel
// Made key methods virtual for extensibility.
// 10/14/2010 - Pinal C. Patel
// Modified GetResourceName() to return path and query for consistency across WCF hosting
// environments (i.e. ASP.NET, WAS, etc.).
// 12/20/2012 - Starlynn Danyelle Gilliam
// Modified Header.
//
//******************************************************************************************************
using System;
using System.Collections.Generic;
using System.IdentityModel.Claims;
using System.IdentityModel.Policy;
using System.Security;
using System.Security.Principal;
using System.ServiceModel;
using System.Threading;
using GSF.Security;
namespace GSF.ServiceModel
{
///
/// Represents an authorization policy that can be used by WCF services for enabling role-based security.
///
///
/// Common config file entries:
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
/// ]]>
///
/// Internal WCF service configuration:
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
/// ]]>
///
/// External WCF service configuration:
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
/// ]]>
///
///
///
public class SecurityPolicy : IAuthorizationPolicy
{
#region [ Members ]
// Fields
private Guid m_id;
#endregion
#region [ Constructors ]
///
/// Initializes a new instance of the class.
///
public SecurityPolicy()
{
m_id = Guid.NewGuid();
}
#endregion
#region [ Properties ]
///
/// Gets the identifier of this instance.
///
public string Id
{
get
{
return m_id.ToString();
}
}
///
/// Gets a claim set that represents the issuer of this .
///
public ClaimSet Issuer
{
get
{
return ClaimSet.System;
}
}
#endregion
#region [ Methods ]
///
/// Evaluates the and initializes security.
///
/// An object.
/// Custom state of the .
///
public virtual bool Evaluate(EvaluationContext evaluationContext, ref object state)
{
// In order for this to work properly security on the binding must be configured to use windows security.
// When this is done the caller's windows identity is available to us here and can be used to derive from
// it the security principal that can be used by WCF service code downstream for implementing security.
object property;
if (evaluationContext.Properties.TryGetValue("Identities", out property))
{
// Extract and assign the caller's windows identity to current thread if available.
IList identities = property as List;
if ((object)identities == null)
throw new SecurityException(string.Format("Null Identities in Evaluation Context for '{0}'", Thread.CurrentPrincipal.Identity));
foreach (IIdentity identity in identities)
{
if (identity is WindowsIdentity)
{
Thread.CurrentPrincipal = new WindowsPrincipal((WindowsIdentity)identity);
break;
}
}
}
string resource = GetResourceName();
if (SecurityProviderUtility.IsResourceSecurable(resource))
{
// Initialize the security principal from caller's windows identity if uninitialized.
ISecurityProvider securityProvider = SecurityProviderCache.CreateProvider(Thread.CurrentPrincipal.Identity.Name);
securityProvider.PassthroughPrincipal = Thread.CurrentPrincipal;
securityProvider.Authenticate();
// Set up the security principal to provide role-based security.
SecurityIdentity securityIdentity = new SecurityIdentity(securityProvider);
Thread.CurrentPrincipal = new SecurityPrincipal(securityIdentity);
// Setup the principal to be attached to the thread on which WCF service will execute.
evaluationContext.Properties["Principal"] = Thread.CurrentPrincipal;
// Verify that the current thread principal has been authenticated.
if (!Thread.CurrentPrincipal.Identity.IsAuthenticated)
throw new SecurityException(string.Format("Authentication failed for user '{0}'", Thread.CurrentPrincipal.Identity.Name));
// Perform a top-level permission check on the resource being accessed.
if (!SecurityProviderUtility.IsResourceAccessible(resource, Thread.CurrentPrincipal))
throw new SecurityException(string.Format("Access to '{0}' is denied", resource));
return true;
}
// Setup the principal to be attached to the thread on which WCF service will execute.
evaluationContext.Properties["Principal"] = Thread.CurrentPrincipal;
return true;
}
///
/// Gets the name of resource being accessed.
///
/// .. property value.
protected virtual string GetResourceName()
{
return OperationContext.Current.IncomingMessageHeaders.To.PathAndQuery;
}
#endregion
}
}