def _validate_tba_auth_key(self):
        """
        Tests the presence of a X-TBA-Auth-Key header or URL param.
        """
        x_tba_auth_key = self.request.headers.get("X-TBA-Auth-Key")
        if x_tba_auth_key is None:
            x_tba_auth_key = self.request.get('X-TBA-Auth-Key')

        self.auth_owner = None
        self.auth_owner_key = None
        self.auth_description = None
        if not x_tba_auth_key:
            account = self._user_bundle.account
            if account:
                self.auth_owner = account.key.id()
                self.auth_owner_key = account.key
            elif 'thebluealliance.com' in self.request.headers.get("Origin", ""):
                self.auth_owner = 'The Blue Alliance'
            else:
                self._errors = json.dumps({"Error": "X-TBA-Auth-Key is a required header or URL param. Please get an access key at http://www.thebluealliance.com/account."})
                self.abort(401)

        if self.auth_owner:
            logging.info("Auth owner: {}, LOGGED IN".format(self.auth_owner))
        else:
            auth = ApiAuthAccess.get_by_id(x_tba_auth_key)
            if auth and auth.is_read_key:
                self.auth_owner = auth.owner.id()
                self.auth_owner_key = auth.owner
                self.auth_description = auth.description
                logging.info("Auth owner: {}, X-TBA-Auth-Key: {}".format(self.auth_owner, x_tba_auth_key))
            else:
                self._errors = json.dumps({"Error": "X-TBA-Auth-Key is invalid. Please get an access key at http://www.thebluealliance.com/account."})
                self.abort(401)
Beispiel #2
0
    def post(self, event_key):
        event_key = event_key.lower(
        )  # Normalize keys to lower case (TBA convention)

        # Start by allowing admins to edit any event
        user_has_auth = (self._user_bundle.user
                         and self._user_bundle.is_current_user_admin)

        if not user_has_auth and self._user_bundle.user:
            # See if this user has any auth keys granted to its account
            now = datetime.datetime.now()
            auth_tokens = ApiAuthAccess.query(
                ApiAuthAccess.owner == self._user_bundle.account.key,
                ApiAuthAccess.event_list == ndb.Key(Event, event_key),
                ndb.OR(ApiAuthAccess.expiration == None,
                       ApiAuthAccess.expiration >= now)).fetch()
            user_has_auth = any(
                self._validate_auth(auth, event_key) is None
                for auth in auth_tokens)

        if not user_has_auth:
            # If not, check if auth id/secret were passed as headers
            auth_id = self.request.headers.get('X-TBA-Auth-Id')
            if not auth_id:
                self._errors = json.dumps({
                    "Error":
                    "Must provide a request header parameter 'X-TBA-Auth-Id'"
                })
                self.abort(400)

            auth_sig = self.request.headers.get('X-TBA-Auth-Sig')
            if not auth_sig:
                self._errors = json.dumps({
                    "Error":
                    "Must provide a request header parameter 'X-TBA-Auth-Sig'"
                })
                self.abort(400)

            auth = ApiAuthAccess.get_by_id(auth_id)
            expected_sig = md5.new('{}{}{}'.format(
                auth.secret if auth else None, self.request.path,
                self.request.body)).hexdigest()
            if not auth or expected_sig != auth_sig:
                logging.info("Auth sig: {}, Expected sig: {}".format(
                    auth_sig, expected_sig))
                self._errors = json.dumps(
                    {"Error": "Invalid X-TBA-Auth-Id and/or X-TBA-Auth-Sig!"})
                self.abort(401)

            # Checks event key is valid, correct auth types, and expiration
            error = self._validate_auth(auth, event_key)
            if error:
                self._errors = json.dumps({"Error": error})
                self.abort(401)

        try:
            self._process_request(self.request, event_key)
        except ParserInputException, e:
            self._errors = json.dumps({"Error": e.message})
            self.abort(400)
    def post(self, event_key):
        auth_id = self.request.headers.get('X-TBA-Auth-Id')
        if not auth_id:
            self._errors = json.dumps({"Error": "Must provide a request header parameter 'X-TBA-Auth-Id'"})
            self.abort(400)

        auth_sig = self.request.headers.get('X-TBA-Auth-Sig')
        if not auth_sig:
            self._errors = json.dumps({"Error": "Must provide a request header parameter 'X-TBA-Auth-Sig'"})
            self.abort(400)

        auth = ApiAuthAccess.get_by_id(auth_id)
        if not auth or md5.new('{}{}{}'.format(auth.secret, self.request.path, self.request.body)).hexdigest() != auth_sig:
            self._errors = json.dumps({"Error": "Invalid X-TBA-Auth-Id and/or X-TBA-Auth-Sig!"})
            self.abort(400)

        allowed_event_keys = [ekey.id() for ekey in auth.event_list]
        if event_key not in allowed_event_keys:
            self._errors = json.dumps({"Error": "Only allowed to edit events: {}".format(', '.join(allowed_event_keys))})
            self.abort(400)

        try:
            self._process_request(self.request, event_key)
        except ParserInputException, e:
            self._errors = json.dumps({"Error": e.message})
            self.abort(400)
    def post(self, auth_id):
        self._require_admin()

        auth = ApiAuthAccess.get_by_id(auth_id)

        auth_types_enum = []
        if self.request.get('allow_edit_teams'):
            auth_types_enum.append(AuthType.EVENT_TEAMS)
        if self.request.get('allow_edit_matches'):
            auth_types_enum.append(AuthType.EVENT_MATCHES)
        if self.request.get('allow_edit_rankings'):
            auth_types_enum.append(AuthType.EVENT_RANKINGS)
        if self.request.get('allow_edit_alliances'):
            auth_types_enum.append(AuthType.EVENT_ALLIANCES)
        if self.request.get('allow_edit_awards'):
            auth_types_enum.append(AuthType.EVENT_AWARDS)
        if self.request.get('allow_edit_match_video'):
            auth_types_enum.append(AuthType.MATCH_VIDEO)

        if not auth:
            auth = ApiAuthAccess(
                id=auth_id,
                description=self.request.get('description'),
                secret=''.join(random.choice(string.ascii_lowercase + string.ascii_uppercase + string.digits) for _ in range(64)),
                event_list=[ndb.Key(Event, event_key.strip()) for event_key in self.request.get('event_list_str').split(',')],
                auth_types_enum=auth_types_enum,
            )
        else:
            auth.description = self.request.get('description')
            auth.event_list = event_list=[ndb.Key(Event, event_key.strip()) for event_key in self.request.get('event_list_str').split(',')]
            auth.auth_types_enum = auth_types_enum

        auth.put()

        self.redirect("/admin/api_auth/manage")
