Tuesday, January 16, 2018

Django REST API using code first approach

In the previous post we have set up the application with JWT authentication.

In this post we will learn about how to use a code first approach to create api through which you can add, edit, delete and read the data in the table.
Given below are the steps -
1) Create a model with name and desc as text fields.


class mytable(models.Model):
    name=models.CharField(max_length=200)
    desc=models.TextField()


2) Migrate the changes to the database by
    a) Cerate the list of changes to be migrated to the database using the command - python manage.py makemigrations
    b) Add the changes to the table - python manage.py migrate
   
3) Create a file called serializers.py inside the app and add the code below -

   
class mytables(serializers.ModelSerializer):
        class Meta:
            model=mytable
            fields=('name','desc')
    


4) Next we need to add views to define the web api in views.py:
    a) Add the below imports into the code -
        from django.shortcuts import render
        from azure.servicebus._http import HTTPResponse
        from .models import *
        from .serializers import *
        from rest_framework.views import APIView
       
    b) Add the below code for reading the data in the table -

   
        class my_list(APIView):
            def get(self,request,format=None):
            dat=mytable.objects.all() #to get all the data from the table
            serialized=mytables(dat,many=True) #to serialize the data
            return Response(serialized.data) #to return the serialized data

   
    c) To insert data into the table -
        @api_view(('POST','PUT'))
        def test_insertmod(request):
            try:
                indata=request.POST.get('name')
                indesc=request.POST.get('desc')
                inkey=request.POST.get('key')
                testinstance=mytable.objects.create(id=inkey,name=indata, desc=indesc)
                return Response('Successfully inserted')
            except Exception as e:
                print(e)
                return(e)

   
    d) To update the data in the table
   
   
        @api_view(('POST','PUT'))
        def test_insertmod(request):
            try:
                indata=request.POST.get('name')
                indesc=request.POST.get('desc')
                inkey=request.POST.get('key')
                testinstance=mytable.objects.create(id=inkey,name=indata, desc=indesc)
                return Response('Successfully inserted')
            except Exception as e:
                print(e)
                return(e)

   
    e) To delete the data in the table -
   

@api_view(('POST','PUT'))
def test_deletemod(request):
    try:
        indata=request.POST.get('name')
        testinstance=mytable.objects.get(name=indata)
        testinstance.delete()
        return Response('Successfully deleted')
    except Exception as e:
        print(e)
        return(e)



5) Now that we have the views in place, we need to make the urls so that the views can be accessible -
    url(r'^mylist/', views.my_list.as_view()),
    url(r'^modinsert/',views.test_insertmod),
    url(r'^modupdate/',views.test_updatemod),
    url(r'^moddelete/',views.test_deletemod),


Now that we are done, start the django project and use the postman in chrome to test it -

Please ensure that you have the url authorized using the link http://127.0.0.1:8000/webs/auth-jwt/ and authenticating the api using the userid and password.

1) To insert data into the table - http://127.0.0.1:8000/webs/modinsert/

   

   

2) To read the data in the table use the url - http://127.0.0.1:8000/webs/mylist/


3) To update the data in the table use the url - http://127.0.0.1:8000/webs/modupdate/





4) To delete a key in the table use the link - http://127.0.0.1:8000/webs/moddelete/



   

Monday, January 15, 2018

Setting up Django Rest API with JWT authentication - Part 1

In this post, I will cover how to setup project and application for REST API and secure it using JWT.

Software used -
1) OS - Windows 10
2) Python - 3.6 (command: Python --version)
3) Django - 1.11.2 (Command: python -c "import django; print(django.get_version())")
4) Django Rest Framework - 3.6.3
5) Django Rest Framework JWT - 1.11.0 dist
6) Eclipse IDE

Setting up of Project and folder structures

Step 1 - Create a django project by clicking on File > New > Other and then selecting PyDev Django Project

Step 2 - Open command prompt and go to the location where the project is present and type the below command -
    django-admin.py startproject djangowebs
   
    Then in order to create an app inside the project you need to use
    python manage.py webs
    You can have any name of your choice in place of webs.

Configuration of the database and authentication    

Step 3 - Open the settings.py in your project and add the below one in place of the existing DATABASES (This will be pointing to sqllite3 by default). I have used postgres in this case.


    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql_psycopg2',
            'NAME': '<Name of the database>',
            'USER': '<Name of the user having access to db>',
            'PASSWORD': '<PASSWORD>',
            'HOST': '<Server name or ipaddress>',
            'PORT': '<Port number, if it is default it can be left blank>',
        }
    }

   
