//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//------------------------------------------------------------------------------
namespace System.Web.ClientServices.Providers
{
using System;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Configuration;
using System.Configuration.Provider;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Security;
using System.Security.Principal;
using System.Security.Permissions;
using System.Net;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.Web.ClientServices;
using System.Web.Resources;
using System.Web.Security;
using System.Threading;
using System.Data;
using System.Data.Common;
using System.Reflection;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Web.ApplicationServices;
using System.Web.Script.Serialization;
using System.Diagnostics.CodeAnalysis;
[SecurityCritical]
[PermissionSet(SecurityAction.InheritanceDemand, Name="FullTrust")]
public class ClientSettingsProvider : SettingsProvider, IApplicationSettingsProvider
{
private string _ConnectionString = null;
private string _ConnectionStringProvider = "";
private bool _NeedToDoReset = false;
private bool _HonorCookieExpiry = false;
private bool _firstTime = true;
private string _UserName = "";
private SettingsPropertyValueCollection _PropertyValues = new SettingsPropertyValueCollection();
private SettingsPropertyCollection _Properties = null;
private static Hashtable _KnownTypesHashtable = null;
private static Type [] _KnownTypesArray = null;
[SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
public override string ApplicationName {
[SecuritySafeCritical]
get { return ""; }
[SecuritySafeCritical]
set { } }
private static string _ServiceUri = "";
private static object _lock = new object();
private static bool _UsingFileSystemStore = false;
private static bool _UsingIsolatedStore = true;
private static bool _UsingWFCService = false;
private static ApplicationSettingsBase _SettingsBaseClass = null;
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
[SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId="0#", Justification="Reviewed and approved by feature crew"),
SuppressMessage("Microsoft.Security", "CA2116:AptcaMethodsShouldOnlyCallAptcaMethods", Justification="Reviewed and approved by feature crew")]
public static SettingsPropertyCollection GetPropertyMetadata(string serviceUri)
{
CookieContainer cookies = null;
IIdentity id = Thread.CurrentPrincipal.Identity;
SettingsPropertyCollection retColl = new SettingsPropertyCollection();
if (id is ClientFormsIdentity)
cookies = ((ClientFormsIdentity)id).AuthenticationCookies;
if (serviceUri.EndsWith(".svc", StringComparison.OrdinalIgnoreCase)) {
throw new NotImplementedException();
// CustomBinding binding = ProxyHelper.GetBinding();
// ChannelFactory channelFactory = new ChannelFactory(binding, new EndpointAddress(serviceUri));
// ProfilePropertyMetadata[] props = null;
// ProfileService clientService = channelFactory.CreateChannel();
// using (new OperationContextScope((IContextChannel)clientService)) {
// ProxyHelper.AddCookiesToWCF(cookies, serviceUri, id.Name, null, null);
// props = clientService.GetPropertiesMetadata();
// ProxyHelper.GetCookiesFromWCF(cookies, serviceUri, id.Name, null, null);
// }
// if (props == null)
// return retColl;
// for(int iter=0; iter));
Collection props2 = (Collection) o;
if (props2 != null) {
foreach(ProfilePropertyMetadata p in props2)
AddToColl(p, retColl, id.IsAuthenticated);
}
}
return retColl;
}
private static void AddToColl(ProfilePropertyMetadata p, SettingsPropertyCollection retColl, bool isAuthenticated) {
string propName = p.PropertyName;
Type propType = Type.GetType(p.TypeName, false, true);
bool allowAnon = p.AllowAnonymousAccess;
bool readOnly = p.IsReadOnly;
if (!allowAnon && !isAuthenticated)
return;
SettingsSerializeAs serializeAs = (SettingsSerializeAs)p.SerializeAs;
SettingsAttributeDictionary dict = new SettingsAttributeDictionary();
dict.Add("AllowAnonymous", allowAnon);
retColl.Add(new SettingsProperty(propName, propType, null, readOnly,p.DefaultValue, serializeAs, dict, true, true));
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
[SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
[SecuritySafeCritical]
public override void Initialize(string name, NameValueCollection config) {
_UsingIsolatedStore = false;
// Initialize using appSettings section
string temp = System.Configuration.ConfigurationManager.AppSettings["ClientSettingsProvider.ServiceUri"];
if (!string.IsNullOrEmpty(temp))
ServiceUri = temp;
temp = System.Configuration.ConfigurationManager.AppSettings["ClientSettingsProvider.ConnectionStringName"];
if (!string.IsNullOrEmpty(temp)) {
if (ConfigurationManager.ConnectionStrings[temp] != null) {
_ConnectionStringProvider = ConfigurationManager.ConnectionStrings[temp].ProviderName;
_ConnectionString = ConfigurationManager.ConnectionStrings[temp].ConnectionString;
} else {
_ConnectionString = temp;
}
} else {
_ConnectionString = SqlHelper.GetDefaultConnectionString();
}
temp = System.Configuration.ConfigurationManager.AppSettings["ClientSettingsProvider.HonorCookieExpiry"];
if (!string.IsNullOrEmpty(temp))
_HonorCookieExpiry = (string.Compare(temp, "true", StringComparison.OrdinalIgnoreCase) == 0);
if (name == null)
name = this.GetType().ToString();
base.Initialize(name, config);
if (config != null) {
temp = config["serviceUri"];
if (!string.IsNullOrEmpty(temp))
ServiceUri = temp;
temp = config["connectionStringName"];
if (!string.IsNullOrEmpty(temp)) {
if (ConfigurationManager.ConnectionStrings[temp] != null) {
_ConnectionStringProvider = ConfigurationManager.ConnectionStrings[temp].ProviderName;
_ConnectionString = ConfigurationManager.ConnectionStrings[temp].ConnectionString;
} else {
_ConnectionString = temp;
}
}
config.Remove("name");
config.Remove("description");
config.Remove("connectionStringName");
config.Remove("serviceUri");
foreach (string attribUnrecognized in config.Keys)
if (!String.IsNullOrEmpty(attribUnrecognized))
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, AtlasWeb.AttributeNotRecognized, attribUnrecognized));
}
switch(SqlHelper.IsSpecialConnectionString(_ConnectionString))
{
case 1:
_UsingFileSystemStore = true;
break;
case 2:
_UsingIsolatedStore = true;
break;
default:
break;
}
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
[SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
[SecuritySafeCritical]
public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection propertyCollection) {
if (propertyCollection == null || propertyCollection.Count < 1)
return new SettingsPropertyValueCollection();
lock(_lock) {
if (_SettingsBaseClass == null && context != null) {
Type oType = context["SettingsClassType"] as Type;
if (oType != null) {
_SettingsBaseClass = oType.InvokeMember("Default", BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Static,
null, null, null, CultureInfo.InvariantCulture) as ApplicationSettingsBase;
}
}
_PropertyValues = new SettingsPropertyValueCollection();
_Properties = propertyCollection;
StoreKnownTypes(propertyCollection);
GetPropertyValuesCore();
return _PropertyValues;
}
}
private void GetPropertyValuesCore()
{
_UserName = Thread.CurrentPrincipal.Identity.Name;
if (_firstTime) {
_firstTime = false;
_NeedToDoReset = GetNeedToReset();
RegisterForValidateUserEvent();
}
if (_NeedToDoReset) {
_NeedToDoReset = false;
SetNeedToReset(false);
_PropertyValues = new SettingsPropertyValueCollection();
SetRemainingValuesToDefault();
SetPropertyValuesCore(_PropertyValues, false);
}
bool isCacheMoreFresh = GetIsCacheMoreFresh();
GetPropertyValuesFromSQL(); // Always start with the local copy
if (!ConnectivityStatus.IsOffline) {
if (isCacheMoreFresh) {
SetPropertyValuesWeb(_PropertyValues, isCacheMoreFresh); // local copy is fresher, so update the web-copy
} else {
GetPropertyValuesFromWeb();
SetPropertyValuesSQL(_PropertyValues, false);
}
}
if (_PropertyValues.Count < _Properties.Count)
SetRemainingValuesToDefault();
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
[SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
[SecuritySafeCritical]
public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection propertyValueCollection) {
if (propertyValueCollection == null || propertyValueCollection.Count < 1)
return;
lock(_lock) {
StoreKnownTypes(propertyValueCollection);
SetPropertyValuesCore(propertyValueCollection, true);
}
}
private void SetPropertyValuesCore(SettingsPropertyValueCollection values, bool raiseEvent) {
lock(_lock) {
bool isCacheMoreFresh = GetIsCacheMoreFresh();
// First store in SQL
SetPropertyValuesSQL(values, true);
Collection errorList = null;
// Store in web if it is offline
if (!ConnectivityStatus.IsOffline)
errorList = SetPropertyValuesWeb(values, isCacheMoreFresh);
if (raiseEvent && SettingsSaved != null) {
if (errorList == null)
errorList = new Collection();
SettingsSaved(this, new SettingsSavedEventArgs(errorList));
}
}
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
[SecuritySafeCritical]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
public void Reset(SettingsContext context) {
lock(_lock) {
if (_Properties == null) {
SetNeedToReset(true);
} else {
_PropertyValues = new SettingsPropertyValueCollection();
SetRemainingValuesToDefault();
SetPropertyValues(context, _PropertyValues);
_NeedToDoReset = false;
SetNeedToReset(false);
}
}
}
[SecuritySafeCritical]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
public void Upgrade(SettingsContext context, SettingsPropertyCollection properties) {
return;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
[SecuritySafeCritical]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
public SettingsPropertyValue GetPreviousVersion(SettingsContext context, SettingsProperty property) {
if (_Properties == null)
_Properties = new SettingsPropertyCollection();
if (_Properties[property.Name] == null)
_Properties.Add(property);
GetPropertyValuesCore();
return _PropertyValues[property.Name];
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
private string GetServiceUri()
{
if (string.IsNullOrEmpty(_ServiceUri))
throw new ArgumentException(AtlasWeb.ServiceUriNotFound);
return _ServiceUri;
}
[SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings", Justification = "Reviewed and approved by feature crew")]
public static string ServiceUri
{
[SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "2#", Justification = "Reviewed and approved by feature crew")]
get
{
return _ServiceUri;
}
[SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "2#", Justification = "Reviewed and approved by feature crew")]
set {
_ServiceUri = value;
if (string.IsNullOrEmpty(_ServiceUri)) {
_UsingWFCService = false;
} else {
_UsingWFCService = _ServiceUri.EndsWith(".svc", StringComparison.OrdinalIgnoreCase);
}
}
}
public event EventHandler SettingsSaved;
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
internal static Type[] GetKnownTypes(ICustomAttributeProvider knownTypeAttributeTarget)
{
if (_KnownTypesArray == null)
InitKnownTypes();
return _KnownTypesArray;
}
static private void InitKnownTypes()
{
_KnownTypesHashtable = new Hashtable();
_KnownTypesArray = new Type[]{ typeof(bool),
typeof(string),
typeof(ArrayList),
typeof(ProfilePropertyMetadata),
typeof(IDictionary),
typeof(Collection)
};
for(int iter=0; iter<_KnownTypesArray.Length; iter++)
_KnownTypesHashtable.Add(_KnownTypesArray[iter], string.Empty);
}
static private void StoreKnownTypes(SettingsPropertyValueCollection propertyValueCollection)
{
if (_KnownTypesHashtable == null)
InitKnownTypes();
ArrayList al = null;
foreach(SettingsPropertyValue p in propertyValueCollection) {
if (!_KnownTypesHashtable.Contains(p.Property.PropertyType)) {
_KnownTypesHashtable.Add(p.Property.PropertyType, string.Empty);
if (al == null)
al = new ArrayList();
al.Add(p.Property.PropertyType);
}
}
if (al != null) {
Type [] temp = new Type[_KnownTypesArray.Length + al.Count];
_KnownTypesArray.CopyTo(temp, 0);
al.CopyTo(temp, _KnownTypesArray.Length);
_KnownTypesArray = temp;
}
}
static private void StoreKnownTypes(SettingsPropertyCollection propertyCollection)
{
if (_KnownTypesHashtable == null)
InitKnownTypes();
ArrayList al = null;
foreach(SettingsProperty p in propertyCollection) {
if (!_KnownTypesHashtable.Contains(p.PropertyType)) {
_KnownTypesHashtable.Add(p.PropertyType, string.Empty);
if (al == null)
al = new ArrayList();
al.Add(p.PropertyType);
}
}
if (al != null) {
Type [] temp = new Type[_KnownTypesArray.Length + al.Count];
_KnownTypesArray.CopyTo(temp, 0);
al.CopyTo(temp, _KnownTypesArray.Length);
_KnownTypesArray = temp;
}
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
private void GetPropertyValuesFromWeb()
{
GetPropertyValuesFromWebCore(_HonorCookieExpiry);
// Any failures?
bool anyFailures = (_PropertyValues.Count < _Properties.Count);
if (!_HonorCookieExpiry && anyFailures) {
// if there were failures, try re-validating the ClientFormsIdentity
// and try again
ClientFormsIdentity id = Thread.CurrentPrincipal.Identity as ClientFormsIdentity;
if (id != null) {
id.RevalidateUser();
GetPropertyValuesFromWebCore(true);
}
}
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
[SuppressMessage("Microsoft.Security", "CA2116:AptcaMethodsShouldOnlyCallAptcaMethods", Justification="Reviewed and approved by feature crew")]
private void GetPropertyValuesFromWebCore(bool bubbleExceptionFromSvc) {
string [] propertyNames = new string[_Properties.Count];
int iter = 0;
CookieContainer cookies = null;
IIdentity id = Thread.CurrentPrincipal.Identity;
foreach (SettingsProperty setting in _Properties) {
propertyNames[iter++] = setting.Name;
}
if (id is ClientFormsIdentity)
cookies = ((ClientFormsIdentity)id).AuthenticationCookies;
if (_UsingWFCService) {
throw new NotImplementedException();
// CustomBinding binding = ProxyHelper.GetBinding();
// ChannelFactory channelFactory = new ChannelFactory(binding, new EndpointAddress(GetServiceUri()));
// ProfileService clientService = channelFactory.CreateChannel();
// Dictionary propertyValues = null;
// using (new OperationContextScope((IContextChannel)clientService)) {
// ProxyHelper.AddCookiesToWCF(cookies, GetServiceUri(), id.Name, GetConnectionString(), _ConnectionStringProvider);
// propertyValues = clientService.GetPropertiesForCurrentUser(propertyNames, id.IsAuthenticated && (id is ClientFormsIdentity));
// ProxyHelper.GetCookiesFromWCF(cookies, GetServiceUri(), id.Name, GetConnectionString(), _ConnectionStringProvider);
// }
// for(iter = 0; iter));
} catch {
if (bubbleExceptionFromSvc)
throw;
}
if (obj != null) {
Dictionary ret = (Dictionary) obj;
foreach(KeyValuePair de in ret) {
SettingsProperty setting = _Properties[(string) de.Key];
if (setting == null)
continue; // Bad -- why wasn't it found?
bool mustAdd = false;
SettingsPropertyValue value = _PropertyValues[setting.Name];
if (value == null) {
value = new SettingsPropertyValue(setting);
mustAdd = true;
}
if (de.Value != null && !setting.PropertyType.IsAssignableFrom(de.Value.GetType()))
{
object convertedValue = null;
if (!ObjectConverter.TryConvertObjectToType(de.Value,
setting.PropertyType,
new JavaScriptSerializer(),
out convertedValue))
{
// Failure to convert!
continue;
}
value.PropertyValue = convertedValue;
} else {
value.PropertyValue = de.Value;
}
value.Deserialized = true;
value.IsDirty = false;
if (mustAdd)
_PropertyValues.Add(value);
}
}
}
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
private Collection SetPropertyValuesWeb(SettingsPropertyValueCollection values, bool cacheIsMoreFresh)
{
bool anyFailures = false;
Collection errorList = null;
ClientFormsIdentity id = Thread.CurrentPrincipal.Identity as ClientFormsIdentity;
try {
errorList = SetPropertyValuesWebCore(values, cacheIsMoreFresh);
anyFailures = (errorList != null && errorList.Count > 0);
}
catch (WebException) {
if (id == null || _HonorCookieExpiry) {
throw;
}
anyFailures = true;
}
if (!_HonorCookieExpiry && anyFailures) {
// if there were failures, try re-validating the ClientFormsIdentity
// and try again
if (id != null) {
id.RevalidateUser();
errorList = SetPropertyValuesWebCore(values, cacheIsMoreFresh);
}
}
return errorList;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
[SuppressMessage("Microsoft.Security", "CA2116:AptcaMethodsShouldOnlyCallAptcaMethods", Justification="Reviewed and approved by feature crew")]
private Collection SetPropertyValuesWebCore(SettingsPropertyValueCollection values, bool cacheIsMoreFresh)
{
Dictionary propertyValues = new Dictionary();
Collection errorList = null;
foreach(SettingsPropertyValue value in values) {
if (cacheIsMoreFresh || value.IsDirty) {
propertyValues.Add(value.Property.Name, value.PropertyValue);
}
}
CookieContainer cookies = null;
IIdentity id = Thread.CurrentPrincipal.Identity;
if (id is ClientFormsIdentity)
cookies = ((ClientFormsIdentity)id).AuthenticationCookies;
if (_UsingWFCService) {
throw new NotImplementedException();
// CustomBinding binding = ProxyHelper.GetBinding();
// ChannelFactory channelFactory = new ChannelFactory(binding, new EndpointAddress(GetServiceUri()));
// ProfileService clientService = channelFactory.CreateChannel();
// using (new OperationContextScope((IContextChannel)clientService)) {
// ProxyHelper.AddCookiesToWCF(cookies, GetServiceUri(), id.Name, GetConnectionString(), _ConnectionStringProvider);
// errorList = clientService.SetPropertiesForCurrentUser(propertyValues, id.IsAuthenticated && (id is ClientFormsIdentity));
// ProxyHelper.GetCookiesFromWCF(cookies, GetServiceUri(), id.Name, GetConnectionString(), _ConnectionStringProvider);
// }
} else {
// Collection SetPropertiesForCurrentUser(IDictionary values, bool authenticatedUserOnly)
string [] paramNames = new string [] {"values", "authenticatedUserOnly" };
object [] paramValues = new object [] {propertyValues, id.IsAuthenticated && (id is ClientFormsIdentity) };
object o = ProxyHelper.CreateWebRequestAndGetResponse(GetServiceUri() + "/SetPropertiesForCurrentUser",
ref cookies,
id.Name,
_ConnectionString,
_ConnectionStringProvider,
paramNames,
paramValues,
typeof(Collection));
errorList = (Collection) o;
}
SetIsCacheMoreFresh(false);
return errorList;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
private void GetPropertyValuesFromSQL()
{
if (_UsingFileSystemStore || _UsingIsolatedStore)
{
ClientData cd = ClientDataManager.GetUserClientData(Thread.CurrentPrincipal.Identity.Name, _UsingIsolatedStore);
if (cd.SettingsNames == null || cd.SettingsValues == null)
return;
int len = cd.SettingsNames.Length;
if (cd.SettingsNames.Length != cd.SettingsStoredAs.Length || cd.SettingsValues.Length != cd.SettingsStoredAs.Length)
{
return; // Bad!
}
for(int iter=0; iter 0 && string.Compare(e.UserName, _UserName, StringComparison.OrdinalIgnoreCase) != 0) {
try {
if (_SettingsBaseClass != null)
_SettingsBaseClass.Reload();
// _PropertyValues = new SettingsPropertyValueCollection();
// GetPropertyValuesCore(); // refresh the collection
} catch {
// it's possible that the (new) user doesn't have the same props
// if (_PropertyValues.Count < _Properties.Count)
// SetRemainingValuesToDefault();
}
}
}
private void SetRemainingValuesToDefault()
{
foreach (SettingsProperty prop in _Properties) {
SettingsPropertyValue value = _PropertyValues[prop.Name];
if (value == null) {
value = new SettingsPropertyValue(prop);
value.SerializedValue = prop.DefaultValue;
value.Deserialized = false;
object o = value.PropertyValue;
value.PropertyValue = o;
_PropertyValues.Add(value);
}
}
}
private string GetConnectionString()
{
if (_ConnectionString == null)
_ConnectionString = SqlHelper.GetDefaultConnectionString();
return _ConnectionString;
}
}
}