Beispiel #5
0
    def post(self, event_key):
        auth_id = self.request.headers.get('X-TBA-Auth-Id')
        if not auth_id:
            self._errors = json.dumps({"Error": "Must provide a request header parameter 'X-TBA-Auth-Id'"})
            self.abort(400)

        auth_sig = self.request.headers.get('X-TBA-Auth-Sig')
        if not auth_sig:
            self._errors = json.dumps({"Error": "Must provide a request header parameter 'X-TBA-Auth-Sig'"})
            self.abort(400)

        auth = ApiAuthAccess.get_by_id(auth_id)
        expected_sig = md5.new('{}{}{}'.format(auth.secret if auth else None, self.request.path, self.request.body)).hexdigest()
        if not auth or expected_sig != auth_sig:
            logging.info("Auth sig: {}, Expected sig: {}".format(auth_sig, expected_sig))
            self._errors = json.dumps({"Error": "Invalid X-TBA-Auth-Id and/or X-TBA-Auth-Sig!"})
            self.abort(400)

        allowed_event_keys = [ekey.id() for ekey in auth.event_list]
        if event_key not in allowed_event_keys:
            self._errors = json.dumps({"Error": "Only allowed to edit events: {}".format(', '.join(allowed_event_keys))})
            self.abort(400)

        missing_auths = self.REQUIRED_AUTH_TYPES.difference(set(auth.auth_types_enum))
        if missing_auths != set():
            self._errors = json.dumps({"Error": "You do not have permission to edit: {}. If this is incorrect, please contact TBA admin.".format(",".join([AuthType.type_names[ma] for ma in missing_auths]))})
            self.abort(400)

        try:
            self._process_request(self.request, event_key)
        except ParserInputException, e:
            self._errors = json.dumps({"Error": e.message})
            self.abort(400)
    def post(self, event_key):
        auth_id = self.request.headers.get('X-TBA-Auth-Id')
        if not auth_id:
            self._errors = json.dumps({"Error": "Must provide a request header parameter 'X-TBA-Auth-Id'"})
            self.abort(400)

        auth_sig = self.request.headers.get('X-TBA-Auth-Sig')
        if not auth_sig:
            self._errors = json.dumps({"Error": "Must provide a request header parameter 'X-TBA-Auth-Sig'"})
            self.abort(400)

        auth = ApiAuthAccess.get_by_id(auth_id)
        if not auth or md5.new('{}{}{}'.format(auth.secret, self.request.path, self.request.body)).hexdigest() != auth_sig:
            self._errors = json.dumps({"Error": "Invalid X-TBA-Auth-Id and/or X-TBA-Auth-Sig!"})
            self.abort(400)

        allowed_event_keys = [ekey.id() for ekey in auth.event_list]
        if event_key not in allowed_event_keys:
            self._errors = json.dumps({"Error": "Only allowed to edit events: {}".format(', '.join(allowed_event_keys))})
            self.abort(400)

        missing_auths = self.REQUIRED_AUTH_TYPES.difference(set(auth.auth_types_enum))
        if missing_auths != set():
            self._errors = json.dumps({"Error": "You do not have permission to edit: {}. If this is incorrect, please contact TBA admin.".format(",".join([AuthType.type_names[ma] for ma in missing_auths]))})
            self.abort(400)

        try:
            self._process_request(self.request, event_key)
        except ParserInputException, e:
            self._errors = json.dumps({"Error": e.message})
            self.abort(400)
