Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
feudal
feudalBackend
Commits
0df7203c
Commit
0df7203c
authored
Apr 20, 2018
by
Lukas Burgey
Browse files
Enhance the API usability
parent
1d8eac79
Changes
3
Hide whitespace changes
Inline
Side-by-side
django_backend/backend/auth/v1/models.py
View file @
0df7203c
...
...
@@ -68,11 +68,11 @@ def default_idp():
class
OIDCTokenAuthBackend
(
object
):
def
get_user
_
info
(
self
,
request
,
access_token
,
token_type
=
'Bearer'
):
def
get_userinfo
(
self
,
request
,
access_token
,
token_type
=
'Bearer'
):
idp_id
=
utils
.
get_session
(
request
,
'idp_id'
,
None
)
o
id
c_config
=
OIDCConfig
.
objects
.
get
(
id
=
idp_id
)
id
p
=
OIDCConfig
.
objects
.
get
(
id
=
idp_id
)
req
=
Request
(
o
id
c_config
.
oidc_client
.
provider_info
[
'userinfo_endpoint'
]
id
p
.
oidc_client
.
provider_info
[
'userinfo_endpoint'
]
)
auth
=
(
token_type
+
' '
+
access_token
)
req
.
add_header
(
'Authorization'
,
auth
)
...
...
@@ -85,32 +85,24 @@ class OIDCTokenAuthBackend(object):
return
None
# get the user info from the idp
user
_
info
=
self
.
get_user
_
info
(
request
,
token
)
userinfo
=
self
.
get_userinfo
(
request
,
token
)
idp_id
=
utils
.
get_session
(
request
,
'idp_id'
,
None
)
o
id
c_config
=
OIDCConfig
.
objects
.
get
(
id
=
idp_id
)
id
p
=
OIDCConfig
.
objects
.
get
(
id
=
idp_id
)
try
:
# if we know the user we return him
return
oidc_config
.
users
.
get
(
sub
=
user_info
[
'sub'
]
return
models
.
User
.
get_user
(
userinfo
,
idp
,
)
except
ObjectDoesNotExist
:
try
:
# if we do not know the user yet, we create him
user
=
models
.
User
.
construct_from_user_info
(
user_info
,
oidc_config
,
)
user
.
save
()
return
user
except
Exception
as
exception
:
LOGGER
.
error
(
'OIDCTokenAuthBackend: error constructing user: %s'
,
exception
)
return
None
except
Exception
as
exception
:
LOGGER
.
error
(
'OIDCTokenAuthBackend: error constructing user: %s'
,
exception
)
return
None
def
get_user
(
self
,
user_id
):
try
:
return
models
.
User
.
objects
.
get
(
user_type
=
'oidcuser'
,
pk
=
user_id
)
except
ObjectDoesNotExist
:
...
...
django_backend/backend/frontend/views.py
View file @
0df7203c
...
...
@@ -107,19 +107,10 @@ class DeploymentView(views.APIView):
id
=
request
.
data
[
'key'
],
)
# check if there is already an deployment
# if not request.user.deployments.filter(service=request_service).exists():
try
:
deployment
=
request
.
user
.
deployments
.
get
(
service
=
request_service
)
except
ObjectDoesNotExist
:
if
request_type
==
'remove'
:
return
_api_error_response
()
deployment
=
models
.
Deployment
(
user
=
request
.
user
,
service
=
request_service
,
)
deployment
.
save
()
deployment
=
models
.
Deployment
.
get_deployment
(
request
.
user
,
request_service
,
)
if
request_type
==
'add'
:
deployment
.
deploy_key
(
request_key
)
...
...
django_backend/backend/models.py
View file @
0df7203c
...
...
@@ -177,6 +177,63 @@ class User(AbstractUser):
editable
=
False
,
)
# returns the user as identified by userinfo and idp
# if the user does not exists
@
classmethod
def
get_user
(
cls
,
userinfo
,
idp
):
if
not
'sub'
in
userinfo
:
raise
Exception
(
'get_user needs a userinfo which contains the users subject'
)
query_result
=
cls
.
objects
.
filter
(
sub
=
userinfo
[
'sub'
],
idp
=
idp
,
)
if
not
query_result
.
exists
():
return
cls
.
construct_from_userinfo
(
userinfo
,
idp
)
if
len
(
query_result
)
>
1
:
return
Exception
(
'Two user instances with same subject from the same idp'
)
# TODO update the users userinfo when it changes
# TODO update the users groupinfo when it changes
return
query_result
.
first
()
@
classmethod
def
construct_from_userinfo
(
cls
,
userinfo
,
idp
):
LOGGER
.
debug
(
'User: constructing from %s'
,
userinfo
)
if
'sub'
not
in
userinfo
:
raise
Exception
(
'Missing attribute in userinfo: sub'
)
sub
=
userinfo
[
'sub'
]
if
'email'
not
in
userinfo
:
if
'name'
not
in
userinfo
:
raise
Exception
(
'Missing attributes in userinfo: email and name'
)
username
=
userinfo
[
'name'
]
else
:
username
=
userinfo
[
'email'
]
user
=
cls
(
user_type
=
'oidcuser'
,
username
=
username
,
sub
=
sub
,
idp
=
idp
,
userinfo
=
userinfo
,
)
user
.
save
()
return
user
@
classmethod
def
construct_client
(
cls
,
username
,
password
):
LOGGER
.
debug
(
'APICLIENT: new client %s'
,
username
)
client
=
cls
(
username
=
username
,
user_type
=
'apiclient'
,
)
client
.
set_password
(
password
)
return
client
# we hide deleted keys here
# the full list of ssh keys is self._ssh_keys
@
property
...
...
@@ -222,56 +279,33 @@ class User(AbstractUser):
LOGGER
.
error
(
self
.
msg
(
'already activated'
))
return
if
self
.
user_type
==
'oidcuser'
:
self
.
is_active
=
True
self
.
_is_active
=
True
self
.
save
(
)
self
.
is_active
=
True
self
.
_
is_active
=
True
self
.
save
()
LOGGER
.
info
(
self
.
msg
(
'activated'
)
)
# oidcuser: deploy the according credentials
if
self
.
user_type
==
'oidcuser'
:
for
dep
in
self
.
deployments
.
all
():
dep
.
activate
()
LOGGER
.
info
(
self
.
msg
(
'activated'
))
# oidcuser: withdraw all credentials
def
deactivate
(
self
):
if
not
self
.
_is_active
:
LOGGER
.
error
(
self
.
msg
(
'already deactivated'
))
return
self
.
is_active
=
False
self
.
_is_active
=
False
self
.
save
()
LOGGER
.
info
(
self
.
msg
(
'deactivated'
))
# oidcuser: withdraw all credentials
if
self
.
user_type
==
'oidcuser'
:
self
.
is_active
=
False
self
.
_is_active
=
False
self
.
save
()
for
dep
in
self
.
deployments
.
all
():
dep
.
deactivate
()
LOGGER
.
info
(
self
.
msg
(
'deactivated'
))
@
classmethod
def
construct_from_user_info
(
cls
,
user_info
,
idp
):
LOGGER
.
debug
(
'User: constructing from %s'
,
user_info
)
return
cls
(
sub
=
user_info
.
get
(
'sub'
,
''
),
first_name
=
user_info
.
get
(
'given_name'
,
''
),
last_name
=
user_info
.
get
(
'family_name'
,
''
),
email
=
user_info
.
get
(
'email'
,
''
),
username
=
user_info
.
get
(
'email'
,
''
),
idp
=
idp
,
userinfo
=
user_info
,
)
@
classmethod
def
construct_client
(
cls
,
username
,
password
):
LOGGER
.
debug
(
'APICLIENT: new client %s'
,
username
)
client
=
cls
(
username
=
username
,
user_type
=
'apiclient'
,
)
client
.
set_password
(
password
)
return
client
class
Site
(
models
.
Model
):
client
=
models
.
OneToOneField
(
...
...
@@ -408,6 +442,27 @@ class Deployment(models.Model):
default
=
True
,
)
# get a deployment for a user/service.
# if it does not exist it is created
@
classmethod
def
get_deployment
(
cls
,
user
,
service
):
query
=
cls
.
objects
.
filter
(
user
=
user
,
).
filter
(
service
=
service
,
)
if
query
.
exists
():
return
query
.
first
()
deployment
=
cls
(
user
=
user
,
service
=
service
,
)
deployment
.
save
()
return
deployment
@
property
def
withdrawals
(
self
):
return
self
.
tasks
.
filter
(
action
=
'withdraw'
)
...
...
@@ -452,55 +507,18 @@ class Deployment(models.Model):
# only deploy the key
def
_deploy_key
(
self
,
key
):
# delete outstanding tasks which are made obsolete by this task
for
withdrawal
in
self
.
withdrawals
.
filter
(
key
=
key
):
LOGGER
.
debug
(
withdrawal
.
msg
(
'now obsolete'
))
withdrawal
.
delete
()
# generate task
task
=
DeploymentTask
(
action
=
'deploy'
,
task
=
DeploymentTask
.
construct_deployment_task
(
deployment
=
self
,
key
=
key
,
)
task
.
save
()
LOGGER
.
debug
(
task
.
msg
(
'generated'
))
# generate task items
for
site
in
self
.
service
.
site
.
all
():
deploy
=
DeploymentTaskItem
(
task
=
task
,
site
=
site
,
)
deploy
.
save
()
LOGGER
.
debug
(
deploy
.
msg
(
'generated'
))
# publish the task
task
.
publish
()
def
_withdraw_key
(
self
,
key
):
# delete outstanding tasks which are made obsolete by this task
for
deploy
in
self
.
deploys
.
filter
(
key
=
key
):
LOGGER
.
debug
(
deploy
.
msg
(
"now obsolete"
))
deploy
.
delete
()
# generate task
task
=
DeploymentTask
(
action
=
'withdraw'
,
task
=
DeploymentTask
.
construct_withdrawal_task
(
deployment
=
self
,
key
=
key
,
)
task
.
save
()
LOGGER
.
debug
(
task
.
msg
(
'generated'
))
# generate task items
for
site
in
self
.
service
.
site
.
all
():
withdrawal
=
DeploymentTaskItem
(
task
=
task
,
site
=
site
,
)
withdrawal
.
save
()
LOGGER
.
debug
(
withdrawal
.
msg
(
'generated'
))
# publish the task
task
.
publish
()
...
...
@@ -554,6 +572,58 @@ class DeploymentTask(models.Model):
on_delete
=
models
.
CASCADE
,
)
@
classmethod
def
construct_deployment_task
(
cls
,
deployment
,
key
):
# delete outstanding tasks which are made obsolete by this task
for
withdrawal
in
deployment
.
withdrawals
.
filter
(
key
=
key
):
LOGGER
.
debug
(
withdrawal
.
msg
(
'now obsolete'
))
withdrawal
.
delete
()
task
=
cls
(
action
=
'deploy'
,
deployment
=
deployment
,
key
=
key
,
)
task
.
save
()
LOGGER
.
debug
(
task
.
msg
(
'generated'
))
# generate task items
for
site
in
deployment
.
service
.
site
.
all
():
deploy
=
DeploymentTaskItem
(
task
=
task
,
site
=
site
,
)
deploy
.
save
()
LOGGER
.
debug
(
deploy
.
msg
(
'generated'
))
return
task
@
classmethod
def
construct_withdrawal_task
(
cls
,
deployment
,
key
):
# delete outstanding tasks which are made obsolete by this task
for
withdrawal
in
deployment
.
deploys
.
filter
(
key
=
key
):
LOGGER
.
debug
(
withdrawal
.
msg
(
'now obsolete'
))
withdrawal
.
delete
()
task
=
cls
(
action
=
'withdraw'
,
deployment
=
deployment
,
key
=
key
,
)
task
.
save
()
LOGGER
.
debug
(
task
.
msg
(
'generated'
))
# generate task items
for
site
in
deployment
.
service
.
site
.
all
():
deploy
=
DeploymentTaskItem
(
task
=
task
,
site
=
site
,
)
deploy
.
save
()
LOGGER
.
debug
(
deploy
.
msg
(
'generated'
))
return
task
@
property
def
user
(
self
):
return
self
.
deployment
.
user
...
...
@@ -630,16 +700,6 @@ class DeploymentTaskItem(models.Model):
# RECEIVERS
#
@
receiver
(
post_save
,
sender
=
User
)
def
upgrade_password
(
sender
,
instance
=
None
,
created
=
False
,
**
kwargs
):
if
(
instance
is
not
None
and
instance
.
user_type
==
'apiclient'
and
not
instance
.
password
.
startswith
(
'pbkdf2_sha256'
)
):
instance
.
set_password
(
instance
.
password
)
instance
.
save
()
@
receiver
(
post_save
,
sender
=
User
)
def
deactivate_user
(
sender
,
instance
=
None
,
created
=
False
,
**
kwargs
):
if
created
:
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new 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