diff --git a/config/settings/base.py b/config/settings/base.py index 4f26af00f91548e74f1756365ae823c1e6d3800a..6cd3f636d08a11b6c9a888f789b8fda284857a7b 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -26,7 +26,7 @@ MAINTENANCE_MODE = False MAINTENANCE_MODE_MESSAGE = None # Version --------------------------------------------------------------------- -PROJECT_VERSION = '2.8.0' +PROJECT_VERSION = '2.8.1' # Unauthenticated access ------------------------------------------------------ # This variable should eventually control whether unauthenticated access is diff --git a/docker/shibboleth-ds/idpselect_config.js b/docker/shibboleth-ds/idpselect_config.js index be2cb66689df11f69a391b1b9b7b3724c352a7a2..164dc98eff6693f40021940049cb511d9af8144f 100644 --- a/docker/shibboleth-ds/idpselect_config.js +++ b/docker/shibboleth-ds/idpselect_config.js @@ -22,7 +22,7 @@ function IdPSelectUIParms(){ this.maxResults = 10; // How many results to show at once or the number at which to // start showing if alwaysShow is false this.myEntityID = null; // If non null then this string must match the string provided in the DS parms - this.preferredIdP = ['https://login.ligo.org/idp/shibboleth', 'https://login2.ligo.org/idp/shibboleth', 'https://google.cirrusidentity.com/gateway']; + this.preferredIdP = ['https://login.ligo.org/idp/shibboleth', 'https://shibbi.pki.itc.u-tokyo.ac.jp/idp/shibboleth', 'https://google.cirrusidentity.com/gateway']; this.hiddenIdPs = null; // Array of entityIds to delete this.ignoreKeywords = false; // Do we ignore the <mdui:Keywords/> when looking for candidates this.showListFirst = false; // Do we start with a list of IdPs or just the dropdown diff --git a/docs/user_docs/source/labels.rst b/docs/user_docs/source/labels.rst index 3fa3ea690218a4bd5e4219e50cef15af04ec73b8..3c7576843e3b7fd1535fbdc1da75a897f1322179 100644 --- a/docs/user_docs/source/labels.rst +++ b/docs/user_docs/source/labels.rst @@ -39,6 +39,8 @@ Here is a table showing the currently available labels and their meanings. +-----------------+----------------------------------------------------------------------------------------------------------------------------------------+ | EM_Throttled | GraceID is ignored by automatic processing because the corresponding pipeline submitted too many events too quickly. | +-----------------+----------------------------------------------------------------------------------------------------------------------------------------+ +| EXT_SKYMAP_READY| External skymap is available | ++-----------------+----------------------------------------------------------------------------------------------------------------------------------------+ | GCN_PRELIM_SENT | A preliminary GCN has been sent. | +-----------------+----------------------------------------------------------------------------------------------------------------------------------------+ | GRB_OFFLINE | Indicates that offline triggered GRB searches found something coincident with this event. | @@ -65,10 +67,12 @@ Here is a table showing the currently available labels and their meanings. +-----------------+----------------------------------------------------------------------------------------------------------------------------------------+ | L1OPS | L1 operator signoff requested. | +-----------------+----------------------------------------------------------------------------------------------------------------------------------------+ -| LUMIN_GO | LUMIN Go | +| LUMIN_GO | Trigger satisfies basic automated checks and should be vetted by humans. Replaced by ADVREQ | +-----------------+----------------------------------------------------------------------------------------------------------------------------------------+ | LUMIN_NO | LUMIN No | +-----------------+----------------------------------------------------------------------------------------------------------------------------------------+ +| NOT_GRB | Event is likely not an astrophysical gamma ray burst | ++-----------------+----------------------------------------------------------------------------------------------------------------------------------------+ | PASTRO_READY | p_astro is available. | +-----------------+----------------------------------------------------------------------------------------------------------------------------------------+ | PE_READY | Parameter estimation results are available | diff --git a/gracedb/annotations/voevent_utils.py b/gracedb/annotations/voevent_utils.py index 9541c0b39194fabdee665a13bdc6bf3b17635145..3454e7ac32346e5308f45e4f16dec7411e403574 100644 --- a/gracedb/annotations/voevent_utils.py +++ b/gracedb/annotations/voevent_utils.py @@ -344,8 +344,6 @@ def construct_voevent_file(obj, voevent, request=None): "Time_Difference", value=float(deltat), ucd="meta.code", - #dataType="float" - #AEP--> figure this out ac=True, ) p_deltat.Description = ("Time difference between GW candidate " @@ -359,8 +357,6 @@ def construct_voevent_file(obj, voevent, request=None): "Time_Coincidence_FAR", value=obj.coinc_far, ucd="arith.rate;stat.falsealarm", - #dataType="float", - #AEP--> figure this out ac=True, unit="Hz" ) @@ -375,8 +371,6 @@ def construct_voevent_file(obj, voevent, request=None): "Time_Sky_Position_Coincidence_FAR", value=obj.coinc_far_space, ucd="arith.rate;stat.falsealarm", - #dataType="float", - #AEP--> figure this out ac=True, unit="Hz" ) @@ -545,7 +539,7 @@ def construct_voevent_file(obj, voevent, request=None): value=float(event.central_freq), ucd="gw.frequency", unit="Hz", - dataType="float" + ac=True, ) p_central_freq.Description = \ "Central frequency of GW burst signal" @@ -557,7 +551,7 @@ def construct_voevent_file(obj, voevent, request=None): value=float(event.duration), unit="s", ucd="time.duration", - dataType="float" + ac=True, ) p_duration.Description = "Measured duration of GW burst signal" v.What.append(p_duration) @@ -607,7 +601,7 @@ def construct_voevent_file(obj, voevent, request=None): value=float(event.frequency_mean), ucd="gw.frequency", unit="Hz", - dataType="float" + ac=True, ) p_freq.Description = "Mean frequency of GW burst signal" v.What.append(p_freq) diff --git a/gracedb/core/tests/utils.py b/gracedb/core/tests/utils.py index 3df7ef510995f80987445d23afbd305ead674122..2df1c84cf65f41d1e6ba6b8493af8a5d6d7c3d88 100644 --- a/gracedb/core/tests/utils.py +++ b/gracedb/core/tests/utils.py @@ -12,7 +12,7 @@ from guardian.conf import settings as guardian_settings from guardian.models import GroupObjectPermission, UserObjectPermission from events.models import Tag -from ligoauth.models import AuthGroup +from ligoauth.models import AuthGroup, AuthorizedLdapMember # Set up user model UserModel = get_user_model() @@ -69,6 +69,14 @@ class InternalGroupAndUserSetup(TestCase): cls.internal_group.ldap_name = 'internal_ldap_group' cls.internal_group.save(update_fields=['ldap_name']) + # Create AuthorizedLdapMember, link it to internal group: + cls.authldapmember, created = AuthorizedLdapMember.objects.get_or_create( + name='TestLDAPAuthMember') + if created: + cls.authldapmember.ldap_gname='internal_ldap_group' + cls.authldapmember.ldap_authgroup=cls.internal_group + cls.authldapmember.save() + # Get or create user cls.internal_user, _ = UserModel.objects.get_or_create( username='internal.user') @@ -116,6 +124,14 @@ class LvemGroupAndUserSetup(TestCase): cls.lvem_group.ldap_name = 'lvem_ldap_group' cls.lvem_group.save(update_fields=['ldap_name']) + # Create AuthorizedLdapMember, link it to LV-EM group: + cls.authldapmember_lvem, created = AuthorizedLdapMember.objects.get_or_create( + name='TestLDAPAuthMember_LVEM') + if created: + cls.authldapmember_lvem.ldap_gname='lvem_ldap_group' + cls.authldapmember_lvem.ldap_authgroup=cls.lvem_group + cls.authldapmember_lvem.save() + # Get or create LV-EM observers group lvem_obs_tag, _ = Tag.objects.get_or_create(name='lvem') cls.lvem_obs_group, created = AuthGroup.objects.get_or_create( @@ -125,6 +141,14 @@ class LvemGroupAndUserSetup(TestCase): cls.lvem_obs_group.tag = lvem_obs_tag cls.lvem_obs_group.save(update_fields=['ldap_name', 'tag']) + # Create AuthorizedLdapMember, link it to LV-EM observers group: + cls.authldapmember_lvemob, created = AuthorizedLdapMember.objects.get_or_create( + name='TestLDAPAuthMember_LVEMOB') + if created: + cls.authldapmember_lvemob.ldap_gname='lvem_observers_ldap_group' + cls.authldapmember_lvemob.ldap_authgroup=cls.lvem_group + cls.authldapmember_lvemob.save() + # Get or create user cls.lvem_user, _ = UserModel.objects.get_or_create( username='lvem.user') @@ -163,6 +187,15 @@ class SupereventManagersGroupAndUserSetup(TestCase): if created: internal_group.ldap_name = 'internal_ldap_group' internal_group.save(update_fields=['ldap_name']) + + # Create AuthorizedLdapMember, link it to internal group: + authldapmember, created = AuthorizedLdapMember.objects.get_or_create( + name='TestLDAPAuthMember') + if created: + authldapmember.ldap_gname='internal_ldap_group' + authldapmember.ldap_authgroup=internal_group + authldapmember.save() + internal_group.user_set.add(cls.sm_user) # Get permissions @@ -212,6 +245,15 @@ class AccessManagersGroupAndUserSetup(TestCase): if created: internal_group.ldap_name = 'internal_ldap_group' internal_group.save(update_fields=['ldap_name']) + + # Create AuthorizedLdapMember, link it to internal group: + authldapmember, created = AuthorizedLdapMember.objects.get_or_create( + name='TestLDAPAuthMember') + if created: + authldapmember.ldap_gname='internal_ldap_group' + authldapmember.ldap_authgroup=internal_group + authldapmember.save() + internal_group.user_set.add(cls.am_user) # Get permissions @@ -248,6 +290,14 @@ class SignoffGroupsAndUsersSetup(TestCase): internal_group.ldap_name = 'internal_ldap_group' internal_group.save(update_fields=['ldap_name']) + # Create AuthorizedLdapMember, link it to internal group: + cls.authldapmember, created = AuthorizedLdapMember.objects.get_or_create( + name='TestLDAPAuthMember') + if created: + cls.authldapmember.ldap_gname='internal_ldap_group' + cls.authldapmember.ldap_authgroup=internal_group + cls.authldapmember.save() + # Get or create IFO control room groups and users, and add perms ifos = ['H1', 'L1', 'V1'] for ifo in ifos: diff --git a/gracedb/events/migrations/0044_add_skymap_labels.py b/gracedb/events/migrations/0044_add_skymap_labels.py new file mode 100644 index 0000000000000000000000000000000000000000..1a508d1c778047b2966bf366c537195b92e2ab65 --- /dev/null +++ b/gracedb/events/migrations/0044_add_skymap_labels.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2018-06-28 10:40:45 +from __future__ import unicode_literals + +from django.db import migrations + +# Create initial Label instances + +# List of label names, default colors, and descriptions +LABELS = [ + { + 'name': 'NOT_GRB', + 'defaultColor': 'black', + 'description': 'Event is likely not an astrophysical gamma ray burst', + }, + { + 'name': 'EXT_SKYMAP_READY', + 'defaultColor': 'green', + 'description': 'A RAVEN coincidence event is publishable', + }, +] + +def add_labels(apps, schema_editor): + Label = apps.get_model('events', 'Label') + + # Create labels + for label_dict in LABELS: + l, created = Label.objects.get_or_create(name=label_dict['name']) + l.defaultColor = label_dict['defaultColor'] + l.description = label_dict['description'] + l.save() + +def remove_labels(apps, schema_editor): + Label = apps.get_model('events', 'Label') + + # Delete labels + for label_dict in LABELS: + try: + l = Label.objects.get(name=label_dict['name']) + except Label.DoesNotExist: + print('Label {0} not found to be deleted, skipping.' \ + .format(label_dict['name'])) + break + l.delete() + +class Migration(migrations.Migration): + + dependencies = [ + ('events', '0043_add_raven_label'), + ] + + operations = [ + migrations.RunPython(add_labels, remove_labels), + ] diff --git a/gracedb/events/serialize.py b/gracedb/events/serialize.py index f3614334931dfe26a17a6893feb2d204af6731d3..4743f5aacdf5bde0131c6167aa6c4e042e70f853 100644 --- a/gracedb/events/serialize.py +++ b/gracedb/events/serialize.py @@ -90,9 +90,11 @@ def write_output_files(root_dir, xmldoc, log_content, \ # Write xml-formatted coinc table # We do it this way instead of using create_versioned_file since the # xmldoc is designed to write to a file object. + file_path = os.path.join(root_dir, xml_fname) f = VersionedFile(file_path, 'w') xmldoc.write(f.file) + f.close() # Write log file create_versioned_file(log_fname, root_dir, log_content) diff --git a/gracedb/events/translator.py b/gracedb/events/translator.py index 30bef5f52752893a822d444d620c461c18922ed5..7aa442be7e56c46f0e4f720fbf8c5a8fdebe8ac9 100644 --- a/gracedb/events/translator.py +++ b/gracedb/events/translator.py @@ -398,12 +398,6 @@ class Translator(object): raise(NotImplemented) def castData(self, data): - # convert ints to ints - # No longer casting gpstime to integer. - #for key in ['gpstime', 'likelihood']: - for key in ['likelihood']: - if data[key]: - data[key] = int(float(data[key])) # convert floats to floats for key in ['far']: diff --git a/gracedb/events/view_utils.py b/gracedb/events/view_utils.py index 3ad0477ad39c843580e1de0a23a24bfadd429cb2..6dd15101acec40081c4469be4e4d767f6dadc857 100644 --- a/gracedb/events/view_utils.py +++ b/gracedb/events/view_utils.py @@ -375,10 +375,8 @@ def eventLogToDict(log, request=None): taglist_uri = api_reverse("events:eventlogtag-list", args=[log.event.graceid, log.N], request=request) - if log.filename: - actual_filename = log.filename - if log.file_version >= 0: - actual_filename += ',%d' % log.file_version + if log.filename and log.file_version is not None: + actual_filename = log.filename + ',%d' % log.file_version # NOTE: the reverse function will return a urlquoted # result, so we don't need urlquote here. Effectively # escaping twice results in wrong urls. diff --git a/gracedb/ligoauth/middleware.py b/gracedb/ligoauth/middleware.py index e08bd5f645cb13c1cd6bdbaf86a72e8c78e2a458..934bfd16f5fe39c78ea8d458985e16e800b86fb7 100644 --- a/gracedb/ligoauth/middleware.py +++ b/gracedb/ligoauth/middleware.py @@ -8,7 +8,7 @@ from django.contrib.auth.middleware import PersistentRemoteUserMiddleware from django.core.exceptions import ImproperlyConfigured from django.urls import reverse_lazy -from .models import AuthGroup +from .models import AuthGroup, AuthorizedLdapMember # Set up logger @@ -88,9 +88,31 @@ class ShibbolethWebAuthMiddleware(PersistentRemoteUserMiddleware): # Get groups from session which are in database as a QuerySet session_group_names = request.META.get(cls.group_header, '').split( cls.group_delimiter) - session_groups = AuthGroup.ldap_objects.filter(ldap_name__in= + + #session_groups = AuthGroup.ldap_objects.filter(ldap_name__in= + # session_group_names) + + # Get the authorized ldap membership object based on the request header: + session_ldap_membership = AuthorizedLdapMember.objects.filter(ldap_gname__in= session_group_names) + # Get the list of AuthGroup objects that don't have a null set of + # AuthorizedLdapMembers. Note that this step seems redundant right now. + # However, it's necessary for the new many-to-one relationship with + # multiple ldap memberships. Plus, this will allow for adding new ldap + # memberships and multiple group affiliations. Note for me: + # If an ldap member needs to be associated with another group (like, + # not just internal_users), then there should be a new authorizedldapmember-ship + # with a new ForeignKey relation. FYI. + + group_set = AuthGroup.objects.exclude(authorizedldapmember__isnull=True) + + # Return a queryset of group memberships associated with the ldap + # community id + + ldap_group_ids = session_ldap_membership.values_list('id') + session_groups = group_set.filter(authorizedldapmember__in=ldap_group_ids) + # Add groups which are in session but not in database user.groups.add(*session_groups) diff --git a/gracedb/ligoauth/migrations/0061_auth_ldap_communities.py b/gracedb/ligoauth/migrations/0061_auth_ldap_communities.py new file mode 100644 index 0000000000000000000000000000000000000000..e916713ed3d599296cc21e8350f70a240a6b60a2 --- /dev/null +++ b/gracedb/ligoauth/migrations/0061_auth_ldap_communities.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.23 on 2019-12-27 17:50 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('ligoauth', '0060_add_emfollow-test_cert'), + ] + + operations = [ + migrations.CreateModel( + name='AuthorizedLdapMember', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('ldap_gname', models.CharField(max_length=50, null=True, unique=True)), + ('name', models.CharField(max_length=50, null=True, unique=True)), + ('ldap_authgroup', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='ligoauth.AuthGroup')), + ], + ), + ] diff --git a/gracedb/ligoauth/migrations/0062_populate_auth_ldap_communities.py b/gracedb/ligoauth/migrations/0062_populate_auth_ldap_communities.py new file mode 100644 index 0000000000000000000000000000000000000000..55a7d5c36f74056fd7f2243dc8867b42fb9972a3 --- /dev/null +++ b/gracedb/ligoauth/migrations/0062_populate_auth_ldap_communities.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.20 on 2019-05-28 18:18 +from __future__ import unicode_literals + +from django.db import migrations + +GROUP_DATA = [ + { + 'name': 'LVC Members', + 'ldap_gname': 'Communities:LSCVirgoLIGOGroupMembers', + }, + { + 'name': 'KAGRA', + 'ldap_gname': 'gw-astronomy:KAGRA-LIGO:members', + }, +] + + +def create_ldapauthgroups(apps, schema_editor): + AuthGroup = apps.get_model('ligoauth', 'AuthGroup') + AuthorizedLdapMember = apps.get_model('ligoauth', 'AuthorizedLdapMember') + + internal_group = AuthGroup.objects.get(name='internal_users') + + # Create AuthrizedLdapMember instances + for group in GROUP_DATA: + + lag = AuthorizedLdapMember.objects.create( + name=group['name'], + ldap_gname=group['ldap_gname'], + ldap_authgroup=internal_group) + lag.save() + + +def delete_ldapauthgroups(apps, schema_editor): + AuthorizedLdapMember = apps.get_model('ligoauth', 'AuthorizedLdapMember') + + # Loop over groups and delete AuthGroup + for group in GROUP_DATA: + # Get AuthGroup + group_name = group['name'] + ag = AuthorizedLdapMember.objects.get(name=group_name) + + # Delete AuthGroup and keep DjangoGroup base class + ag.delete() + + +class Migration(migrations.Migration): + + dependencies = [ + ('ligoauth', '0061_auth_ldap_communities'), + ] + + operations = [ + migrations.RunPython(create_ldapauthgroups, delete_ldapauthgroups), + ] diff --git a/gracedb/ligoauth/migrations/0063_populate_emadv_auth_ldap_communities.py b/gracedb/ligoauth/migrations/0063_populate_emadv_auth_ldap_communities.py new file mode 100644 index 0000000000000000000000000000000000000000..528a1f6521c9edcb1484086950f4a0e4fc833a9b --- /dev/null +++ b/gracedb/ligoauth/migrations/0063_populate_emadv_auth_ldap_communities.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.20 on 2019-05-28 18:18 +from __future__ import unicode_literals + +from django.db import migrations + +GROUP_DATA = [ + { + 'name': 'EM Advovates', + 'ldap_gname': 'Communities:LVC:GraceDB:GraceDBAdvocates', + }, +] + + +def create_ldapauthgroups(apps, schema_editor): + AuthGroup = apps.get_model('ligoauth', 'AuthGroup') + AuthorizedLdapMember = apps.get_model('ligoauth', 'AuthorizedLdapMember') + + internal_group = AuthGroup.objects.get(name='em_advocates') + + # Create AuthrizedLdapMember instances + for group in GROUP_DATA: + + lag = AuthorizedLdapMember.objects.create( + name=group['name'], + ldap_gname=group['ldap_gname'], + ldap_authgroup=internal_group) + lag.save() + + +def delete_ldapauthgroups(apps, schema_editor): + AuthorizedLdapMember = apps.get_model('ligoauth', 'AuthorizedLdapMember') + + # Loop over groups and delete AuthGroup + for group in GROUP_DATA: + # Get AuthGroup + group_name = group['name'] + ag = AuthorizedLdapMember.objects.get(name=group_name) + + # Delete AuthGroup and keep DjangoGroup base class + ag.delete() + + +class Migration(migrations.Migration): + + dependencies = [ + ('ligoauth', '0062_populate_auth_ldap_communities'), + ] + + operations = [ + migrations.RunPython(create_ldapauthgroups, delete_ldapauthgroups), + ] diff --git a/gracedb/ligoauth/migrations/0064_populate_lvem_auth_ldap_communities.py b/gracedb/ligoauth/migrations/0064_populate_lvem_auth_ldap_communities.py new file mode 100644 index 0000000000000000000000000000000000000000..cfe6b8d494c0360402749946f3357389d3cd9030 --- /dev/null +++ b/gracedb/ligoauth/migrations/0064_populate_lvem_auth_ldap_communities.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.20 on 2019-05-28 18:18 +from __future__ import unicode_literals + +from django.db import migrations + +GROUP_DATA = [ + { + 'name': 'LVEM', + 'ldap_gname': 'gw-astronomy:LV-EM', + }, +] + + +def create_ldapauthgroups(apps, schema_editor): + AuthGroup = apps.get_model('ligoauth', 'AuthGroup') + AuthorizedLdapMember = apps.get_model('ligoauth', 'AuthorizedLdapMember') + + internal_group = AuthGroup.objects.get(name='lvem_users') + + # Create AuthrizedLdapMember instances + for group in GROUP_DATA: + + lag = AuthorizedLdapMember.objects.create( + name=group['name'], + ldap_gname=group['ldap_gname'], + ldap_authgroup=internal_group) + lag.save() + + +def delete_ldapauthgroups(apps, schema_editor): + AuthorizedLdapMember = apps.get_model('ligoauth', 'AuthorizedLdapMember') + + # Loop over groups and delete AuthGroup + for group in GROUP_DATA: + # Get AuthGroup + group_name = group['name'] + ag = AuthorizedLdapMember.objects.get(name=group_name) + + # Delete AuthGroup and keep DjangoGroup base class + ag.delete() + + +class Migration(migrations.Migration): + + dependencies = [ + ('ligoauth', '0063_populate_emadv_auth_ldap_communities'), + ] + + operations = [ + migrations.RunPython(create_ldapauthgroups, delete_ldapauthgroups), + ] diff --git a/gracedb/ligoauth/migrations/0065_populate_lvemo_auth_ldap_communities.py b/gracedb/ligoauth/migrations/0065_populate_lvemo_auth_ldap_communities.py new file mode 100644 index 0000000000000000000000000000000000000000..b470df3cf11bc2e6a1a0ea6084b828c8661224db --- /dev/null +++ b/gracedb/ligoauth/migrations/0065_populate_lvemo_auth_ldap_communities.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.20 on 2019-05-28 18:18 +from __future__ import unicode_literals + +from django.db import migrations + +GROUP_DATA = [ + { + 'name': 'LVEM Observers', + 'ldap_gname': 'gw-astronomy:LV-EM:Observer', + }, +] + + +def create_ldapauthgroups(apps, schema_editor): + AuthGroup = apps.get_model('ligoauth', 'AuthGroup') + AuthorizedLdapMember = apps.get_model('ligoauth', 'AuthorizedLdapMember') + + internal_group = AuthGroup.objects.get(name='lvem_observers') + + # Create AuthrizedLdapMember instances + for group in GROUP_DATA: + + lag = AuthorizedLdapMember.objects.create( + name=group['name'], + ldap_gname=group['ldap_gname'], + ldap_authgroup=internal_group) + lag.save() + + +def delete_ldapauthgroups(apps, schema_editor): + AuthorizedLdapMember = apps.get_model('ligoauth', 'AuthorizedLdapMember') + + # Loop over groups and delete AuthGroup + for group in GROUP_DATA: + # Get AuthGroup + group_name = group['name'] + ag = AuthorizedLdapMember.objects.get(name=group_name) + + # Delete AuthGroup and keep DjangoGroup base class + ag.delete() + + +class Migration(migrations.Migration): + + dependencies = [ + ('ligoauth', '0064_populate_lvem_auth_ldap_communities'), + ] + + operations = [ + migrations.RunPython(create_ldapauthgroups, delete_ldapauthgroups), + ] diff --git a/gracedb/ligoauth/models.py b/gracedb/ligoauth/models.py index 238bb110f0d35da70fd0daeaa941ada81f9bc7f5..9a3d18461a1bead652b8115c03fa1257d5880eef 100644 --- a/gracedb/ligoauth/models.py +++ b/gracedb/ligoauth/models.py @@ -21,7 +21,6 @@ class X509Cert(models.Model): subject = models.CharField(max_length=255, unique=True, null=False) user = models.ForeignKey(User) - class AuthGroup(Group): """Enhanced version of Django Group model""" # Description of the group @@ -40,3 +39,16 @@ class AuthGroup(Group): objects = models.Manager() ldap_objects = LdapGroupManager() tag_objects = TagGroupManager() + +class AuthorizedLdapMember(models.Model): + """Model for authorized ldap membership""" + # Group membership in ldap. This is analogous to the `ldap_name` in the + # AuthGroup class: + ldap_gname = models.CharField(max_length=50, unique=True, null=True) + + # Add support for authorized membership: + ldap_authgroup = models.ForeignKey(AuthGroup, null=True) + + # Give it a name: + name = models.CharField(max_length=50, unique=True, null=True) + diff --git a/gracedb/ligoauth/tests/test_middleware.py b/gracedb/ligoauth/tests/test_middleware.py index 73e1513412ccb701f7363abe6e52adec65f60764..316fb89c0c2a500c2252154ffeba957911ece65c 100644 --- a/gracedb/ligoauth/tests/test_middleware.py +++ b/gracedb/ligoauth/tests/test_middleware.py @@ -8,7 +8,7 @@ from django.urls import reverse from user_sessions.middleware import SessionMiddleware -from ligoauth.models import AuthGroup +from ligoauth.models import AuthGroup, AuthorizedLdapMember from ligoauth.middleware import ( ControlRoomMiddleware, ShibbolethWebAuthMiddleware, ) @@ -311,8 +311,14 @@ class TestShibbolethWebAuthMiddleware(GraceDbTestBase): request = self.factory.get(self.url) request.META.update(**{ settings.SHIB_USER_HEADER: self.lvem_user.username, - settings.SHIB_GROUPS_HEADER: self.lvem_obs_group.ldap_name, + settings.SHIB_GROUPS_HEADER: self.lvem_obs_group.ldap_name + 'test_lvemapl', }) + new_lvem_ldap_member, created = AuthorizedLdapMember.objects.get_or_create(name='test_lvem') + if created: + new_lvem_ldap_member.ldap_gname=self.lvem_obs_group.ldap_name + 'test_lvemapl' + new_lvem_ldap_member.ldap_authgroup=self.lvem_obs_group + new_lvem_ldap_member.save() + # Necessary pre-processing middleware SessionMiddleware().process_request(request) AuthenticationMiddleware().process_request(request) @@ -386,14 +392,23 @@ class TestShibbolethWebAuthMiddleware(GraceDbTestBase): request = self.factory.get(self.url) request.META.update(**{ settings.SHIB_USER_HEADER: new_user_dict['username'], - settings.SHIB_GROUPS_HEADER: self.lvem_obs_group.ldap_name, + settings.SHIB_GROUPS_HEADER: self.lvem_obs_group.ldap_name + 'test_lvemuc', settings.SHIB_ATTRIBUTE_MAP['email']: new_user_dict['email'], }) + + # Set up ldap membership + new_test_lvem_ldap_member, created = AuthorizedLdapMember.objects.get_or_create(name='new_test_lvem') + if created: + new_test_lvem_ldap_member.ldap_gname=self.lvem_obs_group.ldap_name + 'test_lvemuc' + new_test_lvem_ldap_member.ldap_authgroup=self.lvem_obs_group + new_test_lvem_ldap_member.save() + # Necessary pre-processing middleware SessionMiddleware().process_request(request) AuthenticationMiddleware().process_request(request) self.mw_instance.process_request(request) + # Make sure user is authenticated and was authenticated by # the shibboleth backend and that the LV-EM observers group is # attached to the user account @@ -418,6 +433,13 @@ class TestShibbolethWebAuthMiddleware(GraceDbTestBase): ldap_name='new_ldap_group') # Compile group header - add one random additional group name string other_group_ldap_str = 'other_group' + + new_auth_ldap_member, created = AuthorizedLdapMember.objects.get_or_create(name='new_membership') + if created: + new_auth_ldap_member.ldap_gname=other_group_ldap_str + new_auth_ldap_member.ldap_authgroup=new_ldap_group + new_auth_ldap_member.save() + delim = ShibbolethWebAuthMiddleware.group_delimiter groups_str = delim.join([self.internal_group.ldap_name, new_ldap_group.ldap_name, other_group_ldap_str]) diff --git a/gracedb/migrations/guardian/0007_add_gareth_davies_to_pycbc.py b/gracedb/migrations/guardian/0007_add_gareth_davies_to_pycbc.py new file mode 100644 index 0000000000000000000000000000000000000000..ae1f3e23068efdeb2f4349d72e0634cb859323f6 --- /dev/null +++ b/gracedb/migrations/guardian/0007_add_gareth_davies_to_pycbc.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2017-11-01 16:19 +from __future__ import unicode_literals + +from django.db import migrations + +# Creates UserObjectPermission objects which allow specific users +# to add events for pipelines. Based on current production database +# content (27 October 2017) + +# List of pipeline names and lists of usernames who should +# be allowed to add events for them +PP_LIST = [ + { + 'pipeline': 'gstlal', + 'usernames': [ + 'cody.messick@LIGO.ORG', + ] + }, + { + 'pipeline': 'pycbc', + 'usernames': [ + 'gareth.davies@LIGO.ORG', + ] + }, +] + +def add_permissions(apps, schema_editor): + User = apps.get_model('auth', 'User') + Permission = apps.get_model('auth', 'Permission') + UserObjectPermission = apps.get_model('guardian', 'UserObjectPermission') + Pipeline = apps.get_model('events', 'Pipeline') + ContentType = apps.get_model('contenttypes', 'ContentType') + + perm = Permission.objects.get(codename='populate_pipeline') + ctype = ContentType.objects.get_for_model(Pipeline) + for pp_dict in PP_LIST: + pipeline = Pipeline.objects.get(name=pp_dict['pipeline']) + + # Loop over users + for username in pp_dict['usernames']: + + # Robot users should have been already created by ligoauth 0003, + # but we have to create human user accounts here + user, _ = User.objects.get_or_create(username=username) + + # Create UserObjectPermission + uop, uop_created = UserObjectPermission.objects.get_or_create( + user=user, permission=perm, content_type=ctype, + object_pk=pipeline.id) + +def remove_permissions(apps, schema_editor): + pass + +class Migration(migrations.Migration): + + dependencies = [ + ('guardian', '0006_authorize_emfollow_to_populate_pipelines'), + ] + + operations = [ + migrations.RunPython(add_permissions, remove_permissions), + ] \ No newline at end of file diff --git a/gracedb/migrations/guardian/0008_add_edoardo_milotti_to_cwb.py b/gracedb/migrations/guardian/0008_add_edoardo_milotti_to_cwb.py new file mode 100644 index 0000000000000000000000000000000000000000..1da0e8624887c8749c238f4dcdd1c9a0712783df --- /dev/null +++ b/gracedb/migrations/guardian/0008_add_edoardo_milotti_to_cwb.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2017-11-01 16:19 +from __future__ import unicode_literals + +from django.db import migrations + +# Creates UserObjectPermission objects which allow specific users +# to add events for pipelines. Based on current production database +# content (27 October 2017) + +# List of pipeline names and lists of usernames who should +# be allowed to add events for them +PP_LIST = [ + { + 'pipeline': 'cwb', + 'usernames': [ + 'edoardo.milotti@ligo.org', + ] + }, +] + +def add_permissions(apps, schema_editor): + User = apps.get_model('auth', 'User') + Permission = apps.get_model('auth', 'Permission') + UserObjectPermission = apps.get_model('guardian', 'UserObjectPermission') + Pipeline = apps.get_model('events', 'Pipeline') + ContentType = apps.get_model('contenttypes', 'ContentType') + + perm = Permission.objects.get(codename='populate_pipeline') + ctype = ContentType.objects.get_for_model(Pipeline) + for pp_dict in PP_LIST: + pipeline = Pipeline.objects.get(name=pp_dict['pipeline']) + + # Loop over users + for username in pp_dict['usernames']: + + # Robot users should have been already created by ligoauth 0003, + # but we have to create human user accounts here + user, _ = User.objects.get_or_create(username=username) + + # Create UserObjectPermission + uop, uop_created = UserObjectPermission.objects.get_or_create( + user=user, permission=perm, content_type=ctype, + object_pk=pipeline.id) + +def remove_permissions(apps, schema_editor): + pass + +class Migration(migrations.Migration): + + dependencies = [ + ('guardian', '0007_add_gareth_davies_to_pycbc'), + ] + + operations = [ + migrations.RunPython(add_permissions, remove_permissions), + ] \ No newline at end of file diff --git a/gracedb/superevents/views.py b/gracedb/superevents/views.py index 7015c862346e7a601d0f7a0b4505df838b7d023d..b449feabac6a19d10fb2b61136a966123bc89919 100644 --- a/gracedb/superevents/views.py +++ b/gracedb/superevents/views.py @@ -233,9 +233,11 @@ class SupereventPublic(DisplayFarMixin, ListView): ("BBH", voe.prob_bbh), ("Terrestrial", voe.prob_terrestrial), ("MassGap", voe.prob_mass_gap)] - pastro_values.sort(reverse=True, key=lambda p_a: p_a[1]) + pastro_values.sort(reverse=True, key=lambda p_a: 0.0 if p_a[1] is None else p_a[1]) sourcelist = [] for key, value in pastro_values: + if value is None: + value = 0.0 if value > 0.01: prob = int(round(100*value)) if prob == 100: prob = '>99'