#StackBounty: #c# #web-services #authentication #password-encryption "Safely" store (on client side) tokens for reuse?

Bounty: 50

I’m trying to create a desktop application that will send updates to a web-service I am developing.

Ideally, the application would be configured only once and deployed to a network share. When configuring the application, the user will enter a password that is used to authenticate within the web-service. After that, a token will be created to be used on future connections.

This would allow any computer with access to the network share to just run the application (which will connect to the web-service) without entering any credentials (because the token has been saved).

Question is: How should I protect this token?

  • I know that storing it client-side will never be completely secure, but I want to make it as hard as possible for someone to gain access to the plaintext token.
  • I’m looking for an answer that, preferably, does not depend on any operational-system resource (since the application can be executed from different devices).
  • Assume I have full control over the application and the web-server
  • I’m developing the console application using C#, but I believe this to be more of a theoretical question (not tied to any specific language)

Here are a few things I’ve tried/thought about:

  • Serializing the token using something like C#’s SecureString and storing it on a file: it’s the best I’ve come with. But obviously, very trivial to reverse if someone gains access to the key file.

  • This answer suggests to use the Windows Data Protection API (DPAPI) (in C#, the ProtectedData class), but apparently, this would allow only the user who initially saved the credentials to access them, which would not work because I have to access the protected data from multiple users/devices.

  • Pass the token as a parameter to the application: this just changes where I’m going to store the token (on a batch file or OS task that calls the program, for example), but I don’t think it makes it any more secure.


Get this bounty!!!

#StackBounty: #sharepoint-server #authentication #cache #ntlm #firefox Load / NTLM Auth / cache issue in Firefox and Sharepoint on prem…

Bounty: 50

I am experiencing a weird issue when trying to access sharepoint on premises from new Firefox version (Quantum >v60.0), which is run on a windows computer.

SCENARIO:

  • firefox correctly configured for using NTLM for Auth
  • Sharepoint 2013. Firefox ESR 60
  • Sharepoint is loaded just fine in IE & Chrome, however Firefox fails to fully load the site, apparently, on a random basid, or usually after a page refresh.
  • Other windows users experience the same issue with firefox.
  • Previous versoin of firefox, like v52.0, doesnt present this issue.
  • no errors are shown in Firefox console.

The problem is that FF (>v60.0) has issues to fully load the page, or sometimes even to start to load the page. However, if I disable the Firefox cache, this issue doesnt happen at all.
If you take a look to the “network” tab from the FF developer tools, it looks like auth process stops at some point, and it is only completed if you refresh the page, or disable cache.

I can’t find out which his the problem, Any ideas? thanks very much


Get this bounty!!!

#StackBounty: #authentication #authorization #oauth Implementing OAuth 2 in a multi-tenant application

Bounty: 50

I’m currently trying to migrate a multi-tenant system from a “custom” authentication and authorization implementation to OAuth2.

The multi-tenancy model is very similar to GitHub’s structure, so I’m going to use it as the main example. Let’s assume that in the application we have users, repositories and organizations. Users have access to repositories directly, or through organizations they are members off. Depending on their access rights, users should have different permissions towards repositories and the sub-resources (like /repository/issues), or organizations and their sub-resources (/organization/members) for users who manage them. Unlike, GitHub’s OAuth2 solution, this system should be able to provide different levels of permissions across repositories or organizations (GitHub does it at a different level with a custom implementation).

The goal is to keep the logic as simple as possible, encapsulate everything in an authorization service and piggyback on OAuth2 as much as possible.

My approach was to deploy a generic OAuth2 service, and handle the permissions using dynamic scopes:

  • user:read
  • user:write
  • repo:read
  • org:read
  • repo:<repo_id>:issues:read
  • repo:<repo_id>:issues:write
  • org:<org_id>:members:read
  • org:<org_id>:members:write

This enables granular permissions for clients and users, such as an user being able to read + write issues in one of his repos, but only read in another.

While this seems to solve the problem, the main limitation is being able to request scopes. Since users would not know the ids for the repos and orgs they have access to, they are not able to request a correct list of scopes when contacting the authorization server.

In order to overcome this I considered 2 solutions:

Solution 1

  1. Issue a token for repo:read and org:read
  2. Retrieve list of repos and orgs the user has access to
  3. Issue a second token with all necesarry scopes

On a deeper thought, this turns out not to be viable since it would not support grants like implicit for authorization_code unless the authorization server would deal with this “discovery” of resources.

Solution 2

The first 2 steps are common to the first solution, while for the 3’rd step, the users would only be able to issue tenant scoped tokens. By extending the OAuth2 with a parameter identifying the tenant (/authorize?...&repo=<repo_id>), clients using authorization_code grant would have to issue tokens for every tenant. The token issued on step 1 would have to persist the identity of the user on the authorization server and eliminate the need of re-authentication when a user would switch between tenants. The downside of this approach would be that it increases the complexity of client integrations and that it might defy the standard in some way.

I’m looking for a second opinion on this, which would possibly simplify the problem and make sure the solution adheres to the standard.


Get this bounty!!!

#StackBounty: #javascript #reactjs #firebase #authentication #firebase-authentication Authentication using ReactJS

Bounty: 100

I’m new to web development and started learning ReactJS.

Till now there is no problem with building simple web apps.

Now I wanted to use authentication using Firebase.

I know how to authenticate a user using Firebase but I’m not able to get how to design frontend to restrict access to certain pages.

Previously, I used PHP and in that I used session variable and include to include the parts of HTML to show to the user.

But I don’t know how to do it in ReactJS using Firebase.

Initial and failed approach:

I thought of updating this.state.loggedIn and using that to show the component. But this is not a correct way because I’m sending both the components to display and easily we can change the state of a component using React developer extension in Chrome.

This is my main index.js code:

import React from 'react';
import ReactDOM from 'react-dom';
import Login from './components/Login/Login';
import Home from './components/Home/Home';
import fire from './components/Fire';


class App extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            loggedIn: false,
        };

        this.authListener = this.authListener.bind(this);

    }

    componentDidMount() {
        this.authListener();
    }

    authListener() {
        fire.auth().onAuthStateChanged(user => {
            if (user) {
              // User is signed in.
                console.log(user);
                this.setState({
                    loggedIn: true
                })
            } else {
              // No user is signed in.
                this.setState({
                    loggedIn: false
                });
            }
        });

    }

    render() {

        return (
            
{this.state.loggedIn ? : }
); } } ReactDOM.render( <App/>, document.getElementById('app'));

