Commit 703b8e21 authored by Alejandro Alvarez Ayllon's avatar Alejandro Alvarez Ayllon
Browse files

FTS-910: Add length validator to String and Json

parent 3961e1dd
Pipeline #144285 passed with stage
in 28 seconds
......@@ -14,8 +14,9 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from sqlalchemy import event
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import ColumnProperty
from sqlalchemy.types import TypeDecorator, String
try:
import simplejson as json
......@@ -24,6 +25,23 @@ except:
import types
def check_string_length(cls, key, inst):
"""
Validate length of string columns
"""
prop = inst.prop
if isinstance(prop, ColumnProperty) and len(prop.columns) == 1:
col = prop.columns[0]
if (isinstance(col.type, String) or isinstance(col.type, Json)) and col.type.length:
max_length = col.type.length
def _set(instance, value, oldvalue, initiator):
if isinstance(col.type, Json):
value = json.dumps(value)
if value and len(value) > max_length:
raise ValueError("Length %d exceeds allowed %d" % (len(value), max_length))
event.listen(inst, 'set', _set)
class BaseAsDict(object):
def __getitem__(self, item):
if hasattr(self, item):
......@@ -31,12 +49,18 @@ class BaseAsDict(object):
else:
raise KeyError()
Base = declarative_base(cls=BaseAsDict)
event.listen(Base, 'attribute_instrument', check_string_length)
class Json(TypeDecorator):
impl = String
def __init__(self, length, *args, **kwargs):
super(Json, self).__init__(*args, **kwargs)
self.length = length
def process_bind_param(self, value, dialect):
return json.dumps(value)
......@@ -77,7 +101,8 @@ class Flag(TypeDecorator):
# This is used for flags that can be True, False, or some other thing
# i.e. verify_checksum flag, which can be True, False, 'Relaxed' (r), 'Destination' (d), 'Source' (s), 'Both' (b), 'None' (n)
# i.e. verify_checksum flag, which can be True, False,
# 'Relaxed' (r), 'Destination' (d), 'Source' (s), 'Both' (b), 'None' (n)
# reuse_job, which can be True, False and 'Multihop' (h)
class TernaryFlag(TypeDecorator):
impl = String
......
......@@ -121,13 +121,16 @@ class ActivitiesConfigController(BaseController):
if not type(value) in (float, int):
raise HTTPBadRequest('Share weight must be a number')
activity_share = ActivityShare(
vo=input_dict['vo'], active=input_dict['active'], activity_share=input_dict['share']
)
try:
activity_share = ActivityShare(
vo=input_dict['vo'], active=input_dict['active'], activity_share=input_dict['share']
)
Session.merge(activity_share)
audit_configuration('activity-share', json.dumps(input_dict))
Session.commit()
except ValueError, e:
raise HTTPBadRequest(str(e))
except:
Session.rollback()
raise
......
......@@ -144,3 +144,14 @@ class TestConfigActivityShare(TestController):
self.app.post_json(url="/config/activity_shares", params=msg, status=403)
self.app.delete(url="/config/activity_shares/dteam", status=403)
self.app.get_json(url="/config/activity_shares", status=403)
def test_activiy_shares_too_long(self):
"""
Activity share too long
"""
self.setup_gridsite_environment()
shares = {}
for i in range(100):
shares["activity%d" % i] = i
msg = {"vo": "dteam", "active": True, "share": shares}
self.app.post_json(url="/config/activity_shares", params=msg, status=400)
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment