diff --git a/consent_provider/app.py b/consent_provider/app.py index b05d403a983084a0170b4beadfc23cb534041c52..b4df17ce681cdf8dd63e5a61672a5932c694f716 100644 --- a/consent_provider/app.py +++ b/consent_provider/app.py @@ -61,12 +61,12 @@ class ConsentView(View): session = { "access_token": {}, "id_token": { - "sub": "248289761001", - "name": "Jane Doe", - "given_name": "Jane", - "family_name": "Doe", - "preferred_username": "j.doe", - "email": "janedoe@example.com", + "sub": "248289761004", + "name": "Example User", + "given_name": "Example", + "family_name": "User", + "preferred_username": "example", + "email": "example@oas.example.com", "picture": "", }, } diff --git a/login_provider/app.py b/login_provider/app.py index 5b24a3a4379020490e060969a25344fcfbf936b4..35f7d8deca3682b269e071ce9769232291c5b6cc 100644 --- a/login_provider/app.py +++ b/login_provider/app.py @@ -4,93 +4,66 @@ from flask.views import View from flask_wtf import FlaskForm from flask_wtf.csrf import CSRFProtect from os import urandom -from wtforms import ( - BooleanField, - HiddenField, - PasswordField, - SelectMultipleField, - StringField, - SubmitField, -) -from wtforms.validators import DataRequired from hydra_client import HydraAdmin - -HYDRA_ADMIN_URL = "http://127.0.0.1:4445" - - -class DataRequiredIf(DataRequired): - field_flags = ("optional",) - - def __init__(self, check_field, *args, **kwargs): - self.check_field = check_field - super().__init__(*args, **kwargs) - - def __call__(self, form, field): - check_field = form._fields.get(self.check_field) - if check_field is None: - raise RuntimeError(f"No field called '{self.check_field}'") - if check_field.data: - super().__call__(form, field) - - - -class LoginForm(FlaskForm): - login = SubmitField("login") - abort = SubmitField("abort") - user = StringField("user", validators=[DataRequiredIf("login")]) - password = PasswordField("password", validators=[DataRequiredIf("login")]) - remember = BooleanField("remember") - challenge = HiddenField("challenge", validators=[DataRequired()]) +from flask_sqlalchemy import SQLAlchemy +from flask_security import Security, SQLAlchemyUserDatastore, \ + UserMixin, RoleMixin, login_required, current_user -class LoginView(View): - methods = "GET", "POST" - def render_form(self, form, **context): - return render_template("login.html", form=form, **context) - - def dispatch_request(self): - form = LoginForm() - hydra = HydraAdmin(HYDRA_ADMIN_URL) - - challenge = request.args.get("login_challenge") or form.challenge.data - if not challenge: - abort(400) - - login_request = hydra.login_request(challenge) - if request.method == "GET": - return self.get(login_request, form, challenge) - elif request.method == "POST": - return self.post(login_request, form, challenge) - abort(405) - - def get(self, login_request, form, challenge): - if login_request.skip: - redirect_to = login_request.accept(subject=login_request.subject) - return redirect(redirect_to) - else: - form.challenge.data = challenge - return self.render_form(form) - - def post(self, login_request, form, challenge): - if form.validate(): - if form.login.data: - if form.user.data == "foo@bar.com" and form.password.data == "password": - subject = form.user.data - print(str(form.remember.data)) - redirect_to = login_request.accept( - subject=subject, remember=form.remember.data - ) - else: - # TODO: show error message - return self.render_form(form) - else: - redirect_to = login_request.reject(error="user_decline") - return redirect(redirect_to) - return self.render_form(form) +HYDRA_ADMIN_URL = "http://127.0.0.1:4445" app = Flask(__name__) app.secret_key = urandom(16) +app.config['DEBUG'] = True +app.config['SECRET_KEY'] = 'super-secret' +app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite://' +app.config["SECURITY_PASSWORD_SALT"] = "SuPeRrAnDoMpAsSwOrD" + +db = SQLAlchemy(app) + +# Define models +roles_users = db.Table('roles_users', + db.Column('user_id', db.Integer(), db.ForeignKey('user.id')), + db.Column('role_id', db.Integer(), db.ForeignKey('role.id'))) + +class Role(db.Model, RoleMixin): + id = db.Column(db.Integer(), primary_key=True) + name = db.Column(db.String(80), unique=True) + description = db.Column(db.String(255)) + +class User(db.Model, UserMixin): + id = db.Column(db.Integer, primary_key=True) + email = db.Column(db.String(255), unique=True) + password = db.Column(db.String(255)) + active = db.Column(db.Boolean()) + confirmed_at = db.Column(db.DateTime()) + roles = db.relationship('Role', secondary=roles_users, + backref=db.backref('users', lazy='dynamic')) + +# Setup Flask-Security +user_datastore = SQLAlchemyUserDatastore(db, User, Role) +security = Security(app, user_datastore) + +# Create a user to test with +@app.before_first_request +def create_user(): + db.create_all() + user_datastore.create_user(email='example@oas.example.com', password='password') + db.session.commit() + csrf = CSRFProtect(app) -app.add_url_rule("/login", view_func=LoginView.as_view("login")) + +@app.route('/') +@login_required +def home(): + hydra = HydraAdmin(HYDRA_ADMIN_URL) + challenge = request.args.get("login_challenge") + if not challenge: + print("nope") + abort(400) + print(challenge) + login_request = hydra.login_request(challenge) + redirect_to = login_request.accept(current_user.email) + return redirect(redirect_to) diff --git a/login_provider/requirements.txt b/login_provider/requirements.txt index 128d32e76b068d0d305215a9955361a7a7fc9e31..f52068f8041a2f172108acb798140727badd5bf6 100644 --- a/login_provider/requirements.txt +++ b/login_provider/requirements.txt @@ -1,3 +1,5 @@ Flask==1.1.1 flask-wtf==0.14.2 hydra-client==0.4.0 +Flask-Security==3.0.0 +Flask-SQLAlchemy==2.4.0