Revision 63836eda
b/snf-astakos-app/astakos/im/auth_providers.py | ||
---|---|---|
47 | 47 |
|
48 | 48 |
# providers registry |
49 | 49 |
PROVIDERS = {} |
50 |
REQUIRED_PROVIDERS = {} |
|
50 | 51 |
|
51 | 52 |
class AuthProviderBase(type): |
52 | 53 |
|
... | ... | |
62 | 63 |
newcls = super(AuthProviderBase, cls).__new__(cls, name, bases, dct) |
63 | 64 |
if include: |
64 | 65 |
PROVIDERS[type_id] = newcls |
66 |
if newcls().is_required(): |
|
67 |
REQUIRED_PROVIDERS[type_id] = newcls |
|
65 | 68 |
return newcls |
66 | 69 |
|
67 | 70 |
|
... | ... | |
122 | 125 |
return self.is_active() and self.get_setting('CAN_ADD', |
123 | 126 |
self.is_active()) |
124 | 127 |
|
128 |
def is_required(self): |
|
129 |
"""Provider required (user cannot remove the last one)""" |
|
130 |
return self.is_active() and self.get_setting('REQUIRED', False) |
|
131 |
|
|
125 | 132 |
def is_active(self): |
126 | 133 |
return self.module in astakos_settings.IM_MODULES |
127 | 134 |
|
b/snf-astakos-app/astakos/im/messages.py | ||
---|---|---|
46 | 46 |
ACCOUNT_ACTIVATED = 'Congratulations. Your account has' + \ |
47 | 47 |
' been activated and you have been' + \ |
48 | 48 |
' automatically signed in to your account.' |
49 |
ALREADY_LOGGED_IN = 'You are already signed in to your account.' |
|
49 | 50 |
PASSWORD_RESET_DONE = 'A mail with details on how to change your password was sent.' |
50 | 51 |
PASSWORD_RESET_CONFIRM_DONE = 'Password changed. You can now login using your new password.' |
51 | 52 |
|
... | ... | |
156 | 157 |
AUTH_PROVIDER_ADD_EXISTS = "Account already assigned to another user." |
157 | 158 |
AUTH_PROVIDER_LOGIN_TO_ADD = "The new login method will be assigned once you login to your account." |
158 | 159 |
AUTH_PROVIDER_INVALID_LOGIN = "No account exists." |
160 |
AUTH_PROVIDER_REQUIRED = "%(provider)s login method is required. Add one from your profile page." |
|
159 | 161 |
|
160 | 162 |
|
161 | 163 |
messages = locals().keys() |
b/snf-astakos-app/astakos/im/models.py | ||
---|---|---|
641 | 641 |
|
642 | 642 |
return True |
643 | 643 |
|
644 |
def can_remove_auth_provider(self, provider): |
|
645 |
if len(self.get_active_auth_providers()) <= 1: |
|
644 |
def can_remove_auth_provider(self, module): |
|
645 |
provider = auth_providers.get_provider(module) |
|
646 |
existing = self.get_active_auth_providers() |
|
647 |
existing_for_provider = self.get_active_auth_providers(module=module) |
|
648 |
|
|
649 |
if len(existing) <= 1: |
|
650 |
return False |
|
651 |
|
|
652 |
if len(existing_for_provider) == 1 and provider.is_required(): |
|
646 | 653 |
return False |
654 |
|
|
647 | 655 |
return True |
648 | 656 |
|
649 | 657 |
def can_change_password(self): |
650 | 658 |
return self.has_auth_provider('local', auth_backend='astakos') |
651 | 659 |
|
660 |
def has_required_auth_providers(self): |
|
661 |
required = auth_providers.REQUIRED_PROVIDERS |
|
662 |
for provider in required: |
|
663 |
if not self.has_auth_provider(provider): |
|
664 |
return False |
|
665 |
return True |
|
666 |
|
|
652 | 667 |
def has_auth_provider(self, provider, **kwargs): |
653 | 668 |
return bool(self.auth_providers.filter(module=provider, |
654 | 669 |
**kwargs).count()) |
... | ... | |
723 | 738 |
|
724 | 739 |
return providers |
725 | 740 |
|
726 |
def get_active_auth_providers(self): |
|
741 |
def get_active_auth_providers(self, **filters):
|
|
727 | 742 |
providers = [] |
728 |
for provider in self.auth_providers.active(): |
|
743 |
for provider in self.auth_providers.active(**filters):
|
|
729 | 744 |
if auth_providers.get_provider(provider.module).is_available_for_login(): |
730 | 745 |
providers.append(provider) |
731 | 746 |
return providers |
... | ... | |
764 | 779 |
|
765 | 780 |
class AstakosUserAuthProviderManager(models.Manager): |
766 | 781 |
|
767 |
def active(self): |
|
768 |
return self.filter(active=True) |
|
782 |
def active(self, **filters):
|
|
783 |
return self.filter(active=True, **filters)
|
|
769 | 784 |
|
770 | 785 |
|
771 | 786 |
class AstakosUserAuthProvider(models.Model): |
b/snf-astakos-app/astakos/im/target/twitter.py | ||
---|---|---|
47 | 47 |
|
48 | 48 |
from astakos.im.util import prepare_response, get_context |
49 | 49 |
from astakos.im.views import requires_anonymous, render_response, \ |
50 |
requires_auth_provider |
|
50 |
requires_auth_provider, required_auth_methods_assigned
|
|
51 | 51 |
from astakos.im.settings import ENABLE_LOCAL_ACCOUNT_MIGRATION, BASEURL |
52 | 52 |
from astakos.im.models import AstakosUser, PendingThirdPartyUser |
53 | 53 |
from astakos.im.forms import LoginForm |
b/snf-astakos-app/astakos/im/views.py | ||
---|---|---|
151 | 151 |
|
152 | 152 |
def signed_terms_required(func): |
153 | 153 |
""" |
154 |
Decorator checkes whether the request.user is Anonymous and in that case
|
|
154 |
Decorator checks whether the request.user is Anonymous and in that case |
|
155 | 155 |
redirects to `logout`. |
156 | 156 |
""" |
157 | 157 |
@wraps(func) |
... | ... | |
165 | 165 |
return wrapper |
166 | 166 |
|
167 | 167 |
|
168 |
def required_auth_methods_assigned(only_warn=False): |
|
169 |
""" |
|
170 |
Decorator that checks whether the request.user has all required auth providers |
|
171 |
assigned. |
|
172 |
""" |
|
173 |
required_providers = auth_providers.REQUIRED_PROVIDERS.keys() |
|
174 |
|
|
175 |
def decorator(func): |
|
176 |
if not required_providers: |
|
177 |
return func |
|
178 |
|
|
179 |
@wraps(func) |
|
180 |
def wrapper(request, *args, **kwargs): |
|
181 |
if request.user.is_authenticated(): |
|
182 |
for required in required_providers: |
|
183 |
if not request.user.has_auth_provider(required): |
|
184 |
provider = auth_providers.get_provider(required) |
|
185 |
if only_warn: |
|
186 |
messages.error(request, |
|
187 |
_(astakos_messages.AUTH_PROVIDER_REQUIRED % { |
|
188 |
'provider': provider.get_title_display})) |
|
189 |
else: |
|
190 |
return HttpResponseRedirect(reverse('edit_profile')) |
|
191 |
return func(request, *args, **kwargs) |
|
192 |
return wrapper |
|
193 |
return decorator |
|
194 |
|
|
195 |
|
|
196 |
def valid_astakos_user_required(func): |
|
197 |
return signed_terms_required(required_auth_methods_assigned()(login_required(func))) |
|
198 |
|
|
199 |
|
|
168 | 200 |
@require_http_methods(["GET", "POST"]) |
169 | 201 |
@signed_terms_required |
170 | 202 |
def index(request, login_template_name='im/login.html', profile_template_name='im/profile.html', extra_context=None): |
... | ... | |
202 | 234 |
|
203 | 235 |
|
204 | 236 |
@require_http_methods(["GET", "POST"]) |
205 |
@login_required |
|
206 |
@signed_terms_required |
|
237 |
@valid_astakos_user_required |
|
207 | 238 |
@transaction.commit_manually |
208 | 239 |
def invite(request, template_name='im/invitations.html', extra_context=None): |
209 | 240 |
""" |
... | ... | |
281 | 312 |
|
282 | 313 |
|
283 | 314 |
@require_http_methods(["GET", "POST"]) |
315 |
@required_auth_methods_assigned(only_warn=True) |
|
284 | 316 |
@login_required |
285 | 317 |
@signed_terms_required |
286 | 318 |
def edit_profile(request, template_name='im/profile.html', extra_context=None): |
... | ... | |
478 | 510 |
|
479 | 511 |
|
480 | 512 |
@require_http_methods(["GET", "POST"]) |
513 |
@required_auth_methods_assigned(only_warn=True) |
|
481 | 514 |
@login_required |
482 | 515 |
@signed_terms_required |
483 | 516 |
def feedback(request, template_name='im/feedback.html', email_template_name='im/feedback_mail.txt', extra_context=None): |
... | ... | |
653 | 686 |
|
654 | 687 |
|
655 | 688 |
@require_http_methods(["GET", "POST"]) |
656 |
@login_required |
|
657 |
@signed_terms_required |
|
689 |
@valid_astakos_user_required |
|
658 | 690 |
@transaction.commit_manually |
659 | 691 |
def change_email(request, activation_key=None, |
660 | 692 |
email_template_name='registration/email_change_email.txt', |
... | ... | |
708 | 740 |
|
709 | 741 |
def send_activation(request, user_id, template_name='im/login.html', extra_context=None): |
710 | 742 |
|
743 |
if request.user.is_authenticated(): |
|
744 |
messages.error(request, _(astakos_messages.ALREADY_LOGGED_IN)) |
|
745 |
return HttpResponseRedirect(reverse('edit_profile')) |
|
746 |
|
|
711 | 747 |
if settings.MODERATION_ENABLED: |
712 | 748 |
raise PermissionDenied |
713 | 749 |
|
... | ... | |
814 | 850 |
|
815 | 851 |
|
816 | 852 |
@require_http_methods(["GET", "POST"]) |
817 |
@signed_terms_required |
|
818 |
@login_required |
|
853 |
@valid_astakos_user_required |
|
819 | 854 |
def group_add(request, kind_name='default'): |
820 | 855 |
|
821 | 856 |
result = callpoint.list_resources() |
... | ... | |
880 | 915 |
|
881 | 916 |
#@require_http_methods(["POST"]) |
882 | 917 |
@require_http_methods(["GET", "POST"]) |
883 |
@signed_terms_required |
|
884 |
@login_required |
|
918 |
@valid_astakos_user_required |
|
885 | 919 |
def group_add_complete(request): |
886 | 920 |
model = AstakosGroup |
887 | 921 |
form = AstakosGroupCreationSummaryForm(request.POST) |
... | ... | |
924 | 958 |
|
925 | 959 |
#@require_http_methods(["GET"]) |
926 | 960 |
@require_http_methods(["GET", "POST"]) |
927 |
@signed_terms_required |
|
928 |
@login_required |
|
961 |
@valid_astakos_user_required |
|
929 | 962 |
def group_list(request): |
930 | 963 |
none = request.user.astakos_groups.none() |
931 | 964 |
query = """ |
... | ... | |
986 | 1019 |
|
987 | 1020 |
|
988 | 1021 |
@require_http_methods(["GET", "POST"]) |
989 |
@signed_terms_required |
|
990 |
@login_required |
|
1022 |
@valid_astakos_user_required |
|
991 | 1023 |
def group_detail(request, group_id): |
992 | 1024 |
q = AstakosGroup.objects.select_related().filter(pk=group_id) |
993 | 1025 |
q = q.extra(select={ |
... | ... | |
1084 | 1116 |
|
1085 | 1117 |
|
1086 | 1118 |
@require_http_methods(["GET", "POST"]) |
1087 |
@signed_terms_required |
|
1088 |
@login_required |
|
1119 |
@valid_astakos_user_required |
|
1089 | 1120 |
def group_search(request, extra_context=None, **kwargs): |
1090 | 1121 |
q = request.GET.get('q') |
1091 | 1122 |
if request.method == 'GET': |
... | ... | |
1160 | 1191 |
|
1161 | 1192 |
|
1162 | 1193 |
@require_http_methods(["GET", "POST"]) |
1163 |
@signed_terms_required |
|
1164 |
@login_required |
|
1194 |
@valid_astakos_user_required |
|
1165 | 1195 |
def group_all(request, extra_context=None, **kwargs): |
1166 | 1196 |
q = AstakosGroup.objects.select_related() |
1167 | 1197 |
q = q.filter(~Q(kind__name='default')) |
... | ... | |
1216 | 1246 |
|
1217 | 1247 |
#@require_http_methods(["POST"]) |
1218 | 1248 |
@require_http_methods(["POST", "GET"]) |
1219 |
@signed_terms_required |
|
1220 |
@login_required |
|
1249 |
@valid_astakos_user_required |
|
1221 | 1250 |
def group_join(request, group_id): |
1222 | 1251 |
m = Membership(group_id=group_id, |
1223 | 1252 |
person=request.user, |
... | ... | |
1236 | 1265 |
|
1237 | 1266 |
|
1238 | 1267 |
@require_http_methods(["POST"]) |
1239 |
@signed_terms_required |
|
1240 |
@login_required |
|
1268 |
@valid_astakos_user_required |
|
1241 | 1269 |
def group_leave(request, group_id): |
1242 | 1270 |
try: |
1243 | 1271 |
m = Membership.objects.select_related().get( |
... | ... | |
1276 | 1304 |
|
1277 | 1305 |
#@require_http_methods(["POST"]) |
1278 | 1306 |
@require_http_methods(["POST", "GET"]) |
1279 |
@signed_terms_required |
|
1280 |
@login_required |
|
1307 |
@valid_astakos_user_required |
|
1281 | 1308 |
@handle_membership |
1282 | 1309 |
def approve_member(request, membership): |
1283 | 1310 |
try: |
... | ... | |
1295 | 1322 |
messages.error(request, msg) |
1296 | 1323 |
|
1297 | 1324 |
|
1298 |
@signed_terms_required |
|
1299 |
@login_required |
|
1325 |
@valid_astakos_user_required |
|
1300 | 1326 |
@handle_membership |
1301 | 1327 |
def disapprove_member(request, membership): |
1302 | 1328 |
try: |
... | ... | |
1312 | 1338 |
|
1313 | 1339 |
#@require_http_methods(["GET"]) |
1314 | 1340 |
@require_http_methods(["POST", "GET"]) |
1315 |
@signed_terms_required |
|
1316 |
@login_required |
|
1341 |
@valid_astakos_user_required |
|
1317 | 1342 |
def resource_usage(request): |
1318 | 1343 |
def with_class(entry): |
1319 | 1344 |
entry['load_class'] = 'red' |
... | ... | |
1426 | 1451 |
|
1427 | 1452 |
#@require_http_methods(["GET"]) |
1428 | 1453 |
@require_http_methods(["POST", "GET"]) |
1429 |
@signed_terms_required |
|
1430 |
@login_required |
|
1454 |
@valid_astakos_user_required |
|
1431 | 1455 |
def timeline(request): |
1432 | 1456 |
# data = {'entity':request.user.email} |
1433 | 1457 |
timeline_body = () |
Also available in: Unified diff