Beispiel #7
0
    def get(self, auth_id):
        self._require_admin()

        auth = ApiAuthAccess.get_by_id(auth_id)

        self.template_values.update({"auth": auth})

        path = os.path.join(os.path.dirname(__file__),
                            '../../templates/admin/api_delete_auth.html')
        self.response.out.write(template.render(path, self.template_values))
Beispiel #8
0
    def post(self):
        self._require_registration()

        key_id = self.request.get('key_id')
        auth = ApiAuthAccess.get_by_id(key_id)

        if auth and auth.owner == self.user_bundle.account.key:
            auth.key.delete()
            self.redirect('/account?status=read_key_delete_success')
        else:
            self.redirect('/account?status=read_key_delete_failure')
    def get(self, auth_id):
        self._require_admin()

        auth = ApiAuthAccess.get_by_id(auth_id)

        self.template_values.update({
            "auth": auth
        })

        path = os.path.join(os.path.dirname(__file__), '../../templates/admin/api_delete_auth.html')
        self.response.out.write(template.render(path, self.template_values))
Beispiel #10
0
    def post(self, auth_id):
        self._require_admin()

        logging.warning("Deleting auth: %s at the request of %s / %s" %
                        (auth_id, self.user_bundle.user.user_id(),
                         self.user_bundle.user.email()))

        auth = ApiAuthAccess.get_by_id(auth_id)
        auth.key.delete()

        self.redirect("/admin/api_auth/manage")
    def get(self, auth_id):
        self._require_admin()

        auth = ApiAuthAccess.get_by_id(auth_id)
        auth.event_list_str = ','.join([event_key.id() for event_key in auth.event_list])

        self.template_values.update({
            "auth": auth,
        })

        path = os.path.join(os.path.dirname(__file__), '../../templates/admin/api_edit_auth.html')
        self.response.out.write(template.render(path, self.template_values))
    def post(self, auth_id):
        self._require_admin()

        logging.warning("Deleting auth: %s at the request of %s / %s" % (
            auth_id,
            self.user_bundle.user.user_id(),
            self.user_bundle.user.email()))

        auth = ApiAuthAccess.get_by_id(auth_id)
        auth.key.delete()

        self.redirect("/admin/api_auth/manage")
    def _validate_tba_auth_key(self):
        """
        Tests the presence of a X-TBA-Auth-Key header or URL param.
        """
        with TraceContext() as root:
            with root.span("ApiBaseController._validate_tba_auth_key"):
                x_tba_auth_key = self.request.headers.get("X-TBA-Auth-Key")
                if x_tba_auth_key is None:
                    x_tba_auth_key = self.request.get('X-TBA-Auth-Key')

                self.auth_owner = None
                self.auth_owner_key = None
                self.auth_description = None
                if not x_tba_auth_key:
                    account = self._user_bundle.account
                    if account:
                        self.auth_owner = account.key.id()
                        self.auth_owner_key = account.key
                    elif 'thebluealliance.com' in self.request.headers.get(
                            "Origin", ""):
                        self.auth_owner = 'The Blue Alliance'
                    else:
                        self._errors = {
                            "Error":
                            "X-TBA-Auth-Key is a required header or URL param. Please get an access key at http://www.thebluealliance.com/account."
                        }
                        self.abort(401)

                if self.auth_owner:
                    logging.info("Auth owner: {}, LOGGED IN".format(
                        self.auth_owner))
                else:
                    auth = ApiAuthAccess.get_by_id(x_tba_auth_key)
                    if auth and auth.is_read_key:
                        self.auth_owner = auth.owner.id()
                        self.auth_owner_key = auth.owner
                        self.auth_description = auth.description
                        if self.REQUIRE_ADMIN_AUTH and not auth.allow_admin:
                            self._errors = {
                                "Error":
                                "X-TBA-Auth-Key does not have required permissions"
                            }
                            self.abort(401)
                        logging.info(
                            "Auth owner: {}, X-TBA-Auth-Key: {}".format(
                                self.auth_owner, x_tba_auth_key))
                    else:
                        self._errors = {
                            "Error":
                            "X-TBA-Auth-Key is invalid. Please get an access key at http://www.thebluealliance.com/account."
                        }
                        self.abort(401)
    def post(self, auth_id):
        self._require_admin()

        auth = ApiAuthAccess.get_by_id(auth_id)

        auth_types_enum = []
        if self.request.get('allow_edit_teams'):
            auth_types_enum.append(AuthType.EVENT_TEAMS)
        if self.request.get('allow_edit_matches'):
            auth_types_enum.append(AuthType.EVENT_MATCHES)
        if self.request.get('allow_edit_rankings'):
            auth_types_enum.append(AuthType.EVENT_RANKINGS)
        if self.request.get('allow_edit_alliances'):
            auth_types_enum.append(AuthType.EVENT_ALLIANCES)
        if self.request.get('allow_edit_awards'):
            auth_types_enum.append(AuthType.EVENT_AWARDS)
        if self.request.get('allow_edit_match_video'):
            auth_types_enum.append(AuthType.MATCH_VIDEO)

        if self.request.get('owner', None):
            owner = Account.query(Account.email == self.request.get('owner')).fetch()
            owner_key = owner[0].key if owner else None
        else:
            owner_key = None

        if self.request.get('expiration', None):
            expiration = datetime.strptime(self.request.get('expiration'), '%Y-%m-%d')
        else:
            expiration = None

        if not auth:
            auth = ApiAuthAccess(
                id=auth_id,
                description=self.request.get('description'),
                owner=owner_key,
                expiration=expiration,
                secret=''.join(random.choice(string.ascii_lowercase + string.ascii_uppercase + string.digits) for _ in range(64)),
                event_list=[ndb.Key(Event, event_key.strip()) for event_key in self.request.get('event_list_str').split(',')],
                auth_types_enum=auth_types_enum,
            )
        else:
            auth.description = self.request.get('description')
            auth.event_list = event_list=[ndb.Key(Event, event_key.strip()) for event_key in self.request.get('event_list_str').split(',')]
            auth.auth_types_enum = auth_types_enum
            auth.owner = owner_key
            auth.expiration = expiration

        auth.put()

        self.redirect("/admin/api_auth/manage")
