Example #1
0
	def save_model(self, request, obj, form, change):
		""" Audit project membership and qualifications when a user is saved. """
		super(UserAdmin, self).save_model(request, obj, form, change)
		record_local_many_to_many_changes(request, obj, form, "projects")
		record_local_many_to_many_changes(request, obj, form, "qualifications")
		record_local_many_to_many_changes(request, obj, form, "physical_access_levels")
		record_active_state(request, obj, form, "is_active", not change)
Example #2
0
	def save_model(self, request, obj, form, change):
		"""
		Audit project creation and modification. Also save any project membership changes explicitly.
		"""
		record_remote_many_to_many_changes_and_save(
			request, obj, form, change, "members", super(ProjectAdmin, self).save_model
		)
		# Make a history entry if a project has been moved under an account.
		# This applies to newly created projects and project ownership reassignment.
		if "account" in form.changed_data:
			# Create a membership removal entry for the project if it used to belong to another account:
			if change:
				previous_account = MembershipHistory()
				previous_account.authorizer = request.user
				previous_account.child_content_object = obj
				previous_account.parent_content_object = Account.objects.get(pk=form.initial["account"])
				previous_account.action = MembershipHistory.Action.REMOVED
				previous_account.save()

			# Create a membership addition entry for the project with its current account.
			current_account = MembershipHistory()
			current_account.authorizer = request.user
			current_account.child_content_object = obj
			current_account.parent_content_object = obj.account
			current_account.action = MembershipHistory.Action.ADDED
			current_account.save()

		# Record whether the project is active or not.
		record_active_state(request, obj, form, "active", not change)

		if "principal_investigators" in form.changed_data:
			obj.manager_set.set(form.cleaned_data["principal_investigators"])
Example #3
0
 def save_model(self, request, obj, form, change):
     """ Audit project membership and qualifications when a user is saved. """
     super(UserAdmin, self).save_model(request, obj, form, change)
     record_local_many_to_many_changes(request, obj, form, "projects")
     record_local_many_to_many_changes(request, obj, form, "qualifications")
     record_local_many_to_many_changes(request, obj, form,
                                       "physical_access_levels")
     record_active_state(request, obj, form, "is_active", not change)
     if "backup_owner_on_tools" in form.changed_data:
         obj.backup_for_tools.set(
             form.cleaned_data["backup_owner_on_tools"])
     if "superuser_on_tools" in form.changed_data:
         obj.superuser_for_tools.set(
             form.cleaned_data["superuser_on_tools"])
Example #4
0
	def save_model(self, request, obj, form, change):
		""" Audit account and project active status. """
		super(AccountAdmin, self).save_model(request, obj, form, change)
		record_active_state(request, obj, form, "active", not change)
