Skip to content

Commit

Permalink
Add OIDC support & Flask 2.3+ fix (#35)
Browse files Browse the repository at this point in the history
Add OIDC support & Flask 2.3+ fix
  • Loading branch information
burritosoftware authored Jun 25, 2024
1 parent 82c8e60 commit c407e44
Show file tree
Hide file tree
Showing 14 changed files with 77 additions and 181 deletions.
15 changes: 15 additions & 0 deletions config-example.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,18 @@
# EULA text, presented upon first launch of channel.
# You may wish to change this to read from a file.
eula_text = "Default terms and conditions."

# OpenID Connect configuration
oidc_redirect_uri = "http://localhost:8080/authorize"
oidc_client_secrets_json = {
"web": {
"client_id": "",
"client_secret": "",
"auth_uri": "",
"token_uri": "",
"userinfo_uri": "",
"issuer": "",
"redirect_uris": [oidc_redirect_uri],
}
}
oidc_logout_url = ""
13 changes: 6 additions & 7 deletions food.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from werkzeug import exceptions
from werkzeug.datastructures import ImmutableMultiDict

from models import db, login
from models import db

import config

Expand All @@ -24,19 +24,18 @@
app.config["SQLALCHEMY_DATABASE_URI"] = config.db_url
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config["SECRET_KEY"] = config.secret_key
app.config["OIDC_CLIENT_SECRETS"] = config.oidc_client_secrets_json
app.config["OIDC_SCOPES"] = "openid profile"
app.config["OIDC_OVERWRITE_REDIRECT_URI"] = config.oidc_redirect_uri

# Ensure DB tables are created.
db.init_app(app)

# Ensure we're handling login.
login.init_app(app)

# Ensure the DB is able to determine migration needs.
migrate = Migrate(app, db, compare_type=True)


@app.before_first_request
def initialize_server():
with app.app_context():
# Ensure our database is present.
db.create_all()

Expand Down Expand Up @@ -64,7 +63,7 @@ def initialize_server():
"webApi_order_done": responses.order_done,
"webApi_inquiry_done": responses.inquiry_done,
"webApi_basket_delete": responses.basket_delete,
"webApi_basket_modify": responses.basket_modify
"webApi_basket_modify": responses.basket_modify,
}


Expand Down
35 changes: 0 additions & 35 deletions models.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,9 @@
import enum

from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.event import listens_for
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin, LoginManager
import sqlalchemy, json

db = SQLAlchemy()
login = LoginManager()


@login.user_loader
def load_user(id):
return User.query.get(int(id))


class DictType(sqlalchemy.types.TypeDecorator):
Expand Down Expand Up @@ -88,29 +79,3 @@ class UserOrders(db.Model):
zip_code = db.Column(db.String, primary_key=True, nullable=False)
auth_key = db.Column(db.String)
basket = db.Column(DictType, nullable=False)


class User(db.Model, UserMixin):
# Used to login to the Admin Panel
id = db.Column(db.Integer, primary_key=True, default=1)
username = db.Column(db.String(100))
password_hash = db.Column(db.String)

def set_password(self, password):
self.password_hash = generate_password_hash(password)

def check_password(self, password):
return check_password_hash(self.password_hash, password)