Beispiel #15
0
    def get(self, auth_id):
        self._require_admin()

        auth = ApiAuthAccess.get_by_id(auth_id)
        auth.event_list_str = ','.join(
            [event_key.id() for event_key in auth.event_list])

        self.template_values.update({
            "auth": auth,
        })

        path = os.path.join(os.path.dirname(__file__),
                            '../../templates/admin/api_edit_auth.html')
        self.response.out.write(template.render(path, self.template_values))
    def post(self, event_key):
        event_key = event_key.lower()  # Normalize keys to lower case (TBA convention)

        # Start by allowing admins to edit any event
        user_has_auth = self._user_bundle.user and self._user_bundle.is_current_user_admin

        if not user_has_auth and self._user_bundle.user:
            # See if this user has any auth keys granted to its account
            now = datetime.datetime.now()
            auth_tokens = ApiAuthAccess.query(
                ApiAuthAccess.owner == self._user_bundle.account.key,
                ApiAuthAccess.event_list == ndb.Key(Event, event_key),
                ndb.OR(ApiAuthAccess.expiration == None, ApiAuthAccess.expiration >= now),
            ).fetch()
            user_has_auth = any(self._validate_auth(auth, event_key) is None for auth in auth_tokens)

        if not user_has_auth:
            # If not, check if auth id/secret were passed as headers
            auth_id = self.request.headers.get("X-TBA-Auth-Id")
            if not auth_id:
                self._errors = json.dumps({"Error": "Must provide a request header parameter 'X-TBA-Auth-Id'"})
                self.abort(400)

            auth_sig = self.request.headers.get("X-TBA-Auth-Sig")
            if not auth_sig:
                self._errors = json.dumps({"Error": "Must provide a request header parameter 'X-TBA-Auth-Sig'"})
                self.abort(400)

            auth = ApiAuthAccess.get_by_id(auth_id)
            expected_sig = md5.new(
                "{}{}{}".format(auth.secret if auth else None, self.request.path, self.request.body)
            ).hexdigest()
            if not auth or expected_sig != auth_sig:
                logging.info("Auth sig: {}, Expected sig: {}".format(auth_sig, expected_sig))
                self._errors = json.dumps({"Error": "Invalid X-TBA-Auth-Id and/or X-TBA-Auth-Sig!"})
                self.abort(401)

            # Checks event key is valid, correct auth types, and expiration
            error = self._validate_auth(auth, event_key)
            if error:
                self._errors = json.dumps({"Error": error})
                self.abort(401)

        try:
            self._process_request(self.request, event_key)
        except ParserInputException, e:
            self._errors = json.dumps({"Error": e.message})
            self.abort(400)
    def post(self, auth_id):
        self._require_admin()

        auth = ApiAuthAccess.get_by_id(auth_id)
        if not auth:
            auth = ApiAuthAccess(
                id=auth_id,
                description=self.request.get('description'),
                secret=''.join(random.choice(string.ascii_lowercase + string.ascii_uppercase + string.digits) for _ in range(64)),
                event_list=[ndb.Key(Event, event_key.strip()) for event_key in self.request.get('event_list_str').split(',')],
            )
        else:
            auth.description = self.request.get('description')
            auth.event_list = event_list=[ndb.Key(Event, event_key.strip()) for event_key in self.request.get('event_list_str').split(',')]

        auth.put()

        self.redirect("/admin/api_auth/manage")
