fully implement 2factor auth
This commit is contained in:
parent
54f058bb57
commit
bd7dbeaecc
|
@ -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}"))
|
|
@ -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())
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()),
|
||||
|
|
46
install.sh
46
install.sh
|
@ -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]
|
||||
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue