Skip to content

Commit 2aa12d4

Browse files
committed
feat(passport): add change user confirm
1 parent d08a416 commit 2aa12d4

18 files changed

Lines changed: 277 additions & 100 deletions

File tree

charts/passport/templates/_helpers.tpl

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ rbac.authorization.k8s.io/v1
1313

1414
{{/* Generate passport deployment envs */}}
1515
{{- define "passport.envs" }}
16+
{{ $redisNodeCount := .Values.redis.replicas | int }}
1617
env:
1718
- name: "TZ"
1819
value: {{ .Values.time_zone | default "UTC" | quote }}
@@ -22,6 +23,11 @@ env:
2223
{{- else }}
2324
value: http://drycc.{{ .Values.global.platform_domain }}
2425
{{- end }}
26+
- name: DRYCC_SECRET_KEY
27+
valueFrom:
28+
secretKeyRef:
29+
name: passport-creds
30+
key: django-secret-key
2531
- name: SOCIAL_AUTH_DRYCC_CONTROLLER_KEY
2632
valueFrom:
2733
secretKeyRef:
@@ -87,6 +93,21 @@ env:
8793
- name: DRYCC_DATABASE_URL
8894
value: "postgres://$(DRYCC_DATABASE_USER):$(DRYCC_DATABASE_PASSWORD)@$(DRYCC_DATABASE_SERVICE_HOST):$(DRYCC_DATABASE_SERVICE_PORT)/$(DRYCC_DATABASE_NAME)"
8995
{{- end }}
96+
{{- if eq .Values.global.redis_location "on-cluster"}}
97+
- name: DRYCC_REDIS_ADDRS
98+
value: "{{range $i := until $redisNodeCount}}drycc-redis-{{$i}}.drycc-redis.{{$.Release.Namespace}}.svc.{{$.Values.global.cluster_domain}}:6379{{if lt (add 1 $i) $redisNodeCount}},{{end}}{{end}}"
99+
{{- else if eq .Values.global.redis_location "off-cluster" }}
100+
- name: DRYCC_REDIS_ADDRS
101+
valueFrom:
102+
secretKeyRef:
103+
name: redis-creds
104+
key: addrs
105+
{{- end }}
106+
- name: DRYCC_REDIS_PASSWORD
107+
valueFrom:
108+
secretKeyRef:
109+
name: redis-creds
110+
key: password
90111
{{- range $key, $value := .Values.environment }}
91112
- name: {{ $key }}
92113
value: {{ $value | quote }}

rootfs/Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ RUN apk add --update --virtual .build-deps \
1919
openssl-dev \
2020
cargo \
2121
rust \
22+
&& ln /usr/lib/libldap.so /usr/lib/libldap_r.so \
2223
&& python3 -m venv /app/.venv \
2324
&& source /app/.venv/bin/activate \
2425
&& pip3 install --disable-pip-version-check --no-cache-dir -r /app/requirements.txt \

rootfs/Dockerfile.test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ RUN echo https://dl-cdn.alpinelinux.org/alpine/edge/testing >>/etc/apk/repositor
1717
openssl-dev \
1818
cargo \
1919
rust \
20+
&& ln /usr/lib/libldap.so /usr/lib/libldap_r.so \
2021
&& python3 -m venv /app/.venv \
2122
&& source /app/.venv/bin/activate \
2223
&& pip3 install --disable-pip-version-check --no-cache-dir -r /app/requirements.txt \