Beispiel #18
0
    def post(self, auth_id):
        self._require_admin()

        auth = ApiAuthAccess.get_by_id(auth_id)

        auth_types_enum = []
        if self.request.get('allow_edit_teams'):
            auth_types_enum.append(AuthType.EVENT_TEAMS)
        if self.request.get('allow_edit_matches'):
            auth_types_enum.append(AuthType.EVENT_MATCHES)
        if self.request.get('allow_edit_rankings'):
            auth_types_enum.append(AuthType.EVENT_RANKINGS)
        if self.request.get('allow_edit_alliances'):
            auth_types_enum.append(AuthType.EVENT_ALLIANCES)
        if self.request.get('allow_edit_awards'):
            auth_types_enum.append(AuthType.EVENT_AWARDS)
        if self.request.get('allow_edit_match_video'):
            auth_types_enum.append(AuthType.MATCH_VIDEO)

        if not auth:
            auth = ApiAuthAccess(
                id=auth_id,
                description=self.request.get('description'),
                secret=''.join(
                    random.choice(string.ascii_lowercase +
                                  string.ascii_uppercase + string.digits)
                    for _ in range(64)),
                event_list=[
                    ndb.Key(Event, event_key.strip()) for event_key in
                    self.request.get('event_list_str').split(',')
                ],
                auth_types_enum=auth_types_enum,
            )
        else:
            auth.description = self.request.get('description')
            auth.event_list = event_list = [
                ndb.Key(Event, event_key.strip())
                for event_key in self.request.get('event_list_str').split(',')
            ]
            auth.auth_types_enum = auth_types_enum

        auth.put()

        self.redirect("/admin/api_auth/manage")
