- Home
- General
- General Chat
Constable Authorization Engine CAZE.NET
Joined: 15-Oct-2004
I am considering utilizing the CAZE engine to implement authorization security in a future application. Hoped to check if any LLBL'ers have used it in their own applications? http://lamarvin.com/caze_default.asp
Joined: 08-Jun-2004
Is your project a web app? If so, why not use the built in security mechanisms that come with .NET 2.0? They're very easy to use.
Joined: 30-Nov-2003
I am keenly interested as well...I lost the thread on the subject Alex. Did you finish the membership project?
Joined: 08-Jun-2004
Finally got approval to post this code.
First, the disclaimer. MSDN provides sample membership and role provider classes. I simply copy/pasted their code and replaced their ADO.NET related code with LLBLGen specific code. The end result has worked great for me so far, but I do not guarantee it to be bug free. Heck, I fixed a spelling mistake after pasting the code into this window! Please let me know if you find any bugs or add any enhancements as I'd like to update my code with your changes.
One thing I know that can be enhanced is in the role provider. My app won't ever have more than like 5 roles total so I don't see a problem caching that information in the Application object thus speeding up the Membership.IsInRole functions.
Other than that, it should be pretty straight forward. I removed all traces of my current project, but may have accidently introduced a bug in the process (A global search/replace will do that sometimes).
Place all of the files in your project and go through the code to make sure objects and namespaces are named according to your application. For example, you will probably want to use something other than YourProject and MyMembershipProvider.
Below is the code for the membership provider.
Imports System.Web.Security
Imports System.Configuration.Provider
Imports System.Collections.Specialized
Imports System
Imports System.Data
Imports System.Data.Odbc
Imports System.Configuration
Imports System.Diagnostics
Imports System.Web
Imports System.Globalization
Imports System.Security.Cryptography
Imports System.Text
Imports System.Web.Configuration
Imports SD.LLBLGen.Pro.ORMSupportClasses
Imports YourProject.DAL
Imports YourProject.DAL.DatabaseSpecific
Imports YourProject.DAL.EntityClasses
Imports YourProject.DAL.HelperClasses
Imports YourProject.DAL.FactoryClasses
Imports YourProject.DAL.RelationClasses
Imports YourProject.DAL.ValidatorClasses
Namespace YourProject.Providers
Public NotInheritable Class MyMembershipProvider
Inherits MembershipProvider
Private _adapter As DataAccessAdapter2
Private newPasswordLength As Integer = 8
Private machineKey As MachineKeySection
Public Overrides Sub Initialize(ByVal name As String, ByVal config As NameValueCollection)
If config Is Nothing Then _
Throw New ArgumentNullException("config")
If name Is Nothing OrElse name.Length = 0 Then _
name = "MyMembershipProvider"
If String.IsNullOrEmpty(config("description")) Then
config.Remove("description")
config.Add("description", "Interacts with custom tables in the Membership database")
End If
' Initialize the abstract base class.
MyBase.Initialize(name, config)
pApplicationName = GetConfigValue(config("applicationName"), _
System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath)
pMaxInvalidPasswordAttempts = Convert.ToInt32(GetConfigValue(config("maxInvalidPasswordAttempts"), "5"))
pPasswordAttemptWindow = Convert.ToInt32(GetConfigValue(config("passwordAttemptWindow"), "10"))
pMinRequiredNonAlphanumericCharacters = Convert.ToInt32(GetConfigValue(config("minRequiredAlphaNumericCharacters"), "1"))
pMinRequiredPasswordLength = Convert.ToInt32(GetConfigValue(config("minRequiredPasswordLength"), "7"))
pPasswordStrengthRegularExpression = Convert.ToString(GetConfigValue(config("passwordStrengthRegularExpression"), ""))
pEnablePasswordReset = Convert.ToBoolean(GetConfigValue(config("enablePasswordReset"), "True"))
pEnablePasswordRetrieval = Convert.ToBoolean(GetConfigValue(config("enablePasswordRetrieval"), "True"))
pRequiresQuestionAndAnswer = Convert.ToBoolean(GetConfigValue(config("requiresQuestionAndAnswer"), "False"))
pRequiresUniqueEmail = Convert.ToBoolean(GetConfigValue(config("requiresUniqueEmail"), "True"))
Dim temp_format As String = config("passwordFormat")
If temp_format Is Nothing Then
temp_format = "Hashed"
End If
Select Case temp_format
Case "Hashed"
pPasswordFormat = MembershipPasswordFormat.Hashed
Case "Encrypted"
pPasswordFormat = MembershipPasswordFormat.Encrypted
Case "Clear"
pPasswordFormat = MembershipPasswordFormat.Clear
Case Else
Throw New ProviderException("Password format not supported.")
End Select
_adapter = New DataAccessAdapter2()
' Get encryption and decryption key information from the configuration.
Dim cfg As System.Configuration.Configuration = _
WebConfigurationManager.OpenWebConfiguration(System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath)
machineKey = CType(cfg.GetSection("system.web/machineKey"), MachineKeySection)
End Sub
'
' A helper function to retrieve config values from the configuration file.
'
Private Function GetConfigValue(ByVal configValue As String, ByVal defaultValue As String) As String
If String.IsNullOrEmpty(configValue) Then _
Return defaultValue
Return configValue
End Function
'
' System.Web.Security.MembershipProvider properties.
'
Private pApplicationName As String
Private pEnablePasswordReset As Boolean
Private pEnablePasswordRetrieval As Boolean
Private pRequiresQuestionAndAnswer As Boolean
Private pRequiresUniqueEmail As Boolean
Private pMaxInvalidPasswordAttempts As Integer
Private pPasswordAttemptWindow As Integer
Private pPasswordFormat As MembershipPasswordFormat
Public Overrides Property ApplicationName() As String
Get
Return pApplicationName
End Get
Set(ByVal value As String)
pApplicationName = value
End Set
End Property
Public Overrides ReadOnly Property EnablePasswordReset() As Boolean
Get
Return pEnablePasswordReset
End Get
End Property
Public Overrides ReadOnly Property EnablePasswordRetrieval() As Boolean
Get
Return pEnablePasswordRetrieval
End Get
End Property
Public Overrides ReadOnly Property RequiresQuestionAndAnswer() As Boolean
Get
Return pRequiresQuestionAndAnswer
End Get
End Property
Public Overrides ReadOnly Property RequiresUniqueEmail() As Boolean
Get
Return pRequiresUniqueEmail
End Get
End Property
Public Overrides ReadOnly Property MaxInvalidPasswordAttempts() As Integer
Get
Return pMaxInvalidPasswordAttempts
End Get
End Property
Public Overrides ReadOnly Property PasswordAttemptWindow() As Integer
Get
Return pPasswordAttemptWindow
End Get
End Property
Public Overrides ReadOnly Property PasswordFormat() As MembershipPasswordFormat
Get
Return pPasswordFormat
End Get
End Property
Private pMinRequiredNonAlphanumericCharacters As Integer
Public Overrides ReadOnly Property MinRequiredNonAlphanumericCharacters() As Integer
Get
Return pMinRequiredNonAlphanumericCharacters
End Get
End Property
Private pMinRequiredPasswordLength As Integer
Public Overrides ReadOnly Property MinRequiredPasswordLength() As Integer
Get
Return pMinRequiredPasswordLength
End Get
End Property
Private pPasswordStrengthRegularExpression As String
Public Overrides ReadOnly Property PasswordStrengthRegularExpression() As String
Get
Return pPasswordStrengthRegularExpression
End Get
End Property
'
' System.Web.Security.MembershipProvider methods.
'
'
' MembershipProvider.ChangePassword
'
Public Overrides Function ChangePassword(ByVal username As String, _
ByVal oldPwd As String, _
ByVal newPassword As String) As Boolean
If Not ValidateUser(username, oldPwd) Then _
Return False
Dim args As ValidatePasswordEventArgs = _
New ValidatePasswordEventArgs(username, newPassword, True)
OnValidatingPassword(args)
If args.Cancel Then
If Not args.FailureInformation Is Nothing Then
Throw args.FailureInformation
Else
Throw New ProviderException("Change password canceled due to New password validation failure.")
End If
End If
' Update users matching the specified username and application name
Dim bucket As New RelationPredicateBucket()
bucket.PredicateExpression.Add(PredicateFactory.CompareValue(UserFieldIndex.UserName, ComparisonOperator.Equal, username))
bucket.PredicateExpression.AddWithAnd(PredicateFactory.CompareValue(UserFieldIndex.ApplicationName, ComparisonOperator.Equal, Me.ApplicationName))
Dim user As New UserEntity()
user.LastPasswordChangeDate = DateTime.Now
user.Password = EncodePassword(newPassword)
Dim rowsAffected As Integer = 0
Try
_adapter.OpenConnection()
rowsAffected = _adapter.UpdateEntitiesDirectly(user, bucket)
Catch ex As Exception
Throw New ProviderException("Error updating password", ex)
Finally
_adapter.CloseConnection()
End Try
If rowsAffected > 0 Then
Return True
End If
Return False
End Function
'
' MembershipProvider.ChangePasswordQuestionAndAnswer
'
Public Overrides Function ChangePasswordQuestionAndAnswer(ByVal username As String, _
ByVal password As String, _
ByVal newPwdQuestion As String, _
ByVal newPwdAnswer As String) As Boolean
If Not ValidateUser(username, password) Then _
Return False
' Update users matching the specified username and application name
Dim bucket As New RelationPredicateBucket()
bucket.PredicateExpression.Add(PredicateFactory.CompareValue(UserFieldIndex.UserName, ComparisonOperator.Equal, username))
bucket.PredicateExpression.AddWithAnd(PredicateFactory.CompareValue(UserFieldIndex.ApplicationName, ComparisonOperator.Equal, Me.ApplicationName))
Dim user As New UserEntity()
user.PasswordQuestion = newPwdQuestion
user.Password = newPwdAnswer
Dim rowsAffected As Integer = 0
Try
_adapter.OpenConnection()
rowsAffected = _adapter.UpdateEntitiesDirectly(user, bucket)
Catch ex As Exception
Throw New ProviderException("Error updating password question and answer", ex)
Finally
_adapter.CloseConnection()
End Try
If rowsAffected > 0 Then
Return True
End If
Return False
End Function
'
' MembershipProvider.CreateUser
'
Public Overrides Function CreateUser(ByVal username As String, _
ByVal password As String, _
ByVal email As String, _
ByVal passwordQuestion As String, _
ByVal passwordAnswer As String, _
ByVal isApproved As Boolean, _
ByVal providerUserKey As Object, _
ByRef status As MembershipCreateStatus) As MembershipUser
Dim Args As ValidatePasswordEventArgs = _
New ValidatePasswordEventArgs(username, password, True)
OnValidatingPassword(Args)
If Args.Cancel Then
status = MembershipCreateStatus.InvalidPassword
Return Nothing
End If
If RequiresUniqueEmail AndAlso GetUserNameByEmail(email) <> "" Then
status = MembershipCreateStatus.DuplicateEmail
Return Nothing
End If
Dim u As MembershipUser = GetUser(username, False)
If u Is Nothing Then
Dim user As New UserEntity()
user.UserName = username
user.Password = EncodePassword(password)
user.Email = email
user.SchoolId = 0
user.PasswordQuestion = passwordQuestion
user.PasswordAnswer = EncodePassword(passwordAnswer)
user.IsApproved = isApproved
user.Description = ""
user.LastPasswordChangeDate = DateTime.Now
user.LastActivityDate = DateTime.Now
user.ApplicationName = Me.ApplicationName
user.IsLockedOut = False
user.LastLockedOutDate = DateTime.Now
user.FailedPasswordAttemptCount = 0
user.FailedPasswordAttemptWindowStart = DateTime.Now
user.FailedPasswordAnswerAttemptCount = 0
user.FailedPasswordAnswerAttemptWindowStart = DateTime.Now
Dim userCreated As Boolean = False
Try
_adapter.OpenConnection()
userCreated = _adapter.SaveEntity(user)
If (userCreated) Then
status = MembershipCreateStatus.Success
Else
status = MembershipCreateStatus.UserRejected
End If
Catch e As Exception
status = MembershipCreateStatus.ProviderError
Throw New ProviderException("Error creating user", e)
Finally
_adapter.CloseConnection()
End Try
Return GetUser(username, False)
Else
status = MembershipCreateStatus.DuplicateUserName
End If
Return Nothing
End Function
'
' MembershipProvider.DeleteUser
'
Public Overrides Function DeleteUser(ByVal username As String, _
ByVal deleteAllRelatedData As Boolean) As Boolean
Dim bucket As New RelationPredicateBucket
bucket.PredicateExpression.Add(PredicateFactory.CompareValue(UserFieldIndex.UserName, ComparisonOperator.Equal, username))
bucket.PredicateExpression.AddWithAnd(PredicateFactory.CompareValue(UserFieldIndex.ApplicationName, ComparisonOperator.Equal, Me.ApplicationName))
Dim rowsAffected As Integer = 0
Try
_adapter.OpenConnection()
rowsAffected = _adapter.DeleteEntitiesDirectly("User", bucket)
If deleteAllRelatedData Then
' Process commands to delete all data for the user in the database.
End If
Catch e As Exception
Throw New ProviderException("Erorr deleting user", e)
Finally
_adapter.CloseConnection()
End Try
If rowsAffected > 0 Then _
Return True
Return False
End Function
'
' MembershipProvider.GetAllUsers
'
Public Overrides Function GetAllUsers(ByVal pageIndex As Integer, _
ByVal pageSize As Integer, _
ByRef totalRecords As Integer) _
As MembershipUserCollection
Dim allUsers As New EntityCollection(New UserEntityFactory())
Dim bucket As New RelationPredicateBucket()
bucket.PredicateExpression.Add(PredicateFactory.CompareValue(UserFieldIndex.ApplicationName, ComparisonOperator.Equal, Me.ApplicationName))
Dim sorter As New SortExpression(SortClauseFactory.Create(UserFieldIndex.UserName, SortOperator.Ascending))
Dim users As MembershipUserCollection = New MembershipUserCollection()
totalRecords = 0
Try
_adapter.OpenConnection()
_adapter.FetchEntityCollection(allUsers, bucket, 0, sorter)
totalRecords = allUsers.Count
If totalRecords <= 0 Then Return users
Dim counter As Integer = 0
Dim startIndex As Integer = pageSize * pageIndex
Dim endIndex As Integer = startIndex + pageSize - 1
Do While counter < totalRecords
If counter >= startIndex Then
Dim u As MembershipUser = GetMembershipUserFromEntity(allUsers(counter))
users.Add(u)
End If
counter += 1
Loop
Catch e As Exception
Throw New ProviderException("Error getting all users", e)
Finally
_adapter.CloseConnection()
End Try
Return users
End Function
'
' GetMembershipUserFromEntity
' A helper function that takes the current user entity
' and hydrates a MembershiUser from the values. Called by the
' MembershipUser.GetUser implementation.
'
Private Function GetMembershipUserFromEntity(ByVal user As UserEntity) As MembershipUser
Dim providerUserKey As Object = user.UserId
Dim username As String = user.UserName
Dim email As String = user.Email
Dim passwordQuestion As String = user.PasswordQuestion
Dim comment As String = user.Description
Dim isApproved As Boolean = user.IsApproved
Dim isLockedOut As Boolean = user.IsLockedOut
Dim creationDate As DateTime = user.CreatedDate
Dim lastLoginDate As DateTime = user.LastLoginDate
Dim lastActivityDate As DateTime = user.LastActivityDate
Dim lastPasswordChangedDate As DateTime = user.LastPasswordChangeDate
Dim lastLockedOutDate As DateTime = user.LastLockedOutDate
Dim u As MembershipUser = New MembershipUser(Me.Name, _
username, _
providerUserKey, _
email, _
passwordQuestion, _
comment, _
isApproved, _
isLockedOut, _
creationDate, _
lastLoginDate, _
lastActivityDate, _
lastPasswordChangedDate, _
lastLockedOutDate)
Return u
End Function
'
' MembershipProvider.GetNumberOfUsersOnline
'
Public Overrides Function GetNumberOfUsersOnline() As Integer
Dim onlineSpan As TimeSpan = New TimeSpan(0, System.Web.Security.Membership.UserIsOnlineTimeWindow, 0)
Dim compareTime As DateTime = DateTime.Now.Subtract(onlineSpan)
Dim lastActiveUsers As New EntityCollection(New UserEntityFactory())
Dim bucket As New RelationPredicateBucket()
bucket.PredicateExpression.Add(PredicateFactory.CompareValue(UserFieldIndex.LastActivityDate, ComparisonOperator.GreaterThan, compareTime))
bucket.PredicateExpression.AddWithAnd(PredicateFactory.CompareValue(UserFieldIndex.ApplicationName, ComparisonOperator.Equal, Me.ApplicationName))
Dim numOnline As Integer = 0
Try
_adapter.OpenConnection()
_adapter.FetchEntityCollection(lastActiveUsers, bucket)
numOnline = lastActiveUsers.Count
Catch e As Exception
Throw New ProviderException("Error getting users onlnie", e)
Finally
_adapter.CloseConnection()
End Try
Return numOnline
End Function
'
' MembershipProvider.GetPassword
'
Public Overrides Function GetPassword(ByVal username As String, ByVal answer As String) As String
If Not EnablePasswordRetrieval Then
Throw New ProviderException("Password Retrieval Not Enabled.")
End If
If PasswordFormat = MembershipPasswordFormat.Hashed Then
Throw New ProviderException("Cannot retrieve Hashed passwords.")
End If
Dim user As New UserEntity()
user.UserName = username
user.ApplicationName = Me.ApplicationName
Dim password As String = ""
Dim passwordAnswer As String = ""
Dim foundUser As Boolean = False
Try
_adapter.OpenConnection()
foundUser = _adapter.FetchEntityUsingUniqueConstraint(user, user.ConstructFilterForUCUserNameApplicationName())
If foundUser Then
If user.IsLockedOut Then _
Throw New MembershipPasswordException("The supplied user is locked out.")
password = user.Password
passwordAnswer = user.PasswordAnswer
Else
Throw New MembershipPasswordException("The supplied user name is not found.")
End If
Catch e As Exception
Throw New ProviderException("Error getting password", e)
Finally
_adapter.CloseConnection()
End Try
If RequiresQuestionAndAnswer AndAlso Not CheckPassword(answer, passwordAnswer) Then
UpdateFailureCount(username, "passwordAnswer")
Throw New MembershipPasswordException("Incorrect password answer.")
End If
If PasswordFormat = MembershipPasswordFormat.Encrypted Then
password = UnEncodePassword(password)
End If
Return password
End Function
'
' MembershipProvider.GetUser(String, Boolean)
'
Public Overrides Function GetUser(ByVal username As String, _
ByVal userIsOnline As Boolean) As MembershipUser
Dim user As New UserEntity()
user.UserName = username
user.ApplicationName = Me.ApplicationName
Dim u As MembershipUser = Nothing
Try
_adapter.OpenConnection()
Dim foundUser As Boolean = False
foundUser = _adapter.FetchEntityUsingUniqueConstraint(user, user.ConstructFilterForUCUserNameApplicationName())
If foundUser Then
u = GetMembershipUserFromEntity(user)
If userIsOnline Then
user.LastActivityDate = DateTime.Now
_adapter.SaveEntity(user)
End If
End If
Catch e As Exception
Throw New ProviderException("Error getting user", e)
Finally
_adapter.CloseConnection()
End Try
Return u
End Function
'
' MembershipProvider.GetUser(Object, Boolean)
'
Public Overrides Function GetUser(ByVal providerUserKey As Object, _
ByVal userIsOnline As Boolean) As MembershipUser
Dim user As New UserEntity(Convert.ToInt32(providerUserKey))
Dim u As MembershipUser = Nothing
Try
_adapter.OpenConnection()
Dim foundUser As Boolean = _adapter.FetchEntity(user)
If foundUser Then
u = GetMembershipUserFromEntity(user)
If userIsOnline Then
user.LastActivityDate = DateTime.Now
_adapter.SaveEntity(user)
End If
End If
Catch e As Exception
Throw New ProviderException("Error getting user", e)
Finally
_adapter.CloseConnection()
End Try
Return u
End Function
'
'
' MembershipProvider.UnlockUser
'
Public Overrides Function UnlockUser(ByVal username As String) As Boolean
Dim user As New UserEntity
user.IsLockedOut = False
Dim bucket As New RelationPredicateBucket()
bucket.PredicateExpression.Add(PredicateFactory.CompareValue(UserFieldIndex.UserName, ComparisonOperator.Equal, username))
bucket.PredicateExpression.AddWithAnd(PredicateFactory.CompareValue(UserFieldIndex.ApplicationName, ComparisonOperator.Equal, Me.ApplicationName))
Dim rowsAffected As Integer = 0
Try
rowsAffected = _adapter.UpdateEntitiesDirectly(user, bucket)
Catch e As Exception
Throw New ProviderException("Error unlocking user", e)
Finally
_adapter.CloseConnection()
End Try
If rowsAffected > 0 Then _
Return True
Return False
End Function
'
' MembershipProvider.GetUserNameByEmail
'
Public Overrides Function GetUserNameByEmail(ByVal email As String) As String
Dim users As New EntityCollection(New UserEntityFactory())
Dim bucket As New RelationPredicateBucket()
bucket.PredicateExpression.Add(PredicateFactory.CompareValue(UserFieldIndex.Email, ComparisonOperator.Equal, email))
bucket.PredicateExpression.AddWithAnd(PredicateFactory.CompareValue(UserFieldIndex.ApplicationName, ComparisonOperator.Equal, Me.ApplicationName))
Dim username As String = ""
Try
_adapter.OpenConnection()
_adapter.FetchEntityCollection(users, bucket)
If (users.Count > 0) Then
username = CType(users(0), UserEntity).UserName
End If
Catch e As Exception
Throw New ProviderException("Error getting user by email", e)
Finally
_adapter.CloseConnection()
End Try
If username Is Nothing Then _
username = ""
Return username
End Function
'
' MembershipProvider.ResetPassword
'
Public Overrides Function ResetPassword(ByVal username As String, ByVal answer As String) As String
If Not EnablePasswordReset Then
Throw New NotSupportedException("Password Reset is not enabled.")
End If
If answer Is Nothing AndAlso RequiresQuestionAndAnswer Then
UpdateFailureCount(username, "passwordAnswer")
Throw New ProviderException("Password answer required for password Reset.")
End If
Dim newPassword As String = _
System.Web.Security.Membership.GeneratePassword(newPasswordLength, MinRequiredNonAlphanumericCharacters)
Dim Args As ValidatePasswordEventArgs = _
New ValidatePasswordEventArgs(username, newPassword, True)
OnValidatingPassword(Args)
If Args.Cancel Then
If Not Args.FailureInformation Is Nothing Then
Throw Args.FailureInformation
Else
Throw New MembershipPasswordException("Reset password canceled due to password validation failure.")
End If
End If
Dim user As New UserEntity()
user.UserName = username
user.ApplicationName = Me.ApplicationName
Dim userUpdated As Boolean = False
Dim passwordAnswer As String = ""
Try
_adapter.OpenConnection()
Dim foundUser As Boolean = _adapter.FetchEntityUsingUniqueConstraint(user, user.ConstructFilterForUCUserNameApplicationName())
If foundUser Then
If user.IsLockedOut Then
Throw New MembershipPasswordException("The supplied user is locked out.")
End If
passwordAnswer = user.PasswordAnswer
Else
Throw New MembershipPasswordException("The supplied user name is not found.")
End If
If RequiresQuestionAndAnswer AndAlso Not CheckPassword(answer, passwordAnswer) Then
UpdateFailureCount(username, "passwordAnswer")
Throw New MembershipPasswordException("Incorrect password answer.")
End If
user.LastPasswordChangeDate = DateTime.Now
user.Password = EncodePassword(newPassword)
userUpdated = _adapter.SaveEntity(user)
Catch e As Exception
Throw New ProviderException("Error resetting password", e)
Finally
_adapter.CloseConnection()
End Try
If userUpdated Then
Return newPassword
Else
Throw New MembershipPasswordException("User not found, or user is locked out. Password not Reset.")
End If
End Function
'
' MembershipProvider.UpdateUser
'
Public Overrides Sub UpdateUser(ByVal user As MembershipUser)
Dim userEntity As New UserEntity()
userEntity.Email = user.Email
userEntity.Description = user.Comment
userEntity.IsApproved = user.IsApproved
Dim bucket As New RelationPredicateBucket()
bucket.PredicateExpression.Add(PredicateFactory.CompareValue(UserFieldIndex.UserName, ComparisonOperator.Equal, user.UserName))
bucket.PredicateExpression.AddWithAnd(PredicateFactory.CompareValue(UserFieldIndex.ApplicationName, ComparisonOperator.Equal, Me.ApplicationName))
Try
_adapter.OpenConnection()
_adapter.UpdateEntitiesDirectly(userEntity, bucket)
Catch e As Exception
Throw New ProviderException("Error updating user", e)
Finally
_adapter.CloseConnection()
End Try
End Sub
'
' MembershipProvider.ValidateUser
'
Public Overrides Function ValidateUser(ByVal username As String, ByVal password As String) As Boolean
Dim isValid As Boolean = False
Dim users As New EntityCollection(New UserEntityFactory())
Dim bucket As New RelationPredicateBucket
bucket.PredicateExpression.Add(PredicateFactory.CompareValue(UserFieldIndex.UserName, ComparisonOperator.Equal, username))
bucket.PredicateExpression.AddWithAnd(PredicateFactory.CompareValue(UserFieldIndex.ApplicationName, ComparisonOperator.Equal, Me.ApplicationName))
bucket.PredicateExpression.AddWithAnd(PredicateFactory.CompareValue(UserFieldIndex.IsLockedOut, ComparisonOperator.Equal, False))
Dim isApproved As Boolean = False
Dim pwd As String = ""
Try
_adapter.OpenConnection()
_adapter.FetchEntityCollection(users, bucket)
If users.Count > 0 Then
Dim user As UserEntity = CType(users(0), UserEntity)
pwd = user.Password
isApproved = user.IsApproved
Else
Return False
End If
If CheckPassword(password, pwd) Then
If isApproved Then
isValid = True
Dim user As UserEntity = CType(users(0), UserEntity)
user.LastLoginDate = DateTime.Now
_adapter.SaveEntity(user)
End If
Else
UpdateFailureCount(username, "password")
End If
Catch e As Exception
Throw New ProviderException("Error validating user", e)
Finally
_adapter.CloseConnection()
End Try
Return isValid
End Function
'
' UpdateFailureCount
' A helper method that performs the checks and updates associated with
' password failure tracking.
'
Private Sub UpdateFailureCount(ByVal username As String, ByVal failureType As String)
Dim user As New UserEntity()
user.UserName = username
user.ApplicationName = Me.ApplicationName
Dim windowStart As DateTime = New DateTime()
Dim failureCount As Integer = 0
Try
_adapter.OpenConnection()
Dim foundUser As Boolean = False
foundUser = _adapter.FetchEntityUsingUniqueConstraint(user, user.ConstructFilterForUCUserNameApplicationName())
If foundUser Then
If failureType = "password" Then
failureCount = user.FailedPasswordAttemptCount
windowStart = user.FailedPasswordAttemptWindowStart
End If
If failureType = "passwordAnswer" Then
failureCount = user.FailedPasswordAnswerAttemptCount
windowStart = user.FailedPasswordAnswerAttemptWindowStart
End If
End If
Dim windowEnd As DateTime = windowStart.AddMinutes(PasswordAttemptWindow)
If failureCount = 0 OrElse DateTime.Now > windowEnd Then
' First password failure or outside of PasswordAttemptWindow.
' Start a New password failure count from 1 and a New window starting now.
If failureType = "password" Then
user.FailedPasswordAttemptCount = 1
user.FailedPasswordAttemptWindowStart = DateTime.Now
End If
If failureType = "passwordAnswer" Then
user.FailedPasswordAnswerAttemptCount = 1
user.FailedPasswordAnswerAttemptWindowStart = DateTime.Now
End If
If _adapter.SaveEntity(user) = False Then _
Throw New ProviderException("Unable to update failure count and window start.")
Else
failureCount += 1
If failureCount >= MaxInvalidPasswordAttempts Then
' Password attempts have exceeded the failure threshold. Lock out
' the user.
user.IsLockedOut = True
user.LastLockedOutDate = DateTime.Now
If _adapter.SaveEntity(user) = False Then _
Throw New ProviderException("Unable to lock out user.")
Else
' Password attempts have not exceeded the failure threshold. Update
' the failure counts. Leave the window the same.
If failureType = "password" Then
user.FailedPasswordAttemptCount = failureCount
End If
If failureType = "passwordAnswer" Then
user.FailedPasswordAnswerAttemptCount = failureCount
End If
If _adapter.SaveEntity(user) = False Then _
Throw New ProviderException("Unable to update failure count.")
End If
End If
Catch e As Exception
Throw New ProviderException("Error updating failure count", e)
Finally
_adapter.CloseConnection()
End Try
End Sub
'
' CheckPassword
' Compares password values based on the MembershipPasswordFormat.
'
Private Function CheckPassword(ByVal password As String, ByVal dbpassword As String) As Boolean
Dim pass1 As String = password
Dim pass2 As String = dbpassword
Select Case PasswordFormat
Case MembershipPasswordFormat.Encrypted
pass2 = UnEncodePassword(dbpassword)
Case MembershipPasswordFormat.Hashed
pass1 = EncodePassword(password)
Case Else
End Select
If pass1 = pass2 Then
Return True
End If
Return False
End Function
'
' EncodePassword
' Encrypts, Hashes, or leaves the password clear based on the PasswordFormat.
'
Private Function EncodePassword(ByVal password As String) As String
Dim encodedPassword As String = password
Select Case PasswordFormat
Case MembershipPasswordFormat.Clear
Case MembershipPasswordFormat.Encrypted
encodedPassword = _
Convert.ToBase64String(EncryptPassword(Encoding.Unicode.GetBytes(password)))
Case MembershipPasswordFormat.Hashed
Dim hash As HMACSHA1 = New HMACSHA1()
hash.Key = HexToByte(machineKey.ValidationKey)
encodedPassword = _
Convert.ToBase64String(hash.ComputeHash(Encoding.Unicode.GetBytes(password)))
Case Else
Throw New ProviderException("Unsupported password format.")
End Select
Return encodedPassword
End Function
'
' UnEncodePassword
' Decrypts or leaves the password clear based on the PasswordFormat.
'
Private Function UnEncodePassword(ByVal encodedPassword As String) As String
Dim password As String = encodedPassword
Select Case PasswordFormat
Case MembershipPasswordFormat.Clear
Case MembershipPasswordFormat.Encrypted
password = _
Encoding.Unicode.GetString(DecryptPassword(Convert.FromBase64String(password)))
Case MembershipPasswordFormat.Hashed
Throw New ProviderException("Cannot unencode a hashed password.")
Case Else
Throw New ProviderException("Unsupported password format.")
End Select
Return password
End Function
'
' HexToByte
' Converts a hexadecimal string to a byte array. Used to convert encryption
' key values from the configuration.
'
Private Function HexToByte(ByVal hexString As String) As Byte()
Dim ReturnBytes(hexString.Length \ 2) As Byte
For i As Integer = 0 To ReturnBytes.Length - 1
ReturnBytes(i) = Convert.ToByte(hexString.Substring(i * 2, 2), 16)
Next
Return ReturnBytes
End Function
'
' MembershipProvider.FindUsersByName
'
Public Overrides Function FindUsersByName(ByVal usernameToMatch As String, _
ByVal pageIndex As Integer, _
ByVal pageSize As Integer, _
ByRef totalRecords As Integer) _
As MembershipUserCollection
Dim usersByName As New EntityCollection(New UserEntityFactory())
Dim bucket As New RelationPredicateBucket()
bucket.PredicateExpression.Add(PredicateFactory.Like(UserFieldIndex.UserName, "%" & usernameToMatch & "%"))
bucket.PredicateExpression.AddWithAnd(PredicateFactory.CompareValue(UserFieldIndex.ApplicationName, ComparisonOperator.Equal, Me.ApplicationName))
Dim users As MembershipUserCollection = New MembershipUserCollection()
Try
_adapter.OpenConnection()
_adapter.FetchEntityCollection(usersByName, bucket)
totalRecords = usersByName.Count
If totalRecords <= 0 Then Return users
Dim counter As Integer = 0
Dim startIndex As Integer = pageSize * pageIndex
Dim endIndex As Integer = startIndex + pageSize - 1
Do While counter < totalRecords
If counter >= startIndex Then
Dim u As MembershipUser = GetMembershipUserFromEntity(usersByName(counter))
users.Add(u)
End If
counter += 1
Loop
Catch e As Exception
Throw New ProviderException("Error finding users by name", e)
Finally
_adapter.CloseConnection()
End Try
Return users
End Function
'
' MembershipProvider.FindUsersByEmail
'
Public Overrides Function FindUsersByEmail(ByVal emailToMatch As String, _
ByVal pageIndex As Integer, _
ByVal pageSize As Integer, _
ByRef totalRecords As Integer) _
As MembershipUserCollection
Dim usersByEmail As New EntityCollection(New UserEntityFactory())
Dim bucket As New RelationPredicateBucket()
bucket.PredicateExpression.Add(PredicateFactory.Like(UserFieldIndex.Email, "%" & emailToMatch & "%"))
bucket.PredicateExpression.AddWithAnd(PredicateFactory.CompareValue(UserFieldIndex.ApplicationName, ComparisonOperator.Equal, Me.ApplicationName))
Dim users As MembershipUserCollection = New MembershipUserCollection()
totalRecords = 0
Try
_adapter.OpenConnection()
_adapter.FetchEntityCollection(usersByEmail, bucket)
totalRecords = usersByEmail.Count
If totalRecords <= 0 Then Return users
Dim counter As Integer = 0
Dim startIndex As Integer = pageSize * pageIndex
Dim endIndex As Integer = startIndex + pageSize - 1
Do While counter < totalRecords
If counter >= startIndex Then
Dim u As MembershipUser = GetMembershipUserFromEntity(usersByEmail(counter))
users.Add(u)
End If
counter += 1
Loop
Catch e As Exception
Throw New ProviderException("Error finding users by email", e)
Finally
_adapter.CloseConnection()
End Try
Return users
End Function
End Class
End Namespace
Next is the Role provider code:
Imports System.Web.Security
Imports System.Configuration.Provider
Imports System.Collections.Specialized
Imports System
Imports System.Data
Imports System.Data.Odbc
Imports System.Configuration
Imports System.Diagnostics
Imports System.Web
Imports System.Globalization
Imports System.Security.Cryptography
Imports System.Text
Imports System.Web.Configuration
Imports SD.LLBLGen.Pro.ORMSupportClasses
Imports YourProject.DAL
Imports YourProject.DAL.DatabaseSpecific
Imports YourProject.DAL.EntityClasses
Imports YourProject.DAL.HelperClasses
Imports YourProject.DAL.FactoryClasses
Imports YourProject.DAL.RelationClasses
Imports YourProject.DAL.ValidatorClasses
Namespace YourProject.Providers
Public NotInheritable Class MyRoleProvider
Inherits RoleProvider
Private _adapter As DataAccessAdapter2
Public Overrides Sub Initialize(ByVal name As String, ByVal config As NameValueCollection)
'
' Initialize values from web.config.
'
If config Is Nothing Then _
Throw New ArgumentNullException("config")
If name Is Nothing OrElse name.Length = 0 Then _
name = "MyRoleProvider"
If String.IsNullOrEmpty(config("description")) Then
config.Remove("description")
config.Add("description", "Interacts with custom tables in the Membership database")
End If
' Initialize the abstract base class.
MyBase.Initialize(name, config)
If config("applicationName") Is Nothing OrElse config("applicationName").Trim() = "" Then
pApplicationName = System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath
Else
pApplicationName = config("applicationName")
End If
_adapter = New DataAccessAdapter2()
End Sub
'
' System.Web.Security.RoleProvider properties.
'
Private pApplicationName As String
Public Overrides Property ApplicationName() As String
Get
Return pApplicationName
End Get
Set(ByVal value As String)
pApplicationName = value
End Set
End Property
'
' System.Web.Security.RoleProvider methods.
'
'
' RoleProvider.AddUsersToRoles
'
Public Overrides Sub AddUsersToRoles(ByVal userNames As String(), ByVal roleNames As String())
For Each rolename As String In roleNames
If Not RoleExists(rolename) Then
Throw New ProviderException("Role name not found.")
End If
Next
For Each username As String In userNames
If username.IndexOf(",") > 0 Then
Throw New ArgumentException("User names cannot contain commas.")
End If
For Each rolename As String In roleNames
If IsUserInRole(username, rolename) Then
Throw New ProviderException("User is already in role.")
End If
Next
Next
' Get all users specified
Dim users As New EntityCollection(New UserEntityFactory())
Dim usersBucket As New RelationPredicateBucket()
usersBucket.PredicateExpression.Add(PredicateFactory.CompareRange(UserFieldIndex.UserName, userNames))
usersBucket.PredicateExpression.AddWithAnd(PredicateFactory.CompareValue(UserFieldIndex.ApplicationName, ComparisonOperator.Equal, Me.ApplicationName))
' get all roles specified
Dim roles As New EntityCollection(New RoleEntityFactory())
Dim rolesBucket As New RelationPredicateBucket()
rolesBucket.PredicateExpression.Add(PredicateFactory.CompareRange(RoleFieldIndex.Name, roleNames))
rolesBucket.PredicateExpression.AddWithAnd(PredicateFactory.CompareValue(RoleFieldIndex.ApplicationName, ComparisonOperator.Equal, Me.ApplicationName))
' Create a collection of userRoles to push out to the database when filled.
Dim userRoles As New EntityCollection(New UserRoleEntityFactory())
Try
_adapter.OpenConnection()
_adapter.FetchEntityCollection(users, usersBucket)
_adapter.FetchEntityCollection(roles, rolesBucket)
For Each user As UserEntity In users
For Each role As RoleEntity In roles
Dim userRole As New UserRoleEntity()
userRole.RoleId = role.RoleId
userRole.UserId = user.UserId
userRole.ApplicationName = Me.ApplicationName
YourProject.DAL.DatabaseSpecific.DataAccessAdapter2.UpdateDetails(userRole)
userRoles.Add(userRole)
Next
Next
_adapter.SaveEntityCollection(userRoles)
Catch e As Exception
Throw New ProviderException("Error adding users to roles", e)
Finally
_adapter.CloseConnection()
End Try
End Sub
'
' RoleProvider.CreateRole
'
Public Overrides Sub CreateRole(ByVal rolename As String)
If rolename.IndexOf(",") > 0 Then
Throw New ArgumentException("Role names cannot contain commas.")
End If
If RoleExists(rolename) Then
Throw New ProviderException("Role name already exists.")
End If
Dim role As New RoleEntity()
role.Name = rolename
role.ApplicationName = Me.ApplicationName
role.Active = True
Try
_adapter.OpenConnection()
_adapter.SaveEntity(role)
Catch e As Exception
Throw New ProviderException("Error creating role", e)
Finally
_adapter.CloseConnection()
End Try
End Sub
'
' RoleProvider.DeleteRole
'
Public Overrides Function DeleteRole(ByVal rolename As String, ByVal throwOnPopulatedRole As Boolean) As Boolean
If Not RoleExists(rolename) Then
Throw New ProviderException("Role does not exist.")
End If
If throwOnPopulatedRole AndAlso GetUsersInRole(rolename).Length > 0 Then
Throw New ProviderException("Cannot delete a populated role.")
End If
' Delete user roles first
Dim userRolesBucket As New RelationPredicateBucket()
userRolesBucket.Relations.Add(UserRoleEntity.Relations.RoleEntityUsingRoleId)
userRolesBucket.PredicateExpression.Add(PredicateFactory.CompareValue(RoleFieldIndex.Name, ComparisonOperator.Equal, rolename))
userRolesBucket.PredicateExpression.AddWithAnd(PredicateFactory.CompareValue(RoleFieldIndex.ApplicationName, ComparisonOperator.Equal, Me.ApplicationName))
' Delete roles
Dim roleBucket As New RelationPredicateBucket()
roleBucket.PredicateExpression.Add(PredicateFactory.CompareValue(RoleFieldIndex.Name, ComparisonOperator.Equal, rolename))
roleBucket.PredicateExpression.AddWithAnd(PredicateFactory.CompareValue(RoleFieldIndex.ApplicationName, ComparisonOperator.Equal, Me.ApplicationName))
Try
_adapter.OpenConnection()
_adapter.DeleteEntitiesDirectly("UserRole", userRolesBucket)
_adapter.DeleteEntitiesDirectly("Role", roleBucket)
Catch e As Exception
Throw New ProviderException("Error deleting role", e)
Finally
_adapter.CloseConnection()
End Try
Return True
End Function
'
' RoleProvider.GetAllRoles
'
Public Overrides Function GetAllRoles() As String()
Dim tmpRoleNames As String = ""
Dim roles As New EntityCollection(New RoleEntityFactory())
Dim rolesBucket As New RelationPredicateBucket()
rolesBucket.PredicateExpression.Add(PredicateFactory.CompareValue(RoleFieldIndex.ApplicationName, ComparisonOperator.Equal, Me.ApplicationName))
Try
_adapter.OpenConnection()
_adapter.FetchEntityCollection(roles, rolesBucket)
For Each role As RoleEntity In roles
tmpRoleNames &= role.Name & ","
Next
Catch e As Exception
Throw New ProviderException("Error getting all roles.", e)
Finally
_adapter.CloseConnection()
End Try
If tmpRoleNames.Length > 0 Then
' Remove trailing comma.
tmpRoleNames = tmpRoleNames.Substring(0, tmpRoleNames.Length - 1)
Return tmpRoleNames.Split(CChar(","))
End If
Return New String() {}
End Function
'
' RoleProvider.GetRolesForUser
'
Public Overrides Function GetRolesForUser(ByVal username As String) As String()
Dim tmpRoleNames As String = ""
Dim user As New UserEntity()
Dim userPath As New PrefetchPath2(EntityType.UserEntity)
userPath.Add(UserEntity.PrefetchPathRolesCollectionViaUserRole)
user.UserName = username
user.ApplicationName = Me.ApplicationName
Try
_adapter.OpenConnection()
If _adapter.FetchEntityUsingUniqueConstraint(user, user.ConstructFilterForUCUserNameApplicationName(), userPath) Then
If user.RolesCollectionViaUserRole.Count > 0 Then
For Each role As RoleEntity In user.RolesCollectionViaUserRole
tmpRoleNames &= role.Name & ","
Next
End If
End If
Catch e As Exception
Throw New ProviderException("Error getting roles for user.", e)
Finally
_adapter.CloseConnection()
End Try
If tmpRoleNames.Length > 0 Then
' Remove trailing comma.
tmpRoleNames = tmpRoleNames.Substring(0, tmpRoleNames.Length - 1)
Return tmpRoleNames.Split(CChar(","))
End If
Return New String() {}
End Function
'
' RoleProvider.GetUsersInRole
'
Public Overrides Function GetUsersInRole(ByVal rolename As String) As String()
Dim tmpUserNames As String = ""
Dim role As New RoleEntity()
role.Name = rolename
role.ApplicationName = Me.ApplicationName
Dim rolePath As New PrefetchPath2(EntityType.RoleEntity)
rolePath.Add(RoleEntity.PrefetchPathUsersCollectionViaUserRole())
Try
_adapter.OpenConnection()
If _adapter.FetchEntityUsingUniqueConstraint(role, role.ConstructFilterForUCNameApplicationName(), rolePath) Then
For Each user As UserEntity In role.UsersCollectionViaUserRole
tmpUserNames &= user.UserName & ","
Next
End If
Catch e As Exception
Throw New ProviderException("Error getting users in role.", e)
Finally
_adapter.CloseConnection()
End Try
If tmpUserNames.Length > 0 Then
' Remove trailing comma.
tmpUserNames = tmpUserNames.Substring(0, tmpUserNames.Length - 1)
Return tmpUserNames.Split(CChar(","))
End If
Return New String() {}
End Function
'
' RoleProvider.IsUserInRole
'
Public Overrides Function IsUserInRole(ByVal username As String, ByVal rolename As String) As Boolean
Dim userIsInRole As Boolean = False
Dim users As New EntityCollection(New UserEntityFactory())
Dim userBucket As New RelationPredicateBucket()
userBucket.Relations.Add(UserEntity.Relations.UserRoleEntityUsingUserId)
userBucket.Relations.Add(UserRoleEntity.Relations.RoleEntityUsingRoleId)
userBucket.PredicateExpression.Add(PredicateFactory.CompareValue(RoleFieldIndex.Name, ComparisonOperator.Equal, rolename))
userBucket.PredicateExpression.AddWithAnd(PredicateFactory.CompareValue(UserFieldIndex.UserName, ComparisonOperator.Equal, username))
userBucket.PredicateExpression.AddWithAnd(PredicateFactory.CompareValue(UserFieldIndex.ApplicationName, ComparisonOperator.Equal, Me.ApplicationName))
Try
_adapter.OpenConnection()
_adapter.FetchEntityCollection(users, userBucket)
If users.Count > 0 Then
userIsInRole = True
End If
Catch e As Exception
Throw New ProviderException("Error determining if user is in role.", e)
Finally
_adapter.CloseConnection()
End Try
Return userIsInRole
End Function
'
' RoleProvider.RemoveUsersFromRoles
'
Public Overrides Sub RemoveUsersFromRoles(ByVal usernames As String(), ByVal rolenames As String())
For Each rolename As String In rolenames
If Not RoleExists(rolename) Then
Throw New ProviderException("Role name not found.")
End If
Next
For Each username As String In usernames
For Each rolename As String In rolenames
If Not IsUserInRole(username, rolename) Then
Throw New ProviderException("User is not in role.")
End If
Next
Next
Dim userRoles As New EntityCollection(New UserRoleEntityFactory())
Dim userRolesBucket As New RelationPredicateBucket()
userRolesBucket.Relations.Add(UserRoleEntity.Relations.RoleEntityUsingRoleId)
userRolesBucket.Relations.Add(UserRoleEntity.Relations.UserEntityUsingUserId)
userRolesBucket.PredicateExpression.Add(PredicateFactory.CompareRange(UserFieldIndex.UserName, usernames))
userRolesBucket.PredicateExpression.AddWithAnd(PredicateFactory.CompareRange(RoleFieldIndex.Name, rolenames))
Try
_adapter.OpenConnection()
_adapter.DeleteEntitiesDirectly("UserRoleEntity", userRolesBucket)
Catch e As Exception
Throw New ProviderException("Error deleting users from roles.", e)
Finally
_adapter.CloseConnection()
End Try
End Sub
'
' RoleProvider.RoleExists
'
Public Overrides Function RoleExists(ByVal rolename As String) As Boolean
Dim exists As Boolean = False
Dim role As New RoleEntity()
role.Name = rolename
role.ApplicationName = Me.ApplicationName
Try
_adapter.OpenConnection()
If _adapter.FetchEntityUsingUniqueConstraint(role, role.ConstructFilterForUCNameApplicationName()) Then
exists = True
End If
Catch e As Exception
Throw New ProviderException("Error finding role.", e)
Finally
_adapter.CloseConnection()
End Try
Return exists
End Function
'
' RoleProvider.FindUsersInRole
'
Public Overrides Function FindUsersInRole(ByVal rolename As String, ByVal usernameToMatch As String) As String()
Dim role As New RoleEntity()
role.Name = rolename
role.ApplicationName = Me.ApplicationName
Dim rolePath As New PrefetchPath2(EntityType.RoleEntity)
rolePath.Add(RoleEntity.PrefetchPathUsersCollectionViaUserRole)
Dim tmpUserNames As String = ""
Try
_adapter.OpenConnection()
If _adapter.FetchEntityUsingUniqueConstraint(role, role.ConstructFilterForUCNameApplicationName, rolePath) Then
For Each user As UserEntity In role.UsersCollectionViaUserRole
tmpUserNames &= user.UserName & ","
Next
End If
Catch e As Exception
Throw New ProviderException("Error getting users in role.", e)
Finally
_adapter.CloseConnection()
End Try
If tmpUserNames.Length > 0 Then
' Remove trailing comma.
tmpUserNames = tmpUserNames.Substring(0, tmpUserNames.Length - 1)
Return tmpUserNames.Split(CChar(","))
End If
Return New String() {}
End Function
End Class
End Namespace
Next, you'll notice my code uses an object called DataAccessAdapter2.. This is just a standard DataAccessAdapter that uses the new ConnectionStrings element in .NET 2.0 applications. It also overrides the SaveEntity function to automatically records the CreatedDate, CreatedByUser, ModifiedDate, and ModifiedByUser fields which exist in every table of my application. And speaking of tables, here are the scripts to create the User, UserRole, and Role tables necessary for the membership code above to work.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Role]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[Role](
[RoleId] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](255) NOT NULL,
[Active] [bit] NOT NULL,
[Description] [varchar](max) NULL,
[CreatedByUser] [varchar](50) NOT NULL,
[CreatedDate] [datetime] NOT NULL,
[ModifiedByUser] [varchar](50) NOT NULL,
[ModifiedDate] [datetime] NOT NULL,
[ApplicationName] [varchar](50) NOT NULL,
CONSTRAINT [PK_Role] PRIMARY KEY CLUSTERED
(
[RoleId] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY],
CONSTRAINT [IX_Role] UNIQUE NONCLUSTERED
(
[ApplicationName] ASC,
[Name] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[UserRole]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[UserRole](
[UserRoleId] [int] IDENTITY(1,1) NOT NULL,
[RoleId] [int] NOT NULL,
[UserId] [int] NOT NULL,
[CreatedByUser] [varchar](50) NOT NULL,
[CreatedDate] [datetime] NOT NULL,
[ModifiedByUser] [varchar](50) NOT NULL,
[ModifiedDate] [datetime] NOT NULL,
[ApplicationName] [varchar](50) NOT NULL,
CONSTRAINT [PK_UserRole] PRIMARY KEY CLUSTERED
(
[UserRoleId] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[User]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[User](
[UserId] [int] IDENTITY(1,1) NOT NULL,
[SchoolId] [int] NOT NULL CONSTRAINT [DF_User_SchoolId] DEFAULT ((0)),
[UserName] [varchar](50) NOT NULL,
[Password] [varchar](50) NOT NULL,
[FirstName] [varchar](50) NOT NULL CONSTRAINT [DF_User_FirstName] DEFAULT ('default'),
[LastName] [varchar](50) NOT NULL CONSTRAINT [DF_User_LastName] DEFAULT ('default'),
[Email] [varchar](100) NULL,
[Description] [varchar](max) NULL,
[ApplicationName] [varchar](50) NULL,
[PasswordQuestion] [varchar](255) NULL,
[PasswordAnswer] [varchar](255) NULL,
[IsApproved] [bit] NULL,
[LastActivityDate] [datetime] NULL,
[LastLoginDate] [datetime] NULL,
[LastPasswordChangeDate] [datetime] NULL,
[LastLockedOutDate] [datetime] NULL,
[IsOnline] [bit] NULL,
[IsLockedOut] [bit] NULL,
[FailedPasswordAttemptCount] [int] NULL,
[FailedPasswordAttemptWindowStart] [datetime] NULL,
[FailedPasswordAnswerAttemptCount] [int] NULL,
[FailedPasswordAnswerAttemptWindowStart] [datetime] NULL,
[ShowAdvancedStandardsOptions] [bit] NULL,
[AllowClassManagement] [bit] NULL,
[CreatedByUser] [varchar](50) NOT NULL,
[CreatedDate] [datetime] NOT NULL,
[ModifiedByUser] [varchar](50) NOT NULL,
[ModifiedDate] [datetime] NOT NULL,
CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED
(
[UserId] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY],
CONSTRAINT [IX_User] UNIQUE NONCLUSTERED
(
[UserName] ASC,
[ApplicationName] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_UserRole_Role]') AND parent_object_id = OBJECT_ID(N'[dbo].[UserRole]'))
ALTER TABLE [dbo].[UserRole] WITH CHECK ADD CONSTRAINT [FK_UserRole_Role] FOREIGN KEY([RoleId])
REFERENCES [dbo].[Role] ([RoleId])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_UserRole_User]') AND parent_object_id = OBJECT_ID(N'[dbo].[UserRole]'))
ALTER TABLE [dbo].[UserRole] WITH CHECK ADD CONSTRAINT [FK_UserRole_User] FOREIGN KEY([UserId])
REFERENCES [dbo].[User] ([UserId])
GO
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_User_School]') AND parent_object_id = OBJECT_ID(N'[dbo].[User]'))
ALTER TABLE [dbo].[User] WITH NOCHECK ADD CONSTRAINT [FK_User_School] FOREIGN KEY([SchoolId])
REFERENCES [dbo].[School] ([SchoolId])
NOT FOR REPLICATION
Wiring it all up is as simple as changing your web.config to look something like this:
<roleManager defaultProvider="MyRoleProvider" enabled="true" cacheRolesInCookie="true" cookieName=".ASPROLES" cookieTimeout="30" cookiePath="/" cookieRequireSSL="false" cookieSlidingExpiration="true" cookieProtection="All">
<providers>
<clear/>
<add name="MyRoleProvider" type="MyProject.Providers.MyRoleProvider" connectionStringName="YourSqlServer" applicationName="YourApplicationName"/>
</providers>
</roleManager>
<membership defaultProvider="MyMembershipProvider (SQL)">
<providers>
<add connectionStringName="YourSqlServer" applicationName="YourApplicationName" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" passwordFormat="Clear" maxInvalidPasswordAttempts="5" passwordAttemptWindow="10" name="MyMembershipProvider (SQL)" type="YourProject.Providers.MyMembershipProvider"/>
</providers>
</membership>
<connectionStrings>
<remove name="YourSqlServer"/>
<add name="YourSqlServer" connectionString="Data Source=(local);Initial Catalog=YourDB;Integrated Security=True" providerName="System.Data.SqlClient"/>
</connectionStrings>
Joined: 05-Aug-2005
alexdresko wrote:
Finally got approval to post this code.
What features does your code provide that the default providers don't? If the purpose is to just replace ADO.Net code with LLBLGEN code I don't see the reason for that?
alexdresko wrote:
Finally got approval to post this code. One thing I know that can be enhanced is in the role provider. My app won't ever have more than like 5 roles total so I don't see a problem caching that information in the Application object thus speeding up the Membership.IsInRole functions.
FYI: The default role manager provider can cache a users roles in his cookie, so if you are only assigning a single user role you can go that route.
BOb
Joined: 08-Dec-2003
Thanks Alex, this is great. I'm going to convert the code to c# and give it a try. One thing I noticed is that you have an Entity called UserEntity. I'm guessing you changed the name of the Aspnet_Users table to User.
Did you do this in the designer, or did you create a new table called user in the db instead of using Aspnet_users (just renamed)?
Also are there other name changes I need to know about (for example, roles, membership, etc)?
Lastly, you mentioned creating a dataaccessadapter2 which I assume modifies the OnSave event. Could you please also provide the code for the dataaccessadapter2 class? This would help me get up and running quickly.
Thanks
Joined: 08-Jun-2004
pilotboba wrote:
What features does your code provide that the default providers don't? If the purpose is to just replace ADO.Net code with LLBLGEN code I don't see the reason for that?
The default provider uses tables which must be installed via aspnet_regsql. Those tables are named aspnet_* where * = User, Role, Profile, etc... Those tables used GUIDs for keys and a couple other SQL specific things that I didn't want my application to inherit. I created my own tables because I wanted to be able to modify the structure of those tables without having to worry about MS or some other developer using aspnet_regsql again to overwrite my schema. I also wanted to store user specific information in the User table instead of using the default Profile provider. Nor did I want to create my own Profile provider.
You're right. It doesn't provide any additional functionality otherwise.
For the other person who asked, here's the code for the DataAccessAdapter2 class that I thought I included in my first post but didn't..
Imports System
Imports System.Configuration
Imports System.Web.Security
Namespace YourProject.DAL.DatabaseSpecific
Public Class DataAccessAdapter2
Inherits DataAccessAdapter
Public Sub New()
MyBase.New(GetConnectionString())
End Sub
Public Sub New(ByVal keepConnectionOpen As Boolean)
MyBase.New(GetConnectionString(), keepConnectionOpen)
End Sub
' Utility function to get the connection string from the web.config
' Uses the new ConnectionStrings area.
Public Shared Function GetConnectionString() As String
Dim connectionStringName As String = System.Configuration.ConfigurationManager.AppSettings("ConnectionStringToUse")
Dim connectionStringSettings As ConnectionStringSettings = ConfigurationManager.ConnectionStrings(connectionStringName)
If connectionStringSettings Is Nothing OrElse connectionStringSettings.ConnectionString.Trim() = "" Then
Throw New Provider.ProviderException("Connection string cannot be blank.")
End If
Dim connectionString As String = connectionStringSettings.ConnectionString
Return connectionString
End Function
Public Overrides Function SaveEntity(ByVal entityToSave As SD.LLBLGen.Pro.ORMSupportClasses.IEntity2, ByVal refetchAfterSave As Boolean, ByVal updateRestriction As SD.LLBLGen.Pro.ORMSupportClasses.IPredicateExpression, ByVal recurse As Boolean) As Boolean
UpdateDetails(entityToSave)
Return MyBase.SaveEntity(entityToSave, refetchAfterSave, updateRestriction, recurse)
End Function
Public Shared Sub UpdateDetails(ByRef entity As SD.LLBLGen.Pro.ORMSupportClasses.IEntity2)
UpdateDetails(entity, True)
End Sub
Public Shared Sub UpdateDetails(ByRef entity As SD.LLBLGen.Pro.ORMSupportClasses.IEntity2, ByVal updateCreated As Boolean)
Dim userName As String = ""
If ((System.Web.HttpContext.Current Is Nothing) _
OrElse ((System.Web.HttpContext.Current.User Is Nothing) _
OrElse (System.Web.HttpContext.Current.User.Identity.Name = ""))) Then
Else
userName = System.Web.HttpContext.Current.User.Identity.Name
End If
If (String.IsNullOrEmpty(userName)) Then
userName = "default"
End If
If (updateCreated AndAlso entity.Fields.State = SD.LLBLGen.Pro.ORMSupportClasses.EntityState.New) Then
SetFieldValue(entity, "CreatedByUser", userName)
SetFieldValue(entity, "CreatedDate", DateTime.Now)
SetFieldValue(entity, "ModifiedByUser", userName)
SetFieldValue(entity, "ModifiedDate", DateTime.Now)
Else
SetFieldValue(entity, "ModifiedByUser", userName.ToString)
SetFieldValue(entity, "ModifiedDate", DateTime.Now)
End If
End Sub
Private Shared Sub SetFieldValue(ByVal entity As SD.LLBLGen.Pro.ORMSupportClasses.IEntity2, ByVal fieldName As String, ByVal fieldValue As Object)
If (Not entity.Fields(fieldName) Is Nothing) Then
entity.Fields(fieldName).CurrentValue = fieldValue
End If
End Sub
End Class
End Namespace
If you get the code to work, it should work no differently than the built in providers. Note that I didn't create my own Profile provider, so you'll need to create your own if you plan on using that feature.
Joined: 05-Aug-2005
alexdresko wrote:
The default provider uses tables which must be installed via aspnet_regsql. Those tables are named aspnet_* where * = User, Role, Profile, etc... Those tables used GUIDs for keys and a couple other SQL specific things that I didn't want my application to inherit. I created my own tables because I wanted to be able to modify the structure of those tables without having to worry about MS or some other developer using aspnet_regsql again to overwrite my schema. I also wanted to store user specific information in the User table instead of using the default Profile provider. Nor did I want to create my own Profile provider.
Those are perfectly good reasons! I was just curious. We actually need to create our own because we provide "roles" as asp.net calls it for every task in the system. So, since there are so many "roles" we call them permissions in our app, we create a way for them to aggregate the permissions with what we call roles in our app.
you said you added some additional attribures to the membership table. Does this get exposed by default in the Membership object or do you have to provide a custom one of those also. Like you I need to add some things, but I was planning to just put it into the profile. What is the reason you didn't just use the profile?
Thanks, BOb
Joined: 05-Aug-2005
omar wrote:
I am considering utilizing the CAZE engine to implement authorization security in a future application. Hoped to check if any LLBL'ers have used it in their own applications? http://lamarvin.com/caze_default.asp
I looked at CAZE and it sounds interesting... But, I think Enterprise Library 2.x gives you pretty much all those features for free.
BOb
Joined: 08-Dec-2003
You said you added some additional attribures to the membership table. Does this get exposed by default in the Membership object or do you have to provide a custom one of those also. Like you I need to add some things, but I was planning to just put it into the profile. What is the reason you didn't just use the profile?
I can't speak for Alex, but storing data in the profile is stored basically as a blob. In other words there is really no way filter, sort, etc on profile data. However, there is a ProfileTableProvider (http://www.asp.net/sandbox/samp_profiles.aspx?tabindex=0&tabid=1) which I'm looking to implement which allows you to store the profile data in a table. This way, using llblenPro you have full access to the profile data for filtering. This was a big problem for me in not using the profile data.
Eric
Joined: 08-Jun-2004
erichar11 wrote:
You said you added some additional attribures to the membership table. Does this get exposed by default in the Membership object or do you have to provide a custom one of those also. Like you I need to add some things, but I was planning to just put it into the profile. What is the reason you didn't just use the profile?
I can't speak for Alex, but storing data in the profile is stored basically as a blob. In other words there is really no way filter, sort, etc on profile data. However, there is a ProfileTableProvider (http://www.asp.net/sandbox/samp_profiles.aspx?tabindex=0&tabid=1) which I'm looking to implement which allows you to store the profile data in a table. This way, using llblenPro you have full access to the profile data for filtering. This was a big problem for me in not using the profile data.
Eric
Now we're talkin meat and potatoes here. These were all concerns I had when I started out on this project. It would appear that MS wants us to use the Profile provider for storing extra information, but as Eric said, there isn't a way to filter users on that profile data. At least, I'm pretty sure there isn't. If you want all users in SC, for excample, You have to loop through every user, get their profile data, check to see if it exists, and add that user to some external collection. Had the ProfileTableProvider existed when I started my project, I might have used that. For now, I have a manager class that works with users to handle the extra fields.