A mailer, member database, and so much more, for digital activism.
From version 20.11 onwards, there is a range of permissions you can grant to users with custom roles. Here is the current list of permissions relevant to members (as opposed to API users):
Permission name | Description |
---|---|
super_admin | Special: this grants all other permissions. Not recommended. |
send_sms | Allows sending SMS messages |
sms | Allows viewing and editing SMS messages before sending (usually used alongside send_sms) |
imports | Allows importing data (accessed via Admin > Settings > Imports), can import members, actions or donations |
manage_variables | Allows managing variables, accessed via Admin > Settings > Variables |
read_mailings | Allows reading mailings which have already been sent |
send_mailings | Allows sending mailings, includes editing, sending samples, scheduling and making recurring mailings |
manage_members | deprecated: use more granular member permissions instead (note: if you previously had this permission enabled, the migration enabled the more granular permissions instead) |
view_members | Allows viewing a single member, searching for a member by email or name. |
update_member_details | Allows updating a member’s details. Can update name, address, notes, member actions and phone numbers |
update_member_subscriptions | Allows toggling a member’s subscriptions (email, SMS, phone etc.) on or off, and unsubscribing permanently |
anonymize_members | Allows anonymizing (AKA ‘ghosting’) a single member, button appears on the member view page |
bulk_update_members | Allows certain bulk member operations (via lists and searches). Includes bulk subscription updating, bulk tag updates and bulk phone number operations |
push_members_to_service | Allows pushing members to a service |
manage_searches | Allows viewing, creating, editing and pushing to list for searches |
upload_lists | Allows creating a new list by submitting emails, phone numbers, IDs or GUIDs |
read_lists | Allows viewing all lists. (NOTE: Anyone can delete a list they created. Only super admins can delete other people’s lists) |
download_lists | Allows downloading a full list export |
anonymize_lists | Allows anonymizing (AKA ‘ghosting’) a list of members (can only be done on lists smaller than Settings.ghoster.bulk_max_members, which is 1,000 by default) |
view_job_status | Allows viewing job statuses, accessed via Admin > Settings > Job Statuses |
You’ll need to use a rails console to create a custom role, with your desired permissions enabled. Here’s an example “staff” role with a wide range of permissions, but lacking the ability to perform some super admin and bulk operations:
Role.create!(description: 'Staff role', view_members: true, update_member_details: true, update_member_subscriptions: true, manage_searches: true, read_mailings: true, send_mailings: true, send_sms: true, sms: true, upload_lists: true, read_lists: true, view_job_status: true)
After you’ve created your custom role or roles, you can use it when adding new admin users. Updating an existing user’s role can be done with the rails console.
Permission slugs are now permission booleans/attributes saved on roles. Any deployment which was updated to work with the update in July 2020 will still work, DB migrations will look after the translation from slugs to booleans. For orgs doing an update from 20.06.1 or earlier to this version or later, you can follow the same instructions with just one change, if you are creating API users with multiple permissions, follow this pattern (note the underscores _ instead of dashes - ):
speakout_user = APIUser.find_by(name: 'speakout')
speakout_user.update!(Role.create!(description: 'speakout api user')) if speakout_user.role.blank?
speakout_user.role.update!(members_api: true, donations_api: true, actions_api: true)
The following webhook and other API endpoints are being tightened up in this release:
endpoint/s | Previous security | New security | Permission slug |
---|---|---|---|
/nexmo/api/inbound_sms |
None | token check | nexmo-webhook |
/plivo/api/inbound_sms |
None | token check + HMAC check | plivo-webhook |
/twilio/api/inbound_sms |
None | token check + HMAC check | twilio-webhook |
/paypal/ipn |
None | token check | paypal-webhook |
/go_cardless/webhook |
HMAC check | token check + HMAC check | go-cardless-webhook |
/stripe/webhook |
HMAC check | token check + HMAC check | stripe-webhook |
/razorpay/webhook |
HMAC check | token check + HMAC check | razorpay-webhook |
/api/ctrlshift_webhook |
IP restricted + (any) token check | IP restricted + token check | csl-webhook |
/api/groups |
None | token check | groups-api |
/api/lists |
None | token check | lists-api |
/api/lists/* |
(any) token check | token check | lists-api |
/api/actions (used by speakout) |
None | token check | actions-api |
api/member_actions/* except /api/member_actions/feed |
(any) token check | token check | actions-api |
/api/alexa/flash-briefing |
None | token check | actions-api |
/api/campaigns/* |
(any) token check | token check | actions-api |
/api/consents/ |
(any) token check | token check | members-api |
/api/contributions/create (used by speakout) |
None | token check | donations-api |
/api/events/upsert & /api/events_rsvp/upsert |
(any) token check | token check | events-api |
/api/issues/list & /api/issue_categories/list (used by speakout) |
(any) token check | token check | actions-api |
/api/mailjet/feedback-loop |
(any) token check | token check | mailjet-api |
/api/member/* (used by speakout) |
(any) token check | token check | members-api |
/api/regular_donations/create |
(any) token check | token check | donations-api |
/api/searches/* |
(any) token check | token check | searches-api |
/api/subscriptions/* |
(any) token check | token check | member-subscriptions-api |
mailings/api/mailings/* except mailings/api/mailings/feedback-loop |
(any) token check | token check | mailings-api |
It’s best to pay attention to these two settings:
These are both true
by default. The simplest process is to add env variables for both set to false before deploying these changes:
heroku config:set REQUIRE_TOKEN_FOR_ALL_API_ROUTES=false REQUIRE_ROLE_FOR_ALL_API_USERS=false
Once deployed, if your log level is set at ‘warn’ or higher, you will see messages about your api routes being accessed without tokens, you can find them by searching for “Webhook endpoint in use without api token verification” and “Api Token in use with no role”. For each of the external services you use, you need to setup an APIUser with the correct permission. Here’s an example with the nexmo permission:
> APIUser.create_with_permission!('nexmo-webhook', name: 'nexmo', active: true).token
Now grab the token, and add it the end of the webhook saved in your 3rd party service with ?api_token=
. For example your nexmo URL might look like https://<your_identity_domain>/nexmo/api/inbound_sms?api_token=0b61e8905bd247715d53ffb76b6f71c4c2a7c337eb6f8e8c70ec8e47f4ff09703c24b0a9b8463ccd8ba6b3c3748898605d9f3b1848276c9310068b2534b09eba
.
Repeat this with all the endpoints you’re using. It’s best to leave your setup open for another day or two and keep an eye on your logs to see if any warnings are still coming through. Once you’re happy, remove your environment variables holding the endpoints open:
heroku config:unset REQUIRE_TOKEN_FOR_ALL_API_ROUTES REQUIRE_ROLE_FOR_ALL_API_USERS
If you already have an APIUser in use by speakout, you can give it the necessary permissions like this:
speakout_user = APIUser.find_by(name: 'speakout')
speakout_permissions = %w(members-api donations-api actions-api).map { |slug| Permission.find_by!(permission_slug: slug) }
speakout_user.update!(role: Role.create!(description: 'speakout api user', permissions: speakout_permissions))
Other common examples: | Application | Permissions needed | |———————-|—————————————| | Speakout | members-api donations-api actions-api | | CSL (id integration) | members-api | | CSL (webhooks) | csl-webhook | | ECC | mailings-api searches-api lists-api | | Analytics | No API access needed |
It is recommended that all API users are restricted to only those API endpoints they need to use for their functionality. In this way, even a token with substantial access (to, for example, update members and actions) cannot be used for other purposes without explicit changes by an identity admin. This is particularly important with the consideration of potential future API endpoints with new permissions.
However, if an org considers the risk acceptable, they can configure API Users with a super-admin
permission, granting access to all current and future API endpoints. As this configuration is discouraged, it is not enabled by default so before creating an API User role with the super-admin
permission, you must enable Settings.app.allow_super_api_users
either via your org Settings file or the ALLOW_SUPER_API_USERS
environment variable.
All identity controllers must call authorize unless they have skip_after_action :verify_authorized_with_fallback
instead. As of this writing, these are the only publicly accessible identity endpoints:
/login
, /logout
, /setup_two_factor
, /two_factor
, /register
, /complete_registration
, /reset-password
, /choose-new-password
(security handled separately via emailed reset token), /login_status
/api/area_zips/pcon_new
/api/postcodes/postcode
/api/postcodes/constituency_postcodes
/api/cors/login_status
(restricted to Settings.app.cors_origins domains, does not return any data other than login status (true/false))/api/member_actions/feed
/change_log
/clicks/link/:mailing_id(/:guid(/:action_id))
/clicks/text-blast/:text_blast_id/:guid
/clicks/notification-blast/:notification_blast_id
/opens/:mailing_id/:guid
/hirefire//:token/info
(separate authentication via token param)/subscriptions/unsubscribe
/subscriptions/unsubscribed
If you are adding a new route or controller, it will need to be covered by a pundit policy, or explicitly skip authorization.
skip_after_action :verify_authorized_with_fallback
to the controller. Scoping down to a single method with only: :method_name
if appropriate. Please also add the endpoint to the list above, with your reasoning for adding a new publicly accessible endpointapp/policies
folder. To use an existing policy (e.g., the MemberPolicy
), call authorize
with either a symbol relating to the policy name (e.g., :member
) or an instance of the model with the same name (e.g., an instance of the Member
model). You will need to add a new method to the policy corresponding to your controller method name (e.g., a list?
method in the policy for a new list
route in the controller)rails g pundit:policy <your_policy_name>
This is a list of all the possible ways that personal member data can be accessed via the Identity app, in rough order of increasing numbers of members
/searches/basic
- Shows name and email of a member/members/:id
- Shows an individual members’ full details/mailings/:id/preview
- Can preview with personalisation details of any member/text_blasts/:id/preview
- Can preview with personalisation details of any member/searches/:id/results
- Shows name and email of 24 members matched by query/administrators
- Shows name and email of all admins/lists/:id
- Shows names of all members in the list, in paginated form/datasets/:id/edit
- Shows random rows of dataset which could contain member details used for personalisation/smses
- Can see SMSes sent to and received by members/audits/list
- Shows all web requests made, which will include parameters containing member details/members
- Shows paginated list of names and emailsIf you are using an RDS database, but running your application somewhere else (heroku for example), you may want to configure the RDS CA cert so that your app accesses the database using SSL - this will prevent man in the middle (MITM) attacks.
The identity repo already has a copy of the root RDS CA cert for 2019 - 2022, so all you need to do is add the path to the cert to your database url as a query parameter - ?sslmode=verify-full&sslrootcert=db/rds-ca-2019-root.pem
NOTE: If your database is currently using the old 2015 CA cert, you should use the combined root cert - sslmode=verify-full&sslrootcert=db/rds-combined-ca-bundle.pem
Once you’ve updated your database URL and confirmed your app is still running OK, it’s worth updating your database parameters in RDS to force SSL usage - this means apps will never be permitted to connect in a way which is vulnerable to MITM attacks. You need to update the rds.force_ssl
to 1
.
app/lib/ghoster.rb
wipes almost all member data. Some is anonymized, some is deleted.
Member data not wiped by ghoster.rb
includes:
app/workers/delete_old_unsubscribe_attempt_logs_worker.rb