2015-05-27 20:10:06 +00:00
|
|
|
# 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.
|
|
|
|
#
|
2016-06-30 22:00:53 +00:00
|
|
|
# (c) 2015-2016 Valentin Samir
|
2015-05-27 19:56:39 +00:00
|
|
|
"""forms for the app"""
|
2016-06-21 12:42:35 +00:00
|
|
|
from .default_settings import settings
|
2015-05-17 21:24:41 +00:00
|
|
|
|
2015-05-16 21:43:46 +00:00
|
|
|
from django import forms
|
2015-05-22 15:55:00 +00:00
|
|
|
from django.utils.translation import ugettext_lazy as _
|
2015-05-16 21:43:46 +00:00
|
|
|
|
2015-06-21 16:56:16 +00:00
|
|
|
import cas_server.utils as utils
|
|
|
|
import cas_server.models as models
|
2015-05-16 21:43:46 +00:00
|
|
|
|
2016-06-03 12:19:43 +00:00
|
|
|
|
2016-07-23 23:49:03 +00:00
|
|
|
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"
|
2016-07-29 11:56:23 +00:00
|
|
|
if field.label: # pragma: no branch (currently all field are hidden or labeled)
|
2016-07-23 23:49:03 +00:00
|
|
|
attrs["placeholder"] = field.label
|
|
|
|
if field.required:
|
|
|
|
attrs["required"] = "required"
|
|
|
|
field.widget.attrs.update(attrs)
|
|
|
|
|
|
|
|
|
|
|
|
class WarnForm(BootsrapForm):
|
2016-07-20 16:28:23 +00:00
|
|
|
"""
|
|
|
|
Bases: :class:`django.forms.Form`
|
|
|
|
|
|
|
|
Form used on warn page before emiting a ticket
|
|
|
|
"""
|
|
|
|
|
|
|
|
#: The service url for which the user want a ticket
|
2016-06-03 12:11:07 +00:00
|
|
|
service = forms.CharField(widget=forms.HiddenInput(), required=False)
|
2016-07-20 16:28:23 +00:00
|
|
|
#: Is the service asking the authentication renewal ?
|
2016-06-03 12:11:07 +00:00
|
|
|
renew = forms.BooleanField(widget=forms.HiddenInput(), required=False)
|
2016-07-20 16:28:23 +00:00
|
|
|
#: Url to redirect to if the authentication fail (user not authenticated or bad service)
|
2016-06-03 12:11:07 +00:00
|
|
|
gateway = forms.CharField(widget=forms.HiddenInput(), required=False)
|
|
|
|
method = forms.CharField(widget=forms.HiddenInput(), required=False)
|
2016-07-20 16:28:23 +00:00
|
|
|
#: ``True`` if the user has been warned of the ticket emission
|
2016-06-03 12:11:07 +00:00
|
|
|
warned = forms.BooleanField(widget=forms.HiddenInput(), required=False)
|
2016-07-20 16:28:23 +00:00
|
|
|
#: A valid LoginTicket to prevent POST replay
|
2016-06-03 12:11:07 +00:00
|
|
|
lt = forms.CharField(widget=forms.HiddenInput(), required=False)
|
2015-06-12 16:10:52 +00:00
|
|
|
|
2016-06-03 12:19:43 +00:00
|
|
|
|
2016-07-23 23:49:03 +00:00
|
|
|
class FederateSelect(BootsrapForm):
|
2016-07-03 15:54:11 +00:00
|
|
|
"""
|
2016-07-20 16:28:23 +00:00
|
|
|
Bases: :class:`django.forms.Form`
|
|
|
|
|
|
|
|
Form used on the login page when ``settings.CAS_FEDERATE`` is ``True``
|
|
|
|
allowing the user to choose an identity provider.
|
2016-07-03 15:54:11 +00:00
|
|
|
"""
|
2016-07-20 16:28:23 +00:00
|
|
|
#: The providers the user can choose to be used as authentication backend
|
2016-07-04 15:23:11 +00:00
|
|
|
provider = forms.ModelChoiceField(
|
2016-07-04 15:40:31 +00:00
|
|
|
queryset=models.FederatedIendityProvider.objects.filter(display=True).order_by(
|
2016-07-04 15:23:11 +00:00
|
|
|
"pos",
|
|
|
|
"verbose_name",
|
|
|
|
"suffix"
|
|
|
|
),
|
|
|
|
to_field_name="suffix",
|
2016-06-17 17:28:49 +00:00
|
|
|
label=_('Identity provider'),
|
|
|
|
)
|
2016-07-20 16:28:23 +00:00
|
|
|
#: The service url for which the user want a ticket
|
2016-06-17 17:28:49 +00:00
|
|
|
service = forms.CharField(label=_('service'), widget=forms.HiddenInput(), required=False)
|
|
|
|
method = forms.CharField(widget=forms.HiddenInput(), required=False)
|
2016-07-20 16:28:23 +00:00
|
|
|
#: A checkbox to remember the user choices of :attr:`provider<FederateSelect.provider>`
|
2016-06-17 17:28:49 +00:00
|
|
|
remember = forms.BooleanField(label=_('Remember the identity provider'), required=False)
|
2016-07-20 16:28:23 +00:00
|
|
|
#: A checkbox to ask to be warn before emiting a ticket for another service
|
2016-07-29 23:31:43 +00:00
|
|
|
warn = forms.BooleanField(
|
|
|
|
label=_('Warn me before logging me into other sites.'),
|
|
|
|
required=False
|
|
|
|
)
|
2016-07-20 16:28:23 +00:00
|
|
|
#: Is the service asking the authentication renewal ?
|
2016-06-28 13:29:45 +00:00
|
|
|
renew = forms.BooleanField(widget=forms.HiddenInput(), required=False)
|
2016-06-17 17:28:49 +00:00
|
|
|
|
|
|
|
|
2016-07-23 23:49:03 +00:00
|
|
|
class UserCredential(BootsrapForm):
|
2016-07-20 16:28:23 +00:00
|
|
|
"""
|
|
|
|
Bases: :class:`django.forms.Form`
|
|
|
|
|
|
|
|
Form used on the login page to retrive user credentials
|
|
|
|
"""
|
|
|
|
#: The user username
|
2016-07-29 23:31:43 +00:00
|
|
|
username = forms.CharField(label=_('username'))
|
2016-07-20 16:28:23 +00:00
|
|
|
#: The service url for which the user want a ticket
|
2015-06-11 21:04:26 +00:00
|
|
|
service = forms.CharField(label=_('service'), widget=forms.HiddenInput(), required=False)
|
2016-07-20 16:28:23 +00:00
|
|
|
#: The user password
|
2015-05-22 15:55:00 +00:00
|
|
|
password = forms.CharField(label=_('password'), widget=forms.PasswordInput)
|
2016-07-20 16:28:23 +00:00
|
|
|
#: A valid LoginTicket to prevent POST replay
|
2015-06-09 20:04:05 +00:00
|
|
|
lt = forms.CharField(widget=forms.HiddenInput(), required=False)
|
2015-05-16 21:43:46 +00:00
|
|
|
method = forms.CharField(widget=forms.HiddenInput(), required=False)
|
2016-07-20 16:28:23 +00:00
|
|
|
#: A checkbox to ask to be warn before emiting a ticket for another service
|
2016-07-29 23:31:43 +00:00
|
|
|
warn = forms.BooleanField(
|
|
|
|
label=_('Warn me before logging me into other sites.'),
|
|
|
|
required=False
|
|
|
|
)
|
2016-07-20 16:28:23 +00:00
|
|
|
#: Is the service asking the authentication renewal ?
|
2016-06-28 13:24:50 +00:00
|
|
|
renew = forms.BooleanField(widget=forms.HiddenInput(), required=False)
|
2015-05-16 21:43:46 +00:00
|
|
|
|
2015-06-12 21:57:11 +00:00
|
|
|
def __init__(self, *args, **kwargs):
|
2015-05-16 21:43:46 +00:00
|
|
|
super(UserCredential, self).__init__(*args, **kwargs)
|
|
|
|
|
|
|
|
def clean(self):
|
2016-07-20 16:28:23 +00:00
|
|
|
"""
|
|
|
|
Validate that the submited :attr:`username` and :attr:`password` are valid
|
|
|
|
|
|
|
|
:raises django.forms.ValidationError: if the :attr:`username` and :attr:`password`
|
|
|
|
are not valid.
|
|
|
|
:return: The cleaned POST data
|
|
|
|
:rtype: dict
|
|
|
|
"""
|
2015-05-16 21:43:46 +00:00
|
|
|
cleaned_data = super(UserCredential, self).clean()
|
2015-05-30 17:45:59 +00:00
|
|
|
auth = utils.import_attr(settings.CAS_AUTH_CLASS)(cleaned_data.get("username"))
|
2015-05-16 21:43:46 +00:00
|
|
|
if auth.test_password(cleaned_data.get("password")):
|
2015-06-12 21:57:11 +00:00
|
|
|
cleaned_data["username"] = auth.username
|
2015-05-16 21:43:46 +00:00
|
|
|
else:
|
2016-07-29 23:31:43 +00:00
|
|
|
raise forms.ValidationError(
|
|
|
|
_(u"The credentials you provided cannot be determined to be authentic.")
|
|
|
|
)
|
2016-06-17 17:28:49 +00:00
|
|
|
return cleaned_data
|
|
|
|
|
|
|
|
|
|
|
|
class FederateUserCredential(UserCredential):
|
2016-07-20 16:28:23 +00:00
|
|
|
"""
|
|
|
|
Bases: :class:`UserCredential`
|
|
|
|
|
|
|
|
Form used on a auto submited page for linking the views
|
|
|
|
:class:`FederateAuth<cas_server.views.FederateAuth>` and
|
|
|
|
:class:`LoginView<cas_server.views.LoginView>`.
|
|
|
|
|
|
|
|
On successful authentication on a provider, in the view
|
|
|
|
:class:`FederateAuth<cas_server.views.FederateAuth>` a
|
|
|
|
:class:`FederatedUser<cas_server.models.FederatedUser>` is created by
|
|
|
|
:meth:`cas_server.federate.CASFederateValidateUser.verify_ticket` and the user is redirected
|
|
|
|
to :class:`LoginView<cas_server.views.LoginView>`. This form is then automatically filled
|
|
|
|
with infos matching the created :class:`FederatedUser<cas_server.models.FederatedUser>`
|
|
|
|
using the ``ticket`` as one time password and submited using javascript. If javascript is
|
|
|
|
not enabled, a connect button is displayed.
|
|
|
|
|
|
|
|
This stub authentication form, allow to implement the federated mode with very few
|
|
|
|
modificatons to the :class:`LoginView<cas_server.views.LoginView>` view.
|
|
|
|
"""
|
|
|
|
#: the user username with the ``@`` component
|
2016-06-17 17:28:49 +00:00
|
|
|
username = forms.CharField(widget=forms.HiddenInput())
|
2016-07-20 16:28:23 +00:00
|
|
|
#: The service url for which the user want a ticket
|
2016-06-17 17:28:49 +00:00
|
|
|
service = forms.CharField(widget=forms.HiddenInput(), required=False)
|
2016-07-20 16:28:23 +00:00
|
|
|
#: The ``ticket`` used to authenticate the user against a provider
|
2016-06-17 17:28:49 +00:00
|
|
|
password = forms.CharField(widget=forms.HiddenInput())
|
2016-07-20 16:28:23 +00:00
|
|
|
#: alias of :attr:`password`
|
2016-06-17 17:28:49 +00:00
|
|
|
ticket = forms.CharField(widget=forms.HiddenInput())
|
2016-07-20 16:28:23 +00:00
|
|
|
#: A valid LoginTicket to prevent POST replay
|
2016-06-17 17:28:49 +00:00
|
|
|
lt = forms.CharField(widget=forms.HiddenInput(), required=False)
|
|
|
|
method = forms.CharField(widget=forms.HiddenInput(), required=False)
|
2016-07-20 16:28:23 +00:00
|
|
|
#: Has the user asked to be warn before emiting a ticket for another service
|
2016-06-17 17:28:49 +00:00
|
|
|
warn = forms.BooleanField(widget=forms.HiddenInput(), required=False)
|
2016-07-20 16:28:23 +00:00
|
|
|
#: Is the service asking the authentication renewal ?
|
2016-06-28 13:29:45 +00:00
|
|
|
renew = forms.BooleanField(widget=forms.HiddenInput(), required=False)
|
2016-06-17 17:28:49 +00:00
|
|
|
|
|
|
|
def clean(self):
|
2016-07-20 16:28:23 +00:00
|
|
|
"""
|
|
|
|
Validate that the submited :attr:`username` and :attr:`password` are valid using
|
|
|
|
the :class:`CASFederateAuth<cas_server.auth.CASFederateAuth>` auth class.
|
|
|
|
|
|
|
|
:raises django.forms.ValidationError: if the :attr:`username` and :attr:`password`
|
|
|
|
do not correspond to a :class:`FederatedUser<cas_server.models.FederatedUser>`.
|
|
|
|
:return: The cleaned POST data
|
|
|
|
:rtype: dict
|
|
|
|
"""
|
2016-06-17 17:28:49 +00:00
|
|
|
cleaned_data = super(FederateUserCredential, self).clean()
|
|
|
|
try:
|
2016-07-04 15:23:11 +00:00
|
|
|
user = models.FederatedUser.get_from_federated_username(cleaned_data["username"])
|
2016-06-17 17:28:49 +00:00
|
|
|
user.ticket = ""
|
|
|
|
user.save()
|
2016-07-04 15:23:11 +00:00
|
|
|
# should not happed as if the FederatedUser do not exists, super should
|
2016-07-03 11:51:00 +00:00
|
|
|
# raise before a ValidationError("bad user")
|
|
|
|
except models.FederatedUser.DoesNotExist: # pragma: no cover (should not happend)
|
|
|
|
raise forms.ValidationError(
|
|
|
|
_(u"User not found in the temporary database, please try to reconnect")
|
|
|
|
)
|
2016-06-17 17:28:49 +00:00
|
|
|
return cleaned_data
|
2015-05-16 21:43:46 +00:00
|
|
|
|
|
|
|
|
|
|
|
class TicketForm(forms.ModelForm):
|
2016-07-20 16:28:23 +00:00
|
|
|
"""
|
|
|
|
Bases: :class:`django.forms.ModelForm`
|
|
|
|
|
|
|
|
Form for Tickets in the admin interface
|
|
|
|
"""
|
2015-05-16 21:43:46 +00:00
|
|
|
class Meta:
|
|
|
|
model = models.Ticket
|
|
|
|
exclude = []
|
2015-06-11 21:04:26 +00:00
|
|
|
service = forms.CharField(label=_('service'), widget=forms.TextInput)
|