Massive customer importation from file


https://forum.kartris.com/Topic3866.aspx
Print Topic | Close Window

By Supermac - Wed 22 Jul 2015
I'd like to write a routine to import massively customers (from csv file or from an SQL table, previously extracted from an ERP) in [tblKartrisUsers] table.

Giving a look to the table I found that the minimal info I should supply to an insert command are:
[U_EmailAddress],[U_Password],[U_AccountHolderName],[U_LanguageID],[U_SaltValue]
having that the rest of fields in SQL database have a default value or are not needed to let then the user access the site.

The problem are [U_Password] and [U_SaltValue] values: I don't understand how they work because it seems to me that every record in [tblKartrisUsers] table has its [U_SaltValue] as if every password has its personal decrypting key (randomly generated?).
Furthermore, even [U_SaltValue] seems encrypted itself... maybe using Hash Salt String defined in install process and stored in web.config.file?

May you summarize to me how it works the relationship between [U_Password] and [U_SaltValue] (and eventually web.config's Hash Salt String)?
And then may you suggest to me a modus operandi to reach my goal?

Thank you a lot
By Paul - Thu 23 Jul 2015
Suggest as a starting point you look at the UsersBLL.vb, and in particular the _Add function

    Public Shared Function _Add(ByVal U_AccountHolderName As String, ByVal U_EmailAddress As String, ByVal U_Password As String, ByVal U_LanguageID As Integer, _
ByVal U_CustomerGroupID As Integer, ByVal U_CustomerDiscount As Double, ByVal blnUserApproved As Boolean, _
ByVal blnUserAffiliate As Boolean, ByVal U_AffiliateCommission As Double, ByVal U_SupportEndDate As Date, ByVal U_Notes As String) As Integer
Try
Dim dtNull As Nullable(Of DateTime) = Nothing
Dim strRandomSalt As String = Membership.GeneratePassword(20, 0)
Return CustomerDetailsAdptr._Add(U_AccountHolderName, U_EmailAddress, EncryptSHA256Managed(U_Password, strRandomSalt), U_LanguageID, U_CustomerGroupID, U_CustomerDiscount, blnUserApproved, _
blnUserAffiliate, U_AffiliateCommission, IIf(U_SupportEndDate = Nothing Or U_SupportEndDate = "#12:00:00 AM#", dtNull, U_SupportEndDate), U_Notes, strRandomSalt)
Catch ex As Exception
ReportHandledError(ex, Reflection.MethodBase.GetCurrentMethod())
Return Nothing
End Try

End Function


This references the EncryptSHA256Managed function, from which you can see how the password in Kartris is hashed:

ConfigurationManager.AppSettings("hashsalt") & ClearString & SaltString

ConfigurationManager.AppSettings("hashsalt") is a value created when you install Kartris, and is written into an appsetting near the top of your web.config file. The SaltString is a random code up to 20 chars long created for each record. The ClearString is the cleartext password.

So if a user chooses 'mypassword123' as their password, then to get the hashed value you see in the users table we do

[hashsalt-from-user-record] & "mypassword123" & [hash-from-web-config]

Then we sha-256 this, and base64 encode the result.

For the purposes of your script to import usernames, you could use the same hashsalt for each user, but it's not a good idea, it's best to generate a random one for each user. Then you need the hashsalt value from your web.config file too, a sha-256 function and base64 function.

btw, the reason we have a global hashsalt as well as one in web.config is for additional security - the db alone doesn't contain all the information you'd need to hash a password guess, so it increases the number of attempts you'd need to make to get a hit massively. It also means if you take a Kartris db from one site and put it on another one, the password logins won't work unless you make sure the web.config hashsalt value matches.
By Mart - Fri 24 Jul 2015
Also, adding a hash salt for each separate password record makes brute force attacks more difficult... if we didn't do that an attacker could attack all the passwords at once. If you have thousands of user accounts his chances of breaking a few are very high, but with a separate salt per password, it means he realistically can only attack one at a time, making a brute force attack much more difficult.
By Supermac - Mon 27 Jul 2015
Thank you a lot
I'll keep updated you on my progress!
By Supermac - Thu 30 Jul 2015
Ok let's say I inserted a record in [tblKartrisUsers] table and now my user could already enter the site logging in.

Now I have to insert his address, etcetera in [tblKartrisAddresses] table.

In KartrisClassess.vb there's an interesting [AddUpdate] function... I think I should use this one, can you please confirm and explain me values I can assign to ADR_Type?
If I understand correctly, after insertion this function returns ADR_ID, is it right?
By Supermac - Thu 30 Jul 2015
I could use a thing like this?

Dim idcliente = userBLL._Add(U_AccountHolderName, U_EmailAddress, U_Password, U_LanguageID, U_CustomerGroupID, U_CustomerDiscount, blnUserApproved, blnUserAffiliate, U_AffiliateCommission, U_SupportEndDate, U_Notes)

'userBLL._Add may return nothing if something goes wrong
if not isnothing(idcliente) then
'create address object with data from file
Dim addr = New KartrisClasses.Address(<name of customer>, <company>, <address>, <city>, <P.O.code>, <destination.D_ID of customer's country>, <phone>Wink

'insert new address
Dim addrID = KartrisClasses.Address.AddUpdate(addr, idcliente, True)
end if

???
By Supermac - Fri 31 Jul 2015
YEAH IT WORKS! :-)
Added a page to backend that loads csv file and do all job using K's classes/methods...
Now I've only to save passwords in a file (I create them randomly as clear strings and save them in a temporary table with relative customer name) and prompt it to the user, otherwise nobody will know how to access website :-)