Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integration Badges Backend Implementation #5

Open
wants to merge 20 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
b6b16a9
Adding integration badges initial setup
dinukadesilva Jun 21, 2024
22b62ec
implemented get requests for integration badges
Kleokhov Jul 5, 2024
644920e
continue editing endpoints
Kleokhov Jul 11, 2024
418c214
Adding the workflow models
dinukadesilva Jul 11, 2024
e4d0307
implemented post requests to resource-badge model
Kleokhov Jul 19, 2024
86672a3
adjust unplan endpoint
Kleokhov Jul 20, 2024
f94bb06
Adjusted workflow model; Implemented task uncomplete endpoint
Kleokhov Jul 23, 2024
26fdf96
update comment field
Kleokhov Aug 6, 2024
5cd8ccd
Merge pull request #6 from access-ci-org/main
jpnavarro Aug 25, 2024
5667a10
Merge pull request #7 from access-ci-org/main
jpnavarro Aug 25, 2024
989ba10
Merge pull request #10 from access-ci-org/main
jpnavarro Aug 27, 2024
3ea5961
Fix some names and column lengths
dinukadesilva Sep 24, 2024
8944b4a
Change the __str__ of models for better experience in the admin portal
dinukadesilva Sep 26, 2024
3abfec4
design documentation for REST api authorization
ericblau Oct 2, 2024
4c9a890
CTT-144 add info_resourceid
andylytical Oct 3, 2024
8c77c29
Change Field to Fields, add Fields of Science to main page
jpnavarro Aug 27, 2024
2d8668f
See CHANGELOG tag v3.35.0
jpnavarro Oct 17, 2024
d2331b3
Enabling searching and ordering for dropdowns in integration badges a…
dinukadesilva Oct 31, 2024
7c4ee2c
Merge branch 'integration_badges' of https://github.com/access-ci-org…
dinukadesilva Oct 31, 2024
7c18179
Configuration for cilogon_tokenauth
ericblau Dec 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,5 @@ dmypy.json

# Mac
.DS_Store

.idea
4 changes: 4 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
v3.35.0 2024-10-17 JP, Andy
- Change Field to Fields, add Fields of Science to main page
- CTT-144 add info_resourceid

v3.34.0 2024-08-27 Andy and JP
- COmpute COmparison json and html
- Simplify developer container setup and instructions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,16 @@
'django_opensearch_dsl',
'allocations',
'cider',
'integration_badges',
'glue2',
'news',
'resource_v4',
'warehouse_state',
'warehouse_tools',
'web',
'dal',
'dal_select2',
'cilogon_tokenauth',
]

