class ChangePasswordView(generics.GenericAPIView): permission_classes = (IsAuthenticated, AnyAdminClientIDPermissions) serializer_class = ChangePasswordSerializer @atomic @method_decorator(sensitive_variables('old_password', 'new_password')) def post(self, request): serializer = self.get_serializer(data=request.data) if serializer.is_valid(): old_password = serializer.validated_data['old_password'] new_password = serializer.validated_data['new_password'] try: if not FailedLoginAttempt.objects.is_locked_out( request.user, request.auth.application): if request.user.check_password(old_password): FailedLoginAttempt.objects.delete_failed_attempts( request.user, request.auth.application) password_validation.validate_password(new_password, request.user) request.user.set_password(new_password) request.user.save() return Response(status=status.HTTP_204_NO_CONTENT) else: FailedLoginAttempt.objects.add_failed_attempt( request.user, request.auth.application) errors = {'old_password': [_('You’ve entered an incorrect password')]} except ValidationError as e: errors = {'new_password': e.error_list} else: errors = serializer.errors return Response( data={'errors': errors}, status=status.HTTP_400_BAD_REQUEST, )
class ChangePasswordWithCodeView(generics.GenericAPIView): permission_classes = () serializer_class = ChangePasswordWithCodeSerializer @atomic @method_decorator(sensitive_variables('new_password')) def post(self, request, code): serializer = self.get_serializer(data=request.data) if serializer.is_valid(): new_password = serializer.validated_data['new_password'] try: user = PasswordChangeRequest.objects.get(code=code).user password_validation.validate_password(new_password, user) user.set_password(new_password) user.save() return Response(status=status.HTTP_204_NO_CONTENT) except PasswordChangeRequest.DoesNotExist: return Response(status=status.HTTP_404_NOT_FOUND) except ValidationError as e: errors = {'new_password': e.error_list} else: errors = serializer.errors return Response( data={'errors': errors}, status=status.HTTP_400_BAD_REQUEST, )
class PasswordResetConfirmView(APIView): # We set no permission to this view (default is Authenticated) permission_classes = () parser_classes = (parsers.FormParser, parsers.MultiPartParser, parsers.JSONParser,) renderer_classes = (renderers.JSONRenderer,) serializer_class = serializers.SetPasswordSerializer token_generator = INTERNAL_SETTINGS['TOKEN_GENERATOR'] def get_user(self, pk): try: user = UserModel.objects.get(pk=pk) except (TypeError, ValueError, OverflowError, UserModel.DoesNotExist, ValidationError): user = None return user @method_decorator(never_cache) def get(self, request, pk, token, format=None): user = self.get_user(pk) if user is not None and self.token_generator.check_token(user, token): # Store the token in the session and redirect to the # password reset form at a URL without the token. That # avoids the possibility of leaking the token in the # HTTP Referer header. request.session[INTERNAL_SETTINGS['INTERNAL_RESET_SESSION_TOKEN']] = token logger.info("Password reset confirm success for pk={pk}".format(pk=pk)) return Response({'message': 'success'}) logger.info("Password reset confirm GET with invalid params for pk={pk}".format(pk=pk)) return Response({'message': 'error invalid parameters'}, status=status.HTTP_400_BAD_REQUEST) @method_decorator(sensitive_variables('password')) @method_decorator(never_cache) def post(self, request, pk, token, format=None): # replace field new_password1 and new_password2 with ***** if error log request.sensitive_post_parameters = ['new_password1', 'new_password2'] user = self.get_user(pk) if user is not None and token == INTERNAL_SETTINGS['INTERNAL_RESET_URL_TOKEN']: session_token = self.request.session.get(INTERNAL_SETTINGS['INTERNAL_RESET_SESSION_TOKEN']) if self.token_generator.check_token(user, session_token): # If the token is valid check the two passwords serializer = self.serializer_class(data=request.data) serializer.is_valid(raise_exception=True) # and set new password password = serializer.validated_data.get("new_password1") password_validation.validate_password(password, user) user.set_password(password) user.save() # Finaly del request.session[INTERNAL_SETTINGS['INTERNAL_RESET_SESSION_TOKEN']] return Response({'message': 'success'}) logger.info("Password reset confirm POST with invalid params for pk={pk}".format(pk=pk)) return Response([_('Invalid parameters')], status=status.HTTP_400_BAD_REQUEST)
def _maybe_decorate_sensitive(self, handler): '''sensitive related decorators''' if self.use_sensitive_variables_decorator: _args = self.sensitive_variables_decorator_args handler = sensitive_variables(*_args)(handler) if self.debug_dispatch_method: logger.debug("sensitive_variables decoration done") if self.use_sensitive_post_parameters_decorator: _args = self.sensitive_post_parameters_decorator_args handler = sensitive_post_parameters(*_args)(handler) if self.debug_dispatch_method: logger.debug("sensitive_post_parameters decoration done")
class MasterPasswordAuthenticationBackend(object): """Authenticate as any user against a master password whose hash is in secret.py. Forces a simple LDAP bind. """ @method_decorator(sensitive_variables("password")) def authenticate(self, username=None, password=None): """Authenticate a username-password pair. Creates a new user if one is not already in the database. Args: username The username of the `User` to authenticate. password The master password. Returns: `User` """ if check_password(password, settings.MASTER_PASSWORD): try: user = User.get_user(username=username) except User.DoesNotExist: logger.debug("Master password correct, user does not exist") return None logger.debug("Authentication with master password successful") return user logger.debug("Master password authentication failed") return None def get_user(self, user_id): """Returns a user, given his or her user id. Required for a custom authentication backend. Args: user_id The user id of the user to fetch. Returns: User or None """ try: return User.get_user(id=user_id) except User.DoesNotExist: return None
class PasswordChangeView(APIView): parser_classes = (parsers.FormParser, parsers.MultiPartParser, parsers.JSONParser,) renderer_classes = (renderers.JSONRenderer,) serializer_class = serializers.PasswordChangeSerializer @method_decorator(sensitive_variables('password')) @method_decorator(never_cache) def post(self, request, format=None): request.sensitive_post_parameters = ['old_password', 'new_password1', 'new_password2'] serializer = self.serializer_class(data=request.data, user=request.user) serializer.is_valid(raise_exception=True) # and set new password password = serializer.validated_data.get("new_password1") password_validation.validate_password(password, request.user) request.user.set_password(password) request.user.save() logger.info("Password change POST for pk={pk}".format(pk=request.user.pk)) return Response({'message': 'success'})
def as_view(cls, **kwargs): """ Optionally wrap the base view in django.views.decorators.debug.sensitive_variables(). """ # Normalize the setting. variables = cls.sensitive_variables if isinstance(variables, six.string_types): variables = (variables,) elif isinstance(variables, collections.Iterable): variables = tuple(variables) elif variables: variables = () else: variables = None view = super(SensitiveVariables, cls).as_view(**kwargs) return ( debug.sensitive_variables(*variables)(view) if variables is not None else view)
class RegisterView(View): form_class = UserForm template_name = 'register.html' def get(self, request): form = self.form_class(None) return render(request, self.template_name, {'form': form}) @method_decorator(sensitive_variables()) @method_decorator(sensitive_post_parameters()) def post(self, request): form = self.form_class(request.POST) if form.is_valid() and form.cleaned_data['password'] == form.cleaned_data['password_confirm']: user = form.save() user.set_password(user.password) user.save() login(self.request, user) return redirect(reverse('simulator:index')) elif form.cleaned_data['password'] != form.cleaned_data['password_confirm']: form.add_error('password_confirm', 'Hasła nie są identyczne!') return render(request, self.template_name, {'form': form})
re_path( r"^proxyValidate$", views.ValidateService.as_view(allow_proxy_ticket=True), name="proxyValidate", ), re_path(r"^proxy$", views.Proxy.as_view(), name="proxy"), re_path( r"^p3/serviceValidate$", views.ValidateService.as_view(allow_proxy_ticket=False), name="p3_serviceValidate", ), re_path( r"^p3/proxyValidate$", views.ValidateService.as_view(allow_proxy_ticket=True), name="p3_proxyValidate", ), re_path(r"^samlValidate$", views.SamlValidate.as_view(), name="samlValidate"), re_path( r"^auth$", sensitive_variables("password", "secret")( sensitive_post_parameters("password", "secret")(views.Auth.as_view()) ), name="auth", ), re_path( r"^federate(?:/(?P<provider>([^/]+)))?$", views.FederateAuth.as_view(), name="federateAuth", ), ]
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin from django.contrib.messages.views import SuccessMessageMixin from rules.contrib.views import PermissionRequiredMixin from django.views.decorators import cache, csrf, debug from django.utils.decorators import method_decorator from django.views.generic import ( ListView, DetailView, CreateView, DeleteView, UpdateView, ) from .models import Vault @method_decorator(debug.sensitive_variables(), name='dispatch') class VaultListView(LoginRequiredMixin, ListView): """ Class based view to display the different safes a user has. It filters them redundantly: first by only querying the vaults belonging to the user, then by checking that the user has view permissions on them. A third permission check is done in the vault_home.html template. """ model = Vault template_name = 'vault/vault_home.html' context_object_name = 'vault' def get_queryset(self): vaults = Vault.objects.filter(owner=self.request.user) valid_vaults = [] for vault in vaults: if self.request.user.has_perm('vault.view_vault', vault):
raise Exception('Error') class FullOpenLocalVariableView(TemplateView): """ ローカル変数のマスク無し """ template_name = 'myapp/breaking_link.html' def get(self, request, *args, **kwargs): conference = 'DjangoCongress' region = 'JP' year = '2019' raise Exception @method_decorator(sensitive_variables('region', 'year'), name='dispatch') class MaskedLocalVariableView(TemplateView): """ 一部ローカル変数をマスク """ template_name = 'myapp/breaking_link.html' def get(self, request, *args, **kwargs): conference = 'DjangoCongress' region = 'JP' # マスクする year = '2019' # マスクする raise Exception @method_decorator(sensitive_variables(), name='dispatch') class AllMaskedLocalVariableView(TemplateView): """ 全ローカル変数をマスク """
name='serviceValidate' ), url( '^proxyValidate$', views.ValidateService.as_view(allow_proxy_ticket=True), name='proxyValidate' ), url('^proxy$', views.Proxy.as_view(), name='proxy'), url( '^p3/serviceValidate$', views.ValidateService.as_view(allow_proxy_ticket=False), name='p3_serviceValidate' ), url( '^p3/proxyValidate$', views.ValidateService.as_view(allow_proxy_ticket=True), name='p3_proxyValidate' ), url('^samlValidate$', views.SamlValidate.as_view(), name='samlValidate'), url( '^auth$', sensitive_variables('password', 'secret')( sensitive_post_parameters('password', 'secret')( views.Auth.as_view() ) ), name='auth' ), url("^federate(?:/(?P<provider>([^/]+)))?$", views.FederateAuth.as_view(), name='federateAuth'), ]
class AuthenticateView(FormView): """ View which can be used by API's to authenticate a username / password combo. """ form_class = forms.DecryptForm @method_decorator(csrf_exempt) def dispatch(self, request, *args, **kwargs): return super(AuthenticateView, self).dispatch(request, *args, **kwargs) def get(self, request, *args, **kwargs): # just a simple debug form return HttpResponse(""" <form method="post"> <input type="text" name="username"> <input type="password" name="password"> <input type="submit"> </form> """) @method_decorator( sensitive_post_parameters("password", "old_password", "new_password1", "new_password2")) @method_decorator(never_cache) def post(self, request, *args, **kwargs): return super(FormView, self).post(request, *args, **kwargs) @method_decorator(sensitive_variables("password")) def form_valid(self, form): portal = form.portal username = form.cleaned_data.get("username") password = form.cleaned_data.get("password") if username and password: return self.authenticate(portal, username, password) else: return JsonError( 'Missing "username" or "password" POST parameters.') def form_invalid(self, form): logger.error("Error while decrypting form: %s", form.errors.as_text()) return HttpResponseBadRequest("Bad signature") @method_decorator(sensitive_variables("password")) def authenticate(self, portal, username, password): user = django_authenticate(username=username, password=password) if user: if not user.is_active: return JsonError("User account is disabled") else: try: # Get profile deprecated in Django >= 1.7 profile = user.user_profile except models.UserProfile.DoesNotExist: return JsonError("No access to this portal") if profile.has_access(portal): user_data = construct_user_data(profile=profile) return JsonResponse({"user": user_data}) else: return JsonError("No access to this portal") else: logger.warn( "Login failed for user %s and ip %s", username, self.request.META["REMOTE_ADDR"], ) return JsonError("Login failed")
except Http404: return self.bad_password(request) if len(self.object.view_password) > 0: if not self.check_password(request, self.object.view_password): return self.bad_password(request) context = self.get_context_data(object=self.object) return self.render_to_response(context) post = get @method_decorator( [ transaction.atomic, sensitive_post_parameters("view-password", "edit-password"), sensitive_variables("view_password", "edit_password"), ], name="dispatch", ) class KinkListCreate(EditorView): def post(self, request, *args, **kwargs): list_data = json.loads(request.POST["kink-list-data"]) view_password = request.POST["view-password"] if len(view_password) > 0: view_password = make_password(view_password) else: view_password = "" edit_password = request.POST["edit-password"] if len(edit_password) > 0: edit_password = make_password(edit_password) else:
class KerberosAuthenticationBackend(object): """Authenticate using Kerberos. This is the default authentication backend. """ @staticmethod def kinit_timeout_handle(username, realm): """Check if the user exists before we throw an error. If the user does not exist in LDAP, only throw a warning. """ try: User.get_user(username=username) except User.DoesNotExist: logger.warning("kinit timed out for {}@{} (invalid user)".format( username, realm)) return logger.critical("kinit timed out for {}@{}".format(username, realm)) @staticmethod @sensitive_variables('password') def get_kerberos_ticket(username, password): """Attempts to create a Kerberos ticket for a user. Args: username The username. password The password. Returns: Boolean indicating success or failure of ticket creation """ cache = "/tmp/ion-%s" % uuid.uuid4() logger.debug("Setting KRB5CCNAME to 'FILE:{}'".format(cache)) os.environ["KRB5CCNAME"] = "FILE:" + cache try: realm = settings.CSL_REALM kinit = pexpect.spawnu("/usr/bin/kinit {}@{}".format( username, realm), timeout=settings.KINIT_TIMEOUT) kinit.expect(":") kinit.sendline(password) kinit.expect(pexpect.EOF) kinit.close() exitstatus = kinit.exitstatus except pexpect.TIMEOUT: KerberosAuthenticationBackend.kinit_timeout_handle(username, realm) exitstatus = 1 if exitstatus != 0: realm = settings.AD_REALM try: kinit = pexpect.spawnu("/usr/bin/kinit {}@{}".format( username, realm), timeout=settings.KINIT_TIMEOUT) kinit.expect(":", timeout=5) kinit.sendline(password) kinit.expect(pexpect.EOF) kinit.close() exitstatus = kinit.exitstatus except pexpect.TIMEOUT: KerberosAuthenticationBackend.kinit_timeout_handle( username, realm) exitstatus = 1 if exitstatus == 0: logger.debug("Kerberos authorized {}@{}".format(username, realm)) return True else: logger.debug("Kerberos failed to authorize {}".format(username)) if "KRB5CCNAME" in os.environ: del os.environ["KRB5CCNAME"] return False @method_decorator(sensitive_variables("password")) def authenticate(self, username=None, password=None): """Authenticate a username-password pair. Creates a new user if one is not already in the database. Args: username The username of the `User` to authenticate. password The password of the `User` to authenticate. Returns: `User` NOTE: None is returned when the user account does not exist. However, if the account exists but does not exist in LDAP, which is the case for former and future students who do not have Intranet access, a dummy user is returned that has the flag is_active=False. (The is_active property in the User class returns False when the username starts with "INVALID_USER".) """ # remove all non-alphanumerics username = re.sub('\W', '', username) krb_ticket = self.get_kerberos_ticket(username, password) if not krb_ticket: return None else: logger.debug("Authentication successful") try: user = User.get_user(username=username) except User.DoesNotExist: # Shouldn't happen logger.error( "User {} successfully authenticated but not found " "in LDAP.".format(username)) user, status = User.objects.get_or_create( username="******", id=99999) return user def get_user(self, user_id): """Returns a user, given his or her user id. Required for a custom authentication backend. Args: user_id The user id of the user to fetch. Returns: User or None """ try: return User.get_user(id=user_id) except User.DoesNotExist: return None
class ResetPasswordView(generics.GenericAPIView): permission_classes = () serializer_class = ResetPasswordSerializer immutable_users = ['transaction-uploader', 'send-money'] error_messages = { 'generic': _('There has been a system error. Please try again later'), 'not_found': _('Username doesn’t match any user account'), 'locked_out': _('Your account is locked, ' 'please contact the person who set it up'), 'no_email': _('We don’t have your email address, ' 'please contact the person who set up the account'), 'multiple_found': _('That email address matches multiple user accounts, ' 'please enter your unique username'), } def failure_response(self, errors, field=NON_FIELD_ERRORS): if isinstance(errors, str): errors = {field: [self.error_messages[errors]]} return Response( data={'errors': errors}, status=status.HTTP_400_BAD_REQUEST, ) @atomic @method_decorator(sensitive_variables('password')) def post(self, request): serializer = self.get_serializer(data=request.data) if serializer.is_valid(): user_identifier = serializer.validated_data['username'] try: user = User.objects.get_by_natural_key(user_identifier) except User.DoesNotExist: users = User.objects.filter(email__iexact=user_identifier) user_count = users.count() if user_count == 0: return self.failure_response('not_found', field='username') elif user_count > 1: return self.failure_response('multiple_found', field='username') user = users[0] if user.username in self.immutable_users: return self.failure_response('not_found', field='username') if user.is_locked_out: return self.failure_response('locked_out', field='username') if not user.email: return self.failure_response('no_email', field='username') service_name = gettext('Prisoner Money').lower() if serializer.validated_data.get('create_password'): change_request, _ = PasswordChangeRequest.objects.get_or_create( user=user) change_password_url = urlsplit( serializer.validated_data['create_password'] ['password_change_url']) query = parse_qs(change_password_url.query) query.update({ serializer.validated_data['create_password']['reset_code_param']: str(change_request.code) }) change_password_url = list(change_password_url) change_password_url[3] = urlencode(query) change_password_url = urlunsplit(change_password_url) send_email( user.email, 'mtp_auth/create_new_password.txt', capfirst( gettext('Create a new %(service_name)s password') % { 'service_name': service_name, }), context={ 'service_name': service_name, 'change_password_url': change_password_url, }, html_template='mtp_auth/create_new_password.html', anymail_tags=['new-password'], ) return Response(status=status.HTTP_204_NO_CONTENT) else: password = generate_new_password() if not password: logger.error( 'Password could not be generated; have validators changed?' ) return self.failure_response('generic') user.set_password(password) user.save() send_email( user.email, 'mtp_auth/reset_password.txt', capfirst( gettext('Your new %(service_name)s password') % { 'service_name': service_name, }), context={ 'service_name': service_name, 'username': user.username, 'password': password, }, html_template='mtp_auth/reset_password.html', anymail_tags=['reset-password'], ) return Response(status=status.HTTP_204_NO_CONTENT) else: return self.failure_response(serializer.errors)
except Http404: return self.bad_password(request) if len(self.object.view_password) > 0: if not self.check_password(request, self.object.view_password): return self.bad_password(request) context = self.get_context_data(object=self.object) return self.render_to_response(context) post = get @method_decorator( [ transaction.atomic, sensitive_post_parameters("view-password", "edit-password"), sensitive_variables("view_password", "edit_password"), ], name="dispatch", ) class KinkListCreate(EditorView): def post(self, request, *args, **kwargs): for key in ("kink-list-data", "view-password", "edit-password"): if key not in request.POST: raise SuspiciousOperation() list_data = json.loads(request.POST["kink-list-data"]) view_password = request.POST["view-password"] if len(view_password) > 0: view_password = make_password(view_password) else: view_password = "" edit_password = request.POST["edit-password"]