diff --git a/blmcontacts.txt b/blmcontacts.txt new file mode 100755 index 0000000..5ea0ee9 --- /dev/null +++ b/blmcontacts.txt @@ -0,0 +1,29 @@ +david.tomalak@noaa.gov,David,Tomalak +woody.roberts@noaa.gov,Woody,Roberts +nnauslar@blm.gov,Nnauslar,Nnauslar +chaskell@blm.gov,Chaskell,Chaskell +cfdierking@alaska.edu,Cfdierking,Cfdierking +basil.newmerzhycky@usda.gov,Basil,Newmerzhycky +dborsum@blm.gov,Dborsum,Dborsum +rkrohn@blm.gov,Rkrohn,Rkrohn +eugene.berger@noaa.gov,Eugene,Berger +dan.nietfeld@noaa.gov,Dan,Nietfeld +kirk.l.holub@noaa.gov,Kirk,Holub +jebb.q.stewart@noaa.gov,Jebb,Stewart +scott.nahman@noaa.gov,Scott,Nahman +curtis.alexader@noaa.gov,Curtis,Alexader +bunnypfau@gmail.com,Bunnypfau,Bunnypfau +mvrencur@gmail.com,Mvrencur,Mvrencur +bernadette.pfau@noaa.gov,Bernadette,Pfau +michael.vrencur@noaa.gov,Michael,Vrencur +none@domain.tld,#None,None +tomalakd@msn.com,tomalakd,tomalakd +first.last@domain.tld,newFirst,Last +linus.kamb@noaa.gov,Linus,Kamb +jamie.r.rhome@noaa.gov,Jamie,Rhome +wallace.hogsett@noaa.gov,Wallace,Hogsett +taylor.trogdon@noaa.gov,Taylor,Trogdon +michael.j.brennan@noaa.gov,Michael,Brennan +pablo.santos@noaa.gov,Pablo,Santos +nathan.hardin@noaa.gov,Nathan,Hardin +nreimer@blm.gov,Nreimer,Nreimer diff --git a/db/setup_db2.sql b/db/setup_db2.sql new file mode 100755 index 0000000..a853ee2 --- /dev/null +++ b/db/setup_db2.sql @@ -0,0 +1,23 @@ +CREATE DATABASE IF NOT EXISTS ssop_dev2; + +CREATE ROLE IF NOT EXISTS 'app2_developer'; +CREATE ROLE IF NOT EXISTS 'app2_readonly'; +CREATE ROLE IF NOT EXISTS 'app2_readwrite'; + +GRANT ALL ON ssop_dev2.* TO 'app2_developer'; +GRANT SELECT ON ssop_dev2.* TO 'app2_readonly'; +GRANT INSERT, UPDATE, DELETE ON ssop_dev2.* TO 'app2_readwrite'; + +#CREATE USER IF NOT EXISTS 'kirkholub'@'localhost' IDENTIFIED BY 'KpwXW8ehnlRIrMLYBBfFeR2'; +#CREATE USER IF NOT EXISTS 'ucanread'@'localhost' IDENTIFIED BY 'ppu_X6LHcu7m0L'; +#CREATE USER IF NOT EXISTS 'ucanreadwrite'@'localhost' IDENTIFIED BY 'wvqUgFmGU3uyWYhwWI'; + +GRANT 'app2_developer' TO 'kirkholub'@'localhost'; +GRANT 'app2_readonly' TO 'ucanread'@'localhost'; +GRANT 'app2_readonly', 'app2_readwrite' TO 'ucanreadwrite'@'localhost'; + +SET DEFAULT ROLE ALL TO 'kirkholub'@'localhost'; +SET DEFAULT ROLE ALL TO 'ucanread'@'localhost'; +SET DEFAULT ROLE ALL TO 'ucanreadwrite'@'localhost'; + +FLUSH PRIVILEGES; diff --git a/requirements.txt b/requirements.txt index 4f97c4a..4271351 100755 --- a/requirements.txt +++ b/requirements.txt @@ -1,59 +1,59 @@ -aenum==3.1.15 -asgiref==3.7.2 -backports.zoneinfo==0.2.1 -beautifulsoup4==4.12.2 -boto3==1.28.28 -botocore==1.31.28 -bs4==0.0.1 -certifi==2023.7.22 -cffi==1.15.1 -charset-normalizer==3.1.0 -contourpy==1.1.0 -cryptography==41.0.1 -cycler==0.11.0 -diagrams==0.23.3 -Django==4.2.2 -django-extensions==3.2.3 -fonttools==4.40.0 -graphviz==0.20.1 -gunicorn==20.1.0 -idna==3.4 -importlib-resources==5.12.0 -isodate==0.6.1 -jdcal==1.4.1 -Jinja2==3.1.2 -jmespath==1.0.1 -kiwisolver==1.4.4 -lxml==4.9.2 -MarkupSafe==2.1.3 -matplotlib==3.7.1 -mysql-connector-python==8.0.33 -mysqlclient==2.2.0 -networkx==3.1 -numpy==1.25.0 -oauthlib==3.2.2 -onelogin==3.1.4 -packaging==23.1 -Pillow==9.5.0 -protobuf==3.20.3 -pyclean==2.7.3 -pycparser==2.21 -pydantic==1.10.9 -pydot==1.4.2 -PyJWT==2.7.0 -pyOpenSSL==23.2.0 -pyparsing==3.1.0 -python-dateutil==2.8.2 -python3-saml==1.15.0 -pytz==2023.3 -requests==2.31.0 -requests-oauthlib==1.3.1 -s3transfer==0.6.1 -six==1.16.0 -soupsieve==2.4.1 -sqlparse==0.4.4 -typed-ast==1.5.4 -typing_extensions==4.6.3 -urllib3==1.26.16 -xmlsec==1.3.13 -zipp==3.15.0 +aenum +asgiref +backports.zoneinfo +beautifulsoup4 +boto3 +botocore +bs4 +certifi +cffi +charset-normalizer +contourpy +cryptography +cycler +diagrams +Django +django-extensions +fonttools +graphviz +gunicorn +idna +importlib-resources +isodate +jdcal +Jinja2 +jmespath +kiwisolver +lxml +MarkupSafe +matplotlib +mysql-connector-python +mysqlclient +networkx +numpy +oauthlib +onelogin +packaging +Pillow +protobuf +pyclean +pycparser +pydantic +pydot +PyJWT +pyOpenSSL +pyparsing +python-dateutil +python3-saml +pytz +requests +requests-oauthlib +s3transfer +six +soupsieve +sqlparse +typed-ast +typing_extensions +urllib3 +xmlsec +zipp diff --git a/sites/admin.py b/sites/admin.py index 2b2b437..509f2d0 100755 --- a/sites/admin.py +++ b/sites/admin.py @@ -60,7 +60,7 @@ class OrganizationAdmin(admin.ModelAdmin): class ProjectAdmin(admin.ModelAdmin): #list_display = ('name', 'organization', 'enabled', 'expiretokens', 'return_to', 'queryparam', 'error_redirect', 'display_order', 'state', 'decrypt_key', 'graph_node_id') - list_display = ('name', 'organization', 'enabled', 'expiretokens', 'queryparam', 'return_to', 'error_redirect', 'contacts_url', 'users', 'decrypt_key', 'state', 'logoimg', 'showlogobin', 'display_order', 'state', 'decrypt_key', 'updated') + list_display = ('name', 'organization', 'enabled', 'expiretokens', 'queryparam', 'return_to', 'error_redirect', 'contacts_url', 'users', 'app_params', 'decrypt_key', 'state', 'logoimg', 'showlogobin', 'display_order', 'state', 'decrypt_key', 'updated') list_display_links = list_display #readonly_fields = ('state', 'updater') ordering = ('display_order', 'organization', 'name') diff --git a/sites/forms.py b/sites/forms.py index f086ad4..18f68f0 100755 --- a/sites/forms.py +++ b/sites/forms.py @@ -26,7 +26,7 @@ class ProjectAdminForm(forms.ModelForm): class Meta: model = Project #fields = '__all__' - field_order = ('name', 'organization', 'verbose_name', 'return_to', 'error_redirect', 'enabled', 'display_order', 'decrypt_key', 'logoimg', 'userlist', 'expiretokens', 'graphnode', 'state', 'queryparam', 'querydelimiter', ) + field_order = ('name', 'organization', 'verbose_name', 'return_to', 'error_redirect', 'enabled', 'display_order', 'decrypt_key', 'logoimg', 'userlist', 'app_params', 'expiretokens', 'graphnode', 'state', 'queryparam', 'querydelimiter', ) fields = field_order diff --git a/sites/management/commands/add_contacts_list.py b/sites/management/commands/add_contacts_list.py new file mode 100755 index 0000000..d58be05 --- /dev/null +++ b/sites/management/commands/add_contacts_list.py @@ -0,0 +1,27 @@ +""" +Add a list of ontacts if they do not exits. This placeholder is required to make the GUI happy. +""" +from __future__ import unicode_literals + + +# https://stackoverflow.com/questions/19475955/using-django-models-in-external-python-script +from django.core.management.base import BaseCommand + +from sites.models import add_contacts_list + +class Command(BaseCommand): + help = "adds a list of Contacts from a list of email, fistname, lastname" + + def add_arguments(self, parser): + parser.add_argument('filename', type=str) + + def handle(self, *args, **options): + + filename = options['filename'] + print('filename: ' + filename) + + fp = open(filename, 'r') + userlist = fp.read() + fp.close + add_contacts_list(userlist) + diff --git a/sites/management/commands/contacts_list.txt b/sites/management/commands/contacts_list.txt new file mode 100755 index 0000000..7d605e2 --- /dev/null +++ b/sites/management/commands/contacts_list.txt @@ -0,0 +1,29 @@ +| david.tomalak@noaa.gov | David | Tomalak | +| woody.roberts@noaa.gov | Woody | Roberts | +| nnauslar@blm.gov | Nnauslar | Nnauslar | +| chaskell@blm.gov | Chaskell | Chaskell | +| cfdierking@alaska.edu | Cfdierking | Cfdierking | +| basil.newmerzhycky@usda.gov | Basil | Newmerzhycky | +| dborsum@blm.gov | Dborsum | Dborsum | +| rkrohn@blm.gov | Rkrohn | Rkrohn | +| eugene.berger@noaa.gov | Eugene | Berger | +| dan.nietfeld@noaa.gov | Dan | Nietfeld | +| kirk.l.holub@noaa.gov | Kirk | Holub | +| jebb.q.stewart@noaa.gov | Jebb | Stewart | +| scott.nahman@noaa.gov | Scott | Nahman | +| curtis.alexader@noaa.gov | Curtis | Alexader | +| bunnypfau@gmail.com | Bunnypfau | Bunnypfau | +| mvrencur@gmail.com | Mvrencur | Mvrencur | +| bernadette.pfau@noaa.gov | Bernadette | Pfau | +| michael.vrencur@noaa.gov | Michael | Vrencur | +| none@domain.tld | #None | None | +| tomalakd@msn.com | tomalakd | tomalakd | +| first.last@domain.tld | newFirst | Last | +| linus.kamb@noaa.gov | Linus | Kamb | +| jamie.r.rhome@noaa.gov | Jamie | Rhome | +| wallace.hogsett@noaa.gov | Wallace | Hogsett | +| taylor.trogdon@noaa.gov | Taylor | Trogdon | +| michael.j.brennan@noaa.gov | Michael | Brennan | +| pablo.santos@noaa.gov | Pablo | Santos | +| nathan.hardin@noaa.gov | Nathan | Hardin | +| nreimer@blm.gov | Nreimer | Nreimer | diff --git a/sites/management/commands/copy_gsl_packs_and_apps.py b/sites/management/commands/copy_gsl_packs_and_apps.py new file mode 100755 index 0000000..0ff7425 --- /dev/null +++ b/sites/management/commands/copy_gsl_packs_and_apps.py @@ -0,0 +1,17 @@ +# https://stackoverflow.com/questions/19475955/using-django-models-in-external-python-script +from django.core.management.base import BaseCommand +import secrets + +class Command(BaseCommand): + help = "generates a random token of a given length; default=64" + + def add_arguments(self, parser): + parser.add_argument('len', type=int) + + def handle(self, *args, **options): + + tokenlen = options['len'] + token = secrets.token_urlsafe(tokenlen) + print(token) + + diff --git a/sites/models.py b/sites/models.py index e2fde55..fa37499 100755 --- a/sites/models.py +++ b/sites/models.py @@ -215,6 +215,18 @@ def add_none_contact(): newcontact = Contact.objects.create(email=settings.NONE_EMAIL) newcontact.save() +def add_contacts_list(userlist): + for line in userlist.split('\n'): + line = str(line) + msg = "line: " + line + if "," in line: + logger.info(msg) + email, firstname, lastname = line.split(',') + qs = Contact.objects.filter(email=email) + if qs.count() == int(0): + newcontact = Contact.objects.create(email=email, firstname=firstname, lastname=lastname) + newcontact.save() + def hash_to_fingerprint(data): dkeys = [] for k in data.keys(): @@ -358,7 +370,7 @@ def save(self, *args, **kwargs): class Contact(models.Model): firstname = models.CharField(max_length=150, default='firstname') lastname = models.CharField(max_length=150, default='lastname') - email = models.EmailField(null=True, blank=True) + email = models.EmailField(null=True, blank='noemail@default.tld') def __str__(self): return self.firstname + ' ' + self.lastname + ' (' + str(self.email) + ')' @@ -405,8 +417,10 @@ class Project(models.Model): logoimg = models.ImageField(upload_to = get_upload_path, verbose_name="Logo Image", null=True, blank=True, help_text=mark_safe(settings.HELP_LOGOIMG)) logobin = models.BinaryField(null=True, blank=True) userlist = models.ManyToManyField('sites.Contact', related_name='project_userlist', help_text=mark_safe(settings.HELP_USERLIST)) + app_params = models.TextField(max_length=4096, null=True, default='{}', help_text=mark_safe(settings.HELP_APP_PARAMS)) #field_order = ('name', 'organization', 'verbose_name', 'return_to', 'error_redirect', 'enabled', 'display_order', 'decrypt_key', 'logoimg', 'userlist', 'expiretokens', 'graphnode', 'state', 'queryparam', 'querydelimiter', ) + #field_order = ('name', 'organization', 'verbose_name', 'return_to', 'error_redirect', 'enabled', 'display_order', 'decrypt_key', 'logoimg', 'expiretokens', 'graphnode', 'state', 'queryparam', 'querydelimiter', ) def __str__(self): return self.name @@ -451,28 +465,28 @@ def initstate(self): destination_filename = pdir + '/logo' filetype = None + imgpath = None try: imgpath = self.logoimg.path + for ft in settings.LOGO_FILETYPES: + if str(imgpath).endswith(ft): + filetype = ft + break + msg = " filetype is: " + str(filetype) + logger.info(msg) + if filetype: + if os.path.exists(imgpath): + os.rename(imgpath, destination_filename) + fp = open(destination_filename, 'rb') + self.logobin = fp.read() + fp.close() + need_to_save = True except ValueError as ve: imgpath = ' ve: ' + str(ve) except SuspiciousFileOperation as sfo: imgpath = ' sfo: ' + str(sfo) msg = " imgpath is: " + str(imgpath) logger.info(msg) - for ft in settings.LOGO_FILETYPES: - if str(imgpath).endswith(ft): - filetype = ft - break - msg = " filetype is: " + str(filetype) - logger.info(msg) - if filetype: - if os.path.exists(imgpath): - os.rename(imgpath, destination_filename) - fp = open(destination_filename, 'rb') - self.logobin = fp.read() - fp.close() - - need_to_save = True if not settings.DEBUG: if not self.expiretokens: @@ -556,6 +570,9 @@ def showlogobin(self): def get_logobin(self): return self.logobin + def get_app_params(self): + return self.app_params + def users(self): users = [] for a in self.userlist.get_queryset(): @@ -569,6 +586,30 @@ def users(self): retstr = str(len(users)) + " users" return retstr + def authorized(self, uu): + msg = " authorized uu: " + str(uu) + logger.info(msg) + #uu = ast.literal_eval(uustr) + #msg = " uu: " + str(uu) + #logger.info(msg) + auth = False + try: + email = uu['email'] + except KeyError: + email = 'noemail' + email = str(email).lower() + msg = " email: " + str(email) + logger.info(msg) + for a in self.userlist.get_queryset(): + msg = " a: " + str(a) + logger.info(msg) + if email in str(a).lower(): + auth = True + break + msg = " authorized auth: " + str(auth) + logger.info(msg) + return auth + def contact_emails(self): users = [] for a in self.userlist.get_queryset(): @@ -690,13 +731,18 @@ def get_token(self): if (utcnow < self.expires): self.accessed = utcnow - mindt = datetime.datetime.combine(datetime.date.min, datetime.time.min) - self.expires = mindt.replace(tzinfo=pytz.UTC) + #mindt = datetime.datetime.combine(datetime.date.min, datetime.time.min) + #self.expires = mindt.replace(tzinfo=pytz.UTC) self.save() return str(self.token) else: return str('EXPIRED') + def expire_token(self): + mindt = datetime.datetime.combine(datetime.date.min, datetime.time.min) + self.expires = mindt.replace(tzinfo=pytz.UTC) + self.save() + class Connection(models.Model): name = models.CharField(max_length=150, default='setme') @@ -738,17 +784,25 @@ def get_connection_state(self): return str(self.connection_state) def get_ca(self): - ca = {} - for fp in self.attrsgroup.attributes().split(','): - at = ast.literal_eval(get_attributesFromFp(fp)) - for k in at.keys(): - ca[k] = at[k] + ca = [] + msg = " model -- get_ca()" + logger.info(msg) + for a in self.attrsgroup.get_attrs(): + msg = " model -- get_ca() -- a: " + str(a) + logger.info(msg) + ca.append(a.get_attributes()) return ca def get_request_attributes(self): + msg = " model -- get_request_attributes()" + logger.info(msg) attributes = [] - ca = self.get_ca() - attributes.append(('requestattrs: ', str(ca))) + for ca in self.get_ca(): + msg = " ca: " + str(ca) + logger.info(msg) + attributes.append(ca) + msg = " attributes: " + str(attributes) + logger.info(msg) return attributes def get_ua(self): @@ -965,7 +1019,7 @@ def get_fields(self): class Organization(models.Model): name = models.CharField(max_length=50, null=True, default='unknownOrganization') userlist = models.ManyToManyField('sites.Contact', related_name='organization_userlist') - projects = models.ManyToManyField(Project, related_name='orgs_projects') + projects = models.ManyToManyField(Project, related_name='organization_projects') updated = models.DateTimeField(auto_now_add=True) graphnode = models.ForeignKey('sites.GraphNode', null=True, blank=True, on_delete=models.SET_NULL) @@ -1056,7 +1110,6 @@ def get_fields(self): retlist.append((k,v)) return retlist - #def graph_node_id(self): # nid = str(-1) # if self.graphnode is not None: diff --git a/sites/views.py b/sites/views.py index cb3c189..d9861d4 100755 --- a/sites/views.py +++ b/sites/views.py @@ -260,16 +260,6 @@ def ldg_authenticated(request): except KeyError: pass - try: - connattrsgroup = attributeGroupFromAttributes(conngrouptype, connattrslist) - except KeyError: - msg = " no connattrsgroup" - logger.info(msg) - - if settings.VERBOSE: - msg = " ldg_authenticated request: " + str(request) - logger.info(msg) - state = 'notautenticated' project_state = settings.LOGINDOTGOV_LOGIN_STATE # first 10 digits of start the are utc seconds @@ -305,6 +295,23 @@ def ldg_authenticated(request): attributes.append(('return_to', return_to)) attributes.append(('error_redirect', error_redirect)) attributes.append(('state', state)) + app_params = qs.get_app_params() + msg = " app_params: " + str(app_params) + logger.info(msg) + aleap = ast.literal_eval(app_params) + msg = " aleap: " + str(aleap) + logger.info(msg) + for alk in aleap.keys(): + atmp = {} + atmp[alk] = aleap[alk] + attributes.append(atmp) + temp = str(atmp).encode() + tempfp = md5(temp).hexdigest() + encrypted_temp = fernet.encrypt(temp) + tempattrs = attributesFromDecodedFp(tempfp, encrypted_temp) + connattrslist.append(tempattrs) + msg = " connection attrslist append: " + str(tempattrs) + logger.info(msg) if settings.VERBOSE: msg = " state: " + str(state) @@ -399,12 +406,14 @@ def ldg_authenticated(request): for attr in attstr.split(','): attr = attr.replace('{', '') attr = attr.replace('}', '') - msg = " attr = " + str(attr) - logger.info(msg) + if settings.VERBOSE: + msg = " attr = " + str(attr) + logger.info(msg) v = str(attr).split(':') - msg = " v = " + str(v) - logger.info(msg) + if settings.VERBOSE: + msg = " v = " + str(v) + logger.info(msg) try: key = str(v[0]).replace('"', '', 10) @@ -428,21 +437,38 @@ def ldg_authenticated(request): nameattrsgroup = attributeGroupFromAttributes(namegrouptype, uuattrslist) - uufp = hash_to_fingerprint(uu) - uniqueuser = uuFromFp(uufp, nameattrsgroup, connattrsgroup) - authtoken = get_authtoken(accesstoken) + authorized = project.authorized(uu) + msg = " uu " + str(uu) + " is " + str(authorized) + logger.info(msg) - connection = Connection(project=project, attrsgroup=connattrsgroup, token=authtoken, connection_state=connection_state, uniqueuser=uniqueuser) - connection.save() + try: + connattrsgroup = attributeGroupFromAttributes(conngrouptype, connattrslist) + except KeyError: + msg = " no connattrsgroup" + logger.info(msg) - # update the connections map - #(imageattributes, debugprint) = make_connections_by_project_img() if settings.VERBOSE: - msg = " authtoken: " + str(authtoken) - logger.info(msg) - msg = " attributes: " + str(attributes) + msg = " ldg_authenticated request: " + str(request) logger.info(msg) + if project.authorized(uu) or settings.DEFAULT_PROJECT_NAME in project.name: + uufp = hash_to_fingerprint(uu) + uniqueuser = uuFromFp(uufp, nameattrsgroup, connattrsgroup) + authtoken = get_authtoken(accesstoken) + + connection = Connection(project=project, attrsgroup=connattrsgroup, token=authtoken, connection_state=connection_state, uniqueuser=uniqueuser) + connection.save() + + # update the connections map + #(imageattributes, debugprint) = make_connections_by_project_img() + if settings.VERBOSE: + msg = " authtoken: " + str(authtoken) + logger.info(msg) + msg = " attributes: " + str(attributes) + logger.info(msg) + else: + authtoken = 'no-accesstoken-for-uu:' + if RETURN_TO: request.session["Authorization"] = "Bearer " + str(authtoken) if project.append_access_token(): @@ -528,10 +554,12 @@ def project_userlist(request, projectname): now = datetime.datetime.now() now = now.replace(tzinfo=pytz.UTC) - html = "
Oops... It is now %s." % now + #html = "Oops... It is now %s." % now + html = '{"Oops": "It is now %s"}' % now for p in Project.objects.all(): if str(p.state).startswith(projectname): - html = '{"updated": "' + str(p.updated) + '", "userlist": "' + str(p.contact_emails()) + '"}' + #html = '
{"updated": "' + str(p.updated) + '", "userlist": "' + str(p.contact_emails()) + '"}' + html = '{"updated": "' + str(p.updated) + '", "userlist": "' + str(p.contact_emails()) + '"}' continue return HttpResponse(html) @@ -772,10 +800,10 @@ def redact_ua(ua): qs[0].redact_attr() def attrsjwt(request, access_token = None): - #msg = " attrsjwt -- request = " + str(request) - #logger.info(msg) - #msg = " attrsjwt -- access_token = " + str(access_token) - #logger.info(msg) + msg = " attrsjwt -- request = " + str(request) + logger.info(msg) + msg = " attrsjwt -- access_token = " + str(access_token) + logger.info(msg) signedattributes = None if access_token: @@ -788,21 +816,20 @@ def attrsjwt(request, access_token = None): connection = cqs[0] # disabled for debugging -- remember it is a one time token - fetchedtoken = None - if connection.project.expiretokens: - fetchedtoken = connection.token.get_token() - if str(fetchedtoken) not in str(authtoken): - msg = "fetchedtoken not equal authtoken for " + str(fetchedtoken) + " and " + str(authtoken) - logger.info(msg) - signedattributes = fetchedtoken - fetchedtoken = None - - if fetchedtoken: + fetchedtoken = connection.token.get_token() + if str(fetchedtoken) not in str(authtoken): + msg = "fetchedtoken not equal authtoken for " + str(fetchedtoken) + " and " + str(authtoken) + logger.info(msg) + signedattributes = fetchedtoken + fetchedtoken = None + else: + if connection.project.expiretokens: + connection.token.expire_token() encode_key = connection.project.get_decode_key() user_attributes = connection.get_user_attributes() - #msg = " connection get_user_attributes(): " + str(user_attributes) - #logger.info(msg) - + msg = " user_attributes: " + str(user_attributes) + logger.info(msg) + dar = Fernet(settings.DATA_AT_REST_KEY_ATTRS) alldecrypted = '\n' for ua in user_attributes: @@ -815,33 +842,54 @@ def attrsjwt(request, access_token = None): #msg = " decrypteddata: " + str(decrypteddata) #logger.info(msg) alldecrypted = decrypteddata + ',' + alldecrypted + + request_attributes = connection.get_request_attributes() + msg = " request_attributes: " + str(request_attributes) + logger.info(msg) + for ra in request_attributes: + #msg = ' request_attribute ra: ' + str(ra) + #logger.info(msg) + aledar = ast.literal_eval(ra) + msg = ' aledar: ' + str(aledar) + logger.info(msg) + dataatrest = bytes_in_string(aledar) + #msg = ' dataatrest: ' + str(dataatrest) + #logger.info(msg) + + decrypteddata = dar.decrypt(dataatrest).decode() + msg = " decrypteddata: " + str(decrypteddata) + logger.info(msg) + if decrypteddata.startswith('{') and decrypteddata.endswith('}'): + alldecrypted = decrypteddata + ',' + alldecrypted #if fetchedtoken: # redact_ua(ua) if len(alldecrypted) > int(1): alldecrypted = alldecrypted[:-2] - #msg = " alldecrypted: " + str(alldecrypted) - #logger.info(msg) + msg = " alldecrypted: " + str(alldecrypted) + logger.info(msg) dit = Fernet(encode_key) data_in_transit = dit.encrypt(alldecrypted.encode()) - #msg = " data_in_transit: " + str(data_in_transit) - #logger.info(msg) + msg = " data_in_transit: " + str(data_in_transit) + logger.info(msg) attrs = {} attrs['dit'] = str(data_in_transit) - #msg = " attrs = " + str(attrs) - #logger.info(msg) + msg = " attrs = " + str(attrs) + logger.info(msg) signedattributes = jwt.encode(attrs, settings.JWT_PRIVATE_KEY, algorithm="RS256") - #msg = " leaving attrsjwt -- access_token = " + str(access_token) - #logger.info(msg) - #msg = " attrsjwt -- signedattributes = " + str(signedattributes) - #logger.info(msg) -# else: -# msg = " cqs.count() is zero for access_token " + str(access_token) -# logger.info(msg) + msg = " leaving attrsjwt -- access_token = " + str(access_token) + logger.info(msg) + msg = " attrsjwt -- signedattributes = " + str(signedattributes) + logger.info(msg) + else: + msg = " cqs.count() is zero for access_token " + str(access_token) + logger.info(msg) + msg = " attrsjwt -- return signedattributes " + str(signedattributes) + logger.info(msg) return render(request, 'signedattrs.html', {'attributes': signedattributes}) def at2uu(request, access_token = None): diff --git a/ssop/settings.py b/ssop/settings.py index 728a899..c4214f0 100755 --- a/ssop/settings.py +++ b/ssop/settings.py @@ -58,11 +58,9 @@ def get_secret(key): # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -DEBUG_SAML_DEBUG = True -VERBOSE = True +DEBUG_SAML_DEBUG = False +VERBOSE = False -# Causes 'subject' field to be redacted -- useful for demonstration -DEMOMODE = True # Organization structure ALL_ORGS_BY_ID = { @@ -88,7 +86,7 @@ def get_secret(key): "modelslist": [], "viewmodels": ["About", "Attributes", "AttributeGroup", "AuthToken", "Connection", "Contact", "Organization", "Project", "Sysadmin", "Uniqueuser"] }, - "cn=_OAR GSL ITS SSG-GSL,cn=groups,cn=nems,ou=apps,dc=noaa,dc=gov": { + "cn=_OAR GSL Sysadm,cn=groups,cn=nems,ou=apps,dc=noaa,dc=gov": { "modelslist": ["Contact", "Key", "Organization", "Project", "Room"], "viewmodels": ["About", "Attributes", "AttributeGroup", "AuthToken", "Connection", "Sysadmin", "Uniqueuser"] }, @@ -105,9 +103,10 @@ def get_secret(key): AUTH_SAML_USER_FLAGS_BY_GROUP = { "is_active": "cn=_OAR ALL,cn=groups,cn=nems,ou=apps,dc=noaa,dc=gov", "is_staff": "cn=_OAR ALL,cn=groups,cn=nems,ou=apps,dc=noaa,dc=gov", - "is_sysadmin": "_OAR GSL ITS SSG-GSL,cn=groups,cn=nems,ou=apps,dc=noaa,dc=gov", + "is_sysadmin": "_OAR GSL Sysadm,cn=groups,cn=nems,ou=apps,dc=noaa,dc=gov", "is_ssopadmin": "cn=_OAR ESRL GSL SSOPAdmin,cn=groups,cn=nems,ou=apps,dc=noaa,dc=gov" } +# "is_sysadmin": "_OAR GSL ITS SSG-GSL,cn=groups,cn=nems,ou=apps,dc=noaa,dc=gov", # NOTE: mapping is case sensitive AUTH_SAML_USER_ATTR_MAP = { @@ -115,6 +114,8 @@ def get_secret(key): "member": "isMemberOf" } + + SSOP_SYSADS = {} #SSOP_SYSADS = { # 'holubdev': {'type': 'localdev', 'email': 'kirk.l.holub@gmail.com', 'homeorg': 'noaa', 'divisions': ['oar', 'gsl', 'gsl-its']}, @@ -349,16 +350,17 @@ def get_secret(key): # } #} -DATABASENAME = 'ssop_dev' +DATABASENAME = 'ssop_dev2' DATABASEUSERNAME = 'ucanreadwrite' DATABASEMIGRATIONUSERNAME = 'kirkholub' DBPWD = get_secret('DATABASE_SECRET') MIGRATIONPWD = get_secret('MIGRATION_SECRET') -# For initial setup -DATABASEUSERNAME = DATABASEMIGRATIONUSERNAME -DBPWD = MIGRATIONPWD +# For initial setup or DB schema updates +#DATABASEUSERNAME = DATABASEMIGRATIONUSERNAME +#DBPWD = MIGRATIONPWD + # https://www.laurencegellert.com/2019/03/making-djangos-database-connection-more-secure-for-migrations/ DATABASES = { @@ -454,6 +456,7 @@ def get_secret(key): LDG_BASE = 'https://gsl.noaa.gov/ssopsb/' LDG_POSTFIX = '/' + # A known parameter return on auth sucess .... can be whatever we want as long as its > 22 chars LOGINDOTGOV_LOGIN_STATE = '2.7182818284590452353602874' LOGINDOTGOV_LOGOUT_STATE = '1.618033988749894848204586' @@ -520,7 +523,7 @@ def get_secret(key): HELP_USERLIST = "A list of authorized users. Use cmd-click to select multiple users. Click + to add a new Contact." HELP_GRAPHNODE = "Used for connection graphing. Automatically generated when needed." HELP_LOGOIMG = "An image used for the Project's tile on the main page. Types are limited to: " + LOGO_FILETYPESTR + ". The image will be resized using a square aspect ratio." - +HELP_APP_PARAMS = "Optional field for application use. Defaults is an empty dictionary." # CWD_PREV = "uploads/ncocwd.txt" CWD_URL = "https://www.nco.ncep.noaa.gov/status/cwd/" diff --git a/templates/base.html b/templates/base.html index 5462f91..f97eadb 100755 --- a/templates/base.html +++ b/templates/base.html @@ -15,10 +15,10 @@ {% endblock %} - - + + - + diff --git a/uploads/ncocwd.txt b/uploads/ncocwd.txt index 3d45b00..da4f9c5 100755 --- a/uploads/ncocwd.txt +++ b/uploads/ncocwd.txt @@ -135,7 +135,7 @@