Mercurial > hg > OKFNAnnotator
annotate AuthTokenGenerator.py @ 9:41f264620073 default tip
adds user's groups from LDAP to generated token.
author | casties |
---|---|
date | Thu, 12 Feb 2015 19:46:55 +0100 |
parents | 93c835b645af |
children |
rev | line source |
---|---|
0 | 1 from OFS.SimpleItem import SimpleItem |
2 from Products.PageTemplates.PageTemplateFile import PageTemplateFile | |
3 from OFS.PropertyManager import PropertyManager | |
6
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
4 from AccessControl import getSecurityManager |
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
5 from zExceptions import Unauthorized |
7
279473355e9b
authentication works with hierarchy of acl_users now.
root@tuxserve03.mpiwg-berlin.mpg.de
parents:
6
diff
changeset
|
6 from Acquisition import aq_chain |
0 | 7 |
2 | 8 import logging |
0 | 9 import datetime |
2 | 10 import jwt |
0 | 11 |
12 | |
13 ZERO = datetime.timedelta(0) | |
14 class Utc(datetime.tzinfo): | |
15 def utcoffset(self, dt): | |
16 return ZERO | |
17 | |
18 def tzname(self, dt): | |
19 return "UTC" | |
20 | |
21 def dst(self, dt): | |
22 return ZERO | |
23 UTC = Utc() | |
24 | |
25 | |
26 class AuthTokenGenerator(SimpleItem, PropertyManager): | |
27 """Generator of auth tokens for OKFN Annotator""" | |
28 | |
29 meta_type = 'AuthTokenGenerator' | |
2 | 30 _properties = ({'id':'consumer_key', 'type': 'string', 'mode': 'w'}, |
0 | 31 {'id':'consumer_secret', 'type': 'string', 'mode': 'w'}, |
32 ) | |
33 | |
34 manage_options = PropertyManager.manage_options + SimpleItem.manage_options | |
35 | |
36 # Only change this if you're sure you know what you're doing | |
2 | 37 tokenTtl = 86400 |
0 | 38 |
39 def __init__(self, id, consumerKey=None, consumerSecret=None): | |
40 """init document viewer""" | |
2 | 41 self.id = id |
0 | 42 self.consumer_key = consumerKey |
43 self.consumer_secret = consumerSecret | |
44 | |
6
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
45 def index_html(self, user='anonymous'): |
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
46 """returns authentication token for user (Zope style)""" |
9 | 47 zUser = self._allowed_user(user=user) |
48 logging.debug("allowed user: %s"%repr(zUser)) | |
49 if zUser: | |
50 token = self._generate_token(zUser) | |
2 | 51 # set CORS headers |
0 | 52 origin = self.REQUEST.getHeader("Origin", None) |
53 if origin is not None: | |
54 self.REQUEST.RESPONSE.setHeader("Access-Control-Allow-Origin", origin) | |
55 else: | |
56 self.REQUEST.RESPONSE.setHeader("Access-Control-Allow-Origin", "*") | |
57 | |
58 self.REQUEST.RESPONSE.setHeader("Access-Control-Allow-Credentials", "true") | |
6
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
59 logging.debug("token for user %s: %s"%(user, token)) |
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
60 self.REQUEST.RESPONSE.setHeader("Content-Type", "text/plain") |
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
61 return token |
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
62 else: |
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
63 raise Unauthorized |
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
64 |
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
65 def getLoginToken(self, user='anonymous', password=None): |
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
66 """returns authentication token or error code""" |
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
67 # set CORS headers |
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
68 origin = self.REQUEST.getHeader("Origin", None) |
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
69 if origin is not None: |
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
70 self.REQUEST.RESPONSE.setHeader("Access-Control-Allow-Origin", origin) |
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
71 else: |
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
72 self.REQUEST.RESPONSE.setHeader("Access-Control-Allow-Origin", "*") |
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
73 |
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
74 self.REQUEST.RESPONSE.setHeader("Access-Control-Allow-Credentials", "true") |
9 | 75 zUser = self._allowed_user(user=user, password=password) |
76 logging.debug("allowed user: %s"%repr(zUser)) | |
77 if zUser: | |
78 token = self._generate_token(zUser) | |
6
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
79 logging.debug("token for user %s: %s"%(user, token)) |
2 | 80 self.REQUEST.RESPONSE.setHeader("Content-Type", "text/plain") |
81 return token | |
0 | 82 else: |
6
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
83 self.REQUEST.RESPONSE.setStatus('Unauthorized') |
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
84 return "Please Authenticate!" |
0 | 85 |
9 | 86 def _allowed_user(self, user=None, password=None): |
6
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
87 # check the login |
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
88 if user == 'anonymous': |
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
89 # everybody can be anonymous |
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
90 return user |
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
91 |
8 | 92 # get logged in user from Zope |
6
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
93 authuser = getSecurityManager().getUser() |
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
94 authname = authuser.getUserName() |
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
95 if authname == user: |
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
96 # user is logged in |
9 | 97 return authuser |
6
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
98 |
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
99 if password: |
8 | 100 logging.debug("trying password for token for user %s"%user) |
7
279473355e9b
authentication works with hierarchy of acl_users now.
root@tuxserve03.mpiwg-berlin.mpg.de
parents:
6
diff
changeset
|
101 # try all user folders in aq_chain |
279473355e9b
authentication works with hierarchy of acl_users now.
root@tuxserve03.mpiwg-berlin.mpg.de
parents:
6
diff
changeset
|
102 authuser = None |
279473355e9b
authentication works with hierarchy of acl_users now.
root@tuxserve03.mpiwg-berlin.mpg.de
parents:
6
diff
changeset
|
103 userfolder = None |
279473355e9b
authentication works with hierarchy of acl_users now.
root@tuxserve03.mpiwg-berlin.mpg.de
parents:
6
diff
changeset
|
104 for ctx in aq_chain(self): |
279473355e9b
authentication works with hierarchy of acl_users now.
root@tuxserve03.mpiwg-berlin.mpg.de
parents:
6
diff
changeset
|
105 new_uf = getattr(ctx, 'acl_users', None) |
279473355e9b
authentication works with hierarchy of acl_users now.
root@tuxserve03.mpiwg-berlin.mpg.de
parents:
6
diff
changeset
|
106 if new_uf != userfolder: |
279473355e9b
authentication works with hierarchy of acl_users now.
root@tuxserve03.mpiwg-berlin.mpg.de
parents:
6
diff
changeset
|
107 userfolder = new_uf |
279473355e9b
authentication works with hierarchy of acl_users now.
root@tuxserve03.mpiwg-berlin.mpg.de
parents:
6
diff
changeset
|
108 authuser = userfolder.authenticate(user, password, None) |
279473355e9b
authentication works with hierarchy of acl_users now.
root@tuxserve03.mpiwg-berlin.mpg.de
parents:
6
diff
changeset
|
109 if authuser is not None: |
279473355e9b
authentication works with hierarchy of acl_users now.
root@tuxserve03.mpiwg-berlin.mpg.de
parents:
6
diff
changeset
|
110 return authuser |
6
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
111 |
17bbd5e80d15
method getLoginToken and real authentication support.
casties
parents:
2
diff
changeset
|
112 return None |
0 | 113 |
9 | 114 def _generate_token(self, user): |
0 | 115 #return JSON-token |
2 | 116 issue_time = datetime.datetime.now(UTC).replace(microsecond=0) |
9 | 117 if isinstance(user, basestring): |
118 # not a real User object | |
119 user_id = user | |
120 else: | |
121 user_id = user.getUserName() | |
122 | |
123 payload = { | |
124 'consumerKey':self.consumer_key, | |
125 'userId':user_id, | |
126 'issuedAt':issue_time.isoformat(), | |
127 'ttl':self.tokenTtl} | |
2 | 128 |
9 | 129 if hasattr(user, '_getLDAPGroups'): |
130 # add groups from LDAP | |
131 groups = user._getLDAPGroups() | |
132 payload['memberOf'] = groups | |
133 | |
134 logging.debug("token payload=%s"%repr(payload)) | |
135 return jwt.encode(payload, self.consumer_secret) | |
2 | 136 |
0 | 137 |
138 def manage_addAuthTokenGeneratorForm(self): | |
139 """form for adding AuthTokenGenerator""" | |
140 pt = PageTemplateFile("zpt/manage_addAuthTokenGenerator", globals()).__of__(self) | |
141 return pt() | |
142 | |
143 def manage_addAuthTokenGenerator(context, id, consumerKey=None, consumerSecret=None): | |
144 """ """ | |
145 context._setObject(id, AuthTokenGenerator(id, consumerKey=consumerKey, consumerSecret=consumerSecret)) | |
146 return "AuthTokenGenerator Installed: %s" % id |