public override bool RoleExists(string roleName) { SecUtility.CheckParameter(ref roleName, true, true, true, MaxTableRoleNameLength, "rolename"); try { TableServiceContext svc = CreateDataServiceContext(); DataServiceQuery <RoleRow> queryObj = svc.CreateQuery <RoleRow>(_tableName); var query = (from role in queryObj where role.PartitionKey == SecUtility.CombineToKey(_applicationName, string.Empty) && role.RowKey == SecUtility.Escape(roleName) select role).AsTableServiceQuery(); try { // this query addresses exactly one result // we thus should get an exception if there is no element return(query.Execute().Any()); } catch (InvalidOperationException e) { if ((e.InnerException is DataServiceClientException && (e.InnerException as DataServiceClientException).StatusCode == (int)HttpStatusCode.NotFound) || (e.InnerException.InnerException is DataServiceClientException && (e.InnerException.InnerException as DataServiceClientException).StatusCode == (int)HttpStatusCode.NotFound)) { return(false); } throw; } } catch (InvalidOperationException e) { throw new ProviderException("Error while accessing the data store.", e); } }
private RoleRow GetUserInRole(DataServiceContext svc, string rolename, string username) { SecUtility.CheckParameter(ref username, true, true, true, Constants.MaxTableUsernameLength, "username"); SecUtility.CheckParameter(ref rolename, true, true, true, MaxTableRoleNameLength, "rolename"); try { DataServiceQuery <RoleRow> queryObj = svc.CreateQuery <RoleRow>(_tableName); var query = (from user in queryObj where user.PartitionKey == SecUtility.CombineToKey(_applicationName, username) && user.RowKey == SecUtility.Escape(rolename) select user).AsTableServiceQuery(); try { IEnumerable <RoleRow> userRows = query.Execute(); return(userRows.FirstOrDefault()); } catch (InvalidOperationException e) { if (e.InnerException is DataServiceClientException && (e.InnerException as DataServiceClientException).StatusCode == (int)HttpStatusCode.NotFound) { return(null); } throw; } } catch (Exception e) { throw new ProviderException("Error while accessing the data store.", e); } }
public override void CreateUninitializedItem(HttpContext context, string id, int timeout) { SecUtility.CheckParameter(ref id, true, true, false, ProviderConfiguration.MaxStringPropertySizeInChars, "id"); if (timeout < 0) { throw new ArgumentException("Parameter timeout must be a non-negative integer!"); } try { TableServiceContext svc = CreateDataServiceContext(); var session = new SessionRow(id, applicationName) { Lock = 0, Initialized = false, Id = id, Timeout = timeout, ExpiresUtc = DateTime.UtcNow.AddMinutes(timeout) }; svc.AddObject(tableName, session); svc.SaveChangesWithRetries(); } catch (InvalidOperationException e) { var innerEx = e.InnerException as DataServiceClientException; if (innerEx != null && innerEx.StatusCode == (int)HttpStatusCode.Conflict) { // the data already exists so we can return because we are reusing a session return; } throw new ProviderException("Error accessing the data store.", e); } }
private SessionRow GetSession(string id, DataServiceContext context) { try { DataServiceQuery <SessionRow> queryObj = context.CreateQuery <SessionRow>(tableName); var query = (from session in queryObj where session.PartitionKey == SecUtility.CombineToKey(applicationName, id) select session).AsTableServiceQuery(); IEnumerable <SessionRow> sessions = query.Execute(); // enumerate the result and store it in a list var sessionList = new List <SessionRow>(sessions); if (sessionList.Count() == 1) { return(sessionList.First()); } if (sessionList.Count() > 1) { throw new ProviderException("Multiple sessions with the same name!"); } return(null); } catch (Exception e) { throw new ProviderException("Error accessing storage.", e); } }
public override SessionStateStoreData GetItem(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions) { SecUtility.CheckParameter(ref id, true, true, false, ProviderConfiguration.MaxStringPropertySizeInChars, "id"); SessionStateStoreData sessionStateStoreData = GetSession(context, id, out locked, out lockAge, out lockId, out actions, false); return(sessionStateStoreData); }
public override void RemoveItem(HttpContext context, string id, object lockId, SessionStateStoreData item) { SecUtility.CheckParameter(ref id, true, true, false, ProviderConfiguration.MaxStringPropertySizeInChars, "id"); try { TableServiceContext svc = CreateDataServiceContext(); SessionRow session = GetSession(id, svc); if (session == null) { return; } if (session.Lock != (int)lockId) { return; } svc.DeleteObject(session); svc.SaveChangesWithRetries(); } catch (InvalidOperationException e) { throw new ProviderException("Error accessing the data store!", e); } // delete associated blobs try { IEnumerable <IListBlobItem> e = blobProvider.ListBlobs(GetBlobNamePrefix(id)); if (e == null) { return; } IEnumerator <IListBlobItem> props = e.GetEnumerator(); if (props == null) { return; } while (props.MoveNext()) { if (props.Current != null) { if (!blobProvider.DeleteBlob(props.Current.Uri.ToString())) { // ignore this; it is possible that another thread could try to delete the blob // at the same time } } } } catch (Exception e) { throw new ProviderException("Error accessing blob storage.", e); } }
// applicationName + userName is partitionKey // roleName is rowKey public RoleRow(string applicationName, string roleName, string userName) : base(SecUtility.CombineToKey(applicationName, userName), SecUtility.Escape(roleName)) { SecUtility.CheckParameter(ref applicationName, true, true, true, Constants.MaxTableApplicationNameLength, "applicationName"); SecUtility.CheckParameter(ref roleName, true, true, true, 512, "roleName"); SecUtility.CheckParameter(ref userName, true, false, true, Constants.MaxTableUsernameLength, "userName"); ApplicationName = applicationName; RoleName = roleName; UserName = userName; }
public override bool IsUserInRole(string username, string roleName) { SecUtility.CheckParameter(ref roleName, true, true, true, MaxTableRoleNameLength, "rolename"); SecUtility.CheckParameter(ref username, true, false, true, Constants.MaxTableUsernameLength, "username"); if (username.Length < 1) { return(false); } try { TableServiceContext svc = CreateDataServiceContext(); DataServiceQuery <RoleRow> queryObj = svc.CreateQuery <RoleRow>(_tableName); var query = (from user in queryObj where (user.PartitionKey == SecUtility.CombineToKey(_applicationName, username) || user.PartitionKey == SecUtility.CombineToKey(_applicationName, string.Empty)) && user.RowKey == SecUtility.Escape(roleName) select user).AsTableServiceQuery(); IEnumerable <RoleRow> userRows = query.Execute(); if (userRows == null) { throw new ProviderException(string.Format(CultureInfo.InstalledUICulture, "The role {0} does not exist.", roleName)); } var l = new List <RoleRow>(userRows); if (l.Count == 0) { throw new ProviderException(string.Format(CultureInfo.InstalledUICulture, "The role {0} does not exist.", roleName)); } RoleRow row; if (IsStaleRole(l, out row)) { throw new ProviderException(string.Format(CultureInfo.InstalledUICulture, "The role {0} does not exist.", roleName)); } if (l.Count > 2) { throw new ProviderException("User name appears twice in the same role!"); } if (l.Count == 1) { Debug.Assert(string.IsNullOrEmpty(l.ElementAt(0).UserName)); return(false); } return(true); } catch (InvalidOperationException e) { throw new ProviderException("Error while accessing the data store.", e); } }
public override void ResetItemTimeout(HttpContext context, string id) { SecUtility.CheckParameter(ref id, true, true, false, ProviderConfiguration.MaxStringPropertySizeInChars, "id"); providerRetry(() => { TableServiceContext svc = CreateDataServiceContext(); SessionRow session = GetSession(id, svc); session.ExpiresUtc = DateTime.UtcNow.AddMinutes(session.Timeout); svc.UpdateObject(session); svc.SaveChangesWithRetries(); }); }
// application name + session id is partitionKey public SessionRow(string sessionId, string applicationName) : base(SecUtility.CombineToKey(applicationName, sessionId), string.Empty) { SecUtility.CheckParameter(ref sessionId, true, true, true, ProviderConfiguration.MaxStringPropertySizeInChars, "sessionId"); SecUtility.CheckParameter(ref applicationName, true, true, true, Constants.MaxTableApplicationNameLength, "applicationName"); Id = sessionId; ApplicationName = applicationName; ExpiresUtc = ProviderConfiguration.MinSupportedDateTime; LockDateUtc = ProviderConfiguration.MinSupportedDateTime; CreatedUtc = ProviderConfiguration.MinSupportedDateTime; Timeout = 0; BlobName = string.Empty; }
public override void ReleaseItemExclusive(HttpContext context, string id, object lockId) { SecUtility.CheckParameter(ref id, true, true, false, ProviderConfiguration.MaxStringPropertySizeInChars, "id"); try { TableServiceContext svc = CreateDataServiceContext(); SessionRow session = GetSession(id, svc); ReleaseItemExclusive(svc, session, lockId); } catch (InvalidOperationException e) { throw new ProviderException("Error accessing the data store!", e); } }
// remember that there is no is no rollback functionality for the table storage service right now // be cautious when using this function // if a role does not exist, we stop deleting roles, if a user in a role does not exist, we continue deleting // in case of error conditions, the behavior of this function is different than the SQL role provider public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames) { SecUtility.CheckArrayParameter(ref roleNames, true, true, true, MaxTableRoleNameLength, "roleNames"); SecUtility.CheckArrayParameter(ref usernames, true, true, true, Constants.MaxTableUsernameLength, "usernames"); try { TableServiceContext svc = CreateDataServiceContext(); foreach (string role in roleNames) { if (!RoleExists(role)) { throw new ProviderException(string.Format(CultureInfo.InstalledUICulture, "The role {0} does not exist!", role)); } foreach (string user in usernames) { RoleRow row = GetUserInRole(svc, role, user); if (row == null) { Log.Write(EventKind.Warning, string.Format(CultureInfo.InstalledUICulture, "The user {0} does not exist in the role {1}.", user, role)); continue; } try { svc.DeleteObject(row); svc.SaveChangesWithRetries(); } catch (Exception e) { var dsce = e.InnerException as DataServiceClientException; if (dsce != null && (dsce.StatusCode == (int)HttpStatusCode.NoContent || dsce.StatusCode == (int)HttpStatusCode.NotFound)) { Log.Write(EventKind.Warning, string.Format(CultureInfo.InstalledUICulture, "The user {0} does not exist in the role {1}.", user, role)); svc.Detach(row); } else { throw new ProviderException(string.Format(CultureInfo.InstalledUICulture, "Error deleting user {0} from role {1}.", user, role)); } } } } } catch (InvalidOperationException e) { throw new ProviderException("Error while accessing the data store.", e); } }
// partition key is applicationName + userName // rowKey is empty public MembershipRow(string applicationName, string userName) : base(SecUtility.CombineToKey(applicationName, userName), string.Empty) { if (string.IsNullOrEmpty(applicationName)) { throw new ProviderException("Partition key cannot be empty!"); } ////if (string.IsNullOrEmpty(userName)) ////{ //// throw new ProviderException("RowKey cannot be empty!"); ////} // applicationName + userName is partitionKey // the reasoning behind this is that we want to strive for the best scalability possible // chosing applicationName as the partition key and userName as row key would not give us that because // it would mean that a site with millions of users had all users on a single partition // having the applicationName and userName inside the partition key is important for queries as queries // for users in a single application are the most frequent // these queries are faster because application name and user name are part of the key ////PartitionKey = SecUtility.CombineToKey(applicationName, userName); ////RowKey = string.Empty; ApplicationName = applicationName; UserName = userName; Password = string.Empty; PasswordSalt = string.Empty; Email = string.Empty; PasswordAnswer = string.Empty; PasswordQuestion = string.Empty; Comment = string.Empty; ProfileBlobName = string.Empty; CreateDateUtc = ProviderConfiguration.MinSupportedDateTime; LastLoginDateUtc = ProviderConfiguration.MinSupportedDateTime; LastActivityDateUtc = ProviderConfiguration.MinSupportedDateTime; LastLockoutDateUtc = ProviderConfiguration.MinSupportedDateTime; LastPasswordChangedDateUtc = ProviderConfiguration.MinSupportedDateTime; FailedPasswordAttemptWindowStartUtc = ProviderConfiguration.MinSupportedDateTime; FailedPasswordAnswerAttemptWindowStartUtc = ProviderConfiguration.MinSupportedDateTime; ProfileLastUpdatedUtc = ProviderConfiguration.MinSupportedDateTime; ProfileIsCreatedByProfileProvider = false; ProfileSize = 0; }
public override string[] GetRolesForUser(string username) { SecUtility.CheckParameter(ref username, true, false, true, Constants.MaxTableUsernameLength, "username"); if (username.Length < 1) { return(new string[0]); } try { TableServiceContext svc = CreateDataServiceContext(); DataServiceQuery <RoleRow> queryObj = svc.CreateQuery <RoleRow>(_tableName); var query = (from user in queryObj where user.PartitionKey == SecUtility.CombineToKey(_applicationName, username) || user.PartitionKey == SecUtility.CombineToKey(_applicationName, string.Empty) select user).AsTableServiceQuery(); IEnumerable <RoleRow> userRows = query.Execute(); if (userRows == null) { return(new string[0]); } List <RoleRow> l = new List <RoleRow>(userRows); if (l.Count == 0) { return(new string[0]); } List <string> ret = new List <string>(); foreach (RoleRow user in l) { if (!string.IsNullOrEmpty(user.UserName) && !IsStaleRole(l, user.RoleName)) { ret.Add(user.RoleName); } } return(ret.ToArray()); } catch (InvalidOperationException e) { throw new ProviderException("Error while accessing the data store.", e); } }
public override void AddUsersToRoles(string[] usernames, string[] roleNames) { SecUtility.CheckArrayParameter(ref roleNames, true, true, true, MaxTableRoleNameLength, "roleNames"); SecUtility.CheckArrayParameter(ref usernames, true, true, true, Constants.MaxTableUsernameLength, "usernames"); try { TableServiceContext svc = CreateDataServiceContext(); foreach (string role in roleNames) { if (!RoleExists(role)) { throw new ProviderException(string.Format(CultureInfo.InstalledUICulture, "The role {0} does not exist!", role)); } foreach (string user in usernames) { var row = new RoleRow(_applicationName, role, user); try { svc.AddObject(_tableName, row); svc.SaveChangesWithRetries(); } catch (InvalidOperationException e) { if (e.InnerException is DataServiceClientException && (e.InnerException as DataServiceClientException).StatusCode == (int)HttpStatusCode.Conflict) { // this element already exists or was created in a failed retry // this is not a fatal error; continue adding elements Log.Write(EventKind.Warning, string.Format(CultureInfo.InstalledUICulture, "The user {0} already exists in the role {1}.", user, role)); svc.Detach(row); } else { throw new ProviderException(string.Format(CultureInfo.InstalledUICulture, "Error adding user {0} to role {1}", user, role)); } } } } } catch (InvalidOperationException e) { throw new ProviderException("Error while accessing the data store.", e); } }
public override string[] GetUsersInRole(string roleName) { SecUtility.CheckParameter(ref roleName, true, true, true, MaxTableRoleNameLength, "rolename"); try { TableServiceContext svc = CreateDataServiceContext(); DataServiceQuery <RoleRow> queryObj = svc.CreateQuery <RoleRow>(_tableName); var query = (from user in queryObj where user.PartitionKey.CompareTo(SecUtility.EscapedFirst(_applicationName)) >= 0 && user.PartitionKey.CompareTo(SecUtility.NextComparisonString(SecUtility.EscapedFirst(_applicationName))) < 0 && user.RowKey == SecUtility.Escape(roleName) select user).AsTableServiceQuery(); IEnumerable <RoleRow> userRows = query.Execute(); if (userRows == null) { // role does not exist; we are supposed to throw an exception here throw new ProviderException(string.Format(CultureInfo.InstalledUICulture, "The role {0} does not exist!", roleName)); } List <RoleRow> l = new List <RoleRow>(userRows); if (l.Count == 0 || IsStaleRole(l, roleName)) { throw new ProviderException(string.Format(CultureInfo.InstalledUICulture, "The role {0} does not exist!", roleName)); } List <string> ret = new List <string>(); foreach (RoleRow user in l) { if (!string.IsNullOrEmpty(user.UserName)) { ret.Add(user.UserName); } } return(ret.ToArray()); } catch (InvalidOperationException e) { throw new ProviderException("Error while accessing the data store.", e); } }
// RoleProvider methods public override void CreateRole(string roleName) { SecUtility.CheckParameter(ref roleName, true, true, true, MaxTableRoleNameLength, "rolename"); try { TableServiceContext svc = CreateDataServiceContext(); var newRole = new RoleRow(_applicationName, roleName, string.Empty); svc.AddObject(_tableName, newRole); svc.SaveChangesWithRetries(); } catch (InvalidOperationException e) { // when retry policies are used we cannot distinguish between a conflict and success // so, in the case of a conflict, we just retrun success here if (e.InnerException is DataServiceClientException && (e.InnerException as DataServiceClientException).StatusCode == (int)HttpStatusCode.Conflict) { return; // the role already exists } throw new ProviderException("Error accessing role table.", e); } }
public override string[] GetAllRoles() { try { DataServiceContext svc = CreateDataServiceContext(); DataServiceQuery <RoleRow> queryObj = svc.CreateQuery <RoleRow>(_tableName); var query = (from role in queryObj where role.PartitionKey == SecUtility.CombineToKey(_applicationName, string.Empty) select role).AsTableServiceQuery(); IEnumerable <RoleRow> userRows = query.Execute(); if (userRows == null) { return(new string[0]); } List <RoleRow> l = new List <RoleRow>(userRows); if (l.Count == 0) { return(new string[0]); } List <string> ret = new List <string>(); foreach (RoleRow role in l) { Debug.Assert(role.UserName != null); if (string.IsNullOrEmpty(role.UserName)) { ret.Add(role.RoleName); } } return(ret.ToArray()); } catch (InvalidOperationException e) { throw new ProviderException("Error while accessing the data store.", e); } }
public override bool DeleteRole(string roleName, bool throwOnPopulatedRole) { SecUtility.CheckParameter(ref roleName, true, true, true, MaxTableRoleNameLength, "rolename"); try { TableServiceContext svc = CreateDataServiceContext(); DataServiceQuery <RoleRow> queryObj = svc.CreateQuery <RoleRow>(_tableName); var query = (from userRole in queryObj where userRole.PartitionKey.CompareTo(SecUtility.EscapedFirst(_applicationName)) >= 0 && userRole.PartitionKey.CompareTo(SecUtility.NextComparisonString(SecUtility.EscapedFirst(_applicationName))) < 0 && userRole.RowKey == SecUtility.Escape(roleName) select userRole).AsTableServiceQuery(); IEnumerable <RoleRow> userRows = query.Execute(); if (userRows == null) { return(false); } var l = new List <RoleRow>(userRows); if (l.Count == 0) { // the role does not exist return(false); } RoleRow role; if (IsStaleRole(l, out role)) { return(false); } if (l.Count > 1 && throwOnPopulatedRole) { throw new ProviderException("Cannot delete populated role."); } svc.DeleteObject(role); svc.SaveChangesWithRetries(); // lets try to remove all remaining elements in the role foreach (RoleRow row in l) { if (row != role) { try { svc.DeleteObject(row); svc.SaveChangesWithRetries(); } catch (InvalidOperationException ex) { var dsce = ex.InnerException as DataServiceClientException; if (dsce != null) { if (ex.InnerException is DataServiceClientException && (dsce.StatusCode == (int)HttpStatusCode.NoContent || dsce.StatusCode == (int)HttpStatusCode.NotFound)) { // this element already was already deleted by another process or during a failed retry // this is not a fatal error; continue deleting elements Log.Write(EventKind.Warning, string.Format(CultureInfo.InstalledUICulture, "The user {0} does not exist in the role {1}.", row.UserName, row.RoleName)); } else { throw new ProviderException(string.Format(CultureInfo.InstalledUICulture, "Error deleting user {0} from role {1}.", row.UserName, row.RoleName)); } } } } } return(true); } catch (InvalidOperationException e) { throw new ProviderException("Error while accessing the data store.", e); } }
// we don't use the retry policy itself in this function because out parameters are not well handled by // retry policies private SessionStateStoreData GetSession(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions, bool exclusive) { SecUtility.CheckParameter(ref id, true, true, false, ProviderConfiguration.MaxStringPropertySizeInChars, "id"); SessionRow session = null; int curRetry = 0; bool retry; // Assign default values to out parameters locked = false; lockId = null; lockAge = TimeSpan.Zero; actions = SessionStateActions.None; do { retry = false; try { TableServiceContext svc = CreateDataServiceContext(); session = GetSession(id, svc); // Assign default values to out parameters locked = false; lockId = null; lockAge = TimeSpan.Zero; actions = SessionStateActions.None; // if the blob does not exist, we return null // ASP.NET will call the corresponding method for creating the session if (session == null) { return(null); } if (session.Initialized == false) { actions = SessionStateActions.InitializeItem; } session.ExpiresUtc = DateTime.UtcNow.AddMinutes(session.Timeout); if (exclusive) { if (!session.Locked) { if (session.Lock == Int32.MaxValue) { session.Lock = 0; } else { session.Lock++; } session.LockDateUtc = DateTime.UtcNow; } lockId = session.Lock; locked = session.Locked; session.Locked = true; } lockAge = DateTime.UtcNow.Subtract(session.LockDateUtc); lockId = session.Lock; if (locked) { return(null); } // let's try to write this back to the data store // in between, someone else could have written something to the store for the same session // we retry a number of times; if all fails, we throw an exception svc.UpdateObject(session); svc.SaveChangesWithRetries(); } catch (InvalidOperationException e) { // precondition fails indicates problems with the status code // not found means we have had the session deleted from under us if (e.InnerException is DataServiceClientException && (e.InnerException as DataServiceClientException).StatusCode == (int)HttpStatusCode.PreconditionFailed) { retry = true; } else if (e.InnerException is DataServiceClientException && (e.InnerException as DataServiceClientException).StatusCode == (int)HttpStatusCode.NotFound) { return(null); } else { throw new ProviderException("Error accessing the data store.", e); } } } while (retry && curRetry++ < NumRetries); // ok, now we have successfully written back our state // we can now read the blob // we do not need to care about read/write locking when accessing the // blob because each time we write a new session we create a new blob with a different name if (actions == SessionStateActions.InitializeItem || string.IsNullOrEmpty(session.BlobName)) { // Return an empty SessionStateStoreData return(new SessionStateStoreData( new SessionStateItemCollection(), SessionStateUtility.GetSessionStaticObjects(context), session.Timeout)); } try { BlobProperties properties; using (MemoryStream stream = blobProvider.GetBlobContent(session.BlobName, out properties)) using (var reader = new StreamReader(stream)) { // Read Items, StaticObjects, and Timeout from the file byte[] items = Convert.FromBase64String(reader.ReadLine()); byte[] statics = Convert.FromBase64String(reader.ReadLine()); int timeout = session.Timeout; // Deserialize the session return(DeserializeSession(items, statics, timeout)); } } catch (Exception e) { throw new ProviderException("Couldn't read session blob!", e); } }
public override void SetAndReleaseItemExclusive(HttpContext context, string id, SessionStateStoreData item, object lockId, bool newItem) { SecUtility.CheckParameter(ref id, true, true, false, ProviderConfiguration.MaxStringPropertySizeInChars, "id"); providerRetry(() => { TableServiceContext svc = CreateDataServiceContext(); SessionRow session; if (!newItem) { session = GetSession(id, svc); if (session == null || session.Lock != (int)lockId) { return; } } else { session = new SessionRow(id, applicationName) { Lock = 1, LockDateUtc = DateTime.UtcNow }; } session.Initialized = true; session.Timeout = item.Timeout; session.ExpiresUtc = DateTime.UtcNow.AddMinutes(session.Timeout); session.Locked = false; // yes, we always create a new blob here session.BlobName = GetBlobNamePrefix(id) + Guid.NewGuid().ToString("N"); // Serialize the session and write the blob byte[] items, statics; SerializeSession(item, out items, out statics); string serializedItems = Convert.ToBase64String(items); string serializedStatics = Convert.ToBase64String(statics); var output = new MemoryStream(); var writer = new StreamWriter(output); try { writer.WriteLine(serializedItems); writer.WriteLine(serializedStatics); writer.Flush(); // for us, it shouldn't matter whether newItem is set to true or false // because we always create the entire blob and cannot append to an // existing one blobProvider.UploadStream(session.BlobName, output); writer.Close(); output.Close(); } catch (Exception e) { if (!newItem) { ReleaseItemExclusive(svc, session, lockId); } throw new ProviderException("Error accessing the data store.", e); } finally { writer.Close(); output.Close(); } if (newItem) { svc.AddObject(tableName, session); svc.SaveChangesWithRetries(); } else { // Unlock the session and save changes ReleaseItemExclusive(svc, session, lockId); } }); }
public override void Initialize(string name, NameValueCollection config) { // Verify that config isn't null if (config == null) { throw new ArgumentNullException("config"); } // Assign the provider a default name if it doesn't have one if (String.IsNullOrEmpty(name)) { name = "TableStorageRoleProvider"; } // Add a default "description" attribute to config if the // attribute doesn't exist or is empty if (string.IsNullOrEmpty(config["description"])) { config.Remove("description"); config.Add("description", "Table storage-based role provider"); } // Call the base class's Initialize method base.Initialize(name, config); bool allowInsecureRemoteEndpoints = ProviderConfiguration.GetBooleanValue(config, "allowInsecureRemoteEndpoints", false); // structure storage-related properties ApplicationName = ProviderConfiguration.GetStringValueWithGlobalDefault(config, "applicationName", ProviderConfiguration.DefaultProviderApplicationNameConfigurationString, ProviderConfiguration.DefaultProviderApplicationName, false); _tableName = ProviderConfiguration.GetStringValueWithGlobalDefault(config, "roleTableName", ProviderConfiguration.DefaultRoleTableNameConfigurationString, ProviderConfiguration.DefaultRoleTableName, false); // remove required attributes config.Remove("allowInsecureRemoteEndpoints"); config.Remove("applicationName"); config.Remove("roleTableName"); // Throw an exception if unrecognized attributes remain if (config.Count > 0) { string attr = config.GetKey(0); if (!String.IsNullOrEmpty(attr)) { throw new ProviderException(string.Format(CultureInfo.InstalledUICulture, "Unrecognized attribute: {0}", attr)); } } CloudStorageAccount account = null; try { account = ProviderConfiguration.GetStorageAccount(ProviderConfiguration.DefaultStorageConfigurationString); SecUtility.CheckAllowInsecureEndpoints(allowInsecureRemoteEndpoints, account.Credentials, account.TableEndpoint); _tableStorage = account.CreateCloudTableClient(); _tableStorage.RetryPolicy = _tableRetry; TableStorageExtensionMethods.CreateTableIfNotExist <RoleRow>(_tableStorage, _tableName); } catch (SecurityException) { throw; } // catch InvalidOperationException as well as StorageException catch (Exception e) { if (account != null) { string exceptionDescription = ProviderConfiguration.GetInitExceptionDescription(account.Credentials, account.TableEndpoint, "table storage configuration"); string tableName = _tableName ?? "no role table name specified"; Log.Write(EventKind.Error, "Could not create or find role table: " + tableName + "!" + Environment.NewLine + exceptionDescription + Environment.NewLine + e.Message + Environment.NewLine + e.StackTrace); } throw new ProviderException("Could not create or find role table. The most probable reason for this is that " + "the storage endpoints are not configured correctly. Please look at the configuration settings " + "in your .cscfg and Web.config files. More information about this error " + "can be found in the logs when running inside the hosting environment or in the output " + "window of Visual Studio.", e); } }
public override void Initialize(string name, NameValueCollection config) { // Verify that config isn't null if (config == null) { throw new ArgumentNullException("config"); } // Assign the provider a default name if it doesn't have one if (String.IsNullOrEmpty(name)) { name = "TableServiceSessionStateProvider"; } // Add a default "description" attribute to config if the // attribute doesn't exist or is empty if (string.IsNullOrEmpty(config["description"])) { config.Remove("description"); config.Add("description", "Session state provider using table storage"); } // Call the base class's Initialize method base.Initialize(name, config); bool allowInsecureRemoteEndpoints = ProviderConfiguration.GetBooleanValue(config, "allowInsecureRemoteEndpoints", false); // structure storage-related properties applicationName = ProviderConfiguration.GetStringValueWithGlobalDefault( config, "applicationName", ProviderConfiguration.DefaultProviderApplicationNameConfigurationString, ProviderConfiguration.DefaultProviderApplicationName, false); tableName = ProviderConfiguration.GetStringValueWithGlobalDefault( config, "sessionTableName", ProviderConfiguration.DefaultSessionTableNameConfigurationString, ProviderConfiguration.DefaultSessionTableName, false); containerName = ProviderConfiguration.GetStringValueWithGlobalDefault( config, "containerName", ProviderConfiguration.DefaultSessionContainerNameConfigurationString, ProviderConfiguration.DefaultSessionContainerName, false); if (!SecUtility.IsValidContainerName(containerName)) { throw new ProviderException( "The provider configuration for the TableStorageSessionStateProvider does not contain a valid container name. " + "Please refer to the documentation for the concrete rules for valid container names." + "The current container name is: " + containerName); } config.Remove("allowInsecureRemoteEndpoints"); config.Remove("containerName"); config.Remove("applicationName"); config.Remove("sessionTableName"); // Throw an exception if unrecognized attributes remain if (config.Count > 0) { string attr = config.GetKey(0); if (!String.IsNullOrEmpty(attr)) { throw new ProviderException("Unrecognized attribute: " + attr); } } CloudStorageAccount account = null; try { account = ProviderConfiguration.GetStorageAccount(ProviderConfiguration.DefaultStorageConfigurationString); SecUtility.CheckAllowInsecureEndpoints(allowInsecureRemoteEndpoints, account.Credentials, account.TableEndpoint); SecUtility.CheckAllowInsecureEndpoints(allowInsecureRemoteEndpoints, account.Credentials, account.BlobEndpoint); tableStorage = account.CreateCloudTableClient(); tableStorage.RetryPolicy = tableRetry; lock (ThisLock) { TableStorageExtensionMethods.CreateTableIfNotExist <SessionRow>(tableStorage, tableName); } blobProvider = new BlobProvider(account.Credentials, account.BlobEndpoint, containerName); } catch (SecurityException) { throw; } catch (Exception e) { string exceptionDescription = ProviderConfiguration.GetInitExceptionDescription( account.Credentials, account.TableEndpoint, account.BlobEndpoint); string table = tableName ?? "no session table name specified"; string container = containerName ?? "no container name specified"; Log.Write( EventKind.Error, "Initialization of data service structures (tables and/or blobs) failed!" + exceptionDescription + Environment.NewLine + "Configured blob container: " + container + Environment.NewLine + "Configured table name: " + table + Environment.NewLine + e.Message + Environment.NewLine + e.StackTrace); throw new ProviderException( "Initialization of data service structures (tables and/or blobs) failed!" + "The most probable reason for this is that " + "the storage endpoints are not configured correctly. Please look at the configuration settings " + "in your .cscfg and Web.config files. More information about this error " + "can be found in the logs when running inside the hosting environment or in the output " + "window of Visual Studio.", e); } }
// Because of limited transactional support in the table storage offering, this function gives limited guarantees // for inserting all users into all roles. // We do not recommend using this function because of missing transactional support. // the username to match can be in a format that varies between providers // for this implementation, a syntax similar to the one used in the SQL provider is applied // "user%" will return all users in a role that start with the string "user" // the % sign can only appear at the end of the usernameToMatch parameter // because the current version of the table storage service does not support StartsWith in LINQ queries, // calling this function can cause significant network trafic when '%' is used in the usernameToMach // parameter public override string[] FindUsersInRole(string roleName, string usernameToMatch) { SecUtility.CheckParameter(ref roleName, true, true, true, MaxTableRoleNameLength, "rolename"); SecUtility.CheckParameter(ref usernameToMatch, true, true, false, Constants.MaxTableUsernameLength, "usernameToMatch"); bool startswith = false; if (usernameToMatch.Contains('%')) { if (usernameToMatch.IndexOf('%') != usernameToMatch.Length - 1) { throw new ArgumentException("The TableStorageRoleProvider only supports search strings that contain '%' as the last character!"); } usernameToMatch = usernameToMatch.Substring(0, usernameToMatch.Length - 1); startswith = true; } try { TableServiceContext svc = CreateDataServiceContext(); DataServiceQuery <RoleRow> queryObj = svc.CreateQuery <RoleRow>(_tableName); CloudTableQuery <RoleRow> query; if (startswith && string.IsNullOrEmpty(usernameToMatch)) { // get all users in the role query = (from userRole in queryObj where userRole.PartitionKey.CompareTo(SecUtility.EscapedFirst(_applicationName)) >= 0 && userRole.PartitionKey.CompareTo(SecUtility.NextComparisonString(SecUtility.EscapedFirst(_applicationName))) < 0 && userRole.RowKey == SecUtility.Escape(roleName) select userRole).AsTableServiceQuery(); } else if (startswith) { // get all users in the role that start with the specified string (we cannot restrict the query more because StartsWith is not supported) // we cannot include the username to search for in the key, because the key might e escaped query = (from userRole in queryObj where userRole.PartitionKey.CompareTo(SecUtility.EscapedFirst(_applicationName)) >= 0 && userRole.PartitionKey.CompareTo(SecUtility.NextComparisonString(SecUtility.EscapedFirst(_applicationName))) < 0 && userRole.RowKey == SecUtility.Escape(roleName) && (userRole.UserName.CompareTo(usernameToMatch) >= 0 || userRole.UserName == string.Empty) select userRole).AsTableServiceQuery(); } else { // get a specific user query = (from userRole in queryObj where (userRole.PartitionKey == SecUtility.CombineToKey(_applicationName, usernameToMatch) || userRole.PartitionKey == SecUtility.CombineToKey(_applicationName, string.Empty)) && userRole.RowKey == SecUtility.Escape(roleName) select userRole).AsTableServiceQuery(); } IEnumerable <RoleRow> userRows = query.Execute(); if (userRows == null) { throw new ProviderException("The role does not exist!"); } var l = new List <RoleRow>(userRows); if (l.Count == 0) { // the role does not exist throw new ProviderException("The role does not exist!"); } RoleRow role; if (IsStaleRole(l, out role)) { throw new ProviderException("The role does not exist!"); } var ret = new List <string>(); foreach (RoleRow row in l) { if (row != role) { if (startswith && !string.IsNullOrEmpty(usernameToMatch) && !row.UserName.StartsWith(usernameToMatch, StringComparison.Ordinal)) { continue; } ret.Add(row.UserName); } } return(ret.ToArray()); } catch (InvalidOperationException e) { throw new ProviderException("Error while accessing the data store.", e); } }