And In Login.js, I’m calling the Firebase authentication function.

Just the snippet:

fire
    .auth()
    .signInWithEmailAndPassword(this.state.email, this.state.password)
    .catch(function (error) {
          // Handle Errors here.
          var errorCode = error.code;
          var errorMessage = error.message;
          console.log(error);
          // ...
     });

The authentication is working fine and I can see it in the console log.

So, how should I do it in ReactJS + Firebase to authenticate?(Is it posible without using any other packages like react-routes etc?)

Or should I be using Cloud functions for this?


Get this bounty!!!

#StackBounty: #authentication #rest #jwt #keychain Is it safe an stateless authorization mechanism where the clear password is stored o…

Bounty: 50

Is it safe to use the following stateless authorization mechanism between a client (iOS & Android) and server?

Sign up

  1. The client provides an email and password and saves the clear password on the Keychain of iOS and using some alternative for Android.

  2. The server checks the password strength if it’s deemed strong enough the user is created on DB.

  3. The server generates a JWT token and returns it to the client. The token has an expiration time of 15 minutes.

  4. The client stores the token (maybe on the Keychain itself) and includes it for each following request on the Authorization header.

  5. For each request, the server checks the token provided (checks the signature and the expiration time). If it’s ok the request is processed, otherwise, an HTTP 401 is returned.

Sign in

  1. When the client receives an HTTP 401 from the server it means a login is required. So the app accesses to the Keychain and gets the email & password and sends it to the server (no user intervention needed).
  2. The server validates the credentials provided and if they’re valid it will repeat the Sign Up steps from 3 to 5.

Thanks to expiration time on the token, if a token is compromised it will be valid during a short time period.

If a user is logged on multiple devices and she changes her password from one device, the other devices will keep logged only for a short time period, but the clear password stored on the Keychain will not be longer valid. So a new manual login will be required, which I think it’s fine.

Which drawbacks do you see?

