Mercurial > p > roundup > code
comparison test/rest_common.py @ 5878:1b57d8f3eb97
Add rudimentery experiment JSON Web Token (jwt) support
issue2551061: Add rudimentary experimental support for JSON Web Tokens
to allow delegation of limited access rights to third parties. See
doc/rest.txt for details and intent.
| author | John Rouillard <rouilj@ieee.org> |
|---|---|
| date | Fri, 27 Sep 2019 20:38:31 -0400 |
| parents | 6630baff5f68 |
| children | 94a7669677ae |
comparison
equal
deleted
inserted
replaced
| 5877:08b241c9fea4 | 5878:1b57d8f3eb97 |
|---|---|
| 3 import shutil | 3 import shutil |
| 4 import errno | 4 import errno |
| 5 import cgi | 5 import cgi |
| 6 | 6 |
| 7 from time import sleep | 7 from time import sleep |
| 8 from datetime import datetime | 8 from datetime import datetime, timedelta |
| 9 | |
| 10 try: | |
| 11 from datetime import timezone | |
| 12 myutc = timezone.utc | |
| 13 except ImportError: | |
| 14 # python 2 | |
| 15 from datetime import tzinfo | |
| 16 ZERO = timedelta(0) | |
| 17 class UTC(tzinfo): | |
| 18 """UTC""" | |
| 19 def utcoffset(self, dt): | |
| 20 return ZERO | |
| 21 | |
| 22 def tzname(self, dt): | |
| 23 return "UTC" | |
| 24 | |
| 25 def dst(self, dt): | |
| 26 return ZERO | |
| 27 | |
| 28 myutc = UTC() | |
| 9 | 29 |
| 10 from roundup.cgi.exceptions import * | 30 from roundup.cgi.exceptions import * |
| 11 from roundup.hyperdb import HyperdbValueError | 31 from roundup.hyperdb import HyperdbValueError |
| 12 from roundup.exceptions import * | 32 from roundup.exceptions import * |
| 13 from roundup import password, hyperdb | 33 from roundup import password, hyperdb |
| 25 from .mocknull import MockNull | 45 from .mocknull import MockNull |
| 26 | 46 |
| 27 from io import BytesIO | 47 from io import BytesIO |
| 28 import json | 48 import json |
| 29 | 49 |
| 50 from copy import copy | |
| 51 | |
| 52 try: | |
| 53 import jwt | |
| 54 skip_jwt = lambda func, *args, **kwargs: func | |
| 55 except ImportError: | |
| 56 from .pytest_patcher import mark_class | |
| 57 jwt=None | |
| 58 skip_jwt = mark_class(pytest.mark.skip( | |
| 59 reason='Skipping JWT tests: jwt library not available')) | |
| 60 | |
| 30 NEEDS_INSTANCE = 1 | 61 NEEDS_INSTANCE = 1 |
| 31 | 62 |
| 32 | 63 |
| 33 class TestCase(): | 64 class TestCase(): |
| 34 | 65 |
| 36 url_pfx = 'http://tracker.example/cgi-bin/roundup.cgi/bugs/rest/data/' | 67 url_pfx = 'http://tracker.example/cgi-bin/roundup.cgi/bugs/rest/data/' |
| 37 | 68 |
| 38 def setUp(self): | 69 def setUp(self): |
| 39 self.dirname = '_test_rest' | 70 self.dirname = '_test_rest' |
| 40 # set up and open a tracker | 71 # set up and open a tracker |
| 41 self.instance = setupTracker(self.dirname, self.backend) | 72 # Set optimize=True as code under test (Client.main()::determine_user) |
| 73 # will close and re-open the database on user changes. This wipes | |
| 74 # out additions to the schema needed for testing. | |
| 75 self.instance = setupTracker(self.dirname, self.backend, optimize=True) | |
| 42 | 76 |
| 43 # open the database | 77 # open the database |
| 44 self.db = self.instance.open('admin') | 78 self.db = self.instance.open('admin') |
| 45 | 79 |
| 46 # Create the Otk db. | 80 # Create the Otk db. |
| 58 address='random@home.org', | 92 address='random@home.org', |
| 59 realname='Joe Random', | 93 realname='Joe Random', |
| 60 roles='User' | 94 roles='User' |
| 61 ) | 95 ) |
| 62 | 96 |
| 97 self.db.user.set('1', address="admin@admin.com") | |
| 98 self.db.user.set('2', address="anon@admin.com") | |
| 63 self.db.commit() | 99 self.db.commit() |
| 64 self.db.close() | 100 self.db.close() |
| 65 self.db = self.instance.open('joe') | 101 self.db = self.instance.open('joe') |
| 66 # Allow joe to retire | 102 # Allow joe to retire |
| 67 p = self.db.security.addPermission(name='Retire', klass='issue') | 103 p = self.db.security.addPermission(name='Retire', klass='issue') |
| 68 self.db.security.addPermissionToRole('User', p) | 104 self.db.security.addPermissionToRole('User', p) |
| 105 | |
| 106 # add set of roles for testing jwt's. | |
| 107 self.db.security.addRole(name="User:email", | |
| 108 description="allow email by jwt") | |
| 109 # allow the jwt to access everybody's email addresses. | |
| 110 # this makes it easier to differentiate between User and | |
| 111 # User:email roles by accessing the /rest/data/user | |
| 112 # endpoint | |
| 113 jwt_perms = self.db.security.addPermission(name='View', | |
| 114 klass='user', | |
| 115 properties=('id', 'realname', 'address', 'username'), | |
| 116 description="Allow jwt access to email", | |
| 117 props_only=False) | |
| 118 self.db.security.addPermissionToRole("User:email", jwt_perms) | |
| 119 | |
| 120 if jwt: | |
| 121 # must be 32 chars in length minimum (I think this is at least | |
| 122 # 256 bits of data) | |
| 123 | |
| 124 secret = "TestingTheJwtSecretTestingTheJwtSecret" | |
| 125 self.db.config['WEB_JWT_SECRET'] = secret | |
| 126 | |
| 127 # generate all timestamps in UTC. | |
| 128 base_datetime = datetime(1970,1,1, tzinfo=myutc) | |
| 129 | |
| 130 # A UTC timestamp for now. | |
| 131 dt = datetime.now(myutc) | |
| 132 now_ts = int((dt - base_datetime).total_seconds()) | |
| 133 | |
| 134 # one good for a minute | |
| 135 dt = dt + timedelta(seconds=60) | |
| 136 plus1min_ts = int((dt - base_datetime).total_seconds()) | |
| 137 | |
| 138 # one that expired a minute ago | |
| 139 dt = dt - timedelta(seconds=120) | |
| 140 expired_ts = int((dt - base_datetime).total_seconds()) | |
| 141 | |
| 142 # claims match what cgi/client.py::determine_user | |
| 143 # is looking for | |
| 144 claim= { 'sub': self.db.getuid(), | |
| 145 'iss': self.db.config.TRACKER_WEB, | |
| 146 'aud': self.db.config.TRACKER_WEB, | |
| 147 'roles': [ 'User' ], | |
| 148 'iat': now_ts, | |
| 149 'exp': plus1min_ts, | |
| 150 } | |
| 151 | |
| 152 self.jwt = {} | |
| 153 self.claim = {} | |
| 154 # generate invalid claim with expired timestamp | |
| 155 self.claim['expired'] = copy(claim) | |
| 156 self.claim['expired']['exp'] = expired_ts | |
| 157 self.jwt['expired'] = b2s(jwt.encode(self.claim['expired'], secret, | |
| 158 algorithm='HS256')) | |
| 159 | |
| 160 # generate valid claim with user role | |
| 161 self.claim['user'] = copy(claim) | |
| 162 self.claim['user']['exp'] = plus1min_ts | |
| 163 self.jwt['user'] = b2s(jwt.encode(self.claim['user'], secret, | |
| 164 algorithm='HS256')) | |
| 165 # generate invalid claim bad issuer | |
| 166 self.claim['badiss'] = copy(claim) | |
| 167 self.claim['badiss']['iss'] = "http://someissuer/bugs" | |
| 168 self.jwt['badiss'] = b2s(jwt.encode(self.claim['badiss'], secret, | |
| 169 algorithm='HS256')) | |
| 170 # generate invalid claim bad aud(ience) | |
| 171 self.claim['badaud'] = copy(claim) | |
| 172 self.claim['badaud']['aud'] = "http://someaudience/bugs" | |
| 173 self.jwt['badaud'] = b2s(jwt.encode(self.claim['badaud'], secret, | |
| 174 algorithm='HS256')) | |
| 175 # generate invalid claim bad sub(ject) | |
| 176 self.claim['badsub'] = copy(claim) | |
| 177 self.claim['badsub']['sub'] = str("99") | |
| 178 self.jwt['badsub'] = b2s(jwt.encode(self.claim['badsub'], secret, | |
| 179 algorithm='HS256')) | |
| 180 # generate invalid claim bad roles | |
| 181 self.claim['badroles'] = copy(claim) | |
| 182 self.claim['badroles']['roles'] = [ "badrole1", "badrole2" ] | |
| 183 self.jwt['badroles'] = b2s(jwt.encode(self.claim['badroles'], secret, | |
| 184 algorithm='HS256')) | |
| 185 # generate valid claim with limited user:email role | |
| 186 self.claim['user:email'] = copy(claim) | |
| 187 self.claim['user:email']['roles'] = [ "user:email" ] | |
| 188 self.jwt['user:email'] = b2s(jwt.encode(self.claim['user:email'], secret, | |
| 189 algorithm='HS256')) | |
| 69 | 190 |
| 70 self.db.tx_Source = 'web' | 191 self.db.tx_Source = 'web' |
| 71 | 192 |
| 72 self.db.issue.addprop(tx_Source=hyperdb.String()) | 193 self.db.issue.addprop(tx_Source=hyperdb.String()) |
| 73 self.db.issue.addprop(anint=hyperdb.Integer()) | 194 self.db.issue.addprop(anint=hyperdb.Integer()) |
| 2756 results = results['data'] | 2877 results = results['data'] |
| 2757 self.assertEqual(self.dummy_client.response_code, 200) | 2878 self.assertEqual(self.dummy_client.response_code, 200) |
| 2758 self.assertEqual(len(results['attributes']['nosy']), 0) | 2879 self.assertEqual(len(results['attributes']['nosy']), 0) |
| 2759 self.assertListEqual(results['attributes']['nosy'], []) | 2880 self.assertListEqual(results['attributes']['nosy'], []) |
| 2760 | 2881 |
| 2882 @skip_jwt | |
| 2883 def test_expired_jwt(self): | |
| 2884 # self.dummy_client.main() closes database, so | |
| 2885 # we need a new test with setup called for each test | |
| 2886 out = [] | |
| 2887 def wh(s): | |
| 2888 out.append(s) | |
| 2889 | |
| 2890 secret = self.db.config.WEB_JWT_SECRET | |
| 2891 | |
| 2892 # verify library and tokens are correct | |
| 2893 self.assertRaises(jwt.exceptions.InvalidTokenError, | |
| 2894 jwt.decode, self.jwt['expired'], | |
| 2895 secret, algorithms=['HS256'], | |
| 2896 audience=self.db.config.TRACKER_WEB, | |
| 2897 issuer=self.db.config.TRACKER_WEB) | |
| 2898 | |
| 2899 result = jwt.decode(self.jwt['user'], | |
| 2900 secret, algorithms=['HS256'], | |
| 2901 audience=self.db.config.TRACKER_WEB, | |
| 2902 issuer=self.db.config.TRACKER_WEB) | |
| 2903 self.assertEqual(self.claim['user'],result) | |
| 2904 | |
| 2905 result = jwt.decode(self.jwt['user:email'], | |
| 2906 secret, algorithms=['HS256'], | |
| 2907 audience=self.db.config.TRACKER_WEB, | |
| 2908 issuer=self.db.config.TRACKER_WEB) | |
| 2909 self.assertEqual(self.claim['user:email'],result) | |
| 2910 | |
| 2911 # set environment for all jwt tests | |
| 2912 env = { | |
| 2913 'PATH_INFO': 'rest/data/user', | |
| 2914 'HTTP_HOST': 'localhost', | |
| 2915 'TRACKER_NAME': 'rounduptest', | |
| 2916 "REQUEST_METHOD": "GET" | |
| 2917 } | |
| 2918 self.dummy_client = client.Client(self.instance, MockNull(), env, | |
| 2919 [], None) | |
| 2920 self.dummy_client.db = self.db | |
| 2921 self.dummy_client.request.headers.get = self.get_header | |
| 2922 self.empty_form = cgi.FieldStorage() | |
| 2923 self.terse_form = cgi.FieldStorage() | |
| 2924 self.terse_form.list = [ | |
| 2925 cgi.MiniFieldStorage('@verbose', '0'), | |
| 2926 ] | |
| 2927 self.dummy_client.form = cgi.FieldStorage() | |
| 2928 self.dummy_client.form.list = [ | |
| 2929 cgi.MiniFieldStorage('@fields', 'username,address'), | |
| 2930 ] | |
| 2931 # accumulate json output for further analysis | |
| 2932 self.dummy_client.write = wh | |
| 2933 | |
| 2934 # set up for expired token first | |
| 2935 env['HTTP_AUTHORIZATION'] = 'bearer %s'%self.jwt['expired'] | |
| 2936 self.dummy_client.main() | |
| 2937 | |
| 2938 # this will be the admin still as auth failed | |
| 2939 self.assertEqual('1', self.db.getuid()) | |
| 2940 self.assertEqual(out[0], b'Invalid Login - Signature has expired') | |
| 2941 del(out[0]) | |
| 2942 | |
| 2943 | |
| 2944 @skip_jwt | |
| 2945 def test_user_jwt(self): | |
| 2946 # self.dummy_client.main() closes database, so | |
| 2947 # we need a new test with setup called for each test | |
| 2948 out = [] | |
| 2949 def wh(s): | |
| 2950 out.append(s) | |
| 2951 | |
| 2952 secret = self.db.config.WEB_JWT_SECRET | |
| 2953 | |
| 2954 # verify library and tokens are correct | |
| 2955 self.assertRaises(jwt.exceptions.InvalidTokenError, | |
| 2956 jwt.decode, self.jwt['expired'], | |
| 2957 secret, algorithms=['HS256'], | |
| 2958 audience=self.db.config.TRACKER_WEB, | |
| 2959 issuer=self.db.config.TRACKER_WEB) | |
| 2960 | |
| 2961 result = jwt.decode(self.jwt['user'], | |
| 2962 secret, algorithms=['HS256'], | |
| 2963 audience=self.db.config.TRACKER_WEB, | |
| 2964 issuer=self.db.config.TRACKER_WEB) | |
| 2965 self.assertEqual(self.claim['user'],result) | |
| 2966 | |
| 2967 result = jwt.decode(self.jwt['user:email'], | |
| 2968 secret, algorithms=['HS256'], | |
| 2969 audience=self.db.config.TRACKER_WEB, | |
| 2970 issuer=self.db.config.TRACKER_WEB) | |
| 2971 self.assertEqual(self.claim['user:email'],result) | |
| 2972 | |
| 2973 # set environment for all jwt tests | |
| 2974 env = { | |
| 2975 'PATH_INFO': 'rest/data/user', | |
| 2976 'HTTP_HOST': 'localhost', | |
| 2977 'TRACKER_NAME': 'rounduptest', | |
| 2978 "REQUEST_METHOD": "GET" | |
| 2979 } | |
| 2980 self.dummy_client = client.Client(self.instance, MockNull(), env, | |
| 2981 [], None) | |
| 2982 self.dummy_client.db = self.db | |
| 2983 self.dummy_client.request.headers.get = self.get_header | |
| 2984 self.empty_form = cgi.FieldStorage() | |
| 2985 self.terse_form = cgi.FieldStorage() | |
| 2986 self.terse_form.list = [ | |
| 2987 cgi.MiniFieldStorage('@verbose', '0'), | |
| 2988 ] | |
| 2989 self.dummy_client.form = cgi.FieldStorage() | |
| 2990 self.dummy_client.form.list = [ | |
| 2991 cgi.MiniFieldStorage('@fields', 'username,address'), | |
| 2992 ] | |
| 2993 # accumulate json output for further analysis | |
| 2994 self.dummy_client.write = wh | |
| 2995 | |
| 2996 # set up for standard user role token | |
| 2997 env['HTTP_AUTHORIZATION'] = 'bearer %s'%self.jwt['user'] | |
| 2998 self.dummy_client.main() | |
| 2999 print(out[0]) | |
| 3000 json_dict = json.loads(b2s(out[0])) | |
| 3001 print(json_dict) | |
| 3002 # user will be joe id 3 as auth works | |
| 3003 self.assertTrue('3', self.db.getuid()) | |
| 3004 # there should be three items in the collection admin, anon, and joe | |
| 3005 self.assertEqual(3, len(json_dict['data']['collection'])) | |
| 3006 # since this token has no access to email addresses, only joe | |
| 3007 # should have email addresses. Order is by id by default. | |
| 3008 self.assertFalse('address' in json_dict['data']['collection'][0]) | |
| 3009 self.assertFalse('address' in json_dict['data']['collection'][1]) | |
| 3010 self.assertTrue('address' in json_dict['data']['collection'][2]) | |
| 3011 del(out[0]) | |
| 3012 self.db.setCurrentUser('admin') | |
| 3013 | |
| 3014 @skip_jwt | |
| 3015 def test_user_email_jwt(self): | |
| 3016 # self.dummy_client.main() closes database, so | |
| 3017 # we need a new test with setup called for each test | |
| 3018 out = [] | |
| 3019 def wh(s): | |
| 3020 out.append(s) | |
| 3021 | |
| 3022 secret = self.db.config.WEB_JWT_SECRET | |
| 3023 | |
| 3024 # verify library and tokens are correct | |
| 3025 self.assertRaises(jwt.exceptions.InvalidTokenError, | |
| 3026 jwt.decode, self.jwt['expired'], | |
| 3027 secret, algorithms=['HS256'], | |
| 3028 audience=self.db.config.TRACKER_WEB, | |
| 3029 issuer=self.db.config.TRACKER_WEB) | |
| 3030 | |
| 3031 result = jwt.decode(self.jwt['user'], | |
| 3032 secret, algorithms=['HS256'], | |
| 3033 audience=self.db.config.TRACKER_WEB, | |
| 3034 issuer=self.db.config.TRACKER_WEB) | |
| 3035 self.assertEqual(self.claim['user'],result) | |
| 3036 | |
| 3037 result = jwt.decode(self.jwt['user:email'], | |
| 3038 secret, algorithms=['HS256'], | |
| 3039 audience=self.db.config.TRACKER_WEB, | |
| 3040 issuer=self.db.config.TRACKER_WEB) | |
| 3041 self.assertEqual(self.claim['user:email'],result) | |
| 3042 | |
| 3043 # set environment for all jwt tests | |
| 3044 env = { | |
| 3045 'PATH_INFO': 'rest/data/user', | |
| 3046 'HTTP_HOST': 'localhost', | |
| 3047 'TRACKER_NAME': 'rounduptest', | |
| 3048 "REQUEST_METHOD": "GET" | |
| 3049 } | |
| 3050 self.dummy_client = client.Client(self.instance, MockNull(), env, | |
| 3051 [], None) | |
| 3052 self.dummy_client.db = self.db | |
| 3053 self.dummy_client.request.headers.get = self.get_header | |
| 3054 self.empty_form = cgi.FieldStorage() | |
| 3055 self.terse_form = cgi.FieldStorage() | |
| 3056 self.terse_form.list = [ | |
| 3057 cgi.MiniFieldStorage('@verbose', '0'), | |
| 3058 ] | |
| 3059 self.dummy_client.form = cgi.FieldStorage() | |
| 3060 self.dummy_client.form.list = [ | |
| 3061 cgi.MiniFieldStorage('@fields', 'username,address'), | |
| 3062 ] | |
| 3063 # accumulate json output for further analysis | |
| 3064 self.dummy_client.write = wh | |
| 3065 | |
| 3066 # set up for limited user:email role token | |
| 3067 env['HTTP_AUTHORIZATION'] = 'bearer %s'%self.jwt['user:email'] | |
| 3068 self.dummy_client.main() | |
| 3069 json_dict = json.loads(b2s(out[0])) | |
| 3070 print(json_dict) | |
| 3071 # user will be joe id 3 as auth works | |
| 3072 self.assertTrue('3', self.db.getuid()) | |
| 3073 # there should be three items in the collection admin, anon, and joe | |
| 3074 self.assertEqual(3, len(json_dict['data']['collection'])) | |
| 3075 # However this token has access to email addresses, so all three | |
| 3076 # should have email addresses. Order is by id by default. | |
| 3077 self.assertTrue('address' in json_dict['data']['collection'][0]) | |
| 3078 self.assertTrue('address' in json_dict['data']['collection'][1]) | |
| 3079 self.assertTrue('address' in json_dict['data']['collection'][2]) | |
| 3080 | |
| 3081 | |
| 3082 @skip_jwt | |
| 3083 def test_disabled_jwt(self): | |
| 3084 # self.dummy_client.main() closes database, so | |
| 3085 # we need a new test with setup called for each test | |
| 3086 out = [] | |
| 3087 def wh(s): | |
| 3088 out.append(s) | |
| 3089 | |
| 3090 # set environment for all jwt tests | |
| 3091 env = { | |
| 3092 'PATH_INFO': 'rest/data/user', | |
| 3093 'HTTP_HOST': 'localhost', | |
| 3094 'TRACKER_NAME': 'rounduptest', | |
| 3095 "REQUEST_METHOD": "GET" | |
| 3096 } | |
| 3097 self.dummy_client = client.Client(self.instance, MockNull(), env, | |
| 3098 [], None) | |
| 3099 self.dummy_client.db = self.db | |
| 3100 self.dummy_client.request.headers.get = self.get_header | |
| 3101 self.empty_form = cgi.FieldStorage() | |
| 3102 self.terse_form = cgi.FieldStorage() | |
| 3103 self.terse_form.list = [ | |
| 3104 cgi.MiniFieldStorage('@verbose', '0'), | |
| 3105 ] | |
| 3106 self.dummy_client.form = cgi.FieldStorage() | |
| 3107 self.dummy_client.form.list = [ | |
| 3108 cgi.MiniFieldStorage('@fields', 'username,address'), | |
| 3109 ] | |
| 3110 # accumulate json output for further analysis | |
| 3111 self.dummy_client.write = wh | |
| 3112 # disable jwt validation by making secret too short | |
| 3113 # use the default value for this in configure.py. | |
| 3114 self.db.config['WEB_JWT_SECRET'] = "disabled" | |
| 3115 env['HTTP_AUTHORIZATION'] = 'bearer %s'%self.jwt['user'] | |
| 3116 self.dummy_client.main() | |
| 3117 # user will be 1 as there is no auth | |
| 3118 self.assertTrue('1', self.db.getuid()) | |
| 3119 self.assertEqual(out[0], b'Invalid Login - Support for jwt disabled by admin.') | |
| 3120 | |
| 3121 @skip_jwt | |
| 3122 def test_bad_issue_jwt(self): | |
| 3123 # self.dummy_client.main() closes database, so | |
| 3124 # we need a new test with setup called for each test | |
| 3125 out = [] | |
| 3126 def wh(s): | |
| 3127 out.append(s) | |
| 3128 | |
| 3129 # set environment for all jwt tests | |
| 3130 env = { | |
| 3131 'PATH_INFO': 'rest/data/user', | |
| 3132 'HTTP_HOST': 'localhost', | |
| 3133 'TRACKER_NAME': 'rounduptest', | |
| 3134 "REQUEST_METHOD": "GET" | |
| 3135 } | |
| 3136 self.dummy_client = client.Client(self.instance, MockNull(), env, | |
| 3137 [], None) | |
| 3138 self.dummy_client.db = self.db | |
| 3139 self.dummy_client.request.headers.get = self.get_header | |
| 3140 self.empty_form = cgi.FieldStorage() | |
| 3141 self.terse_form = cgi.FieldStorage() | |
| 3142 self.terse_form.list = [ | |
| 3143 cgi.MiniFieldStorage('@verbose', '0'), | |
| 3144 ] | |
| 3145 self.dummy_client.form = cgi.FieldStorage() | |
| 3146 self.dummy_client.form.list = [ | |
| 3147 cgi.MiniFieldStorage('@fields', 'username,address'), | |
| 3148 ] | |
| 3149 # accumulate json output for further analysis | |
| 3150 self.dummy_client.write = wh | |
| 3151 env['HTTP_AUTHORIZATION'] = 'bearer %s'%self.jwt['badiss'] | |
| 3152 self.dummy_client.main() | |
| 3153 # user will be 1 as there is no auth | |
| 3154 self.assertTrue('1', self.db.getuid()) | |
| 3155 self.assertEqual(out[0], b'Invalid Login - Invalid issuer') | |
| 3156 | |
| 3157 @skip_jwt | |
| 3158 def test_bad_audience_jwt(self): | |
| 3159 # self.dummy_client.main() closes database, so | |
| 3160 # we need a new test with setup called for each test | |
| 3161 out = [] | |
| 3162 def wh(s): | |
| 3163 out.append(s) | |
| 3164 | |
| 3165 # set environment for all jwt tests | |
| 3166 env = { | |
| 3167 'PATH_INFO': 'rest/data/user', | |
| 3168 'HTTP_HOST': 'localhost', | |
| 3169 'TRACKER_NAME': 'rounduptest', | |
| 3170 "REQUEST_METHOD": "GET" | |
| 3171 } | |
| 3172 self.dummy_client = client.Client(self.instance, MockNull(), env, | |
| 3173 [], None) | |
| 3174 self.dummy_client.db = self.db | |
| 3175 self.dummy_client.request.headers.get = self.get_header | |
| 3176 self.empty_form = cgi.FieldStorage() | |
| 3177 self.terse_form = cgi.FieldStorage() | |
| 3178 self.terse_form.list = [ | |
| 3179 cgi.MiniFieldStorage('@verbose', '0'), | |
| 3180 ] | |
| 3181 self.dummy_client.form = cgi.FieldStorage() | |
| 3182 self.dummy_client.form.list = [ | |
| 3183 cgi.MiniFieldStorage('@fields', 'username,address'), | |
| 3184 ] | |
| 3185 # accumulate json output for further analysis | |
| 3186 self.dummy_client.write = wh | |
| 3187 env['HTTP_AUTHORIZATION'] = 'bearer %s'%self.jwt['badaud'] | |
| 3188 self.dummy_client.main() | |
| 3189 # user will be 1 as there is no auth | |
| 3190 self.assertTrue('1', self.db.getuid()) | |
| 3191 self.assertEqual(out[0], b'Invalid Login - Invalid audience') | |
| 3192 | |
| 3193 @skip_jwt | |
| 3194 def test_bad_roles_jwt(self): | |
| 3195 # self.dummy_client.main() closes database, so | |
| 3196 # we need a new test with setup called for each test | |
| 3197 out = [] | |
| 3198 def wh(s): | |
| 3199 out.append(s) | |
| 3200 | |
| 3201 # set environment for all jwt tests | |
| 3202 env = { | |
| 3203 'PATH_INFO': 'rest/data/user', | |
| 3204 'HTTP_HOST': 'localhost', | |
| 3205 'TRACKER_NAME': 'rounduptest', | |
| 3206 "REQUEST_METHOD": "GET" | |
| 3207 } | |
| 3208 self.dummy_client = client.Client(self.instance, MockNull(), env, | |
| 3209 [], None) | |
| 3210 self.dummy_client.db = self.db | |
| 3211 self.dummy_client.request.headers.get = self.get_header | |
| 3212 self.empty_form = cgi.FieldStorage() | |
| 3213 self.terse_form = cgi.FieldStorage() | |
| 3214 self.terse_form.list = [ | |
| 3215 cgi.MiniFieldStorage('@verbose', '0'), | |
| 3216 ] | |
| 3217 self.dummy_client.form = cgi.FieldStorage() | |
| 3218 self.dummy_client.form.list = [ | |
| 3219 cgi.MiniFieldStorage('@fields', 'username,address'), | |
| 3220 ] | |
| 3221 # accumulate json output for further analysis | |
| 3222 self.dummy_client.write = wh | |
| 3223 env['HTTP_AUTHORIZATION'] = 'bearer %s'%self.jwt['badroles'] | |
| 3224 self.dummy_client.main() | |
| 3225 # user will be 1 as there is no auth | |
| 3226 self.assertTrue('1', self.db.getuid()) | |
| 3227 self.assertEqual(out[0], b'Invalid Login - Token roles are invalid.') | |
| 3228 | |
| 3229 @skip_jwt | |
| 3230 def test_bad_subject_jwt(self): | |
| 3231 # self.dummy_client.main() closes database, so | |
| 3232 # we need a new test with setup called for each test | |
| 3233 out = [] | |
| 3234 def wh(s): | |
| 3235 out.append(s) | |
| 3236 | |
| 3237 # set environment for all jwt tests | |
| 3238 env = { | |
| 3239 'PATH_INFO': 'rest/data/user', | |
| 3240 'HTTP_HOST': 'localhost', | |
| 3241 'TRACKER_NAME': 'rounduptest', | |
| 3242 "REQUEST_METHOD": "GET" | |
| 3243 } | |
| 3244 self.dummy_client = client.Client(self.instance, MockNull(), env, | |
| 3245 [], None) | |
| 3246 self.dummy_client.db = self.db | |
| 3247 self.dummy_client.request.headers.get = self.get_header | |
| 3248 self.empty_form = cgi.FieldStorage() | |
| 3249 self.terse_form = cgi.FieldStorage() | |
| 3250 self.terse_form.list = [ | |
| 3251 cgi.MiniFieldStorage('@verbose', '0'), | |
| 3252 ] | |
| 3253 self.dummy_client.form = cgi.FieldStorage() | |
| 3254 self.dummy_client.form.list = [ | |
| 3255 cgi.MiniFieldStorage('@fields', 'username,address'), | |
| 3256 ] | |
| 3257 # accumulate json output for further analysis | |
| 3258 self.dummy_client.write = wh | |
| 3259 env['HTTP_AUTHORIZATION'] = 'bearer %s'%self.jwt['badsub'] | |
| 3260 self.dummy_client.main() | |
| 3261 # user will be 1 as there is no auth | |
| 3262 self.assertTrue('1', self.db.getuid()) | |
| 3263 self.assertEqual(out[0], b'Invalid Login - Token subject is invalid.') | |
| 2761 | 3264 |
| 2762 def get_obj(path, id): | 3265 def get_obj(path, id): |
| 2763 return { | 3266 return { |
| 2764 'id': id, | 3267 'id': id, |
| 2765 'link': path + id | 3268 'link': path + id |
