Skip to content

Commit

Permalink
Add image for securedev training
Browse files Browse the repository at this point in the history
  • Loading branch information
pyaillet committed Aug 23, 2024
1 parent 89f85f8 commit eb30c0b
Show file tree
Hide file tree
Showing 121 changed files with 40,334 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.PHONY: build-all push-all
images=k8s-training-tools k8s-training-stress
images=k8s-training-tools k8s-training-stress securedev-training-curlbot

build-all:
for image in $(images) ; do \
Expand Down
36 changes: 36 additions & 0 deletions securedev-training-curlbot/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
FROM node
MAINTAINER Thomas FADY <[email protected]>

ADD front/app /app
WORKDIR /app
RUN npm install && npm install --only=dev
ENV NODE_OPTIONS --openssl-legacy-provider
RUN npm run build


FROM python:3.11-alpine
MAINTAINER Thomas FADY <[email protected]>

RUN echo "http://dl-4.alpinelinux.org/alpine/v3.14/main" >> /etc/apk/repositories && \
echo "http://dl-4.alpinelinux.org/alpine/v3.14/community" >> /etc/apk/repositories

# install chromedriver
RUN apk update
RUN apk add chromium chromium-chromedriver curl bash

# upgrade pip
RUN pip install --upgrade pip

RUN pip install pipenv

RUN adduser --gecos "" --disabled-password simpleuser
WORKDIR /home/simpleuser
COPY --chown=simpleuser Pipfile Pipfile.lock ./
USER simpleuser
RUN pipenv install
COPY --chown=simpleuser curlbot curlbot
WORKDIR /home/simpleuser/curlbot
RUN export SECRET_KEY=testing ; pipenv run pytest ; for file in $(find -name "test_*.py"); do echo "Delete $file";rm $file; done && for file in $(find -name "*.db"); do echo "Delete $file";rm $file; done
COPY --from=0 /app/dist /home/simpleuser/curlbot/app/front-app
EXPOSE 5000
ENTRYPOINT export SECRET_KEY=$(head /dev/urandom| md5sum | cut -d ' ' -f1) && pipenv run gunicorn -b :5000 run:app -w 4
24 changes: 24 additions & 0 deletions securedev-training-curlbot/Pipfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true

[dev-packages]

[packages]
flask = "*"
flask-sqlalchemy = "*"
pytest = "*"
pytest-flask = "*"
flask-login = "*"
pylint = "*"
pylint-flask = "*"
names = "*"
gunicorn = "*"
faker = "*"
flask-mail = "*"
pyjwt = "*"
selenium = "*"

[requires]
python_version = "3.11"
672 changes: 672 additions & 0 deletions securedev-training-curlbot/Pipfile.lock

Large diffs are not rendered by default.

83 changes: 83 additions & 0 deletions securedev-training-curlbot/curlbot/app/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
from flask import Flask, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
from flask_mail import Mail
from os import getenv
import os
import importlib

db = SQLAlchemy()
login_manager = LoginManager()
mail = Mail()

def create_app(challenge="default"):
global mail, db, login_manager
app = Flask(__name__)

app.config['MAIL_SERVER'] = getenv('MAIL_SERVER', 'localhost')
app.config['MAIL_PORT'] = getenv('MAIL_PORT', 1025)
app.config['MAIL_USERNAME'] = getenv('MAIL_USERNAME', '')
app.config['MAIL_PASSWORD'] = getenv('MAIL_PASSWORD', '')
app.config['MAIL_USE_TLS'] = getenv('MAIL_USE_TLS', False)
app.config['MAIL_USE_SSL'] = getenv('MAIL_USE_SSL', False)
app.config['CHALLENGE'] = getenv("CHALLENGE", challenge)
app.config['UPLOAD_DIR'] = os.path.join(os.path.dirname(os.path.realpath(__file__)), "profiles")
if getenv('SECRET_KEY', '') == 'testing':
app.config['MAIL_SUPPRESS_SEND'] = True
mail.init_app(app)

app.config.from_object('config')

db.init_app(app)

login_manager.init_app(app)

from app.account.views import profile, auth
app.register_blueprint(profile.profile_blueprint, url_prefix='/api/v1/user')
app.register_blueprint(auth.auth_blueprint, url_prefix='/api/v1/auth')

from app.main.views import main, root
app.register_blueprint(main.main_blueprint, url_prefix='/api/v1/')
app.register_blueprint(root.root_blueprint, url_prefix='/')

from app.robots.views import robots
app.register_blueprint(robots.robots_blueprint, url_prefix='/api/v1/')

@app.errorhandler(404)
def not_found(error):
return jsonify(status="error",message="Page not found"), 404

@app.errorhandler(500)
def not_found(error):
return jsonify(status="error",message="Internal Server Error"), 500

challenge = importlib.import_module('app.challenge.'+app.config['CHALLENGE'])

with app.app_context():
challenge.load(app)
db.create_all()
db_seed()
challenge.seed(app)

return app

def db_seed():
from faker import Faker
from app.account.models import User
from app.robots.models import Robot
from names import get_full_name
from app.utils import get_random_string
fake = Faker()
if len(User.query.filter_by(admin=True).all()) == 0:
admin_user = User.insert_admin(fake.simple_profile()['username'],get_random_string())
for i in range(10):
name = get_full_name()
description = name+" is a dummy curl bot."
Robot(name=name,description=description,url=fake.url(),credentials="",owner_id=admin_user.id).save()
for u in range(10):
user = User.insert_user(fake.simple_profile()['username'],get_random_string())
for i in range(10):
name = get_full_name()
description = name+" is a dummy curl bot."
Robot(name=name,description=description,url=fake.url(),credentials="",owner_id=user.id).save()