I’ve been thinking on using refresh token procedure to avoid store the clear password but this adds complexity and other drawbacks (for example: how to guarantee the refresh token is only used once). And as far as I’ve seen, storing the clear password on the KeyChain is secure enough:

KeyChain Services Documentation

What is the best way to maintain the login credentials in iOS?

But I also have seen other questions that do not recommend storing passwords on the device.

So I would like to hear opinions from others on this.


Get this bounty!!!

#StackBounty: #encryption #authentication #certificates #public-key-infrastructure #iot What kind of IoT devices use certificates?

Bounty: 50

I have read that PKI certificates are the main way to provide security on IoT platforms. And the common enrollment protocols for certificates are:

(CMP is the one which is used for securing LTE eNodeBs.)


Now what is not clear is what devices get the certificates? I am assuming that sensors etc are too small to get certificates and use them? So is anything used for securing sensors in IoT? I think gateways can use certs but gateways probably don’t need these protocols – they are not really IOT devices. Also what do the gateways use the certs for – is it to communicate with the cloud servers or is it to communicate with the gateways?

So what kind of IoT devices use these protocols to enroll certs? How do they use the certs? Do they use it only for authentication? Or also for encrypting communication? Are they sophisticated enough to do this?


Get this bounty!!!

#StackBounty: #oracle #oracle-12c #authentication #remote Remote login via rman working for one instance but not another

Bounty: 50

I have Oracle 12c installed on two servers. On server UAT I have an instance RMCAT that hosts an RMAN recovery catalog. On server EXT I have two instances, extdev02 and extuat01. I can use the following command on server UAT to connect to my RMCAT catalog, and target of extdev02, but when I try to connect to extuat01 it gives an ORA-01017

UAT> rman target= sys/tiger@extdev02  catalog= rmuser/tigerman@rmcat

Recovery Manager: Release 12.1.0.2.0 - Production on Wed May 30 22:59:26 2018

Copyright (c) 1982, 2014, Oracle and/or its affiliates.  All rights reserved.

connected to target database: EXTDEV02 (DBID=4287636681)
connected to recovery catalog database

RMAN> exit


Recovery Manager complete.

UAT> rman target= sys/tiger@extuat01  catalog= rmuser/tigerman@rmcat

Recovery Manager: Release 12.1.0.2.0 - Production on Wed May 30 22:59:42 2018

Copyright (c) 1982, 2014, Oracle and/or its affiliates.  All rights reserved.

RMAN-00571: ===========================================================
RMAN-00569: =============== ERROR MESSAGE STACK FOLLOWS ===============
RMAN-00571: ===========================================================
RMAN-00554: initialization of internal recovery manager package failed
RMAN-04005: error from target database:
ORA-01017: invalid username/password; logon denied

I get OK results from tnsping from UAT server to both instances on EXT, and I can connect to a non-dba user from UAT server to both instances. I recreated the Oracle password file using orapw on EXT server instance EXTUAT01 and that did not help.

Instance names are extdev02 and extuat01 on server EXT. Here are my password files on that server:

/u01/app/oracle/product/12.1.0.2/db_1/dbs> ls -o orapw*
-rw-r-----. 1 oracle 18432 Jun  1 00:07 orapwextuat01
/u01/app/oracle/product/12.1.0.2/db_0/dbs> ls -o orapw*
-rw-r-----. 1 oracle  7680 Feb  6 20:22 orapwextdev02

Note they are in two different ORACLE_HOME directories. The value for remote_login_passwordfile is EXCLUSIVE for both instances


Get this bounty!!!

#StackBounty: #python #python-3.x #security #authentication #django Let's register that Django user

Bounty: 200

Short intro

So, I’ve been using Django for a while now and thought it would be nice to start a simple application. In an ideal World, each app must have a way of letting its users register and that’s what I’m gonna do below.


Description

I’ve used the latest Django version for this project -> because of this, I couldn’t use django-registration module as it’s incompatible with the above. Apart from this, I’ve used Python 3.6.5.

What I want to do it’s common along other web applications:

  1. The user goes to the registration page and fills in the following fields:
    • first_name
    • last_name
    • email
  2. The user submits the form and receives a confirmation email with an URL containing a unique token.

  3. When the user clicks on the received link, he’s redirected to a page where he’ll set his password.

  4. When done, he’s logged in to the dashboard page.


Code

models.py

