Пример #1
0
    def test_get_pdf_token_allowed(self):
        """You don't need to be logged in at all, if your token is right."""
        (other, teammate, contact, captain, super_admin, team, classroom,
         report_dict) = self.test_post_team_pdf()

        # Put in a classroom report for the same team so we know we can
        # correctly select the team-level one.
        classReport = Report.create(
            team_id=team.uid,
            classroom_id=classroom.uid,
            filename='classroom.pdf',
            gcs_path='/mybucket/upload/classroom.pdf',
            size=1000000,
            content_type='application/pdf',
        )
        classReport.put()

        path = '/api/teams/{team_id}/reports/{filename}'.format(
            team_id=team.uid,
            filename=report_dict['filename'],
        )
        endpoint_str = util.get_endpoint_str(method='GET', path=path)
        jwt = jwt_helper.encode({'allowed_endpoints': [endpoint_str]}),
        url = util.set_query_parameters(path, token=jwt)

        response = self.testapp.get(url)  # asserts 200

        self.assert_pdf_response(report_dict, response)
    def test_delete_code_allowed(self):
        code = 'trout viper'
        path = '/api/codes/{}'.format(code.replace(' ', '-'))
        pc = ProjectCohort.create(
            code=code,
            organization_id='triton',
            program_label='triton',
        )
        pc.put()
        pc.key.get()  # simulate consistency, code fetches are eventual
        token = jwt_helper.encode({
            'user_id': 'User_foo',
            'email': '*****@*****.**',
            'allowed_endpoints': ['DELETE //neptune{}'.format(path)],
        })
        self.testapp.delete(
            path,
            headers={'Authorization': 'Bearer ' + token},
            status=204,
        )

        # Project cohort AND Unique should be gone
        self.assertIsNone(pc.key.get())
        unique_key = ndb.Key('Unique', ProjectCohort.uniqueness_key(code))
        self.assertIsNone(unique_key.get())
 def test_precheck_jwt_expired(self):
     payload = {'user_id': 'User_foo', 'email': '*****@*****.**'}
     token = jwt_helper.encode(payload, expiration_minutes=-1)
     response = self.testapp.get(
         '/api/auth_tokens/{}/user'.format(token),
         status=410,
     )
     self.assertEqual(json.loads(response.body), 'expired')
Пример #4
0
def signup(request):
    """
    token content:
        - email (username)
        - username (display name | firstname in Django)
        - password
        - remember
        - expire
    """
    status = False
    msg = ''
    token = ''

    if request.method != 'POST':
        return HttpResponse(status=403)
    email = request.POST.get('email', None)
    password = request.POST.get('password', None)
    username = request.POST.get('username', None)
    expire = calendar.timegm(datetime.utcnow().utctimetuple()) + 2629743
    if None in (email, password, username):
        return HttpResponse(status=404)
    
    # validate
    if not re.match(r"[^@]+@[^@]+\.[^@]+", email):
        msg = 'Email not valid'
    elif len(username) < 2:
        msg = 'Username too short'
    elif len(password) < 4:
        msg = 'Password too short'
    else:
        # get the user
        try:
            user = User.objects.create_user(
                username=email,
                password=password,
                first_name=username
            )
            status = True
        except:
            user = None
            msg = 'User already exists'

        # check pswd
        if user:
            stuff = {
                'email': email,
                'expire': expire,
            }
            token = jwt_helper.encode(stuff)

    res = {
        'status': status,
        'msg': msg,
        'token': token,
        'email': email,
        'username': username,
    }
    return JsonResponse(res, safe=False)
 def test_delete_code_forbidden(self):
     """Requires 'allowed_endpoints' in jwt."""
     token = jwt_helper.encode({'user_id': 'User_foo',
                                'email': '*****@*****.**'})
     self.testapp.delete(
         '/api/codes/trout-viper',
         headers={'Authorization': 'Bearer ' + token},
         status=403,
     )