1 change: 1 addition & 0 deletions securedev-training-curlbot/curlbot/app/account/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import views
63 changes: 63 additions & 0 deletions securedev-training-curlbot/curlbot/app/account/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from app import db, login_manager
from flask_login import UserMixin
from werkzeug.security import generate_password_hash, check_password_hash

class User(db.Model, UserMixin):
__tablename__ = 'users'

id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(32), index=True)
password_hash = db.Column(db.String(128))
admin = db.Column(db.Boolean(),default=False)
reset_token = db.Column(db.String(128))
avatar = db.Column(db.String(128), default="avatar.png")

robots = db.relationship('Robot', backref='owner', lazy='dynamic')

def set_password(self, password):
self.password_hash = generate_password_hash(password,'pbkdf2:sha256:1')

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

def is_admin(self):
return self.admin == True

@classmethod
def insert_user(cls, username, password):
user = User(
username=username,
admin=False,
)
user.set_password(password)
db.session.add(user)
db.session.commit()
db.session.refresh(user)
return user
@classmethod
def insert_admin(cls, username, password):
admin = User(
username=username,
admin=True,
)
admin.set_password(password)
db.session.add(admin)
db.session.commit()
db.session.refresh(admin)
return admin

@login_manager.user_loader
def load_user(user_id):
""" User loader function
Registered within Flask-Login
"""
try:
user_id = int(user_id)
except ValueError:
print("Could not convert data to an integer.")
return None
except:
print("Unkown error when loading the user")
return None
return User.query.get(user_id)
96 changes: 96 additions & 0 deletions securedev-training-curlbot/curlbot/app/account/test_account.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import pytest
from .models import User
from app import create_app ,db, mail
import os, json

mimetype = 'application/json'
headers = {
'Content-Type': mimetype,
'Accept': mimetype
}

@pytest.fixture
def app():
app = create_app()
app.config.update({
"TESTING": True,
})

yield app

@pytest.fixture()
def client(app):
return app.test_client()

def setup_function():
app = create_app()
with app.app_context():
db.session.commit()
db.drop_all()
db.create_all()

def teardown_function():
os.remove('app.db')

class TestUserClass:
@classmethod
def setup_class(self):
setup_function()

@classmethod
def teardown_class(self):
teardown_function()

def post_json(self,client, url ,data):
return client.post(url, data=json.dumps(data), headers=headers)

def test_user_is_not_admin(self):
user = User(username="test")
assert user.is_admin() == False

def test_admin_is_admin(self, app):
user = User.insert_admin("test","test")
assert user.is_admin() == True

def test_bad_user_login(self,client):
User.insert_admin("admin","toto")
login_request = client.post("/api/v1/auth/login", data=json.dumps({"login": "a", "password": "a"}), headers=headers)
assert login_request.status_code == 401
assert login_request.json == {'message': 'Wrong credentials', 'status': 'error'}
login_request = client.post("/api/v1/auth/login", data=json.dumps({"login": "admin", "password": "a"}), headers=headers)
assert login_request.status_code == 401
assert login_request.json == {'message': 'Wrong credentials', 'status': 'error'}
assert client.get("/api/v1/user/profile").status_code == 401

def test_bad_good_login_and_logout(self,client, app):
User.insert_user("toto","toto")
login_request = client.post("/api/v1/auth/login", data=json.dumps({"login": "toto", "password": "toto"}), headers=headers)
assert login_request.status_code == 200
assert login_request.json['status'] == "success"
login = client.get("/api/v1/user/profile")
assert login.status_code == 200
assert login.json['login'] == "toto"
assert login.json['is_admin'] == False
assert client.get("/api/v1/auth/logout").status_code == 200
assert client.get("/api/v1/user/profile").status_code == 401

def test_user_can_register(self,client):
assert client.post("/api/v1/auth/register", data=json.dumps({"login": "test_register_user", "password": "test_register_user"}), headers=headers).status_code == 200
login_request = client.post("/api/v1/auth/login", data=json.dumps({"login": "test_register_user", "password": "test_register_user"}), headers=headers)
assert login_request.status_code == 200
assert login_request.json['status'] == "success"
login = client.get("/api/v1/user/profile")
assert login.status_code == 200
assert login.json['login'] == "test_register_user"
assert User.query.filter_by(username="test_register_user").first().is_admin() == False

def test_user_can_reset(self, client):
client.post("/api/v1/auth/register", data=json.dumps({"login": "test_reset_user", "password": "test_reset_user"}), headers=headers)
res = client.post("/api/v1/auth/reset", data=json.dumps({"login": "test_reset_user"}), headers=headers).json
reset_token = res['message'].split(': ')[1]
reset_request = client.post("/api/v1/auth/reset-password", data=json.dumps({"token": reset_token, "password": "newpassword"}), headers=headers)
assert reset_request.status_code == 200
reset_request = client.post("/api/v1/auth/reset-password", data=json.dumps({"token": reset_token, "password": "newpassword"}), headers=headers)
assert reset_request.status_code == 401
assert self.post_json(client,"/api/v1/auth/login",{"login": "test_reset_user", "password": "newpassword"}).json['status'] == "success"

Empty file.
Loading

0 comments on commit eb30c0b

Please sign in to comment.