Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion noggin/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from flask import Flask, Blueprint, request
from flask_babel import Babel
from flask_wtf.csrf import CSRFProtect
from flask_healthz import healthz
from flask_mail import Mail
from flask_wtf.csrf import CSRFProtect
from whitenoise import WhiteNoise

from noggin.security.ipa_admin import IPAAdmin
Expand Down Expand Up @@ -32,6 +33,7 @@
template_folder="themes/" + themename + "/templates/",
)
app.register_blueprint(blueprint)
app.register_blueprint(healthz, url_prefix="/healthz")

# Flask-Mail
mailer = Mail(app)
Expand Down
14 changes: 13 additions & 1 deletion noggin/controller/root.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from flask import render_template, request, redirect, url_for, session, jsonify
from flask_healthz import HealthError

from noggin import app
from noggin import app, ipa_admin
from noggin.form.register_user import RegisterUserForm
from noggin.form.login_user import LoginUserForm
from noggin.representation.group import Group
Expand Down Expand Up @@ -75,3 +76,14 @@ def search_json(ipa):
res.append({'cn': group_.name, 'description': group_.description})

return jsonify(res)


def liveness():
pass


def readiness():
try:
ipa_admin.ping()
except Exception:
raise HealthError("Can't connect to the FreeIPA Server")
7 changes: 6 additions & 1 deletion noggin/defaults.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,9 @@ HIDE_GROUPS_IN = "hidden_groups"
AVATAR_SERVICE_URL = "https://seccdn.libravatar.org/"
AVATAR_DEFAULT_TYPE = "robohash"

MAIL_DOMAIN_BLOCKLIST = ['fedoraproject.org']
MAIL_DOMAIN_BLOCKLIST = ['fedoraproject.org']

