Revision bf0c6de5

b/snf-astakos-app/astakos/im/forms.py
89 89
        """
90 90
        Changes the order of fields, and removes the username field.
91 91
        """
92
        request = kwargs.get('request', None)
92
        request = kwargs.pop('request', None)
93 93
        if request:
94
            kwargs.pop('request')
95 94
            self.ip = request.META.get('REMOTE_ADDR',
96 95
                                       request.META.get('HTTP_X_REAL_IP', None))
97 96

  
......
150 149
        save behavior is complete.
151 150
        """
152 151
        user = super(LocalUserCreationForm, self).save(commit=False)
153
        user.renew_token()
154 152
        if commit:
155 153
            user.save()
156 154
            logger._log(LOGGING_LEVEL, 'Created user %s' % user.email, [])
......
240 238
    def save(self, commit=True):
241 239
        user = super(ThirdPartyUserCreationForm, self).save(commit=False)
242 240
        user.set_unusable_password()
243
        user.renew_token()
244 241
        user.provider = get_query(self.request).get('provider')
245 242
        if commit:
246 243
            user.save()
......
385 382
        fields = ('email', 'first_name', 'last_name', 'auth_token', 'auth_token_expires')
386 383

  
387 384
    def __init__(self, *args, **kwargs):
385
        self.session_key = kwargs.pop('session_key', None)
388 386
        super(ProfileForm, self).__init__(*args, **kwargs)
389 387
        instance = getattr(self, 'instance', None)
390 388
        ro_fields = ('email', 'auth_token', 'auth_token_expires')
......
396 394
        user = super(ProfileForm, self).save(commit=False)
397 395
        user.is_verified = True
398 396
        if self.cleaned_data.get('renew'):
399
            user.renew_token()
397
            user.renew_token(
398
                flush_sessions=True,
399
                current_key=self.session_key
400
            )
400 401
        if commit:
401 402
            user.save()
402 403
        return user
......
523 524
                                   help_text='Unsetting this may result in security risk.')
524 525

  
525 526
    def __init__(self, user, *args, **kwargs):
527
        self.session_key = kwargs.pop('session_key', None)
526 528
        super(ExtendedPasswordChangeForm, self).__init__(user, *args, **kwargs)
527 529

  
528 530
    def save(self, commit=True):
529
        if NEWPASSWD_INVALIDATE_TOKEN or self.cleaned_data.get('renew'):
530
            self.user.renew_token()
531
        try:
532
            if NEWPASSWD_INVALIDATE_TOKEN or self.cleaned_data.get('renew'):
533
                self.user.renew_token()
534
            self.user.flush_sessions(current_key=self.session_key)
535
        except AttributeError:
536
            # if user model does has not such methods
537
            pass
531 538
        return super(ExtendedPasswordChangeForm, self).save(commit=commit)
532 539

  
533 540
class ExtendedSetPasswordForm(SetPasswordForm):
......
536 543
    to optionally renew also the token.
537 544
    """
538 545
    if not NEWPASSWD_INVALIDATE_TOKEN:
539
        renew = forms.BooleanField(label='Renew token', required=False,
540
                                   initial=True,
541
                                   help_text='Unsetting this may result in security risk.')
546
        renew = forms.BooleanField(
547
            label='Renew token',
548
            required=False,
549
            initial=True,
550
            help_text='Unsetting this may result in security risk.'
551
        )
542 552
    
543 553
    def __init__(self, user, *args, **kwargs):
544 554
        super(ExtendedSetPasswordForm, self).__init__(user, *args, **kwargs)
545 555
    
546 556
    def save(self, commit=True):
547
        if NEWPASSWD_INVALIDATE_TOKEN or self.cleaned_data.get('renew'):
548
            if isinstance(self.user, AstakosUser):
557
        try:
558
            self.user = AstakosUser.objects.get(id=self.user.id)
559
            if NEWPASSWD_INVALIDATE_TOKEN or self.cleaned_data.get('renew'):
549 560
                self.user.renew_token()
561
            self.user.flush_sessions()
562
        except BaseException, e:
563
            logger.exception(e)
564
            pass
550 565
        return super(ExtendedSetPasswordForm, self).save(commit=commit)
