1 Commits

Author SHA1 Message Date
73b94e8aa2 jwt, first try not working 2021-01-24 20:41:08 +01:00
10 changed files with 240 additions and 290 deletions

View File

@ -10,10 +10,6 @@ ENV DB_HOST="172.16.10.18"
ENV DB_NAME="hausverwaltung" ENV DB_NAME="hausverwaltung"
ENV DB_USER="hausverwaltung-ui" ENV DB_USER="hausverwaltung-ui"
ENV DB_PASS="test123" ENV DB_PASS="test123"
ENV JWT_ISSUER='de.hottis.hausverwaltung'
ENV JWT_SECRET='streng_geheim'
ENV JWT_LIFETIME_SECONDS=60
ENV JWT_ALGORITHM='HS256'
RUN \ RUN \
@ -24,7 +20,9 @@ RUN \
pip3 install connexion && \ pip3 install connexion && \
pip3 install connexion[swagger-ui] && \ pip3 install connexion[swagger-ui] && \
pip3 install uwsgi && \ pip3 install uwsgi && \
pip3 install flask-cors pip3 install flask-cors && \
pip3 install python-jose[cryptography] && \
pip3 install six
RUN \ RUN \
mkdir -p ${APP_DIR} && \ mkdir -p ${APP_DIR} && \

View File

@ -5,4 +5,3 @@ export DB_USER="hausverwaltung-ui"
export DB_PASS="test123" export DB_PASS="test123"
export DB_NAME="hausverwaltung" export DB_NAME="hausverwaltung"
export JWT_SECRET='streng_geheim'

View File