Example #5
0
def create_or_modify_user(request, user_id):
    identity_service = get_identity_service()
    # Get access levels and sort by area category
    access_levels = list(PhysicalAccessLevel.objects.all().only(
        'name', 'area'))
    access_level_for_sort = list(
        set([
            ancestor for access in access_levels
            for ancestor in access.area.get_ancestors(include_self=True)
        ]))
    access_level_for_sort.sort(key=lambda x: x.tree_category())
    area_access_levels = Area.objects.filter(
        id__in=[area.id for area in access_level_for_sort])
    dict_area = {}
    for access in access_levels:
        dict_area.setdefault(access.area.id, []).append(access)

    dictionary = {
        'projects': Project.objects.filter(active=True, account__active=True),
        'tools': Tool.objects.filter(visible=True),
        'area_access_dict': dict_area,
        'area_access_levels': area_access_levels,
        'one_year_from_now': timezone.now() + timedelta(days=365),
        'identity_service_available': identity_service.get('available', False),
        'identity_service_domains': identity_service.get('domains', []),
    }
    try:
        user = User.objects.get(id=user_id)
    except:
        user = None

    timeout = identity_service.get('timeout', 3)
    site_title = get_customization('site_title')
    if dictionary['identity_service_available']:
        try:
            result = requests.get(urljoin(identity_service['url'], '/areas/'),
                                  timeout=timeout)
            if result.status_code == HTTPStatus.OK:
                dictionary[
                    'externally_managed_physical_access_levels'] = result.json(
                    )
            else:
                dictionary['identity_service_available'] = False
                warning_message = f"The identity service encountered a problem while attempting to return a list of externally managed areas. The administrator has been notified to resolve the problem."
                dictionary['warning'] = warning_message
                warning_message += ' The HTTP error was {}: {}'.format(
                    result.status_code, result.text)
                users_logger.error(warning_message)
        except Exception as e:
            dictionary['identity_service_available'] = False
            warning_message = f"There was a problem communicating with the identity service. {site_title} is unable to retrieve the list of externally managed areas. The administrator has been notified to resolve the problem."
            dictionary['warning'] = warning_message
            warning_message += ' An exception was encountered: ' + type(
                e).__name__ + ' - ' + str(e)
            users_logger.error(warning_message)
    elif identity_service:
        # display warning if identity service is defined but disabled
        dictionary[
            'warning'] = 'The identity service is disabled. You will not be able to modify externally managed physical access levels, reset account passwords, or unlock accounts.'

    if request.method == 'GET':
        dictionary['form'] = UserForm(instance=user)
        try:
            if dictionary[
                    'identity_service_available'] and user and user.is_active and user.domain:
                parameters = {
                    'username': user.username,
                    'domain': user.domain,
                }
                result = requests.get(identity_service['url'],
                                      parameters,
                                      timeout=timeout)
                if result.status_code == HTTPStatus.OK:
                    dictionary['user_identity_information'] = result.json()
                elif result.status_code == HTTPStatus.NOT_FOUND:
                    dictionary[
                        'warning'] = "The identity service could not find username {} on the {} domain. Does the user's account reside on a different domain? If so, select that domain now and save the user information.".format(
                            user.username, user.domain)
                else:
                    dictionary['identity_service_available'] = False
                    warning_message = 'The identity service encountered a problem while attempting to search for a user. The administrator has been notified to resolve the problem.'
                    dictionary['warning'] = warning_message
                    warning_message += ' The HTTP error was {}: {}'.format(
                        result.status_code, result.text)
                    users_logger.error(warning_message)
        except Exception as e:
            dictionary['identity_service_available'] = False
            warning_message = f"There was a problem communicating with the identity service. {site_title} is unable to search for a user. The administrator has been notified to resolve the problem."
            dictionary['warning'] = warning_message
            warning_message += ' An exception was encountered: ' + type(
                e).__name__ + ' - ' + str(e)
            users_logger.error(warning_message)
        return render(request, 'users/create_or_modify_user.html', dictionary)
    elif request.method == 'POST':
        form = UserForm(request.POST, instance=user)
        dictionary['form'] = form
        if not form.is_valid():
            return render(request, 'users/create_or_modify_user.html',
                          dictionary)

        # Remove the user account from the domain if it's deactivated, changed domain, or changed username...
        if dictionary['identity_service_available'] and user:
            no_longer_active = form.initial[
                'is_active'] is True and form.cleaned_data['is_active'] is False
            domain_switched = form.initial['domain'] != '' and form.initial[
                'domain'] != form.cleaned_data['domain']
            username_changed = form.initial['username'] != form.cleaned_data[
                'username']
            if no_longer_active or domain_switched or username_changed:
                parameters = {
                    'username': form.initial['username'],
                    'domain': form.initial['domain'],
                }
                try:
                    result = requests.delete(identity_service['url'],
                                             data=parameters,
                                             timeout=timeout)
                    # If the delete succeeds, or the user is not found, then everything is ok.
                    if result.status_code not in (HTTPStatus.OK,
                                                  HTTPStatus.NOT_FOUND):
                        dictionary['identity_service_available'] = False
                        users_logger.error(
                            'The identity service encountered a problem while attempting to delete a user. The HTTP error is {}: {}'
                            .format(result.status_code, result.text))
                        dictionary[
                            'warning'] = 'The user information was not modified because the identity service could not delete the corresponding domain account. The administrator has been notified to resolve the problem.'
                        return render(request,
                                      'users/create_or_modify_user.html',
                                      dictionary)
                except Exception as e:
                    dictionary['identity_service_available'] = False
                    users_logger.error(
                        'There was a problem communicating with the identity service while attempting to delete a user. An exception was encountered: '
                        + type(e).__name__ + ' - ' + str(e))
                    dictionary[
                        'warning'] = 'The user information was not modified because the identity service could not delete the corresponding domain account. The administrator has been notified to resolve the problem.'
                    return render(request, 'users/create_or_modify_user.html',
                                  dictionary)

        # Ensure the user account is added and configured correctly on the current domain if the user is active...
        if dictionary['identity_service_available'] and form.cleaned_data[
                'is_active']:
            parameters = {
                'username':
                form.cleaned_data['username'],
                'domain':
                form.cleaned_data['domain'],
                'badge_number':
                form.cleaned_data.get('badge_number', ''),
                'email':
                form.cleaned_data.get('email'),
                'access_expiration':
                form.cleaned_data.get('access_expiration'),
                'requested_areas':
                request.POST.getlist('externally_managed_access_levels'),
            }
            try:
                if len(parameters['requested_areas']
                       ) > 0 and not parameters['badge_number']:
                    dictionary[
                        'warning'] = 'A user must have a badge number in order to have area access. Please enter the badge number first, then grant access to areas.'
                    return render(request, 'users/create_or_modify_user.html',
                                  dictionary)
                result = requests.put(identity_service['url'],
                                      data=parameters,
                                      timeout=timeout)
                if result.status_code == HTTPStatus.NOT_FOUND:
                    dictionary[
                        'warning'] = 'The username was not found on this domain. Did you spell the username correctly in this form and did you select the correct domain? Ensure the user exists on the domain in order to proceed.'
                    return render(request, 'users/create_or_modify_user.html',
                                  dictionary)
                if result.status_code != HTTPStatus.OK:
                    dictionary['identity_service_available'] = False
                    users_logger.error(
                        'The identity service encountered a problem while attempting to modify a user. The HTTP error is {}: {}'
                        .format(result.status_code, result.text))
                    dictionary[
                        'warning'] = 'The user information was not modified because the identity service encountered a problem while creating the corresponding domain account. The administrator has been notified to resolve the problem.'
                    return render(request, 'users/create_or_modify_user.html',
                                  dictionary)
            except Exception as e:
                dictionary['identity_service_available'] = False
                users_logger.error(
                    'There was a problem communicating with the identity service while attempting to modify a user. An exception was encountered: '
                    + type(e).__name__ + ' - ' + str(e))
                dictionary[
                    'warning'] = 'The user information was not modified because the identity service encountered a problem while creating the corresponding domain account. The administrator has been notified to resolve the problem.'
                return render(request, 'users/create_or_modify_user.html',
                              dictionary)

        # Only save the user model for now, and wait to process the many-to-many relationships.
        # This way, many-to-many changes can be recorded.
        # See this web page for more information:
        # https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#the-save-method
        user = form.save(commit=False)
        user.save()
        record_active_state(request, user, form, 'is_active', user_id == 'new')
        record_local_many_to_many_changes(request, user, form,
                                          'qualifications')
        record_local_many_to_many_changes(request, user, form,
                                          'physical_access_levels')
        record_local_many_to_many_changes(request, user, form, 'projects')
        form.save_m2m()

        message = f"{user} has been added successfully to {site_title}" if user_id == 'new' else f"{user} has been updated successfully"
        messages.success(request, message)
        return redirect('users')
    else:
        return HttpResponseBadRequest('Invalid method')