Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
J
jumpserver
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ops
jumpserver
Commits
9b350920
Commit
9b350920
authored
Feb 28, 2019
by
ibuler
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[Update] 修改authentication目录结构
parent
6700dc96
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
78 additions
and
65 deletions
+78
-65
auth.py
apps/authentication/api/auth.py
+3
-24
__init__.py
apps/authentication/backends/__init__.py
+0
-0
api.py
apps/authentication/backends/api.py
+0
-0
ldap.py
apps/authentication/backends/ldap.py
+0
-0
__init__.py
apps/authentication/backends/openid/__init__.py
+6
-0
backends.py
apps/authentication/backends/openid/backends.py
+7
-4
middleware.py
apps/authentication/backends/openid/middleware.py
+6
-3
models.py
apps/authentication/backends/openid/models.py
+2
-1
signals.py
apps/authentication/backends/openid/signals.py
+5
-0
tests.py
apps/authentication/backends/openid/tests.py
+0
-0
urls.py
apps/authentication/backends/openid/urls.py
+11
-0
utils.py
apps/authentication/backends/openid/utils.py
+2
-3
views.py
apps/authentication/backends/openid/views.py
+7
-8
radius.py
apps/authentication/backends/radius.py
+0
-0
__init__.py
apps/authentication/ldap/__init__.py
+0
-0
signals.py
apps/authentication/signals.py
+0
-1
signals_handlers.py
apps/authentication/signals_handlers.py
+11
-4
view_urls.py
apps/authentication/urls/view_urls.py
+2
-4
__init__.py
apps/authentication/views/__init__.py
+0
-1
settings.py
apps/jumpserver/settings.py
+9
-8
__init__.py
apps/users/api/__init__.py
+0
-1
auth.py
apps/users/api/auth.py
+0
-3
api_urls.py
apps/users/urls/api_urls.py
+7
-0
No files found.
apps/authentication/api/auth.py
View file @
9b350920
...
@@ -24,8 +24,10 @@ from users.utils import (
...
@@ -24,8 +24,10 @@ from users.utils import (
)
)
from
users.hands
import
Asset
,
SystemUser
from
users.hands
import
Asset
,
SystemUser
logger
=
get_logger
(
__name__
)
logger
=
get_logger
(
__name__
)
__all__
=
[
'UserAuthApi'
,
'UserConnectionTokenApi'
,
'UserOtpAuthApi'
,
]
class
UserAuthApi
(
RootOrgViewMixin
,
APIView
):
class
UserAuthApi
(
RootOrgViewMixin
,
APIView
):
...
@@ -146,29 +148,6 @@ class UserConnectionTokenApi(RootOrgViewMixin, APIView):
...
@@ -146,29 +148,6 @@ class UserConnectionTokenApi(RootOrgViewMixin, APIView):
return
super
()
.
get_permissions
()
return
super
()
.
get_permissions
()
class
UserToken
(
APIView
):
permission_classes
=
(
AllowAny
,)
def
post
(
self
,
request
):
if
not
request
.
user
.
is_authenticated
:
username
=
request
.
data
.
get
(
'username'
,
''
)
email
=
request
.
data
.
get
(
'email'
,
''
)
password
=
request
.
data
.
get
(
'password'
,
''
)
public_key
=
request
.
data
.
get
(
'public_key'
,
''
)
user
,
msg
=
check_user_valid
(
username
=
username
,
email
=
email
,
password
=
password
,
public_key
=
public_key
)
else
:
user
=
request
.
user
msg
=
None
if
user
:
token
=
user
.
create_bearer_token
(
request
)
return
Response
({
'Token'
:
token
,
'Keyword'
:
'Bearer'
},
status
=
200
)
else
:
return
Response
({
'error'
:
msg
},
status
=
406
)
class
UserOtpAuthApi
(
RootOrgViewMixin
,
APIView
):
class
UserOtpAuthApi
(
RootOrgViewMixin
,
APIView
):
permission_classes
=
(
AllowAny
,)
permission_classes
=
(
AllowAny
,)
serializer_class
=
UserSerializer
serializer_class
=
UserSerializer
...
...
apps/authentication/
radiu
s/__init__.py
→
apps/authentication/
backend
s/__init__.py
View file @
9b350920
File moved
apps/authentication/
authentication
.py
→
apps/authentication/
backends/api
.py
View file @
9b350920
File moved
apps/authentication/
ldap/backends
.py
→
apps/authentication/
backends/ldap
.py
View file @
9b350920
File moved
apps/authentication/backends/openid/__init__.py
0 → 100644
View file @
9b350920
# -*- coding: utf-8 -*-
#
from
.backends
import
*
from
.middleware
import
*
from
.utils
import
*
apps/authentication/openid/backends.py
→
apps/authentication/
backends/
openid/backends.py
View file @
9b350920
...
@@ -4,16 +4,19 @@
...
@@ -4,16 +4,19 @@
from
django.contrib.auth
import
get_user_model
from
django.contrib.auth
import
get_user_model
from
django.conf
import
settings
from
django.conf
import
settings
from
.
import
client
from
common.utils
import
get_logger
from
common.utils
import
get_logger
from
authentication.openid.models
import
OIDT_ACCESS_TOKEN
from
.utils
import
new_client
from
.models
import
OIDT_ACCESS_TOKEN
UserModel
=
get_user_model
()
UserModel
=
get_user_model
()
logger
=
get_logger
(
__file__
)
logger
=
get_logger
(
__file__
)
client
=
new_client
()
BACKEND_OPENID_AUTH_CODE
=
\
'authentication.openid.backends.OpenIDAuthorizationCodeBackend'
__all__
=
[
'OpenIDAuthorizationCodeBackend'
,
'OpenIDAuthorizationPasswordBackend'
,
]
class
BaseOpenIDAuthorizationBackend
(
object
):
class
BaseOpenIDAuthorizationBackend
(
object
):
...
...
apps/authentication/openid/middleware.py
→
apps/authentication/
backends/
openid/middleware.py
View file @
9b350920
...
@@ -6,12 +6,15 @@ from django.contrib.auth import logout
...
@@ -6,12 +6,15 @@ from django.contrib.auth import logout
from
django.utils.deprecation
import
MiddlewareMixin
from
django.utils.deprecation
import
MiddlewareMixin
from
django.contrib.auth
import
BACKEND_SESSION_KEY
from
django.contrib.auth
import
BACKEND_SESSION_KEY
from
.
import
client
from
common.utils
import
get_logger
from
common.utils
import
get_logger
from
.
backends
import
BACKEND_OPENID_AUTH_CODE
from
.
utils
import
new_client
from
authentication.openid
.models
import
OIDT_ACCESS_TOKEN
from
.models
import
OIDT_ACCESS_TOKEN
BACKEND_OPENID_AUTH_CODE
=
\
'authentication.backends.openid.OpenIDAuthorizationCodeBackend'
client
=
new_client
()
logger
=
get_logger
(
__file__
)
logger
=
get_logger
(
__file__
)
__all__
=
[
'OpenIDAuthenticationMiddleware'
]
class
OpenIDAuthenticationMiddleware
(
MiddlewareMixin
):
class
OpenIDAuthenticationMiddleware
(
MiddlewareMixin
):
...
...
apps/authentication/openid/models.py
→
apps/authentication/
backends/
openid/models.py
View file @
9b350920
...
@@ -5,7 +5,8 @@ from django.db import transaction
...
@@ -5,7 +5,8 @@ from django.db import transaction
from
django.contrib.auth
import
get_user_model
from
django.contrib.auth
import
get_user_model
from
keycloak.realm
import
KeycloakRealm
from
keycloak.realm
import
KeycloakRealm
from
keycloak.keycloak_openid
import
KeycloakOpenID
from
keycloak.keycloak_openid
import
KeycloakOpenID
from
..signals
import
post_create_openid_user
from
.signals
import
post_create_openid_user
OIDT_ACCESS_TOKEN
=
'oidt_access_token'
OIDT_ACCESS_TOKEN
=
'oidt_access_token'
...
...
apps/authentication/backends/openid/signals.py
0 → 100644
View file @
9b350920
from
django.dispatch
import
Signal
post_create_openid_user
=
Signal
(
providing_args
=
(
'user'
,))
post_openid_login_success
=
Signal
(
providing_args
=
(
'user'
,
'request'
))
apps/authentication/openid/tests.py
→
apps/authentication/
backends/
openid/tests.py
View file @
9b350920
File moved
apps/authentication/backends/openid/urls.py
0 → 100644
View file @
9b350920
# -*- coding: utf-8 -*-
#
from
django.urls
import
path
from
.
import
views
urlpatterns
=
[
path
(
'login/'
,
views
.
OpenIDLoginView
.
as_view
(),
name
=
'openid-login'
),
path
(
'login/complete/'
,
views
.
OpenIDLoginCompleteView
.
as_view
(),
name
=
'openid-login-complete'
),
]
apps/authentication/
openid/__init__
.py
→
apps/authentication/
backends/openid/utils
.py
View file @
9b350920
...
@@ -4,6 +4,8 @@
...
@@ -4,6 +4,8 @@
from
django.conf
import
settings
from
django.conf
import
settings
from
.models
import
Client
from
.models
import
Client
__all__
=
[
'new_client'
]
def
new_client
():
def
new_client
():
"""
"""
...
@@ -15,6 +17,3 @@ def new_client():
...
@@ -15,6 +17,3 @@ def new_client():
client_id
=
settings
.
AUTH_OPENID_CLIENT_ID
,
client_id
=
settings
.
AUTH_OPENID_CLIENT_ID
,
client_secret
=
settings
.
AUTH_OPENID_CLIENT_SECRET
client_secret
=
settings
.
AUTH_OPENID_CLIENT_SECRET
)
)
client
=
new_client
()
apps/authentication/
views/openid
.py
→
apps/authentication/
backends/openid/views
.py
View file @
9b350920
...
@@ -3,7 +3,6 @@
...
@@ -3,7 +3,6 @@
import
logging
import
logging
from
django.urls
import
reverse
from
django.conf
import
settings
from
django.conf
import
settings
from
django.core.cache
import
cache
from
django.core.cache
import
cache
from
django.views.generic.base
import
RedirectView
from
django.views.generic.base
import
RedirectView
...
@@ -14,12 +13,12 @@ from django.http.response import (
...
@@ -14,12 +13,12 @@ from django.http.response import (
HttpResponseRedirect
HttpResponseRedirect
)
)
from
.
.openid
import
client
from
.
utils
import
new_
client
from
.
.openid.
models
import
Nonce
from
.models
import
Nonce
from
.
.signals
import
post_auth
_success
from
.
signals
import
post_openid_login
_success
logger
=
logging
.
getLogger
(
__name__
)
logger
=
logging
.
getLogger
(
__name__
)
client
=
new_client
()
__all__
=
[
'OpenIDLoginView'
,
'OpenIDLoginCompleteView'
]
__all__
=
[
'OpenIDLoginView'
,
'OpenIDLoginCompleteView'
]
...
@@ -27,8 +26,8 @@ __all__ = ['OpenIDLoginView', 'OpenIDLoginCompleteView']
...
@@ -27,8 +26,8 @@ __all__ = ['OpenIDLoginView', 'OpenIDLoginCompleteView']
class
OpenIDLoginView
(
RedirectView
):
class
OpenIDLoginView
(
RedirectView
):
def
get_redirect_url
(
self
,
*
args
,
**
kwargs
):
def
get_redirect_url
(
self
,
*
args
,
**
kwargs
):
redirect_uri
=
settings
.
BASE_SITE_URL
+
\
# Todo: 待优化
reverse
(
"authentication:openid-login-complete"
)
redirect_uri
=
settings
.
BASE_SITE_URL
+
settings
.
LOGIN_COMPLETE_URL
nonce
=
Nonce
(
nonce
=
Nonce
(
redirect_uri
=
redirect_uri
,
redirect_uri
=
redirect_uri
,
next_path
=
self
.
request
.
GET
.
get
(
'next'
)
next_path
=
self
.
request
.
GET
.
get
(
'next'
)
...
@@ -72,6 +71,6 @@ class OpenIDLoginCompleteView(RedirectView):
...
@@ -72,6 +71,6 @@ class OpenIDLoginCompleteView(RedirectView):
return
HttpResponseBadRequest
()
return
HttpResponseBadRequest
()
login
(
self
.
request
,
user
)
login
(
self
.
request
,
user
)
post_
auth
_success
.
send
(
sender
=
self
.
__class__
,
user
=
user
,
request
=
self
.
request
)
post_
openid_login
_success
.
send
(
sender
=
self
.
__class__
,
user
=
user
,
request
=
self
.
request
)
return
HttpResponseRedirect
(
nonce
.
next_path
or
'/'
)
return
HttpResponseRedirect
(
nonce
.
next_path
or
'/'
)
apps/authentication/
radius/backend
s.py
→
apps/authentication/
backends/radiu
s.py
View file @
9b350920
File moved
apps/authentication/ldap/__init__.py
deleted
100644 → 0
View file @
6700dc96
apps/authentication/signals.py
View file @
9b350920
from
django.dispatch
import
Signal
from
django.dispatch
import
Signal
post_create_openid_user
=
Signal
(
providing_args
=
(
'user'
,))
post_auth_success
=
Signal
(
providing_args
=
(
'user'
,
'request'
))
post_auth_success
=
Signal
(
providing_args
=
(
'user'
,
'request'
))
post_auth_failed
=
Signal
(
providing_args
=
(
'username'
,
'request'
,
'reason'
))
post_auth_failed
=
Signal
(
providing_args
=
(
'username'
,
'request'
,
'reason'
))
apps/authentication/signals_handlers.py
View file @
9b350920
...
@@ -6,11 +6,12 @@ from django.utils import timezone
...
@@ -6,11 +6,12 @@ from django.utils import timezone
from
django_auth_ldap.backend
import
populate_user
from
django_auth_ldap.backend
import
populate_user
from
common.utils
import
get_request_ip
from
common.utils
import
get_request_ip
from
.openid
import
client
from
.backends.openid
import
new_client
from
.tasks
import
write_login_log_async
from
.backends.openid.signals
import
(
from
.signals
import
(
post_create_openid_user
,
post_openid_login_success
post_create_openid_user
,
post_auth_success
,
post_auth_failed
)
)
from
.tasks
import
write_login_log_async
from
.signals
import
post_auth_success
,
post_auth_failed
@receiver
(
user_logged_out
)
@receiver
(
user_logged_out
)
...
@@ -23,6 +24,7 @@ def on_user_logged_out(sender, request, user, **kwargs):
...
@@ -23,6 +24,7 @@ def on_user_logged_out(sender, request, user, **kwargs):
'redirect_uri'
:
settings
.
BASE_SITE_URL
'redirect_uri'
:
settings
.
BASE_SITE_URL
})
})
client
=
new_client
()
openid_logout_url
=
"
%
s?
%
s"
%
(
openid_logout_url
=
"
%
s?
%
s"
%
(
client
.
openid_connect_client
.
get_url
(
client
.
openid_connect_client
.
get_url
(
name
=
'end_session_endpoint'
),
name
=
'end_session_endpoint'
),
...
@@ -39,6 +41,11 @@ def on_post_create_openid_user(sender, user=None, **kwargs):
...
@@ -39,6 +41,11 @@ def on_post_create_openid_user(sender, user=None, **kwargs):
user
.
save
()
user
.
save
()
@receiver
(
post_openid_login_success
)
def
on_openid_login_success
(
sender
,
user
=
None
,
request
=
None
,
**
kwargs
):
post_auth_success
.
send
(
sender
=
sender
,
user
=
user
,
request
=
request
)
@receiver
(
populate_user
)
@receiver
(
populate_user
)
def
on_ldap_create_user
(
sender
,
user
,
ldap_user
,
**
kwargs
):
def
on_ldap_create_user
(
sender
,
user
,
ldap_user
,
**
kwargs
):
if
user
and
user
.
name
!=
'admin'
:
if
user
and
user
.
name
!=
'admin'
:
...
...
apps/authentication/urls/view_urls.py
View file @
9b350920
# coding:utf-8
# coding:utf-8
#
#
from
django.urls
import
path
from
django.urls
import
path
,
include
from
..
import
views
from
..
import
views
...
@@ -9,9 +9,7 @@ app_name = 'authentication'
...
@@ -9,9 +9,7 @@ app_name = 'authentication'
urlpatterns
=
[
urlpatterns
=
[
# openid
# openid
path
(
'openid/login/'
,
views
.
OpenIDLoginView
.
as_view
(),
name
=
'openid-login'
),
path
(
'openid/'
,
include
((
'authentication.backends.openid.urls'
,
'authentication'
),
namespace
=
'openid'
)),
path
(
'openid/login/complete/'
,
views
.
OpenIDLoginCompleteView
.
as_view
(),
name
=
'openid-login-complete'
),
# login
# login
path
(
'login/'
,
views
.
UserLoginView
.
as_view
(),
name
=
'login'
),
path
(
'login/'
,
views
.
UserLoginView
.
as_view
(),
name
=
'login'
),
...
...
apps/authentication/views/__init__.py
View file @
9b350920
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
#
#
from
.openid
import
*
from
.login
import
*
from
.login
import
*
apps/jumpserver/settings.py
View file @
9b350920
...
@@ -100,7 +100,7 @@ MIDDLEWARE = [
...
@@ -100,7 +100,7 @@ MIDDLEWARE = [
'django.contrib.auth.middleware.AuthenticationMiddleware'
,
'django.contrib.auth.middleware.AuthenticationMiddleware'
,
'django.contrib.messages.middleware.MessageMiddleware'
,
'django.contrib.messages.middleware.MessageMiddleware'
,
'django.middleware.clickjacking.XFrameOptionsMiddleware'
,
'django.middleware.clickjacking.XFrameOptionsMiddleware'
,
'authentication.
openid.middleware.OpenIDAuthenticationMiddleware'
,
# openid
'authentication.
backends.openid.middleware.OpenIDAuthenticationMiddleware'
,
'jumpserver.middleware.TimezoneMiddleware'
,
'jumpserver.middleware.TimezoneMiddleware'
,
'jumpserver.middleware.DemoMiddleware'
,
'jumpserver.middleware.DemoMiddleware'
,
'jumpserver.middleware.RequestMiddleware'
,
'jumpserver.middleware.RequestMiddleware'
,
...
@@ -343,10 +343,10 @@ REST_FRAMEWORK = {
...
@@ -343,10 +343,10 @@ REST_FRAMEWORK = {
),
),
'DEFAULT_AUTHENTICATION_CLASSES'
:
(
'DEFAULT_AUTHENTICATION_CLASSES'
:
(
# 'rest_framework.authentication.BasicAuthentication',
# 'rest_framework.authentication.BasicAuthentication',
'authentication.
authentication
.AccessKeyAuthentication'
,
'authentication.
backends.api
.AccessKeyAuthentication'
,
'authentication.
authentication
.AccessTokenAuthentication'
,
'authentication.
backends.api
.AccessTokenAuthentication'
,
'authentication.
authentication
.PrivateTokenAuthentication'
,
'authentication.
backends.api
.PrivateTokenAuthentication'
,
'authentication.
authentication
.SessionAuthentication'
,
'authentication.
backends.api
.SessionAuthentication'
,
),
),
'DEFAULT_FILTER_BACKENDS'
:
(
'DEFAULT_FILTER_BACKENDS'
:
(
'django_filters.rest_framework.DjangoFilterBackend'
,
'django_filters.rest_framework.DjangoFilterBackend'
,
...
@@ -409,12 +409,13 @@ AUTH_OPENID_REALM_NAME = CONFIG.AUTH_OPENID_REALM_NAME
...
@@ -409,12 +409,13 @@ AUTH_OPENID_REALM_NAME = CONFIG.AUTH_OPENID_REALM_NAME
AUTH_OPENID_CLIENT_ID
=
CONFIG
.
AUTH_OPENID_CLIENT_ID
AUTH_OPENID_CLIENT_ID
=
CONFIG
.
AUTH_OPENID_CLIENT_ID
AUTH_OPENID_CLIENT_SECRET
=
CONFIG
.
AUTH_OPENID_CLIENT_SECRET
AUTH_OPENID_CLIENT_SECRET
=
CONFIG
.
AUTH_OPENID_CLIENT_SECRET
AUTH_OPENID_BACKENDS
=
[
AUTH_OPENID_BACKENDS
=
[
'authentication.openid.backends.OpenIDAuthorizationPasswordBackend'
,
'authentication.
backends.
openid.backends.OpenIDAuthorizationPasswordBackend'
,
'authentication.openid.backends.OpenIDAuthorizationCodeBackend'
,
'authentication.
backends.
openid.backends.OpenIDAuthorizationCodeBackend'
,
]
]
if
AUTH_OPENID
:
if
AUTH_OPENID
:
LOGIN_URL
=
reverse_lazy
(
"authentication:openid-login"
)
LOGIN_URL
=
reverse_lazy
(
"authentication:openid:openid-login"
)
LOGIN_COMPLETE_URL
=
reverse_lazy
(
"authentication:openid:openid-login-complete"
)
AUTHENTICATION_BACKENDS
.
insert
(
0
,
AUTH_OPENID_BACKENDS
[
0
])
AUTHENTICATION_BACKENDS
.
insert
(
0
,
AUTH_OPENID_BACKENDS
[
0
])
AUTHENTICATION_BACKENDS
.
insert
(
0
,
AUTH_OPENID_BACKENDS
[
1
])
AUTHENTICATION_BACKENDS
.
insert
(
0
,
AUTH_OPENID_BACKENDS
[
1
])
...
...
apps/users/api/__init__.py
View file @
9b350920
...
@@ -2,5 +2,4 @@
...
@@ -2,5 +2,4 @@
#
#
from
.user
import
*
from
.user
import
*
from
.auth
import
*
from
.group
import
*
from
.group
import
*
apps/users/api/auth.py
deleted
100644 → 0
View file @
6700dc96
# -*- coding: utf-8 -*-
#
apps/users/urls/api_urls.py
View file @
9b350920
...
@@ -5,6 +5,8 @@ from __future__ import absolute_import
...
@@ -5,6 +5,8 @@ from __future__ import absolute_import
from
django.urls
import
path
from
django.urls
import
path
from
rest_framework_bulk.routes
import
BulkRouter
from
rest_framework_bulk.routes
import
BulkRouter
from
authentication
import
api
as
auth_api
from
..
import
api
from
..
import
api
app_name
=
'users'
app_name
=
'users'
...
@@ -15,6 +17,11 @@ router.register(r'groups', api.UserGroupViewSet, 'user-group')
...
@@ -15,6 +17,11 @@ router.register(r'groups', api.UserGroupViewSet, 'user-group')
urlpatterns
=
[
urlpatterns
=
[
path
(
'connection-token/'
,
auth_api
.
UserConnectionTokenApi
.
as_view
(),
name
=
'connection-token'
),
path
(
'auth/'
,
auth_api
.
UserAuthApi
.
as_view
(),
name
=
'user-auth'
),
path
(
'otp/auth/'
,
auth_api
.
UserOtpAuthApi
.
as_view
(),
name
=
'user-otp-auth'
),
path
(
'profile/'
,
api
.
UserProfileApi
.
as_view
(),
name
=
'user-profile'
),
path
(
'profile/'
,
api
.
UserProfileApi
.
as_view
(),
name
=
'user-profile'
),
path
(
'otp/reset/'
,
api
.
UserResetOTPApi
.
as_view
(),
name
=
'my-otp-reset'
),
path
(
'otp/reset/'
,
api
.
UserResetOTPApi
.
as_view
(),
name
=
'my-otp-reset'
),
path
(
'users/<uuid:pk>/otp/reset/'
,
api
.
UserResetOTPApi
.
as_view
(),
name
=
'user-reset-otp'
),
path
(
'users/<uuid:pk>/otp/reset/'
,
api
.
UserResetOTPApi
.
as_view
(),
name
=
'user-reset-otp'
),
...
...
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