PEP8
This commit is contained in:
		@@ -14,8 +14,12 @@ from .models import ServiceTicket, ProxyTicket, ProxyGrantingTicket, User, Servi
 | 
			
		||||
from .models import Username, ReplaceAttributName, ReplaceAttributValue, FilterAttributValue
 | 
			
		||||
from .forms import TicketForm
 | 
			
		||||
 | 
			
		||||
tickets_readonly_fields=('validate', 'service', 'service_pattern', 'creation', 'renew', 'single_log_out', 'value')
 | 
			
		||||
tickets_fields = ('validate', 'service', 'service_pattern', 'creation', 'renew', 'single_log_out')
 | 
			
		||||
tickets_readonly_fields = ('validate', 'service', 'service_pattern',
 | 
			
		||||
                           'creation', 'renew', 'single_log_out', 'value')
 | 
			
		||||
tickets_fields = ('validate', 'service', 'service_pattern',
 | 
			
		||||
                  'creation', 'renew', 'single_log_out')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ServiceTicketInline(admin.TabularInline):
 | 
			
		||||
    """`ServiceTicket` in admin interface"""
 | 
			
		||||
    model = ServiceTicket
 | 
			
		||||
@@ -23,6 +27,8 @@ class ServiceTicketInline(admin.TabularInline):
 | 
			
		||||
    form = TicketForm
 | 
			
		||||
    readonly_fields = tickets_readonly_fields
 | 
			
		||||
    fields = tickets_fields
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ProxyTicketInline(admin.TabularInline):
 | 
			
		||||
    """`ProxyTicket` in admin interface"""
 | 
			
		||||
    model = ProxyTicket
 | 
			
		||||
@@ -30,6 +36,8 @@ class ProxyTicketInline(admin.TabularInline):
 | 
			
		||||
    form = TicketForm
 | 
			
		||||
    readonly_fields = tickets_readonly_fields
 | 
			
		||||
    fields = tickets_fields
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ProxyGrantingInline(admin.TabularInline):
 | 
			
		||||
    """`ProxyGrantingTicket` in admin interface"""
 | 
			
		||||
    model = ProxyGrantingTicket
 | 
			
		||||
@@ -38,30 +46,39 @@ class ProxyGrantingInline(admin.TabularInline):
 | 
			
		||||
    readonly_fields = tickets_readonly_fields
 | 
			
		||||
    fields = tickets_fields[1:]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class UserAdmin(admin.ModelAdmin):
 | 
			
		||||
    """`User` in admin interface"""
 | 
			
		||||
    inlines = (ServiceTicketInline, ProxyTicketInline, ProxyGrantingInline)
 | 
			
		||||
    readonly_fields=('username', 'date', "session_key")
 | 
			
		||||
    readonly_fields = ('username', 'date', "session_key")
 | 
			
		||||
    fields = ('username', 'date', "session_key")
 | 
			
		||||
    list_display = ('username', 'date', "session_key")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class UsernamesInline(admin.TabularInline):
 | 
			
		||||
    """`Username` in admin interface"""
 | 
			
		||||
    model = Username
 | 
			
		||||
    extra = 0
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ReplaceAttributNameInline(admin.TabularInline):
 | 
			
		||||
    """`ReplaceAttributName` in admin interface"""
 | 
			
		||||
    model = ReplaceAttributName
 | 
			
		||||
    extra = 0
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ReplaceAttributValueInline(admin.TabularInline):
 | 
			
		||||
    """`ReplaceAttributValue` in admin interface"""
 | 
			
		||||
    model = ReplaceAttributValue
 | 
			
		||||
    extra = 0
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FilterAttributValueInline(admin.TabularInline):
 | 
			
		||||
    """`FilterAttributValue` in admin interface"""
 | 
			
		||||
    model = FilterAttributValue
 | 
			
		||||
    extra = 0
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ServicePatternAdmin(admin.ModelAdmin):
 | 
			
		||||
    """`ServicePattern` in admin interface"""
 | 
			
		||||
    inlines = (
 | 
			
		||||
@@ -70,7 +87,8 @@ class ServicePatternAdmin(admin.ModelAdmin):
 | 
			
		||||
        ReplaceAttributValueInline,
 | 
			
		||||
        FilterAttributValueInline
 | 
			
		||||
    )
 | 
			
		||||
    list_display = ('pos', 'name', 'pattern', 'proxy', 'single_log_out', 'proxy_callback', 'restrict_users')
 | 
			
		||||
    list_display = ('pos', 'name', 'pattern', 'proxy',
 | 
			
		||||
                    'single_log_out', 'proxy_callback', 'restrict_users')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
admin.site.register(User, UserAdmin)
 | 
			
		||||
 
 | 
			
		||||
@@ -19,8 +19,10 @@ try:
 | 
			
		||||
except ImportError:
 | 
			
		||||
    MySQLdb = None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DummyAuthUser(object):
 | 
			
		||||
    """A Dummy authentication class"""
 | 
			
		||||
 | 
			
		||||
    def __init__(self, username):
 | 
			
		||||
        self.username = username
 | 
			
		||||
 | 
			
		||||
@@ -36,6 +38,7 @@ class DummyAuthUser(object):
 | 
			
		||||
class TestAuthUser(DummyAuthUser):
 | 
			
		||||
    """A test authentication class with one user test having
 | 
			
		||||
    alose test as password and some attributes"""
 | 
			
		||||
 | 
			
		||||
    def __init__(self, username):
 | 
			
		||||
        super(TestAuthUser, self).__init__(username)
 | 
			
		||||
 | 
			
		||||
