Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
feudal
feudalBackend
Commits
a5a4daa4
Commit
a5a4daa4
authored
Nov 07, 2018
by
Lukas Burgey
Browse files
Add a more clear api to the User class
Alongside other linting / minor changes.
parent
b9a15d9e
Changes
6
Hide whitespace changes
Inline
Side-by-side
example-config/home/feudal/config/django_settings.py
View file @
a5a4daa4
...
...
@@ -8,6 +8,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
DEBUG
=
True
DEBUG_AUTH
=
False
DEBUG_CREDENTIALS
=
True
ALLOWED_HOSTS
=
[
'hdf-portal.data.kit.edu'
,
...
...
feudal/backend/models/__init__.py
View file @
a5a4daa4
...
...
@@ -5,7 +5,9 @@ from logging import getLogger
from
django.contrib.auth.models
import
Group
from
django.db
import
models
from
django_mysql.models
import
JSONField
from
django.conf
import
settings
# these imports are exports!
from
.brokers
import
RabbitMQInstance
from
.users
import
User
,
SSHPublicKey
from
.groups
import
GroupDescription
...
...
@@ -21,6 +23,10 @@ QUESTIONNAIRE = 'questionnaire'
FAILED
=
'failed'
REJECTED
=
'rejected'
TARGET_CHOICES
=
(
(
DEPLOYED
,
'Deployed'
),
(
NOT_DEPLOYED
,
'Not Deployed'
),
)
STATE_CHOICES
=
(
(
DEPLOYMENT_PENDING
,
'Deployment Pending'
),
(
REMOVAL_PENDING
,
'Removal Pending'
),
...
...
@@ -346,7 +352,7 @@ class NewDeployment(models.Model):
)
def
msg
(
self
,
msg
):
return
'[
Deploy:
{}] {}'
.
format
(
self
,
msg
)
return
'[{}] {}'
.
format
(
self
,
msg
)
def
_set_target
(
self
,
target
):
self
.
state_target
=
target
...
...
@@ -355,12 +361,12 @@ class NewDeployment(models.Model):
def
__str__
(
self
):
if
self
.
service
is
not
None
:
return
'{}:{}#{}'
.
format
(
return
'
SVC-Dep: (
{}:{}
)
#{}'
.
format
(
self
.
service
,
self
.
user
,
self
.
id
,
)
return
'{}:{}#{}'
.
format
(
return
'
VO-Dep: (
{}:{}
)
#{}'
.
format
(
self
.
group
,
self
.
user
,
self
.
id
,
...
...
@@ -421,6 +427,23 @@ class NewDeploymentStateItem(models.Model):
def
group
(
self
):
return
self
.
parent
.
group
# starts tracking this the credential for this item
def
add_credential
(
self
,
credential
):
if
settings
.
DEBUG_CREDENTIALS
:
LOGGER
.
debug
(
'add_credential: %s %s'
,
self
,
credential
)
CredentialState
.
get_credential_state
(
credential
,
self
,
)
def
remove_credential
(
self
,
credential
):
if
settings
.
DEBUG_CREDENTIALS
:
LOGGER
.
debug
(
'remove_credential: %s %s'
,
self
,
credential
)
# TODO implement
# what is needs to be done here?
pass
@
classmethod
def
get_state_item
(
cls
,
parent
=
None
,
site
=
None
,
service
=
None
):
try
:
...
...
@@ -429,7 +452,7 @@ class NewDeploymentStateItem(models.Model):
site
=
site
,
service
=
service
,
)
LOGGER
.
debug
(
'get_state_item: item already exists'
)
#
LOGGER.debug('get_state_item: item already exists')
return
item
except
cls
.
DoesNotExist
:
...
...
@@ -442,11 +465,9 @@ class NewDeploymentStateItem(models.Model):
# start tracking the states of the users ssh keys
for
key
in
parent
.
user
.
ssh_keys
.
all
():
CredentialState
.
get_credential_state
(
key
,
item
,
)
LOGGER
.
debug
(
item
.
msg
(
'created'
))
item
.
add_credential
(
key
)
LOGGER
.
debug
(
'get_state_item: created %s'
,
item
)
return
item
# STATE TRANSITIONS
...
...
@@ -547,8 +568,7 @@ class NewDeploymentStateItem(models.Model):
def
set_onroute_credential_states
(
self
,
state
):
for
credential_state
in
self
.
get_onroute_credential_states
().
all
():
credential_state
.
state
=
state
credential_state
.
save
()
credential_state
.
set
(
state
)
# resets all client sent values
def
_reset
(
self
):
...
...
@@ -557,7 +577,7 @@ class NewDeploymentStateItem(models.Model):
self
.
message
=
''
def
msg
(
self
,
msg
):
return
'[
DSItem:
{}] {}'
.
format
(
self
,
msg
)
return
'[{}] {}'
.
format
(
self
,
msg
)
def
_set_state
(
self
,
state
,
publish
=
True
):
self
.
set_onroute_credential_states
(
state
)
...
...
@@ -568,14 +588,8 @@ class NewDeploymentStateItem(models.Model):
self
.
parent
.
publish_to_user
()
def
__str__
(
self
):
if
self
.
group
is
not
None
:
return
'{}:{}@{}#{}'
.
format
(
self
.
group
,
self
.
service
,
self
.
site
,
self
.
id
,
)
return
'{}:@{}#{}'
.
format
(
return
'Item: ({}:{}:{})#{}'
.
format
(
self
.
parent
.
id
,
self
.
service
,
self
.
site
,
self
.
id
,
...
...
@@ -610,7 +624,8 @@ class CredentialState(models.Model):
target
=
target
,
)
except
cls
.
DoesNotExist
:
LOGGER
.
debug
(
'new credential state for %s / %s'
,
credential
,
target
)
if
settings
.
DEBUG_CREDENTIALS
:
LOGGER
.
debug
(
'new credential state for %s / %s'
,
credential
,
target
)
new_state
=
cls
(
credential
=
credential
,
target
=
target
,
...
...
@@ -622,7 +637,8 @@ class CredentialState(models.Model):
def
set
(
self
,
state
):
self
.
state
=
state
self
.
save
()
LOGGER
.
debug
(
'%s state changed to: %s'
,
self
,
state
)
if
settings
.
DEBUG_CREDENTIALS
:
LOGGER
.
debug
(
'%s state changed to: %s'
,
self
,
state
)
def
__str__
(
self
):
return
'{}@{}'
.
format
(
...
...
feudal/backend/models/serializers/clients.py
View file @
a5a4daa4
...
...
@@ -22,7 +22,11 @@ class UserSerializer(serializers.ModelSerializer):
class
Meta
:
model
=
models
.
User
fields
=
[
'email'
,
'groups'
,
'userinfo'
]
fields
=
[
'email'
,
'groups'
,
'userinfo'
,
]
class
NewDeploymentSerializer
(
serializers
.
ModelSerializer
):
...
...
@@ -52,4 +56,6 @@ class NewDeploymentsSerializer(serializers.Serializer):
class
RabbitMQInstanceSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
models
.
RabbitMQInstance
fields
=
[
'vhost'
]
fields
=
[
'vhost'
,
]
feudal/backend/models/users.py
View file @
a5a4daa4
...
...
@@ -13,6 +13,7 @@ from ..auth.v1.models import OIDCConfig
LOGGER
=
logging
.
getLogger
(
__name__
)
def
user_info_default
():
return
{}
...
...
@@ -213,8 +214,9 @@ class User(AbstractUser):
# oidcuser: deploy the according credentials
if
self
.
user_type
==
'oidcuser'
:
for
dep
in
self
.
deployments
.
all
():
dep
.
activate
()
#for dep in self.deployments.all():
# dep.activate()
pass
def
deactivate
(
self
):
if
not
self
.
_is_active
:
...
...
@@ -224,13 +226,25 @@ class User(AbstractUser):
self
.
is_active
=
False
self
.
_is_active
=
False
self
.
save
()
LOGGER
.
info
(
self
.
msg
(
'deactivated'
))
LOGGER
.
debug
(
self
.
msg
(
'deactivating'
))
# oidcuser: remove all credentials
if
self
.
user_type
==
'oidcuser'
:
self
.
deployments_remove_all
()
LOGGER
.
info
(
self
.
msg
(
'deactivated'
))
for
dep
in
self
.
deployments
.
all
():
dep
.
user_remove
()
def
deployments_remove_all
(
self
):
LOGGER
.
debug
(
'Removing all deployments of user %s'
,
self
)
sites
=
[]
# find which sites need to be notified
for
dep
in
self
.
deployments
.
all
():
for
state_item
in
dep
.
state_items
.
all
():
if
state_item
.
state
!=
'not_deployed'
:
sites
.
append
(
state_item
.
site
)
def
update_userinfo_groups
(
self
,
userinfo
):
changed
=
False
...
...
@@ -239,16 +253,13 @@ class User(AbstractUser):
# check if groups were removed
for
group
in
self
.
groups
.
all
():
if
group
.
name
not
in
groups
:
LOGGER
.
info
(
self
.
msg
(
'User left the group %s'
),
group
)
self
.
groups
.
remove
(
group
)
# remove group from user and deactivate deployments
for
dep
in
self
.
deployments
.
filter
(
group
=
group
):
LOGGER
.
info
(
dep
.
msg
(
'Deactivating, as user left the group'
),
group
)
dep
.
deactivate
()
# TRIGGER
self
.
user_changed_group_removed
(
group
)
if
not
changed
:
changed
=
True
self
.
groups
.
remove
(
group
)
changed
=
True
# check if groups were added
for
group_name
in
groups
:
...
...
@@ -260,11 +271,10 @@ class User(AbstractUser):
if
not
self
.
groups
.
filter
(
name
=
group_name
).
exists
():
LOGGER
.
info
(
self
.
msg
(
'User is now in the group %s'
),
group
)
self
.
groups
.
add
(
group
)
for
dep
in
self
.
deployments
.
filter
(
group
=
group
):
dep
.
activate
()
if
not
changed
:
changed
=
True
self
.
user_changed_group_added
(
group
)
changed
=
True
except
Group
.
DoesNotExist
:
LOGGER
.
info
(
'New group from IdP: %s'
,
group_name
)
...
...
@@ -272,23 +282,33 @@ class User(AbstractUser):
group
.
save
()
self
.
groups
.
add
(
group
)
for
dep
in
self
.
deployments
.
filter
(
group
=
group
):
LOGGER
.
info
(
dep
.
msg
(
'Reactivating, as user is back in the group'
),
group
)
dep
.
activate
()
# TRIGGER
self
.
user_changed_group_added
(
group
)
if
not
changed
:
changed
=
True
changed
=
True
return
changed
# returns True if any keys changed
def
update_userinfo_ssh_key
(
self
,
userinfo
):
unity_key_value
=
userinfo
.
get
(
'ssh_key'
,
''
)
idp_key_name
=
'ssh_key'
unity_key_name
=
'unity_key'
unity_key_value
=
userinfo
.
get
(
idp_key_name
,
''
)
try
:
key
=
self
.
_ssh_keys
.
get
(
name
=
unity_key_name
)
if
idp_key_name
not
in
userinfo
:
self
.
user_changed_key_changed
(
key
)
key
.
delete_key
()
return
True
if
key
.
key
!=
unity_key_value
:
LOGGER
.
debug
(
'unity_key of user %s changed'
,
self
)
key
.
delete_key
()
key
=
SSHPublicKey
(
name
=
unity_key_name
,
...
...
@@ -296,13 +316,17 @@ class User(AbstractUser):
user
=
self
,
)
key
.
save
()
# changed
self
.
user_changed_key_changed
(
key
)
return
True
# not changed
return
False
except
SSHPublicKey
.
DoesNotExist
:
if
idp_key_name
not
in
userinfo
:
return
False
key
=
SSHPublicKey
(
name
=
unity_key_name
,
key
=
unity_key_value
,
...
...
@@ -310,7 +334,8 @@ class User(AbstractUser):
)
key
.
save
()
# changed
self
.
user_changed_key_added
(
key
)
return
True
def
update_userinfo
(
self
,
userinfo
):
...
...
@@ -335,15 +360,73 @@ class User(AbstractUser):
changed
=
True
if
changed
:
LOGGER
.
debug
(
'update_userinfo caused changes to the user'
)
self
.
user_changed
()
# TODO implement
# Call if the user or its keys are changed
def
user_changed
(
self
):
LOGGER
.
debug
(
'
U
ser
changed
. Propagating changes
'
)
LOGGER
.
info
(
'
u
ser
_
changed'
)
pass
def
sanity_check
(
self
):
for
dep
in
self
.
deployments
.
all
():
LOGGER
.
debug
(
'User has a deployment %s with target %s'
,
dep
,
dep
.
state_target
)
for
state_item
in
dep
.
state_items
.
all
():
LOGGER
.
debug
(
'User has a state item for %s'
,
state_item
.
service
)
for
credential_state
in
state_item
.
credential_states
.
all
():
if
credential_state
.
credential
is
None
:
LOGGER
.
debug
(
'Credential state exists for null key -> we have to update the deployment so the according key is deleted'
)
else
:
LOGGER
.
debug
(
'User has a credential state for %s'
,
credential_state
.
credential
)
for
ssh_key
in
self
.
ssh_keys
.
all
():
try
:
state_item
.
credential_states
.
get
(
key
=
ssh_key
,
)
except
:
LOGGER
.
debug
(
'ssh key %s has no credential_state! -> we possibly need to deploy this key'
,
ssh_key
)
# TODO implement all user_changed_ triggers
# The user_changed methods are triggerd in user_changed
# They serve to assure the correct state at the backend and clients
#
def
user_changed_key_added
(
self
,
key
):
LOGGER
.
debug
(
'user_changed_key_added: %s %s'
,
self
,
key
)
for
dep
in
self
.
deployments
.
all
():
LOGGER
.
debug
(
'user_changed_key_added: need to add key to deployment %s'
,
dep
)
def
user_changed_key_changed
(
self
,
key
):
LOGGER
.
debug
(
'user_changed_key_changed: %s %s'
,
self
,
key
)
for
credential_state
in
key
.
credential_states
.
all
():
LOGGER
.
debug
(
'user_changed_key_changed: need to handle credential state %s'
,
credential_state
)
def
user_changed_key_removed
(
self
,
key
):
LOGGER
.
debug
(
'user_changed_key_removed: %s %s'
,
self
,
key
)
for
credential_state
in
key
.
credential_states
.
all
():
LOGGER
.
debug
(
'user_changed_key_removed: need to handle credential state %s'
,
credential_state
)
# delete accordingly
def
user_changed_group_added
(
self
,
group
):
LOGGER
.
debug
(
'user_changed_group_added: %s %s'
,
self
,
group
)
# check if the user has deactivated deployments for this exact group
# if yes: reactivate the deployments
for
dep
in
self
.
deployments
.
filter
(
group
=
group
):
LOGGER
.
debug
(
'user_changed_group_added: need to activate deployment %s'
,
dep
)
def
user_changed_group_removed
(
self
,
group
):
LOGGER
.
debug
(
'user_changed_group_removed: %s %s'
,
self
,
group
)
# check if the user has deployments which need member ship of this group
# if yes remove them
for
dep
in
self
.
deployments
.
filter
(
group
=
group
):
LOGGER
.
debug
(
'user_changed_group_removed: need to deactivate deployment %s'
,
dep
)
class
SSHPublicKey
(
models
.
Model
):
name
=
models
.
CharField
(
...
...
@@ -366,14 +449,10 @@ class SSHPublicKey(models.Model):
editable
=
False
,
)
# does not directly delete the key if the key is deployed or removen
# somewhere
# the receiver 'delete_removen_ssh_key' does the actual deletion
def
delete_key
(
self
):
# LOGGER.info(self.msg('Deletion of key started'))
# self.deleted = True
# self.save()
LOGGER
.
info
(
'Direct deletion of SSH key'
)
LOGGER
.
info
(
'Deleting SSH key %s'
,
self
.
name
)
for
credential_state
in
self
.
credential_states
.
all
():
credential_state
.
set
(
'removal_pending'
)
self
.
delete
()
# we do not update the user object from here: update_userinfo does that anyway
...
...
feudal/backend/views/clients.py
View file @
a5a4daa4
...
...
@@ -7,7 +7,7 @@ from rest_framework import generics, views
from
rest_framework.authentication
import
BasicAuthentication
from
rest_framework.response
import
Response
from
..models.serializers.
clients
import
NewDeploymentSerializer
from
..models.serializers.
webpage
import
NewDeploymentSerializer
from
..models.serializers.clients
import
RabbitMQInstanceSerializer
from
..
import
models
...
...
feudal/backend/views/webpage.py
View file @
a5a4daa4
...
...
@@ -3,6 +3,7 @@ import logging
from
django.contrib.auth
import
logout
from
django.contrib.auth.models
import
Group
from
django.conf
import
settings
from
django.shortcuts
import
get_object_or_404
from
rest_framework
import
status
from
rest_framework
import
views
...
...
@@ -79,13 +80,18 @@ class SSHPublicKeyView(views.APIView):
if
'type'
in
request
.
data
:
if
request
.
data
[
'type'
]
==
'remove'
:
if
'id'
in
request
.
data
:
key
=
get_object_or_404
(
models
.
SSHPublicKey
,
id
=
request
.
data
[
'id'
]
id
=
request
.
data
[
'id'
]
,
)
# we do not delete ssh keys directly, as we need to keep track
# of them until all clients have also deleted them
key
.
delete_key
()
request
.
user
.
user_changed_key_removed
(
key
)
return
Response
({
'deleted'
:
True
,
})
...
...
@@ -97,6 +103,9 @@ class SSHPublicKeyView(views.APIView):
key
=
request
.
data
[
'key'
][
'key'
],
)
key
.
save
()
request
.
user
.
user_changed_key_added
(
key
)
return
Response
(
model_serializers
.
SSHPublicKeySerializer
(
key
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment