fully implement 2factor auth

This commit is contained in:
wh1te909 2020-01-19 22:24:38 +00:00
parent 54f058bb57
commit bd7dbeaecc
8 changed files with 88 additions and 31 deletions

View File

@ -0,0 +1,22 @@
import pyotp
import subprocess
from django.core.management.base import BaseCommand
class Command(BaseCommand):
help = "Generates barcode for Google Authenticator"
def add_arguments(self, parser):
parser.add_argument("code", type=str)
parser.add_argument("username", type=str)
def handle(self, *args, **kwargs):
code = kwargs["code"]
username = kwargs["username"]
url = pyotp.totp.TOTP(code).provisioning_uri(
username, issuer_name="Tactical RMM"
)
subprocess.run(f'qr "{url}"', shell=True)
self.stdout.write(self.style.SUCCESS("Scan the barcode above with your google authenticator app"))
self.stdout.write(self.style.SUCCESS(f"If that doesn't work you may manually enter the key: {code}"))

View File

@ -0,0 +1,9 @@
import pyotp
from django.core.management.base import BaseCommand
class Command(BaseCommand):
help = "Generates TOTP Random Base 32"
def handle(self, *args, **kwargs):
self.stdout.write(pyotp.random_base32())

View File

@ -17,6 +17,15 @@ from rest_framework.decorators import (
from accounts.models import User
class CheckCreds(KnoxLoginView):
permission_classes = (AllowAny,)
def post(self, request, format=None):
serializer = AuthTokenSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
return Response("ok")
class LoginView(KnoxLoginView):
@ -24,9 +33,8 @@ class LoginView(KnoxLoginView):
def post(self, request, format=None):
token = request.data["twofactor"]
# totp = pyotp.TOTP(settings.TWO_FACTOR_OTP)
# if totp.verify(token, valid_window=1):
if token == "sekret":
totp = pyotp.TOTP(settings.TWO_FACTOR_OTP)
if totp.verify(token, valid_window=1):
serializer = AuthTokenSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data["user"]
@ -41,9 +49,8 @@ class LoginView(KnoxLoginView):
@permission_classes((IsAuthenticated,))
def installer_twofactor(request):
token = request.data["twofactorToken"]
# totp = pyotp.TOTP(settings.TWO_FACTOR_OTP)
# if totp.verify(token, valid_window=1):
if token == "sekret":
totp = pyotp.TOTP(settings.TWO_FACTOR_OTP)
if totp.verify(token, valid_window=1):
return Response("ok")
else:
return Response("bad 2 factor code", status=status.HTTP_400_BAD_REQUEST)

View File

@ -23,6 +23,7 @@ pycparser==2.19
pyotp==2.3.0
pyparsing==2.4.6
pytz==2019.3
qrcode==6.1
redis==3.3.11
requests==2.22.0
six==1.14.0

View File

@ -2,10 +2,11 @@ from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from knox import views as knox_views
from accounts.views import LoginView, installer_twofactor
from accounts.views import LoginView, CheckCreds, installer_twofactor
urlpatterns = [
path(settings.ADMIN_URL, admin.site.urls),
path("checkcreds/", CheckCreds.as_view()),
path("login/", LoginView.as_view()),
path("logout/", knox_views.LogoutView.as_view()),
path("logoutall/", knox_views.LogoutAllView.as_view()),

View File

@ -44,8 +44,6 @@ echo -ne "${YELLOW}Enter your username for meshcentral${NC}: "
read meshusername
echo -ne "${YELLOW}Enter your email address for let's encrypt renewal notifications${NC}: "
read letsemail
echo -ne "${YELLOW}Please use google authenticator and enter TOTP code${NC}: "
read twofactor
print_green 'Creating saltapi user'
@ -157,6 +155,30 @@ sudo chown ${USER}:${USER} /var/log/celery
git clone https://github.com/wh1te909/tacticalrmm.git /home/${USER}/rmm/
sudo chown ${USER}:www-data -R /home/${USER}/rmm/api/tacticalrmm
print_green 'Installing the backend'
cd /home/${USER}/rmm/api
python3.7 -m venv env
source /home/${USER}/rmm/api/env/bin/activate
cd /home/${USER}/rmm/api/tacticalrmm
pip install --upgrade pip
pip install -r /home/${USER}/rmm/api/tacticalrmm/requirements.txt
python manage.py migrate
python manage.py collectstatic
printf >&2 "${YELLOW}%0.s*${NC}" {1..80}
printf >&2 "\n"
printf >&2 "${YELLOW}Please create your login for the RMM website and django admin${NC}\n"
printf >&2 "${YELLOW}%0.s*${NC}" {1..80}
printf >&2 "\n"
echo -ne "Username: "
read djangousername
python manage.py createsuperuser --username ${djangousername} --email ${letsemail}
RANDBASE=$(python manage.py generate_totp)
python manage.py generate_barcode ${RANDBASE} ${djangousername}
deactivate
localvars="$(cat << EOF
SECRET_KEY = "${DJANGO_SEKRET}"
@ -210,29 +232,11 @@ SALT_USERNAME = "saltapi"
SALT_PASSWORD = "${SALTPW}"
MESH_USERNAME = "${meshusername}"
MESH_SITE = "https://${meshdomain}"
TWO_FACTOR_OTP = "${twofactor}"
TWO_FACTOR_OTP = "${RANDBASE}"
EOF
)"
echo "${localvars}" > /home/${USER}/rmm/api/tacticalrmm/tacticalrmm/local_settings.py
print_green 'Installing the backend'
cd /home/${USER}/rmm/api
python3.7 -m venv env
source /home/${USER}/rmm/api/env/bin/activate
cd /home/${USER}/rmm/api/tacticalrmm
pip install --upgrade pip
pip install -r /home/${USER}/rmm/api/tacticalrmm/requirements.txt
python manage.py migrate
python manage.py collectstatic
printf >&2 "${YELLOW}%0.s*${NC}" {1..80}
printf >&2 "\n"
printf >&2 "${YELLOW}Please create your login for the RMM website and django admin${NC}\n"
printf >&2 "${YELLOW}%0.s*${NC}" {1..80}
printf >&2 "\n"
python manage.py createsuperuser
deactivate
uwsgini="$(cat << EOF
[uwsgi]

View File

@ -169,7 +169,7 @@ export const store = new Vuex.Store({
timeout: 1000,
textColor: "white",
icon: "fas fa-times-circle",
message: "Invalid credentials"
message: "Bad token"
});
reject(error);
});

View File

@ -3,8 +3,8 @@
<div class="row text-center">
<div class="col"></div>
<div class="col">
<h5>Tactical Techs RMM</h5>
<q-form @submit.prevent="prompt = true" class="q-gutter-md">
<h5>Tactical RMM</h5>
<q-form @submit.prevent="checkCreds" class="q-gutter-md">
<q-input
outlined
v-model="credentials.username"
@ -55,8 +55,12 @@
</template>
<script>
import axios from "axios";
import mixins from "@/mixins/mixins";
export default {
name: "Login",
mixins: [mixins],
data() {
return {
credentials: {},
@ -65,6 +69,15 @@ export default {
},
methods: {
checkCreds() {
axios.post("/checkcreds/", this.credentials)
.then(r => {
this.prompt = true;
})
.catch(() => {
this.notifyError('Bad credentials')
})
},
onSubmit() {
this.$store
.dispatch("retrieveToken", this.credentials)