Пример #6
0
def signup(request):
    """
    token content:
        - email (username)
        - username (display name | firstname in Django)
        - password
        - remember
        - expire
    """
    status = False
    msg = ''
    token = ''

    if request.method != 'POST':
        return HttpResponse(status=403)
    email = request.POST.get('email', None)
    password = request.POST.get('password', None)
    username = request.POST.get('username', None)
    expire = calendar.timegm(datetime.utcnow().utctimetuple()) + 2629743
    if None in (email, password, username):
        return HttpResponse(status=404)

    # validate
    if not re.match(r"[^@]+@[^@]+\.[^@]+", email):
        msg = 'Email not valid'
    elif len(username) < 2:
        msg = 'Username too short'
    elif len(password) < 4:
        msg = 'Password too short'
    else:
        # get the user
        try:
            user = User.objects.create_user(username=email,
                                            password=password,
                                            first_name=username)
            status = True
        except:
            user = None
            msg = 'User already exists'

        # check pswd
        if user:
            stuff = {
                'email': email,
                'expire': expire,
            }
            token = jwt_helper.encode(stuff)

    res = {
        'status': status,
        'msg': msg,
        'token': token,
        'email': email,
        'username': username,
    }
    return JsonResponse(res, safe=False)
Пример #7
0
    def batch_participation(self, user, pcs):
        # Successful with allowed endpoints for individual project cohorts
        # (even if the paths are different). Can use either uid or code.
        start = datetime.date.today()
        end = start + datetime.timedelta(days=1)
        for attr in ('uid', 'code'):
            ids = [getattr(pc, attr).replace(' ', '-') for pc in pcs]
            paths = [
                '/api/project_cohorts/{}/participation'.format(id)
                for id in ids
            ]

            payload = {
                'user_id':
                user.uid,
                'email':
                user.email,
                'allowed_endpoints':
                [get_endpoint_str('GET', 'neptune', p) for p in paths],
            }

            url = ('/api/project_cohorts/participation?'
                   'uid={}&uid={}&start={start}&end={end}'.format(
                       *ids,
                       start=start.strftime(config.iso_datetime_format),
                       end=end.strftime(config.iso_datetime_format)))

            result = self.testapp.get(
                url,
                headers={
                    'Authorization': 'Bearer ' + jwt_helper.encode(payload),
                },
            )
            expected = {
                getattr(pc, attr).replace(' ', '-'): [
                    {
                        'project_cohort_id': pc.uid,
                        'survey_ordinal': 1,
                        'n': 1,
                        'value': '1',
                        'code': pc.code
                    },
                    {
                        'project_cohort_id': pc.uid,
                        'survey_ordinal': 1,
                        'n': 1,
                        'value': '100',
                        'code': pc.code
                    },
                ]
                for pc in pcs
            }

            self.assertEqual(json.loads(result.body), expected)
 def test_bad_token(self):
     """Invalid token: decoding error b/c typo or bad secret."""
     payload = {'user_id': 'User_foo', 'email': '*****@*****.**'}
     token = jwt_helper.encode(payload, expiration_minutes=-1)
     response = self.testapp.post_json(
         '/api/set_password',
         {'password': '******'},
         headers={'Authorization': 'Bearer ' + token[:-1]},
         status=401,
     )
     self.assertEqual(json.loads(response.body), 'not found')
Пример #9
0
def login(request):
    """
    token content:
        - email (username)
        - username (display name | firstname in Django)
        - password
        - remember
        - expire
    """
    status = False
    msg = ''
    token = ''
    e = ''
    name = ''

    if request.method != 'POST':
        return HttpResponse(status=403)
    email = request.POST.get('email', None)
    password = request.POST.get('password', None)
    expire = calendar.timegm(datetime.utcnow().utctimetuple()) + 2629743
    if None in (email, password):
        return HttpResponse(status=404)

    # get the user
    try:
        user = User.objects.get(username=email)
        e = user.username
        name = user.first_name
    except:
        user = None
        msg = 'User not exists'

    # check pswd
    if user:
        if user.check_password(password):
            status = True
            stuff = {
                'email': email,
                'expire': expire,
            }
            token = jwt_helper.encode(stuff)
        else:
            msg = 'Incorrect password'

    res = {
        'status': status,
        'msg': msg,
        'token': token,
        'email': e,
        'username': name,
    }
    return JsonResponse(res, safe=False)