Beispiel #19
0
    def _validate_tba_auth_key(self):
        """
        Tests the presence of a X-TBA-Auth-Key header or URL param.
        """
        x_tba_auth_key = self.request.headers.get("X-TBA-Auth-Key")
        if x_tba_auth_key is None:
            x_tba_auth_key = self.request.get('X-TBA-Auth-Key')

        self.auth_owner = None
        self.auth_owner_key = None
        self.auth_description = None
        if not x_tba_auth_key:
            account = self._user_bundle.account
            if account:
                self.auth_owner = account.key.id()
                self.auth_owner_key = account.key
            elif 'thebluealliance.com' in self.request.headers.get(
                    "Origin", ""):
                self.auth_owner = 'The Blue Alliance'
            else:
                self._errors = json.dumps({
                    "Error":
                    "X-TBA-Auth-Key is a required header or URL param. Please get an access key at http://www.thebluealliance.com/account."
                })
                self.abort(401)

        if self.auth_owner:
            logging.info("Auth owner: {}, LOGGED IN".format(self.auth_owner))
        else:
            auth = ApiAuthAccess.get_by_id(x_tba_auth_key)
            if auth and auth.is_read_key:
                self.auth_owner = auth.owner.id()
                self.auth_owner_key = auth.owner
                self.auth_description = auth.description
                logging.info("Auth owner: {}, X-TBA-Auth-Key: {}".format(
                    self.auth_owner, x_tba_auth_key))
            else:
                self._errors = json.dumps({
                    "Error":
                    "X-TBA-Auth-Key is invalid. Please get an access key at http://www.thebluealliance.com/account."
                })
                self.abort(401)
    def _validate_tba_auth_key(self):
        """
        Tests the presence of a X-TBA-Auth-Key header or URL param.
        """
        with TraceContext() as root:
            with root.span("ApiBaseController._validate_tba_auth_key"):
                x_tba_auth_key = self.request.headers.get("X-TBA-Auth-Key")
                if x_tba_auth_key is None:
                    x_tba_auth_key = self.request.get('X-TBA-Auth-Key')

                self.auth_owner = None
                self.auth_owner_key = None
                self.auth_description = None
                if not x_tba_auth_key:
                    account = self._user_bundle.account
                    if account:
                        self.auth_owner = account.key.id()
                        self.auth_owner_key = account.key
                    elif 'thebluealliance.com' in self.request.headers.get("Origin", ""):
                        self.auth_owner = 'The Blue Alliance'
                    else:
                        self._errors = {"Error": "X-TBA-Auth-Key is a required header or URL param. Please get an access key at http://www.thebluealliance.com/account."}
                        self.abort(401)

                if self.auth_owner:
                    logging.info("Auth owner: {}, LOGGED IN".format(self.auth_owner))
                else:
                    auth = ApiAuthAccess.get_by_id(x_tba_auth_key)
                    if auth and auth.is_read_key:
                        self.auth_owner = auth.owner.id()
                        self.auth_owner_key = auth.owner
                        self.auth_description = auth.description
                        if self.REQUIRE_ADMIN_AUTH and not auth.allow_admin:
                            self._errors = {"Error": "X-TBA-Auth-Key does not have required permissions"}
                            self.abort(401)
                        logging.info("Auth owner: {}, X-TBA-Auth-Key: {}".format(self.auth_owner, x_tba_auth_key))
                    else:
                        self._errors = {"Error": "X-TBA-Auth-Key is invalid. Please get an access key at http://www.thebluealliance.com/account."}
                        self.abort(401)