from django.contrib.auth.models import AbstractBaseUser
from django.contrib.auth.models import BaseUserManager
from django.contrib.auth.models import PermissionsMixin
from django.db import models
from django.utils.translation import ugettext_lazy as _


class UserManager(BaseUserManager):
    """
    A custom user manager to deal with emails as unique identifiers for auth
    instead of usernames. The default that's used is "UserManager"
    """

    def _create_user(self, email, password, **extra_fields):
        """
        Creates and saves a User with the given email and password.
        """

        if not email:
            raise ValueError('The Email must be set')

        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)

        return user

    def create_user(self, email, password=None, **extra_fields):
        """
        Create and save a regular User with the given email and password.
        """

        extra_fields.setdefault('is_staff', False)
        extra_fields.setdefault('is_superuser', False)

        return self._create_user(email, password, **extra_fields)

    def create_superuser(self, email, password, **extra_fields):
        """
        Create and save a SuperUser with the given email and password.
        """

        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        extra_fields.setdefault('is_active', True)

        if extra_fields.get('is_staff') is not True:
            raise ValueError('Superuser must have is_staff=True.')

        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')

        return self._create_user(email, password, **extra_fields)


class User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(unique=True, null=True, max_length=64)
    first_name = models.CharField(max_length=64)
    last_name = models.CharField(max_length=64)

    is_staff = models.BooleanField(
        _('staff status'),
        default=False,
        help_text=_('Designates whether the user can log into this site.'),
    )
    is_active = models.BooleanField(
        _('active'),
        default=True,
        help_text=_(
            'Designates whether this user should be treated as active. '
            'Unselect this instead of deleting accounts.'
        ),
    )
    USERNAME_FIELD = 'email'
    objects = UserManager()

    def __str__(self):
        return self.email

    def get_full_name(self):
        return self.email

    def get_short_name(self):
        return self.email

forms.py

from django.contrib.auth import get_user_model
from django.forms import ModelForm

User = get_user_model()


class RegistrationForm(ModelForm):

    class Meta:
        model = User
        fields = ('email', 'first_name', 'last_name')

    def save(self, commit=True):
        user = super(RegistrationForm, self).save(commit=False)
        if commit:
            user.save()
        return user

views.py

from django.contrib import messages
from django.contrib.auth import update_session_auth_hash, get_user_model, authenticate, login
from django.contrib.auth.forms import AuthenticationForm, SetPasswordForm
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.views import LoginView, LogoutView
from django.contrib.sites.shortcuts import get_current_site
from django.core.mail import EmailMessage
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.template.loader import render_to_string
from django.utils.encoding import force_bytes, force_text
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.views.generic import TemplateView, View

from .forms import RegistrationForm
from .tokens import account_activation_token

User = get_user_model()


class HomeView(LoginRequiredMixin, TemplateView):
    template_name = 'base/home.html'


class CustomLoginView(LoginView):
    template_name = 'base/login.html'
    form_class = AuthenticationForm


class CustomLogoutView(LogoutView):
    template_name = 'base/login.html'


class RegistrationView(View):

    def get(self, request):
        registration_form = RegistrationForm()
        return render(request, 'base/register.html', {'form': registration_form})

    def post(self, request):
        registration_form = RegistrationForm(request.POST)

        if registration_form.is_valid():
            user = registration_form.save(commit=False)
            user.is_active = False
            user.set_unusable_password()
            user.save()

            current_site = get_current_site(request)
            mail_subject = 'Activate your account.'
            message = render_to_string('base/activation-email.html', {
                'user': user,
                'domain': current_site.domain,
                'uid': urlsafe_base64_encode(force_bytes(user.pk)).decode(),
                'token': account_activation_token.make_token(user),
            })
            to_email = registration_form.cleaned_data.get('email')
            email = EmailMessage(
                mail_subject, message, to=[to_email]
            )
            email.send()

            return render(request, 'base/confirm-email.html')