Пример #10
0
def login(request):
    """
    token content:
        - email (username)
        - username (display name | firstname in Django)
        - password
        - remember
        - expire
    """
    status = False
    msg = ''
    token = ''
    e = ''
    name = ''

    if request.method != 'POST':
        return HttpResponse(status=403)
    email = request.POST.get('email', None)
    password = request.POST.get('password', None)
    expire = calendar.timegm(datetime.utcnow().utctimetuple()) + 2629743
    if None in (email, password):
        return HttpResponse(status=404)

    # get the user
    try:
        user = User.objects.get(username=email)
        e = user.username
        name = user.first_name
    except:
        user = None
        msg = 'User not exists'

    # check pswd
    if user:
        if user.check_password(password):
            status = True
            stuff = {
                'email': email,
                'expire': expire,
            }
            token = jwt_helper.encode(stuff)
        else:
            msg = 'Incorrect password'

    res = {
        'status': status,
        'msg': msg,
        'token': token,
        'email': e,
        'username': name,
    }
    return JsonResponse(res, safe=False)
    def test_patch_bad_method(self):
        """Can only package PUT and DELETE with a bulk PATCH."""
        codes = ('trout viper', 'solid snake')

        token = jwt_helper.encode({
            'user_id': 'User_foo',
            'email': '*****@*****.**',
            'allowed_endpoints': ['POST //neptune{}'.format(path(c))
                                  for c in codes],
        })

        self.testapp.patch_json(
            '/api/codes',  # doesn't match "/api/other"
            [{'method': 'POST', 'path': path(c)} for c in codes],
            headers={'Authorization': 'Bearer ' + token},
            status=400,
        )
Пример #12
0
    def test_get_pdf_bad_token_forbidden(self):
        (other, teammate, contact, captain, super_admin, team, classroom,
         classReport1, classReport2, teamReport) = self.create_reports()

        # Not any old jwt will do. For instance, the typical auth jwt doesn't
        # work as a token.
        path = '/api/classrooms/{}/reports/foo.pdf?token={}'.format(
            classReport1.uid,
            jwt_helper.encode({
                'user_id': contact.uid,
                'email': contact.email
            }))
        self.testapp.get(
            path,
            headers=self.login_headers(contact),
            status=403,
        )
    def test_patch_update_codes(self):
        codes = ('trout viper', 'solid snake')
        pcs = []
        for c in codes:
            pcs.append(ProjectCohort.create(
                code=c,
                organization_id='triton',
                program_label='triton',
            ))
        ndb.put_multi(pcs)
        for pc in pcs:
            pc.key.get()  # simulate consistency, code fetches are eventual

        token = jwt_helper.encode({
            'user_id': 'User_foo',
            'email': '*****@*****.**',
            'allowed_endpoints': ['PUT //neptune{}'.format(path(c))
                                  for c in codes],
        })

        body = {'portal_message': 'hi'}
        response = self.testapp.patch_json(
            '/api/codes',
            [{'method': 'PUT', 'path': path(c), 'body': body} for c in codes],
            headers={'Authorization': 'Bearer ' + token},
        )
        task_names = [t['task_name'] for t in json.loads(response.body)]

        # PATCHing two codes should result in two tasks.
        for name in task_names:
            tasks = self.taskqueue.get_filtered_tasks(name=name)
            self.assertEqual(len(tasks), 1)
            t = tasks[0]

            # Running the tasks should update the codes.
            self.assertEqual(t.method, 'PUT')
            self.testapp.put_json(
                t.url,
                json.loads(t.payload),
                headers=t.headers,
            )

        for pc in pcs:
            fetched = pc.key.get()
            self.assertEqual(fetched.portal_message, 'hi')
    def test_new_success(self):
        """Valid token and password, user is new."""
        # User.create() actually hits the db with a Unique entity, so we can't
        # use that to make a user.
        payload = {'user_id': 'User_foo', 'email': '*****@*****.**'}
        token = jwt_helper.encode(payload)

        response = self.testapp.post_json(
            '/api/set_password', {'password': '******'},
            headers={'Authorization': 'Bearer ' + token})
        user_dict = json.loads(response.body)
        self.assertEqual(type(user_dict), dict)
        self.assertEqual(user_dict['uid'], payload['user_id'])

        # should now be in the db
        self.assertIsNotNone(User.get_by_id(payload['user_id']))

        return token
