Index: main/waeup.sirp/trunk/src/waeup/sirp/accesscodes/accesscode.py
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/accesscodes/accesscode.py	(revision 6926)
+++ main/waeup.sirp/trunk/src/waeup/sirp/accesscodes/accesscode.py	(revision 6927)
@@ -67,4 +67,5 @@
         self.batch_serial = batch_serial
         self.random_num = random_num
+        self.owner = None
         IWorkflowInfo(self).fireTransition('init')
 
@@ -419,5 +420,5 @@
     return code
 
-def fire_transition(access_code, arg, toward=False, comment=None):
+def fire_transition(access_code, arg, toward=False, comment=None, owner=None):
     """Fire workflow transition for access code.
 
@@ -437,4 +438,7 @@
     history of the changed access code. You can use this to place
     remarks like for which object the access code was used or similar.
+
+    If `owner` is specified, the owner attribute of the access code is checked.
+    If the owner is different :func:`fire_transition` fails and returns False.
 
     :func:`fire_transition` might raise exceptions depending on the
@@ -469,4 +473,8 @@
         raise KeyError(
             'No site available for looking up accesscodes')
+    if owner:
+        ac_owner = getattr(ac, 'owner', None)
+        if ac_owner and ac_owner != owner:
+            return False
     info = IWorkflowInfo(ac)
     if toward:
@@ -476,5 +484,5 @@
     return True
 
-def invalidate_accesscode(access_code, comment=None):
+def invalidate_accesscode(access_code, comment=None, owner=None):
     """Invalidate AccessCode denoted by string ``access_code``.
 
@@ -488,6 +496,5 @@
     """
     try:
-        fire_transition(access_code, 'use', comment=comment)
-        return True
+        return fire_transition(access_code, 'use', comment=comment, owner=owner)
     except:
         return False
Index: main/waeup.sirp/trunk/src/waeup/sirp/accesscodes/interfaces.py
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/accesscodes/interfaces.py	(revision 6926)
+++ main/waeup.sirp/trunk/src/waeup/sirp/accesscodes/interfaces.py	(revision 6927)
@@ -29,4 +29,7 @@
     representation = schema.TextLine(
         title = u'Complete title of access code',
+        )
+    owner = schema.TextLine(
+        title = u'Purchaser',
         )
     history = schema.Text(
Index: main/waeup.sirp/trunk/src/waeup/sirp/students/browser.py
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/students/browser.py	(revision 6926)
+++ main/waeup.sirp/trunk/src/waeup/sirp/students/browser.py	(revision 6927)
@@ -1066,6 +1066,8 @@
             comment = u"AC invalidated for %s" % self.context.student_id
             # Here we know that the ac is in state initialized so we do not
-            # expect an exception
-            invalidate_accesscode(pin,comment)
+            # expect an exception, but the owner might be different
+            if not invalidate_accesscode(pin,comment,self.context.student_id):
+                self.flash('You are not the owner of this access code.')
+                return
             self.context.clr_code = pin
         IWorkflowInfo(self.context).fireTransition('start_clearance')
Index: main/waeup.sirp/trunk/src/waeup/sirp/students/tests/test_browser.py
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/students/tests/test_browser.py	(revision 6926)
+++ main/waeup.sirp/trunk/src/waeup/sirp/students/tests/test_browser.py	(revision 6927)
@@ -124,7 +124,7 @@
             datetime.now(), 'some_userid', 'CLR', 9.99, 5)
         pins = pin_container[pin_container.keys()[0]].values()
-        self.clrpins = [x.representation for x in pins]
-        self.existing_clrpin = self.clrpins[0]
-        self.existing_clrpin
+        pins[0].owner = u'Hans Wurst'
+        self.existing_clrac = pins[0]
+        self.existing_clrpin = pins[0].representation
         parts = self.existing_clrpin.split('-')[1:]
         self.existing_clrseries, self.existing_clrnumber = parts
@@ -584,4 +584,10 @@
         self.browser.getControl(name="ac_series").value = self.existing_clrseries
         self.browser.getControl(name="ac_number").value = self.existing_clrnumber
+        # Owner is Hans Wurst, AC can't be invalidated
+        self.browser.getControl("Start clearance now").click()
+        self.assertMatches('...You are not the owner of this access code...',
+                           self.browser.contents)
+        # Set the correct owner
+        self.existing_clrac.owner = self.student_id
         self.browser.getControl("Start clearance now").click()
         self.assertMatches('...Clearance process has been started...',
