Tuesday, November 5, 2013

wxPython + Django - Basic authentication in wxPython with Django

The beauty of Python and any other OOP programing languages is the reusable functionality. So, I reuse the authentication module of Django to add a basic security layer for my wxPython application:

+ Authenticate a user with Django (django.contrib.auth.authenticate)
+ Save the session to a file names 'cred'
+ Read the 'cred' file to verify if that user has the privilege.


* The main frame:

class HomeFrame(wx.Frame):

    def __init__(self):
        wx.Frame.__init__(
            self,
            parent=None,
            title='My wxPython application',
            size=wx.DisplaySize(),
        )

        self.panel = HomePanel(self)

        sizer = wx.GridSizer(1, 1)
        sizer.Add(self.panel, flag=wx.ALIGN_CENTER)
        self.SetSizer(sizer)

        self.Bind(wx.EVT_CLOSE, self.OnClose, self)
        self.Show()


    def show_login_dialog(self):
        login_dialog = LoginDialog(self)



    def OnClose(self, event):
        self.Destroy()



class HomePanel(wx.Panel):

    search_height = 50

    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        ...
        self.do_layout()
        self.setup_bindings()
        ...


    def setup_bindings(self):
        ...

    def do_layout(self):
        ...


    def check_login(self, event):
        try:
            privilege_file = open('cred', 'rb')
            privilege = privilege_file.read()
            privilege_file.close()
            print("Has privilege: %s" % privilege)
            if privilege=='True':
                 # do thing here               




            else:
                self.Parent.show_login_dialog()
        except IOError as e:
            print("Cred file not found.")
            self.Parent.show_login_dialog()



* Login dialog:


class LoginDialog(wx.Dialog):

    def __init__(self, parent, id=-1, title='Login',
                 text='Please type your username and password:',
                 username=''):

        size = (400, 200)
        wx.Dialog.__init__(self, parent, id, title, size=size)

        self.panel = LoginPanel(self)

        sizer = wx.GridSizer(1, 1)
        sizer.Add(self.panel, flag=wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL)
        self.SetSizer(sizer)

        self.Show()


class LoginPanel(wx.Panel):

    def __init__(self, parent):
        wx.Panel.__init__(self, parent)

        self.setup_login_form()

        self.do_layout()
        self.setup_bindings()

    def setup_login_form(self):
        self.usernametxt = wx.StaticText(self, label="Username: ")
        self.usernamebox = wx.TextCtrl(self, size=(230, 30))

        self.passwordtxt = wx.StaticText(self, label="Password:  ")
        self.passwordbox = wx.TextCtrl(self, size=(230, 30), style=wx.TE_PASSWORD)

        self.loginbutton = wx.Button(self, wx.ID_OK, ' OK ', size=(150, 30))
        self.cancelbutton = wx.Button(self, wx.ID_CANCEL, ' Cancel ', size=(150, 30))
        self.usernamebox.SetFocus()

        self.errormsg = wx.StaticText(self, label="")
        self.errormsg.SetForegroundColour((255,0,0))

    def do_layout(self):

        v_sizer = wx.BoxSizer(wx.VERTICAL)

        v_sizer.Add(self.errormsg, wx.ALIGN_CENTER)

        username_sizer = wx.BoxSizer()
        username_sizer.Add(self.usernametxt)
        username_sizer.Add(self.usernamebox)

        password_sizer = wx.BoxSizer()
        password_sizer.Add(self.passwordtxt)
        password_sizer.Add(self.passwordbox)

        button_sizer = wx.BoxSizer()
        button_sizer.Add(self.cancelbutton)
        button_sizer.Add(self.loginbutton)

        v_sizer.Add(username_sizer)
        v_sizer.Add(password_sizer)
        v_sizer.Add((0,30),0, wx.EXPAND)
        v_sizer.Add(button_sizer)

        self.SetSizer(v_sizer)

    def setup_bindings(self):
        self.loginbutton.Bind(wx.EVT_BUTTON, self.do_login)


    def get_values(self):
        auth = None
        username = self.usernamebox.GetValue()
        password = self.passwordbox.GetValue()

        if username:
            if password:
                auth = [username, password]

        return auth

    def do_login(self, event):
        from django.contrib.auth import authenticate

        auth = self.get_values()
        if auth:
            user = authenticate(username=auth[0], password=auth[1])
            if user is not None:
                cred_file = open('cred', 'wb')
                cred_file.write('True')
                cred_file.close()
                print("Welcome %s" % (user.username))
                self.Parent.Show(False)
 

                # do things here               


            else:
                self.errormsg.SetLabel("The username and password were incorrect.")
                print("The username and password were incorrect.")
        else:
            self.errormsg.SetLabel("Please enter username and password.")
            print("Please enter username and password.")