b/snf-astakos-app/astakos/im/functions.py
40 40
from django.core.urlresolvers import reverse
41 41
from django.core.exceptions import ValidationError
42 42
from django.template import Context, loader
43
from django.contrib.auth import login as auth_login, logout as auth_logout
43
from django.contrib.auth import (
44
    login as auth_login,
45
    logout as auth_logout,
46
    SESSION_KEY
47
)
44 48
from django.http import HttpRequest
45 49

  
46 50
from urllib import quote
......
49 53
from datetime import datetime
50 54
from functools import wraps
51 55

  
52
from astakos.im.settings import DEFAULT_CONTACT_EMAIL, DEFAULT_FROM_EMAIL, \
53
    SITENAME, BASEURL, DEFAULT_ADMIN_EMAIL, LOGGING_LEVEL, \
54
    VERIFICATION_EMAIL_SUBJECT, ADMIN_NOTIFICATION_EMAIL_SUBJECT, \
55
    HELPDESK_NOTIFICATION_EMAIL_SUBJECT, INVITATION_EMAIL_SUBJECT, \
56
from astakos.im.settings import (
57
    DEFAULT_CONTACT_EMAIL, DEFAULT_FROM_EMAIL,
58
    SITENAME, BASEURL, DEFAULT_ADMIN_EMAIL, LOGGING_LEVEL,
59
    VERIFICATION_EMAIL_SUBJECT, ADMIN_NOTIFICATION_EMAIL_SUBJECT,
60
    HELPDESK_NOTIFICATION_EMAIL_SUBJECT, INVITATION_EMAIL_SUBJECT,
56 61
    GREETING_EMAIL_SUBJECT, FEEDBACK_EMAIL_SUBJECT, EMAIL_CHANGE_EMAIL_SUBJECT
57
from astakos.im.models import Invitation, AstakosUser
62
)
63
from astakos.im.models import Invitation, AstakosUser, SessionCatalog
58 64

  
59 65
logger = logging.getLogger(__name__)
60 66

  
......
75 81
        return r
76 82
    return with_logging
77 83

  
78
login = logged(auth_login, '%s logged in.')
84

  
85
def login(request, user):
86
    auth_login(request, user)
87
    SessionCatalog(session_key=request.session.session_key, user=user).save()
88

  
89
login = logged(login, '%s logged in.')
79 90
logout = logged(auth_logout, '%s logged out.')
80 91

  
81 92
def send_verification(user, template_name='im/activation_email.txt'):
b/snf-astakos-app/astakos/im/management/commands/user-add.py
99 99
                           email=email, affiliation=affiliation,
100 100
                           provider='local')
101 101
        user.set_password(password)
102
        user.renew_token()
103 102
        
104 103
        if options['active']:
105 104
            user.is_active = True
b/snf-astakos-app/astakos/im/migrations/0016_auto__add_sessioncatalog.py
1
# encoding: utf-8
2
import datetime
3
from south.db import db
4
from south.v2 import SchemaMigration
5
from django.db import models
6

  
7
class Migration(SchemaMigration):
8

  
9
    def forwards(self, orm):
10
        
11
        # Adding model 'SessionCatalog'
12
        db.create_table('im_sessioncatalog', (
13
            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
14
            ('session_key', self.gf('django.db.models.fields.CharField')(max_length=40)),
15
            ('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='sessions', null=True, to=orm['im.AstakosUser'])),
16
        ))
17
        db.send_create_signal('im', ['SessionCatalog'])
18

  
19

  
20
    def backwards(self, orm):
21
        
22
        # Deleting model 'SessionCatalog'
23
        db.delete_table('im_sessioncatalog')
24

  
25

  
26
    models = {
27
        'auth.group': {
28
            'Meta': {'object_name': 'Group'},
29
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
30
            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
31
            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
32
        },
33
        'auth.permission': {
34
            'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
35
            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
36
            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
37
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
38
            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
39
        },
40
        'auth.user': {
41
            'Meta': {'object_name': 'User'},
42
            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
43
            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
44
            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
45
            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
46
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
47
            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
48
            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
49
            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
50
            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
51
            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
52
            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
53
            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
54
            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
55
        },
56
        'contenttypes.contenttype': {
57
            'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
58
            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
59
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
60
            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
61
            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
62
        },
63
        'im.additionalmail': {
64
            'Meta': {'object_name': 'AdditionalMail'},
65
            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
66
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
67
            'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"})
68
        },
69
        'im.approvalterms': {
70
            'Meta': {'object_name': 'ApprovalTerms'},
71
            'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 11, 27, 16, 51, 48, 446565)', 'db_index': 'True'}),
72
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
73
            'location': ('django.db.models.fields.CharField', [], {'max_length': '255'})
74
        },