rootfs/api/serializers.py

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,13 @@
33
"""
44
import logging
55

6-
from django.conf import settings
76
from django.contrib.admin.models import LogEntry
87
from django.contrib.auth.forms import UserCreationForm
98
from django.contrib.auth.models import User
109
from oauth2_provider.models import Grant, AccessToken
1110
from oauth2_provider.oauth2_validators import OAuth2Validator
1211
from rest_framework import serializers
1312

14-
from api.exceptions import DryccException
1513
from api.utils import timestamp2datetime
1614

1715
logger = logging.getLogger(__name__)
@@ -24,28 +22,12 @@ class Meta(UserCreationForm.Meta):
2422

2523

2624
class UserSerializer(serializers.ModelSerializer):
27-
username = serializers.CharField(max_length=150, required=False)
28-
email = serializers.CharField(max_length=254, required=False)
29-
3025
class Meta:
3126
model = User
32-
fields = ('id', 'username', 'email', "first_name", "last_name",
33-
"is_staff", "is_active", "is_superuser")
34-
35-
def update(self, instance, validated_data):
36-
if settings.LDAP_ENDPOINT:
37-
raise DryccException(
38-
"You cannot change user info when ldap is enabled.")
39-
if validated_data.get('username'):
40-
qs = User.objects.filter(username=validated_data.get('username')).\
41-
exclude(username=instance.username)
42-
if qs:
43-
raise DryccException("new username already exists.")
44-
instance.username = validated_data.get('username')
45-
if validated_data.get('email'):
46-
instance.email = validated_data.get('email')
47-
instance.save()
48-
return instance
27+
fields = ('id', 'username', 'email', 'first_name', 'last_name',
28+
'is_staff', 'is_active', 'is_superuser')
29+
read_only_fields = ('id', 'username', 'is_staff', 'is_active',
30+
'is_superuser')
4931

5032

5133
class UserEmailSerializer(serializers.ModelSerializer):

rootfs/api/settings/production.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@
2121
# https://docs.djangoproject.com/en/2.2/ref/settings/#debug-propagate-exceptions
2222
DEBUG_PROPAGATE_EXCEPTIONS = True
2323
# Enable Django admin
24-
ADMIN_ENABLED = bool(os.environ.get('ADMIN_ENABLED', False))
24+
ADMIN_ENABLED = os.environ.get('ADMIN_ENABLED', 'false') != 'false'
2525
# Enable Registration
2626
# If this function is enabled, please set Django email related parameters
27-
REGISTRATION_ENABLED = bool(os.environ.get('REGISTRATION_ENABLED', False))
27+
REGISTRATION_ENABLED = os.environ.get('REGISTRATION_ENABLED', 'false') != 'false'
2828
# Silence two security messages around SSL as router takes care of them
2929
# https://docs.djangoproject.com/en/2.2/ref/checks/#security
3030
SILENCED_SYSTEM_CHECKS = [
@@ -267,6 +267,8 @@
267267
STATIC_ROOT = os.path.abspath(os.path.join(BASE_DIR, '..', 'web', 'dist', 'assets'))
268268
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
269269

270+
# Avatar URL
271+
AVATAR_URL = "https://cravatar.cn/avatar/"
270272
# see: https://django-oauth-toolkit.readthedocs.io/en/latest/oidc.html?highlight=oidc.key#creating-rsa-private-key # noqa
271273
with open('/var/run/secrets/drycc/passport/oidc-rsa-private-key') as f:
272274
OIDC_RSA_PRIVATE_KEY = f.read()
@@ -295,6 +297,22 @@
295297
'rest_framework.authentication.BasicAuthentication',
296298
)
297299

300+
# Redis Configuration
301+
DRYCC_REDIS_ADDRS = os.environ.get('DRYCC_REDIS_ADDRS', '127.0.0.1:6379').split(",")
302+
DRYCC_REDIS_PASSWORD = os.environ.get('DRYCC_REDIS_PASSWORD', '')
303+
304+
# Cache Configuration
305+
CACHES = {
306+
"default": {
307+
"BACKEND": "django_redis.cache.RedisCache",
308+
"LOCATION": ['redis://:{}@{}'.format(DRYCC_REDIS_PASSWORD, DRYCC_REDIS_ADDR) \
309+
for DRYCC_REDIS_ADDR in DRYCC_REDIS_ADDRS], # noqa
310+
"OPTIONS": {
311+
"CLIENT_CLASS": "django_redis.client.ShardClient",
312+
}
313+
}
314+
}
315+
298316
# LDAP settings taken from environment variables.
299317
LDAP_ENDPOINT = os.environ.get('LDAP_ENDPOINT', '')
300318
LDAP_BIND_DN = os.environ.get('LDAP_BIND_DN', '')
@@ -354,5 +372,5 @@
354372
DEFAULT_FROM_EMAIL = os.environ.get('DEFAULT_FROM_EMAIL', '')
355373
EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER', '')
356374
EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD', '')
357-
EMAIL_USE_TLS = os.environ.get('EMAIL_USE_TLS', True)
358-
EMAIL_USE_SSL = os.environ.get('EMAIL_USE_SSL', True)
375+
EMAIL_USE_TLS = os.environ.get('EMAIL_USE_TLS', 'false').lower() != 'false'
376+
EMAIL_USE_SSL = os.environ.get('EMAIL_USE_SSL', 'false').lower() != 'false'
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{% extends 'user/message.html' %}
2+
{% block title %}Account update successful{% endblock %}
3+
{% block message %}
4+
Your account has been update successfully.
5+
Please go to the <a href="/">main</a> page.
6+
{% endblock %}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{% autoescape off %}
2+
Hi {{ user.username }},
3+
4+
Please click on the link below to confirm your update:
5+
6+
{{ domain }}{% url 'user_update_account' uidb64=uid token=token%}
7+
{% endautoescape %}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{% extends 'user/message.html' %}
2+
{% block title %}Account update fail{% endblock %}
3+
{% block message %}
4+
The confirmation link was invalid, possibly it has already been expired.
5+
Please go to the <a href="/">main</a> page.
6+
{% endblock %}

rootfs/api/urls.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,25 @@
33
from rest_framework.routers import DefaultRouter
44

55
from api import views
6-
from api.views import RegistrationView, ActivateAccount, RegistrationDoneView, \
7-
ActivateAccountDoneView, ActivateAccountFailView, LoginDoneView
86

97
router = DefaultRouter(trailing_slash=False)
108

119
urlpatterns = [
1210
re_path(r'^', include(router.urls)),
1311
re_path(r'^info/?$',
1412
views.UserDetailView.as_view({'get': 'retrieve', 'put': 'update'})),
15-
re_path(r'registration/?$', RegistrationView.as_view(), name='registration'),
13+
re_path(r'update/(?P<uidb64>.+)/(?P<token>.+)/?$',
14+
views.UpdateAccount.as_view(), name='user_update_account'),
15+
re_path(r'^avatar/(?P<username>[-_\w]+)/?$',
16+
views.UserAvatarViewSet.as_view({'get': 'avatar'})),
17+
re_path(r'registration/?$', views.RegistrationView.as_view(), name='registration'),
1618
re_path(r'activate/(?P<uidb64>.+)/(?P<token>.+)/?$',
17-
ActivateAccount.as_view(), name='user_activate_account'),
18-
re_path(r'registration/done/?$', RegistrationDoneView.as_view(),
19+
views.ActivateAccount.as_view(), name='user_activate_account'),
20+
re_path(r'registration/done/?$', views.RegistrationDoneView.as_view(),
1921
name='user_registration_done'),
20-
re_path(r'activate/done/?$', ActivateAccountDoneView.as_view(),
22+
re_path(r'activate/done/?$', views.ActivateAccountDoneView.as_view(),
2123
name='user_activate_account_done'),
22-
re_path(r'activate/fail/?$', ActivateAccountFailView.as_view(),
24+
re_path(r'activate/fail/?$', views.ActivateAccountFailView.as_view(),
2325
name='user_activate_account_done'),
2426
re_path(r'password_reset/?$', views.UserPasswordResetView.as_view(),
2527
name='user_password_reset'),
@@ -33,7 +35,7 @@
3335
views.UserPasswordResetCompleteView.as_view(),
3436
name='user_password_reset_complete'),
3537
re_path(r'login/?$', views.UserLoginView.as_view(), name='user_login'),
36-
re_path(r'login/done/?$', LoginDoneView.as_view(), name='login_done'),
38+
re_path(r'login/done/?$', views.LoginDoneView.as_view(), name='login_done'),
3739
re_path(r'logout/?$', views.UserLogoutView.as_view(), name='user_logout'),
3840

3941
re_path(r'tokens/?$',

rootfs/api/utils.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,12 @@ def __decorator(request, *args, **kwargs):
3535
class TokenGenerator(PasswordResetTokenGenerator):
3636
def _make_hash_value(self, user, timestamp):
3737
return (
38-
six.text_type(user.pk) + six.text_type(timestamp) +
39-
six.text_type(user.is_active)
38+
six.text_type(user.pk) + six.text_type(timestamp) +
39+
six.text_type(user.is_active)
4040
)
4141

4242

43-
account_activation_token = TokenGenerator()
43+
token_generator = TokenGenerator()
4444

4545

4646
def get_local_host(request):

0 commit comments

Comments
 (0)