Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
7
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
feudal
feudalBackend
Commits
b2c2badc
Commit
b2c2badc
authored
Mar 01, 2018
by
Lukas Burgey
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Lint a lot of code
parent
b5b15984
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
162 additions
and
164 deletions
+162
-164
django_backend/backend/auth/v1/models.py
django_backend/backend/auth/v1/models.py
+21
-22
django_backend/backend/auth/v1/views.py
django_backend/backend/auth/v1/views.py
+28
-27
django_backend/backend/clientapi/views.py
django_backend/backend/clientapi/views.py
+7
-7
django_backend/backend/frontend/views.py
django_backend/backend/frontend/views.py
+9
-8
django_backend/backend/logging.py
django_backend/backend/logging.py
+24
-31
django_backend/backend/models.py
django_backend/backend/models.py
+73
-69
No files found.
django_backend/backend/auth/v1/models.py
View file @
b2c2badc
from
...
import
models
import
logging
import
json
from
urllib.request
import
Request
,
urlopen
from
django.db.utils
import
OperationalError
from
django.core.exceptions
import
ObjectDoesNotExist
from
django.db
import
models
as
db_models
from
oic.oic
import
Client
from
oic.oic.message
import
RegistrationResponse
from
oic.utils.authn.client
import
CLIENT_AUTHN_METHOD
from
urllib.request
import
Request
,
urlopen
import
json
from
...
import
models
import
logging
logger
=
logging
.
getLogger
(
__name__
)
LOGGER
=
logging
.
getLogger
(
__name__
)
oidc_client
=
{}
OIDC_CLIENT
=
{}
class
OIDCConfig
(
db_models
.
Model
):
...
...
@@ -30,21 +30,19 @@ class OIDCConfig(db_models.Model):
@
property
def
oidc_client
(
self
):
global
oidc_client
if
self
.
id
not
in
oidc_client
:
if
self
.
id
not
in
OIDC_CLIENT
:
new_oidc_client
=
Client
(
client_authn_method
=
CLIENT_AUTHN_METHOD
)
new_oidc_client
.
provider_config
(
self
.
issuer_uri
)
new_oidc_client
.
store_registration_info
(
self
.
registration_response
)
oidc_client
[
self
.
id
]
=
new_oidc_client
return
oidc_client
[
self
.
id
]
OIDC_CLIENT
[
self
.
id
]
=
new_oidc_client
return
OIDC_CLIENT
[
self
.
id
]
@
property
def
provider_info
(
self
):
return
self
.
oidc_client
.
provider_info
@
property
def
name
(
self
):
return
self
.
issuer_uri
def
__str__
(
self
):
return
self
.
name
def
get_auth_request
(
self
,
client
,
state
):
args
=
{
...
...
@@ -56,12 +54,10 @@ class OIDCConfig(db_models.Model):
}
auth_req
=
client
.
construct_AuthorizationRequest
(
request_args
=
args
)
request_args
=
args
)
return
auth_req
.
request
(
client
.
authorization_endpoint
)
def
__str__
(
self
):
return
self
.
name
def
default_idp
():
return
OIDCConfig
.
objects
.
filter
(
enabled
=
True
).
first
()
...
...
@@ -72,15 +68,17 @@ class OIDCTokenAuthBackend(object):
try
:
idp_id
=
request
.
session
[
'idp_id'
]
except
OperationalError
:
logger
.
error
(
'OperationalError: Unable to get from session'
)
LOGGER
.
error
(
'OperationalError: Unable to get from session'
)
raise
oidc_config
=
OIDCConfig
.
objects
.
get
(
id
=
idp_id
)
q
=
Request
(
oidc_config
.
oidc_client
.
provider_info
[
'userinfo_endpoint'
])
req
=
Request
(
oidc_config
.
oidc_client
.
provider_info
[
'userinfo_endpoint'
]
)
auth
=
(
token_type
+
' '
+
access_token
)
q
.
add_header
(
'Authorization'
,
auth
)
re
q
.
add_header
(
'Authorization'
,
auth
)
userinfo_bytes
=
urlopen
(
q
).
read
()
userinfo_bytes
=
urlopen
(
re
q
).
read
()
return
json
.
loads
(
userinfo_bytes
.
decode
(
'UTF-8'
))
def
authenticate
(
self
,
request
,
token
=
None
):
...
...
@@ -90,7 +88,8 @@ class OIDCTokenAuthBackend(object):
user_info
=
self
.
get_user_info
(
request
,
token
)
try
:
user
=
models
.
User
.
objects
.
get
(
sub
=
user_info
[
'sub'
])
sub
=
user_info
[
'sub'
]
)
return
user
except
ObjectDoesNotExist
:
...
...
django_backend/backend/auth/v1/views.py
View file @
b2c2badc
import
json
import
logging
from
django.contrib.auth
import
authenticate
,
login
,
logout
from
django.db.utils
import
OperationalError
from
django.http
import
HttpResponse
from
django.shortcuts
import
redirect
from
django.views
import
View
from
oic
import
rndstr
from
oic.oic.message
import
AuthorizationResponse
from
rest_framework
import
generics
,
views
from
rest_framework.permissions
import
AllowAny
from
rest_framework.response
import
Response
import
json
from
...logging
import
get_logger
from
oic
import
rndstr
from
oic.oic.message
import
AuthorizationResponse
from
.models
import
OIDCConfig
,
default_idp
from
.serializers
import
AuthInfoSerializer
logger
=
get
_l
ogger
(
__name__
)
LOGGER
=
logging
.
get
L
ogger
(
__name__
)
idp_cookie_name
=
'idp_id'
IDP_COOKIE_NAME
=
'idp_id'
def
idp_id_from_request
(
request
):
id
=
request
.
COOKIES
.
get
(
idp_cookie_name
,
None
)
if
id
is
not
None
:
return
id
else
:
return
default_idp
().
id
idp_
id
=
request
.
COOKIES
.
get
(
IDP_COOKIE_NAME
,
None
)
if
idp_
id
is
not
None
:
return
id
p_id
return
default_idp
().
id
def
get_session
(
request
,
key
,
default
):
try
:
value
=
request
.
session
.
get
(
key
,
None
)
except
OperationalError
:
logger
.
error
(
'Operational: Error getting from session'
)
LOGGER
.
error
(
'Operational: Error getting from session'
)
raise
if
value
is
not
None
:
return
value
else
:
return
default
return
default
def
set_session
(
request
,
key
,
value
):
try
:
value
=
request
.
session
[
key
]
=
value
except
OperationalError
:
logger
.
error
(
'Operational: Error setting in session'
)
LOGGER
.
error
(
'Operational: Error setting in session'
)
raise
class
Auth
(
View
):
def
get
(
self
,
request
,
**
kwargs
):
def
get
(
self
,
request
):
try
:
state
=
rndstr
()
...
...
@@ -67,18 +66,18 @@ class Auth(View):
)
)
except
Exception
:
logger
.
error
(
'Malformed oidc config: {}'
.
format
(
oidc_config
))
LOGGER
.
error
(
'Malformed oidc config: {}'
.
format
(
oidc_config
))
raise
except
Exception
as
e
:
logger
.
error
(
'request: {}'
.
format
(
e
))
except
Exception
as
e
xception
:
LOGGER
.
error
(
'request: {}'
.
format
(
e
xception
))
# the error is deleted from the session when the state is delivered
request
.
session
[
'error'
]
=
'Server Error'
return
redirect
(
'/'
)
class
AuthCallback
(
View
):
def
get
(
self
,
request
,
**
kwargs
):
def
get
(
self
,
request
):
try
:
state
=
get_session
(
request
,
'state'
,
None
)
idp_id
=
get_session
(
request
,
'idp_id'
,
default_idp
().
id
)
...
...
@@ -90,7 +89,7 @@ class AuthCallback(View):
)
if
not
state
==
aresp
[
'state'
]:
logger
.
error
(
'states do not match'
)
LOGGER
.
error
(
'states do not match'
)
raise
Exception
(
'States do not match'
)
ac_token_response
=
(
...
...
@@ -123,30 +122,32 @@ class AuthCallback(View):
if
user
is
None
:
# authentication failed -> "401"
logger
.
error
(
'User failed to log in'
.
format
(
request
.
user
)
)
LOGGER
.
error
(
'User failed to log in'
)
request
.
session
[
'error'
]
=
'Login failed'
# response = HttpResponse('Unauthorized', status=401)
elif
not
user
.
is_active
:
# user is deactivated -> "403"
logger
.
info
(
'{} tried to log in'
.
format
(
user
))
LOGGER
.
info
(
'{} tried to log in'
.
format
(
user
))
request
.
session
[
'error'
]
=
'Account deactivated'
# response = HttpResponse('Forbidden', status=403)
else
:
# user authenticated -> back to frontend
login
(
request
,
user
)
LOGGER
.
debug
(
'authenticated {}'
.
format
(
user
))
response
.
set_cookie
(
'sessionid'
,
request
.
COOKIES
[
'sessionid'
])
return
response
except
Exception
as
e
:
logger
.
error
(
'request: {}'
.
format
(
e
))
except
Exception
as
e
xception
:
LOGGER
.
error
(
'request: {}'
.
format
(
e
xception
))
# the error is deleted from the session when the state is delivered
request
.
session
[
'error'
]
=
'Server Error'
return
redirect
(
'/'
)
class
LogoutView
(
views
.
APIView
):
def
post
(
self
,
request
,
format
=
None
):
def
post
(
self
,
request
):
LOGGER
.
debug
(
'logged out {}'
.
format
(
request
.
user
))
logout
(
request
)
return
Response
({})
...
...
django_backend/backend/clientapi/views.py
View file @
b2c2badc
...
...
@@ -2,15 +2,15 @@
from
rest_framework
import
generics
,
views
,
status
from
rest_framework.authentication
import
TokenAuthentication
from
rest_framework.response
import
Response
from
..models
import
rabbitmq_instance
from
..models
import
RABBITMQ_INSTANCE
from
.
import
serializers
# authentication class for the client api
authentication_classes
=
(
TokenAuthentication
,
)
AUTHENTICATION_CLASSES
=
(
TokenAuthentication
,
)
class
DeploymentsView
(
generics
.
RetrieveAPIView
):
authentication_classes
=
authentication_classes
authentication_classes
=
AUTHENTICATION_CLASSES
serializer_class
=
serializers
.
SiteSerializer
def
get_object
(
self
):
...
...
@@ -19,7 +19,7 @@ class DeploymentsView(generics.RetrieveAPIView):
# the client has to fetch the configuration (like services etc.) here
class
ConfigurationView
(
generics
.
ListAPIView
):
authentication_classes
=
authentication_classes
authentication_classes
=
AUTHENTICATION_CLASSES
serializer_class
=
serializers
.
ServiceSerializer
def
get_queryset
(
self
):
...
...
@@ -27,14 +27,14 @@ class ConfigurationView(generics.ListAPIView):
# we update the rabbitmq permission here, so the
# client can access all of his services, even new ones
rabbitmq_instance
()
.
update_site
(
site
)
RABBITMQ_INSTANCE
.
update_site
(
site
)
return
site
.
services
.
all
()
class
AckView
(
views
.
APIView
):
authentication_classes
=
authentication_classes
authentication_classes
=
AUTHENTICATION_CLASSES
def
delete
(
self
,
request
,
id
=
None
,
format
=
None
):
def
delete
(
self
,
request
,
id
=
None
):
# find the corresponding task for this item
for
item
in
request
.
user
.
site
.
task_items
.
all
():
if
item
.
task
.
id
==
int
(
id
):
...
...
django_backend/backend/frontend/views.py
View file @
b2c2badc
...
...
@@ -6,8 +6,8 @@ from rest_framework.permissions import AllowAny
from
rest_framework.response
import
Response
from
rest_framework
import
status
from
.
import
serializers
,
models
as
frontend_models
from
..
import
models
from
django_backend.backend.frontend
import
serializers
,
models
as
frontend_models
from
django_backend.backend
import
models
import
logging
logger
=
logging
.
getLogger
(
__name__
)
...
...
@@ -100,16 +100,15 @@ class SSHPublicKeyView(views.APIView):
class
DeploymentView
(
views
.
APIView
):
def
post
(
self
,
request
,
format
=
None
):
if
(
'type'
not
in
request
.
data
or
'key'
not
in
request
.
data
or
'service'
not
in
request
.
data
):
):
logger
.
error
(
'Deployment api got invalid request {}'
.
format
(
request
.
data
))
'Deployment api got invalid request {}'
.
format
(
request
.
data
))
return
_api_error_response
()
request_type
=
request
.
data
[
'type'
]
...
...
@@ -120,6 +119,7 @@ class DeploymentView(views.APIView):
name
=
request
.
data
[
'key'
])
# check if there is already an deployment
if
not
request
.
user
.
deployments
.
filter
(
service
=
request_service
).
exists
():
oeuaoeuaoeuoaeuoeauoaeuoeuaoeuoaeuaoeua
try
:
deployment
=
request
.
user
.
deployments
.
get
(
service
=
request_service
)
except
Exception
:
...
...
@@ -127,8 +127,9 @@ class DeploymentView(views.APIView):
return
_api_error_response
()
deployment
=
models
.
Deployment
(
user
=
request
.
user
,
service
=
request_service
)
user
=
request
.
user
,
service
=
request_service
,
)
deployment
.
save
()
if
request_type
==
'add'
:
...
...
django_backend/backend/logging.py
View file @
b2c2badc
import
logging
from
logging
import
Formatter
,
FileHandler
,
StreamHandler
,
getLogger
import
sys
logger_dir
=
'./logs/
'
formatter
=
logging
.
Formatter
(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
LOGGER_NAME
=
'django_backend.backend
'
LOGGER_DIR
=
'./logs/'
FORMATTER
=
Formatter
(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
error_fh
=
logging
.
FileHandler
(
logger_dir
+
'error.log'
)
error_fh
.
setLevel
(
logging
.
ERROR
)
error_fh
.
setFormatter
(
formatter
)
ERROR_FH
=
FileHandler
(
LOGGER_DIR
+
'error.log'
)
ERROR_FH
.
setLevel
(
'
ERROR
'
)
ERROR_FH
.
setFormatter
(
FORMATTER
)
info_fh
=
logging
.
FileHandler
(
logger_dir
+
'info.log'
)
info_fh
.
setLevel
(
logging
.
INFO
)
info_fh
.
setFormatter
(
formatter
)
INFO_FH
=
FileHandler
(
LOGGER_DIR
+
'info.log'
)
INFO_FH
.
setLevel
(
'
INFO
'
)
INFO_FH
.
setFormatter
(
FORMATTER
)
debug_fh
=
logging
.
FileHandler
(
logger_dir
+
'debug.log'
)
debug_fh
.
setLevel
(
logging
.
DEBUG
)
debug_fh
.
setFormatter
(
formatter
)
DEBUG_FH
=
FileHandler
(
LOGGER_DIR
+
'debug.log'
)
DEBUG_FH
.
setLevel
(
'
DEBUG
'
)
DEBUG_FH
.
setFormatter
(
FORMATTER
)
# for the console
ch
=
logging
.
StreamHandler
(
sys
.
stdout
)
ch
.
setLevel
(
logging
.
INFO
)
ch
.
setFormatter
(
formatter
)
CH
=
StreamHandler
(
sys
.
stdout
)
CH
.
setLevel
(
'
INFO
'
)
CH
.
setFormatter
(
FORMATTER
)
def
setup_logger
(
name
):
logger
=
logging
.
getLogger
(
name
)
logger
.
setLevel
(
logging
.
DEBUG
)
def
setup_logger
():
logger
=
getLogger
(
LOGGER_NAME
)
logger
.
setLevel
(
'
DEBUG
'
)
# add all handlers
logger
.
addHandler
(
error_fh
)
logger
.
addHandler
(
info_fh
)
logger
.
addHandler
(
ch
)
logger
.
addHandler
(
debug_fh
)
logger
.
addHandler
(
ERROR_FH
)
logger
.
addHandler
(
INFO_FH
)
logger
.
addHandler
(
CH
)
logger
.
addHandler
(
DEBUG_FH
)
logger
.
info
(
'STARTED LOGGER {}'
.
format
(
name
))
def
get_logger
(
name
):
return
logging
.
getLogger
(
name
)
setup_logger
(
'django_backend.backend'
)
logger
.
info
(
'STARTED LOGGER {}'
.
format
(
LOGGER_NAME
))
django_backend/backend/models.py
View file @
b2c2badc
# django senders need their arguments
# pylint: disable=unused-argument
import
json
import
logging
import
requests
from
requests.auth
import
HTTPBasicAuth
import
pika
from
django.conf
import
settings
from
django.contrib.auth.models
import
AbstractUser
,
Group
from
django.db
import
models
from
django.db.models.signals
import
post_save
,
pre_delete
from
django.dispatch
import
receiver
from
requests.auth
import
HTTPBasicAuth
from
rest_framework.authtoken.models
import
Token
import
json
import
pika
import
requests
from
.logging
import
get_logger
from
.logging
import
setup_logger
logger
=
get_logger
(
__name__
)
# we start the logger here
setup_logger
()
LOGGER
=
logging
.
getLogger
(
__name__
)
# clients are registerred at rabbitmq, when they are assigned to a site
...
...
@@ -49,14 +55,6 @@ class RabbitMQInstance(models.Model):
def
msg
(
self
,
msg
):
return
'[RabbitMQ:{}] {}'
.
format
(
self
.
host
,
msg
)
@
property
def
api
(
self
):
return
'http://{}:{}/{}'
.
format
(
self
.
host
,
self
.
port
,
self
.
path
,
)
@
property
def
auth
(
self
):
return
HTTPBasicAuth
(
...
...
@@ -82,7 +80,7 @@ class RabbitMQInstance(models.Model):
self
.
rabbitmq_connection
=
pika
.
BlockingConnection
(
rabbitmqconnection_properties
)
logger
.
debug
(
self
.
msg
(
'opened connection'
))
LOGGER
.
debug
(
self
.
msg
(
'opened connection'
))
return
self
.
rabbitmq_connection
...
...
@@ -95,36 +93,42 @@ class RabbitMQInstance(models.Model):
durable
=
True
,
exchange_type
=
'topic'
)
self
.
rabbitmq_channel
.
confirm_delivery
()
logger
.
debug
(
self
.
msg
(
'opened channel'
))
LOGGER
.
debug
(
self
.
msg
(
'opened channel'
))
return
self
.
rabbitmq_channel
def
get_uri
(
self
,
path
):
return
'{}/{}'
.
format
(
self
.
api
,
path
)
api
=
'http://{}:{}/{}'
.
format
(
self
.
host
,
self
.
port
,
self
.
path
,
)
return
'{}/{}'
.
format
(
api
,
path
)
def
rest_get
(
self
,
api_path
):
r
=
requests
.
get
(
r
eq
=
requests
.
get
(
self
.
get_uri
(
api_path
),
auth
=
self
.
auth
)
r
.
raise_for_status
()
return
r
.
json
()
r
eq
.
raise_for_status
()
return
r
eq
.
json
()
# send a rest call with path and data to the rest interface of
# the rabbitmq instance
def
rest_put
(
self
,
api_path
,
data
):
r
=
requests
.
put
(
r
eq
=
requests
.
put
(
self
.
get_uri
(
api_path
),
json
=
data
,
auth
=
self
.
auth
)
r
.
raise_for_status
()
return
r
r
eq
.
raise_for_status
()
return
r
eq
def
rest_del
(
self
,
api_path
):
r
=
requests
.
delete
(
r
eq
=
requests
.
delete
(
self
.
get_uri
(
api_path
),
auth
=
self
.
auth
)
r
.
raise_for_status
()
return
r
r
eq
.
raise_for_status
()
return
r
eq
def
set_topic_permissions
(
self
,
site
):
username
=
site
.
client
.
username
...
...
@@ -136,19 +140,19 @@ class RabbitMQInstance(models.Model):
# set permissions for the correct topics
# we construct a regex to match the services of the site
services
=
''
omit
B
ar
=
True
omit
_b
ar
=
True
for
service
in
site
.
services
.
all
():
prefix
=
'|'
if
omit
B
ar
:
if
omit
_b
ar
:
prefix
=
''
omit
B
ar
=
False
omit
_b
ar
=
False
services
=
services
+
prefix
+
service
.
name
set_topic_permission_data
=
{
'exchange'
:
self
.
exchange
,
'write'
:
'^$'
,
'read'
:
'^service\.({})$'
.
format
(
services
),
'read'
:
r
'^service\.({})$'
.
format
(
services
),
}
return
self
.
rest_put
(
path
,
set_topic_permission_data
)
...
...
@@ -160,7 +164,7 @@ class RabbitMQInstance(models.Model):
self
.
vhost
,
username
,
)
permission
=
'^(amq\.gen.*|{})'
.
format
(
self
.
exchange
)
permission
=
r
'^(amq\.gen.*|{})'
.
format
(
self
.
exchange
)
set_permission_data
=
{
'configure'
:
permission
,
'write'
:
permission
,
...
...
@@ -194,14 +198,14 @@ class RabbitMQInstance(models.Model):
self
.
create_user
(
site
)
self
.
set_permissions
(
site
)
self
.
set_topic_permissions
(
site
)
logger
.
info
(
self
.
msg
(
'registered {}'
.
format
(
site
.
client
)))
LOGGER
.
info
(
self
.
msg
(
'registered {}'
.
format
(
site
.
client
)))
def
update_site
(
self
,
site
):
self
.
set_topic_permissions
(
site
)
logger
.
info
(
self
.
msg
(
'updated permissions for {}'
.
format
(
site
.
client
)))
LOGGER
.
info
(
self
.
msg
(
'updated permissions for {}'
.
format
(
site
.
client
)))
def
deregister_site
(
self
,
site
):
logger
.
info
(
self
.
msg
(
'deregistered {}'
.
format
(
site
.
client
)))
LOGGER
.
info
(
self
.
msg
(
'deregistered {}'
.
format
(
site
.
client
)))
def
is_client_connected
(
self
,
site
):
connections
=
self
.
rest_get
(
"connections/"
)
...
...
@@ -211,12 +215,9 @@ class RabbitMQInstance(models.Model):
return
len
(
clients_for_site
)
>
0
def
disconnect
(
self
):
logger
.
debug
(
self
.
msg
(
'closing connection'
))
LOGGER
.
debug
(
self
.
msg
(
'closing connection'
))
self
.
connection
.
close
()
def
service_routing_key
(
self
,
service
):
return
'service.'
+
service
.
name
def
online_clients
(
self
,
service
):
return
[
site
for
site
in
service
.
site
.
all
()
...
...
@@ -233,8 +234,11 @@ class RabbitMQInstance(models.Model):
)
def
rabbitmq_instance
():
return
RabbitMQInstance
.
objects
.
get
(
is_active
=
True
)
def
service_routing_key
(
service
):
return
'service.'
+
service
.
name
RABBITMQ_INSTANCE
=
RabbitMQInstance
.
objects
.
filter
(
is_active
=
True
).
first
()
class
User
(
AbstractUser
):
...
...
@@ -274,12 +278,14 @@ class User(AbstractUser):
def
__str__
(
self
):
if
self
.
user_type
==
'admin'
:
return
'ADMIN {}'
.
format
(
self
.
username
)
if
self
.
user_type
==
'oidcuser'
:
el
if
self
.
user_type
==
'oidcuser'
:
if
not
self
.
is_active
:
return
'DEACTIVATED USER {}'
.
format
(
self
.
username
)
return
'USER {}'
.
format
(
self
.
username
)
if
self
.
user_type
==
'apiclient'
:
el
if
self
.
user_type
==
'apiclient'
:
return
'APICLIENT {}@{}'
.
format
(
self
.
username
,
self
.
site
)
else
:
raise
Exception
()
def
msg
(
self
,
msg
):
return
'[{}] {}'
.
format
(
self
,
msg
)
...
...
@@ -288,7 +294,7 @@ class User(AbstractUser):
def
remove
(
self
):
if
self
.
user_type
==
'oidcuser'
:
self
.
deactivate
()
logger
.
info
(
self
.
msg
(
'Deleting'
))
LOGGER
.
info
(
self
.
msg
(
'Deleting'
))
# TODO: deleting the user brings problems:
# the deletion cascades down to DeploymentTask and DeploymentTaskItem
...
...
@@ -297,7 +303,7 @@ class User(AbstractUser):