@ -1,8 +1,6 @@
from dbpool import getConnection, getMany, getOne from dbpool import getConnection, getMany, getOne
from auth import check_scope
def get_mieters(token_info): def get_mieters():
check_scope(token_info, [ "mieter/read", "wohnung/read", "objekt/read" ])
return getMany(""" return getMany("""
SELECT m.id as id, SELECT m.id as id,
o.id as objekt, o.id as objekt,
@ -23,8 +21,7 @@ SELECT m.id as id,
w.id = m.wohnung w.id = m.wohnung
""", [], "Mieter") """, [], "Mieter")
def get_mieter(id, token_info): def get_mieter(id=None):
check_scope(token_info, [ "mieter/read", "wohnung/read", "objekt/read" ])
return getOne(""" return getOne("""
SELECT m.id as id, SELECT m.id as id,
o.id as objekt, o.id as objekt,

View File

@ -1,11 +1,8 @@
from dbpool import getConnection, getMany, getOne from dbpool import getConnection, getMany, getOne
from auth import check_scope
def get_objekte(token_info): def get_objekte():
check_scope(token_info, "objekt/read")
return getMany("SELECT id, shortname, flaeche FROM objekt", [], "Objekt") return getMany("SELECT id, shortname, flaeche FROM objekt", [], "Objekt")
def get_objekt(id, token_info): def get_objekt(id=None):
check_scope(token_info, "objekt/read")
return getOne("SELECT id, shortname, flaeche FROM objekt WHERE id = ?", return getOne("SELECT id, shortname, flaeche FROM objekt WHERE id = ?",
(id,), "Objekt") (id,), "Objekt")

View File

@ -1,9 +1,6 @@
from dbpool import getConnection, getOne, getMany from dbpool import getConnection, getOne, getMany
from auth import check_scope
def get_wohnungen():
def get_wohnungen(token_info):
check_scope(token_info, "wohnung/read")
return getMany(""" return getMany("""
SELECT w.id as id, SELECT w.id as id,
w.objekt as objekt, w.objekt as objekt,
@ -14,8 +11,7 @@ SELECT w.id as id,
WHERE o.id = w.objekt WHERE o.id = w.objekt
""", [], "Wohnung") """, [], "Wohnung")
def get_wohnung(id, token_info): def get_wohnung(id=None):
check_scope(token_info, [ "wohnung/read", "objekt/read" ])
return getOne(""" return getOne("""
SELECT w.id as id, SELECT w.id as id,
w.objekt as objekt, w.objekt as objekt,
@ -27,8 +23,7 @@ SELECT w.id as id,
w.id = ? w.id = ?
""", (id, ), "Wohnung") """, (id, ), "Wohnung")
def get_wohnungen_by_objekt(id, token_info): def get_wohnungen_by_objekt(id):
check_scope(token_info, [ "wohnung/read", "objekt/read" ])
return getMany(""" return getMany("""
SELECT w.id as id, SELECT w.id as id,
w.objekt as objekt, w.objekt as objekt,

View File

@ -2,10 +2,8 @@ from dbpool import getConnection, getOne, getMany, putOne
import datetime import datetime
import decimal import decimal
import dateparser import dateparser
from auth import check_scope
def get_zahlungen_by_mieter(mieter_id, token_info): def get_zahlungen_by_mieter(mieter_id):
check_scope(token_info, "zahlung/read")
return getMany(""" return getMany("""
SELECT id, SELECT id,
mieter, mieter,
@ -30,8 +28,7 @@ SELECT id,
""", [ id ], "Zahlung") """, [ id ], "Zahlung")
def get_forderungen_by_mieter(mieter_id, token_info): def get_forderungen_by_mieter(mieter_id):
check_scope(token_info, "forderung/read")
return getMany(""" return getMany("""
SELECT id, SELECT id,
mieter, mieter,
@ -43,8 +40,7 @@ SELECT id,
WHERE mieter = ? WHERE mieter = ?
""", [ mieter_id ], "Forderung") """, [ mieter_id ], "Forderung")
def get_forderung(id, token_info): def get_forderung(id):
check_scope(token_info, "forderung/read")
return getOne(""" return getOne("""
SELECT id, SELECT id,
mieter, mieter,
@ -56,8 +52,7 @@ SELECT id,
WHERE id = ? WHERE id = ?
""", [ id ], "Forderung") """, [ id ], "Forderung")
def get_zahlungforderung_by_mieter_and_year(mieter_id, year, token_info): def get_zahlungforderung_by_mieter_and_year(mieter_id, year):
check_scope(token_info, [ "forderung/read", "zahlung/read", "mieter/read" ])
if year == 0: if year == 0:
year = datetime.datetime.now().year year = datetime.datetime.now().year
start_date = "{}-01-01".format(year) start_date = "{}-01-01".format(year)
@ -77,8 +72,7 @@ WHERE mieter = ? AND
datum_soll BETWEEN ? AND ? datum_soll BETWEEN ? AND ?
""", [mieter_id, start_date, end_date], "ZahlungForderung") """, [mieter_id, start_date, end_date], "ZahlungForderung")
def get_saldo_by_mieter_and_year(mieter_id, year, token_info): def get_saldo_by_mieter_and_year(mieter_id, year):
check_scope(token_info, [ "forderung/read", "zahlung/read", "mieter/read" ])
if year == 0: if year == 0:
year = datetime.datetime.now().year year = datetime.datetime.now().year
start_date = "{}-01-01".format(year) start_date = "{}-01-01".format(year)
@ -112,8 +106,7 @@ WHERE mieter = ? AND
"zahlungen": float(sumZ) "zahlungen": float(sumZ)
} }
def put_zahlung(zahlung, token_info): def put_zahlung(zahlung):
check_scope(token_info, "zahlung/write")
print("Input of put_zahlung: {} {}".format(type(zahlung), zahlung)) print("Input of put_zahlung: {} {}".format(type(zahlung), zahlung))
datum_soll = dateparser.parse(zahlung["datum_soll"], languages=["de"]) datum_soll = dateparser.parse(zahlung["datum_soll"], languages=["de"])
datum_ist = dateparser.parse(zahlung["datum_ist"], languages=["de"]) datum_ist = dateparser.parse(zahlung["datum_ist"], languages=["de"])

