This changeset reverts a change we had made previously where we accidentally locked down the ability for service admins to invite other users to their own service. This removes the platform admin user check and reverts it back to the proper permissions check (including adjusting the tests to account for this).
Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
This changeset removes webauthn from the Notify.gov admin app. We are not using webauthn at all in our implementation and will be looking at an entirely different authentication system in the near future.
Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
* Updated header and footer
* Moved files around and updated gulpfile to correct the build process when it goes to production
* Updated fonts
* Adjusted grid templating
* Adding images to assets
* Updated account pages, dashboard, and pages in message sending flow
* Updated the styling for the landing pages in the account section once logged in
* Updated header and footer
* Updated fonts
* Moved files around and updated gulpfile to correct the build process when it goes to production
* Adjusted grid templating
* Added images to assets
* Update app/templates/components/uk_components/footer/template.njk
Co-authored-by: Steven Reilly <stvnrlly@users.noreply.github.com>
It looks like, by default, Flask no longer makes full URLs, for example
`https://example.com/path`. Instead it does `/path`. This will still
work fine, and if anything is better because it reduces the number of
bytes of HTML we are sending.
It won’t mean that requests go over `http` instead of `https` without
the protocol because we set the appropriate HSTS header here:
0c57da7781/ansible/roles/paas-proxy/templates/admin.conf.j2 (L11)
This commit changes all our tests to reflect that URLs no longer have
the protocol and domain in them. `_external=True` is Flask’s way of
saying whether a URL should be generated with the domain and protocol
(`True`) or without it (`False`).
Again, I can’t find the changelog or diff where this was introuduced,
but if you’d like to go spelunking then here’s a starting point:
50374e3cfe/src/flask/helpers.py (L192)
At the moment if a user is pending we don’t show the ‘change’ link.
This is unhelpful because:
- there’s no way to remove this user
- there’s no way to change their phone number, if the reason that
they are still pending is because they’ve been unable to receive
the two factor code at the number they first provided
This commits adds test coverage for ther HTML in several of the forms
which had broken autofocus.
It means that if we make changes to the HTML which triggers autofocus in
the future it should be more obvious that something is depending on the
attributes being added/removed.
This wasn't adding anything now that we have two new and more specific
fixtures, `active_user_create_broadcasts_permission` and
`active_user_approve_broadcasts_permission`, that can be used instead.
`manage_templates` has now been removed from the `create_broadcasts`
permission, so this also adjusts the fixture for a user who can create
broadcasts.
At the moment we say that you either ‘add’ an alert or ‘send’ it.
This is confusing because:
- an alert isn’t received on people’s phones until it’s approved, so
this is really when it is ‘sent’ conceptually
- an alert can be rejected before anyone receives it, so the UI can say
an alert that no-one ever received was sent
This commit re-labels things so that the the first part of the process
is ‘creating’ the alert.
This makes all the permissions nice and distinct from each other. Adding
templates and adding alerts feel conceptually quite different things
(what are you adding the alert to?).
It will likely be the same people who have permission to create alerts
and edit templates (maybe someone in a comms role).
But combining the two permissions makes the options presented in the
form feel clunky because ‘alerts’ and ‘templates’ are conceptually quite
different.
So I think it makes sense to keep the templates permission the same as
it is for regular Notify services.
We've added new broadcast roles in the database (`create_broadcasts` and
`approve_broadcasts`).
Adding these has meant we've needed to do a bit of a rewrite of the roles and
permissions code since this had been based on the assumption that each
database permission only belongs to one admin role - this is no longer true.
This means that flipping the roles dict round to create a dict which
contains database permissions as the keys is no longer possible. We can't
necessarily tell which admin role someone has given a database permission.
To check if a user has an admin role given a list of database permissions,
the user must now have ALL the database permissions mapped to that role
(instead of just one). This works because no one has the `manage_users`
permission without also having the `manage_settings` (and similar for
the other admin roles which map to multiple database permissions).
Some test data was changed because it was using admin roles where
database permissions are actually used when the app is running. I've kept
the functionality of the `translate_permissions_from_db_to_admin_roles`
function passing through any unknown roles it is passed as an argument.
This is not necessary, so can be changed later if we decide it will not
ever be used. However, removing it would require updating a lot of
tests since the tests rely on this behaviour.
We don’t want a single person to have two accounts on an emergency
alerts service because it would let them circumvent the two eyes
approval process.
We can go some way to mitigating against this by stopping people using
common methods that email providers use to alias email addresses. These
are:
- being case insensitive
- being insensitive to the position or number of dots in the local part
of an email address
- using ‘plus addressing’
We already prevent the first one, this commit adds normalisation which
strip out the second two before doing the comparision with the current
user’s email address.
For most events this makes the purpose of each argument clearer at
the point the event is called. It's still worth having a function
for each event type, as this abstracts knowledge of the event label.
Using a schema approach will make adding new events easier.
In the next commit we'll DRY-up the duplication in the tests as well.
Previously we only had one test for SMS auth not being disabled on
the invite version of the form. This modifies that test to fully
check what's displayed, and adds two more for the edit version of
the form.
Previously we applied this restriction to Platform Admins, on the
assumption that all of them use a security key to log in. Rather
than making that assumption, we can explicitly check their login
method, which also supports rolling out the feature to more users.
We hide the radio field in the HTML for platform admins, as we don't
want anyone to be able to change their auth type. However, when the form
is validated, the form has a field called login_authentication that it
expects a value for. It silently fails as it complains that when the
user POSTed they didn't select a value for that radio field, but the
error message is on the radio fields that don't get displayed to the
user so they'd never know.
Fixing this is actually pretty hard.
We use this form in two places, one where we have a user to edit, one
where we are creating an invite from scratch. So sometimes we don't know
about a user's auth type. In addition, radio buttons are mandatory by
design, but now sometimes we don't just want to make it optional but
explicitly ignore the value being passed in? To solve this, remove the
field entirely from the form if the user is a platform admin. This means
that if the code in manage_users.py tries to access the
login_authentication value from the form, it'll error, but I think
that's okay to leave for now given we concede that this isn't a perfect
final solution.
The tests didn't flag this previously as they tried to set from sms_auth
(the default for `platform_admin_user`) TO email_auth or sms_auth. Also,
the diagnosis of this bug was confounded further by the fact that
`mock_get_users_by_service` sets what is returned by the API - the
service model then takes the IDs out of that response and calls
`User.get_user_by_id` for the matching ID (as in, the code only uses
get_users_by_service to ensure the user belongs to that service). This
means that we accidentally set the form editing the current user, as
when we log in we set `get_user_by_id` to return the user of our choice
This closes a security loophole, where the auth type of a Platform
Admin could be unwittingly changed when they accept an invite, or
by an admin of a service they are a member of.
We shouldn’t have a page where someone can look up any other user’s
email address based on their user ID.
We also don’t want a page where a malicious user could send someone an
link which would get them invited to the service.
Restricting the invite to be populated just from users in their own
organisation doesn’t mitigate against this stuff completely, but they
probably have a way of finding out the email address of someone in their
organisation already.
At the moment users must be invited to join a service. But this means:
- users must know that a service already exists
- they need to know who to ask for an invite
If the user doesn’t know these thing then sometimes they just go ahead
and set up a new service. Which means they have to get all the way to
the point of requesting to go live before we tell them that there’s
already a service with a similar name or purpose.
So we should let users:
1. discover what other services exist in their organisation
2. apply to join a service
3. automatically notify the service managers of their interest
4. be invited by a service manager
5. accept the invite
This commit implements step 4. We can just link them to the invite form
in step 3., but we should make it easy for them to send the invite,
without having to copy and paste email addresses.
So this commit let the invite form be pre-populated with an existing
user’s email address.