class ActivationView(View):

    def get(self, request, uidb64, token):
        try:
            uid = force_text(urlsafe_base64_decode(uidb64))
            user = User.objects.get(pk=uid)
        except(TypeError, ValueError, OverflowError, User.DoesNotExist):
            user = None

        if user is not None and account_activation_token.check_token(user, token):
            user.is_active = True
            user.save()
            login(request, user)

            form = SetPasswordForm(request.user)
            return render(request, 'base/password-set.html', {'form': form})
        else:
            return render(request, 'base/verification-failed.html')

    def post(self, request, uidb64, token):

        try:
            uid = force_text(urlsafe_base64_decode(uidb64))
            user = User.objects.get(pk=uid)
        except(TypeError, ValueError, OverflowError, User.DoesNotExist):
            user = None

        form = SetPasswordForm(user, request.POST)

        if form.is_valid():
            user = form.save()
            update_session_auth_hash(request, user)

            user = authenticate(username=user.email, password=form.cleaned_data['new_password1'])
            login(request, user)

            return HttpResponseRedirect('/')
        else:
            messages.error(request, form.errors)
            return render(request, 'base/password-set.html', {'form': form})

urls.py

from django.conf.urls import url
from django.views.generic import TemplateView

from .views import (
    CustomLoginView, CustomLogoutView, HomeView, 
    RegistrationView, ActivationView
)

app_name = 'apps.base'

urlpatterns = [
    url(r'^$', HomeView.as_view(), name='home'),

    url(r'^login/$', CustomLoginView.as_view(), name='login'),
    url(r'^logout/$', CustomLogoutView.as_view(), name='logout'),

    url(r'^register/$', RegistrationView.as_view(), name='register'),
    url(r'^confirm_email/$', TemplateView.as_view(template_name='base/confirm-email.html'), name='confirm_email'),
    url(r'^activate/(?P<uidb64>[0-9A-Za-z_-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
        ActivationView.as_view(), name='activate'),
]

tokens.py

from django.contrib.auth.tokens import PasswordResetTokenGenerator
from django.utils import six


class TokenGenerator(PasswordResetTokenGenerator):
    def _make_hash_value(self, user, timestamp):
        return (
            six.text_type(user.pk) + six.text_type(timestamp) +
            six.text_type(user.is_active)
        )


account_activation_token = TokenGenerator()

Things that I’d like to be reviewed:

  • Django Design Patterns: Did I use the correct views / forms / models in my app? Should some of the logic be written somewhere else etc…
  • Security: Is my register system secure? If not, what can I do to make it so?
  • General feedback: Anything that comes to your mind is welcome (including criticism, ideas, improvements, cats…aliens..)


Get this bounty!!!

#StackBounty: #python #python-3.x #security #authentication #django Let's register that Django user

Bounty: 200

Short intro

So, I’ve been using Django for a while now and thought it would be nice to start a simple application. In an ideal World, each app must have a way of letting its users register and that’s what I’m gonna do below.


Description

I’ve used the latest Django version for this project -> because of this, I couldn’t use django-registration module as it’s incompatible with the above. Apart from this, I’ve used Python 3.6.5.

What I want to do it’s common along other web applications:

  1. The user goes to the registration page and fills in the following fields:
    • first_name
    • last_name
    • email
  2. The user submits the form and receives a confirmation email with an URL containing a unique token.

  3. When the user clicks on the received link, he’s redirected to a page where he’ll set his password.

  4. When done, he’s logged in to the dashboard page.


Code

models.py

from django.contrib.auth.models import AbstractBaseUser
from django.contrib.auth.models import BaseUserManager
from django.contrib.auth.models import PermissionsMixin
from django.db import models
from django.utils.translation import ugettext_lazy as _


class UserManager(BaseUserManager):
    """
    A custom user manager to deal with emails as unique identifiers for auth
    instead of usernames. The default that's used is "UserManager"
    """

    def _create_user(self, email, password, **extra_fields):
        """
        Creates and saves a User with the given email and password.
        """

        if not email:
            raise ValueError('The Email must be set')

        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)

        return user

    def create_user(self, email, password=None, **extra_fields):
        """
        Create and save a regular User with the given email and password.
        """

        extra_fields.setdefault('is_staff', False)
        extra_fields.setdefault('is_superuser', False)

        return self._create_user(email, password, **extra_fields)

    def create_superuser(self, email, password, **extra_fields):
        """
        Create and save a SuperUser with the given email and password.
        """

        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        extra_fields.setdefault('is_active', True)

        if extra_fields.get('is_staff') is not True:
            raise ValueError('Superuser must have is_staff=True.')

        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')

        return self._create_user(email, password, **extra_fields)


