Hide keyboard shortcuts

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 

13 

14from django import forms 

15from django.forms import widgets 

16from django.utils.translation import ugettext_lazy as _ 

17 

18import cas_server.utils as utils 

19import cas_server.models as models 

20 

21 

22class BootsrapForm(forms.Form): 

23 """ 

24 Bases: :class:`django.forms.Form` 

25 

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) 

44 

45 

46class BaseLogin(BootsrapForm): 

47 """ 

48 Bases: :class:`BootsrapForm` 

49 

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) 

61 

62 

63class WarnForm(BaseLogin): 

64 """ 

65 Bases: :class:`BaseLogin` 

66 

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) 

71 

72 

73class FederateSelect(BaseLogin): 

74 """ 

75 Bases: :class:`BaseLogin` 

76 

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) 

97 

98 

99class UserCredential(BaseLogin): 

100 """ 

101 Bases: :class:`BaseLogin` 

102 

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 ) 

117 

118 def clean(self): 

119 """ 

120 Validate that the submited :attr:`username` and :attr:`password` are valid 

121 

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 

137 

138 

139class FederateUserCredential(UserCredential): 

140 """ 

141 Bases: :class:`UserCredential` 

142 

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>`. 

146 

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. 

155 

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 """ 

159 

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 

166 

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. 

171 

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 

189 

190 

191class TicketForm(forms.ModelForm): 

192 """ 

193 Bases: :class:`django.forms.ModelForm` 

194 

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)