• Print

Author Topic: 2FA Authentication for Garry's Mod  (Read 7833 times)

0 Members and 1 Guest are viewing this topic.

Offline iViscosity

  • Respected Community Member
  • Hero Member
  • *****
  • Posts: 803
  • Karma: 58
2FA Authentication for Garry's Mod
« on: October 17, 2016, 05:40:33 pm »
I was wondering about some hooks. In particular, PlayerSpawn, PlayerInitialSpawn, PlayerConnect, and PlayerAuthed. When, exactly are these called? PlayerSpawn says it calls even on respawns, so that one's out of the question of what I want. Basically, I want a hook that is called when the person first actually enters the game, and not again until they leave.


EDIT: Read below.
« Last Edit: October 18, 2016, 02:42:38 pm by iViscosity »
I'm iViscosity. I like gaming and programming. Need some help? Shoot me PM.

Offline Megiddo

  • Ulysses Team Member
  • Hero Member
  • *****
  • Posts: 6214
  • Karma: 394
  • Project Lead
Re: Hook Question
« Reply #1 on: October 17, 2016, 05:50:48 pm »
You want PlayerInitialSpawn and PlayerDisconnected.

If you want to know exactly when they're called, add them all and have them print some test message.
Experiencing God's grace one day at a time.

Offline iViscosity

  • Respected Community Member
  • Hero Member
  • *****
  • Posts: 803
  • Karma: 58
Re: Hook Question
« Reply #2 on: October 17, 2016, 07:23:51 pm »
Ok, on a related note, can you help me figure out why this isn't working?

Here's a link to my repo: https://github.com/iViscosity/2FA-Gmod

You've probably seen it on the forums, but it's the 2FA-style authentication for gmod. Basically, nothing pops up when I first spawn into the server, and there is no 'pins.txt' file in my data/2fa folder (but there is a data/2fa folder). Is there something obvious I'm missing here? Also, adding a PIN works fine, but changing it gives me an error:
Code: [Select]
[ERROR] addons/ulx/lua/ulx/log.lua:476: bad argument #2 to 'format' (number expected, got userdata)
  1. format - [C]:-1
   2. unknown - addons/ulx/lua/ulx/log.lua:476
    3. gsub - [C]:-1
     4. fancyLogAdmin - addons/ulx/lua/ulx/log.lua:450
      5. fancyLog - addons/ulx/lua/ulx/log.lua:514
       6. call - addons/2fa/lua/ulx/modules/sh/sh_setpin.lua:85
        7. __fn - addons/ulib/lua/ulib/shared/commands.lua:943
         8. unknown - addons/ulib/lua/ulib/shared/commands.lua:1296
          9. unknown - lua/includes/modules/concommand.lua:54
related code:
https://github.com/iViscosity/2FA-Gmod/blob/master/2FA/lua/ulx/modules/sh/sh_setpin.lua#L85
« Last Edit: October 17, 2016, 07:25:50 pm by iViscosity »
I'm iViscosity. I like gaming and programming. Need some help? Shoot me PM.

Offline roastchicken

  • Respected Community Member
  • Sr. Member
  • *****
  • Posts: 476
  • Karma: 84
  • I write code
Re: Hook Question
« Reply #3 on: October 18, 2016, 11:37:16 am »
The reason pins.txt isn't being created is because you're created a file by concatenating 'data/2FA' and 'pins.txt'. This is probably not what you want to do, as shown by running the following code:

Code: Lua
  1. local dir = "data/2FA"
  2. local pins = "pins.txt"
  3. local file = dir .. pins
  4.  
  5. print( file )

This will output

Code: Lua
  1. data/2FApins.txt

You'll need to add another slash somewhere in there.
Give a man some code and you help him for a day; teach a man to code and you help him for a lifetime.

Offline iViscosity

  • Respected Community Member
  • Hero Member
  • *****
  • Posts: 803
  • Karma: 58
Re: Hook Question
« Reply #4 on: October 18, 2016, 11:46:34 am »
Ohh I get it. Makes sense, thanks.

Edit: Realized why it was erroring, too. I changed the arg to a StringArg, but forgot to change all the #i to #s.

Another question: I'm wondering how to get a specific value from a certain key, in this case ULXTFAPins[ sid ].

I tried ULXTFAPINs[ sid ].v[ 1 ], but I'm not sure if that's right.
« Last Edit: October 18, 2016, 11:50:32 am by iViscosity »
I'm iViscosity. I like gaming and programming. Need some help? Shoot me PM.

