Páginas

quarta-feira, junho 07, 2017

Django OAuth server and Flask OAuth consumer with Django Outh Toolkit

Hi everyone!

I'm starting the integration of an app that will serve OAuth authentication method in a Django project. Django OAuth Toolkit appeared as a good solution, however the documentation was a little confused to me and I had a hard way of testing to understand how it works.

For this tutorial I'm using

Django==1.9.1

Flask==0.10.1
django-cors-headers==1.1.0
django-oauth-toolkit==0.10.0



The Server


First of all, create a Django project:

django-admin.py startproject my_oauth_server

After that, let's follow the steps at the oficial tutorial (assuming you have already installed the packages above):


Add oauth2_provider and corsheader in your settings.py

INSTALLED_APPS = {
    # ...
    'oauth2_provider',
    'corsheaders',
}


Add the toolkit urls:

urlpatterns = patterns(
    '',
    url(r'^admin/', include(admin.site.urls)),
    url(r'^o/', include('oauth2_provider.urls', namespace='oauth2_provider')),
    # ...
)

And the middleware:

MIDDLEWARE_CLASSES = (
    # ...
    'corsheaders.middleware.CorsMiddleware',
    # ...
)

And add this in settings:

CORS_ORIGIN_ALLOW_ALL = True

Now let's create the authentication system for our Django:

django-admin.py startapp my_authentication


By the simplest way, create the view:

from django.http.response import HttpResponse, HttpResponseRedirect
from django.shortcuts import render
from django.contrib.auth import authenticate, login, logout


# Create your views here.

def login_page(request):
    next_page = request.GET.get('next', '/')
    if request.method == 'POST':
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(username=username, password=password)
        login(request, user)
        return HttpResponseRedirect(next_page)

    return render(request, 'login.html', {'next': next_page})


def logout_page(request):
    logout(request)
    return HttpResponseRedirect('/')


def home(request):
    return HttpResponse("Logged in: %s" % request.user.is_authenticated())



Now create the template login.html:

<form method="post">    {% csrf_token %}
    <input type="hidden" name="next" value="{{ next }}" />    <p>        username
        <input type="text" name="username" />    </p>    <p>        password <input type="password" name="password" />    </p>    <button type="submit" >Login</button></form>


Actually, it's stupid simple, just to have an exemple. The "next" input receives the value from the url. This is required to were go after login. 
Finally, add your app urls:

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

urlpatterns = [
    url(r'^admin/', admin.site.urls),    url(r'^o/', include('oauth2_provider.urls', namespace='oauth2_provider')),    url(r'^$', 'authorization_server.views.home'),    url(r'^accounts/login/$', 'authorization_server.views.login_page'),    url(r'^logout/$', 'authorization_server.views.logout_page'),]