@@ -45,20 +48,21 @@ class TestAuthUser(DummyAuthUser):
 | 
			
		||||
 | 
			
		||||
    def attributs(self):
 | 
			
		||||
        """return a dict of user attributes"""
 | 
			
		||||
        return {'nom':'Nymous', 'prenom':'Ano', 'email':'anonymous@example.net'}
 | 
			
		||||
        return {'nom': 'Nymous', 'prenom': 'Ano', 'email': 'anonymous@example.net'}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MysqlAuthUser(DummyAuthUser):
 | 
			
		||||
    """A mysql auth class: authentication user agains a mysql database"""
 | 
			
		||||
    user = None
 | 
			
		||||
 | 
			
		||||
    def __init__(self, username):
 | 
			
		||||
        mysql_config = {
 | 
			
		||||
            "user": settings.CAS_SQL_USERNAME,
 | 
			
		||||
            "passwd": settings.CAS_SQL_PASSWORD,
 | 
			
		||||
            "db": settings.CAS_SQL_DBNAME,
 | 
			
		||||
            "host": settings.CAS_SQL_HOST,
 | 
			
		||||
            "charset":settings.CAS_SQL_DBCHARSET,
 | 
			
		||||
            "cursorclass":MySQLdb.cursors.DictCursor
 | 
			
		||||
            "charset": settings.CAS_SQL_DBCHARSET,
 | 
			
		||||
            "cursorclass": MySQLdb.cursors.DictCursor
 | 
			
		||||
        }
 | 
			
		||||
        if not MySQLdb:
 | 
			
		||||
            raise RuntimeError("Please install MySQLdb before using the MysqlAuthUser backend")
 | 
			
		||||
@@ -92,9 +96,11 @@ class MysqlAuthUser(DummyAuthUser):
 | 
			
		||||
        else:
 | 
			
		||||
            return self.user
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DjangoAuthUser(DummyAuthUser):
 | 
			
		||||
    """A django auth class: authenticate user agains django internal users"""
 | 
			
		||||
    user = None
 | 
			
		||||
 | 
			
		||||
    def __init__(self, username):
 | 
			
		||||
        try:
 | 
			
		||||
            self.user = User.objects.get(username=username)
 | 
			
		||||
@@ -102,7 +108,6 @@ class DjangoAuthUser(DummyAuthUser):
 | 
			
		||||
            pass
 | 
			
		||||
        super(DjangoAuthUser, self).__init__(username)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def test_password(self, password):
 | 
			
		||||
        """test `password` agains the user"""
 | 
			
		||||
        if not self.user:
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,7 @@
 | 
			
		||||
"""Default values for the app's settings"""
 | 
			
		||||
from django.conf import settings
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def setting_default(name, default_value):
 | 
			
		||||
    """if the config `name` is not set, set it the `default_value`"""
 | 
			
		||||
    value = getattr(settings, name, default_value)
 | 
			
		||||
@@ -60,7 +61,6 @@ setting_default('CAS_SQL_USERNAME', '')
 | 
			
		||||
setting_default('CAS_SQL_PASSWORD', '')
 | 
			
		||||
setting_default('CAS_SQL_DBNAME', '')
 | 
			
		||||
setting_default('CAS_SQL_DBCHARSET', 'utf8')
 | 
			
		||||
setting_default('CAS_SQL_USER_QUERY', 'SELECT user AS usersame, pass AS ' \
 | 
			
		||||
    'password, users.* FROM users WHERE user = %s')
 | 
			
		||||
setting_default('CAS_SQL_PASSWORD_CHECK', 'crypt') # crypt or plain
 | 
			
		||||
 | 
			
		||||
setting_default('CAS_SQL_USER_QUERY', 'SELECT user AS usersame, pass AS '
 | 
			
		||||
                'password, users.* FROM users WHERE user = %s')
 | 
			
		||||
setting_default('CAS_SQL_PASSWORD_CHECK', 'crypt')  # crypt or plain
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,7 @@ from django.utils.translation import ugettext_lazy as _
 | 
			
		||||
import utils
 | 
			
		||||
import models
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class UserCredential(forms.Form):
 | 
			
		||||
    """Form used on the login page to retrive user credentials"""
 | 
			
		||||
    username = forms.CharField(label=_('login'))
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,9 @@
 | 
			
		||||
from django.core.management.base import BaseCommand, CommandError
 | 
			
		||||
from django.core.management.base import BaseCommand
 | 
			
		||||
from django.utils.translation import ugettext_lazy as _
 | 
			
		||||
 | 
			
		||||
from ... import models
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Command(BaseCommand):
 | 
			
		||||
    args = ''
 | 
			
		||||
    help = _(u"Clean deleted sessions")
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,9 @@
 | 
			
		||||
from django.core.management.base import BaseCommand, CommandError
 | 
			
		||||
from django.core.management.base import BaseCommand
 | 
			
		||||
from django.utils.translation import ugettext_lazy as _
 | 
			
		||||
 | 
			
		||||
from ... import models
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Command(BaseCommand):
 | 
			
		||||
    args = ''
 | 
			
		||||
    help = _(u"Clean old trickets")
 | 
			
		||||
 
 | 
			
		||||
@@ -31,6 +31,7 @@ import utils
 | 
			
		||||
 | 
			
		||||
SessionStore = import_module(settings.SESSION_ENGINE).SessionStore
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class User(models.Model):
 | 
			
		||||
    """A user logged into the CAS"""
 | 
			
		||||
    class Meta:
 | 
			
		||||