class User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(unique=True, null=True, max_length=64)
    first_name = models.CharField(max_length=64)
    last_name = models.CharField(max_length=64)

    is_staff = models.BooleanField(
        _('staff status'),
        default=False,
        help_text=_('Designates whether the user can log into this site.'),
    )
    is_active = models.BooleanField(
        _('active'),
        default=True,
        help_text=_(
            'Designates whether this user should be treated as active. '
            'Unselect this instead of deleting accounts.'
        ),
    )
    USERNAME_FIELD = 'email'
    objects = UserManager()

    def __str__(self):
        return self.email

    def get_full_name(self):
        return self.email

    def get_short_name(self):
        return self.email

forms.py

from django.contrib.auth import get_user_model
from django.forms import ModelForm

User = get_user_model()


class RegistrationForm(ModelForm):

    class Meta:
        model = User
        fields = ('email', 'first_name', 'last_name')

    def save(self, commit=True):
        user = super(RegistrationForm, self).save(commit=False)
        if commit:
            user.save()
        return user

views.py

from django.contrib import messages
from django.contrib.auth import update_session_auth_hash, get_user_model, authenticate, login
from django.contrib.auth.forms import AuthenticationForm, SetPasswordForm
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.views import LoginView, LogoutView
from django.contrib.sites.shortcuts import get_current_site
from django.core.mail import EmailMessage
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.template.loader import render_to_string
from django.utils.encoding import force_bytes, force_text
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.views.generic import TemplateView, View

from .forms import RegistrationForm
from .tokens import account_activation_token

User = get_user_model()


class HomeView(LoginRequiredMixin, TemplateView):
    template_name = 'base/home.html'


class CustomLoginView(LoginView):
    template_name = 'base/login.html'
    form_class = AuthenticationForm


class CustomLogoutView(LogoutView):
    template_name = 'base/login.html'


class RegistrationView(View):

    def get(self, request):
        registration_form = RegistrationForm()
        return render(request, 'base/register.html', {'form': registration_form})

    def post(self, request):
        registration_form = RegistrationForm(request.POST)

        if registration_form.is_valid():
            user = registration_form.save(commit=False)
            user.is_active = False
            user.set_unusable_password()
            user.save()

            current_site = get_current_site(request)
            mail_subject = 'Activate your account.'
            message = render_to_string('base/activation-email.html', {
                'user': user,
                'domain': current_site.domain,
                'uid': urlsafe_base64_encode(force_bytes(user.pk)).decode(),
                'token': account_activation_token.make_token(user),
            })
            to_email = registration_form.cleaned_data.get('email')
            email = EmailMessage(
                mail_subject, message, to=[to_email]
            )
            email.send()

            return render(request, 'base/confirm-email.html')


class ActivationView(View):

    def get(self, request, uidb64, token):
        try:
            uid = force_text(urlsafe_base64_decode(uidb64))
            user = User.objects.get(pk=uid)
        except(TypeError, ValueError, OverflowError, User.DoesNotExist):
            user = None

        if user is not None and account_activation_token.check_token(user, token):
            user.is_active = True
            user.save()
            login(request, user)

            form = SetPasswordForm(request.user)
            return render(request, 'base/password-set.html', {'form': form})
        else:
            return render(request, 'base/verification-failed.html')

    def post(self, request, uidb64, token):

        try:
            uid = force_text(urlsafe_base64_decode(uidb64))
            user = User.objects.get(pk=uid)
        except(TypeError, ValueError, OverflowError, User.DoesNotExist):
            user = None

        form = SetPasswordForm(user, request.POST)

        if form.is_valid():
            user = form.save()
            update_session_auth_hash(request, user)

            user = authenticate(username=user.email, password=form.cleaned_data['new_password1'])
            login(request, user)

            return HttpResponseRedirect('/')
        else:
            messages.error(request, form.errors)
            return render(request, 'base/password-set.html', {'form': form})

urls.py

from django.conf.urls import url
from django.views.generic import TemplateView

from .views import (
    CustomLoginView, CustomLogoutView, HomeView, 
    RegistrationView, ActivationView
)

app_name = 'apps.base'

