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
f4167cb8
Commit
f4167cb8
authored
Mar 02, 2018
by
Lukas Burgey
Browse files
Restructure the authentication
parent
11572b13
Changes
4
Hide whitespace changes
Inline
Side-by-side
django_backend/backend/auth/v1/models.py
View file @
f4167cb8
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
...
import
models
from
.
import
utils
LOGGER
=
logging
.
getLogger
(
__name__
)
...
...
@@ -24,17 +24,21 @@ class OIDCConfig(db_models.Model):
@
property
def
registration_response
(
self
):
info
=
{
"client_id"
:
self
.
client_id
,
"client_secret"
:
self
.
client_secret
}
info
=
{
'client_id'
:
self
.
client_id
,
'client_secret'
:
self
.
client_secret
}
return
RegistrationResponse
(
**
info
)
@
property
def
oidc_client
(
self
):
# create the client object if does no yet exist
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
]
@
property
...
...
@@ -65,12 +69,7 @@ def default_idp():
class
OIDCTokenAuthBackend
(
object
):
def
get_user_info
(
self
,
request
,
access_token
,
token_type
=
'Bearer'
):
try
:
idp_id
=
request
.
session
[
'idp_id'
]
except
OperationalError
:
LOGGER
.
error
(
'OperationalError: Unable to get from session'
)
raise
idp_id
=
utils
.
get_session
(
request
,
'idp_id'
,
None
)
oidc_config
=
OIDCConfig
.
objects
.
get
(
id
=
idp_id
)
req
=
Request
(
oidc_config
.
oidc_client
.
provider_info
[
'userinfo_endpoint'
]
...
...
@@ -85,23 +84,26 @@ class OIDCTokenAuthBackend(object):
if
token
is
None
:
return
None
# get the user info from the idp
user_info
=
self
.
get_user_info
(
request
,
token
)
idp_id
=
utils
.
get_session
(
request
,
'idp_id'
,
None
)
try
:
user
=
models
.
User
.
objects
.
get
(
# if we know the user we return him
oidc_config
=
OIDCConfig
.
objects
.
get
(
id
=
idp_id
)
return
oidc_config
.
users
.
get
(
sub
=
user_info
[
'sub'
]
)
return
user
except
ObjectDoesNotExist
:
# if we do not know the user yet, we create him
user
=
models
.
construct_user
(
user_info
)
user
.
save
()
return
user
return
None
def
get_user
(
self
,
user_id
):
try
:
return
models
.
User
.
objects
.
get
(
pk
=
user_id
)
except
models
.
User
.
DoesNotExist
:
return
models
.
User
.
objects
.
get
(
pk
=
user_id
)
except
ObjectDoesNotExist
:
return
None
django_backend/backend/auth/v1/utils.py
0 → 100644
View file @
f4167cb8
import
logging
from
django.db.utils
import
OperationalError
LOGGER
=
logging
.
getLogger
(
__name__
)
def
get_session
(
request
,
key
,
default
):
try
:
value
=
request
.
session
.
get
(
key
,
None
)
except
OperationalError
as
exp
:
raise
OperationalError
(
'get_session: Error getting from session: {}'
.
format
(
exp
))
if
value
is
not
None
:
return
value
return
default
def
set_session
(
request
,
key
,
value
):
try
:
value
=
request
.
session
[
key
]
=
value
except
OperationalError
as
exp
:
raise
OperationalError
(
'get_session: Error setting in session: {}'
.
format
(
exp
))
django_backend/backend/auth/v1/views.py
View file @
f4167cb8
import
json
import
logging
from
django.contrib.auth
import
authenticate
,
login
,
logout
from
django.db.utils
import
OperationalError
from
django.shortcuts
import
redirect
from
django.views
import
View
from
rest_framework
import
generics
,
views
...
...
@@ -12,6 +11,7 @@ from oic.oic.message import AuthorizationResponse
from
.models
import
OIDCConfig
,
default_idp
from
.serializers
import
AuthInfoSerializer
from
.
import
utils
LOGGER
=
logging
.
getLogger
(
__name__
)
...
...
@@ -26,51 +26,27 @@ def idp_id_from_request(request):
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'
)
raise
if
value
is
not
None
:
return
value
return
default
def
set_session
(
request
,
key
,
value
):
try
:
value
=
request
.
session
[
key
]
=
value
except
OperationalError
:
LOGGER
.
error
(
'Operational: Error setting in session'
)
raise
class
Auth
(
View
):
def
get
(
self
,
request
):
try
:
state
=
rndstr
()
idp_id
=
idp_id_from_request
(
request
)
oidc_config
=
OIDCConfig
.
objects
.
get
(
id
=
idp_id
)
set_session
(
request
,
'state'
,
state
)
set_session
(
request
,
'idp_id'
,
idp_id
)
utils
.
set_session
(
request
,
'state'
,
state
)
utils
.
set_session
(
request
,
'idp_id'
,
idp_id
)
try
:
return
redirect
(
oidc_config
.
get_auth_request
(
oidc_config
.
oidc_client
,
state
,
)
)
except
Exception
:
LOGGER
.
error
(
'Malformed oidc config: %s'
,
oidc_config
)
raise
auth_redirect
=
oidc_config
.
get_auth_request
(
oidc_config
.
oidc_client
,
state
,
)
LOGGER
.
debug
(
'redirecting user to oidc client %s'
,
oidc_config
)
return
redirect
(
auth_redirect
)
except
Exception
as
exception
:
LOGGER
.
error
(
'request: %s'
,
exception
)
LOGGER
.
error
(
'Auth: %s'
,
exception
)
# the error is deleted from the session when the state is delivered
request
.
session
[
'error'
]
=
'Server Error'
return
redirect
(
'/'
)
...
...
@@ -79,8 +55,8 @@ class Auth(View):
class
AuthCallback
(
View
):
def
get
(
self
,
request
):
try
:
state
=
get_session
(
request
,
'state'
,
None
)
idp_id
=
get_session
(
request
,
'idp_id'
,
default_idp
().
id
)
state
=
utils
.
get_session
(
request
,
'state'
,
None
)
idp_id
=
utils
.
get_session
(
request
,
'idp_id'
,
default_idp
().
id
)
oidc_config
=
OIDCConfig
.
objects
.
get
(
id
=
idp_id
)
aresp
=
oidc_config
.
oidc_client
.
parse_response
(
...
...
@@ -123,23 +99,24 @@ class AuthCallback(View):
if
user
is
None
:
# authentication failed -> "401"
LOGGER
.
error
(
'User failed to log in'
)
request
.
session
[
'error'
]
=
'Login failed'
utils
.
set_session
(
request
,
'error'
,
'Login failed'
)
# response = HttpResponse('Unauthorized', status=401)
elif
not
user
.
is_active
:
# user is deactivated -> "403"
LOGGER
.
info
(
'%s tried to log in'
,
user
)
request
.
session
[
'error'
]
=
'Account deactivated'
utils
.
set_session
(
request
,
'error'
,
'Account deactivated'
)
# response = HttpResponse('Forbidden', status=403)
else
:
# user authenticated -> back to frontend
login
(
request
,
user
)
LOGGER
.
debug
(
'
authenticated %s'
,
user
)
LOGGER
.
debug
(
'
oidc client %s authenticated user as %s'
,
oidc_config
,
user
)
response
.
set_cookie
(
'sessionid'
,
request
.
COOKIES
[
'sessionid'
])
return
response
except
Exception
as
exception
:
LOGGER
.
error
(
'request: %s'
,
exception
)
LOGGER
.
error
(
'AuthCallback: %s'
,
exception
)
# the error is deleted from the session when the state is delivered
request
.
session
[
'error'
]
=
'Server Error'
return
redirect
(
'/'
)
...
...
@@ -148,6 +125,7 @@ class AuthCallback(View):
class
LogoutView
(
views
.
APIView
):
def
post
(
self
,
request
):
LOGGER
.
debug
(
'logged out %s'
,
request
.
user
)
# TODO should we logout the user at the oidc client?
logout
(
request
)
return
Response
({})
...
...
django_backend/backend/models.py
View file @
f4167cb8
...
...
@@ -12,6 +12,7 @@ from django.db import models
from
django.db.models.signals
import
post_save
,
pre_delete
from
django.dispatch
import
receiver
from
rest_framework.authtoken.models
import
Token
from
.auth.v1.models
import
OIDCConfig
LOGGER
=
logging
.
getLogger
(
__name__
)
...
...
@@ -269,6 +270,12 @@ class User(AbstractUser):
default
=
True
,
editable
=
False
,
)
# the idp which authenticated the user
idp
=
models
.
ForeignKey
(
OIDCConfig
,
related_name
=
'users'
,
on_delete
=
models
.
CASCADE
,
)
# we hide deleted keys here
# the full list of ssh keys is self._ssh_keys
...
...
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