Step 4 - Now, lets move the authentication tables into the database. This is done in 3 steps:
    a) To allow django to make scripts for migration using the command -
        python manage.py makemigrations
    b) To make the changes into the database based on the configurations made in Step 3 -
        python manage.py migrate
    Once this is done, login into the database and ensure that the new tables and functions (in case of postgres) appear in the database.
    c) To create a superuser who has complete access to the entire db and application.
        python manage.py createsuperuser
        This will prompt you for userid and password along with confirmation of password.
       
    Once you add this, start the app: this usually will be http://127.0.0.1:8000/admin
    login using the superuser created above and it should allow you to login.



Django App Settings:

Step 5 - Add the below to your INSTALLED_APPS

    'webs',  -> This will be the app you just created in step 2
    'rest_framework.authtoken', -> This is used for authentication
    'rest_framework_jwt',  -> This is used for authentication via JSON Web Tokens (JWT)

Your INSTALLED_APPS should look like the below:


        INSTALLED_APPS = [
            'django.contrib.admin',
            'django.contrib.auth',
            'django.contrib.contenttypes',
            'django.contrib.sessions',
            'django.contrib.messages',
            'django.contrib.staticfiles',
            'rest_framework',
            'webs',
            'rest_framework.authtoken',
            'rest_framework_jwt',
        ]


Step 6 - In order to use JWT based authentication you need to add REST_FRAMEWORK. Please ensure the order is maintained as shown in the snippet below:
        REST_FRAMEWORK = {
            'DEFAULT_AUTHENTICATION_CLASSES': (
                'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
                'rest_framework.authentication.TokenAuthentication',
                'rest_framework.authentication.BasicAuthentication',
                'rest_framework.authentication.SessionAuthentication',
            ),
            'DEFAULT_PERMISSION_CLASSES': (
                'rest_framework.permissions.IsAuthenticated',
                #'rest_framework.permissions.AllowAny', (To be used instead of IsAuthenticated if you do not want any authentication for the web API)
            )
        }


Step 7 - Add the below for JWT settings:

       
JWT_AUTH = {
            'JWT_ENCODE_HANDLER':'rest_framework_jwt.utils.jwt_encode_handler',
            'JWT_DECODE_HANDLER':'rest_framework_jwt.utils.jwt_decode_handler',
            'JWT_PAYLOAD_HANDLER':'rest_framework_jwt.utils.jwt_payload_handler',
            'JWT_PAYLOAD_GET_USER_ID_HANDLER':'rest_framework_jwt.utils.jwt_get_user_id_from_payload_handler',
            'JWT_RESPONSE_PAYLOAD_HANDLER':'rest_framework_jwt.utils.jwt_response_payload_handler',
            'JWT_SECRET_KEY': SECRET_KEY,
            'JWT_GET_USER_SECRET_KEY': None,
            'JWT_PUBLIC_KEY': None,
            'JWT_PRIVATE_KEY': None,
            'JWT_ALGORITHM': 'HS256',
            'JWT_VERIFY': True,
            'JWT_VERIFY_EXPIRATION': True,
            'JWT_LEEWAY': 0,
            'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=300),
            'JWT_AUDIENCE': None,
            'JWT_ISSUER': None,
            'JWT_ALLOW_REFRESH': True,
            'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7),
            'JWT_AUTH_HEADER_PREFIX': ('JWT','Bearer'),
            'JWT_AUTH_COOKIE': None,
        }

       
Step 8 - Setting up urls in the project to make it understand the app which you have installed.

        url(r'^webs/',include('webs.urls')),
       
        Your urls.py in the main project file should look like:

       
        from django.conf.urls import url, include
        from django.contrib import admin

        urlpatterns = [
            url(r'^admin/', admin.site.urls),
            url(r'^webs/',include('webs.urls')),
        ]

       

Step 9 - Setting up the app urls for authentication related tasks
       
        imports which need to be added:

       
        from rest_framework_jwt.views import obtain_jwt_token
        from rest_framework_jwt.views import refresh_jwt_token
        from rest_framework_jwt.views import verify_jwt_token

       
        urls which need to be added within urlpatterns -
       
        url(r'^auth-jwt/', obtain_jwt_token),
        url(r'^auth-jwt-refresh/', refresh_jwt_token),
        url(r'^auth-jwt-verify/', verify_jwt_token),

       
To test the above application -

1) use http://127.0.0.1:8000/admin and provide userid and password used for superadmin, it should allow you to login.
2) To test the JWT part, install postman plugin in chrome, then provide the url along with User ID and password used for super admin in header and you can see the token as shown in the image below. 