44
auth.py Executable file → Normal file
View File

@ -1,35 +1,36 @@
import time import time
import connexion import connexion
from werkzeug.exceptions import Unauthorized, Forbidden import six
from werkzeug.exceptions import Unauthorized
from jose import JWTError, jwt from jose import JWTError, jwt
import os
JWT_SECRET = os.environ['JWT_SECRET'] JWT_ISSUER = 'de.hottis.hausverwaltung'
JWT_SECRET = 'streng_geheim'
JWT_LIFETIME_SECONDS = 600
JWT_ALGORITHM = 'HS256'
def generate_token(user_id):
timestamp = _current_timestamp()
payload = {
"iss": JWT_ISSUER,
"iat": int(timestamp),
"exp": int(timestamp + JWT_LIFETIME_SECONDS),
"sub": str(user_id),
}
return jwt.encode(payload, JWT_SECRET, algorithm=JWT_ALGORITHM)
def decode_token(token): def decode_token(token):
try: try:
print("DEBUG decode_token: try to decode") return jwt.decode(token, JWT_SECRET, algorithms=[JWT_ALGORITHM])
token_info = jwt.decode(token, JWT_SECRET)
print("DEBUG decode_token: token_info: {}".format(token_info))
return token_info
except JWTError as e: except JWTError as e:
print("ERROR decode_token: error when decoding token: {}".format(e)) six.raise_from(Unauthorized, e)
raise Unauthorized()
def check_token(token, key, value):
if (key in token) and ((token[key] == value) or (isinstance(token[key], list) and (value in token[key]))):
return True
print("WARN: check_token: {} -> {} required but not granted".format(key, value))
raise Forbidden()
def check_scope(token, value):
if isinstance(value, list):
for v in value:
check_token(token, "x-scope", v)
else:
check_token(token, "x-scope", value)
def get_secret(user, token_info) -> str: def get_secret(user, token_info) -> str:
return ''' return '''
@ -38,7 +39,6 @@ def get_secret(user, token_info) -> str:
'''.format(user=user, token_info=token_info) '''.format(user=user, token_info=token_info)
def _current_timestamp() -> int: def _current_timestamp() -> int:
return int(time.time()) return int(time.time())

4
run.sh
View File

@ -15,8 +15,4 @@ docker run \
-e DB_USER=$DB_USER \ -e DB_USER=$DB_USER \
-e DB_PASS=$DB_PASS \ -e DB_PASS=$DB_PASS \
-e DB_NAME=$DB_NAME \ -e DB_NAME=$DB_NAME \
-e JWT_ISSUER=$JWT_ISSUER \
-e JWT_SECRET=$JWT_SECRET \
-e JWT_LIFETIME_SECONDS=$JWT_LIFETIME_SECONDS \
-e JWT_ALGORITHM=$JWT_ALGORITHM
${IMAGE_NAME}:${VERSION} ${IMAGE_NAME}:${VERSION}

View File

@ -3,7 +3,7 @@ from flask_cors import CORS
# instantiate the webservice # instantiate the webservice
app = connexion.App(__name__) app = connexion.App(__name__)
app.add_api('openapi.yaml') app.add_api('swagger.yaml')
# CORSify it - otherwise Angular won't accept it # CORSify it - otherwise Angular won't accept it
CORS(app.app) CORS(app.app)

View File