75
        'im.astakosuser': {
76
            'Meta': {'unique_together': "(('provider', 'third_party_identifier'),)", 'object_name': 'AstakosUser', '_ormbases': ['auth.User']},
77
            'activation_sent': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
78
            'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
79
            'auth_token': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
80
            'auth_token_created': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
81
            'auth_token_expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
82
            'date_signed_terms': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
83
            'email_verified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
84
            'has_credits': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
85
            'has_signed_terms': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
86
            'invitations': ('django.db.models.fields.IntegerField', [], {'default': '100'}),
87
            'is_verified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
88
            'level': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
89
            'provider': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
90
            'third_party_identifier': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
91
            'updated': ('django.db.models.fields.DateTimeField', [], {}),
92
            'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'})
93
        },
94
        'im.emailchange': {
95
            'Meta': {'object_name': 'EmailChange'},
96
            'activation_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40', 'db_index': 'True'}),
97
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
98
            'new_email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
99
            'requested_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 11, 27, 16, 51, 48, 448299)'}),
100
            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'emailchange_user'", 'unique': 'True', 'to': "orm['im.AstakosUser']"})
101
        },
102
        'im.invitation': {
103
            'Meta': {'object_name': 'Invitation'},
104
            'code': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True'}),
105
            'consumed': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
106
            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
107
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
108
            'inviter': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'invitations_sent'", 'null': 'True', 'to': "orm['im.AstakosUser']"}),
109
            'is_consumed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
110
            'realname': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
111
            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'})
112
        },
113
        'im.pendingthirdpartyuser': {
114
            'Meta': {'unique_together': "(('provider', 'third_party_identifier'),)", 'object_name': 'PendingThirdPartyUser'},
115
            'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
116
            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
117
            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
118
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
119
            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
120
            'provider': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
121
            'third_party_identifier': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
122
            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
123
        },
124
        'im.service': {
125
            'Meta': {'object_name': 'Service'},
126
            'auth_token': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
127
            'auth_token_created': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
128
            'auth_token_expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
129
            'icon': ('django.db.models.fields.FilePathField', [], {'max_length': '100', 'blank': 'True'}),
130
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
131
            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
132
            'url': ('django.db.models.fields.FilePathField', [], {'max_length': '100'})
133
        },
134
        'im.sessioncatalog': {
135
            'Meta': {'object_name': 'SessionCatalog'},
136
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
137
            'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
138
            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'sessions'", 'null': 'True', 'to': "orm['im.AstakosUser']"})
139
        }
140
    }
141

  
142
    complete_apps = ['im']
b/snf-astakos-app/astakos/im/models.py
49 49
from django.template.loader import render_to_string
50 50
from django.core.mail import send_mail
51 51
from django.db import transaction
52
from django.db.models.signals import post_save, post_syncdb
52
from django.db.models.signals import post_save, pre_save, post_syncdb
53 53
from django.db.models import Q
54 54
from django.conf import settings
55
from django.utils.importlib import import_module
55 56

  
56
from astakos.im.settings import DEFAULT_USER_LEVEL, INVITATIONS_PER_LEVEL, \
57
    AUTH_TOKEN_DURATION, BILLING_FIELDS, QUEUE_CONNECTION, SITENAME, \
57
from astakos.im.settings import (
58
    DEFAULT_USER_LEVEL, INVITATIONS_PER_LEVEL,
59
    AUTH_TOKEN_DURATION, BILLING_FIELDS, QUEUE_CONNECTION, SITENAME,
58 60
    EMAILCHANGE_ACTIVATION_DAYS, LOGGING_LEVEL
61
)
59 62

  
60 63
QUEUE_CLIENT_ID = 3 # Astakos.
61 64

  
......
165 168
            except Group.DoesNotExist, e:
166 169
                logger.exception(e)
167 170
    
168
    def renew_token(self):
171
    def renew_token(self, flush_sessions=False, current_key=None):
169 172
        md5 = hashlib.md5()
170 173
        md5.update(settings.SECRET_KEY)
171 174
        md5.update(self.username)
172 175
        md5.update(self.realname.encode('ascii', 'ignore'))
173 176
        md5.update(asctime())
174

  
177
        
175 178
        self.auth_token = b64encode(md5.digest())
176 179
        self.auth_token_created = datetime.now()
177 180
        self.auth_token_expires = self.auth_token_created + \
178 181
                                  timedelta(hours=AUTH_TOKEN_DURATION)
182
        if flush_sessions:
183
            self.flush_sessions(current_key)
179 184
        msg = 'Token renewed for %s' % self.email
180 185
        logger._log(LOGGING_LEVEL, msg, [])
181 186

  
187
    def flush_sessions(self, current_key=None):
188
        q = self.sessions
189
        if current_key:
190
            q = q.exclude(session_key=current_key)
191
        