Just run the migrate command and create an user to authorize using oauth. Create an an app at:
/o/applications. Copy the client id and client secret. Put the redirect url to /consumer at your address (in my case, the consumer will run at port 9100



The consumer

I got this exemple and applyed to my project. you can see the code bellow:

from flask import Flask
from flask import request

app = Flask(__name__)

CLIENT_ID = "Vkh2wibaQZLaxrvhYQUq8I5WWdqRLmQJXQc2YxPB"CLIENT_SECRET = "czsU5umPX2mrLqKTlLV6YNSgbPLQKxdp2WsOlWJkIYJjXP4rSrnwEwZJlAkCo7fjlCCPo3ReLMGazjeMWO5ujtjAJEOLIsTWcrE18PxwiioQMOQxTvEQQliMSCOLxEnl"REDIRECT_URI = "http://localhost:9100/consumer"
from flask import Flask

app = Flask(__name__)


# Left as an exercise to the reader.# You may want to store valid states in a database or memcache,# or perhaps cryptographically sign them and verify upon retrieval.def save_created_state(state):
    pass
def is_valid_state(state):
    return True

import requests
import requests.auth


def get_token(code):
    client_auth = requests.auth.HTTPBasicAuth(CLIENT_ID, CLIENT_SECRET)
    post_data = {"grant_type": "authorization_code",                 "code": code,                 "redirect_uri": REDIRECT_URI}
    response = requests.post("http://localhost:9000/o/token",                             auth=client_auth,                             data=post_data)
    token_json = response.json()
    return token_json["access_token"]


from flask import abort, request
@app.route('/consumer/')
def reddit_callback():
    error = request.args.get('error', '')
    if error:
        return "Error: " + error
    state = request.args.get('state', '')
    if not is_valid_state(state):
        # Uh-oh, this request wasn't started by us!        abort(403)
    code = request.args.get('code')
    # We'll change this next line in just a moment    return "got a code! %s" % code


if __name__ == '__main__':
    app.run(debug=True, port=9100)


def get_username(access_token):
    headers = {"Authorization": "bearer " + access_token}
    response = requests.get("http://localhost:9000/user_data", headers=headers)
    me_json = response.json()
    return me_json['username']



Run the flask server. Here I used the port 9000 to the server and 9100 for the consumer. The authentication url:

http://localhost:9000/o/authorize/?response_type=code&state=random_state_string&client_id=Vkh2wibaQZLaxrvhYQUq8I5WWdqRLmQJXQc2YxPB

Use the right attribute values for client id. With this you can log users in your application with oauth and consume that.







segunda-feira, abril 04, 2016

Change GCC default arguments

I experience this problem with pip, receiving:


    psycopg/adapter_datetime.c:341: error: undefined reference to 'lround'
    psycopg/adapter_datetime.c:336: error: undefined reference to 'lround'
    psycopg/adapter_datetime.c:312: error: undefined reference to 'lround'
    psycopg/adapter_datetime.c:309: error: undefined reference to 'lround'
    psycopg/adapter_datetime.c:381: error: undefined reference to 'floor'
    psycopg/adapter_datetime.c:407: error: undefined reference to 'floor'
    psycopg/adapter_datetime.c:441: error: undefined reference to 'floor'
    ./psycopg/typecast_datetime.c:321: error: undefined reference to 'floor'
    collect2: error: ld returned 1 exit status

To solve this I have to use -lm as argument in GCC. But, I'm using pip! Just export the default cflags:


export CFLAGS='-lm'
 
 
 Try this! 

quinta-feira, março 10, 2016

Django Crispy Forms without form tag

I'm experiencing some problems with buttons and crispy forms with translations in Django. It appears that the render is caching the button rendering, and when the user changes the language buttons still use the first language used by users.

To solve this I removed buttons from the form layout and put it on the HTML template. However by default Crispy open and close the form tag. To solve this, just insert in the __init__ of your form:

self.helper.form_tag = False

It will set in Crispy that it does not have to open and close the form tag, and you can put buttons as you need.

Check Crispy's documentation at:
http://django-crispy-forms.readthedocs.org/en/latest/form_helper.html

_______________________________________________________________

Estou tendo alguns problemas com o Django Crispy forms e botões com internacionalização. Parece que ele cacheia a renderização dos botões e quando mudo o idioma ele não muda o conteúdo dos botões. Estranhamente somente dos botões.

Pra resolver o problema eu retirei os botões do layout dos forms no crispy e fiz inserção no html, o problema é que por padrão o Crispy abre e fecha a tag form. Pra que ele não faça isso coloquei no  __init__ do meu form:

self.helper.form_tag = False

Isso diz para o Crispy que ele não deve abrir e fechar a tag e ele renderiza somente os campos.

Confira a documentação do Crispy em:
http://django-crispy-forms.readthedocs.org/en/latest/form_helper.html

________________________________________________________________

Code exemple:
from crispy_forms.helper import FormHelper
from .form_layouts import MY_FORM_LAYOUT

class MyForm(forms.Form):
    some_field = forms.CharField()

    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.layout = MY_FORM_LAYOUT
        self.helper.form_tag = False



quarta-feira, novembro 18, 2015

Gerador de jogo da Mega Sena em Python

Que tal gerar números para sua aposta na Mega desse ano??

https://github.com/guimesmo/numero_da_sorte/


import random
def numero_da_sorte():
    l = list(range(1, 61))
    random.shuffle(l)
    print("-".join([str(i) for i in l[:6]]))
numero_da_sorte()

Baseado nesse cara aqui:
http://piscoespecial.blogspot.com.br/2012/08/script-em-python-para-mega-sena.html

sexta-feira, agosto 29, 2014

Grouping Django querysets

This is a simple tip for group or "sum" or "make a union" of Django query sets.

This is the case:

class SomeModel(models.Model):
    name = models.CharField(max_length=100)
    short= models.CharField(max_length=10)

fst_exemple = SomeModel.objects.create(
    name="Luiz Guilherme", short="LG")
scd_exemple = SomeModel.objects.create(
    name="Guilherme Silva", short="Silva")

lg_cases = SomeModel.objects.filter(short="LG")
silva_cases = SomeModel.objects.filter(short="Silva")

# getting the two cases
lg_or_silva = lg_cases | silva_cases

# starting from empty
starting_from_none = SomeModel.objects.none()

# adding cases on empty:
# Usefull for loops (this is my reason for write this)
starting_from_none |= lg_or_silva

I hope to save somebody with this.

quinta-feira, agosto 29, 2013

Creating Django permissions using South Datamigrations.

After a long time away I'm back to post (for my own information and for everybody who needs it) how to create django permissions using South datamigrations. For understanding what is Django, South and Python, follow the links in the end of this post.

First step, create a Data Migration:
python manage.py datamigration app_name name_describing_your_permission_creation

This command will generate a file like XXXX_name_describing_your_permission_creation.py. Open and edit this file. It will have a "fowards" method. Change it to be like this:

     def forwards(self, orm):
        ct = orm['contenttypes.ContentType'].objects.get(
            model='model_name', app_label='app_label')
        orm['auth.permission'].objects.get_or_create(
            content_type=ct, codename='permission_codename',
            defaults=dict(name=u'Permission Label')
        )

After create this, run this command:
python manage.py migrate your_app_name

It will apply your data migration creating permissions. You can add the backwards for your datamigration deleting the permissions:

    def backwards(self, orm):
        ct = orm['contenttypes.ContentType'].objects.get(
            model='nome_do_model', app_label='label_da_app')
        orm['auth.permission'].objects.filter(
            content_type=ct, codename='permission_codename',
        ).delete()

I found it on this page on Stack Overflow:
http://stackoverflow.com/questions/1742021/adding-new-custom-permissions-in-django

More interesting links:
[1] http://south.aeracode.org/
[2] https://www.djangoproject.com/
[3] http://www.python.org.br/wiki
[4] https://docs.djangoproject.com/en/dev/ref/django-admin/#syncdb
[5] https://docs.djangoproject.com/en/dev/topics/auth/

Criando permissões Django com South

Após muito tempo sem postar volto aqui pra registrar (pra mim mesmo e a quem interessar), como criar permissões usando South. Obviamente para entender este post é necessário conhecer o South[1], Django[2] e Python[3]. Se não preenche nenhum dos requisitos provavelmente isso vai parecer grego.

Quando criamos um model no Django e adicionamos permissões (seja no Meta ou as permissões automáticas) o comando syncdb[4] as adiciona ao .model Permission [5]. Apesar disso, quem usa o South não usa syncdb e o south, muito simpático não cria as permissões. Explicado o problema, acredito...

Com isso frequentemente acabava criando as permissões manualmente via django admin porém em um grupo de desenvolvedores isso acaba sendo trabalhoso demais por que as bases deveriam ser o mais semelhantes possível Enfim, precisava de forma simples atualizar as permissões com o South. Obviamente uma datamigration seria a solução obvia, e procurando quais seriam os dados necessários encontrei no Stack Overflow[6] a resposta:

Primeiro vamos criar a datamigration:
python manage.py datamigration nome_da_app nome_que_quiser_descrevendo_a_data_migration

Esse comando vai gerar um arquivo XXXX_nome_que_quiser_descrevendo_a_data_migration.py. Abra o arquivo para edição. Vai haver um método fowards que deve ficar assim:

    def forwards(self, orm):
        ct = orm['contenttypes.ContentType'].objects.get(
            model='nome_do_model', app_label='label_da_app')
        orm['auth.permission'].objects.get_or_create(
            content_type=ct, codename='codename_da_permission',
            defaults=dict(name=u'Label da Permission')
        )

Se quiser pode adicionar também o backwards:

    def backwards(self, orm):
        ct = orm['contenttypes.ContentType'].objects.get(
            model='nome_do_model', app_label='label_da_app')
        orm['auth.permission'].objects.filter(
            content_type=ct, codename='codename_da_permission',
        ).delete()

Espero que ajude!

[1] http://south.aeracode.org/
[2] https://www.djangoproject.com/
[3] http://www.python.org.br/wiki
[4] https://docs.djangoproject.com/en/dev/ref/django-admin/#syncdb
[5] https://docs.djangoproject.com/en/dev/topics/auth/
[6]http://stackoverflow.com/questions/1742021/adding-new-custom-permissions-in-django

domingo, agosto 30, 2009

Habilitar Python em servidor apache (Mandriva)

Estou começando agora a me aprofundar na linguagem python pra web. Obviamente, preciso testar meus scripts, mas a tarefa fica complicada sem documentação. Depois de procurar bastante, encontrei esta página que ensina os passos para várias distros, e o mandriva está entre elas. Não vou entrar em detalhes nem me aprofundar muito no assunto, mas pra quem não manja de inglês é só executar os comandos que a coisa vai estar funcionando. Abraço.

http://www.howtoforge.com/embedding-python-in-apache2-with-mod_python-debian-ubuntu-fedora-centos-mandriva-opensuse-p2