@listens_for(User.__table__, "after_create")
def create_default_user(target, connection, **kw):
"""Adds a default user to The Pantry.
By default, we assume admin:admin."""
table = User.__table__
connection.execute(
table.insert().values(
username="admin",
password_hash=generate_password_hash("admin"),
)
)
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Flask>=2.2
flask-login>=0.6.3
flask-oidc>=2.2.0
flask-wtf>=1.0.1
lxml>=4.9.1
pillow>=9.2
Expand Down
19 changes: 9 additions & 10 deletions responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,8 +351,7 @@ def shop_one(request):
},
},
# Setting values to null will trigger the confirmation screen
"selList": {
},
"selList": {},
"holiday": "We're on holiday. Back soon!",
"status": {
"isOpen": 1,
Expand Down Expand Up @@ -500,14 +499,14 @@ def category_list(request):
return {
"response": {
"Pizza": formulate_restaurant(CategoryTypes.Pizza),
# "Bento": formulate_restaurant(CategoryTypes.Bento_Box),
# "Sushi": formulate_restaurant(CategoryTypes.Sushi),
# "Fish": formulate_restaurant(CategoryTypes.Fish),
#"Seafood": formulate_restaurant(CategoryTypes.Seafood),
#"American": formulate_restaurant(CategoryTypes.Western),
#"Fast": formulate_restaurant(CategoryTypes.Fast_Food),
#"Indian": formulate_restaurant(CategoryTypes.Curry),
#"Party": formulate_restaurant(CategoryTypes.Party_Food),
# "Bento": formulate_restaurant(CategoryTypes.Bento_Box),
# "Sushi": formulate_restaurant(CategoryTypes.Sushi),
# "Fish": formulate_restaurant(CategoryTypes.Fish),
# "Seafood": formulate_restaurant(CategoryTypes.Seafood),
# "American": formulate_restaurant(CategoryTypes.Western),
# "Fast": formulate_restaurant(CategoryTypes.Fast_Food),
# "Indian": formulate_restaurant(CategoryTypes.Curry),
# "Party": formulate_restaurant(CategoryTypes.Party_Food),
"Drinks": formulate_restaurant(CategoryTypes.Others),
"Other": formulate_restaurant(CategoryTypes.Test),
"Placeholder": formulate_restaurant(CategoryTypes.Others),
Expand Down
3 changes: 1 addition & 2 deletions templates/includes/sidebar.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
{% endmacro %}

<aside class="menu">
{% if current_user.is_authenticated %}
{% if g.oidc_user.logged_in %}
<p class="menu-label">
General
</p>
Expand All @@ -21,7 +21,6 @@
<p class="menu-label">
Account
</p>
{{ menu_item('Change Password', 'change_password', 'fa-key') }}
<ul class="menu-list">
<li><a href="{{ url_for('logout') }}"><i class="fas fa-sign-out-alt" style="margin-right: .75em; width: 1em; height: 1em;"></i>Logout</a></li>
</ul>
Expand Down
19 changes: 6 additions & 13 deletions templates/login.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,10 @@
{% endblock %}

{% block content %}
<form action="" method="post">
<p>
{{ form.hidden_tag() }}
{{ form.username.label(class_="label") }}
{{ form.username(size=32, class_="input") }}
<br>
<br>
{{ form.password.label(class_="label") }}
{{ form.password(size=32, class_="input") }}
</p>
<br>
<p>{{ form.submit(class_="button is-link") }}</p>
</form>
<h1 class="title">Click below to enter the pantry.</h1>
<p class="buttons" style="display: block">
<a href="{{ url_for('admin') }}">
<button class="button is-link">Login with WiiLink Internal</button>
</a>
</p>
{% endblock %}
6 changes: 1 addition & 5 deletions templates/pantry.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,12 @@
{% endblock %}

{% block content %}
<h1 class="title">Welcome, {{ current_user.username }}.</h1>
<h1 class="title">Welcome, {{ g.oidc_user.profile.name }}.</h1>
<h2 class="subtitle">Click on an operation below to get started:</h2>
<a href="{{ url_for('select_food_type') }}">
<button>Manage Resturants</button>
</a>
<br/>
<a href="{{ url_for('change_password') }}">
<button>Change Password</button>
</a>
<br/>
<br/>
<a href="{{ url_for('logout') }}">
<button>Logout</button>
Expand Down
25 changes: 0 additions & 25 deletions templates/user_pwchange.html

This file was deleted.

58 changes: 18 additions & 40 deletions thepantry/admin.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from food import app, db
from food import app
from flask import render_template, send_from_directory, redirect, url_for, flash
from flask_login import current_user, login_user, login_required, logout_user
from models import User
from thepantry.forms import LoginForm, ChangePasswordForm
from flask_oidc import OpenIDConnect

import config

@app.login_manager.unauthorized_handler
def unauthorized():
return redirect(url_for("root"))
oidc = OpenIDConnect(app)


@app.context_processor
def inject_oidc():
return dict(oidc=oidc)


@app.route("/thepantry")
Expand All @@ -16,51 +18,27 @@ def root():
return redirect(url_for("login"))


@app.route("/thepantry/login", methods=["GET", "POST"])
@app.route("/thepantry/login")
def login():
if current_user.is_authenticated:
if oidc.user_loggedin:
return redirect(url_for("admin"))

form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(username=form.username.data).first()
if user is None or not user.check_password(form.password.data):
flash("Invalid username or password")
else:
login_user(user, remember=False)
return redirect(url_for("admin"))

return render_template("login.html", form=form)
return render_template("login.html")


@app.route("/thepantry/admin")
@login_required
@oidc.require_login
def admin():
return render_template("pantry.html")


@app.route("/thepantry/change_password", methods=["GET", "POST"])
@login_required
def change_password():
form = ChangePasswordForm()
if form.validate_on_submit():
print(type(current_user))
u = User.query.filter_by(username=current_user.username).first()
u.set_password(form.new_password.data)
db.session.add(u)
db.session.commit()
return redirect(url_for("admin"))

return render_template(
"user_pwchange.html", form=form, username=current_user.username
)


@app.route("/thepantry/logout")
@login_required
@oidc.require_login
def logout():
logout_user()
return redirect(url_for("login"))
oidc.logout()
response = redirect(config.oidc_logout_url)
response.set_cookie("session", expires=0)
return response


@app.route("/thepantry/common.css")
Expand Down
27 changes: 2 additions & 25 deletions thepantry/forms.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,9 @@
from flask_wtf import FlaskForm
from wtforms.validators import DataRequired, ValidationError
from wtforms import StringField, PasswordField, SubmitField, SelectField, FileField
from wtforms.validators import DataRequired
from wtforms import StringField, SubmitField, SelectField, FileField
from models import CategoryTypes


class LoginForm(FlaskForm):
username = StringField("Username")
password = PasswordField("Password")
submit = SubmitField("Enter the pantry")


class ChangePasswordForm(FlaskForm):
current_password = PasswordField("Password", validators=[DataRequired()])
new_password = PasswordField("New Password", validators=[DataRequired()])
new_password_confirmation = PasswordField(
"Confirm New Password", validators=[DataRequired()]
)
complete = SubmitField("Complete")

def validate_current_password(self, _):
if self.current_password.data == self.new_password.data:
return ValidationError("New password cannot be the same as current!")

def validate_new_password(self, _):
if self.new_password.data != self.new_password_confirmation.data:
return ValidationError("New passwords must be the same")


class FoodTypes(FlaskForm):
food = SelectField(
"Food Types",
Expand Down
Loading

0 comments on commit c407e44

Please sign in to comment.