192
        keys = q.values_list('session_key', flat=True)
193
        if keys:
194
            msg = 'Flushing sessions: %s' % ','.join(keys)
195
            logger._log(LOGGING_LEVEL, msg, [])
196
        engine = import_module(settings.SESSION_ENGINE)
197
        for k in keys:
198
            s = engine.SessionStore(k)
199
            s.flush()
200
#         q.all().delete()
201

  
182 202
    def __unicode__(self):
183 203
        return self.username
184 204
    
......
355 375
    auth_token_created = models.DateTimeField('Token creation date', null=True)
356 376
    auth_token_expires = models.DateTimeField('Token expiration date', null=True)
357 377
    
358
    def save(self, **kwargs):
359
        if not self.id:
360
            self.renew_token()
361
        self.full_clean()
362
        super(Service, self).save(**kwargs)
363
    
364 378
    def renew_token(self):
365 379
        md5 = hashlib.md5()
366 380
        md5.update(settings.SECRET_KEY)
......
372 386
        self.auth_token_created = datetime.now()
373 387
        self.auth_token_expires = self.auth_token_created + \
374 388
                                  timedelta(hours=AUTH_TOKEN_DURATION)
389
        msg = 'Token renewed for %s' % self.name
390
        logger._log(LOGGING_LEVEL, msg, [])