Пример #15
0
    def report_link(self, report):
        parent_kind = SqlModel.get_url_kind(report.parent_id)
        short_id = SqlModel.convert_uid(report.parent_id)

        if report.gcs_path:
            platform = 'triton'
            prefix = ''
            view_path = '/api/{parent_kind}/{id}/reports/{filename}'.format(
                parent_kind=parent_kind,
                id=short_id,
                filename=report.filename,
            )
        elif report.dataset_id:
            platform = 'neptune'
            prefix = '{protocol}://{domain}'.format(
                protocol='http' if util.is_localhost() else 'https',
                domain=('localhost:8888' if util.is_localhost() else
                        os.environ['NEPTUNE_DOMAIN']),
            )
            view_path = '/datasets/{ds_id}/{template}/{filename}'.format(
                ds_id=SqlModel.convert_uid(report.dataset_id),  # short form
                template=report.template,
                filename=report.filename,
            )

        # Permit report clients to query some data about participation.
        parent_path = '/api/{parent_kind}/{id}'.format(parent_kind=parent_kind,
                                                       id=short_id)
        data_path = '/api/{parent_kind}/{id}/report_data'.format(
            parent_kind=parent_kind, id=short_id)

        link_jwt = jwt_helper.encode(
            {
                'allowed_endpoints': [
                    self.get_endpoint_str(platform=platform, path=view_path),
                    self.get_endpoint_str(platform='triton', path=parent_path),
                    self.get_endpoint_str(platform='triton', path=data_path),
                ]
            },
            expiration_minutes=(30 * 24 * 60),  # thirty days
        )

        return util.set_query_parameters(prefix + view_path, token=link_jwt)
    def test_patch_bad_scope(self):
        """You can't request calls from some different scope/collection."""
        codes = ('trout viper', 'solid snake')

        # These paths are for the "other" collection, not "codes".
        path = lambda code: '/api/other/{}'.format(code.replace(' ', '-'))

        token = jwt_helper.encode({
            'user_id': 'User_foo',
            'email': '*****@*****.**',
            'allowed_endpoints': ['DELETE //neptune{}'.format(path(c))
                                  for c in codes],
        })

        self.testapp.patch_json(
            '/api/codes',  # doesn't match "/api/other"
            [{'method': 'DELETE', 'path': path(c)} for c in codes],
            headers={'Authorization': 'Bearer ' + token},
            status=400,
        )
 def test_update_code_allowed(self):
     code = 'trout viper'
     path = '/api/codes/{}'.format(code.replace(' ', '-'))
     pc = ProjectCohort.create(
         code=code,
         organization_id='triton',
         program_label='triton',
     )
     pc.put()
     pc.key.get()  # simulate consistency, code fetches are eventual
     token = jwt_helper.encode({
         'user_id': 'User_foo',
         'email': '*****@*****.**',
         'allowed_endpoints': ['PUT //neptune{}'.format(path)],
     })
     self.testapp.put_json(
         path,
         {'portal_message': 'hi'},
         headers={'Authorization': 'Bearer ' + token}
     )
Пример #18
0
def get_participation(cycle, classrooms):
    handler = TeamsClassrooms()
    user = User.create(id='triton', email='')

    payload = jwt_helper.get_payload(user)
    payload['allowed_endpoints'] = [
        BaseHandler().get_endpoint_str(
            'GET', 'neptune',
            '/api/project_cohorts/{}/participation'.format(c.url_code))
        for c in classrooms
    ]
    jwt = jwt_helper.encode(payload)

    result = urlfetch.fetch(url=participation_query_url(cycle, classrooms),
                            method=urlfetch.GET,
                            headers={'Authorization': 'Bearer {}'.format(jwt)})

    if not result or result.status_code != 200:
        raise Exception("Failed to get participation {}".format(result))

    return json.loads(result.content)
Пример #19
0
 def login_headers(self, user):
     payload = {'user_id': user.uid, 'email': user.email}
     return {'Authorization': 'Bearer ' + jwt_helper.encode(payload)}