@@ -123,24 +124,32 @@ class User(models.Model):
 | 
			
		||||
        """Return the url to which the user must be redirected to
 | 
			
		||||
        after a Service Ticket has been generated"""
 | 
			
		||||
        ticket = self.get_ticket(ServiceTicket, service, service_pattern, renew)
 | 
			
		||||
        url = utils.update_url(service, {'ticket':ticket.value})
 | 
			
		||||
        url = utils.update_url(service, {'ticket': ticket.value})
 | 
			
		||||
        return url
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ServicePatternException(Exception):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class BadUsername(ServicePatternException):
 | 
			
		||||
    """Exception raised then an non allowed username
 | 
			
		||||
    try to get a ticket for a service"""
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class BadFilter(ServicePatternException):
 | 
			
		||||
    """"Exception raised then a user try
 | 
			
		||||
    to get a ticket for a service and do not reach a condition"""
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class UserFieldNotDefined(ServicePatternException):
 | 
			
		||||
    """Exception raised then a user try to get a ticket for a service
 | 
			
		||||
    using as username an attribut not present on this user"""
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ServicePattern(models.Model):
 | 
			
		||||
    """Allowed services pattern agains services are tested to"""
 | 
			
		||||
    class Meta:
 | 
			
		||||
@@ -196,11 +205,10 @@ class ServicePattern(models.Model):
 | 
			
		||||
        default="",
 | 
			
		||||
        blank=True,
 | 
			
		||||
        verbose_name=_(u"single log out callback"),
 | 
			
		||||
        help_text=_(u"URL where the SLO request will be POST. empty = service url\n" \
 | 
			
		||||
        help_text=_(u"URL where the SLO request will be POST. empty = service url\n"
 | 
			
		||||
                    u"This is usefull for non HTTP proxied services.")
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def __unicode__(self):
 | 
			
		||||
        return u"%s: %s" % (self.pos, self.pattern)
 | 
			
		||||
 | 
			
		||||
@@ -226,7 +234,6 @@ class ServicePattern(models.Model):
 | 
			
		||||
            raise UserFieldNotDefined()
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def validate(cls, service):
 | 
			
		||||
        """Check if a Service Patern match `service` and
 | 
			
		||||
@@ -236,6 +243,7 @@ class ServicePattern(models.Model):
 | 
			
		||||
                return service_pattern
 | 
			
		||||
        raise cls.DoesNotExist()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Username(models.Model):
 | 
			
		||||
    """A list of allowed usernames on a service pattern"""
 | 
			
		||||
    value = models.CharField(
 | 
			
		||||
@@ -248,6 +256,7 @@ class Username(models.Model):
 | 
			
		||||
    def __unicode__(self):
 | 
			
		||||
        return self.value
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ReplaceAttributName(models.Model):
 | 
			
		||||
    """A list of replacement of attributs name for a service pattern"""
 | 
			
		||||
    class Meta:
 | 
			
		||||
@@ -261,8 +270,8 @@ class ReplaceAttributName(models.Model):
 | 
			
		||||
        max_length=255,
 | 
			
		||||
        blank=True,
 | 
			
		||||
        verbose_name=_(u"replace"),
 | 
			
		||||
        help_text=_(u"name under which the attribut will be show" \
 | 
			
		||||
        u"to the service. empty = default name of the attribut")
 | 
			
		||||
        help_text=_(u"name under which the attribut will be show"
 | 
			
		||||
                    u"to the service. empty = default name of the attribut")
 | 
			
		||||
    )
 | 
			
		||||
    service_pattern = models.ForeignKey(ServicePattern, related_name="attributs")
 | 
			
		||||
 | 
			
		||||
@@ -272,6 +281,7 @@ class ReplaceAttributName(models.Model):
 | 
			
		||||
        else:
 | 
			
		||||
            return u"%s → %s" % (self.name, self.replace)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FilterAttributValue(models.Model):
 | 
			
		||||
    """A list of filter on attributs for a service pattern"""
 | 
			
		||||
    attribut = models.CharField(
 | 
			
		||||
@@ -289,6 +299,7 @@ class FilterAttributValue(models.Model):
 | 
			
		||||
    def __unicode__(self):
 | 
			
		||||
        return u"%s %s" % (self.attribut, self.pattern)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ReplaceAttributValue(models.Model):
 | 
			
		||||
    """Replacement to apply on attributs values for a service pattern"""
 | 
			
		||||
    attribut = models.CharField(
 | 
			
		||||
@@ -338,10 +349,10 @@ class Ticket(models.Model):
 | 
			
		||||
        # removing old validated ticket and non validated expired tickets
 | 
			
		||||
        cls.objects.filter(
 | 
			
		||||
            (
 | 
			
		||||
                Q(single_log_out=False)&Q(validate=True)
 | 
			
		||||
            )|(
 | 
			
		||||
                Q(validate=False)&\
 | 
			
		||||
                Q(creation__lt=(timezone.now() - timedelta(seconds=cls.VALIDITY)))
 | 
			
		||||
                Q(single_log_out=False) & Q(validate=True)
 | 
			
		||||
            ) | (
 | 
			
		||||
                Q(validate=False)
 | 
			
		||||
                & Q(creation__lt=(timezone.now() - timedelta(seconds=cls.VALIDITY)))
 | 
			
		||||
            )
 | 
			
		||||
        ).delete()
 | 
			
		||||
 | 
			
		||||
@@ -373,18 +384,18 @@ class Ticket(models.Model):
 | 
			
		||||
    <saml:NameID xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"></saml:NameID>
 | 
			
		||||
    <samlp:SessionIndex>%(ticket)s</samlp:SessionIndex>
 | 
			
		||||
  </samlp:LogoutRequest>""" % \
 | 
			
		||||
            {
 | 
			
		||||
                'id' : os.urandom(20).encode("hex"),
 | 
			
		||||
                'datetime' : timezone.now().isoformat(),
 | 
			
		||||
                'ticket': self.value
 | 
			
		||||
            }
 | 
			
		||||
                    {
 | 
			
		||||
                        'id': os.urandom(20).encode("hex"),
 | 
			
		||||
                        'datetime': timezone.now().isoformat(),
 | 
			
		||||
                        'ticket':  self.value
 | 
			
		||||
                    }
 | 
			
		||||
                if self.service_pattern.single_log_out_callback:
 | 
			
		||||
                    url = self.service_pattern.single_log_out_callback
 | 
			
		||||
                else:
 | 
			
		||||
                   url = self.service
 | 
			
		||||
                    url = self.service
 | 
			
		||||
                return session.post(
 | 
			
		||||
                    url.encode('utf-8'),
 | 
			
		||||
                    data={'logoutRequest':xml.encode('utf-8')},
 | 
			
		||||
                    data={'logoutRequest': xml.encode('utf-8')},
 | 
			
		||||
                )
 | 
			
		||||
            except Exception as error:
 | 
			
		||||
                if request is not None:
 | 
			
		||||
@@ -393,33 +404,40 @@ class Ticket(models.Model):
 | 
			
		||||
                        request,
 | 
			
		||||
                        messages.WARNING,
 | 
			
		||||
                        _(u'Error during service logout %(service)s:\n%(error)s') %
 | 
			
		||||
                        {'service': self.service, 'error':error}
 | 
			
		||||
                        {'service':  self.service, 'error': error}
 | 
			
		||||
                    )
 | 
			
		||||
                else:
 | 
			
		||||
                    sys.stderr.write("%r\n" % error)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ServiceTicket(Ticket):
 | 
			
		||||
    """A Service Ticket"""
 | 
			
		||||
    PREFIX = settings.CAS_SERVICE_TICKET_PREFIX
 | 
			
		||||
    value = models.CharField(max_length=255, default=utils.gen_st, unique=True)
 | 
			
		||||
 | 
			
		||||
    def __unicode__(self):
 | 
			
		||||
        return u"ServiceTicket-%s" % self.pk
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ProxyTicket(Ticket):
 | 
			
		||||
    """A Proxy Ticket"""
 | 
			
		||||
    PREFIX = settings.CAS_PROXY_TICKET_PREFIX
 | 
			
		||||
    value = models.CharField(max_length=255, default=utils.gen_pt, unique=True)
 | 
			
		||||
 | 
			
		||||
    def __unicode__(self):
 | 
			
		||||
        return u"ProxyTicket-%s" % self.pk
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ProxyGrantingTicket(Ticket):
 | 
			
		||||
    """A Proxy Granting Ticket"""
 | 
			
		||||
    PREFIX = settings.CAS_PROXY_GRANTING_TICKET_PREFIX
 | 
			
		||||
    VALIDITY = settings.CAS_PGT_VALIDITY
 | 
			
		||||
    value = models.CharField(max_length=255, default=utils.gen_pgt, unique=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def __unicode__(self):
 | 
			
		||||
        return u"ProxyGrantingTicket-%s" % self.pk
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Proxy(models.Model):
 | 
			
		||||
    """A list of proxies on `ProxyTicket`"""
 | 
			
		||||
    class Meta:
 | 
			
		||||
@@ -429,4 +447,3 @@ class Proxy(models.Model):
 | 
			
		||||
 | 
			
		||||
    def __unicode__(self):
 | 
			
		||||
        return self.url
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +0,0 @@
 | 
			
		||||
# This program is distributed in the hope that it will be useful, but WITHOUT
 | 
			
		||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 | 
			
		||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License version 3 for
 | 
			
		||||
# more details.
 | 
			
		||||
#
 | 
			
		||||
# You should have received a copy of the GNU General Public License version 3
 | 
			
		||||
# along with this program; if not, write to the Free Software Foundation, Inc., 51
 | 
			
		||||
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 | 
			
		||||
#
 | 
			
		||||
# (c) 2015 Valentin Samir
 | 
			
		||||
from django.test import TestCase
 | 
			
		||||
 | 
			
		||||
@@ -21,12 +21,27 @@ urlpatterns = patterns(
 | 
			
		||||
    url('^login$', views.LoginView.as_view(), name='login'),
 | 
			
		||||
    url('^logout$', views.LogoutView.as_view(), name='logout'),
 | 
			
		||||
    url('^validate$', views.Validate.as_view(), name='validate'),
 | 
			
		||||
    url('^serviceValidate$', views.ValidateService.as_view(allow_proxy_ticket=False), name='serviceValidate'),
 | 
			
		||||
    url('^proxyValidate$', views.ValidateService.as_view(allow_proxy_ticket=True), name='proxyValidate'),
 | 
			
		||||
    url(
 | 
			
		||||
        '^serviceValidate$',
 | 
			
		||||
        views.ValidateService.as_view(allow_proxy_ticket=False),
 | 
			
		||||
        name='serviceValidate'
 | 
			
		||||
    ),
 | 
			
		||||
    url(
 | 
			
		||||
        '^proxyValidate$',
 | 
			
		||||
        views.ValidateService.as_view(allow_proxy_ticket=True),
 | 
			
		||||
        name='proxyValidate'
 | 
			
		||||
    ),
 | 
			
		||||
    url('^proxy$', views.Proxy.as_view(), name='proxy'),
 | 
			
		||||
    url('^p3/serviceValidate$', views.ValidateService.as_view(allow_proxy_ticket=False), name='p3_serviceValidate'),
 | 
			
		||||
    url('^p3/proxyValidate$', views.ValidateService.as_view(allow_proxy_ticket=True), name='p3_proxyValidate'),
 | 
			
		||||
    url(
 | 
			
		||||
        '^p3/serviceValidate$',
 | 
			
		||||
        views.ValidateService.as_view(allow_proxy_ticket=False),
 | 
			
		||||
        name='p3_serviceValidate'
 | 
			
		||||
    ),
 | 
			
		||||
    url(
 | 
			
		||||
        '^p3/proxyValidate$',
 | 
			
		||||
        views.ValidateService.as_view(allow_proxy_ticket=True),
 | 
			
		||||
        name='p3_proxyValidate'
 | 
			
		||||
    ),
 | 
			
		||||
    url('^samlValidate$', views.SamlValidate.as_view(), name='samlValidate'),
 | 
			
		||||
    url('^auth$', views.Auth.as_view(), name='auth'),
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -21,6 +21,7 @@ import urllib
 | 
			
		||||
import random
 | 
			
		||||
import string
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def import_attr(path):
 | 
			
		||||
    """transform a python module.attr path to the attr"""
 | 
			
		||||
    if not isinstance(path, str):
 | 
			
		||||
@@ -28,16 +29,18 @@ def import_attr(path):
 | 
			
		||||
    module, attr = path.rsplit('.', 1)
 | 
			
		||||
    return getattr(import_module(module), attr)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def redirect_params(url_name, params=None):
 | 
			
		||||
    """Redirect to `url_name` with `params` as querystring"""
 | 
			
		||||
    url = reverse(url_name)
 | 
			
		||||
    params = urllib.urlencode(params if params else {})
 | 
			
		||||
    return HttpResponseRedirect(url + "?%s" % params)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def update_url(url, params):
 | 
			
		||||
    """update params in the `url` query string"""
 | 
			
		||||
    if isinstance(url, unicode):
 | 
			
		||||
       url = url.encode('utf-8')
 | 
			
		||||
        url = url.encode('utf-8')
 | 
			
		||||
    for key, value in params.items():
 | 
			
		||||
        if isinstance(key, unicode):
 | 
			
		||||
            del params[key]
 | 
			
		||||
@@ -51,6 +54,7 @@ def update_url(url, params):
 | 
			
		||||
    url_parts[4] = urllib.urlencode(query)
 | 
			
		||||
    return urlparse.urlunparse(url_parts).decode('utf-8')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def unpack_nested_exception(error):
 | 
			
		||||
    """If exception are stacked, return the first one"""
 | 
			
		||||
    i = 0
 | 
			
		||||
@@ -77,22 +81,27 @@ def _gen_ticket(prefix, lg=settings.CAS_TICKET_LEN):
 | 
			
		||||
        )
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def gen_lt():
 | 
			
		||||
    """Generate a Service Ticket"""
 | 
			
		||||
    return _gen_ticket(settings.CAS_LOGIN_TICKET_PREFIX, settings.CAS_LT_LEN)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def gen_st():
 | 
			
		||||
    """Generate a Service Ticket"""
 | 
			
		||||
    return _gen_ticket(settings.CAS_SERVICE_TICKET_PREFIX, settings.CAS_ST_LEN)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def gen_pt():
 | 
			
		||||
    """Generate a Proxy Ticket"""
 | 
			
		||||
    return _gen_ticket(settings.CAS_PROXY_TICKET_PREFIX, settings.CAS_PT_LEN)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def gen_pgt():
 | 
			
		||||
    """Generate a Proxy Granting Ticket"""
 | 
			
		||||
    return _gen_ticket(settings.CAS_PROXY_GRANTING_TICKET_PREFIX, settings.CAS_PGT_LEN)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def gen_pgtiou():
 | 
			
		||||
    """Generate a Proxy Granting Ticket IOU"""
 | 
			
		||||
    return _gen_ticket(settings.CAS_PROXY_GRANTING_TICKET_IOU_PREFIX, settings.CAS_PGTIOU_LEN)
 | 
			
		||||
 
 | 
			
		||||
@@ -33,6 +33,7 @@ import models
 | 
			
		||||
from .models import ServiceTicket, ProxyTicket, ProxyGrantingTicket
 | 
			
		||||
from .models import ServicePattern
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AttributesMixin(object):
 | 
			
		||||
    """mixin for the attributs methode"""
 | 
			
		||||
 | 
			
		||||
@@ -49,6 +50,7 @@ class AttributesMixin(object):
 | 
			
		||||
                attributes.append((key, value))
 | 
			
		||||
        return attributes
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LogoutMixin(object):
 | 
			
		||||
    """destroy CAS session utils"""
 | 
			
		||||
    def clean_session_variables(self):
 | 
			
		||||
@@ -80,6 +82,7 @@ class LogoutMixin(object):
 | 
			
		||||
        finally:
 | 
			
		||||
            self.clean_session_variables()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LogoutView(View, LogoutMixin):
 | 
			
		||||
    """destroy CAS session (logout) view"""
 | 
			
		||||
 | 
			
		||||
@@ -94,10 +97,10 @@ class LogoutView(View, LogoutMixin):
 | 
			
		||||
        self.logout()
 | 
			
		||||
        # if service is set, redirect to service after logout
 | 
			
		||||
        if self.service:
 | 
			
		||||
            list(messages.get_messages(request)) # clean messages before leaving the django app
 | 
			
		||||
            list(messages.get_messages(request))  # clean messages before leaving the django app
 | 
			
		||||
            return HttpResponseRedirect(self.service)
 | 
			
		||||
        elif self.url:
 | 
			
		||||
            list(messages.get_messages(request)) # clean messages before leaving the django app
 | 
			
		||||
            list(messages.get_messages(request))  # clean messages before leaving the django app
 | 
			
		||||
            return HttpResponseRedirect(self.url)
 | 
			
		||||
        # else redirect to login page
 | 
			
		||||
        else:
 | 
			
		||||
@@ -107,6 +110,7 @@ class LogoutView(View, LogoutMixin):
 | 
			
		||||
            else:
 | 
			
		||||
                return render(request, settings.CAS_LOGOUT_TEMPLATE)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LoginView(View, LogoutMixin):
 | 
			
		||||
    """credential requestor / acceptor"""
 | 
			
		||||
 | 
			
		||||
@@ -188,10 +192,10 @@ class LoginView(View, LogoutMixin):
 | 
			
		||||
            self.request,
 | 
			
		||||
            values,
 | 
			
		||||
            initial={
 | 
			
		||||
                'service':self.service,
 | 
			
		||||
                'method':self.method,
 | 
			
		||||
                'warn':self.request.session.get("warn"),
 | 
			
		||||
                'lt':self.request.session['lt']
 | 
			
		||||
                'service': self.service,
 | 
			
		||||
                'method': self.method,
 | 
			
		||||
                'warn': self.request.session.get("warn"),
 | 
			
		||||
                'lt': self.request.session['lt']
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
@@ -207,13 +211,13 @@ class LoginView(View, LogoutMixin):
 | 
			
		||||
                messages.add_message(
 | 
			
		||||
                    self.request,
 | 
			
		||||
                    messages.WARNING,
 | 
			
		||||
                    _(u"Authentication has been required by service %(name)s (%(url)s)") % \
 | 
			
		||||
                    {'name':service_pattern.name, 'url':self.service}
 | 
			
		||||
                    _(u"Authentication has been required by service %(name)s (%(url)s)") %
 | 
			
		||||
                    {'name': service_pattern.name, 'url': self.service}
 | 
			
		||||
                )
 | 
			
		||||
                return render(
 | 
			
		||||
                    self.request,
 | 
			
		||||
                    settings.CAS_WARN_TEMPLATE,
 | 
			
		||||
                    {'service_ticket_url':self.user.get_service_url(
 | 
			
		||||
                    {'service_ticket_url': self.user.get_service_url(
 | 
			
		||||
                        self.service,
 | 
			
		||||
                        service_pattern,
 | 
			
		||||
                        renew=self.renew
 | 
			
		||||
@@ -221,7 +225,7 @@ class LoginView(View, LogoutMixin):
 | 
			
		||||
                )
 | 
			
		||||
            else:
 | 
			
		||||
                # redirect, using method ?
 | 
			
		||||
                list(messages.get_messages(self.request)) # clean messages before leaving django
 | 
			
		||||
                list(messages.get_messages(self.request))  # clean messages before leaving django
 | 
			
		||||
                return HttpResponseRedirect(
 | 
			
		||||
                    self.user.get_service_url(self.service, service_pattern, renew=self.renew)
 | 
			
		||||
                )
 | 
			
		||||
@@ -229,7 +233,7 @@ class LoginView(View, LogoutMixin):
 | 
			
		||||
            messages.add_message(
 | 
			
		||||
                self.request,
 | 
			
		||||
                messages.ERROR,
 | 
			
		||||
                _(u'Service %(url)s non allowed.') % {'url' : self.service}
 | 
			
		||||
                _(u'Service %(url)s non allowed.') % {'url': self.service}
 | 
			
		||||
            )
 | 
			
		||||
        except models.BadUsername:
 | 
			
		||||
            messages.add_message(
 | 
			
		||||
@@ -247,16 +251,16 @@ class LoginView(View, LogoutMixin):
 | 
			
		||||
            messages.add_message(
 | 
			
		||||
                self.request,
 | 
			
		||||
                messages.ERROR,
 | 
			
		||||
                _(u"The attribut %(field)s is needed to use" \
 | 
			
		||||
                   " that service") % {'field':service_pattern.user_field}
 | 
			
		||||
                _(u"The attribut %(field)s is needed to use"
 | 
			
		||||
                  u" that service") % {'field': service_pattern.user_field}
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
        # if gateway is set and auth failed redirect to the service without authentication
 | 
			
		||||
        if self.gateway:
 | 
			
		||||
            list(messages.get_messages(self.request)) # clean messages before leaving django
 | 
			
		||||
            list(messages.get_messages(self.request))  # clean messages before leaving django
 | 
			
		||||
            return HttpResponseRedirect(self.service)
 | 
			
		||||
 | 
			
		||||
        return render(self.request, settings.CAS_LOGGED_TEMPLATE, {'session':self.request.session})
 | 
			
		||||
        return render(self.request, settings.CAS_LOGGED_TEMPLATE, {'session': self.request.session})
 | 
			
		||||
 | 
			
		||||
    def authenticated(self):
 | 
			
		||||
        """Processing authenticated users"""
 | 
			
		||||
@@ -276,7 +280,7 @@ class LoginView(View, LogoutMixin):
 | 
			
		||||
            return render(
 | 
			
		||||
                self.request,
 | 
			
		||||
                settings.CAS_LOGGED_TEMPLATE,
 | 
			
		||||
                {'session':self.request.session}
 | 
			
		||||
                {'session': self.request.session}
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
    def not_authenticated(self):
 | 
			
		||||
@@ -285,21 +289,22 @@ class LoginView(View, LogoutMixin):
 | 
			
		||||
            try:
 | 
			
		||||
                service_pattern = ServicePattern.validate(self.service)
 | 
			
		||||
                if self.gateway:
 | 
			
		||||
                    list(messages.get_messages(self.request))# clean messages before leaving django
 | 
			
		||||
                    # clean messages before leaving django
 | 
			
		||||
                    list(messages.get_messages(self.request))
 | 
			
		||||
                    return HttpResponseRedirect(self.service)
 | 
			
		||||
                if self.request.session.get("authenticated") and self.renew:
 | 
			
		||||
                    messages.add_message(
 | 
			
		||||
                        self.request,
 | 
			
		||||
                        messages.WARNING,
 | 
			
		||||
                        _(u"Authentication renewal required by service %(name)s (%(url)s).") %
 | 
			
		||||
                        {'name':service_pattern.name, 'url':self.service}
 | 
			
		||||
                        {'name': service_pattern.name, 'url': self.service}
 | 
			
		||||
                    )
 | 
			
		||||
                else:
 | 
			
		||||
                    messages.add_message(
 | 
			
		||||
                        self.request,
 | 
			
		||||
                        messages.WARNING,
 | 
			
		||||
                        _(u"Authentication required by service %(name)s (%(url)s).") %
 | 
			
		||||
                        {'name':service_pattern.name, 'url':self.service}
 | 
			
		||||
                        {'name': service_pattern.name, 'url': self.service}
 | 
			
		||||
                    )
 | 
			
		||||
            except ServicePattern.DoesNotExist:
 | 
			
		||||
                messages.add_message(
 | 
			
		||||
@@ -307,7 +312,7 @@ class LoginView(View, LogoutMixin):
 | 
			
		||||
                    messages.ERROR,
 | 
			
		||||
                    _(u'Service %s non allowed') % self.service
 | 
			
		||||
                )
 | 
			
		||||
        return render(self.request, settings.CAS_LOGIN_TEMPLATE, {'form':self.form})
 | 
			
		||||
        return render(self.request, settings.CAS_LOGIN_TEMPLATE, {'form': self.form})
 | 
			
		||||
 | 
			
		||||
    def common(self):
 | 
			
		||||
        """Part execute uppon GET and POST request"""
 | 
			
		||||
@@ -317,6 +322,7 @@ class LoginView(View, LogoutMixin):
 | 
			
		||||
        else:
 | 
			
		||||
            return self.not_authenticated()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Auth(View):
 | 
			
		||||
    """A simple view to validate username/password/service tuple"""
 | 
			
		||||
    @method_decorator(csrf_exempt)
 | 
			
		||||
@@ -342,16 +348,16 @@ class Auth(View):
 | 
			
		||||
            request,
 | 
			
		||||
            request.POST,
 | 
			
		||||
            initial={
 | 
			
		||||
                'service':service,
 | 
			
		||||
                'method':'POST',
 | 
			
		||||
                'warn':False
 | 
			
		||||
                'service': service,
 | 
			
		||||
                'method': 'POST',
 | 
			
		||||
                'warn': False
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
        if form.is_valid():
 | 
			
		||||
            try:
 | 
			
		||||
                user = models.User.objects.get(
 | 
			
		||||
                    username=form.cleaned_data['username'],
 | 
			
		||||
                    session_key=self.request.session.session_key
 | 
			
		||||
                    session_key=request.session.session_key
 | 
			
		||||
                )
 | 
			
		||||
                # is the service allowed
 | 
			
		||||
                service_pattern = ServicePattern.validate(service)
 | 
			
		||||
@@ -360,11 +366,12 @@ class Auth(View):
 | 
			
		||||
                if not request.session.get("authenticated"):
 | 
			
		||||
                    user.delete()
 | 
			
		||||
                return HttpResponse("yes\n", content_type="text/plain")
 | 
			
		||||
            except (ServicePattern.DoesNotExist, ServicePatternException) as error:
 | 
			
		||||
            except (ServicePattern.DoesNotExist, models.ServicePatternException):
 | 
			
		||||
                return HttpResponse("no\n", content_type="text/plain")
 | 
			
		||||
        else:
 | 
			
		||||
            return HttpResponse("no\n", content_type="text/plain")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Validate(View):
 | 
			
		||||
    """service ticket validation"""
 | 
			
		||||
    @staticmethod
 | 
			
		||||
@@ -406,7 +413,7 @@ class ValidateError(Exception):
 | 
			
		||||
        return render(
 | 
			
		||||
            request,
 | 
			
		||||
            "cas_server/serviceValidateError.xml",
 | 
			
		||||
            {'code':self.code, 'msg':self.msg},
 | 
			
		||||
            {'code': self.code, 'msg': self.msg},
 | 
			
		||||
            content_type="text/xml; charset=utf-8"
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
@@ -437,12 +444,12 @@ class ValidateService(View, AttributesMixin):
 | 
			
		||||
            try:
 | 
			
		||||
                self.ticket, proxies = self.process_ticket()
 | 
			
		||||
                params = {
 | 
			
		||||
                    'username':self.ticket.user.username,
 | 
			
		||||
                    'attributes':self.attributes(),
 | 
			
		||||
                    'proxies':proxies
 | 
			
		||||
                    'username': self.ticket.user.username,
 | 
			
		||||
                    'attributes': self.attributes(),
 | 
			
		||||
                    'proxies': proxies
 | 
			
		||||
                }
 | 
			
		||||
                if self.ticket.service_pattern.user_field and \
 | 
			
		||||
                self.ticket.user.attributs.get(self.ticket.service_pattern.user_field):
 | 
			
		||||
                if (self.ticket.service_pattern.user_field and
 | 
			
		||||
                        self.ticket.user.attributs.get(self.ticket.service_pattern.user_field)):
 | 
			
		||||
                    params['username'] = self.ticket.user.attributs.get(
 | 
			
		||||
                        self.ticket.service_pattern.user_field
 | 
			
		||||
                    )
 | 
			
		||||
@@ -458,7 +465,6 @@ class ValidateService(View, AttributesMixin):
 | 
			
		||||
            except ValidateError as error:
 | 
			
		||||
                return error.render(request)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def process_ticket(self):
 | 
			
		||||
        """fetch the ticket angains the database and check its validity"""
 | 
			
		||||
        try:
 | 
			
		||||
@@ -489,7 +495,6 @@ class ValidateService(View, AttributesMixin):
 | 
			
		||||
        except (ServiceTicket.DoesNotExist, ProxyTicket.DoesNotExist):
 | 
			
		||||
            raise ValidateError('INVALID_TICKET', 'ticket not found')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def process_pgturl(self, params):
 | 
			
		||||
        """Handle PGT request"""
 | 
			
		||||
        try:
 | 
			
		||||
@@ -502,7 +507,7 @@ class ValidateService(View, AttributesMixin):
 | 
			
		||||
                    service_pattern=pattern,
 | 
			
		||||
                    single_log_out=pattern.single_log_out
 | 
			
		||||
                )
 | 
			
		||||
                url = utils.update_url(self.pgt_url, {'pgtIou':proxyid, 'pgtId':pticket.value})
 | 
			
		||||
                url = utils.update_url(self.pgt_url, {'pgtIou': proxyid, 'pgtId': pticket.value})
 | 
			
		||||
                try:
 | 
			
		||||
                    ret = requests.get(url, verify=settings.CAS_PROXY_CA_CERTIFICATE_PATH)
 | 
			
		||||
                    if ret.status_code == 200:
 | 
			
		||||
@@ -529,6 +534,7 @@ class ValidateService(View, AttributesMixin):
 | 
			
		||||
                'callback url not allowed by configuration'
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Proxy(View):
 | 
			
		||||
    """proxy ticket service"""
 | 
			
		||||
 | 
			
		||||
@@ -552,7 +558,6 @@ class Proxy(View):
 | 
			
		||||
        except ValidateError as error:
 | 
			
		||||
            return error.render(request)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def process_proxy(self):
 | 
			
		||||
        """handle PT request"""
 | 
			
		||||
        try:
 | 
			
		||||
@@ -579,7 +584,7 @@ class Proxy(View):
 | 
			
		||||
            return render(
 | 
			
		||||
                self.request,
 | 
			
		||||
                "cas_server/proxy.xml",
 | 
			
		||||
                {'ticket':pticket.value},
 | 
			
		||||
                {'ticket': pticket.value},
 | 
			
		||||
                content_type="text/xml; charset=utf-8"
 | 
			
		||||
            )
 | 
			
		||||
        except ProxyGrantingTicket.DoesNotExist:
 | 
			
		||||
@@ -593,7 +598,6 @@ class Proxy(View):
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SamlValidateError(Exception):
 | 
			
		||||
    """handle saml validation error"""
 | 
			
		||||
    def __init__(self, code, msg=""):
 | 
			
		||||
@@ -610,27 +614,14 @@ class SamlValidateError(Exception):
 | 
			
		||||
            request,
 | 
			
		||||
            "cas_server/samlValidateError.xml",
 | 
			
		||||
            {
 | 
			
		||||
                'code':self.code,
 | 
			
		||||
                'msg':self.msg,
 | 
			
		||||
                'IssueInstant':timezone.now().isoformat(),
 | 
			
		||||
                'ResponseID':utils.gen_saml_id()
 | 
			
		||||
                'code': self.code,
 | 
			
		||||
                'msg': self.msg,
 | 
			
		||||
                'IssueInstant': timezone.now().isoformat(),
 | 
			
		||||
                'ResponseID': utils.gen_saml_id()
 | 
			
		||||
            },
 | 
			
		||||
            content_type="text/xml; charset=utf-8"
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
def _saml_validate_error(request, code, msg=""):
 | 
			
		||||
    """render the samlValidateError.xml templace using `code` and `msg`"""
 | 
			
		||||
    return render(
 | 
			
		||||
        request,
 | 
			
		||||
        "cas_server/samlValidateError.xml",
 | 
			
		||||
        {
 | 
			
		||||
            'code':code,
 | 
			
		||||
            'msg':msg,
 | 
			
		||||
            'IssueInstant':timezone.now().isoformat(),
 | 
			
		||||
            'ResponseID':utils.gen_saml_id()
 | 
			
		||||
        },
 | 
			
		||||
        content_type="text/xml; charset=utf-8"
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
class SamlValidate(View, AttributesMixin):
 | 
			
		||||
    """SAML ticket validation"""
 | 
			
		||||
@@ -651,19 +642,19 @@ class SamlValidate(View, AttributesMixin):
 | 
			
		||||
        self.root = etree.fromstring(request.body)
 | 
			
		||||
        try:
 | 
			
		||||
            self.ticket = self.process_ticket()
 | 
			
		||||
            expire_instant = (self.ticket.creation + \
 | 
			
		||||
            timedelta(seconds=self.ticket.VALIDITY)).isoformat()
 | 
			
		||||
            expire_instant = (self.ticket.creation +
 | 
			
		||||
                              timedelta(seconds=self.ticket.VALIDITY)).isoformat()
 | 
			
		||||
            attributes = self.attributes()
 | 
			
		||||
            params = {
 | 
			
		||||
                'IssueInstant':timezone.now().isoformat(),
 | 
			
		||||
                'expireInstant':expire_instant,
 | 
			
		||||
                'Recipient':self.target,
 | 
			
		||||
                'ResponseID':utils.gen_saml_id(),
 | 
			
		||||
                'username':self.ticket.user.username,
 | 
			
		||||
                'attributes':attributes
 | 
			
		||||
                'IssueInstant': timezone.now().isoformat(),
 | 
			
		||||
                'expireInstant': expire_instant,
 | 
			
		||||
                'Recipient': self.target,
 | 
			
		||||
                'ResponseID': utils.gen_saml_id(),
 | 
			
		||||
                'username': self.ticket.user.username,
 | 
			
		||||
                'attributes': attributes
 | 
			
		||||
            }
 | 
			
		||||
            if self.ticket.service_pattern.user_field and \
 | 
			
		||||
            self.ticket.user.attributs.get(self.ticket.service_pattern.user_field):
 | 
			
		||||
                    self.ticket.user.attributs.get(self.ticket.service_pattern.user_field):
 | 
			
		||||
                params['username'] = self.ticket.user.attributs.get(
 | 
			
		||||
                    self.ticket.service_pattern.user_field
 | 
			
		||||
                )
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user