Beispiel #1
0
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,
        )
Beispiel #3
0
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")
Beispiel #5
0
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
Beispiel #6
0
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'})
Beispiel #7
0
 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",
    ),
]
Beispiel #10
0
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):
    """ 全ローカル変数をマスク """
Beispiel #12
0
        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")
Beispiel #14
0
        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'),
]
Beispiel #15
0
        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:
Beispiel #16
0
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)
Beispiel #18
0
        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"]