Drop dependancies django-picklefield and django-bootstrap3
This commit is contained in:
@ -18,6 +18,14 @@ from importlib import import_module
|
||||
|
||||
#: URL to the logo showed in the up left corner on the default templates.
|
||||
CAS_LOGO_URL = static("cas_server/logo.png")
|
||||
#: URLs to css and javascript external components.
|
||||
CAS_COMPONENT_URLS = {
|
||||
"bootstrap3_css": "//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css",
|
||||
"bootstrap3_js": "//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js",
|
||||
"html5shiv": "//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js",
|
||||
"respond": "//oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js",
|
||||
"jquery": "//code.jquery.com/jquery.min.js",
|
||||
}
|
||||
#: Path to the template showed on /login then the user is not autenticated.
|
||||
CAS_LOGIN_TEMPLATE = 'cas_server/login.html'
|
||||
#: Path to the template showed on /login?service=... then the user is authenticated and has asked
|
||||
|
@ -84,7 +84,7 @@ class CASFederateValidateUser(object):
|
||||
if username is not None:
|
||||
if attributs is None:
|
||||
attributs = {}
|
||||
attributs["provider"] = self.provider
|
||||
attributs["provider"] = self.provider.suffix
|
||||
self.username = username
|
||||
self.attributs = attributs
|
||||
user = FederatedUser.objects.update_or_create(
|
||||
|
@ -18,7 +18,28 @@ import cas_server.utils as utils
|
||||
import cas_server.models as models
|
||||
|
||||
|
||||
class WarnForm(forms.Form):
|
||||
class BootsrapForm(forms.Form):
|
||||
"""Form base class to use boostrap then rendering the form fields"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(BootsrapForm, self).__init__(*args, **kwargs)
|
||||
for (name, field) in self.fields.items():
|
||||
# Only tweak the fiel if it will be displayed
|
||||
if not isinstance(field.widget, forms.HiddenInput):
|
||||
# tell to display the field (used in form.html)
|
||||
self[name].display = True
|
||||
attrs = {}
|
||||
if isinstance(field.widget, forms.CheckboxInput):
|
||||
self[name].checkbox = True
|
||||
else:
|
||||
attrs['class'] = "form-control"
|
||||
if field.label:
|
||||
attrs["placeholder"] = field.label
|
||||
if field.required:
|
||||
attrs["required"] = "required"
|
||||
field.widget.attrs.update(attrs)
|
||||
|
||||
|
||||
class WarnForm(BootsrapForm):
|
||||
"""
|
||||
Bases: :class:`django.forms.Form`
|
||||
|
||||
@ -38,7 +59,7 @@ class WarnForm(forms.Form):
|
||||
lt = forms.CharField(widget=forms.HiddenInput(), required=False)
|
||||
|
||||
|
||||
class FederateSelect(forms.Form):
|
||||
class FederateSelect(BootsrapForm):
|
||||
"""
|
||||
Bases: :class:`django.forms.Form`
|
||||
|
||||
@ -66,7 +87,7 @@ class FederateSelect(forms.Form):
|
||||
renew = forms.BooleanField(widget=forms.HiddenInput(), required=False)
|
||||
|
||||
|
||||
class UserCredential(forms.Form):
|
||||
class UserCredential(BootsrapForm):
|
||||
"""
|
||||
Bases: :class:`django.forms.Form`
|
||||
|
||||
|
@ -4,7 +4,6 @@ from __future__ import unicode_literals
|
||||
from django.db import models, migrations
|
||||
import django.db.models.deletion
|
||||
import cas_server.utils
|
||||
import picklefield.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
@ -31,7 +30,7 @@ class Migration(migrations.Migration):
|
||||
name='ProxyGrantingTicket',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('attributs', picklefield.fields.PickledObjectField(editable=False)),
|
||||
('attributs', models.TextField(blank=True, default=None, null=True)),
|
||||
('validate', models.BooleanField(default=False)),
|
||||
('service', models.TextField()),
|
||||
('creation', models.DateTimeField(auto_now_add=True)),
|
||||
@ -47,7 +46,7 @@ class Migration(migrations.Migration):
|
||||
name='ProxyTicket',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('attributs', picklefield.fields.PickledObjectField(editable=False)),
|
||||
('attributs', models.TextField(blank=True, default=None, null=True)),
|
||||
('validate', models.BooleanField(default=False)),
|
||||
('service', models.TextField()),
|
||||
('creation', models.DateTimeField(auto_now_add=True)),
|
||||
@ -80,7 +79,7 @@ class Migration(migrations.Migration):
|
||||
name='ServiceTicket',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('attributs', picklefield.fields.PickledObjectField(editable=False)),
|
||||
('attributs', models.TextField(blank=True, default=None, null=True)),
|
||||
('validate', models.BooleanField(default=False)),
|
||||
('service', models.TextField()),
|
||||
('creation', models.DateTimeField(auto_now_add=True)),
|
||||
|
@ -3,7 +3,6 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import picklefield.fields
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
@ -41,7 +40,7 @@ class Migration(migrations.Migration):
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('username', models.CharField(max_length=124)),
|
||||
('provider', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cas_server.FederatedIendityProvider')),
|
||||
('attributs', picklefield.fields.PickledObjectField(editable=False)),
|
||||
('attributs', models.TextField(blank=True, default=None, null=True)),
|
||||
('ticket', models.CharField(max_length=255)),
|
||||
('last_update', models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
|
56
cas_server/migrations/0007_auto_20160723_2252.py
Normal file
56
cas_server/migrations/0007_auto_20160723_2252.py
Normal file
@ -0,0 +1,56 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.8 on 2016-07-23 22:52
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cas_server', '0006_auto_20160706_1727'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='federateduser',
|
||||
name='attributs',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='proxygrantingticket',
|
||||
name='attributs',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='proxyticket',
|
||||
name='attributs',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='serviceticket',
|
||||
name='attributs',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='federateduser',
|
||||
name='_attributs',
|
||||
field=models.TextField(blank=True, default=None, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='proxygrantingticket',
|
||||
name='_attributs',
|
||||
field=models.TextField(blank=True, default=None, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='proxyticket',
|
||||
name='_attributs',
|
||||
field=models.TextField(blank=True, default=None, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='serviceticket',
|
||||
name='_attributs',
|
||||
field=models.TextField(blank=True, default=None, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='federatediendityprovider',
|
||||
name='suffix',
|
||||
field=models.CharField(help_text='Suffix append to backend CAS returned username: ``returned_username`` @ ``suffix``.', max_length=30, unique=True, verbose_name='suffix'),
|
||||
),
|
||||
]
|
@ -18,7 +18,6 @@ from django.contrib import messages
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils import timezone
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from picklefield.fields import PickledObjectField
|
||||
|
||||
import re
|
||||
import sys
|
||||
@ -140,8 +139,8 @@ class FederatedUser(models.Model):
|
||||
username = models.CharField(max_length=124)
|
||||
#: A foreign key to :class:`FederatedIendityProvider`
|
||||
provider = models.ForeignKey(FederatedIendityProvider, on_delete=models.CASCADE)
|
||||
#: The user attributes returned by the CAS backend on successful ticket validation
|
||||
attributs = PickledObjectField()
|
||||
#: The user attributes json encoded
|
||||
_attributs = models.TextField(default=None, null=True, blank=True)
|
||||
#: The last ticket used to authenticate :attr:`username` against :attr:`provider`
|
||||
ticket = models.CharField(max_length=255)
|
||||
#: Last update timespampt. Usually, the last time :attr:`ticket` has been set.
|
||||
@ -150,6 +149,17 @@ class FederatedUser(models.Model):
|
||||
def __str__(self):
|
||||
return self.federated_username
|
||||
|
||||
@property
|
||||
def attributs(self):
|
||||
"""The user attributes returned by the CAS backend on successful ticket validation"""
|
||||
if self._attributs is not None:
|
||||
return utils.json.loads(self._attributs)
|
||||
|
||||
@attributs.setter
|
||||
def attributs(self, value):
|
||||
"""attributs property setter"""
|
||||
self._attributs = utils.json_encode(value)
|
||||
|
||||
@property
|
||||
def federated_username(self):
|
||||
"""The federated username with a suffix for the current :class:`FederatedUser`."""
|
||||
@ -712,8 +722,8 @@ class Ticket(models.Model):
|
||||
abstract = True
|
||||
#: ForeignKey to a :class:`User`.
|
||||
user = models.ForeignKey(User, related_name="%(class)s")
|
||||
#: The user attributes to be transmited to the service on successful validation
|
||||
attributs = PickledObjectField()
|
||||
#: The user attributes to transmit to the service json encoded
|
||||
_attributs = models.TextField(default=None, null=True, blank=True)
|
||||
#: A boolean. ``True`` if the ticket has been validated
|
||||
validate = models.BooleanField(default=False)
|
||||
#: The service url for the ticket
|
||||
@ -736,6 +746,17 @@ class Ticket(models.Model):
|
||||
#: requests.
|
||||
TIMEOUT = settings.CAS_TICKET_TIMEOUT
|
||||
|
||||
@property
|
||||
def attributs(self):
|
||||
"""The user attributes to be transmited to the service on successful validation"""
|
||||
if self._attributs is not None:
|
||||
return utils.json.loads(self._attributs)
|
||||
|
||||
@attributs.setter
|
||||
def attributs(self, value):
|
||||
"""attributs property setter"""
|
||||
self._attributs = utils.json_encode(value)
|
||||
|
||||
class DoesNotExist(Exception):
|
||||
"""raised in :meth:`Ticket.get` then ticket prefix and ticket classes mismatch"""
|
||||
pass
|
||||
|
@ -1,36 +1,63 @@
|
||||
{% extends 'bootstrap3/bootstrap3.html' %}
|
||||
{% load i18n %}
|
||||
{% block bootstrap3_title %}{% block title %}{% trans "Central Authentication Service" %}{% endblock %}{% endblock %}
|
||||
|
||||
{% load staticfiles %}
|
||||
{% load bootstrap3 %}
|
||||
|
||||
{% block bootstrap3_extra_head %}
|
||||
<link rel="shortcut icon" href="/static/cas_server/favicon.ico?v=1" />
|
||||
<link href="{% static "cas_server/login.css" %}" rel="stylesheet">
|
||||
{% endblock %}
|
||||
|
||||
{% block bootstrap3_content %}
|
||||
<div class="container">
|
||||
{% if auto_submit %}<noscript>{% endif %}
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
|
||||
<h1 id="app-name">
|
||||
{% if settings.CAS_LOGO_URL %}<img src="{{settings.CAS_LOGO_URL}}"></img> {% endif %}
|
||||
{% trans "Central Authentication Service" %}</h1>
|
||||
</div>
|
||||
</div>
|
||||
{% if auto_submit %}</noscript>{% endif %}
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-3 col-sm-2 col-xs-12"></div>
|
||||
<div class="col-lg-6 col-md-6 col-sm-8 col-xs-12">
|
||||
{% if auto_submit %}<noscript>{% endif %}
|
||||
{% bootstrap_messages %}
|
||||
{% if auto_submit %}</noscript>{% endif %}
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
<div class="col-lg-3 col-md-3 col-sm-2 col-xs-0"></div>
|
||||
</div>
|
||||
</div> <!-- /container -->
|
||||
{% endblock %}
|
||||
<!DOCTYPE html>
|
||||
<html{% if request.LANGUAGE_CODE %} lang="{{ request.LANGUAGE_CODE }}"{% endif %}>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge" /><![endif]-->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{% block title %}{% trans "Central Authentication Service" %}{% endblock %}</title>
|
||||
<link href="{{settings.CAS_COMPONENT_URLS.bootstrap3_css}}" rel="stylesheet">
|
||||
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
|
||||
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
|
||||
<!--[if lt IE 9]>
|
||||
<script src="{{settings.CAS_COMPONENT_URLS.html5shiv}}"></script>
|
||||
<script src="{{settings.CAS_COMPONENT_URLS.respond}}"></script>
|
||||
<![endif]-->
|
||||
<link rel="shortcut icon" href="{% static "cas_server/favicon.ico?v=1" %}" />
|
||||
<link href="{% static "cas_server/login.css" %}" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
{% if auto_submit %}<noscript>{% endif %}
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
|
||||
<h1 id="app-name">
|
||||
{% if settings.CAS_LOGO_URL %}<img src="{{settings.CAS_LOGO_URL}}"></img> {% endif %}
|
||||
{% trans "Central Authentication Service" %}</h1>
|
||||
</div>
|
||||
</div>
|
||||
{% if auto_submit %}</noscript>{% endif %}
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-3 col-sm-2 col-xs-12"></div>
|
||||
<div class="col-lg-6 col-md-6 col-sm-8 col-xs-12">
|
||||
{% block ante_messages %}{% endblock %}
|
||||
{% if auto_submit %}<noscript>{% endif %}
|
||||
{% for message in messages %}
|
||||
<div {% spaceless %}
|
||||
{% if message.level == message_levels.DEBUG %}
|
||||
class="alert alert-warning alert-dismissable"
|
||||
{% elif message.level == message_levels.INFO %}
|
||||
class="alert alert-info alert-dismissable"
|
||||
{% elif message.level == message_levels.SUCCESS %}
|
||||
class="alert alert-success alert-dismissable"
|
||||
{% elif message.level == message_levels.WARNING %}
|
||||
class="alert alert-warning alert-dismissable"
|
||||
{% else %}
|
||||
class="alert alert-danger alert-dismissable"
|
||||
{% endif %}
|
||||
{% endspaceless %}>
|
||||
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% if auto_submit %}</noscript>{% endif %}
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
<div class="col-lg-3 col-md-3 col-sm-2 col-xs-0"></div>
|
||||
</div>
|
||||
</div> <!-- /container -->
|
||||
<script src="{{settings.CAS_COMPONENT_URLS.jquery}}"></script>
|
||||
<script src="{{settings.CAS_COMPONENT_URLS.bootstrap3_js}}"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
25
cas_server/templates/cas_server/form.html
Normal file
25
cas_server/templates/cas_server/form.html
Normal file
@ -0,0 +1,25 @@
|
||||
{% for error in form.non_field_errors %}
|
||||
<div class="alert alert-danger alert-dismissable">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
|
||||
{{error}}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% for field in form %}{% if field.display %}
|
||||
<div class="form-group{% spaceless %}
|
||||
{% if not form.non_field_errors %}
|
||||
{% if field.errors %} has-error
|
||||
{% elif form.cleaned_data %} has-success
|
||||
{% endif %}
|
||||
{% endif %}"
|
||||
{% endspaceless %}>{% spaceless %}
|
||||
{% if field.checkbox %}
|
||||
<div class="checkbox"><label for="{{field.auto_id}}">{{field}}{{field.label}}</label>
|
||||
{% else %}
|
||||
<label class="control-label" for="{{field.auto_id}}">{{field.label}}</label>
|
||||
{{field}}
|
||||
{% endif %}
|
||||
{% for error in field.errors %}
|
||||
<span class="help-block">{{error}}</span>
|
||||
{% endfor %}
|
||||
{% endspaceless %}</div>
|
||||
{% else %}{{field}}{% endif %}{% endfor %}
|
@ -1,6 +1,4 @@
|
||||
{% extends "cas_server/base.html" %}
|
||||
{% load bootstrap3 %}
|
||||
{% load staticfiles %}
|
||||
{% load i18n %}
|
||||
{% block content %}
|
||||
<div class="alert alert-success" role="alert">{% trans "Logged" %}</div>
|
||||
@ -10,7 +8,7 @@
|
||||
<input type="checkbox" name="all" value="1"> {% trans "Log me out from all my sessions" %}
|
||||
</label>
|
||||
</div>
|
||||
{% bootstrap_button _('Logout') size='lg' button_type="submit" button_class="btn-danger btn-block"%}
|
||||
<button class="btn btn-danger btn-block btn-lg" type="submit">{% trans "Logout" %}</button>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
|
@ -1,18 +1,19 @@
|
||||
{% extends "cas_server/base.html" %}
|
||||
{% load bootstrap3 %}
|
||||
{% load staticfiles %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block ante_messages %}
|
||||
{% if auto_submit %}<noscript>{% endif %}
|
||||
<h2 class="form-signin-heading">{% trans "Please log in" %}</h2>
|
||||
{% if auto_submit %}</noscript>{% endif %}
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<form class="form-signin" method="post" id="login_form"{% if post_url %} action="{{post_url}}"{% endif %}>
|
||||
{% if auto_submit %}<noscript>{% endif %}
|
||||
<h2 class="form-signin-heading">{% trans "Please log in" %}</h2>
|
||||
{% if auto_submit %}</noscript>{% endif %}
|
||||
{% csrf_token %}
|
||||
{% bootstrap_form form %}
|
||||
{% if auto_submit %}<noscript>{% endif %}
|
||||
{% bootstrap_button _('Login') size='lg' button_type="submit" button_class="btn-primary btn-block"%}
|
||||
{% if auto_submit %}</noscript>{% endif %}
|
||||
</form>
|
||||
<form class="form-signin" method="post" id="login_form"{% if post_url %} action="{{post_url}}"{% endif %}>
|
||||
{% csrf_token %}
|
||||
{% include "cas_server/form.html" %}
|
||||
{% if auto_submit %}<noscript>{% endif %}
|
||||
<button class="btn btn-primary btn-block btn-lg" type="submit">{% trans "Login" %}</button>
|
||||
{% if auto_submit %}</noscript>{% endif %}
|
||||
</form>
|
||||
{% if auto_submit %}
|
||||
<script type="text/javascript">
|
||||
document.getElementById('login_form').submit(); // SUBMIT FORM
|
||||
|
@ -1,5 +1,4 @@
|
||||
{% extends "cas_server/base.html" %}
|
||||
{% load bootstrap3 %}
|
||||
{% load staticfiles %}
|
||||
{% load i18n %}
|
||||
{% block content %}
|
||||
|
@ -1,12 +1,11 @@
|
||||
{% extends "cas_server/base.html" %}
|
||||
{% load bootstrap3 %}
|
||||
{% load staticfiles %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
<form class="form-signin" method="post">
|
||||
{% csrf_token %}
|
||||
{% bootstrap_form form %}
|
||||
{% bootstrap_button _('Connect to the service') size='lg' button_type="submit" button_class="btn-primary btn-block"%}
|
||||
{% include "cas_server/form.html" %}
|
||||
<button class="btn btn-primary btn-block btn-lg" type="submit">{% trans "Connect to the service" %}</button>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
@ -37,7 +37,6 @@ INSTALLED_APPS = [
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'bootstrap3',
|
||||
'cas_server',
|
||||
]
|
||||
|
||||
|
@ -15,6 +15,8 @@ from .default_settings import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.http import HttpResponseRedirect, HttpResponse
|
||||
from django.contrib import messages
|
||||
from django.contrib.messages import constants as DEFAULT_MESSAGE_LEVELS
|
||||
from django.core.serializers.json import DjangoJSONEncoder
|
||||
|
||||
import random
|
||||
import string
|
||||
@ -29,6 +31,15 @@ from datetime import datetime, timedelta
|
||||
from six.moves.urllib.parse import urlparse, urlunparse, parse_qsl, urlencode
|
||||
|
||||
|
||||
def json_encode(obj):
|
||||
"""Encode a python object to json"""
|
||||
try:
|
||||
return json_encode.encoder.encode(obj)
|
||||
except AttributeError:
|
||||
json_encode.encoder = DjangoJSONEncoder(default=six.text_type)
|
||||
return json_encode(obj)
|
||||
|
||||
|
||||
def context(params):
|
||||
"""
|
||||
Function that add somes variable to the context before template rendering
|
||||
@ -39,6 +50,7 @@ def context(params):
|
||||
:rtype: dict
|
||||
"""
|
||||
params["settings"] = settings
|
||||
params["message_levels"] = DEFAULT_MESSAGE_LEVELS
|
||||
return params
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user