urlpatterns = [
    url(r'^$', HomeView.as_view(), name='home'),

    url(r'^login/$', CustomLoginView.as_view(), name='login'),
    url(r'^logout/$', CustomLogoutView.as_view(), name='logout'),

    url(r'^register/$', RegistrationView.as_view(), name='register'),
    url(r'^confirm_email/$', TemplateView.as_view(template_name='base/confirm-email.html'), name='confirm_email'),
    url(r'^activate/(?P<uidb64>[0-9A-Za-z_-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
        ActivationView.as_view(), name='activate'),
]

tokens.py

from django.contrib.auth.tokens import PasswordResetTokenGenerator
from django.utils import six


class TokenGenerator(PasswordResetTokenGenerator):
    def _make_hash_value(self, user, timestamp):
        return (
            six.text_type(user.pk) + six.text_type(timestamp) +
            six.text_type(user.is_active)
        )


account_activation_token = TokenGenerator()

Things that I’d like to be reviewed:

  • Django Design Patterns: Did I use the correct views / forms / models in my app? Should some of the logic be written somewhere else etc…
  • Security: Is my register system secure? If not, what can I do to make it so?
  • General feedback: Anything that comes to your mind is welcome (including criticism, ideas, improvements, cats…aliens..)


Get this bounty!!!

#StackBounty: #python #python-3.x #security #authentication #django Let's register that Django user

Bounty: 200

Short intro

So, I’ve been using Django for a while now and thought it would be nice to start a simple application. In an ideal World, each app must have a way of letting its users register and that’s what I’m gonna do below.


Description

I’ve used the latest Django version for this project -> because of this, I couldn’t use django-registration module as it’s incompatible with the above. Apart from this, I’ve used Python 3.6.5.

What I want to do it’s common along other web applications:

  1. The user goes to the registration page and fills in the following fields:
    • first_name
    • last_name
    • email
  2. The user submits the form and receives a confirmation email with an URL containing a unique token.

  3. When the user clicks on the received link, he’s redirected to a page where he’ll set his password.

  4. When done, he’s logged in to the dashboard page.


Code

models.py

from django.contrib.auth.models import AbstractBaseUser
from django.contrib.auth.models import BaseUserManager
from django.contrib.auth.models import PermissionsMixin
from django.db import models
from django.utils.translation import ugettext_lazy as _


class UserManager(BaseUserManager):
    """
    A custom user manager to deal with emails as unique identifiers for auth
    instead of usernames. The default that's used is "UserManager"
    """

    def _create_user(self, email, password, **extra_fields):
        """
        Creates and saves a User with the given email and password.
        """

        if not email:
            raise ValueError('The Email must be set')

        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)

        return user

    def create_user(self, email, password=None, **extra_fields):
        """
        Create and save a regular User with the given email and password.
        """

        extra_fields.setdefault('is_staff', False)
        extra_fields.setdefault('is_superuser', False)

        return self._create_user(email, password, **extra_fields)

    def create_superuser(self, email, password, **extra_fields):
        """
        Create and save a SuperUser with the given email and password.
        """

        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        extra_fields.setdefault('is_active', True)

        if extra_fields.get('is_staff') is not True:
            raise ValueError('Superuser must have is_staff=True.')

        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')

        return self._create_user(email, password, **extra_fields)


class User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(unique=True, null=True, max_length=64)
    first_name = models.CharField(max_length=64)
    last_name = models.CharField(max_length=64)

    is_staff = models.BooleanField(
        _('staff status'),
        default=False,
        help_text=_('Designates whether the user can log into this site.'),
    )
    is_active = models.BooleanField(
        _('active'),
        default=True,
        help_text=_(
            'Designates whether this user should be treated as active. '
            'Unselect this instead of deleting accounts.'
        ),
    )
    USERNAME_FIELD = 'email'
    objects = UserManager()

    def __str__(self):
        return self.email

    def get_full_name(self):
        return self.email

    def get_short_name(self):
        return self.email

forms.py

from django.contrib.auth import get_user_model
from django.forms import ModelForm

User = get_user_model()


class RegistrationForm(ModelForm):

    class Meta:
        model = User
        fields = ('email', 'first_name', 'last_name')

    def save(self, commit=True):
        user = super(RegistrationForm, self).save(commit=False)
        if commit:
            user.save()
        return user

views.py