MIDDLEWARE = [
Expand Down Expand Up @@ -348,7 +352,9 @@
STATICFILES_DIRS = (
os.path.join( os.path.dirname(__file__), '../static' ),
)

# For cilogon_tokenauth
CLIENT_KEY = CONF.get('CLIENT_KEY', None)
CLIENT_SECRET = CONF.get('CLIENT_SECRET', None)
#
# 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
REST_FRAMEWORK = {
Expand All @@ -364,6 +370,9 @@
'DEFAULT_PAGINATION_CLASS': "rest_framework.pagination.PageNumberPagination",
'PAGE_SIZE': 25,
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
'DEFAULT_AUTHENTICATION_CLASSES': [
'cilogon_tokenauth.auth.CITokenAuthentication',
],
}

# REST_AUTH_REGISTER_PERMISSION_CLASSES = (
Expand Down Expand Up @@ -408,6 +417,10 @@
'services': {
'handlers': ['file'],
'level': 'DEBUG'
},
'cilogon_tokenauth': {
'handlers': ['file'],
'level': 'DEBUG'
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
path('wh2/state/', include('warehouse_state.urls')),
path('wh2/allocations/', include('allocations.urls') ),
path('wh2/cider/', include('cider.urls') ),
path('wh2/integration_badges/', include('integration_badges.urls') ),
path('wh2/glue2/', include('glue2.urls') ),
path('wh2/news/', include('news.urls') ),
path('wh2/resource/', include('resource_v4.urls') ),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{% extends "web/base_nav_none.html" %}
{% block title %}Field of Science List{% endblock %}
{% block title %}Fields of Science List{% endblock %}
{% block content %}

<h1 align="center">Field of Science List</h1>
<h1 align="center">Fields of Science List</h1>
<p><h3>As of: {% now 'Y-m-d H:i e' %}</h3></p>

<table style="margin-left:2px" border=0 cellspacing=0 cellpadding=3>
Expand Down
2 changes: 1 addition & 1 deletion Operations_Warehouse_Django/allocations/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

class Allocations_v1_fos_List(ListAPIView):
'''
Field of Science list
Fields of Science list

Optional response argument(s):
```
Expand Down
2 changes: 1 addition & 1 deletion Operations_Warehouse_Django/cider/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ class CiderInfrastructure(models.Model):
other_attributes = models.JSONField()
updated_at = models.DateTimeField(null=True)
def __str__(self):
return str(self.cider_resource_id)
return "%s (%d)" % (self.resource_descriptive_name, self.cider_resource_id)
20 changes: 17 additions & 3 deletions Operations_Warehouse_Django/cider/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ def get_resource_info( attrs ):
]
resource_info = { k: attrs[k] for k in keys }
resource_info.update( get_best_org_details( attrs['organizations'] ) )
#CTT-144 add info_resourceid
info_resourceid = attrs['parent_resource']['info_resourceid']
resource_info.update( {'info_resourceid':info_resourceid} )
return resource_info


Expand All @@ -69,6 +72,7 @@ def get_resource_attribute_names():
# gateway_recommended_use,
'gpu_description',
'graphics_card',
'info_resourceid',
'interconnect',
# ip_address,
'job_manager',
Expand Down Expand Up @@ -120,14 +124,17 @@ def mk_headers( cols, resources ):
org_name = resource[ 'organization_name' ]
logo_url = resource[ 'organization_logo_url' ]
abbr = resource[ 'organization_abbreviation' ]
# info_resourceid = resource[ 'info_resourceid' ]
img_size=75
h = (
f'<!-- org_abbr: {abbr} -->'
f'<img width="{img_size}" height="{img_size}" src="{logo_url}" alt="{org_name}">'
'<br/>'
f'<a href="{org_url}">({abbr})</a>'
f'<a href="{org_url}">'
f'<img width="{img_size}" height="{img_size}" src="{logo_url}" alt="{abbr}">'
f'</a>'
'<br/>'
f'<a href="{resource_url}">{resource_short_name}</a>'
# '<br/>'
# f'&lt;{info_resourceid}&gt;'
)
headers.append( h )
return headers
Expand Down Expand Up @@ -183,6 +190,13 @@ def cider_to_coco( objects ):
features[k][resource_id] = v
except KeyError as e:
features[k] = { 'Attribute': k, resource_id: v }
#CTT-144 add info_resourceid
k = 'info_resourceid'
v = resources[ resource_id ][k]
try:
features[k][resource_id] = v
except KeyError as e:
features[k] = { 'Attribute': k, resource_id: v }
data = { 'resources': resources, 'attributes': features }
return data

Expand Down
1 change: 1 addition & 0 deletions Operations_Warehouse_Django/cider/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def get(self, request, format=None, **kwargs):
template_name = 'coco.html'
objects = CiderInfrastructure_Active_Filter( type='Compute' )
serializer = CiderInfrastructure_OtherAttrs_Serializer(objects, context={'request': request}, many=True)
# return MyAPIResponse( { 'results': serializer.data }, template_name=template_name )
coco_data = cider_to_coco( { 'results': serializer.data } )
if returnformat != 'json':
coco_data = mk_html_table( coco_data )
Expand Down
21 changes: 21 additions & 0 deletions Operations_Warehouse_Django/docs/authorization_design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Design document for oAuth authentication and authorization for Information Warehouse, specifically integration badges


Design for the Authentication and Authorization for the django rest framework APIs of the Operations Information Warehouse.

The Django web front end of the Information Warehouse has already integrated CILogon to allow users to log in and see authenticated web views. However, Django Rest Framework APIs do not use the same authentication methods as the front end. Thus, we need to develop some custom code to integrate CILogon authentication to our DRF APIs.

This custom authentication integration takes the form of a django app “tokenauth” which provides decorators for API functions that can consume a CILogon oAuth token and provide an authentication decision based on the validity of the token and scope, and the identity of the token.

Aside from using the same oAuth provider (CILogon), this authentication check is entirely separate from the SSO login of the Django front end. It does not integrate with the Django users table, nor the Social Accounts table used by the front end. It makes its own calls to introspect the tokens it receives.


Everything should be authenticated using CILogon

The integration badging endpoints are top priority for authenticating.

POST endpoints will need to be authenticated AND check authorization against a table that lists ACCESS-CI identities with the resource IDs for which they are authorized to make changes.

The route will have a decorator that will confirm that the identity is authorized to call the function to make changes.
The endpoint will also need code to look at which resource IDs they’re trying to change, and make the authorization decision.

4 changes: 3 additions & 1 deletion Operations_Warehouse_Django/glue2/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1056,7 +1056,9 @@ class Software_Full(APIView):
'''
GLUE2 Software detailed information ApplicationHandle, ApplicationEnvironment, ...
'''
permission_classes = (IsAuthenticatedOrReadOnly,)
authentication_Classes = [ 'cilogon_tokenauth.auth.TokenAuthentication']
#permission_classes = (IsAuthenticatedOrReadOnly,)
permission_classes = (IsAuthenticated,)
serializer_class = Software_Community_Serializer
def get(self, request, format=None, **kwargs):
if 'id' in self.kwargs:
Expand Down
Empty file.
100 changes: 100 additions & 0 deletions Operations_Warehouse_Django/integration_badges/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
from django.contrib import admin
from dal import autocomplete

from integration_badges.models import *

class Integration_Roadmap_Admin(admin.ModelAdmin):
list_display = ('roadmap_id', 'name', 'graphic', 'executive_summary', 'infrastructure_types',
'integration_coordinators', 'status')
list_display_links = ['name']
ordering = ['name', 'roadmap_id']
search_fields = ['name', 'executive_summary']

# Register your models here.
admin.site.register(Integration_Roadmap, Integration_Roadmap_Admin)

class Integration_Badge_Admin(admin.ModelAdmin):
list_display = ('badge_id', 'name', 'graphic', 'researcher_summary', 'resource_provider_summary',
'verification_summary', 'verification_method',
'default_badge_access_url', 'default_badge_access_url_label')
list_display_links = ['name']
ordering = ['name', 'badge_id']
search_fields = ['name', 'researcher_summary', 'resource_provider_summary']

# Register your models here.
admin.site.register(Integration_Badge, Integration_Badge_Admin)


class Integration_Roadmap_Badge_Admin(admin.ModelAdmin):
autocomplete_fields = ('roadmap_id', 'badge_id',)
list_display = ('id', 'roadmap_id', 'badge_id', 'sequence_no', 'required')
list_display_links = ['id']
ordering = ['roadmap_id', 'badge_id']
search_fields = ['id', 'roadmap_id', 'badge_id', 'sequence_no', 'required']

# Register your models here.
admin.site.register(Integration_Roadmap_Badge, Integration_Roadmap_Badge_Admin)

class Integration_Task_Admin(admin.ModelAdmin):
list_display = ('task_id', 'name', 'technical_summary', 'implementor_roles', 'task_experts', 'detailed_instructions_url')
list_display_links = ['name']
ordering = ['task_id']
search_fields = ['name', 'technical_summary']

# Register your models here.
admin.site.register(Integration_Task, Integration_Task_Admin)

class Integration_Badge_Prerequisite_Badge_Admin(admin.ModelAdmin):
autocomplete_fields = ('badge_id', 'prerequisite_badge_id',)
list_display = ('id', 'badge_id', 'prerequisite_badge_id', 'sequence_no')
list_display_links = ['id']
ordering = ['badge_id', 'prerequisite_badge_id']
search_fields = ['id', 'badge_id', 'prerequisite_badge_id', 'sequence_no']

# Register your models here.
admin.site.register(Integration_Badge_Prerequisite_Badge, Integration_Badge_Prerequisite_Badge_Admin)


class Integration_Badge_Task_Admin(admin.ModelAdmin):
autocomplete_fields = ('badge_id', 'task_id',)
list_display = ('id', 'badge_id', 'task_id', 'sequence_no')
list_display_links = ['id']
ordering = ['badge_id', 'task_id']
search_fields = ['id', 'badge_id', 'task_id', 'sequence_no']

# Register your models here.
admin.site.register(Integration_Badge_Task, Integration_Badge_Task_Admin)


class Integration_Resource_Roadmap_Admin(admin.ModelAdmin):
autocomplete_fields = ('resource_id', 'roadmap_id',)
list_display = ('id', 'resource_id', 'roadmap_id')
list_display_links = ['id']
ordering = ['resource_id', 'roadmap_id']
search_fields = ['id', 'resource_id', 'roadmap_id']


# Register your models here.
admin.site.register(Integration_Resource_Roadmap, Integration_Resource_Roadmap_Admin)


class Integration_Resource_Badge_Admin(admin.ModelAdmin):
autocomplete_fields = ('resource_id', 'badge_id',)
list_display = ('id', 'resource_id', 'badge_id')
list_display_links = ['id']
ordering = ['resource_id', 'badge_id']
search_fields = ['resource_id', 'badge_id']

# Register your models here.
admin.site.register(Integration_Resource_Badge, Integration_Resource_Badge_Admin)


class Integration_Workflow_Admin(admin.ModelAdmin):
autocomplete_fields = ('resource_id', 'badge_id',)
list_display = ('workflow_id', 'resource_id', 'badge_id', 'state', 'stateUpdatedBy', 'stateUpdatedAt')
list_display_links = ['workflow_id']
ordering = ['resource_id', 'badge_id', 'workflow_id']
search_fields = ['resource_id', 'badge_id', 'state', 'stateUpdatedBy']

# Register your model here.
admin.site.register(Integration_Workflow, Integration_Workflow_Admin)
6 changes: 6 additions & 0 deletions Operations_Warehouse_Django/integration_badges/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class IntegrationbadgesConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'integration_badges'
Loading