HEALTHZ = {
"live": "noggin.controller.root.liveness",
"ready": "noggin.controller.root.readiness",
}
1 change: 1 addition & 0 deletions noggin/security/ipa_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class IPAAdmin(object):
"stageuser_add",
"stageuser_show",
"stageuser_activate",
"ping",
)
__WRAPPED_METHODS_TESTING = (
"user_del",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
interactions:
- request:
body: user=admin&password=adminPassw0rd%21
headers:
Accept:
- text/plain
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
Content-Length:
- '36'
Content-Type:
- application/x-www-form-urlencoded
Referer:
- https://ipa.example.com/ipa/session/login_password
User-Agent:
- python-requests/2.23.0
method: POST
uri: https://ipa.example.com/ipa/session/login_password
response:
body:
string: !!binary |
H4sIAAAAAAAAAwMAAAAAAAAAAAA=
headers:
Cache-Control:
- no-cache, private
Connection:
- Keep-Alive
Content-Encoding:
- gzip
Content-Length:
- '20'
Content-Security-Policy:
- frame-ancestors 'none'
Content-Type:
- text/plain; charset=UTF-8
Date:
- Wed, 03 Jun 2020 11:41:01 GMT
Keep-Alive:
- timeout=30, max=100
Server:
- Apache/2.4.43 (Fedora) OpenSSL/1.1.1d mod_wsgi/4.6.6 Python/3.7 mod_auth_gssapi/1.6.1
Set-Cookie:
- ipa_session=MagBearerToken=NN8eWQkKxtS8Jv2YQzPJUTr5CCvzmFMiGoBXkyPuY%2fFpzPUj5aBFW%2fFidEABif1EHAfRlT6sylDuPfEQ5ld%2b6dgO%2fOk9pSqYOEysRjOlI1a1hz%2fMlprsOn6YUUmMDDdaJzHNJ9V2eX6RtBtjczy%2fpja9GtyclCSkZM2M9jh%2btDuy26yaZ3wwZiEEK9t59bm%2b;path=/ipa;httponly;secure;
Vary:
- Accept-Encoding
X-Frame-Options:
- DENY
status:
code: 200
message: Success
- request:
body: '{"method": "ping", "params": [[], {}]}'
headers:
Accept:
- application/json
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
Content-Length:
- '38'
Content-Type:
- application/json
Cookie:
- ipa_session=MagBearerToken=NN8eWQkKxtS8Jv2YQzPJUTr5CCvzmFMiGoBXkyPuY%2fFpzPUj5aBFW%2fFidEABif1EHAfRlT6sylDuPfEQ5ld%2b6dgO%2fOk9pSqYOEysRjOlI1a1hz%2fMlprsOn6YUUmMDDdaJzHNJ9V2eX6RtBtjczy%2fpja9GtyclCSkZM2M9jh%2btDuy26yaZ3wwZiEEK9t59bm%2b
Referer:
- https://ipa.example.com/ipa
User-Agent:
- python-requests/2.23.0
method: POST
uri: https://ipa.example.com/ipa/session/json
response:
body:
string: !!binary |
H4sIAAAAAAAAA0yQTWvDMAyG/4rxZZcQ+jHK2Glh9FBYWE5jMMZQYzcYYjtI9koI+e+TE7P2YJAl
Pa9eaZKoKfZBPotJUrQWcORYnppKkMZfjYIfGe/EY/lUHkpRNaf/1K7c7Q+yENJqIug0Mfo1yTAO
OolcAZ1xXWpwYJfUx0rWhihXMpqKSTo3CBftmYdfgYTzgb24UIiLR9ZUovV2gGDOpjdhXOpdBAQX
tFbskHgRVs8LPNC95+JmuvUqjd3uN5stfxUEWM+wYD8ZSMZWZJ6/Z+7TiB4562Lf89eoWzygca0Z
oE8QKDbxcvys6ubtWL6+12nmnehyTzn/AQAA//8DAOyF6AGCAQAA
headers:
Cache-Control:
- no-cache, private
Connection:
- Keep-Alive
Content-Encoding:
- gzip
Content-Security-Policy:
- frame-ancestors 'none'
Content-Type:
- application/json; charset=utf-8
Date:
- Wed, 03 Jun 2020 11:41:01 GMT
Keep-Alive:
- timeout=30, max=99
Server:
- Apache/2.4.43 (Fedora) OpenSSL/1.1.1d mod_wsgi/4.6.6 Python/3.7 mod_auth_gssapi/1.6.1
Transfer-Encoding:
- chunked
Vary:
- Accept-Encoding
X-Frame-Options:
- DENY
status:
code: 200
message: Success
- request:
body: '{"method": "ping", "params": [[], {}]}'
headers:
Accept:
- application/json
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
Content-Length:
- '38'
Content-Type:
- application/json
Cookie:
- ipa_session=MagBearerToken=NN8eWQkKxtS8Jv2YQzPJUTr5CCvzmFMiGoBXkyPuY%2fFpzPUj5aBFW%2fFidEABif1EHAfRlT6sylDuPfEQ5ld%2b6dgO%2fOk9pSqYOEysRjOlI1a1hz%2fMlprsOn6YUUmMDDdaJzHNJ9V2eX6RtBtjczy%2fpja9GtyclCSkZM2M9jh%2btDuy26yaZ3wwZiEEK9t59bm%2b
Referer:
- https://ipa.example.com/ipa
User-Agent:
- python-requests/2.23.0
method: POST
uri: https://ipa.example.com/ipa/session/json
response:
body:
string: !!binary |
H4sIAAAAAAAAA0yQTWvDMAyG/4rxZZcQ+jHK2Glh9FBYWE5jMMZQYzcYYjtI9koI+e+TE7P2YJAl
Pa9eaZKoKfZBPotJUrQWcORYnppKkMZfjYIfGe/EY/lUHkpRNaf/1K7c7Q+yENJqIug0Mfo1yTAO
OolcAZ1xXWpwYJfUx0rWhihXMpqKSTo3CBftmYdfgYTzgb24UIiLR9ZUovV2gGDOpjdhXOpdBAQX
tFbskHgRVs8LPNC95+JmuvUqjd3uN5stfxUEWM+wYD8ZSMZWZJ6/Z+7TiB4562Lf89eoWzygca0Z
oE8QKDbxcvys6ubtWL6+12nmnehyTzn/AQAA//8DAOyF6AGCAQAA
headers:
Cache-Control:
- no-cache, private
Connection:
- Keep-Alive
Content-Encoding:
- gzip
Content-Security-Policy:
- frame-ancestors 'none'
Content-Type:
- application/json; charset=utf-8
Date:
- Wed, 03 Jun 2020 11:41:01 GMT
Keep-Alive:
- timeout=30, max=98
Server:
- Apache/2.4.43 (Fedora) OpenSSL/1.1.1d mod_wsgi/4.6.6 Python/3.7 mod_auth_gssapi/1.6.1
Transfer-Encoding:
- chunked
Vary:
- Accept-Encoding
X-Frame-Options:
- DENY
status:
code: 200
message: Success
- request:
body: '{"method": "session_logout", "params": [[], {}]}'
headers:
Accept:
- application/json
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
Content-Length:
- '48'
Content-Type:
- application/json
Cookie:
- ipa_session=MagBearerToken=NN8eWQkKxtS8Jv2YQzPJUTr5CCvzmFMiGoBXkyPuY%2fFpzPUj5aBFW%2fFidEABif1EHAfRlT6sylDuPfEQ5ld%2b6dgO%2fOk9pSqYOEysRjOlI1a1hz%2fMlprsOn6YUUmMDDdaJzHNJ9V2eX6RtBtjczy%2fpja9GtyclCSkZM2M9jh%2btDuy26yaZ3wwZiEEK9t59bm%2b
Referer:
- https://ipa.example.com/ipa
User-Agent:
- python-requests/2.23.0
method: POST
uri: https://ipa.example.com/ipa/session/json
response:
body:
string: !!binary |
H4sIAAAAAAAAA0yPy2rDQAxFf0XMphtj8qKUrmpKFoWaZFUKpRTFo5oBe8ZI44Rg/O/V2AZ3p8e9
50qDYZK+ieYZhrX0fdNkYFoSwZpEJ1+DifeOtDI3ZO98bVTgsZ1GH8Tigi+dyLJZrGlZnN9gESi4
vRDDDQV8iCDkYwa/gZVpoQpth9FdXOPifdrXPTL6SGRzKET6Vulq4ivxg0ACX2dwBrt8t39MyVWw
KXa732y22lqMOD03234WQzpstozj96g6Yg68vu7sWnfsfOU6bJIJrR7xcvwsyvP7MX89lSnzH/SQ
P+UK/QMAAP//AwBCBmNsWAEAAA==
headers:
Cache-Control:
- no-cache, private
Connection:
- Keep-Alive
Content-Encoding:
- gzip
Content-Security-Policy:
- frame-ancestors 'none'
Content-Type:
- application/json; charset=utf-8
Date:
- Wed, 03 Jun 2020 11:41:01 GMT
Keep-Alive:
- timeout=30, max=97
Server:
- Apache/2.4.43 (Fedora) OpenSSL/1.1.1d mod_wsgi/4.6.6 Python/3.7 mod_auth_gssapi/1.6.1
Set-Cookie:
- ipa_session=;Max-Age=0;path=/ipa;httponly;secure;
Transfer-Encoding:
- chunked
Vary:
- Accept-Encoding
X-Frame-Options:
- DENY
status:
code: 200
message: Success
version: 1
27 changes: 27 additions & 0 deletions noggin/tests/unit/controller/test_root.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import pytest
from unittest import mock
from bs4 import BeautifulSoup


Expand Down Expand Up @@ -42,3 +43,29 @@ def test_search_json_empty(client, logged_in_dummy_user):
result = client.get('/search/json')
assert result.status_code == 200
assert result.json == []


@pytest.mark.vcr()
def test_healthz_liveness(client):
"""Test the /healthz/live check endpoint"""
result = client.get('/healthz/live')
assert result.status_code == 200
assert result.data == b'OK\n'


@pytest.mark.vcr()
def test_healthz_readiness_ok(client):
"""Test the /healthz/ready check endpoint"""
result = client.get('/healthz/ready')
assert result.status_code == 200
assert result.data == b'OK\n'


@pytest.mark.vcr()
def test_healthz_readiness_not_ok(client):
"""Test the /healthz/ready check endpoint when not ready (IPA disabled)"""
with mock.patch("noggin.ipa_admin.ping") as ipaping:
ipaping.side_effect = Exception()
result = client.get('/healthz/ready')
assert result.status_code == 503
assert result.data == b"Can't connect to the FreeIPA Server\n"
17 changes: 16 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ backoff = "^1.10.0"
noggin-messages = "^0.0.1"
whitenoise = "^5.0.1"
flask-babel = "^1.0.0"
flask-healthz = "^0.0.1"

[tool.poetry.dev-dependencies]
pytest = "^5.3"
Expand Down