In the up coming posts, I shall cover
1) Creating CRUD rest api using code first approach.
2) Creating CRUD rest api using database first approach using sqlalchemy
3) Creating CRUD rest api using stored procedure / functions in database and not using any ORM.

Sunday, January 7, 2018

Connecting to Active Directory using Python

This post speaks about connecting to Active Directory using python - 

python provides the ldap3 for python which can be used to connect to active directory servers. The below code will take the userid and password of the user and check it against active directory to verify the user and his credentials.

import sys
from ldap3 import Server, Connection, ALL, NTLM, ALL_ATTRIBUTES, ALL_OPERATIONAL_ATTRIBUTES, AUTO_BIND_NO_TLS, SUBTREE
from ldap3.core.exceptions import LDAPCursorError

server_name = 'your server name or ipaddress'
domain_name = 'your domain name'
user_name = <username of the user>
password = <password of the user>


format_string = '{:40}   {}'

server = Server(server_name, get_info=ALL)
conn = Connection(server, user='{}\\{}'.format(domain_name, user_name), password=)
if not conn.bind():
    print("error")
else:
    print("sucessful")
   
print(format_string.format('Group', 'Description'))

#CN to get the only the users and not the servers
conn.search('CN=users,dc=domain_name,dc=com'.format(domain_name), search_filter='(&(samAccountName=' + '' + '))',search_scope=SUBTREE,attributes=[ALL_ATTRIBUTES, ALL_OPERATIONAL_ATTRIBUTES])
for e in sorted(conn.entries):
    try:
        desc = e.description
    except LDAPCursorError:
        desc = ""
    print(format_string.format(str(e.name), desc))


This code will connect and print. However this code is not production ready code as you can see there is no exception handling, and the values are more or less hard coded in the code.

Friday, January 5, 2018

Send email using Python with To, Cc, and Bcc

So this is a very small post on how to send email in python where in there needs to be users in To, Cc and Bcc. 

Let us say we need to send mail with the below details - 
From address - abc@gmail.com
To address - def@gmail.com
Cc address - d@gmail.com, e@gmail.com
Bcc address - f@gmail.com 
Email subject - test
Email Body - test body
smtp - smtp.gmail.com
port - 587

*please note the email random.

Based on the above below is the code and explanation is above each one of the lines


import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
import sys
import logging
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))


def sendemail(fromaddr,senderpwd,smtp,port,msgSubject,msgBody,toaddr,cc,bcc):
      
    # instance of MIMEMultipart
    msg = MIMEMultipart()
    toaddr = toaddr 
    # storing the senders email address  
    msg['From'] = fromaddr
     
    # storing the receivers email address 
    msg['To'] = toaddr
    msg['Cc'] = cc
    msg['Bcc']= bcc
     
    # storing the subject 
    msg['Subject'] = msgSubject
     
    # string to store the body of the mail
    body = msgBody
     

     
    msg.attach(MIMEText(body, 'plain'))
     
    
      
    # creates SMTP session
    s = smtplib.SMTP(smtp, port)
     
    # start TLS for security
    s.starttls()
     
    # Authentication
    s.login(fromaddr, senderpwd)
     
    # Converts the Multipart msg into a string
    text = msg.as_string()
    msg.attach(body)
     
    # sending the mail
    s.sendmail(fromaddr, [toaddr,cc,bcc], text)
     
    # terminating the session
    s.quit()
    



def main():
    sendemail(' abc@gmail.com','randaompawd','smtp.gmail.com',587,'test','body test','def@gmail.com','d@gmail.com,e@gmail.com','f@gmail.com')
    
if __name__=="__main__":
    main()

Thursday, January 4, 2018

Cross database query in Postgres

We might face a scenario where in you want to create a query across databases or want to refer to the data in other database. Now postgres does not directly allow the users to do this. We would require to do workaround for the same using dblink. 

Given below are the steps we need to follow - 

Step 1 -
install dblink using extension in the database as shown in the image below - 



once you add it, you should be able to see the extension as shown in the image below: 






Step 2 -
then have the user who has or does not have password, but make sure he has access to the foreign db.

Step 3
then use the below query. 


select dblink_connect('<servername of your choice>',
                      'host=<hostname or ip> 
                       port=<port number> 
                       dbname=<database for which the user needs to connect> 
                       user=<username> password=<password>'




select * from dblink('<servername used above>', 
                     <query>) as <alias>(return columns along with datatype eg - id integer, name text)


example -
SELECT dblink_connect('test2server', 'host=127.0.0.1 port=5432 dbname=test2 user=testuser'); 
select *
from dblink('test2server',
           'select * from users')
           AS users_test2(id integer,name text)


you can have a user with or without password depending on your usecase