from django.contrib import messages
from django.contrib.auth import update_session_auth_hash, get_user_model, authenticate, login
from django.contrib.auth.forms import AuthenticationForm, SetPasswordForm
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.views import LoginView, LogoutView
from django.contrib.sites.shortcuts import get_current_site
from django.core.mail import EmailMessage
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.template.loader import render_to_string
from django.utils.encoding import force_bytes, force_text
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.views.generic import TemplateView, View

from .forms import RegistrationForm
from .tokens import account_activation_token

User = get_user_model()


class HomeView(LoginRequiredMixin, TemplateView):
    template_name = 'base/home.html'


class CustomLoginView(LoginView):
    template_name = 'base/login.html'
    form_class = AuthenticationForm


class CustomLogoutView(LogoutView):
    template_name = 'base/login.html'


class RegistrationView(View):

    def get(self, request):
        registration_form = RegistrationForm()
        return render(request, 'base/register.html', {'form': registration_form})

    def post(self, request):
        registration_form = RegistrationForm(request.POST)

        if registration_form.is_valid():
            user = registration_form.save(commit=False)
            user.is_active = False
            user.set_unusable_password()
            user.save()

            current_site = get_current_site(request)
            mail_subject = 'Activate your account.'
            message = render_to_string('base/activation-email.html', {
                'user': user,
                'domain': current_site.domain,
                'uid': urlsafe_base64_encode(force_bytes(user.pk)).decode(),
                'token': account_activation_token.make_token(user),
            })
            to_email = registration_form.cleaned_data.get('email')
            email = EmailMessage(
                mail_subject, message, to=[to_email]
            )
            email.send()

            return render(request, 'base/confirm-email.html')


class ActivationView(View):

    def get(self, request, uidb64, token):
        try:
            uid = force_text(urlsafe_base64_decode(uidb64))
            user = User.objects.get(pk=uid)
        except(TypeError, ValueError, OverflowError, User.DoesNotExist):
            user = None

        if user is not None and account_activation_token.check_token(user, token):
            user.is_active = True
            user.save()
            login(request, user)

            form = SetPasswordForm(request.user)
            return render(request, 'base/password-set.html', {'form': form})
        else:
            return render(request, 'base/verification-failed.html')

    def post(self, request, uidb64, token):

        try:
            uid = force_text(urlsafe_base64_decode(uidb64))
            user = User.objects.get(pk=uid)
        except(TypeError, ValueError, OverflowError, User.DoesNotExist):
            user = None

        form = SetPasswordForm(user, request.POST)

        if form.is_valid():
            user = form.save()
            update_session_auth_hash(request, user)

            user = authenticate(username=user.email, password=form.cleaned_data['new_password1'])
            login(request, user)

            return HttpResponseRedirect('/')
        else:
            messages.error(request, form.errors)
            return render(request, 'base/password-set.html', {'form': form})

urls.py

from django.conf.urls import url
from django.views.generic import TemplateView

from .views import (
    CustomLoginView, CustomLogoutView, HomeView, 
    RegistrationView, ActivationView
)

app_name = 'apps.base'

urlpatterns = [
    url(r'^$', HomeView.as_view(), name='home'),

    url(r'^login/$', CustomLoginView.as_view(), name='login'),
    url(r'^logout/$', CustomLogoutView.as_view(), name='logout'),

    url(r'^register/$', RegistrationView.as_view(), name='register'),
    url(r'^confirm_email/$', TemplateView.as_view(template_name='base/confirm-email.html'), name='confirm_email'),
    url(r'^activate/(?P<uidb64>[0-9A-Za-z_-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
        ActivationView.as_view(), name='activate'),
]

tokens.py

from django.contrib.auth.tokens import PasswordResetTokenGenerator
from django.utils import six


class TokenGenerator(PasswordResetTokenGenerator):
    def _make_hash_value(self, user, timestamp):
        return (
            six.text_type(user.pk) + six.text_type(timestamp) +
            six.text_type(user.is_active)
        )


account_activation_token = TokenGenerator()

Things that I’d like to be reviewed:

  • Django Design Patterns: Did I use the correct views / forms / models in my app? Should some of the logic be written somewhere else etc…
  • Security: Is my register system secure? If not, what can I do to make it so?
  • General feedback: Anything that comes to your mind is welcome (including criticism, ideas, improvements, cats…aliens..)


Get this bounty!!!