Offline iViscosity

  • Respected Community Member
  • Hero Member
  • *****
  • Posts: 803
  • Karma: 58
Re: 2FA-Authentication
« Reply #5 on: October 18, 2016, 01:04:54 pm »
Seems that didn't fix it... I changed it to #s but I still get the error. It's the same error.


Also, is there a way to restrict the number of characters in the string for the PIN, as I want it to be no more or less than 6.
« Last Edit: October 18, 2016, 02:53:10 pm by iViscosity »
I'm iViscosity. I like gaming and programming. Need some help? Shoot me PM.

Offline Bytewave

  • Respected Community Member
  • Hero Member
  • *****
  • Posts: 718
  • Karma: 116
  • :)
    • My Homepage
Re: 2FA Authentication for Garry's Mod
« Reply #6 on: October 18, 2016, 03:53:36 pm »
Protip, iViscosity: Don't echo the pins to everyone, even if it's a silent echo. Also, you may want to look into hashing the pins before storing them, and you should probably not let other users set pins.

Also, perhaps you should take a look at TOTP-based authentication (a bit more complicated, but doable in Lua if you can find a spec). Then, pins will change automatically on 30-second intervals, and require a second factor (phone, etc) for authentication.

Here's a TOTP library I found. Might be worth looking into.
Here's a QR code library as well, which would be useful for generating a QR code for the URI given by luaotp. You could have users type their secret in manually, but that's inconvenient. Plus, luaqrcode seems to just output a 2D array with 1s and 0s representing black and white cells, perfect for doing whatever with.
« Last Edit: October 18, 2016, 03:57:14 pm by Bytewave »
bw81@ulysses-forums ~ % whoami
Homepage

Offline iViscosity

  • Respected Community Member
  • Hero Member
  • *****
  • Posts: 803
  • Karma: 58
Re: 2FA Authentication for Garry's Mod
« Reply #7 on: October 18, 2016, 04:03:47 pm »
Protip, iViscosity: Don't echo the pins to everyone, even if it's a silent echo. Also, you may want to look into hashing the pins before storing them, and you should probably not let other users set pins.

Huh, I thought using fancyLog( { something in here } ... ) would only echo to the "something in here", am I wrong?

Also, perhaps you should take a look at TOTP-based authentication (a bit more complicated, but doable in Lua if you can find a spec). Then, pins will change automatically on 30-second intervals, and require a second factor (phone, etc) for authentication.
Here's a TOTP library I found. Might be worth looking into.
Here's a QR code library as well, which would be useful for generating a QR code for the URI given by luaotp. You could have users type their secret in manually, but that's inconvenient. Plus, luaqrcode seems to just output a 2D array with 1s and 0s representing black and white cells, perfect for doing whatever with.
I thought about this, but I've no idea where I could store it. On a related note, if it were to store/change, where could those users access it?
I'm iViscosity. I like gaming and programming. Need some help? Shoot me PM.

Offline Bytewave

  • Respected Community Member
  • Hero Member
  • *****
  • Posts: 718
  • Karma: 116
  • :)
    • My Homepage
Re: 2FA Authentication for Garry's Mod
« Reply #8 on: October 18, 2016, 04:25:33 pm »
Huh, I thought using fancyLog( { something in here } ... ) would only echo to the "something in here", am I wrong?
Well, if anything, it stores it in the serverside logs, so those could be pulled by someone attacking the server. But if your server gets hacked that badly, you have bigger problems. So I suppose it's less of an issue.

I thought about this, but I've no idea where I could store it. On a related note, if it were to store/change, where could those users access it?
Store the secret in plaintext, like in pdata. The QR code needs to only be shown once, then never again once you verify the TOTP app was set up properly.
You should never need to change the TOTP secret unless an account is compromised, in which case you should probably have a re-generate button or command of some sort available for other admins to run.

My suggestion for the TOTP flow:
  • Staff member joins server
    • If no TOTP secret in database, generate one and show a popup with a QR code and a code box, preferably with some instructions on how to set up TOTP with an app
    • If TOTP key, show a simple code box
  • Once code is verified, add user to staff rank

Again, if an account is compromised, you could have a command to invalidate (unset) the TOTP secret in your database, which causes the user to go through the first time setup again.
bw81@ulysses-forums ~ % whoami
Homepage

Offline iViscosity

  • Respected Community Member
  • Hero Member
  • *****
  • Posts: 803
  • Karma: 58
