Skip to content

Commit cc6059a

Browse files
committed
fix spacing on example code and typo fix.
1 parent 151ebc2 commit cc6059a

File tree

1 file changed

+106
-105
lines changed

1 file changed

+106
-105
lines changed

doc/rest.txt

Lines changed: 106 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1439,14 +1439,15 @@ proper authorization::
14391439
db.security.addPermissionToRole("User:timelog", perm)
14401440

14411441
perm = db.security.addPermission(name='View', klass='issue',
1442-
properties=('id', 'times'),
1443-
description="Allow timelog retreival for issue",
1444-
props_only=False)
1442+
properties=('id', 'times'),
1443+
description="Allow retrieving issue etag or timelog issue",
1444+
props_only=False)
14451445
db.security.addPermissionToRole("User:timelog", perm)
14461446

14471447
perm = db.security.addPermission(name='Edit', klass='issue',
14481448
properties=('id', 'times'),
1449-
description="Allow editing timelog for issue", props_only=False)
1449+
description="Allow editing timelog for issue",
1450+
props_only=False)
14501451
db.security.addPermissionToRole("User:timelog", perm)
14511452

14521453
The role is named to work with the /rest/jwt/issue rest endpoint
@@ -1456,7 +1457,7 @@ role has the User role.
14561457

14571458
The role *must* have access to the issue ``id`` to retrieve the etag for
14581459
the issue. The etag is passed in the ``If-Match`` HTTP header when you
1459-
make a call to patch or update the ``timess` property of the issue.
1460+
make a call to patch or update the ``times` property of the issue.
14601461

14611462
If you use a PATCH rest call with "@op=add" to append the new timelog,
14621463
you don't need View access to the ``times`` property. If you replace the
@@ -1477,106 +1478,106 @@ only been tested with python3)::
14771478
from roundup.rest import Routing, RestfulInstance, _data_decorator
14781479