Beispiel #21
0
    def post(self, event_key):
        event_key = event_key.lower(
        )  # Normalize keys to lower case (TBA convention)

        # Make sure we are processing for a valid event first
        # (it's fine to do this before auth, since leaking the existence of an
        # event isn't really that big a deal)
        self.event = Event.get_by_id(event_key)
        if not self.event:
            self._errors = json.dumps(
                {"Error": "Event {} not found".format(event_key)})
            self.abort(404)

        # Start by allowing admins to edit any event
        user_is_admin = (self._user_bundle.user
                         and self._user_bundle.is_current_user_admin)

        # Also grant access if the user as the EVENTWIZARD permission and this
        # is a current year offseason event
        account = self._user_bundle.account
        current_year = datetime.datetime.now().year
        user_has_permission = (self.event.event_type_enum
                               == EventType.OFFSEASON
                               and self.event.year == current_year
                               and account is not None
                               and AccountPermissions.OFFSEASON_EVENTWIZARD
                               in account.permissions)

        user_has_auth = (user_is_admin or user_has_permission)
        if not user_has_auth and self._user_bundle.user:
            # See if this user has any auth keys granted to its account
            now = datetime.datetime.now()
            auth_tokens = ApiAuthAccess.query(
                ApiAuthAccess.owner == account.key,
                ApiAuthAccess.event_list == ndb.Key(Event, event_key),
                ndb.OR(ApiAuthAccess.expiration == None,
                       ApiAuthAccess.expiration >= now)).fetch()
            user_has_auth = any(
                self._validate_auth(auth, event_key) is None
                for auth in auth_tokens)

        if not user_has_auth:
            # If not, check if auth id/secret were passed as headers
            auth_id = self.request.headers.get('X-TBA-Auth-Id')
            if not auth_id:
                self._errors = json.dumps({
                    "Error":
                    "Must provide a request header parameter 'X-TBA-Auth-Id'"
                })
                self.abort(400)

            auth_sig = self.request.headers.get('X-TBA-Auth-Sig')
            if not auth_sig:
                self._errors = json.dumps({
                    "Error":
                    "Must provide a request header parameter 'X-TBA-Auth-Sig'"
                })
                self.abort(400)

            auth = ApiAuthAccess.get_by_id(auth_id)
            expected_sig = md5.new('{}{}{}'.format(
                auth.secret if auth else None, self.request.path,
                self.request.body)).hexdigest()
            if not auth or expected_sig != auth_sig:
                logging.info("Auth sig: {}, Expected sig: {}".format(
                    auth_sig, expected_sig))
                self._errors = json.dumps(
                    {"Error": "Invalid X-TBA-Auth-Id and/or X-TBA-Auth-Sig!"})
                self.abort(401)

            # Checks event key is valid, correct auth types, and expiration
            error = self._validate_auth(auth, event_key)
            if error:
                self._errors = json.dumps({"Error": error})
                self.abort(401)

        try:
            self._process_request(self.request, event_key)
        except ParserInputException, e:
            self._errors = json.dumps({"Error": e.message})
            self.abort(400)
    def post(self, event_key):
        event_key = event_key.lower()  # Normalize keys to lower case (TBA convention)

        # Make sure we are processing for a valid event first
        # (it's fine to do this before auth, since leaking the existence of an
        # event isn't really that big a deal)
        self.event = Event.get_by_id(event_key)
        if not self.event:
            self._errors = json.dumps({"Error": "Event {} not found".format(event_key)})
            self.abort(404)

        # Start by allowing admins to edit any event
        user_is_admin = (self._user_bundle.user and self._user_bundle.is_current_user_admin)

        # Also grant access if the user as the EVENTWIZARD permission and this
        # is a current year offseason event
        account = self._user_bundle.account
        current_year = datetime.datetime.now().year
        user_has_permission = (self.event.event_type_enum == EventType.OFFSEASON
            and self.event.year == current_year
            and account is not None
            and AccountPermissions.OFFSEASON_EVENTWIZARD in account.permissions)

        user_has_auth = (user_is_admin or user_has_permission)
        if not user_has_auth and self._user_bundle.user:
            # See if this user has any auth keys granted to its account
            now = datetime.datetime.now()
            auth_tokens = ApiAuthAccess.query(ApiAuthAccess.owner == account.key,
                                              ApiAuthAccess.event_list == ndb.Key(Event, event_key),
                                              ndb.OR(ApiAuthAccess.expiration == None, ApiAuthAccess.expiration >= now)).fetch()
            user_has_auth = any(self._validate_auth(auth, event_key) is None for auth in auth_tokens)

        if not user_has_auth:
            # If not, check if auth id/secret were passed as headers
            auth_id = self.request.headers.get('X-TBA-Auth-Id')
            if not auth_id:
                self._errors = json.dumps({"Error": "Must provide a request header parameter 'X-TBA-Auth-Id'"})
                self.abort(400)

            auth_sig = self.request.headers.get('X-TBA-Auth-Sig')
            if not auth_sig:
                self._errors = json.dumps({"Error": "Must provide a request header parameter 'X-TBA-Auth-Sig'"})
                self.abort(400)

            auth = ApiAuthAccess.get_by_id(auth_id)
            expected_sig = md5.new('{}{}{}'.format(auth.secret if auth else None, self.request.path, self.request.body)).hexdigest()
            if not auth or expected_sig != auth_sig:
                logging.info("Auth sig: {}, Expected sig: {}".format(auth_sig, expected_sig))
                self._errors = json.dumps({"Error": "Invalid X-TBA-Auth-Id and/or X-TBA-Auth-Sig!"})
                self.abort(401)

            # Checks event key is valid, correct auth types, and expiration
            error = self._validate_auth(auth, event_key)
            if error:
                self._errors = json.dumps({"Error": error})
                self.abort(401)

        try:
            self._process_request(self.request, event_key)
        except ParserInputException, e:
            self._errors = json.dumps({"Error": e.message})
            self.abort(400)