375 391

  
376 392
class AdditionalMail(models.Model):
377 393
    """
......
419 435
                    self.username = username
420 436
        super(PendingThirdPartyUser, self).save(**kwargs)
421 437

  
438
class SessionCatalog(models.Model):
439
    session_key = models.CharField(_('session key'), max_length=40)
440
    user = models.ForeignKey(AstakosUser, related_name='sessions', null=True)
441

  
422 442
def create_astakos_user(u):
423 443
    try:
424 444
        AstakosUser.objects.get(user_ptr=u.pk)
425 445
    except AstakosUser.DoesNotExist:
426 446
        extended_user = AstakosUser(user_ptr_id=u.pk)
427 447
        extended_user.__dict__.update(u.__dict__)
428
        extended_user.renew_token()
429 448
        extended_user.save()
430 449
    except:
431 450
        pass
......
443 462
    if instance.is_superuser:
444 463
        create_astakos_user(instance)
445 464

  
446
post_save.connect(superuser_post_save, sender=User)
465
def astakosuser_post_save(sender, instance, **kwargs):
466
    pass
467

  
468
post_save.connect(superuser_post_save, sender=User)
469

  
470
def renew_token(sender, instance, **kwargs):
471
    if not instance.id:
472
        instance.renew_token()
473

  
474
pre_save.connect(renew_token, sender=AstakosUser)
475
pre_save.connect(renew_token, sender=Service)
b/snf-astakos-app/astakos/im/target/local.py
31 31
# interpreted as representing official policies, either expressed
32 32
# or implied, of GRNET S.A.
33 33

  
34
from django.http import HttpResponseBadRequest
34
from django.http import HttpResponseBadRequest, HttpResponseRedirect
35 35
from django.shortcuts import render_to_response
36 36
from django.template import RequestContext
37 37
from django.contrib.auth import authenticate
......
40 40
from django.views.decorators.csrf import csrf_exempt
41 41
from django.views.decorators.http import require_http_methods
42 42
from django.core.urlresolvers import reverse
43
from django.contrib.auth.decorators import login_required
43 44

  
44 45
from astakos.im.util import prepare_response, get_query
45
from astakos.im.views import requires_anonymous
46
from astakos.im.views import requires_anonymous, signed_terms_required
46 47
from astakos.im.models import AstakosUser, PendingThirdPartyUser
47
from astakos.im.forms import LoginForm
48
from astakos.im.forms import LoginForm, ExtendedPasswordChangeForm
48 49
from astakos.im.settings import RATELIMIT_RETRIES_ALLOWED
49 50
from astakos.im.settings import ENABLE_LOCAL_ACCOUNT_MIGRATION
50 51

  
......
123 124
                request,
124 125
                _('Account successfully switched to %(provider)s' % user.__dict__)
125 126
            )
126
    return prepare_response(request, user, next)
127
    return prepare_response(request, user, next)
128

  
129
@require_http_methods(["GET", "POST"])
130
@signed_terms_required
131
@login_required
132
def password_change(request, template_name='registration/password_change_form.html',
133
                    post_change_redirect=None, password_change_form=ExtendedPasswordChangeForm):
134
    if post_change_redirect is None:
135
        post_change_redirect = reverse('django.contrib.auth.views.password_change_done')
136
    if request.method == "POST":
137
        form = password_change_form(
138
            user=request.user,
139
            data=request.POST,
140
            session_key=request.session.session_key
141
        )
142
        if form.is_valid():
143
            form.save()
144
            return HttpResponseRedirect(post_change_redirect)
145
    else:
146
        form = password_change_form(user=request.user)
147
    return render_to_response(template_name, {
148
        'form': form,
149
    }, context_instance=RequestContext(request))
b/snf-astakos-app/astakos/im/target/redirect.py
96 96
            return response
97 97
        renew = request.GET.get('renew', None)
98 98
        if renew == '':
99
            request.user.renew_token()
99
            request.user.renew_token(
100
                flush_sessions=True,
101
                current_key=request.session.session_key
102
            )
100 103
            try:
101 104
                request.user.save()
102 105
            except ValidationError, e:
b/snf-astakos-app/astakos/im/templates/registration/password_change_form.html
1 1
{% extends "im/account_base.html" %}
2 2

  
3 3
{% block body %}
4
<form action="{% url django.contrib.auth.views.password_change %}" method="post"
4
<form action="{% url astakos.im.target.local.password_change %}" method="post"
5 5
    class="withlabels">{% csrf_token %}
6 6

  
7 7
    {% include "im/form_render.html" %}
b/snf-astakos-app/astakos/im/urls.py
49 49
    url(r'^activate/?$', 'activate'),
50 50
    url(r'^approval_terms/?$', 'approval_terms', {}, name='latest_terms'),
51 51
    url(r'^approval_terms/(?P<term_id>\d+)/?$', 'approval_terms'),
52
    url(r'^password/?$', 'change_password', {}, name='password_change'),
53 52
    url(r'^send/activation/(?P<user_id>\d+)/?$', 'send_activation', {}, name='send_activation')
54 53
)
55 54

  
......
66 65

  
67 66
if 'local' in IM_MODULES:
68 67
    urlpatterns += patterns('astakos.im.target',
69
        url(r'^local/?$', 'local.login')
68
        url(r'^local/?$', 'local.login'),
69
        url(r'^password_change/?$', 'local.password_change', {
70
            'post_change_redirect':'profile',
71
            'password_change_form':ExtendedPasswordChangeForm
72
            },
73
            name='password_change')
70 74
    )
71 75
    urlpatterns += patterns('django.contrib.auth.views',
72 76
        url(r'^local/password_reset/?$', 'password_reset',
......
75 79
        url(r'^local/password_reset_done/?$', 'password_reset_done'),
76 80
        url(r'^local/reset/confirm/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/?$',
77 81
         'password_reset_confirm', {'set_password_form':ExtendedSetPasswordForm}),
78
        url(r'^local/password/reset/complete/?$', 'password_reset_complete'),
79
        url(r'^password_change/?$', 'password_change', {'post_change_redirect':'profile',
80
            'password_change_form':ExtendedPasswordChangeForm})
82
        url(r'^local/password/reset/complete/?$', 'password_reset_complete')
81 83
    )
82 84

  
83 85
if INVITATIONS_ENABLED:
b/snf-astakos-app/astakos/im/util.py
156 156
    renew = renew or (not user.auth_token)
157 157
    renew = renew or (user.auth_token_expires and user.auth_token_expires < datetime.datetime.now())
158 158
    if renew:
159
        user.renew_token()
159
        user.renew_token(
160
            flush_sessions=True,
161
            current_key=request.session.session_key
162
        )
160 163
        try:
161 164
            user.save()
162 165
        except ValidationError, e:
b/snf-astakos-app/astakos/im/views.py
263 263
    * LOGIN_URL: login uri
264 264
    """
265 265
    extra_context = extra_context or {}
266
    form = ProfileForm(instance=request.user)
266
    form = ProfileForm(
267
        instance=request.user,
268
        session_key=request.session.session_key
269
    )
267 270
    extra_context['next'] = request.GET.get('next')
268 271
    if request.method == 'POST':
269
        form = ProfileForm(request.POST, instance=request.user)
272
        form = ProfileForm(
273
            request.POST,
274
            instance=request.user,
275
            session_key=request.session.session_key
276
        )
270 277
        if form.is_valid():
271 278
            try:
272 279
                prev_token = request.user.auth_token
273 280
                user = form.save()
274
                form = ProfileForm(instance=user)
281
                form = ProfileForm(
282
                    instance=user,
283
                    session_key=request.session.session_key
284
                )
275 285
                next = restrict_next(
276 286
                    request.POST.get('next'),
277 287
                    domain=COOKIE_DOMAIN

Also available in: Unified diff