14791480
class RestfulInstance(object):
1480-
@Routing.route("/jwt/issue", 'POST')
1481-
@_data_decorator
1482-
def generate_jwt(self, input):
1483-
import jwt
1484-
import datetime
1485-
from roundup.anypy.strings import b2s
1486-
1487-
# require basic auth to generate a token
1488-
# At some point we can support a refresh token.
1489-
# maybe a jwt with the "refresh": True claim generated
1490-
# using: "refresh": True in the json request payload.
1491-
1492-
denialmsg='Token creation requires login with basic auth.'
1493-
if 'HTTP_AUTHORIZATION' in self.client.env:
1494-
try:
1495-
auth = self.client.env['HTTP_AUTHORIZATION']
1496-
scheme, challenge = auth.split(' ', 1)
1497-
except (ValueError, AttributeError):
1498-
# bad format for header
1499-
raise Unauthorised(denialmsg)
1500-
if scheme.lower() != 'basic':
1501-
raise Unauthorised(denialmsg)
1502-
else:
1503-
raise Unauthorised(denialmsg)
1504-
1505-
# If we reach this point we have validated that the user has
1506-
# logged in with a password using basic auth.
1507-
all_roles = list(self.db.security.role.items())
1508-
rolenames = []
1509-
for role in all_roles:
1510-
rolenames.append(role[0])
1511-
1512-
user_roles = list(self.db.user.get_roles(self.db.getuid()))
1513-
1514-
claim= { 'sub': self.db.getuid(),
1515-
'iss': self.db.config.TRACKER_WEB,
1516-
'aud': self.db.config.TRACKER_WEB,
1517-
'iat': datetime.datetime.utcnow(),
1518-
}
1519-
1520-
lifetime = 0
1521-
if 'lifetime' in input:
1522-
if input['lifetime'].value != 'unlimited':
1523-
try:
1524-
lifetime = datetime.timedelta(seconds=int(input['lifetime'].value))
1525-
except ValueError:
1526-
raise UsageError("Value 'lifetime' must be 'unlimited' or an integer to specify" +
1527-
" lifetime in seconds. Got %s."%input['lifetime'].value)
1528-
else:
1529-
lifetime = datetime.timedelta(seconds=86400) # 1 day by default
1530-
1531-
if lifetime: # if lifetime = 0 make unlimited by omitting exp claim
1532-
claim['exp'] = datetime.datetime.utcnow() + lifetime
1533-
1534-
newroles = []
1535-
if 'roles' in input:
1536-
for role in input['roles'].value:
1537-
if role not in rolenames:
1538-
raise UsageError("Role %s is not valid."%role)
1539-
if role in user_roles:
1540-
newroles.append(role)
1541-
continue
1542-
parentrole = role.split(':', 1)[0]
1543-
if parentrole in user_roles:
1544-
newroles.append(role)
1545-
continue
1546-
1547-
raise UsageError("Role %s is not permitted."%role)
1548-
1549-
claim['roles'] = newroles
1550-
else:
1551-
claim['roles'] = user_roles
1552-
secret = self.db.config.WEB_JWT_SECRET
1553-
myjwt = jwt.encode(claim, secret, algorithm='HS256')
1554-
1555-
result = {"jwt": b2s(myjwt),
1556-
}
1557-
1558-
return 200, result
1559-
1560-
@Routing.route("/jwt/validate", 'GET')
1561-
@_data_decorator
1562-
def validate_jwt(self,input):
1563-
import jwt
1564-
if not 'jwt' in input:
1565-
raise UsageError("jwt key must be specified")
1566-
1567-
myjwt = input['jwt'].value
1568-
1569-
secret = self.db.config.WEB_JWT_SECRET
1570-
try:
1571-
result = jwt.decode(myjwt, secret,
1572-
algorithms=['HS256'],
1573-
audience=self.db.config.TRACKER_WEB,
1574-
issuer=self.db.config.TRACKER_WEB,
1575-
)
1576-
except jwt.exceptions.InvalidTokenError as err:
1577-
return 401, str(err)
1578-
1579-
return 200, result
1481+
@Routing.route("/jwt/issue", 'POST')
1482+
@_data_decorator
1483+
def generate_jwt(self, input):
1484+
import jwt
1485+
import datetime
1486+
from roundup.anypy.strings import b2s
1487+
1488+
# require basic auth to generate a token
1489+
# At some point we can support a refresh token.
1490+
# maybe a jwt with the "refresh": True claim generated
1491+
# using: "refresh": True in the json request payload.
1492+
1493+
denialmsg='Token creation requires login with basic auth.'
1494+
if 'HTTP_AUTHORIZATION' in self.client.env:
1495+
try:
1496+
auth = self.client.env['HTTP_AUTHORIZATION']
1497+
scheme, challenge = auth.split(' ', 1)
1498+
except (ValueError, AttributeError):
1499+
# bad format for header
1500+
raise Unauthorised(denialmsg)
1501+
if scheme.lower() != 'basic':
1502+
raise Unauthorised(denialmsg)
1503+
else:
1504+
raise Unauthorised(denialmsg)
1505+
1506+
# If we reach this point we have validated that the user has
1507+
# logged in with a password using basic auth.
1508+
all_roles = list(self.db.security.role.items())
1509+
rolenames = []
1510+
for role in all_roles:
1511+
rolenames.append(role[0])
1512+
1513+
user_roles = list(self.db.user.get_roles(self.db.getuid()))
1514+
1515+
claim= { 'sub': self.db.getuid(),
1516+
'iss': self.db.config.TRACKER_WEB,
1517+
'aud': self.db.config.TRACKER_WEB,
1518+
'iat': datetime.datetime.utcnow(),
1519+
}
1520+
1521+
lifetime = 0
1522+
if 'lifetime' in input:
1523+
if input['lifetime'].value != 'unlimited':
1524+
try:
1525+
lifetime = datetime.timedelta(seconds=int(input['lifetime'].value))
1526+
except ValueError:
1527+
raise UsageError("Value 'lifetime' must be 'unlimited' or an integer to specify" +
1528+
" lifetime in seconds. Got %s."%input['lifetime'].value)
1529+
else:
1530+
lifetime = datetime.timedelta(seconds=86400) # 1 day by default
1531+
1532+
if lifetime: # if lifetime = 0 make unlimited by omitting exp claim
1533+
claim['exp'] = datetime.datetime.utcnow() + lifetime
1534+
1535+
newroles = []
1536+
if 'roles' in input:
1537+
for role in input['roles'].value:
1538+
if role not in rolenames:
1539+
raise UsageError("Role %s is not valid."%role)
1540+
if role in user_roles:
1541+
newroles.append(role)
1542+
continue
1543+
parentrole = role.split(':', 1)[0]
1544+
if parentrole in user_roles:
1545+
newroles.append(role)
1546+
continue
1547+
1548+
raise UsageError("Role %s is not permitted."%role)
1549+
1550+
claim['roles'] = newroles
1551+
else:
1552+
claim['roles'] = user_roles
1553+
secret = self.db.config.WEB_JWT_SECRET
1554+
myjwt = jwt.encode(claim, secret, algorithm='HS256')
1555+
1556+
result = {"jwt": b2s(myjwt),
1557+
}
1558+
1559+
return 200, result
1560+
1561+
@Routing.route("/jwt/validate", 'GET')
1562+
@_data_decorator
1563+
def validate_jwt(self,input):
1564+
import jwt
1565+
if not 'jwt' in input:
1566+
raise UsageError("jwt key must be specified")
1567+
1568+
myjwt = input['jwt'].value
1569+
1570+
secret = self.db.config.WEB_JWT_SECRET
1571+
try:
1572+
result = jwt.decode(myjwt, secret,
1573+
algorithms=['HS256'],
1574+
audience=self.db.config.TRACKER_WEB,
1575+
issuer=self.db.config.TRACKER_WEB,
1576+
)
1577+
except jwt.exceptions.InvalidTokenError as err:
1578+
return 401, str(err)
1579+
1580+
return 200, result
15801581

15811582
**Note this is sample code. Use at your own risk.** It breaks a few
15821583
rules about jwts (e.g. it allows you to make unlimited lifetime

0 commit comments

Comments
 (0)