Beispiel #23
0
    def post(self, auth_id):
        self._require_admin()

        auth = ApiAuthAccess.get_by_id(auth_id)

        auth_types_enum = [
            AuthType.READ_API
        ] if auth and AuthType.READ_API in auth.auth_types_enum else []
        if self.request.get('allow_edit_teams'):
            auth_types_enum.append(AuthType.EVENT_TEAMS)
        if self.request.get('allow_edit_matches'):
            auth_types_enum.append(AuthType.EVENT_MATCHES)
        if self.request.get('allow_edit_rankings'):
            auth_types_enum.append(AuthType.EVENT_RANKINGS)
        if self.request.get('allow_edit_alliances'):
            auth_types_enum.append(AuthType.EVENT_ALLIANCES)
        if self.request.get('allow_edit_awards'):
            auth_types_enum.append(AuthType.EVENT_AWARDS)
        if self.request.get('allow_edit_match_video'):
            auth_types_enum.append(AuthType.MATCH_VIDEO)
        if self.request.get('allow_edit_info'):
            auth_types_enum.append(AuthType.EVENT_INFO)
        if self.request.get('allow_edit_zebra_motionworks'):
            auth_types_enum.append(AuthType.ZEBRA_MOTIONWORKS)

        if self.request.get('owner', None):
            owner = Account.query(
                Account.email == self.request.get('owner')).fetch()
            owner_key = owner[0].key if owner else None
        else:
            owner_key = None

        if self.request.get('expiration', None):
            expiration = datetime.strptime(self.request.get('expiration'),
                                           '%Y-%m-%d')
        else:
            expiration = None

        if self.request.get('event_list_str'):
            split_events = self.request.get('event_list_str', '').split(',')
            event_list = [
                ndb.Key(Event, event_key.strip()) for event_key in split_events
            ]
        else:
            event_list = []

        if not auth:
            auth = ApiAuthAccess(
                id=auth_id,
                description=self.request.get('description'),
                owner=owner_key,
                expiration=expiration,
                allow_admin=True if self.request.get('allow_admin') else False,
                secret=''.join(
                    random.choice(string.ascii_lowercase +
                                  string.ascii_uppercase + string.digits)
                    for _ in range(64)),
                event_list=event_list,
                auth_types_enum=auth_types_enum,
            )
        else:
            auth.description = self.request.get('description')
            auth.event_list = event_list
            auth.auth_types_enum = auth_types_enum
            auth.owner = owner_key
            auth.expiration = expiration
            auth.allow_admin = True if self.request.get(
                'allow_admin') else False

        auth.put()

        self.redirect("/admin/api_auth/manage")
    def post(self, event_key):
        event_key = event_key.lower(
        )  # Normalize keys to lower case (TBA convention)

        if not (self._user_bundle.user
                and self._user_bundle.is_current_user_admin
                ):  # Allow admins to use without auth keys
            auth_id = self.request.headers.get('X-TBA-Auth-Id')
            if not auth_id:
                self._errors = json.dumps({
                    "Error":
                    "Must provide a request header parameter 'X-TBA-Auth-Id'"
                })
                self.abort(400)

            auth_sig = self.request.headers.get('X-TBA-Auth-Sig')
            if not auth_sig:
                self._errors = json.dumps({
                    "Error":
                    "Must provide a request header parameter 'X-TBA-Auth-Sig'"
                })
                self.abort(400)

            auth = ApiAuthAccess.get_by_id(auth_id)
            expected_sig = md5.new('{}{}{}'.format(
                auth.secret if auth else None, self.request.path,
                self.request.body)).hexdigest()
            if not auth or expected_sig != auth_sig:
                logging.info("Auth sig: {}, Expected sig: {}".format(
                    auth_sig, expected_sig))
                self._errors = json.dumps(
                    {"Error": "Invalid X-TBA-Auth-Id and/or X-TBA-Auth-Sig!"})
                self.abort(401)

            allowed_event_keys = [ekey.id() for ekey in auth.event_list]
            if event_key not in allowed_event_keys:
                self._errors = json.dumps({
                    "Error":
                    "Only allowed to edit events: {}".format(
                        ', '.join(allowed_event_keys))
                })
                self.abort(401)

            missing_auths = self.REQUIRED_AUTH_TYPES.difference(
                set(auth.auth_types_enum))
            if missing_auths != set():
                self._errors = json.dumps({
                    "Error":
                    "You do not have permission to edit: {}. If this is incorrect, please contact TBA admin."
                    .format(",".join(
                        [AuthType.type_names[ma] for ma in missing_auths]))
                })
                self.abort(401)

            if auth.expiration and auth.expiration < datetime.datetime.now():
                self._errors = json.dumps({
                    "Error":
                    "These keys expired on {}. Contact TBA admin to make changes"
                    .format(auth.expiration)
                })
                self.abort(401)

        try:
            self._process_request(self.request, event_key)
        except ParserInputException, e:
            self._errors = json.dumps({"Error": e.message})
            self.abort(400)