Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Net / System / Net / AuthenticationManager.cs / 1407647 / AuthenticationManager.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- namespace System.Net { using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.Configuration; using System.Globalization; using System.Net.Configuration; using System.Reflection; using System.Security.Authentication.ExtendedProtection; using System.Security.Permissions; using System; using System.Threading; using System.Diagnostics; // // A contract that applications can use to restrict auth scenarios in current appDomain // public interface ICredentialPolicy { bool ShouldSendCredential(Uri challengeUri, WebRequest request, NetworkCredential credential, IAuthenticationModule authenticationModule); } ////// public class AuthenticationManager { //also used as a lock object private static PrefixLookup s_ModuleBinding = new PrefixLookup(); private static ArrayList s_ModuleList; private static ICredentialPolicy s_ICredentialPolicy; private static SpnDictionary m_SpnDictionary = new SpnDictionary(); private static TriState s_OSSupportsExtendedProtection = TriState.Unspecified; private static TriState s_SspSupportsExtendedProtection = TriState.Unspecified; // not creatable... // private AuthenticationManager() { } // // // public static ICredentialPolicy CredentialPolicy { get { return s_ICredentialPolicy; } set { ExceptionHelper.ControlPolicyPermission.Demand(); s_ICredentialPolicy = value; } } // // public static StringDictionary CustomTargetNameDictionary { get {return m_SpnDictionary;} } // // This will give access to some internal methods // internal static SpnDictionary SpnDictionary { get {return m_SpnDictionary;} } // // internal static void EnsureConfigLoaded() { try { object o = ModuleList; } catch (Exception e) { if (e is ThreadAbortException || e is OutOfMemoryException || e is StackOverflowException) throw; // A Config System has circular dependency on HttpWebRequest so they call this method to // trigger the config. For some reason they don't want any exceptions from here. } } internal static bool OSSupportsExtendedProtection { get { if (s_OSSupportsExtendedProtection == TriState.Unspecified) { if (ComNetOS.IsWin7) { s_OSSupportsExtendedProtection = TriState.True; } else { if (SspSupportsExtendedProtection) { // EP is considered supported only if both SSPs and http.sys support CBT/EP. // We don't support scenarios where e.g. only SSPs support CBT. In such cases // the customer needs to patch also http.sys (even if he may not use it). if (UnsafeNclNativeMethods.HttpApi.ExtendedProtectionSupported) { s_OSSupportsExtendedProtection = TriState.True; } else { s_OSSupportsExtendedProtection = TriState.False; } } else { s_OSSupportsExtendedProtection = TriState.False; } } } return (s_OSSupportsExtendedProtection == TriState.True); } } internal static bool SspSupportsExtendedProtection { get { if (s_SspSupportsExtendedProtection == TriState.Unspecified) { if (ComNetOS.IsWin7) { s_SspSupportsExtendedProtection = TriState.True; } else { // Perform a loopback NTLM authentication to determine whether the underlying OS supports // extended protection ContextFlags clientFlags = ContextFlags.Connection | ContextFlags.InitIdentify; NTAuthentication client = new NTAuthentication(false, NtlmClient.AuthType, SystemNetworkCredential.defaultCredential, "http/localhost", clientFlags, null); try { NTAuthentication server = new NTAuthentication(true, NtlmClient.AuthType, SystemNetworkCredential.defaultCredential, null, ContextFlags.Connection, null); try { SecurityStatus status; byte[] blob = null; while (!server.IsCompleted) { blob = client.GetOutgoingBlob(blob, true, out status); blob = server.GetOutgoingBlob(blob, true, out status); } if (server.OSSupportsExtendedProtection) { s_SspSupportsExtendedProtection = TriState.True; } else { if (Logging.On) Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_ssp_dont_support_cbt)); s_SspSupportsExtendedProtection = TriState.False; } } finally { server.CloseContext(); } } finally { client.CloseContext(); } } } return (s_SspSupportsExtendedProtection == TriState.True); } } // // ModuleList - static initialized property - // contains list of Modules used for Authentication // private static ArrayList ModuleList { get { // // GetConfig() might use us, so we have a circular dependency issue, // that causes us to nest here, we grab the lock, only // if we haven't initialized, or another thread is busy in initialization // if (s_ModuleList == null) { lock (s_ModuleBinding) { if (s_ModuleList == null) { GlobalLog.Print("AuthenticationManager::Initialize(): calling ConfigurationManager.GetSection()"); // This will never come back as null. Additionally, it will // have the items the user wants available. ListManages the authentication modules called during the client authentication /// process. ///authenticationModuleTypes = AuthenticationModulesSectionInternal.GetSection().AuthenticationModules; // // Should be registered in a growing list of encryption/algorithm strengths // basically, walk through a list of Types, and create new Auth objects // from them. // // order is meaningful here: // load the registered list of auth types // with growing level of encryption. // ArrayList moduleList = new ArrayList(); IAuthenticationModule moduleToRegister; foreach (Type type in authenticationModuleTypes){ try { moduleToRegister = Activator.CreateInstance(type, BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, // Binder new object[0], // no arguments CultureInfo.InvariantCulture ) as IAuthenticationModule; if (moduleToRegister != null) { GlobalLog.Print("WebRequest::Initialize(): Register:" + moduleToRegister.AuthenticationType); RemoveAuthenticationType(moduleList, moduleToRegister.AuthenticationType); moduleList.Add(moduleToRegister); } } catch (Exception exception) { // // ignore failure (log exception for debugging) // GlobalLog.Print("AuthenticationManager::constructor failed to initialize: " + exception.ToString()); } } s_ModuleList = moduleList; } } } return s_ModuleList; } } private static void RemoveAuthenticationType(ArrayList list, string typeToRemove) { for (int i=0; i< list.Count; ++i) { if (string.Compare(((IAuthenticationModule)list[i]).AuthenticationType, typeToRemove, StringComparison.OrdinalIgnoreCase) ==0) { list.RemoveAt(i); break; } } } /// /// public static Authorization Authenticate(string challenge, WebRequest request, ICredentials credentials) { // // parameter validation // if (request == null) { throw new ArgumentNullException("request"); } if (credentials == null) { throw new ArgumentNullException("credentials"); } if (challenge==null) { throw new ArgumentNullException("challenge"); } GlobalLog.Print("AuthenticationManager::Authenticate() challenge:[" + challenge + "]"); Authorization response = null; HttpWebRequest httpWebRequest = request as HttpWebRequest; if (httpWebRequest != null && httpWebRequest.CurrentAuthenticationState.Module != null) { response = httpWebRequest.CurrentAuthenticationState.Module.Authenticate(challenge, request, credentials); } else { // This is the case where we would try to find the module on the first server challenge lock (s_ModuleBinding) { // // fastest way of iterating on the ArryList // for (int i = 0; i < ModuleList.Count; i++) { IAuthenticationModule authenticationModule = (IAuthenticationModule)ModuleList[i]; // // the AuthenticationModule will // 1) return a valid string on success // 2) return null if it knows it cannot respond // 3) throw if it could have responded but unexpectedly failed to do so // if (httpWebRequest != null) { httpWebRequest.CurrentAuthenticationState.Module = authenticationModule; } response = authenticationModule.Authenticate(challenge, request, credentials); if (response!=null) { // // found the Authentication Module, return it // GlobalLog.Print("AuthenticationManager::Authenticate() found IAuthenticationModule:[" + authenticationModule.AuthenticationType + "]"); break; } } } } return response; } // These four authentication modules require a Channel Binding Token to be able to preauthenticate over https. // After a successful authentication, they will cache the CBT used on the ServicePoint. In order to PreAuthenticate, // they require that a CBT has previously been cached. Any other module should be allowed to try preauthentication // without a cached CBT #if DEBUG // This method is only called as part of an assert private static bool ModuleRequiresChannelBinding(IAuthenticationModule authenticationModule) { return (authenticationModule is NtlmClient || authenticationModule is KerberosClient || authenticationModule is NegotiateClient || authenticationModule is DigestClient); } #endif ///Call each registered authentication module to determine the first module that /// can respond to the authentication request. ////// public static Authorization PreAuthenticate(WebRequest request, ICredentials credentials) { GlobalLog.Print("AuthenticationManager::PreAuthenticate() request:" + ValidationHelper.HashString(request) + " credentials:" + ValidationHelper.HashString(credentials)); if (request == null) { throw new ArgumentNullException("request"); } if (credentials == null) { return null; } HttpWebRequest httpWebRequest = request as HttpWebRequest; IAuthenticationModule authenticationModule; if (httpWebRequest == null) return null; // // PrefixLookup is thread-safe // string moduleName = s_ModuleBinding.Lookup(httpWebRequest.ChallengedUri.AbsoluteUri) as string; GlobalLog.Print("AuthenticationManager::PreAuthenticate() s_ModuleBinding.Lookup returns:" + ValidationHelper.ToString(moduleName)); if (moduleName == null) return null; authenticationModule = findModule(moduleName); if (authenticationModule == null) { // The module could have been unregistered // No preauthentication is possible return null; } // prepopulate the channel binding token so we can try preauth (but only for modules that actually need it!) if (httpWebRequest.ChallengedUri.Scheme == Uri.UriSchemeHttps) { object binding = httpWebRequest.ServicePoint.CachedChannelBinding; #if DEBUG // the ModuleRequiresChannelBinding method is only compiled in DEBUG so the assert must be restricted to DEBUG // as well // If the authentication module does CBT, we require that it also caches channel bindings. System.Diagnostics.Debug.Assert(!(binding == null && ModuleRequiresChannelBinding(authenticationModule))); #endif // can also be DBNull.Value, indicating "we previously succeeded without getting a CBT." // (ie, unpatched SSP talking to a partially-hardened server) ChannelBinding channelBinding = binding as ChannelBinding; if (channelBinding != null) { httpWebRequest.CurrentAuthenticationState.TransportContext = new CachedTransportContext(channelBinding); } } // Otherwise invoke the PreAuthenticate method // we're guaranteed that CanPreAuthenticate is true because we check before calling BindModule() Authorization authorization = authenticationModule.PreAuthenticate(request, credentials); if (authorization != null && !authorization.Complete && httpWebRequest != null) httpWebRequest.CurrentAuthenticationState.Module = authenticationModule; GlobalLog.Print("AuthenticationManager::PreAuthenticate() IAuthenticationModule.PreAuthenticate() returned authorization:" + ValidationHelper.HashString(authorization)); return authorization; } ///Pre-authenticates a request. ////// public static void Register(IAuthenticationModule authenticationModule) { ExceptionHelper.UnmanagedPermission.Demand(); if (authenticationModule == null) { throw new ArgumentNullException("authenticationModule"); } GlobalLog.Print("AuthenticationManager::Register() registering :[" + authenticationModule.AuthenticationType + "]"); lock (s_ModuleBinding) { IAuthenticationModule existentModule = findModule(authenticationModule.AuthenticationType); if (existentModule != null) { ModuleList.Remove(existentModule); } ModuleList.Add(authenticationModule); } } ///Registers an authentication module with the authentication manager. ////// public static void Unregister(IAuthenticationModule authenticationModule) { ExceptionHelper.UnmanagedPermission.Demand(); if (authenticationModule == null) { throw new ArgumentNullException("authenticationModule"); } GlobalLog.Print("AuthenticationManager::Unregister() unregistering :[" + authenticationModule.AuthenticationType + "]"); lock (s_ModuleBinding) { if (!ModuleList.Contains(authenticationModule)) { throw new InvalidOperationException(SR.GetString(SR.net_authmodulenotregistered)); } ModuleList.Remove(authenticationModule); } } ///Unregisters authentication modules for an authentication scheme. ////// public static void Unregister(string authenticationScheme) { ExceptionHelper.UnmanagedPermission.Demand(); if (authenticationScheme == null) { throw new ArgumentNullException("authenticationScheme"); } GlobalLog.Print("AuthenticationManager::Unregister() unregistering :[" + authenticationScheme + "]"); lock (s_ModuleBinding) { IAuthenticationModule existentModule = findModule(authenticationScheme); if (existentModule == null) { throw new InvalidOperationException(SR.GetString(SR.net_authschemenotregistered)); } ModuleList.Remove(existentModule); } } ///Unregisters authentication modules for an authentication scheme. ////// public static IEnumerator RegisteredModules { get { return ModuleList.GetEnumerator(); } } ////// Returns a list of registered authentication modules. /// ////// // Create binding between an authorization response and the module // generating that response // This association is used for deciding which module to invoke // for preauthentication purposes internal static void BindModule(Uri uri, Authorization response, IAuthenticationModule module) { GlobalLog.Assert(module.CanPreAuthenticate, "AuthenticationManager::BindModule()|module.CanPreAuthenticate == false"); if (response.ProtectionRealm!=null) { // The authentication module specified which Uri prefixes // will be preauthenticated string[] prefix = response.ProtectionRealm; for (int k=0; k/// Binds an authentication response to a request for pre-authentication. /// ///=signature.Length) { int firstQuote = -1, secondQuote = -1; for (int i = 0; i < challenge.Length && index < 0; i++) { // Search for the quotes if (challenge[i]=='\"') { if (firstQuote <= secondQuote) firstQuote = i; else secondQuote = i; } // We've found both ends of an unquoted segment (could be whole challenge), search inside for the signature. if (i==challenge.Length-1 || (challenge[i]=='\"' && firstQuote>secondQuote)) { // see if the portion of challenge out of the quotes contains // the signature of the IAuthenticationModule if (i==challenge.Length-1) firstQuote = challenge.Length; // unquoted segment is too small to hold a scheme name, ie: scheme param="value",a="" if (firstQuote = 0) { // Verify the signature is a full scheme name match, not a partial match or a parameter name: if ((index == 0 || challenge[index - 1] == ' ' || challenge[index - 1] == ',') && (index + signature.Length == challenge.Length || challenge[index + signature.Length] == ' ' || challenge[index + signature.Length] == ',')) { break; } // Only a partial match / param name, but maybe there is another occurance of the signature later? checkLength -= index - checkstart + 1; checkstart = index + 1; } } while (index >= 0); } } } GlobalLog.Print("AuthenticationManager::FindSubstringNotInQuotes(" + challenge + ", " + signature + ")=" + index.ToString()); return index; } // // Helper for FindSubstringNotInQuotes // Find the FIRST possible index of a signature. private static int IndexOf(string challenge, string lwrCaseSignature, int start, int count) { count += start + 1 - lwrCaseSignature.Length; for (; start < count; ++start) { int i = 0; for (; i < lwrCaseSignature.Length; ++i) { // force a challenge char to lowecase (safe assuming it works on trusted ASCII source) if ((challenge[start+i] | 0x20) != lwrCaseSignature[i]) break; } if (i == lwrCaseSignature.Length) return start; } return -1; } // // this method is called by the IAuthenticationModule implementations // (mainly Digest) to safely find their list of parameters in a challenge. // it returns the index of the first ',' that is not included in quotes, // -1 is returned on error or end of string. on return offset contains the // index of the first '=' that is not included in quotes, -1 if no '=' was found. // internal static int SplitNoQuotes(string challenge, ref int offset) { // GlobalLog.Print("SplitNoQuotes([" + challenge + "], " + offset.ToString() + ")"); // // save offset // int realOffset = offset; // // default is not found // offset = -1; if (challenge != null && realOffset secondQuote means we are in a quoted string // if (firstQuote>secondQuote && challenge[i]=='\\' && i+1 < challenge.Length && challenge[i+1]=='\"') { // // skip <\"> when in a quoted string // i++; } else if (challenge[i]=='\"') { if (firstQuote <= secondQuote) { firstQuote = i; } else { secondQuote = i; } } else if (challenge[i]=='=' && firstQuote<=secondQuote && offset<0) { offset = i; } else if (challenge[i]==',' && firstQuote<=secondQuote) { return i; } } } return -1; } #if !FEATURE_PAL internal static Authorization GetGroupAuthorization(IAuthenticationModule thisModule, string token, bool finished, NTAuthentication authSession, bool shareAuthenticatedConnections, bool mutualAuth) { return new Authorization( token, finished, (shareAuthenticatedConnections) ? null : (thisModule.GetType().FullName + "/" + authSession.UniqueUserId), mutualAuth); } #endif // !FEATURE_PAL }; // class AuthenticationManager // // This internal class implements a data structure which can be // used for storing a set of objects keyed by string prefixes // Looking up an object given a string returns the value associated // with the longest matching prefix // (A prefix "matches" a string IFF the string starts with that prefix // The degree of the match is prefix length) // // The class has a configurable maximum capacity. When adding items, if the // list is over capacity, then the least recently used (LRU) item is dropped. // internal class PrefixLookup { // Do not go over this limit. Discard old data elements // Longer lists suffer a search penalty private const int defaultCapacity = 100; private int capacity = defaultCapacity; // LRU list - Least Recently Used. // Add new items to the front. Drop items from the end if beyond capacity. // Promote used items to the top. private LinkedList lruList = new LinkedList (); private class PrefixValuePair { public string prefix; public object value; public PrefixValuePair(string pre, object val) { prefix = pre; value = val; } } #if DEBUG // this method is only called by test code internal int Capacity { get { return capacity; } set { lock (lruList) { if (value <= 0) { // Disabled, flush list capacity = 0; lruList.Clear(); } else { capacity = value; // Ensure list is still within capacity while (lruList.Count > capacity) { lruList.RemoveLast(); } } } } } #endif internal void Add(string prefix, object value) { Debug.Assert(prefix != null, "PrefixLookup.Add; prefix must not be null"); Debug.Assert(prefix.Length > 0, "PrefixLookup.Add; prefix must not be empty"); Debug.Assert(value != null, "PrefixLookup.Add; value must not be null"); if (capacity == 0 || prefix == null || prefix.Length == 0 || value == null) return; // writers are locked lock (lruList) { // Special case duplicate check at start of list, very common if (lruList.First != null && lruList.First.Value.prefix.Equals(prefix)) { // Already in list, update value lruList.First.Value.value = value; } else { // New entry // Duplicates will just be pushed down and eventually discarded lruList.AddFirst(new PrefixValuePair(prefix, value)); // If full, drop the least recently used while (lruList.Count > capacity) { lruList.RemoveLast(); } } } } internal object Lookup(string lookupKey) { Debug.Assert(lookupKey != null, "PrefixLookup.Lookup; lookupKey must not be null"); Debug.Assert(lookupKey.Length > 0, "PrefixLookup.Lookup; lookupKey must not be empty"); if (lookupKey==null || lookupKey.Length == 0|| lruList.Count == 0) { return null; } LinkedListNode mostSpecificMatch = null; lock (lruList) { // // Normally readers don't need to be locked, but if the value is found // then it is promoted to the top of the list. // // Oh well, do it the slow way, search for the longest partial match string prefix; int longestMatchPrefix = 0; for (LinkedListNode pairNode = lruList.First; pairNode != null; pairNode = pairNode.Next) { // // check if the match is better than the current-most-specific match // prefix = pairNode.Value.prefix; if (prefix.Length > longestMatchPrefix && lookupKey.StartsWith(prefix)) { // // Yes-- update the information about currently preferred match // longestMatchPrefix = prefix.Length; mostSpecificMatch = pairNode; if (longestMatchPrefix == lookupKey.Length) break; // Exact match, optimal solution. } } if (mostSpecificMatch != null && mostSpecificMatch != lruList.First) { // We have a match and it's not the first element, move it up in the list lruList.Remove(mostSpecificMatch); lruList.AddFirst(mostSpecificMatch); } } return mostSpecificMatch != null ? mostSpecificMatch.Value.value : null; } } // class PrefixLookup } // namespace System.Net // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- TreeViewEvent.cs
- CompositeDuplexElement.cs
- AppDomainUnloadedException.cs
- EventMemberCodeDomSerializer.cs
- ThreadSafeList.cs
- CompressEmulationStream.cs
- BStrWrapper.cs
- ToolStripRenderer.cs
- AvTraceFormat.cs
- CharacterHit.cs
- ParserContext.cs
- FormConverter.cs
- CodeExporter.cs
- ComboBoxAutomationPeer.cs
- AuthenticationService.cs
- StateItem.cs
- FileLevelControlBuilderAttribute.cs
- RadialGradientBrush.cs
- ServicesUtilities.cs
- CheckBoxBaseAdapter.cs
- ProtocolElement.cs
- StylusPointPropertyInfo.cs
- _ChunkParse.cs
- _AutoWebProxyScriptWrapper.cs
- ExpressionsCollectionEditor.cs
- MD5CryptoServiceProvider.cs
- SamlAttribute.cs
- BuildProvidersCompiler.cs
- ToolboxItemFilterAttribute.cs
- WsdlHelpGeneratorElement.cs
- InternalResources.cs
- OptimalTextSource.cs
- Message.cs
- GroupBox.cs
- Vector3DAnimation.cs
- JobInputBins.cs
- UInt64Converter.cs
- SEHException.cs
- XmlUTF8TextWriter.cs
- ConfigurationCollectionAttribute.cs
- SmiGettersStream.cs
- GeneralTransformCollection.cs
- BitmapPalette.cs
- CornerRadiusConverter.cs
- SystemException.cs
- MsmqInputSessionChannelListener.cs
- OleDbParameter.cs
- SQLChars.cs
- DbReferenceCollection.cs
- Validator.cs
- ReadOnlyDictionary.cs
- _OverlappedAsyncResult.cs
- ComponentEditorForm.cs
- ToolStripContextMenu.cs
- SqlMethods.cs
- DataColumnChangeEvent.cs
- DateRangeEvent.cs
- FieldNameLookup.cs
- XmlHierarchicalDataSourceView.cs
- ConfigurationPropertyAttribute.cs
- CatalogZoneBase.cs
- AggregationMinMaxHelpers.cs
- ServiceReference.cs
- StrokeNodeData.cs
- RotationValidation.cs
- baseaxisquery.cs
- IDQuery.cs
- RequiredAttributeAttribute.cs
- OleDbException.cs
- COSERVERINFO.cs
- GrammarBuilderBase.cs
- AdapterUtil.cs
- SplitterCancelEvent.cs
- SoapInteropTypes.cs
- Int32CollectionConverter.cs
- ChildDocumentBlock.cs
- ContentPlaceHolder.cs
- XmlReader.cs
- XmlDataCollection.cs
- CodeObject.cs
- AnnotationResourceCollection.cs
- XmlUTF8TextReader.cs
- InternalRelationshipCollection.cs
- CharacterMetricsDictionary.cs
- OleDbRowUpdatingEvent.cs
- InstrumentationTracker.cs
- VideoDrawing.cs
- TextTreeTextElementNode.cs
- SmiEventSink_DeferedProcessing.cs
- DateTimeConstantAttribute.cs
- CharStorage.cs
- ApplicationServiceManager.cs
- SymmetricAlgorithm.cs
- ZipIOCentralDirectoryBlock.cs
- NullRuntimeConfig.cs
- HashCodeCombiner.cs
- GridViewCancelEditEventArgs.cs
- RuleSettings.cs
- CodeExporter.cs
- FilePrompt.cs