//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ /* * ProfileBase * * Copyright (c) 2002 Microsoft Corporation */ namespace System.Web.Profile { using System.Security.Principal; using System.Security.Permissions; using System.Collections; using System.Collections.Specialized; using System.Web.Configuration; using System.Web.Util; using System.Web.Security; using System.Web.Compilation; using System.Configuration; using System.Configuration.Provider; using System.Reflection; using System.CodeDom; using System.Web.Hosting; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Security; public class ProfileBase : SettingsBase { ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // Public (instance) functions and properties public override object this[string propertyName] { get { if (!HttpRuntime.DisableProcessRequestInApplicationTrust) { // VSWhidbey 427541 if (HttpRuntime.NamedPermissionSet != null && HttpRuntime.ProcessRequestInApplicationTrust) { HttpRuntime.NamedPermissionSet.PermitOnly(); } } return GetInternal(propertyName); } set { if (!HttpRuntime.DisableProcessRequestInApplicationTrust) { // VSWhidbey 427541 if (HttpRuntime.NamedPermissionSet != null && HttpRuntime.ProcessRequestInApplicationTrust) { HttpRuntime.NamedPermissionSet.PermitOnly(); } } SetInternal(propertyName, value); } } [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.SerializationFormatter)] private object GetInternal(string propertyName) { return base[propertyName]; } [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.SerializationFormatter)] private void SetInternal(string propertyName, object value) { if (!_IsAuthenticated) { SettingsProperty p = s_Properties[propertyName]; if (p != null) { bool fAllowAnonymous = (bool)p.Attributes["AllowAnonymous"]; if (!fAllowAnonymous) throw new ProviderException(SR.GetString(SR.Profile_anonoymous_not_allowed_to_set_property)); } } base[propertyName] = value; } public object GetPropertyValue(string propertyName) { return this[propertyName]; } public void SetPropertyValue(string propertyName, object propertyValue) { this[propertyName] = propertyValue; } public ProfileGroupBase GetProfileGroup(string groupName) { ProfileGroupBase grp = (ProfileGroupBase)_Groups[groupName]; if (grp == null) { Type t = BuildManager.GetProfileType(); if (t == null) throw new ProviderException(SR.GetString(SR.Profile_group_not_found, groupName)); t = t.Assembly.GetType("ProfileGroup" + groupName, false); if (t == null) throw new ProviderException(SR.GetString(SR.Profile_group_not_found, groupName)); grp = (ProfileGroupBase)Activator.CreateInstance(t); grp.Init(this, groupName); } return grp; } public ProfileBase() { if (!ProfileManager.Enabled) throw new ProviderException(SR.GetString(SR.Profile_not_enabled)); if (!s_Initialized) InitializeStatic(); } public void Initialize(string username, bool isAuthenticated) { if (username != null) _UserName = username.Trim(); else _UserName = username; //if (string.IsNullOrEmpty(_UserName)) // throw new ArgumentException(SR.GetString(SR.Membership_InvalidUserName), "username"); SettingsContext sc = new SettingsContext(); sc.Add("UserName", _UserName); sc.Add("IsAuthenticated", isAuthenticated); _IsAuthenticated = isAuthenticated; base.Initialize(sc, s_Properties, ProfileManager.Providers); } public override void Save() { if (!HttpRuntime.DisableProcessRequestInApplicationTrust) { // VSWhidbey 427541 if (HttpRuntime.NamedPermissionSet != null && HttpRuntime.ProcessRequestInApplicationTrust) { HttpRuntime.NamedPermissionSet.PermitOnly(); } } SaveWithAssert(); } [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.SerializationFormatter)] private void SaveWithAssert() { base.Save(); _IsDirty = false; _DatesRetrieved = false; } public string UserName { get { return _UserName; } } public bool IsAnonymous { get { return !_IsAuthenticated; } } public bool IsDirty { get { if (_IsDirty) return true; foreach (SettingsPropertyValue pv in PropertyValues) { if (pv.IsDirty) { _IsDirty = true; return true; } } return false; } } public DateTime LastActivityDate { get { if (!_DatesRetrieved) RetrieveDates(); return _LastActivityDate.ToLocalTime(); } } public DateTime LastUpdatedDate { get { if (!_DatesRetrieved) RetrieveDates(); return _LastUpdatedDate.ToLocalTime(); } } ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // static public Properties and functions static public ProfileBase Create(string username) { return Create(username, true); } static public ProfileBase Create(string username, bool isAuthenticated) { if (!ProfileManager.Enabled) throw new ProviderException(SR.GetString(SR.Profile_not_enabled)); InitializeStatic(); if (s_SingletonInstance != null) return s_SingletonInstance; if (s_Properties.Count == 0) { lock (s_InitializeLock) { if (s_SingletonInstance == null) s_SingletonInstance = new DefaultProfile(); return s_SingletonInstance; } } HttpRuntime.CheckAspNetHostingPermission(AspNetHostingPermissionLevel.Low, SR.Feature_not_supported_at_this_level); return CreateMyInstance(username, isAuthenticated); } new static public SettingsPropertyCollection Properties { get { InitializeStatic(); return s_Properties; } } ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // Internal static functions and properties ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// internal static Type InheritsFromType { get { if (!ProfileManager.Enabled) { return typeof(DefaultProfile); } Type t; if (HostingEnvironment.IsHosted) t = BuildManager.GetType(InheritsFromTypeString, true, true); else t = GetPropType(InheritsFromTypeString); if (!typeof(ProfileBase).IsAssignableFrom(t)) { ProfileSection config = MTConfigUtil.GetProfileAppConfig(); throw new ConfigurationErrorsException(SR.GetString(SR.Wrong_profile_base_type), null, config.ElementInformation.Properties["inherits"].Source, config.ElementInformation.Properties["inherit"].LineNumber); } return t; } } internal static string InheritsFromTypeString { get { string defaultType = typeof(ProfileBase).ToString(); if (!ProfileManager.Enabled) return defaultType; ProfileSection config = MTConfigUtil.GetProfileAppConfig(); if (config.Inherits == null) return defaultType; string inheritsType = config.Inherits.Trim(); if (inheritsType.Length < 1) return defaultType; Type t = Type.GetType(inheritsType, false, true); if (t == null) return inheritsType; if (!typeof(ProfileBase).IsAssignableFrom(t)) throw new ConfigurationErrorsException(SR.GetString(SR.Wrong_profile_base_type), null, config.ElementInformation.Properties["inherits"].Source, config.ElementInformation.Properties["inherit"].LineNumber); return t.AssemblyQualifiedName; } } internal static bool InheritsFromCustomType { get { if (!ProfileManager.Enabled) return false; ProfileSection config = MTConfigUtil.GetProfileAppConfig(); if (config.Inherits == null) return false; string inheritsType = config.Inherits.Trim(); if (inheritsType == null || inheritsType.Length < 1) return false; Type t = Type.GetType(inheritsType, false, true); if (t == null || t != typeof(ProfileBase)) return true; else return false; } } ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// internal static ProfileBase SingletonInstance { get { return s_SingletonInstance; } } ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// internal static Hashtable GetPropertiesForCompilation() { if (!ProfileManager.Enabled) return null; if (s_PropertiesForCompilation != null) return s_PropertiesForCompilation; lock (s_InitializeLock) { if (s_PropertiesForCompilation != null) return s_PropertiesForCompilation; Hashtable ht = new Hashtable(); ProfileSection config = MTConfigUtil.GetProfileAppConfig(); if (config.PropertySettings == null) { s_PropertiesForCompilation = ht; return s_PropertiesForCompilation; } AddProfilePropertySettingsForCompilation(config.PropertySettings, ht, null); foreach (ProfileGroupSettings pgs in config.PropertySettings.GroupSettings) { AddProfilePropertySettingsForCompilation(pgs.PropertySettings, ht, pgs.Name); } AddProfilePropertySettingsForCompilation(ProfileManager.DynamicProfileProperties, ht, null); s_PropertiesForCompilation = ht; } return s_PropertiesForCompilation; } ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// internal static string GetProfileClassName() { Hashtable props = GetPropertiesForCompilation(); if (props == null) return "System.Web.Profile.DefaultProfile"; if (props.Count > 0 || InheritsFromCustomType) return "ProfileCommon"; else return "System.Web.Profile.DefaultProfile"; } ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// private static void AddProfilePropertySettingsForCompilation(ProfilePropertySettingsCollection propertyCollection, Hashtable ht, string groupName) { foreach (ProfilePropertySettings pps in propertyCollection) { ProfileNameTypeStruct prop = new ProfileNameTypeStruct(); if (groupName != null) { prop.Name = groupName + "." + pps.Name; } else { prop.Name = pps.Name; } Type t = pps.TypeInternal; if (t == null) t = ResolvePropertyTypeForCommonTypes(pps.Type.ToLower(System.Globalization.CultureInfo.InvariantCulture)); if (t == null) t = BuildManager.GetType(pps.Type, false); if (t == null) { prop.PropertyCodeRefType = new CodeTypeReference(pps.Type); } else { prop.PropertyCodeRefType = new CodeTypeReference(t); } prop.PropertyType = t; pps.TypeInternal = t; prop.IsReadOnly = pps.ReadOnly; prop.LineNumber = pps.ElementInformation.Properties["name"].LineNumber; prop.FileName = pps.ElementInformation.Properties["name"].Source; ht.Add(prop.Name, prop); } } ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // Private static functions and properties ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// static private ProfileBase CreateMyInstance(string username, bool isAuthenticated) { Type t; if (HostingEnvironment.IsHosted) t = BuildManager.GetProfileType(); else t = InheritsFromType; ProfileBase hbc = (ProfileBase)Activator.CreateInstance(t); hbc.Initialize(username, isAuthenticated); return hbc; } ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// static private void InitializeStatic() { if (!ProfileManager.Enabled || s_Initialized) { if (s_InitializeException != null) throw s_InitializeException; return; } lock (s_InitializeLock) { if (s_Initialized) { if (s_InitializeException != null) throw s_InitializeException; return; } try { ProfileSection config = MTConfigUtil.GetProfileAppConfig(); bool fAnonEnabled = (HostingEnvironment.IsHosted ? AnonymousIdentificationModule.Enabled : true); Type baseType = ProfileBase.InheritsFromType; bool hasLowTrust = HttpRuntime.HasAspNetHostingPermission(AspNetHostingPermissionLevel.Low); s_Properties = new SettingsPropertyCollection(); // Step 0: Add all dynamic profile properties set programatically during PreAppStart ProfileBase.AddPropertySettingsFromConfig(baseType, fAnonEnabled, hasLowTrust, ProfileManager.DynamicProfileProperties, null); ////////////////////////////////////////////////////////////////////// // Step 1: Add Properties from the base class (if not ProfileBase) if (baseType != typeof(ProfileBase)) { ////////////////////////////////////////////////////////////////////// // Step 2: Construct a hashtable containing a list of all the property-names in the ProfileBase type PropertyInfo[] baseProps = typeof(ProfileBase).GetProperties(); NameValueCollection baseProperties = new NameValueCollection(baseProps.Length); foreach (PropertyInfo baseProp in baseProps) baseProperties.Add(baseProp.Name, String.Empty); ////////////////////////////////////////////////////////////////////// // Step 3: For each property in the derived class, add it to the s_Properties class. PropertyInfo[] props = baseType.GetProperties(); foreach (PropertyInfo prop in props) { if (baseProperties[prop.Name] == null) { //not in the base class ProfileProvider prov = hasLowTrust ? ProfileManager.Provider : null; bool readOnly = false; SettingsSerializeAs serializeAs = SettingsSerializeAs.ProviderSpecific; string defaultValue = String.Empty; bool allowAnonymous = false; string customData = null; ////////////////////////////////////////////////////////////////////// // Step 4: For the property, get the attributes Attribute[] attribs = Attribute.GetCustomAttributes(prop, true); foreach (Attribute attrib in attribs) { if (attrib is SettingsSerializeAsAttribute) { serializeAs = ((SettingsSerializeAsAttribute)attrib).SerializeAs; } else if (attrib is SettingsAllowAnonymousAttribute) { allowAnonymous = ((SettingsAllowAnonymousAttribute)attrib).Allow; if (!fAnonEnabled && allowAnonymous) throw new ConfigurationErrorsException(SR.GetString(SR.Annoymous_id_module_not_enabled, prop.Name), config.ElementInformation.Properties["inherits"].Source, config.ElementInformation.Properties["inherits"].LineNumber); } else if (attrib is System.ComponentModel.ReadOnlyAttribute) { readOnly = ((System.ComponentModel.ReadOnlyAttribute)attrib).IsReadOnly; } else if (attrib is DefaultSettingValueAttribute) { defaultValue = ((DefaultSettingValueAttribute)attrib).Value; } else if (attrib is CustomProviderDataAttribute) { customData = ((CustomProviderDataAttribute)attrib).CustomProviderData; } else if (hasLowTrust && attrib is ProfileProviderAttribute) { prov = ProfileManager.Providers[((ProfileProviderAttribute)attrib).ProviderName]; if (prov == null) throw new ConfigurationErrorsException(SR.GetString(SR.Profile_provider_not_found, ((ProfileProviderAttribute)attrib).ProviderName), config.ElementInformation.Properties["inherits"].Source, config.ElementInformation.Properties["inherits"].LineNumber); } } ////////////////////////////////////////////////////////////////////// // Step 5: Add the property to the s_Properties SettingsAttributeDictionary settings = new SettingsAttributeDictionary(); settings.Add("AllowAnonymous", allowAnonymous); if (!string.IsNullOrEmpty(customData)) settings.Add("CustomProviderData", customData); SettingsProperty sp = new SettingsProperty(prop.Name, prop.PropertyType, prov, readOnly, defaultValue, serializeAs, settings, false, true); s_Properties.Add(sp); } } } ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // Step 6: Add all properties from config if (config.PropertySettings != null) { AddPropertySettingsFromConfig(baseType, fAnonEnabled, hasLowTrust, config.PropertySettings, null); foreach (ProfileGroupSettings pgs in config.PropertySettings.GroupSettings) { AddPropertySettingsFromConfig(baseType, fAnonEnabled, hasLowTrust, pgs.PropertySettings, pgs.Name); } } } catch (Exception e) { if (s_InitializeException == null) s_InitializeException = e; } // If there are no properties, create an empty collection. if (s_Properties == null) s_Properties = new SettingsPropertyCollection(); // Make the properties collection read-only s_Properties.SetReadOnly(); s_Initialized = true; } // Throw an exception if there was an exception during initialization if (s_InitializeException != null) throw s_InitializeException; } private static void AddPropertySettingsFromConfig(Type baseType, bool fAnonEnabled, bool hasLowTrust, ProfilePropertySettingsCollection settingsCollection, string groupName) { foreach (ProfilePropertySettings pps in settingsCollection) { string name = (groupName != null) ? (groupName + "." + pps.Name) : pps.Name; if (baseType != typeof(ProfileBase) && s_Properties[name] != null) throw new ConfigurationErrorsException(SR.GetString(SR.Profile_property_already_added), null, pps.ElementInformation.Properties["name"].Source, pps.ElementInformation.Properties["name"].LineNumber); try { if (pps.TypeInternal == null) { pps.TypeInternal = ResolvePropertyType(pps.Type); } } catch (Exception e) { throw new ConfigurationErrorsException(SR.GetString(SR.Profile_could_not_create_type, e.Message), e, pps.ElementInformation.Properties["type"].Source, pps.ElementInformation.Properties["type"].LineNumber); } if (!fAnonEnabled) { bool fAllowAnonymous = pps.AllowAnonymous; if (fAllowAnonymous) throw new ConfigurationErrorsException(SR.GetString(SR.Annoymous_id_module_not_enabled, pps.Name), pps.ElementInformation.Properties["allowAnonymous"].Source, pps.ElementInformation.Properties["allowAnonymous"].LineNumber); } if (hasLowTrust) { SetProviderForProperty(pps); } else { pps.ProviderInternal = null; } // Providers that use NetDataContractSerialzier do not require Serializable attributes any longer, only enforce this for the SqlProfileProvider bool requireSerializationCheck = pps.ProviderInternal == null || pps.ProviderInternal.GetType() == typeof(SqlProfileProvider); if (requireSerializationCheck && pps.SerializeAs == SerializationMode.Binary && !pps.TypeInternal.IsSerializable) { throw new ConfigurationErrorsException(SR.GetString(SR.Property_not_serializable, pps.Name), pps.ElementInformation.Properties["serializeAs"].Source, pps.ElementInformation.Properties["serializeAs"].LineNumber); } SettingsAttributeDictionary settings = new SettingsAttributeDictionary(); settings.Add("AllowAnonymous", pps.AllowAnonymous); if (!string.IsNullOrEmpty(pps.CustomProviderData)) settings.Add("CustomProviderData", pps.CustomProviderData); SettingsProperty sp = new SettingsProperty(name, pps.TypeInternal, pps.ProviderInternal, pps.ReadOnly, pps.DefaultValue, (SettingsSerializeAs)pps.SerializeAs, settings, false, true); s_Properties.Add(sp); } } ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// static private void SetProviderForProperty(ProfilePropertySettings pps) { if (pps.Provider == null || pps.Provider.Length < 1) { pps.ProviderInternal = ProfileManager.Provider; // Use default provider } else { pps.ProviderInternal = ProfileManager.Providers[pps.Provider]; // Use specified provider } // Provider not found? if (pps.ProviderInternal == null) throw new ConfigurationErrorsException(SR.GetString(SR.Profile_provider_not_found, pps.Provider), pps.ElementInformation.Properties["provider"].Source, pps.ElementInformation.Properties["provider"].LineNumber); } ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// static private Type ResolvePropertyTypeForCommonTypes(string typeName) { switch (typeName) { case "string": return typeof(string); case "byte": case "int8": return typeof(byte); case "boolean": case "bool": return typeof(bool); case "char": return typeof(char); case "int": case "integer": case "int32": return typeof(int); case "date": case "datetime": return typeof(DateTime); case "decimal": return typeof(decimal); case "double": case "float64": return typeof(System.Double); case "float": case "float32": return typeof(float); case "long": case "int64": return typeof(long); case "short": case "int16": return typeof(System.Int16); case "single": return typeof(Single); case "uint16": case "ushort": return typeof(UInt16); case "uint32": case "uint": return typeof(uint); case "ulong": case "uint64": return typeof(ulong); case "object": return typeof(object); default: return null; } } static private Type ResolvePropertyType(string typeName) { Type t = ResolvePropertyTypeForCommonTypes(typeName.ToLower(System.Globalization.CultureInfo.InvariantCulture)); if (t != null) return t; if (HostingEnvironment.IsHosted) return BuildManager.GetType(typeName, true, true); else return GetPropType(typeName); } static private Type GetPropType(string typeName) { return Type.GetType(typeName, true, true); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // Instance data private Hashtable _Groups = new Hashtable(); private bool _IsAuthenticated = false; private string _UserName = null; private bool _IsDirty = false; private DateTime _LastActivityDate; private DateTime _LastUpdatedDate; private bool _DatesRetrieved; private void RetrieveDates() { if (_DatesRetrieved || ProfileManager.Provider == null) return; int totalRecords; ProfileInfoCollection coll = ProfileManager.Provider.FindProfilesByUserName(ProfileAuthenticationOption.All, _UserName, 0, 1, out totalRecords); foreach (ProfileInfo p in coll) { _LastActivityDate = p.LastActivityDate.ToUniversalTime(); _LastUpdatedDate = p.LastUpdatedDate.ToUniversalTime(); _DatesRetrieved = true; return; } } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // Static data private static SettingsPropertyCollection s_Properties = null; private static object s_InitializeLock = new Object(); private static Exception s_InitializeException = null; private static bool s_Initialized = false; private static ProfileBase s_SingletonInstance = null; private static Hashtable s_PropertiesForCompilation = null; } ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// internal class ProfileNameTypeStruct { internal string Name; internal CodeTypeReference PropertyCodeRefType; internal Type PropertyType; internal bool IsReadOnly; internal int LineNumber; internal string FileName; } }