Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# This program is distributed in the hope that it will be useful, but WITHOUT
2# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
3# FOR A PARTICULAR PURPOSE. See the GNU General Public License version 3 for
4# more details.
5#
6# You should have received a copy of the GNU General Public License version 3
7# along with this program; if not, write to the Free Software Foundation, Inc., 51
8# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
9#
10# (c) 2015-2016 Valentin Samir
11"""forms for the app"""
12from .default_settings import settings
14from django import forms
15from django.forms import widgets
16from django.utils.translation import ugettext_lazy as _
18import cas_server.utils as utils
19import cas_server.models as models
22class BootsrapForm(forms.Form):
23 """
24 Bases: :class:`django.forms.Form`
26 Form base class to use boostrap then rendering the form fields
27 """
28 def __init__(self, *args, **kwargs):
29 super(BootsrapForm, self).__init__(*args, **kwargs)
30 for field in self.fields.values():
31 # Only tweak the field if it will be displayed
32 if not isinstance(field.widget, widgets.HiddenInput):
33 attrs = {}
34 if (
35 isinstance(field.widget, (widgets.Input, widgets.Select, widgets.Textarea)) and
36 not isinstance(field.widget, (widgets.CheckboxInput,))
37 ):
38 attrs['class'] = "form-control"
39 if isinstance(field.widget, (widgets.Input, widgets.Textarea)) and field.label:
40 attrs["placeholder"] = field.label
41 if field.required:
42 attrs["required"] = "required"
43 field.widget.attrs.update(attrs)
46class BaseLogin(BootsrapForm):
47 """
48 Bases: :class:`BootsrapForm`
50 Base form with all field possibly hidden on the login pages
51 """
52 #: The service url for which the user want a ticket
53 service = forms.CharField(widget=forms.HiddenInput(), required=False)
54 #: A valid LoginTicket to prevent POST replay
55 lt = forms.CharField(widget=forms.HiddenInput(), required=False)
56 #: Is the service asking the authentication renewal ?
57 renew = forms.BooleanField(widget=forms.HiddenInput(), required=False)
58 #: Url to redirect to if the authentication fail (user not authenticated or bad service)
59 gateway = forms.CharField(widget=forms.HiddenInput(), required=False)
60 method = forms.CharField(widget=forms.HiddenInput(), required=False)
63class WarnForm(BaseLogin):
64 """
65 Bases: :class:`BaseLogin`
67 Form used on warn page before emiting a ticket
68 """
69 #: ``True`` if the user has been warned of the ticket emission
70 warned = forms.BooleanField(widget=forms.HiddenInput(), required=False)
73class FederateSelect(BaseLogin):
74 """
75 Bases: :class:`BaseLogin`
77 Form used on the login page when ``settings.CAS_FEDERATE`` is ``True``
78 allowing the user to choose an identity provider.
79 """
80 #: The providers the user can choose to be used as authentication backend
81 provider = forms.ModelChoiceField(
82 queryset=models.FederatedIendityProvider.objects.filter(display=True).order_by(
83 "pos",
84 "verbose_name",
85 "suffix"
86 ),
87 to_field_name="suffix",
88 label=_('Identity provider'),
89 )
90 #: A checkbox to ask to be warn before emiting a ticket for another service
91 warn = forms.BooleanField(
92 label=_('Warn me before logging me into other sites.'),
93 required=False
94 )
95 #: A checkbox to remember the user choices of :attr:`provider<FederateSelect.provider>`
96 remember = forms.BooleanField(label=_('Remember the identity provider'), required=False)
99class UserCredential(BaseLogin):
100 """
101 Bases: :class:`BaseLogin`
103 Form used on the login page to retrive user credentials
104 """
105 #: The user username
106 username = forms.CharField(
107 label=_('username'),
108 widget=forms.TextInput(attrs={'autofocus': 'autofocus'})
109 )
110 #: The user password
111 password = forms.CharField(label=_('password'), widget=forms.PasswordInput)
112 #: A checkbox to ask to be warn before emiting a ticket for another service
113 warn = forms.BooleanField(
114 label=_('Warn me before logging me into other sites.'),
115 required=False
116 )
118 def clean(self):
119 """
120 Validate that the submited :attr:`username` and :attr:`password` are valid
122 :raises django.forms.ValidationError: if the :attr:`username` and :attr:`password`
123 are not valid.
124 :return: The cleaned POST data
125 :rtype: dict
126 """
127 cleaned_data = super(UserCredential, self).clean()
128 if "username" in cleaned_data and "password" in cleaned_data:
129 auth = utils.import_attr(settings.CAS_AUTH_CLASS)(cleaned_data["username"])
130 if auth.test_password(cleaned_data["password"]):
131 cleaned_data["username"] = auth.username
132 else:
133 raise forms.ValidationError(
134 _(u"The credentials you provided cannot be determined to be authentic.")
135 )
136 return cleaned_data
139class FederateUserCredential(UserCredential):
140 """
141 Bases: :class:`UserCredential`
143 Form used on a auto submited page for linking the views
144 :class:`FederateAuth<cas_server.views.FederateAuth>` and
145 :class:`LoginView<cas_server.views.LoginView>`.
147 On successful authentication on a provider, in the view
148 :class:`FederateAuth<cas_server.views.FederateAuth>` a
149 :class:`FederatedUser<cas_server.models.FederatedUser>` is created by
150 :meth:`cas_server.federate.CASFederateValidateUser.verify_ticket` and the user is redirected
151 to :class:`LoginView<cas_server.views.LoginView>`. This form is then automatically filled
152 with infos matching the created :class:`FederatedUser<cas_server.models.FederatedUser>`
153 using the ``ticket`` as one time password and submited using javascript. If javascript is
154 not enabled, a connect button is displayed.
156 This stub authentication form, allow to implement the federated mode with very few
157 modificatons to the :class:`LoginView<cas_server.views.LoginView>` view.
158 """
160 def __init__(self, *args, **kwargs):
161 super(FederateUserCredential, self).__init__(*args, **kwargs)
162 # All fields are hidden and auto filled by the /login view logic
163 for name, field in self.fields.items():
164 field.widget = forms.HiddenInput()
165 self[name].display = False
167 def clean(self):
168 """
169 Validate that the submited :attr:`username` and :attr:`password` are valid using
170 the :class:`CASFederateAuth<cas_server.auth.CASFederateAuth>` auth class.
172 :raises django.forms.ValidationError: if the :attr:`username` and :attr:`password`
173 do not correspond to a :class:`FederatedUser<cas_server.models.FederatedUser>`.
174 :return: The cleaned POST data
175 :rtype: dict
176 """
177 cleaned_data = super(FederateUserCredential, self).clean()
178 try:
179 user = models.FederatedUser.get_from_federated_username(cleaned_data["username"])
180 user.ticket = ""
181 user.save()
182 # should not happed as if the FederatedUser do not exists, super should
183 # raise before a ValidationError("bad user")
184 except models.FederatedUser.DoesNotExist: # pragma: no cover (should not happend)
185 raise forms.ValidationError(
186 _(u"User not found in the temporary database, please try to reconnect")
187 )
188 return cleaned_data
191class TicketForm(forms.ModelForm):
192 """
193 Bases: :class:`django.forms.ModelForm`
195 Form for Tickets in the admin interface
196 """
197 class Meta:
198 model = models.Ticket
199 exclude = []
200 service = forms.CharField(label=_('service'), widget=forms.TextInput)