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
- InfoCardServiceInstallComponent.cs
- TokenBasedSetEnumerator.cs
- FrameworkTemplate.cs
- SizeIndependentAnimationStorage.cs
- ScalarType.cs
- TableCellCollection.cs
- CommandEventArgs.cs
- IndexOutOfRangeException.cs
- RepeatInfo.cs
- FlatButtonAppearance.cs
- FixedSOMFixedBlock.cs
- HTTPNotFoundHandler.cs
- BatchParser.cs
- DependencyObjectProvider.cs
- BmpBitmapDecoder.cs
- TextMessageEncodingElement.cs
- QilPatternFactory.cs
- InvalidOleVariantTypeException.cs
- ColorTransform.cs
- CriticalExceptions.cs
- Vector3DConverter.cs
- FragmentQueryKB.cs
- PageHandlerFactory.cs
- SqlWebEventProvider.cs
- ApplicationBuildProvider.cs
- UserCancellationException.cs
- MemberDescriptor.cs
- DatatypeImplementation.cs
- Set.cs
- PickDesigner.xaml.cs
- AmbientValueAttribute.cs
- XmlDataCollection.cs
- XamlPointCollectionSerializer.cs
- BamlResourceDeserializer.cs
- Metafile.cs
- ACE.cs
- _CacheStreams.cs
- DecoratedNameAttribute.cs
- InvalidDataException.cs
- ConfigurationException.cs
- SqlCacheDependencySection.cs
- StorageMappingItemCollection.cs
- CodeMemberMethod.cs
- ContainerParaClient.cs
- OracleTransaction.cs
- EntitySetDataBindingList.cs
- AuthenticationModulesSection.cs
- CompilerCollection.cs
- ErrorInfoXmlDocument.cs
- ToolStripItemEventArgs.cs
- WebPartZoneBase.cs
- TextBounds.cs
- HttpWebRequestElement.cs
- ProfilePropertySettings.cs
- HtmlControlPersistable.cs
- EventWaitHandleSecurity.cs
- PageThemeBuildProvider.cs
- CurrentChangedEventManager.cs
- WsatExtendedInformation.cs
- MailBnfHelper.cs
- PageRequestManager.cs
- WebBrowserPermission.cs
- PropertyIDSet.cs
- Assembly.cs
- MetafileHeaderWmf.cs
- ItemList.cs
- SecurityPermission.cs
- SelectionService.cs
- TryCatchDesigner.xaml.cs
- WebSysDefaultValueAttribute.cs
- FlowLayoutSettings.cs
- HwndSourceParameters.cs
- MulticastDelegate.cs
- Bits.cs
- DrawingAttributeSerializer.cs
- TableSectionStyle.cs
- WebPartRestoreVerb.cs
- AudioSignalProblemOccurredEventArgs.cs
- HiddenFieldPageStatePersister.cs
- TableStyle.cs
- WindowsHyperlink.cs
- PhonemeConverter.cs
- Pair.cs
- WebPartConnectionsDisconnectVerb.cs
- DataRecord.cs
- SafeMarshalContext.cs
- ClientSettingsSection.cs
- AbandonedMutexException.cs
- ContentPlaceHolder.cs
- FailedToStartupUIException.cs
- DBParameter.cs
- _SafeNetHandles.cs
- BuilderPropertyEntry.cs
- TdsParserHelperClasses.cs
- ResolveNextArgumentWorkItem.cs
- SchemeSettingElement.cs
- SplayTreeNode.cs
- MsmqInputChannelBase.cs
- DefaultParameterValueAttribute.cs
- DataSourceView.cs