Code:
/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / Dispatcher / SecurityImpersonationBehavior.cs / 2 / SecurityImpersonationBehavior.cs
//------------------------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- namespace System.ServiceModel.Dispatcher { using System; using System.ServiceModel.Channels; using System.ServiceModel; using System.ServiceModel.Description; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Security; using System.Security.Principal; using System.Security.Cryptography; using System.Threading; using System.IdentityModel.Claims; using System.IdentityModel.Policy; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.ServiceModel.Diagnostics; using System.ServiceModel.Security; using System.Text; using System.ServiceModel.Security.Tokens; using SafeNativeMethods = System.ServiceModel.ComIntegration.SafeNativeMethods; using Win32Error = System.ServiceModel.ComIntegration.Win32Error; using EXTENDED_NAME_FORMAT = System.ServiceModel.ComIntegration.EXTENDED_NAME_FORMAT; using SafeCloseHandle = System.IdentityModel.SafeCloseHandle; internal sealed class SecurityImpersonationBehavior { PrincipalPermissionMode principalPermissionMode; object roleProvider; bool impersonateCallerForAllOperations; DictionarydomainNameMap; Random random; const int maxDomainNameMapSize = 5; static WindowsPrincipal anonymousWindowsPrincipal; AuditLevel auditLevel = ServiceSecurityAuditBehavior.defaultMessageAuthenticationAuditLevel; AuditLogLocation auditLogLocation = ServiceSecurityAuditBehavior.defaultAuditLogLocation; bool suppressAuditFailure = ServiceSecurityAuditBehavior.defaultSuppressAuditFailure; SecurityImpersonationBehavior(DispatchRuntime dispatch) { this.principalPermissionMode = dispatch.PrincipalPermissionMode; this.impersonateCallerForAllOperations = dispatch.ImpersonateCallerForAllOperations; this.auditLevel = dispatch.MessageAuthenticationAuditLevel; this.auditLogLocation = dispatch.SecurityAuditLogLocation; this.suppressAuditFailure = dispatch.SuppressAuditFailure; if (dispatch.IsRoleProviderSet) { ApplyRoleProvider(dispatch); } this.domainNameMap = new Dictionary (maxDomainNameMapSize, StringComparer.OrdinalIgnoreCase); } public static SecurityImpersonationBehavior CreateIfNecessary(DispatchRuntime dispatch) { if (IsSecurityBehaviorNeeded(dispatch)) { return new SecurityImpersonationBehavior(dispatch); } else { return null; } } static WindowsPrincipal AnonymousWindowsPrincipal { get { if (anonymousWindowsPrincipal == null) anonymousWindowsPrincipal = new WindowsPrincipal(WindowsIdentity.GetAnonymous()); return anonymousWindowsPrincipal; } } [MethodImpl(MethodImplOptions.NoInlining)] void ApplyRoleProvider(DispatchRuntime dispatch) { this.roleProvider = dispatch.RoleProvider; } static bool IsSecurityBehaviorNeeded(DispatchRuntime dispatch) { if (IsSecurityContextImpersonationRequiredByAspNet()) { return true; } if (dispatch.PrincipalPermissionMode != PrincipalPermissionMode.None) { return true; } // Impersonation behavior is required if // 1) Contract requires it or // 2) Contract allows it and config requires it for (int i = 0; i < dispatch.Operations.Count; i++) { DispatchOperation operation = dispatch.Operations[i]; if (operation.Impersonation == ImpersonationOption.Required) { return true; } else if (operation.Impersonation == ImpersonationOption.NotAllowed) { // a validation rule enforces that config cannot require impersonation in this case return false; } } // contract allows impersonation. Return true if config requires it. return dispatch.ImpersonateCallerForAllOperations; } [MethodImpl(MethodImplOptions.NoInlining)] IPrincipal SetCurrentThreadPrincipal(ServiceSecurityContext securityContext, out bool isThreadPrincipalSet) { IPrincipal result = null; IPrincipal principal = null; if (this.principalPermissionMode == PrincipalPermissionMode.UseWindowsGroups) { principal = GetWindowsPrincipal(securityContext); } else if (this.principalPermissionMode == PrincipalPermissionMode.UseAspNetRoles) { principal = new RoleProviderPrincipal(this.roleProvider, securityContext); } else if (this.principalPermissionMode == PrincipalPermissionMode.Custom) { principal = GetCustomPrincipal(securityContext); } if (principal != null) { result = Thread.CurrentPrincipal; Thread.CurrentPrincipal = principal; isThreadPrincipalSet = true; } else { isThreadPrincipalSet = false; } return result; } [MethodImpl(MethodImplOptions.NoInlining)] static IPrincipal GetCustomPrincipal(ServiceSecurityContext securityContext) { object customPrincipal; if (securityContext.AuthorizationContext.Properties.TryGetValue(SecurityUtils.Principal, out customPrincipal) && customPrincipal is IPrincipal) return (IPrincipal)customPrincipal; else throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.NoPrincipalSpecifiedInAuthorizationContext))); } bool IsSecurityContextImpersonationRequired(ref MessageRpc rpc) { return ((rpc.Operation.Impersonation == ImpersonationOption.Required) || ((rpc.Operation.Impersonation == ImpersonationOption.Allowed) && this.impersonateCallerForAllOperations)); } static bool IsSecurityContextImpersonationRequiredByAspNet() { return ServiceHostingEnvironment.IsHosted && ServiceHostingEnvironment.AspNetCompatibilityEnabled; } /// /// Critical - calls SecurityCritical method StartImpersonation2 /// caller must ensure that this method is called at an appropriate time and that impersonationContext out param is Dispose()'d correctly /// [SecurityCritical] public void StartImpersonation(ref MessageRpc rpc, out IDisposable impersonationContext, out IPrincipal originalPrincipal, out bool isThreadPrincipalSet) { impersonationContext = null; originalPrincipal = null; isThreadPrincipalSet = false; ServiceSecurityContext securityContext; bool setThreadPrincipal = this.principalPermissionMode != PrincipalPermissionMode.None; bool isSecurityContextImpersonationOn = IsSecurityContextImpersonationRequired(ref rpc); if (setThreadPrincipal || isSecurityContextImpersonationOn) securityContext = GetAndCacheSecurityContext(ref rpc); else securityContext = null; if (setThreadPrincipal && securityContext != null) originalPrincipal = this.SetCurrentThreadPrincipal(securityContext, out isThreadPrincipalSet); if (isSecurityContextImpersonationOn || IsSecurityContextImpersonationRequiredByAspNet()) { impersonationContext = StartImpersonation2(ref rpc, securityContext, isSecurityContextImpersonationOn); } } ////// Critical - calls SecurityCritical method HostedImpersonationContext.Impersonate /// caller must ensure that this method is called at an appropriate time and that the result is Dispose()'d correctly /// [SecurityCritical] IDisposable StartImpersonation2(ref MessageRpc rpc, ServiceSecurityContext securityContext, bool isSecurityContextImpersonationOn) { IDisposable impersonationContext = null; try { if (isSecurityContextImpersonationOn) { if (securityContext == null) throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxSecurityContextPropertyMissingFromRequestMessage)), rpc.Request); WindowsIdentity impersonationToken = securityContext.WindowsIdentity; if (impersonationToken.User != null) { impersonationContext = impersonationToken.Impersonate(); } else if (securityContext.PrimaryIdentity is WindowsSidIdentity) { WindowsSidIdentity sidIdentity = (WindowsSidIdentity)securityContext.PrimaryIdentity; if (sidIdentity.SecurityIdentifier.IsWellKnown(WellKnownSidType.AnonymousSid)) { impersonationContext = new WindowsAnonymousIdentity().Impersonate(); } else { string fullyQualifiedDomainName = GetUpnFromDownlevelName(sidIdentity.Name); using (WindowsIdentity windowsIdentity = new WindowsIdentity(fullyQualifiedDomainName)) { impersonationContext = windowsIdentity.Impersonate(); } } } else throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SecurityContextDoesNotAllowImpersonation, rpc.Operation.Action)), rpc.Request); } else if (IsSecurityContextImpersonationRequiredByAspNet()) { if (rpc.HostingProperty != null && rpc.HostingProperty.ImpersonationContext != null) { impersonationContext = rpc.HostingProperty.ImpersonationContext.Impersonate(); } } SecurityTraceRecordHelper.TraceImpersonationSucceeded(rpc.Operation); // update the impersonation succeed audit if (AuditLevel.Success == (this.auditLevel & AuditLevel.Success)) { SecurityAuditHelper.WriteImpersonationSuccessEvent(this.auditLogLocation, this.suppressAuditFailure, rpc.Operation.Name, SecurityUtils.GetIdentityNamesFromContext(securityContext.AuthorizationContext)); } } catch (Exception ex) { if (DiagnosticUtility.IsFatal(ex)) { throw; } SecurityTraceRecordHelper.TraceImpersonationFailed(rpc.Operation, ex); // // Update the impersonation failure audit // Copy SecurityAuthorizationBehavior.Audit level to here!!! // if (AuditLevel.Failure == (this.auditLevel & AuditLevel.Failure)) { try { string primaryIdentity; if ( securityContext != null) primaryIdentity = SecurityUtils.GetIdentityNamesFromContext(securityContext.AuthorizationContext); else primaryIdentity = SecurityUtils.AnonymousIdentity.Name; SecurityAuditHelper.WriteImpersonationFailureEvent(this.auditLogLocation, this.suppressAuditFailure, rpc.Operation.Name, primaryIdentity, ex); } #pragma warning suppress 56500 catch (Exception auditException) { if (DiagnosticUtility.IsFatal(auditException)) throw; DiagnosticUtility.ExceptionUtility.TraceHandledException(auditException, TraceEventType.Error); } } throw; } return impersonationContext; } public void StopImpersonation(ref MessageRpc rpc, IDisposable impersonationContext, IPrincipal originalPrincipal, bool isThreadPrincipalSet) { try { if (IsSecurityContextImpersonationRequired(ref rpc) || IsSecurityContextImpersonationRequiredByAspNet()) { if (impersonationContext != null) { impersonationContext.Dispose(); } } if (isThreadPrincipalSet) { Thread.CurrentPrincipal = originalPrincipal; } } #pragma warning suppress 56500 // covered by FxCOP catch { string message = null; try { message = SR.GetString(SR.SFxRevertImpersonationFailed0); } finally { DiagnosticUtility.FailFast(message); } } } IPrincipal GetWindowsPrincipal(ServiceSecurityContext securityContext) { WindowsIdentity wid = securityContext.WindowsIdentity; if (!wid.IsAnonymous) return new WindowsPrincipal(wid); WindowsSidIdentity wsid = securityContext.PrimaryIdentity as WindowsSidIdentity; if (wsid != null) return new WindowsSidPrincipal(wsid, securityContext); return AnonymousWindowsPrincipal; } ServiceSecurityContext GetAndCacheSecurityContext(ref MessageRpc rpc) { ServiceSecurityContext securityContext = rpc.SecurityContext; if (!rpc.HasSecurityContext) { SecurityMessageProperty securityContextProperty = rpc.Request.Properties.Security; if (securityContextProperty == null) securityContext = null; // SecurityContext.Anonymous else { securityContext = securityContextProperty.ServiceSecurityContext; if (securityContext == null) throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SecurityContextMissing, rpc.Operation.Name)), rpc.Request); } rpc.SecurityContext = securityContext; rpc.HasSecurityContext = true; } return securityContext; } string GetUpnFromDownlevelName(string downlevelName) { if (downlevelName == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("downlevelName"); } int delimiterPos = downlevelName.IndexOf('\\'); if ((delimiterPos < 0) || (delimiterPos == 0) || (delimiterPos == downlevelName.Length - 1)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR.GetString(SR.DownlevelNameCannotMapToUpn, downlevelName))); } string shortDomainName = downlevelName.Substring(0, delimiterPos + 1); string userName = downlevelName.Substring(delimiterPos + 1); string fullDomainName; bool found; // 1) Read from cache lock (this.domainNameMap) { found = this.domainNameMap.TryGetValue(shortDomainName, out fullDomainName); } // 2) Not found, do expensive look up if (!found) { uint capacity = 50; StringBuilder fullyQualifiedDomainName = new StringBuilder((int)capacity); if (!SafeNativeMethods.TranslateName(shortDomainName, EXTENDED_NAME_FORMAT.NameSamCompatible, EXTENDED_NAME_FORMAT.NameCanonical, fullyQualifiedDomainName, out capacity)) { int errorCode = Marshal.GetLastWin32Error(); if (errorCode == (int)Win32Error.ERROR_INSUFFICIENT_BUFFER) { fullyQualifiedDomainName = new StringBuilder((int)capacity); if (!SafeNativeMethods.TranslateName(shortDomainName, EXTENDED_NAME_FORMAT.NameSamCompatible, EXTENDED_NAME_FORMAT.NameCanonical, fullyQualifiedDomainName, out capacity)) { errorCode = Marshal.GetLastWin32Error(); throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR.GetString(SR.DownlevelNameCannotMapToUpn, downlevelName), new Win32Exception(errorCode))); } } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR.GetString(SR.DownlevelNameCannotMapToUpn, downlevelName), new Win32Exception(errorCode))); } } // trim the trailing / from fqdn fullyQualifiedDomainName = fullyQualifiedDomainName.Remove(fullyQualifiedDomainName.Length - 1, 1); fullDomainName = fullyQualifiedDomainName.ToString(); // 3) Save in cache (remove a random item if cache is full) lock (this.domainNameMap) { if (this.domainNameMap.Count >= maxDomainNameMapSize) { if (this.random == null) { this.random = new Random(unchecked((int)DateTime.Now.Ticks)); } int victim = this.random.Next() % this.domainNameMap.Count; foreach (string key in this.domainNameMap.Keys) { if (victim <= 0) { this.domainNameMap.Remove(key); break; } --victim; } } this.domainNameMap[shortDomainName] = fullDomainName; } } return userName + "@" + fullDomainName; } class WindowsSidPrincipal : IPrincipal { WindowsSidIdentity identity; ServiceSecurityContext securityContext; public WindowsSidPrincipal(WindowsSidIdentity identity, ServiceSecurityContext securityContext) { this.identity = identity; this.securityContext = securityContext; } public IIdentity Identity { get { return this.identity; } } public bool IsInRole(string role) { if (role == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("role"); NTAccount account = new NTAccount(role); Claim claim = Claim.CreateWindowsSidClaim((SecurityIdentifier)account.Translate(typeof(SecurityIdentifier))); AuthorizationContext authContext = this.securityContext.AuthorizationContext; for (int i = 0; i < authContext.ClaimSets.Count; i++) { ClaimSet claimSet = authContext.ClaimSets[i]; if (claimSet.ContainsClaim(claim)) return true; } return false; } } class WindowsAnonymousIdentity { public IDisposable Impersonate() { // PreSharp Bug: Call 'Marshal.GetLastWin32Error' or 'Marshal.GetHRForLastWin32Error' before any other interop call. #pragma warning suppress 56523 // The LastWin32Error can be ignored here. IntPtr threadHandle = SafeNativeMethods.GetCurrentThread(); SafeCloseHandle tokenHandle; if (!SafeNativeMethods.OpenCurrentThreadToken(threadHandle, TokenAccessLevels.Impersonate, true, out tokenHandle)) { int error = Marshal.GetLastWin32Error(); Utility.CloseInvalidOutSafeHandle(tokenHandle); if (error == (int)System.ServiceModel.ComIntegration.Win32Error.ERROR_NO_TOKEN) { tokenHandle = new SafeCloseHandle(IntPtr.Zero, false); } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(error)); } } if (!SafeNativeMethods.ImpersonateAnonymousUserOnCurrentThread(threadHandle)) { int error = Marshal.GetLastWin32Error(); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(error)); } return new ImpersonationContext(threadHandle, tokenHandle); } class ImpersonationContext : IDisposable { IntPtr threadHandle; SafeCloseHandle tokenHandle; bool disposed = false; public ImpersonationContext(IntPtr threadHandle, SafeCloseHandle tokenHandle) { this.threadHandle = threadHandle; this.tokenHandle = tokenHandle; } void Undo() { // PreSharp Bug: Call 'Marshal.GetLastWin32Error' or 'Marshal.GetHRForLastWin32Error' before any other interop call. #pragma warning suppress 56523 // The LastWin32Error can be ignored here. DiagnosticUtility.DebugAssert(this.threadHandle == SafeNativeMethods.GetCurrentThread(), ""); // We are in the Dispose method. If a failure occurs we just have to ignore it. // PreSharp Bug: Call 'Marshal.GetLastWin32Error' or 'Marshal.GetHRForLastWin32Error' before any other interop call. // #pragma warning suppress 56523 // The LastWin32Error can be ignored here. if (!SafeNativeMethods.SetCurrentThreadToken(IntPtr.Zero, this.tokenHandle)) { int error = Marshal.GetLastWin32Error(); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityException(SR.GetString(SR.RevertImpersonationFailure, new Win32Exception(error).Message))); } tokenHandle.Close(); } public void Dispose() { if (!this.disposed) { Undo(); } this.disposed = true; } } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ListViewSortEventArgs.cs
- Variable.cs
- LinkedDataMemberFieldEditor.cs
- EventLogPermissionEntryCollection.cs
- QueryAccessibilityHelpEvent.cs
- OdbcDataAdapter.cs
- UnsafeNativeMethods.cs
- FormViewModeEventArgs.cs
- DWriteFactory.cs
- CodeRemoveEventStatement.cs
- StrokeFIndices.cs
- FlowDocumentPaginator.cs
- XmlAutoDetectWriter.cs
- NavigationHelper.cs
- ToolboxSnapDragDropEventArgs.cs
- XamlPointCollectionSerializer.cs
- RemotingConfiguration.cs
- AttributeTableBuilder.cs
- mediaclock.cs
- EditorZoneBase.cs
- MultilineStringConverter.cs
- KernelTypeValidation.cs
- TableLayoutStyle.cs
- ObjectDataSourceDisposingEventArgs.cs
- ToolStripOverflowButton.cs
- HttpMethodAttribute.cs
- RegexCode.cs
- LightweightCodeGenerator.cs
- XsltException.cs
- Stackframe.cs
- CssStyleCollection.cs
- BindToObject.cs
- DockingAttribute.cs
- PanelDesigner.cs
- PrePrepareMethodAttribute.cs
- InkCanvasFeedbackAdorner.cs
- ObjectManager.cs
- HtmlTableCellCollection.cs
- _NegotiateClient.cs
- Parallel.cs
- WebPermission.cs
- RotateTransform3D.cs
- CommonProperties.cs
- TypeToTreeConverter.cs
- StringBuilder.cs
- MediaCommands.cs
- WebPartActionVerb.cs
- TableHeaderCell.cs
- CodeDelegateCreateExpression.cs
- ValidationSummary.cs
- ReadOnlyCollectionBase.cs
- OdbcEnvironment.cs
- CompiledIdentityConstraint.cs
- RSAPKCS1SignatureFormatter.cs
- CharEnumerator.cs
- Utils.cs
- SqlXmlStorage.cs
- ScrollBarAutomationPeer.cs
- LassoSelectionBehavior.cs
- ExtensionDataReader.cs
- StringKeyFrameCollection.cs
- SqlCacheDependencyDatabase.cs
- DiscardableAttribute.cs
- Visual.cs
- ContextTokenTypeConverter.cs
- TextMarkerSource.cs
- BitmapData.cs
- ProxyBuilder.cs
- dsa.cs
- Environment.cs
- ByteStorage.cs
- ElementHost.cs
- IteratorDescriptor.cs
- Method.cs
- ReflectEventDescriptor.cs
- FileLogRecord.cs
- OleDbConnectionPoolGroupProviderInfo.cs
- HopperCache.cs
- WebPartConnectionsCancelVerb.cs
- SystemBrushes.cs
- SerialReceived.cs
- Int32AnimationUsingKeyFrames.cs
- Lock.cs
- MatrixKeyFrameCollection.cs
- HttpGetClientProtocol.cs
- BitmapSourceSafeMILHandle.cs
- WindowsAuthenticationModule.cs
- ServiceHostingEnvironment.cs
- TriState.cs
- ConstraintEnumerator.cs
- filewebrequest.cs
- QueryExpression.cs
- FontWeights.cs
- SQLInt64Storage.cs
- Currency.cs
- RegistrySecurity.cs
- DbgUtil.cs
- BamlLocalizabilityResolver.cs
- BaseUriWithWildcard.cs
- AlgoModule.cs