forked from mystiq/sso
Compare commits
11 Commits
Author | SHA1 | Date |
---|---|---|
Harikrishna Jiju | bffba7ec30 | |
Alan Alexander Thomas | 77b01cec1c | |
Alan Alexander Thomas | 8f62c31d49 | |
Aravinth Manivannan | 729447e9d6 | |
Aravinth Manivannan | b7009ebf22 | |
Alan Alexander Thomas | 6cd459fd5c | |
Aravinth Manivannan | b5e1bc9d5e | |
Aravinth Manivannan | 2e9cc6aa7f | |
Aravinth Manivannan | d1cb6b1b95 | |
Alan Alexander Thomas | 33e9d830f8 | |
Aravinth Manivannan | 5acf8683a9 |
|
@ -0,0 +1,163 @@
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
*.py,cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
cover/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
.pybuilder/
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
# For a library or package, you might want to ignore these files since the code is
|
||||||
|
# intended to run in multiple environments; otherwise, check them in:
|
||||||
|
# .python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
#Pipfile.lock
|
||||||
|
|
||||||
|
# poetry
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||||
|
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||||
|
# commonly ignored for libraries.
|
||||||
|
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||||
|
#poetry.lock
|
||||||
|
|
||||||
|
# pdm
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||||
|
#pdm.lock
|
||||||
|
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||||
|
# in version control.
|
||||||
|
# https://pdm.fming.dev/#use-with-ide
|
||||||
|
.pdm.toml
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||||
|
__pypackages__/
|
||||||
|
|
||||||
|
# Celery stuff
|
||||||
|
celerybeat-schedule
|
||||||
|
celerybeat.pid
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
||||||
|
# pytype static type analyzer
|
||||||
|
.pytype/
|
||||||
|
|
||||||
|
# Cython debug symbols
|
||||||
|
cython_debug/
|
||||||
|
|
||||||
|
# PyCharm
|
||||||
|
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||||
|
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||||
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
|
#.idea/
|
||||||
|
|
||||||
|
sso/local_settings.py
|
||||||
|
sso/local_settings/local_settings.py
|
|
@ -158,3 +158,5 @@ cython_debug/
|
||||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
#.idea/
|
#.idea/
|
||||||
|
sso/local_settings.py
|
||||||
|
sso/local_settings/local_settings.py
|
||||||
|
|
|
@ -6,3 +6,12 @@ pipeline:
|
||||||
- make env
|
- make env
|
||||||
- make lint
|
- make lint
|
||||||
- make coverage
|
- make coverage
|
||||||
|
|
||||||
|
publish:
|
||||||
|
image: plugins/docker
|
||||||
|
settings:
|
||||||
|
username: realaravinth
|
||||||
|
password:
|
||||||
|
from_secret: DOCKER_TOKEN
|
||||||
|
repo: realaravinth/mystiq-sso
|
||||||
|
tags: latest
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
FROM python:3
|
||||||
|
ENV PYTHONDONTWRITEBYTECODE=1
|
||||||
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
#RUN useradd -ms /bin/bash -u 1001 mystiq-sso
|
||||||
|
#USER mystiq-sso
|
||||||
|
WORKDIR /code
|
||||||
|
LABEL org.opencontainers.image.source https://git.batsense.net/mystiq/sso
|
||||||
|
COPY requirements.txt /code/
|
||||||
|
RUN pip install -r requirements.txt
|
||||||
|
COPY . /code/
|
16
Makefile
16
Makefile
|
@ -7,15 +7,23 @@ default: ## Run app
|
||||||
$(call run_migrations)
|
$(call run_migrations)
|
||||||
. ./venv/bin/activate && python manage.py runserver
|
. ./venv/bin/activate && python manage.py runserver
|
||||||
|
|
||||||
env: ## setup environment
|
|
||||||
@-virtualenv venv
|
|
||||||
. ./venv/bin/activate && pip install -r requirements.txt
|
|
||||||
|
|
||||||
coverage: ## Generate test coverage report
|
coverage: ## Generate test coverage report
|
||||||
. ./venv/bin/activate && coverage run manage.py test
|
. ./venv/bin/activate && coverage run manage.py test
|
||||||
. ./venv/bin/activate && coverage report -m
|
. ./venv/bin/activate && coverage report -m
|
||||||
. ./venv/bin/activate && coverage html
|
. ./venv/bin/activate && coverage html
|
||||||
|
|
||||||
|
docker: ## Build Docker image
|
||||||
|
docker build -t realaravinth/mystiq-sso:master -t realaravinth/mystiq-sso:latest .
|
||||||
|
|
||||||
|
docker-publish: docker ## Build and publish Docker image
|
||||||
|
docker push realaravinth/mystiq-sso:master
|
||||||
|
docker push realaravinth/mystiq-sso:latest
|
||||||
|
|
||||||
|
env: ## setup environment
|
||||||
|
@-virtualenv venv
|
||||||
|
. ./venv/bin/activate && pip install -r requirements.txt
|
||||||
|
|
||||||
|
|
||||||
freeze: ## Freeze python dependencies
|
freeze: ## Freeze python dependencies
|
||||||
@. ./venv/bin/activate && pip freeze > requirements.txt
|
@. ./venv/bin/activate && pip freeze > requirements.txt
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
[![status-badge](https://ci.batsense.net/api/badges/mystiq/sso/status.svg)](https://ci.batsense.net/mystiq/sso)
|
[![status-badge](https://ci.batsense.net/api/badges/mystiq/sso/status.svg)](https://ci.batsense.net/mystiq/sso)
|
||||||
|
[![Docker](https://img.shields.io/docker/pulls/realaravinth/mystiq-sso)](https://hub.docker.com/r/realaravinth/mystiq-sso)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# SSO
|
# SSO
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
{% comment %} Login Page {% endcomment %}
|
||||||
|
|
||||||
|
{% block login %}
|
||||||
|
<h2>Log In</h2>
|
||||||
|
<form method="post" action="">
|
||||||
|
{% csrf_token %} {{ form.as_p }}
|
||||||
|
<label class="form__label" for="email">Email</label><br/>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="email"
|
||||||
|
name="email"
|
||||||
|
autofocus
|
||||||
|
required/><br/><br/>
|
||||||
|
|
||||||
|
<label class="form__label" for="pwd">Password</label><br/>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
required
|
||||||
|
id="password"
|
||||||
|
name="password"/><br/><br/>
|
||||||
|
<button type="submit">Log In</button>
|
||||||
|
<input type="hidden" name="next" value="{{ next }}">
|
||||||
|
{% for message in messages %}
|
||||||
|
<p id="messages">{{message}}</p>
|
||||||
|
{% endfor %}
|
||||||
|
</form>
|
||||||
|
{% comment %} <div class="form-group">
|
||||||
|
<label for="exampleInputEmail1">Email address</label>
|
||||||
|
<input type="email" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" placeholder="Enter email">
|
||||||
|
<small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone else.</small>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="exampleInputPassword1">Password</label>
|
||||||
|
<input type="password" class="form-control" id="exampleInputPassword1" placeholder="Password">
|
||||||
|
</div>
|
||||||
|
<div class="form-group form-check">
|
||||||
|
<input type="checkbox" class="form-check-input" id="exampleCheck1">
|
||||||
|
<label class="form-check-label" for="exampleCheck1">Check me out</label>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">Submit</button> {% endcomment %}
|
||||||
|
|
||||||
|
<p class="form__alt-action">
|
||||||
|
New to Mystiq?
|
||||||
|
<a href="{% url 'accounts:register' %}">Create an account</a>
|
||||||
|
</p>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,89 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Registration</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- <form action="{% url 'accounts:register' %}" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<fieldset>
|
||||||
|
<legend><h1>{{ Registration }}</h1></legend>
|
||||||
|
</fieldset>
|
||||||
|
<fieldset>
|
||||||
|
<label for="email">
|
||||||
|
<b>Email</b>
|
||||||
|
<input type="text" placeholder="Enter Email" name="email" id="email" required>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<label for="psw">
|
||||||
|
<b>Password</b>
|
||||||
|
<input type="password" placeholder="Enter Password" name="psw" id="psw" required>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
</fieldset>
|
||||||
|
<fieldset>
|
||||||
|
<label for="cnf-psw">
|
||||||
|
<b>Password</b>
|
||||||
|
<input type="password" placeholder="Confirn Password" name="cnf-psw" id="cnf-psw" required>
|
||||||
|
</label>
|
||||||
|
</fieldset>
|
||||||
|
<input type="submit" value="register">
|
||||||
|
</form> -->
|
||||||
|
|
||||||
|
<form action="{% url 'accounts:register' %}" method="post" class="form" accept-charset="utf-8">
|
||||||
|
{% if error %}
|
||||||
|
<div class="error__container">
|
||||||
|
<h3 class="error__title">ERROR: {{ error.title }}</h3>
|
||||||
|
<p class="error__message">{{ error.reason }}</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="container">
|
||||||
|
<h1>Register</h1>
|
||||||
|
<p>Welcome to mystiq registration.</p>
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<label for="email">
|
||||||
|
<b>Email</b>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Enter Email"
|
||||||
|
name="email"
|
||||||
|
id="email"
|
||||||
|
required
|
||||||
|
{% if email %}
|
||||||
|
value={{ username }}
|
||||||
|
{% endif %}
|
||||||
|
>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
|
||||||
|
<label for="password">
|
||||||
|
<b>Password</b>
|
||||||
|
<input type="password" placeholder="Enter Password" name="password" id="password" required>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
|
||||||
|
<label for="password-confirm">
|
||||||
|
<b>Confirm Password</b>
|
||||||
|
<input type="password" placeholder="Confirm Password" name="password-confirm" id="password-confirm" required>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<p>By creating an account you agree to our <a href="#">Terms & Privacy</a>.</p>
|
||||||
|
<button type="submit" class="form_submit">Register</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="container signin">
|
||||||
|
<p>Already have an account? <a href="{% url 'accounts:login' %}">Sign in</a>.</p>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1 @@
|
||||||
|
<b> Login Successful! <b>
|
|
@ -1,6 +1,7 @@
|
||||||
# Create your tests here.
|
# Create your tests here.
|
||||||
|
|
||||||
# Copyright © 2022 Aravinth Manivannan <realaravinth@batsense.net>
|
# Copyright © 2022 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
|
# Copyright © 2022 Alan Alexander Thomas <alan2000alex@gmail.com>
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU Affero General Public License as
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
@ -36,10 +37,9 @@ from oauth2_provider.models import get_application_model
|
||||||
|
|
||||||
def register_util(t: TestCase, username: str):
|
def register_util(t: TestCase, username: str):
|
||||||
t.password = "asdklfja;ldkfja;df"
|
t.password = "asdklfja;ldkfja;df"
|
||||||
t.username = username
|
t.email = f"{username}@vitap.ac.in"
|
||||||
t.email = f"{t.username}@example.org"
|
|
||||||
t.user = get_user_model().objects.create(
|
t.user = get_user_model().objects.create(
|
||||||
username=t.username,
|
username=username,
|
||||||
email=t.email,
|
email=t.email,
|
||||||
)
|
)
|
||||||
t.user.set_password(t.password)
|
t.user.set_password(t.password)
|
||||||
|
@ -48,10 +48,11 @@ def register_util(t: TestCase, username: str):
|
||||||
|
|
||||||
def login_util(t: TestCase, c: Client, redirect_to: str):
|
def login_util(t: TestCase, c: Client, redirect_to: str):
|
||||||
payload = {
|
payload = {
|
||||||
"login": t.username,
|
"email": t.email,
|
||||||
"password": t.password,
|
"password": t.password,
|
||||||
}
|
}
|
||||||
resp = c.post(reverse("accounts.login"), payload)
|
resp = c.post(reverse("accounts:login"), payload)
|
||||||
|
print(resp.content)
|
||||||
t.assertEqual(resp.status_code, 302)
|
t.assertEqual(resp.status_code, 302)
|
||||||
t.assertEqual(resp.headers["location"], reverse(redirect_to))
|
t.assertEqual(resp.headers["location"], reverse(redirect_to))
|
||||||
|
|
||||||
|
@ -102,3 +103,82 @@ class CreateOidCApplicaiton(TestCase):
|
||||||
self.assertEqual(app.client_type, "confidential")
|
self.assertEqual(app.client_type, "confidential")
|
||||||
self.assertEqual(app.authorization_grant_type, "authorization-code")
|
self.assertEqual(app.authorization_grant_type, "authorization-code")
|
||||||
self.assertEqual(app.algorithm, "HS256")
|
self.assertEqual(app.algorithm, "HS256")
|
||||||
|
|
||||||
|
|
||||||
|
class RegistrationTest(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.username = "register_user"
|
||||||
|
self.password = "2i3j4;1qlk2asdf"
|
||||||
|
self.email = "register_user@vitap.ac.in"
|
||||||
|
|
||||||
|
def test_register_template_works(self):
|
||||||
|
"""
|
||||||
|
Tests if register template renders
|
||||||
|
"""
|
||||||
|
resp = self.client.get(reverse("accounts:register"))
|
||||||
|
self.assertEqual(b"Register" in resp.content, True)
|
||||||
|
|
||||||
|
def test_register_works(self):
|
||||||
|
"""
|
||||||
|
Tests if register works
|
||||||
|
"""
|
||||||
|
c = Client()
|
||||||
|
|
||||||
|
# passwords don't match
|
||||||
|
msg = {
|
||||||
|
"password": self.password,
|
||||||
|
"email": self.email,
|
||||||
|
"password-confirm": self.email,
|
||||||
|
}
|
||||||
|
resp = c.post(reverse("accounts:register"), msg)
|
||||||
|
self.assertEqual(resp.status_code, 400)
|
||||||
|
|
||||||
|
# register user
|
||||||
|
msg["password-confirm"] = self.password
|
||||||
|
resp = c.post(reverse("accounts:register"), msg)
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
|
||||||
|
user = get_user_model().objects.get(username=self.username)
|
||||||
|
|
||||||
|
# duplicate email
|
||||||
|
resp = c.post(reverse("accounts:register"), msg)
|
||||||
|
self.assertEqual(resp.status_code, 400)
|
||||||
|
self.assertEqual(b"This email is already registered." in resp.content, True)
|
||||||
|
|
||||||
|
msg["email"] = "12345@gmail.com"
|
||||||
|
resp = c.post(reverse("accounts:register"), msg)
|
||||||
|
self.assertEqual(resp.status_code, 400)
|
||||||
|
self.assertEqual(
|
||||||
|
b"We do not provide services for this domain yet." in resp.content, True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Login Tests
|
||||||
|
|
||||||
|
|
||||||
|
class LoginTest(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.username = "register_user"
|
||||||
|
self.password = "2i3j4;1qlk2asdf"
|
||||||
|
self.email = "register_user@vitap.ac.in"
|
||||||
|
register_util(t=self, username=self.username)
|
||||||
|
|
||||||
|
def test_register_template_works(self):
|
||||||
|
"""
|
||||||
|
Tests if register template renders
|
||||||
|
"""
|
||||||
|
resp = self.client.get(reverse("accounts:login"))
|
||||||
|
self.assertEqual(b"Log" in resp.content, True)
|
||||||
|
|
||||||
|
def test_login_works(self):
|
||||||
|
"""
|
||||||
|
Tests if login works
|
||||||
|
"""
|
||||||
|
c = Client()
|
||||||
|
payload = {
|
||||||
|
"email": self.email,
|
||||||
|
"password": self.password,
|
||||||
|
}
|
||||||
|
resp = c.post(reverse("accounts:login"), payload)
|
||||||
|
self.assertEqual(resp.status_code, 302)
|
||||||
|
self.assertEqual(resp.headers["location"], reverse("accounts:success_page"))
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
"""sso URL Configuration
|
||||||
|
|
||||||
|
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||||
|
https://docs.djangoproject.com/en/4.1/topics/http/urls/
|
||||||
|
|
||||||
|
Exaimples:
|
||||||
|
Function views
|
||||||
|
1. Add an import: from my_app import views
|
||||||
|
2. Add a URL to urlpatterns: path('', views.home, name='home')
|
||||||
|
Class-based views
|
||||||
|
1. Add an import: from other_app.views import Home
|
||||||
|
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
||||||
|
Including another URLconf
|
||||||
|
1. Import the include() function: from django.urls import include, path
|
||||||
|
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||||
|
"""
|
||||||
|
from django.contrib import admin
|
||||||
|
from django.urls import path
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
app_name = "accounts"
|
||||||
|
urlpatterns = [
|
||||||
|
path("", views.index, name="accounts.index"),
|
||||||
|
path("register/", views.register, name="register"),
|
||||||
|
path("login/", views.login_user, name="login"),
|
||||||
|
path("success/", views.success_page, name="success_page"),
|
||||||
|
# path("accounts/login/", default_login_url, name="accounts.default_login_url"),
|
||||||
|
]
|
|
@ -1,3 +1,165 @@
|
||||||
from django.shortcuts import render
|
# Copyright © 2022 Alan Alexander Thomas <alan2000alex@gmail.com>
|
||||||
|
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
|
#
|
||||||
|
# License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from audioop import reverse
|
||||||
|
from multiprocessing import get_context
|
||||||
|
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
|
from re import template
|
||||||
|
from urllib import response
|
||||||
|
from django.shortcuts import render, redirect, get_object_or_404
|
||||||
|
from django.contrib.auth.password_validation import validate_password
|
||||||
|
from django.contrib.auth import authenticate, login, logout, get_user_model
|
||||||
|
from django.http import HttpResponse, HttpResponseRedirect
|
||||||
|
from django.views.decorators.csrf import csrf_protect
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django.contrib import messages
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
|
# Create your views here.
|
||||||
|
from django.http import HttpResponse
|
||||||
|
|
||||||
|
|
||||||
|
def index(request):
|
||||||
|
return HttpResponse("Hello World.")
|
||||||
|
|
||||||
|
|
||||||
|
# @csrf_protect
|
||||||
|
# def login(request):
|
||||||
|
# return render(request, 'accounts/login.html')
|
||||||
|
|
||||||
|
|
||||||
|
# login page
|
||||||
|
@csrf_protect
|
||||||
|
def login_user(request):
|
||||||
|
def default_login_ctx():
|
||||||
|
return {
|
||||||
|
"title": "Login",
|
||||||
|
"footer": footer_ctx(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if request.method == "POST":
|
||||||
|
email = request.POST["email"]
|
||||||
|
password = request.POST["password"]
|
||||||
|
# domain_check = email.split("@")
|
||||||
|
# check user exists
|
||||||
|
User = get_user_model()
|
||||||
|
|
||||||
|
if not User.objects.filter(email=email).exists():
|
||||||
|
messages.info(request, "Username OR password is incorrect")
|
||||||
|
return redirect(reverse("accounts:login"))
|
||||||
|
|
||||||
|
username = User.objects.get(email=email).username
|
||||||
|
user = authenticate(request, username=username, password=password)
|
||||||
|
|
||||||
|
if user is not None:
|
||||||
|
login(request, user)
|
||||||
|
# Redirect to a success page.
|
||||||
|
print(reverse("accounts:success_page"))
|
||||||
|
if "next" in request.POST:
|
||||||
|
next = request.POST["next"]
|
||||||
|
if len(next) > 0:
|
||||||
|
return redirect(next)
|
||||||
|
return redirect(reverse("accounts:success_page"))
|
||||||
|
else:
|
||||||
|
# Return an 'invalid login' error message.
|
||||||
|
messages.info(request, "Username OR password is incorrect")
|
||||||
|
return redirect(reverse("accounts:login"))
|
||||||
|
else:
|
||||||
|
context = {}
|
||||||
|
if "next" in request.GET:
|
||||||
|
next = request.GET["next"]
|
||||||
|
context["next"] = next
|
||||||
|
return render(request, "accounts/login.html", context=context)
|
||||||
|
|
||||||
|
|
||||||
|
# success page
|
||||||
|
@login_required(login_url="/accounts/login/")
|
||||||
|
@csrf_protect
|
||||||
|
def success_page(request):
|
||||||
|
return render(request, "accounts/success.html")
|
||||||
|
|
||||||
|
|
||||||
|
# user registratoin
|
||||||
|
|
||||||
|
|
||||||
|
@csrf_protect
|
||||||
|
def register(request):
|
||||||
|
# response = "You are at the Registration Page."
|
||||||
|
get_context = {}
|
||||||
|
if request.method == "GET":
|
||||||
|
if "next" in request.GET:
|
||||||
|
get_context["next"] = request.GET["next"]
|
||||||
|
return render(request, "accounts/register.html", get_context)
|
||||||
|
|
||||||
|
context = {}
|
||||||
|
|
||||||
|
# variables
|
||||||
|
email = request.POST["email"]
|
||||||
|
password = request.POST["password"]
|
||||||
|
password_confirm = request.POST["password-confirm"]
|
||||||
|
|
||||||
|
# password matching
|
||||||
|
if password != password_confirm:
|
||||||
|
context["error"] = {
|
||||||
|
"title": "Registration Failed",
|
||||||
|
"reason": "Passwords do not match.",
|
||||||
|
}
|
||||||
|
return render(request, "accounts/register.html", status=400, context=context)
|
||||||
|
|
||||||
|
# domain verification
|
||||||
|
domain_check = email.split("@")
|
||||||
|
if domain_check[1] != "vitap.ac.in":
|
||||||
|
context["error"] = {
|
||||||
|
"title": "Registration Failed",
|
||||||
|
"reason": "We do not provide services for this domain yet.",
|
||||||
|
}
|
||||||
|
return render(request, "accounts/register.html", status=400, context=context)
|
||||||
|
|
||||||
|
# email verification
|
||||||
|
User = get_user_model()
|
||||||
|
if any(
|
||||||
|
[
|
||||||
|
User.objects.filter(email=email).exists(),
|
||||||
|
User.objects.filter(username=domain_check[0]).exists(),
|
||||||
|
]
|
||||||
|
):
|
||||||
|
context["error"] = {
|
||||||
|
"title": "Registration Failed",
|
||||||
|
"reason": "This email is already registered.",
|
||||||
|
}
|
||||||
|
return render(request, "accounts/register.html", status=400, context=context)
|
||||||
|
|
||||||
|
user = get_user_model()(
|
||||||
|
username=domain_check[0],
|
||||||
|
email=email,
|
||||||
|
)
|
||||||
|
user.set_password(password)
|
||||||
|
|
||||||
|
try:
|
||||||
|
user.full_clean()
|
||||||
|
validate_password(password, user=user)
|
||||||
|
except ValidationError as err:
|
||||||
|
reason = ""
|
||||||
|
for errors in err:
|
||||||
|
reason += errors + " "
|
||||||
|
context["error"] = {"title": "Registration Failed", "reason": reason}
|
||||||
|
print(reason)
|
||||||
|
return render(request, "accounts/register.html", status=400, context=context)
|
||||||
|
|
||||||
|
user.save()
|
||||||
|
return HttpResponse("New acc. can be registered.")
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
version: "3.3"
|
||||||
|
|
||||||
|
services:
|
||||||
|
# db:
|
||||||
|
# image: postgres
|
||||||
|
# volumes:
|
||||||
|
# - ./data/db:/var/lib/postgresql/data
|
||||||
|
# environment:
|
||||||
|
# - POSTGRES_DB=postgres
|
||||||
|
# - POSTGRES_USER=postgres
|
||||||
|
# - POSTGRES_PASSWORD=postgres
|
||||||
|
web:
|
||||||
|
# build: .
|
||||||
|
image: realaravinth/mystiq-sso:latest
|
||||||
|
restart: always
|
||||||
|
command: >
|
||||||
|
sh -c "python manage.py makemigrations &&
|
||||||
|
python manage.py migrate &&
|
||||||
|
python manage.py runserver 0.0.0.0:8000"
|
||||||
|
volumes:
|
||||||
|
- ./sso/local_settings:/code/sso/local_settings/
|
||||||
|
ports:
|
||||||
|
- 8000:8000
|
||||||
|
# environment:
|
||||||
|
# - POSTGRES_NAME=postgres
|
||||||
|
# - POSTGRES_USER=postgres
|
||||||
|
# - POSTGRES_PASSWORD=postgres
|
||||||
|
# depends_on:
|
||||||
|
# - db
|
|
@ -29,6 +29,7 @@ pylint==2.14.5
|
||||||
pynvim==0.4.3
|
pynvim==0.4.3
|
||||||
requests==2.28.1
|
requests==2.28.1
|
||||||
sqlparse==0.4.2
|
sqlparse==0.4.2
|
||||||
|
tblib==1.7.0
|
||||||
tomli==2.0.1
|
tomli==2.0.1
|
||||||
tomlkit==0.11.4
|
tomlkit==0.11.4
|
||||||
urllib3==1.26.11
|
urllib3==1.26.11
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
"""
|
||||||
|
Django settings for dashboard project.
|
||||||
|
|
||||||
|
Generated by 'django-admin startproject' using Django 4.0.3.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/4.0/topics/settings/
|
||||||
|
|
||||||
|
For the full list of settings and their values, see
|
||||||
|
https://docs.djangoproject.com/en/4.0/ref/settings/
|
||||||
|
"""
|
||||||
|
import environ
|
||||||
|
import os
|
||||||
|
|
||||||
|
env = environ.Env()
|
||||||
|
|
||||||
|
# Quick-start development settings - unsuitable for production
|
||||||
|
# See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/
|
||||||
|
|
||||||
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
|
# A new SECRET_KEY can be generated by running the following command:
|
||||||
|
# openssl rand -hex 32
|
||||||
|
SECRET_KEY = "django-insecure-44zt@)$td7_yh(01q^hrce%h(311n!djn%%#s1b7$cvfy!pf7y"
|
||||||
|
|
||||||
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
|
DEBUG = True
|
||||||
|
|
||||||
|
ALLOWED_HOSTS = []
|
||||||
|
|
||||||
|
print("Finished importing local_settings.ci.py")
|
|
@ -135,3 +135,11 @@ OAUTH2_PROVIDER = {
|
||||||
"openid": "OpenID Connect scope",
|
"openid": "OpenID Connect scope",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
from .local_settings.local_settings import *
|
||||||
|
|
||||||
|
print("Found local_settings")
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
print("No local_settings available, using defaults")
|
||||||
|
pass
|
||||||
|
|
|
@ -19,4 +19,5 @@ from django.urls import path, include
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("admin/", admin.site.urls),
|
path("admin/", admin.site.urls),
|
||||||
path("o/", include("oauth2_provider.urls", namespace="oauth2_provider")),
|
path("o/", include("oauth2_provider.urls", namespace="oauth2_provider")),
|
||||||
|
path("accounts/", include("accounts.urls")),
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in New Issue