Re: 2FA Authentication for Garry's Mod
« Reply #9 on: October 18, 2016, 04:35:50 pm »
Sounds interesting enough... I could try and give it a shot.

I have a couple questions, though. If it shows a QR code and say they scan it with their phone, how would they be able to access it? Say if they used Google Authenticator, how can I set up a system with gmod to have the key match the key in that app to work? I'm pretty sure I can't set PData of a Steam ID (could be wrong) but even if I could, I'd need to set the PData to the same get as in the Authenticator, correct? If that's the case, my other questions stands, how can I get them to match?
I'm iViscosity. I like gaming and programming. Need some help? Shoot me PM.

Offline Bytewave

  • Respected Community Member
  • Hero Member
  • *****
  • Posts: 718
  • Karma: 116
  • :)
    • My Homepage
Re: 2FA Authentication for Garry's Mod
« Reply #10 on: October 18, 2016, 05:23:08 pm »
Sounds interesting enough... I could try and give it a shot.

I have a couple questions, though. If it shows a QR code and say they scan it with their phone, how would they be able to access it? Say if they used Google Authenticator, how can I set up a system with gmod to have the key match the key in that app to work? I'm pretty sure I can't set PData of a Steam ID (could be wrong) but even if I could, I'd need to set the PData to the same get as in the Authenticator, correct? If that's the case, my other questions stands, how can I get them to match?
Well, PData was an example, though for offline manipulation you might want to try /data/ or something similar.

Anyway, the OTP spec has ways of matching codes. Basically, you generate a secret key for a user, and give that to them on their app and store it locally on the server. The secret key as well as the current Unix time (+/- 15 seconds) are used to generate a (typically) 6 digit PIN, which is sent to the server where it is compared to a PIN generated in the same way. So, all you would have to do is store the secret key on the server, and use luaotp to verify.

edit: If you think servers aren't going to be synced up very accurately time-wise, you may wish to consider HOTP over TOTP, which uses an internal counter to generate PINs. However, this is easier to exploit.
« Last Edit: October 18, 2016, 05:24:58 pm by Bytewave »
bw81@ulysses-forums ~ % whoami
Homepage

Offline iViscosity

  • Respected Community Member
  • Hero Member
  • *****
  • Posts: 803
  • Karma: 58
Re: 2FA Authentication for Garry's Mod
« Reply #11 on: October 18, 2016, 05:26:41 pm »
Haha, I have absolutely no clue where to start, to be honest. Is there any guide or tutorial on how to get started doing that? Also, it's not that I don't think they're be synced, I just don't know how to make them be synced :P
I'm iViscosity. I like gaming and programming. Need some help? Shoot me PM.

Offline Bytewave

  • Respected Community Member
  • Hero Member
  • *****
  • Posts: 718
  • Karma: 116
  • :)
    • My Homepage
Re: 2FA Authentication for Garry's Mod
« Reply #12 on: October 18, 2016, 05:35:17 pm »
Haha, I have absolutely no clue where to start, to be honest. Is there any guide or tutorial on how to get started doing that? Also, it's not that I don't think they're be synced, I just don't know how to make them be synced :P
Synchronization is done by the server's operating system. You shouldn't have to worry about that unless a server is poorly maintained.

You should probably start with the basics first. Get PIN storage down. Then, take a look at luaotp's documentation over TOTP. You would do something like (pseudocode):
Code: Lua
  1. totp = otp.new_totp()
  2. storePlayerKey(ply, totp:get_key())
  3. showQRCodeToPlayer(ply)
  4. code = getPlayerResponse(ply)
  5. if totp:verify(code) then
  6.     -- Code successfully set up, close panel and add user to staff
  7. else
  8.     -- Incorrect code or something went wrong, error out
  9. end

Or, for a user who has a key (pseudocode):
Code: Lua
  1. totp = otp.new_totp_from_key(getPlayerKey(ply))
  2. code = getPlayerResponse(ply)
  3. if totp:verify(code) then
  4.     -- Code valid, add user to staff
  5. else
  6.     -- Code invalid, show error and do whatever
  7. end

Also, for QR codes, luaqrcode provides a single function, qrcode that generates a 2-dimensional array with 1's and 0's, as I said. You would have to convert that to something on-screen somehow, but that shouldn't be **terribly** difficult.
« Last Edit: October 18, 2016, 05:38:38 pm by Bytewave »
bw81@ulysses-forums ~ % whoami
Homepage

  • Print