Fixed Price Projects          Flexibele IT oplossingen

Software op maat              Web Applications

Ever wanted to implement your own password policy?
This is how you can do it 

 

This code remembers the last 10 passwords, and checks that a new password is not in this list.

 

The Web.Config: 

<membership defaultProvider="BITMembershipProvider" userIsOnlineTimeWindow="15">
      <providers>
        <clear />

....

<add name="BITMembershipProvider" type="Glassdrive.provider.myOwnMembershipProvider" connectionStringName="SiteSqlServer" enablePasswordRetrieval="true" enablePasswordReset="true" requiresQuestionAndAnswer="false" minRequiredPasswordLength="7" minRequiredNonalphanumericCharacters="0" requiresUniqueEmail="false" passwordFormat="Encrypted" applicationName="DotNetNuke" description="Stores and retrieves membership data from the local Microsoft SQL Server database" passwordStrengthRegularExpression="(?i)^(?!.*bitconsultancy).*$" />

....

 

The SQL Table: 

 /****** Object:  Table [dbo].[gl_pw_hist]    Script Date: 06/10/2009 10:30:00 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[gl_pw_hist](
 [username] [nvarchar](100) NOT NULL,
 [dt_cre] [datetime] NOT NULL CONSTRAINT [DF_gl_pw_hist_dt_cre]  DEFAULT (getdate()),
 [password] [nvarchar](255) NOT NULL,
 CONSTRAINT [PK_gl_pw_hist] PRIMARY KEY CLUSTERED
(
 [username] ASC,
 [dt_cre] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

The Stored Procedure:

-- =============================================
-- Author:    Olivier Jooris
-- Create date: 09/06/2009
-- Description:  add a new password to the history table, and remove the last one
-- =============================================
create PROCEDURE [dbo].[gl_pw_histADD]
  @username              nvarchar(100), --username to remember history for
  @password              nvarchar(255), --encrypted password to remember
  @NrOfPasswordsToRemember      int = 0      --hostsetting for number of passwords to remember, if not entered, it will be selected from the table

AS
BEGIN
-- declare variables
declare @NrOfPasswordsToRemember_int    int
declare @NrOfPasswordsToRemember_string    nvarchar(50)
declare @NrOfPaswordsStored          int

-- select the number of passwords to remember
IF @NrOfPasswordsToRemember > 0
  BEGIN
    set @NrOfPasswordsToRemember_int = @NrOfPasswordsToRemember
  END
ELSE
  BEGIN
    -- select the setting from the table
    SELECT @NrOfPasswordsToRemember_string = settingvalue from hostsettings where settingname = 'NrOfPasswordsToRemember'

    -- try to convert the setting from text to integer
    BEGIN TRY
      set @NrOfPasswordsToRemember_int = cast(@NrOfPasswordsToRemember_string as int)
    END TRY
    BEGIN CATCH
      set @NrOfPasswordsToRemember_int = 0
    END CATCH;
  END

-- insert the new pasword
INSERT INTO [gl_pw_hist] ([username],[password]) VALUES (@username, @password)

-- select the number of passwords in the system
select @NrOfPaswordsStored = count(*) from gl_pw_hist where username = @username

-- delete the last one if there are more than requested
if @NrOfPaswordsStored > @NrOfPasswordsToRemember_int
  BEGIN
    delete from gl_pw_hist
      where  username = @username
      and    dt_cre   = (select min(dt_cre) from gl_pw_hist where username = @username)
  END

END

 

The VB Code:

 

 

Imports System.Collections.Generic
 
Imports System.Data.SqlClient
 
Imports System.Security.Cryptography
 
Imports System.IO
 
Namespace BIT.provider
Public Class myOwnMembershipProvider
Inherits SqlMembershipProvider
Private my_salt As String = "tP+AyV0u7hdu+YOueFc7ow=="
 
#Region "Entry pointS"
 
Public Overrides Function ResetPassword(ByVal username As String, ByVal passwordAnswer As String) As String
 
Try
 
 
 
Return MyBase.ResetPassword(username, passwordAnswer)
Catch ex As Exception
Throw New Exception(ex.Message)
End Try
 
End Function
 
 
Public Overrides Function ChangePassword(ByVal username As String, ByVal oldPassword As String, ByVal newPassword As String) As Boolean
 
Try
 
'TODO:Does not work to inject a alert javascript into the calling page

'Dim i As Stream = DirectCast(HttpContext.Current.Response, System.Web.HttpResponse).OutputStream
 
'Dim smess As String = "<script language='javascript'>alert('this is an injection from my provider oljo');</script>"
 
'Dim bytes() As Byte = Encoding.ASCII.GetBytes(smess)
 
'i.Write(bytes, 0, bytes.Length)
 
'Dim executingPage As Page = TryCast(HttpContext.Current.Handler, Page)
 
'executingPage.RegisterStartupScript("kjhkjh", smess)
 
'executingPage.ClientScript.RegisterClientScriptBlock(executingPage.GetType, "oljokey", smess)
 
'executingPage.ClientScript.RegisterStartupScript(executingPage.GetType, "oljokey", smess)
 
'Dim c As ControlCollection = executingPage.Controls()
 
'DirectCast(DirectCast(c(2), System.Web.UI.Control), System.Web.UI.HtmlControls.HtmlGenericControl).Attributes.Add("oljokey", smess)
 
'HttpContext.Current.Response.Write(smess)
 
'executingPage.ClientScript.RegisterStartupScript(executingPage.GetType, "oljokey", smess)
 
'encode the password with my specific salt
 
Dim sEncodedPw As String = EncodePassword(newPassword, 2, my_salt)
'check if the password is already used
 
If check_new_pw_recurrence(username, sEncodedPw) Then
 
Return False
 
End If
 
'it was not used, continue with the standard code
 
Dim ok As Boolean = MyBase.ChangePassword(username, oldPassword, newPassword)
'if the change was ok, then add the new password to the history
 
If ok Then
 
add_new_password_to_the_list(username, sEncodedPw)
End If
 
'return the result from the standard code
 
Return ok
Catch ex As Exception
Throw New Exception(ex.Message)
End Try
 
End Function
#End Region
#Region "Private Functions"
 
''' <summary>
 
''' check if the password is recurring, the add new_history deletes older passwords
 
''' so the history contains always all passwords to check
 
''' </summary>
 
''' <param name="username"></param>
 
''' <param name="sEncPassword">encripted password</param>
 
''' <returns></returns>
 
''' <remarks></remarks>
 
Private Function check_new_pw_recurrence(ByVal username As String, ByVal sEncPassword As String) As Boolean
 
Try
 
'check it in the db
 
Return password_exists_in_db(username, sEncPassword)
Catch ex As Exception
Throw New Exception(ex.Message)
End Try
 
End Function
 
''' <summary>
 
''' encode the pasword with the salt
 
''' </summary>
 
''' <param name="pass"></param>
 
''' <param name="passwordFormat"></param>
 
''' <param name="salt"></param>
 
''' <returns></returns>
 
''' <remarks></remarks>
 
Private Function EncodePassword(ByVal pass As String, ByVal passwordFormat As Integer, ByVal salt As String) As String
 
If (passwordFormat = 0) Then
 
Return pass
End If
 
Dim bytes As Byte() = Encoding.Unicode.GetBytes(pass)
Dim src As Byte() = Convert.FromBase64String(salt)
Dim dst As Byte() = New Byte((src.Length + bytes.Length) - 1) {}
Dim inArray As Byte() = Nothing
 
Buffer.BlockCopy(src, 0, dst, 0, src.Length)
Buffer.BlockCopy(bytes, 0, dst, src.Length, bytes.Length)
If (passwordFormat = 1) Then
 
inArray = Me.EncryptPassword(bytes) 'not used for glassdrive, use un-salted encription
 
Else
 
inArray = Me.EncryptPassword(dst)
End If
 
Return Convert.ToBase64String(inArray)
End Function
 
#End Region
#Region "DB Access"
 
''' <summary>
 
''' read the gl_pw_hist table with the new password
 
''' </summary>
 
''' <param name="username"></param>
 
''' <param name="newPassword">encoded new password</param>
 
''' <returns></returns>
 
''' <remarks></remarks>
 
Private Function password_exists_in_db(ByVal username As String, ByVal newPassword As String) As Boolean
 
Dim ir As IDataReader = Nothing
 
Try
 
Dim s As String = "select * from [gl_pw_hist] where username = '@u' and password = '@p'"
 
s = s.Replace("@u", username).Replace("@p", newPassword)
ir = select_reader_sql(s)
Return ir.Read 'read it in the database
 
Catch ex As Exception
Throw New Exception(ex.Message)
Finally
 
If ir IsNot Nothing AndAlso Not ir.IsClosed Then
 
ir.Close()
End If
 
End Try
 
End Function
 
''' <summary>
 
''' adds the new password to the history, and removes older ones (depending on the hostsetting "NrOfPasswordsToRemember")
 
''' </summary>
 
''' <param name="username"></param>
 
''' <param name="newEncrPassword">new encrypted password</param>
 
''' <returns></returns>
 
''' <remarks></remarks>
 
Private Function add_new_password_to_the_list(ByVal username As String, ByVal newEncrPassword As String) As Boolean
 
Try
 
Dim p As New List(Of SqlParameter)
p.Add(New SqlParameter("@username", username))
p.Add(New SqlParameter("@password", newEncrPassword))
Dim i As Integer = exec_sqlsp("gl_pw_histADD", p.ToArray)
Catch ex As Exception
Throw New Exception(ex.Message)
End Try
 
End Function
#End Region
 
 
End Class
End Namespace

Categorie: .NET, DotNetNuke
Actions: E-mail | Permalink |

waardering