/// <summary> /// Logs an authenticated user out. /// </summary> /// <remarks> /// This method will return a single, anonymous user. /// <para> /// By default, this method can only be used for forms authentication and leverages /// ASP.NET <see cref="FormsAuthentication"/>. /// </para> /// </remarks> /// <returns>A single, default user.</returns> /// <exception cref="InvalidOperationException"> is thrown if the ASP.NET /// authentication mode is not <see cref="AuthenticationMode.Forms"/>. /// </exception> /// <seealso cref="GetUser()"/> public T Logout() { AuthenticationBase <T> .CheckAuthenticationMode(); this.ClearAuthenticationToken(); return(this.GetUserCore(AuthenticationBase <T> .DefaultPrincipal)); }
/// <summary> /// Returns a value indicating whether the specified property has a backing member in /// the ASP.NET profile. /// </summary> /// <param name="propertyInfo">The property to make the determination for</param> /// <returns>Whether the property is in the profile</returns> private static bool IsInProfile(PropertyInfo propertyInfo) { bool isInProfile = true; ProfileUsageAttribute usageAttribute = AuthenticationBase <T> .GetProfileUsage(propertyInfo); if (usageAttribute != null) { isInProfile = !usageAttribute.IsExcluded; } return(isInProfile); }
/// <summary> /// Authenticates and returns the user with the specified name and password. /// </summary> /// <remarks> /// This method will return a single user if the /// authentication was successful. If the user could not be authenticated, <c>null</c> /// will be returned. /// <para> /// By default, this method can be only used for forms authentication and leverages /// ASP.NET <see cref="Membership"/> and <see cref="FormsAuthentication"/>. /// </para> /// </remarks> /// <param name="userName">The userName associated with the user to authenticate</param> /// <param name="password">The password associated with the user to authenticate</param> /// <param name="isPersistent">Whether the authentication should persist between sessions</param> /// <param name="customData">Optional implementation-specific data. It is unused by this base class.</param> /// <returns>A single user or <c>null</c> if authentication failed</returns> /// <exception cref="InvalidOperationException"> is thrown if the ASP.NET /// authentication mode is not <see cref="AuthenticationMode.Forms"/>. /// </exception> /// <seealso cref="GetUser()"/> public T Login(string userName, string password, bool isPersistent, string customData) { AuthenticationBase <T> .CheckAuthenticationMode(); if (this.ValidateUser(userName, password)) { IPrincipal principal = new GenericPrincipal( new GenericIdentity(userName, "Forms"), AuthenticationBase <T> .DefaultRoles.ToArray()); this.IssueAuthenticationToken(principal, isPersistent); return(this.GetUserCore(principal)); } return(default(T)); }
/// <summary> /// Gets the profile alias for the specified property. /// </summary> /// <remarks> /// This is either: /// <para> /// 1) <see cref="ProfileUsageAttribute.Alias"/> when the property is marked with the attribute. /// 2) <see cref="MemberInfo.Name"/> for the specified property. /// </para> /// </remarks> /// <param name="propertyInfo">The property to get the profile alias for</param> /// <returns>The profile alias for the specified property</returns> private static string GetProfileAlias(PropertyInfo propertyInfo) { string profileAlias = propertyInfo.Name; ProfileUsageAttribute usageAttribute = AuthenticationBase <T> .GetProfileUsage(propertyInfo); if (usageAttribute != null) { if (!string.IsNullOrEmpty(usageAttribute.Alias)) { profileAlias = usageAttribute.Alias; } } return(profileAlias); }
/// <summary> /// Gets the profile settings for the current user from the <see cref="ProfileBase"/> /// and sets them into the specified <paramref name="user"/>. /// </summary> /// <remarks> /// The <paramref name="user"/> is updated from the profile using the following algorithm. /// <para> /// For every property in <paramref name="user"/>: /// if (the property can be set and is in the profile) /// then set the property value using the value in the profile specified by the alias /// </para> /// </remarks> /// <param name="user">The user to update with the profile settings</param> /// <exception cref="InvalidDataContractException"> is thrown if a property in /// <paramref name="user"/> that meets the specified conditions does not have a /// corresponding profile value. /// </exception> private static void GetProfile(T user) { if (string.IsNullOrEmpty(user.Name) || !ProfileManager.Enabled) { return; } // We're creating a new profile so this algorithm works with both Login and // Logout where the current principal and Profile have not been updated. ProfileBase profile = ProfileBase.Create(user.Name); foreach (PropertyInfo property in user.GetType().GetProperties()) { if (!property.CanWrite || !AuthenticationBase <T> .IsInProfile(property) || property.GetIndexParameters().Length > 0) { // Skip this property if it is not writable or in the profile or is an indexer property continue; } try { property.SetValue(user, profile.GetPropertyValue(AuthenticationBase <T> .GetProfileAlias(property)), null); } catch (System.Data.SqlClient.SqlException ex) { // The default ASP.NET providers use SQL. Since these errors are sometimes // hard to interpret, we're wrapping them to provide more context. throw new DomainException(string.Format( CultureInfo.InvariantCulture, Resources.ApplicationServices_ProviderError, "Profile", ex.Message), ex); } catch (SettingsPropertyNotFoundException e) { throw new InvalidDataContractException( string.Format( CultureInfo.InvariantCulture, Resources.ApplicationServices_ProfilePropertyDoesNotExist, AuthenticationBase <T> .GetProfileAlias(property)), e); } } }
/// <summary> /// Gets the user for the specified principal. /// </summary> /// <remarks> /// The user is populated with data from <paramref name="principal"/>, /// <see cref="Roles"/>, and <see cref="ProfileBase"/>. /// </remarks> /// <param name="principal">The principal to get the user for</param> /// <returns>The user for the specified principal</returns> private T GetUserImpl(IPrincipal principal) { T user = this.CreateUser(); if (user == null) { throw new InvalidOperationException( string.Format( CultureInfo.InvariantCulture, Resources.ApplicationServices_CreateUserCannotBeNull, this.GetType())); } user.Name = principal.Identity.Name; user.Roles = AuthenticationBase <T> .GetRoles(user.Name); AuthenticationBase <T> .GetProfile(user); return(user); }
/// <summary> /// Updates the user data for the authenticated identity. /// </summary> /// <remarks> /// This method is invoked from <see cref="UpdateUser"/> after the identity of the /// current principal has been verified. It is responsible for persisting the /// updated user data. By default, this method will persist the user using /// <see cref="ProfileBase"/>. The base implementation does not need to be invoked /// when this method is overridden. /// </remarks> /// <param name="user">The updated user data</param> protected virtual void UpdateUserCore(T user) { AuthenticationBase <T> .UpdateProfile(user); }
public T GetUser() { return(this.GetUserCore(AuthenticationBase <T> .GetPrincipal())); }
/// <summary> /// Writes the profile settings for the current user to the <see cref="ProfileBase"/> /// using the specified <paramref name="user"/>. /// </summary> /// <remarks> /// The profile is updated from the <paramref name="user"/> using the following algorithm. /// <para> /// For every property in <paramref name="user"/>: /// if (the property can be read and is in the profile) /// then use the property value to set the value in the profile specified by the alias /// </para> /// </remarks> /// <param name="user">The user to update the profile settings with</param> /// <exception cref="InvalidDataContractException"> is thrown if a property in /// <paramref name="user"/> that meets the specified conditions does not have a /// corresponding profile value. /// </exception> private static void UpdateProfile(T user) { if (string.IsNullOrEmpty(user.Name) || !ProfileManager.Enabled) { return; } // We're using the current Profile since we've verified it matches the current // principal and it allows us to leverage the auto-save feature. When testing, // however, we'll need to create a new one. ProfileBase profile = AuthenticationBase <T> .GetProfileBase(user.Name); foreach (PropertyInfo property in user.GetType().GetProperties()) { if (!property.CanRead || !property.CanWrite || !AuthenticationBase <T> .IsInProfile(property) || AuthenticationBase <T> .IsReadOnly(property) || property.GetIndexParameters().Length > 0) { // Skip this property if it is not readable, in the profile, is readonly or is an indexer property continue; } try { profile.SetPropertyValue(AuthenticationBase <T> .GetProfileAlias(property), property.GetValue(user, null)); } catch (SettingsPropertyNotFoundException e) { throw new InvalidDataContractException( string.Format( CultureInfo.InvariantCulture, Resources.ApplicationServices_ProfilePropertyDoesNotExist, AuthenticationBase <T> .GetProfileAlias(property)), e); } catch (SettingsPropertyIsReadOnlyException e) { throw new InvalidDataContractException( string.Format( CultureInfo.InvariantCulture, Resources.ApplicationServices_ProfilePropertyReadOnly, AuthenticationBase <T> .GetProfileAlias(property)), e); } catch (SettingsPropertyWrongTypeException e) { throw new InvalidDataContractException( string.Format( CultureInfo.InvariantCulture, Resources.ApplicationServices_ProfilePropertyTypeMismatch, AuthenticationBase <T> .GetProfileAlias(property)), e); } } // Explicit invocation is necessary when auto-save is not enabled bool isAutoSaveEnabled = false; try { isAutoSaveEnabled = ProfileManager.AutomaticSaveEnabled; } catch (HttpException) { // If the feature is not supported at the current hosting permission level, // we can assume it is not enabled. } if (!isAutoSaveEnabled) { profile.Save(); } }