@ -1,10 +1,7 @@
openapi: 3.0.0 openapi: 3.0.0
info: info:
title: Hausverwaltung title: Hausverwaltung-JWT
version: "0.1" version: "0.2"
security:
- jwt: []
paths: paths:
/hv/objekte: /hv/objekte:
@ -15,12 +12,10 @@ paths:
responses: responses:
200: 200:
description: Successful response. description: Successful response.
content:
'application/json':
schema: schema:
type: array type: array
items: items:
$ref: '#/components/schemas/Objekt' $ref: '#/components/Objekt'
404: 404:
description: No Objekte available description: No Objekte available
500: 500:
@ -33,16 +28,13 @@ paths:
parameters: parameters:
- name: id - name: id
in: path in: path
required: true
schema:
type: integer type: integer
required: true
responses: responses:
200: 200:
description: Successful response. description: Successful response.
content:
'application/json':
schema: schema:
$ref: '#/components/schemas/Objekt' $ref: '#/components/Objekt'
404: 404:
description: Objekt not found description: Objekt not found
500: 500:
@ -55,12 +47,10 @@ paths:
responses: responses:
200: 200:
description: Successful response. description: Successful response.
content:
'application/json':
schema: schema:
type: array type: array
items: items:
$ref: '#/components/schemas/Wohnung' $ref: '#/components/Wohnung'
404: 404:
description: No Wohnung available description: No Wohnung available
500: 500:
@ -73,18 +63,15 @@ paths:
parameters: parameters:
- name: id - name: id
in: path in: path
required: true
schema:
type: integer type: integer
required: true
responses: responses:
200: 200:
description: Successful response. description: Successful response.
content:
'application/json':
schema: schema:
type: array type: array
items: items:
$ref: '#/components/schemas/Wohnung' $ref: '#/components/Wohnung'
404: 404:
description: No Wohnung available description: No Wohnung available
500: 500:
@ -97,16 +84,13 @@ paths:
parameters: parameters:
- name: id - name: id
in: path in: path
required: true
schema:
type: integer type: integer
required: true
responses: responses:
200: 200:
description: Successful response. description: Successful response.
content:
'application/json':
schema: schema:
$ref: '#/components/schemas/Wohnung' $ref: '#/components/Wohnung'
404: 404:
description: Wohnung not found description: Wohnung not found
500: 500:
@ -119,19 +103,14 @@ paths:
responses: responses:
200: 200:
description: Successful response. description: Successful response.
content:
'application/json':
schema: schema:
type: array type: array
items: items:
$ref: '#/components/schemas/Mieter' $ref: '#/components/Mieter'
404: 404:
description: No Mieter available description: No Mieter available
500: 500:
description: Some server error description: Some server error
security:
- jwt: ['secret']
/hv/mieter/{id}: /hv/mieter/{id}:
get: get:
tags: [ "Mieter" ] tags: [ "Mieter" ]
@ -140,16 +119,13 @@ paths:
parameters: parameters:
- name: id - name: id
in: path in: path
required: true
schema:
type: integer type: integer
required: true
responses: responses:
200: 200:
description: Successful response. description: Successful response.
content:
'application/json':
schema: schema:
$ref: '#/components/schemas/Mieter' $ref: '#/components/Mieter'
404: 404:
description: Mieter not found description: Mieter not found
500: 500:
@ -162,16 +138,13 @@ paths:
parameters: parameters:
- name: id - name: id
in: path in: path
required: true
schema:
type: integer type: integer
required: true
responses: responses:
200: 200:
description: Successful response. description: Successful response.
content:
'application/json':
schema: schema:
$ref: '#/components/schemas/Forderung' $ref: '#/components/Forderung'
404: 404:
description: Forderung not found description: Forderung not found
500: 500:
@ -184,18 +157,15 @@ paths:
parameters: parameters:
- name: mieter_id - name: mieter_id
in: path in: path
required: true
schema:
type: integer type: integer
required: true
responses: responses:
200: 200:
description: Successful response. description: Successful response.
content:
'application/json':
schema: schema:
type: array type: array
items: items:
$ref: '#/components/schemas/Forderung' $ref: '#/components/Forderung'
404: 404:
description: No Forderung available description: No Forderung available
500: 500:
@ -208,16 +178,13 @@ paths:
parameters: parameters:
- name: id - name: id
in: path in: path
required: true
schema:
type: integer type: integer
required: true
responses: responses:
200: 200:
description: Successful response. description: Successful response.
content:
'application/json':
schema: schema:
$ref: '#/components/schemas/Zahlung' $ref: '#/components/Zahlung'
404: 404:
description: Zahlung not found description: Zahlung not found
500: 500:
@ -230,18 +197,15 @@ paths:
parameters: parameters:
- name: mieter_id - name: mieter_id
in: path in: path
required: true
schema:
type: integer type: integer
required: true
responses: responses:
200: 200:
description: Successful response. description: Successful response.
content:
'application/json':
schema: schema:
type: array type: array
items: items:
$ref: '#/components/schemas/Zahlung' $ref: '#/components/Zahlung'
404: 404:
description: No Zahlung available description: No Zahlung available
500: 500:
@ -254,23 +218,19 @@ paths:
parameters: parameters:
- name: mieter_id - name: mieter_id
in: path in: path
required: true
schema:
type: integer type: integer
required: true
- name: year - name: year
in: path in: path
required: true
schema:
type: integer type: integer
required: true
responses: responses:
200: 200:
description: Successful response description: Successful response
content:
'application/json':
schema: schema:
type: array type: array
items: items:
$ref: '#/components/schemas/ZahlungForderung' $ref: '#/components/ZahlungForderung'
404: 404:
description: No ZahlungForderung available description: No ZahlungForderung available
500: 500:
@ -283,21 +243,17 @@ paths:
parameters: parameters:
- name: mieter_id - name: mieter_id
in: path in: path
required: true
schema:
type: integer type: integer
required: true
- name: year - name: year
in: path in: path
required: true
schema:
type: integer type: integer
required: true
responses: responses:
200: 200:
description: Successful response description: Successful response
content:
'application/json':
schema: schema:
$ref: '#/components/schemas/Saldo' $ref: '#/components/Saldo'
404: 404:
description: Neither Forderungen nor Zahlungen available description: Neither Forderungen nor Zahlungen available
500: 500:
@ -307,19 +263,39 @@ paths:
tags: [ "Zahlung" ] tags: [ "Zahlung" ]
operationId: ZahlungenForderungen.put_zahlung operationId: ZahlungenForderungen.put_zahlung
summary: Inserts a new Zahlung summary: Inserts a new Zahlung
requestBody: parameters:
content: - name: zahlung
'application/json': in: body
schema: schema:
$ref: '#/components/schemas/Zahlung' $ref: '#/components/Zahlung'
responses: responses:
202: 202:
description: Zahlung successfully inserted description: Zahlung successfully inserted
500: 500:
description: Some server or database error description: Some server or database error
/auth/{user_id}:
get:
tags: [ "jwt" ]
summary: Return JWT token
operationId: auth.generate_token
parameters:
- name: user_id
description: User unique identifier
in: path
required: true
example: 12
schema:
type: integer
responses:
'200':
description: JWT token
content:
'text/plain':
schema:
type: string
/secret: /secret:
get: get:
tags: [ "JWT" ] tags: [ "jwt" ]
summary: Return secret string summary: Return secret string
operationId: auth.get_secret operationId: auth.get_secret
responses: responses:
@ -329,17 +305,10 @@ paths:
'text/plain': 'text/plain':
schema: schema:
type: string type: string
security:
- jwt: ['secret']
components: components:
securitySchemes:
jwt:
type: http
scheme: bearer
bearerFormat: JWT
x-bearerInfoFunc: auth.decode_token
schemas:
Objekt: Objekt:
description: Objekt type description: Objekt type
type: object type: object
@ -458,3 +427,9 @@ components:
type: number type: number
saldo: saldo:
type: number type: number
securitySchemes:
jwt:
type: http
scheme: bearer
bearerFormat: JWT
x-bearerInfoFunc: auth.decode_token