decidim-trusted_ids 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE-AGPLv3.txt +661 -0
- data/README.md +344 -0
- data/Rakefile +40 -0
- data/app/commands/concerns/decidim/trusted_ids/system/create_organization_override.rb +22 -0
- data/app/commands/concerns/decidim/trusted_ids/system/needs_census_config.rb +29 -0
- data/app/commands/concerns/decidim/trusted_ids/system/update_organization_override.rb +21 -0
- data/app/controllers/concerns/decidim/trusted_ids/admin/impersonations_controller_override.rb +31 -0
- data/app/controllers/concerns/decidim/trusted_ids/check_existing_authorizations.rb +40 -0
- data/app/controllers/concerns/decidim/trusted_ids/check_omniauth_email_on_login.rb +25 -0
- data/app/controllers/concerns/decidim/trusted_ids/needs_trusted_ids_snippets.rb +26 -0
- data/app/events/decidim/trusted_ids/verifications/invalid_notification.rb +10 -0
- data/app/events/decidim/trusted_ids/verifications/success_notification.rb +33 -0
- data/app/forms/concerns/decidim/trusted_ids/system/organization_form_override.rb +93 -0
- data/app/forms/decidim/trusted_ids/verifications/trusted_ids_handler.rb +65 -0
- data/app/forms/decidim/via_oberta/verifications/via_oberta_handler.rb +103 -0
- data/app/jobs/decidim/trusted_ids/application_job.rb +8 -0
- data/app/jobs/decidim/trusted_ids/omniauth_verification_job.rb +76 -0
- data/app/jobs/decidim/trusted_ids/system/propagate_census_config_job.rb +29 -0
- data/app/jobs/decidim/trusted_ids/system/propagate_census_settings_job.rb +29 -0
- data/app/models/concerns/decidim/trusted_ids/authorization_override.rb +21 -0
- data/app/models/concerns/decidim/trusted_ids/organization_override.rb +17 -0
- data/app/models/decidim/trusted_ids/organization_config.rb +20 -0
- data/app/overrides/decidim/devise/sessions/new/add_trusted_id_buttons.html.erb.deface +3 -0
- data/app/overrides/decidim/devise/sessions/new/wrap_default_login_form.html.erb.deface +4 -0
- data/app/overrides/decidim/devise/shared/_omniauth_buttons/replace_button_content.html.erb.deface +17 -0
- data/app/overrides/decidim/devise/shared/_omniauth_buttons/skip_trusted_ids_provider.html.erb.deface +3 -0
- data/app/overrides/decidim/system/organizations/_advanced_settings/settings_form.html.erb.deface +3 -0
- data/app/overrides/decidim/system/organizations/_omniauth_provider/add_icon_placeholder.html.erb.deface +3 -0
- data/app/overrides/layouts/decidim/_head/add_trusted_ids_tags.html.erb.deface +11 -0
- data/app/packs/entrypoints/decidim_trusted_ids.js +3 -0
- data/app/packs/images/idcat_mobil-icon.svg +8 -0
- data/app/packs/images/valid-icon.png +0 -0
- data/app/packs/stylesheets/decidim/trusted_ids/oauth_icons.scss +75 -0
- data/app/services/decidim/via_oberta/api/request.rb +156 -0
- data/app/services/decidim/via_oberta/api/response.rb +67 -0
- data/app/views/decidim/trusted_ids/devise/sessions/_login_box.html.erb +30 -0
- data/app/views/decidim/trusted_ids/system/organizations/_icon_path_placeholder.html.erb +10 -0
- data/app/views/decidim/trusted_ids/system/organizations/_settings_form.html.erb +25 -0
- data/app/views/decidim/trusted_ids/verifications/_form.html.erb +39 -0
- data/app/views/decidim/via_oberta/verifications/_form.html.erb +56 -0
- data/config/assets.rb +16 -0
- data/config/i18n-tasks.yml +12 -0
- data/config/locales/ca.yml +132 -0
- data/config/locales/de.yml +168 -0
- data/config/locales/en.yml +169 -0
- data/config/locales/es.yml +132 -0
- data/config/locales/fr.yml +168 -0
- data/config/locales/it.yml +168 -0
- data/config/locales/oc.yml +132 -0
- data/config/locales/zz_fallbacks.rb +45 -0
- data/db/migrate/20230718082548_create_organization_trusted_ids_config.rb +14 -0
- data/lib/decidim/trusted_ids/engine.rb +181 -0
- data/lib/decidim/trusted_ids/test/factories.rb +21 -0
- data/lib/decidim/trusted_ids/verifications.rb +10 -0
- data/lib/decidim/trusted_ids/version.rb +10 -0
- data/lib/decidim/trusted_ids.rb +69 -0
- data/lib/omniauth/strategies/valid.rb +134 -0
- data/lib/omniauth/strategies.rb +7 -0
- data/lib/tasks/decidim_trusted_ids_upgrade_tasks.rake +5 -0
- data/package-lock.json +29154 -0
- data/package.json +43 -0
- metadata +200 -0
data/README.md
ADDED
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
# Decidim :: Trusted IDs
|
|
2
|
+
|
|
3
|
+
[![[CI] Lint](https://github.com/ConsorciAOC-PRJ/decidim-module-trusted-ids/actions/workflows/lint.yml/badge.svg)](https://github.com/ConsorciAOC-PRJ/decidim-module-trusted-ids/actions/workflows/lint.yml)
|
|
4
|
+
[![[CI] Test](https://github.com/ConsorciAOC-PRJ/decidim-module-trusted-ids/actions/workflows/test.yml/badge.svg)](https://github.com/ConsorciAOC-PRJ/decidim-module-trusted-ids/actions/workflows/test.yml)
|
|
5
|
+
[](https://codeclimate.com/github/ConsorciAOC-PRJ/decidim-module-trusted-ids/maintainability)
|
|
6
|
+
[](https://codecov.io/gh/ConsorciAOC-PRJ/decidim-module-trusted-ids)
|
|
7
|
+
[](https://badge.fury.io/rb/decidim-trusted-ids)
|
|
8
|
+
|
|
9
|
+
Translations:
|
|
10
|
+
|
|
11
|
+
[](https://crowdin.com/project/decidim-trusted-ids)
|
|
12
|
+
|
|
13
|
+
This module is an evolution of the original [IdCat Mòbil](https://github.com/gencat/decidim-module-idcat_mobil) that was funded by the Department d'Exteriors of [Generalitat de Catalunya](http://gencat.cat) and developed by [CodiTramuntana](http://coditramuntana.com/).
|
|
14
|
+
|
|
15
|
+
On of the goals of this module is to decouple the authentication method from the IdCat Mòbil and pursue a more agnostic with a registry of providers. It also implements additional user options for extended verification methods using Via Oberta (or other providers) with improved user's control over personal data management.
|
|
16
|
+
|
|
17
|
+
The main goal, though, is to provide an, opinionated, easy to use, and secure authentication method for Decidim with **strong authentication systems**. That is, OAuth authentication systems that provide a unique identifier for each user. Preferably from official entities. Each user logged using this system will be verified automatically using the integrated verification method that this plugin provides, and will save the unique identifier as metadata.
|
|
18
|
+
|
|
19
|
+
Later on, this metadata will be used to connect to an additional, configurable, API to retrieve more information about the user. This information will be used to verify the user's identity with more granularity (for instance, restrict user actions to certain user properties, such as which census belongs to).
|
|
20
|
+
|
|
21
|
+
Finally, GDPR regulations are very present in this workflow, so user consent is a must. This plugins adds some additional steps to the registration process to give the user more control over the data that is being used, and to give the user the ability to revoke consent at any time.
|
|
22
|
+
|
|
23
|
+
### Workflow:
|
|
24
|
+
|
|
25
|
+

|
|
26
|
+
|
|
27
|
+
As is shown in the previous workflow, this module implements two stages for user registration:
|
|
28
|
+
|
|
29
|
+
##### First stage:
|
|
30
|
+
|
|
31
|
+
- **A OAuth 2.0 authentication (login & register) method that is configurable**. At the moment the default provider is `valid` (is a built-in identity validator from the [AOC](https://www.aoc.cat/) consortium. However, it is possible to add other (external) providers, not necessarily available in this plugin. PRs are welcome to add OAuth registration/login in this plugin itself if they come from official sources. See the [CONTRIBUTING](CONTRIBUTING.md) file for more information.
|
|
32
|
+
|
|
33
|
+
- **Automatic creation of the first authorization with OAuth metadata**. This authorization will be used to verify the user's identity in the second stage. It saves some data from the OAuth provider, such as the unique identifier, the provider name, and the expiration date of the authorization or other. The saved data is configurable in this plugin. This data should be the one necessary to authenticate the users, without their intervention to an external census API provider in the second stage.
|
|
34
|
+
|
|
35
|
+
##### Second stage:
|
|
36
|
+
|
|
37
|
+
- A second authorization ("Census authorization") can be issued to verify the user's identity. This authorization will be used to connect to an external API to retrieve more information about the user (mainly if belongs to a particular census). This authorization is optional and configurable in this plugin. It can be disabled if not needed.
|
|
38
|
+
|
|
39
|
+
- The default census authorization uses [Via Oberta](https://www.aoc.cat/serveis-aoc/via-oberta/) but others can be used instead (either internal or external). If you want to incorporate a new provider see the [CONTRIBUTING](CONTRIBUTING.md) file for more information.
|
|
40
|
+
|
|
41
|
+
- Once the user has obtained the census authorization, you can use it to ensure that the user belongs to a particular census. This increases the security and avoids spoofing attacks (if the second authorization methods does not uses user inputs).
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
## Installation
|
|
45
|
+
|
|
46
|
+
Add this line to your application's Gemfile:
|
|
47
|
+
|
|
48
|
+
```ruby
|
|
49
|
+
gem "decidim-trusted_ids"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Or, if you want to stay up to date with the latest changes use this line instead:
|
|
53
|
+
|
|
54
|
+
```ruby
|
|
55
|
+
gem 'decidim-trusted_ids', git: "https://github.com/ConsorciAOC-PRJ/decidim-module-trusted-ids"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
And then execute:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
bundle
|
|
62
|
+
bin/rails decidim:upgrade
|
|
63
|
+
bin/rails db:migrate
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
> **EXPERTS ONLY**
|
|
67
|
+
>
|
|
68
|
+
> Under the hood, when running `bundle exec rails decidim:upgrade` the `decidim-trusted_ids` gem will run the following (that can also be run manually if you consider):
|
|
69
|
+
>
|
|
70
|
+
> ```bash
|
|
71
|
+
> bin/rails decidim_trusted_ids:install:migrations
|
|
72
|
+
> ```
|
|
73
|
+
|
|
74
|
+
## Using OAuth in Decidim
|
|
75
|
+
|
|
76
|
+
This module adds a new authentication method to Decidim that allows users to log in and register using an OAuth2 provider. This provider must be configured in the `ENV` variables or through an initializer.
|
|
77
|
+
|
|
78
|
+
One important thing to note is that, in order to use an OAuth authentication system, you need on the provider to register and authorize the return url of your Decidim instance. This is usually done by adding the URL of your Decidim instance to the list of authorized URLs in the OAuth provider's settings.
|
|
79
|
+
|
|
80
|
+
By default this plugin uses the `valid` provider, which is a built-in identity validator from the [AOC](https://www.aoc.cat/) consortium.
|
|
81
|
+
|
|
82
|
+
This means that you need to enable the following return url in the OAuth provider:
|
|
83
|
+
|
|
84
|
+
```text
|
|
85
|
+
https://your-decidim-instance.com/users/auth/valid/callback
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
If you are using a different provider, you should replace `valid` with the name of your provider.
|
|
89
|
+
|
|
90
|
+
## Usage
|
|
91
|
+
|
|
92
|
+
This plugin comes prepared to be used solely with `ENV` variables, but you can also configure it through an initializer.
|
|
93
|
+
|
|
94
|
+
By default, you can use these variables to configure the module:
|
|
95
|
+
|
|
96
|
+
Environment variable | Description | Default value
|
|
97
|
+
--- | --- | ---
|
|
98
|
+
`OMNIAUTH_PROVIDER` | The OAuth2 provider to use. Currently only `valid` is built-in in this plugin. Note that this word will be used as a prefix (in uppercase) for all the omniauth values defined after this. If you use a different provider, say `foo`, nexts ENV vars will start with `FOO_` instead of `VALID_` | `valid`
|
|
99
|
+
`CUSTOM_LOGIN_SCREEN` | Whether to use a custom login screen or the default Decidim login screen. | `true` (only if omniauth is enabled)
|
|
100
|
+
`OMNIAUTH_ENABLED_BY_DEFAULT` | Whether the OAuth2 login is enabled by default. If false must be enabled in system. | `true` (if `VALID_CLIENT_ID` is present)
|
|
101
|
+
`OMNIAUTH_GLOBAL_ATTRIBUTES` | Attributes sent to the Omniauth provider that are not writeable in the `/system` admin. Separated by spaces. | `site icon_path scope`
|
|
102
|
+
`VALID_CLIENT_ID` | The OAuth2 client ID. Note that the prefix `VALID` is because `OMNIAUTH_PROVIDER` is set to "valid". Other values will require to name this variable accordingly (for instance `FOO_CLIENT_ID`). **IF this variable is empty, no OAuth login will be used**. | `nil`
|
|
103
|
+
`VALID_CLIENT_SECRET` | The OAuth2 client secret. | `nil`
|
|
104
|
+
`VALID_SITE` | The OAuth2 site. | `nil`
|
|
105
|
+
`VALID_ICON` | The icon used for the login button. | `media/images/valid-icon.png`
|
|
106
|
+
`VALID_SCOPE` | The OAuth2 scope that returns the necessary fields for registration (some OAuth method might override this making it unnecessary). | `autenticacio_usuari`
|
|
107
|
+
`VERIFICATION_EXPIRATION_TIME` | In seconds, how long the authorizations will be valid. Use zero or empty to prevent expiration. | `7776000` (90 days)
|
|
108
|
+
`SEND_VERIFICATION_NOTIFICATIONS` | Whether to send notifications to users when they are verified or the verification process fails. | `true`
|
|
109
|
+
`CENSUS_AUTHORIZATION_HANDLER` | The authorization handler to use for the census authorization. Currently only `via_oberta_handler` is built-in in this plugin. | `via_oberta_handler`
|
|
110
|
+
`CENSUS_AUTHORIZATION_FORM` | The authorization form to use for the census authorization. This is an standard [authorization form](https://docs.decidim.org/en/develop/customize/authorizations) and it should be responsible for the actions of connecting to a census API and handle any user interaction that might require. Currently only `ViaObertaHandler` is built-in in this plugin. | `Decidim::ViaOberta::Verifications::ViaObertaHandler`
|
|
111
|
+
`CENSUS_AUTHORIZATION_ENV` | The environment variable that will be used to store the census authorization. In the case of Via Oberta, calls to the proper URL api. | `production`
|
|
112
|
+
`CENSUS_AUTHORIZATION_API_URL` | The URL of the census API. By default it is empty, if defined, overrides the pre-defined URL obtained from the previous ENV var (if the census authorization is created this way). | `nil`
|
|
113
|
+
`CENSUS_AUTHORIZATION_SYSTEM_ATTRIBUTES` | This var defines which attributes need to be configured at the [/system](https://docs.decidim.org/en/v0.27/admin/system.html) multi-tenant super admin page. These might be secret properties that can be used by the census authorization but might vary from tenant to tenant. Each value must be a word, separated by spaces. See the [screenshots section](#screenshots). | `nif` `ine` `municipal_code` `province_code` `organization_name`
|
|
114
|
+
`VIA_OBERTA_PURPOSE` | The purpose of Via Oberta request.
|
|
115
|
+
|
|
116
|
+
In` `addition, metadata obtained from the OAuth provider that need to be stored in the `trusted_ids_handler` authorization can be configured through next variables.
|
|
117
|
+
|
|
118
|
+
Note that these ENVs variables work the same way as the previous `VALID_*` vars.
|
|
119
|
+
If the provider is `foo`, it should start with `FOO_METADATA_*`.
|
|
120
|
+
|
|
121
|
+
Any ENV var starting as `VALID_METADATA_SUFFIX` will make the plugin to save a metadata attribute called `suffix` as part of the authorization metadata encrypted hash.
|
|
122
|
+
|
|
123
|
+
As the the returned JSON from a successful OAuth login/registration might follow a different structure, you can configure the names of the fields that will be used to extract the metadata. This is done by using each word inside the value of the ENV var (separated by spaces) as a level in the JSON structure. For instance, if you have a return OAuth JSON data like this:
|
|
124
|
+
|
|
125
|
+
```json
|
|
126
|
+
{
|
|
127
|
+
"uid": "12345678Z",
|
|
128
|
+
"provider": "valid",
|
|
129
|
+
"credentials": {
|
|
130
|
+
"expires_at": "2020-12-31T23:59:59Z"
|
|
131
|
+
},
|
|
132
|
+
"info": {
|
|
133
|
+
"identifier_type": "NIF",
|
|
134
|
+
"method": "idcat_mobil"
|
|
135
|
+
},
|
|
136
|
+
"assurance_level": "high"
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
You can configure the ENV vars like this:
|
|
141
|
+
|
|
142
|
+
Environment variable | Value
|
|
143
|
+
--- | ---
|
|
144
|
+
`VALID_METADATA_EXPIRES_AT` | `credentials expires_at`
|
|
145
|
+
`VALID_METADATA_IDENTIFIER_TYPE` | `info identifier_type`
|
|
146
|
+
`VALID_METADATA_METHOD` | `info method`
|
|
147
|
+
`VALID_METADATA_ASSURANCE_LEVEL` | `info assurance_level`
|
|
148
|
+
|
|
149
|
+
And this will store in the `trusted_ids_handler` authorization metadata the following values:
|
|
150
|
+
|
|
151
|
+
```json
|
|
152
|
+
{
|
|
153
|
+
"uid": "12345678Z",
|
|
154
|
+
"provider": "valid",
|
|
155
|
+
"extra" {
|
|
156
|
+
"expires_at": "2020-12-31T23:59:59Z",
|
|
157
|
+
"identifier_type": "NIF",
|
|
158
|
+
"method": "idcat_mobil",
|
|
159
|
+
"assurance_level": "high"
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Note that the `uid` and `provider` fields are always stored, and the `extra` field is used to store any other metadata.
|
|
165
|
+
|
|
166
|
+
### Via initializer
|
|
167
|
+
|
|
168
|
+
If you are using a different source for your settings, you can also configure this module through an initializer.
|
|
169
|
+
|
|
170
|
+
For instance, create a file `config/initializers/decidim_trusted_ids.rb` with the following content:
|
|
171
|
+
|
|
172
|
+
```ruby
|
|
173
|
+
Decidim::TrustedIds.configure do |config|
|
|
174
|
+
# The name of the omniauth provider, must be registered in Decidim.
|
|
175
|
+
config.omniauth_provider = "valid"
|
|
176
|
+
config.omniauth = {
|
|
177
|
+
enabled: true,
|
|
178
|
+
client_id: "my-client-id",
|
|
179
|
+
client_secret: "my-client-secret",
|
|
180
|
+
site: "https://valid.aoc.cat",
|
|
181
|
+
scope: "autenticacio_usuari",
|
|
182
|
+
icon: "media/images/valid-icon.png"
|
|
183
|
+
},
|
|
184
|
+
...
|
|
185
|
+
end
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
For the complete list of available options, see the [trusted_ids](lib/decidim/trusted_ids.rb) file.
|
|
189
|
+
|
|
190
|
+
### Screenshots
|
|
191
|
+
|
|
192
|
+
- If system attributes are defined, it will available in the system configuration page:
|
|
193
|
+

|
|
194
|
+
|
|
195
|
+
- If the census authorization is created, it will be available in the census authorization page.
|
|
196
|
+
This is how the Via Oberta Handler looks like:
|
|
197
|
+

|
|
198
|
+
|
|
199
|
+
- If the login screen is customized, it will look like this:
|
|
200
|
+

|
|
201
|
+
|
|
202
|
+
## Decidim core overrides
|
|
203
|
+
|
|
204
|
+
This module customizes Decidim core behavior through Deface overrides (for views) and module-based form extensions.
|
|
205
|
+
|
|
206
|
+
### Views
|
|
207
|
+
|
|
208
|
+
- **`app/overrides/decidim/devise/sessions/new/add_trusted_id_buttons.html.erb.deface`** — Replaces the core call that renders omniauth buttons with `decidim/trusted_ids/devise/sessions/login_box`, showing the VÀLid login box on the login page.
|
|
209
|
+
|
|
210
|
+
- **`app/overrides/decidim/devise/sessions/new/wrap_default_login_form.html.erb.deface`** — Replaces the core `decidim_form_for` line to conditionally hide the default login form when the custom VÀLid login screen is enabled.
|
|
211
|
+
|
|
212
|
+
- **`app/overrides/decidim/devise/shared/_omniauth_buttons/skip_trusted_ids_provider.html.erb.deface`** — Inserts a guard to skip rendering the VÀLid provider in the core omniauth buttons loop on the sessions/new page when the custom login screen is enabled, avoiding duplicated buttons.
|
|
213
|
+
|
|
214
|
+
- **`app/overrides/decidim/devise/shared/_omniauth_buttons/replace_button_content.html.erb.deface`** — Replaces the core `oauth_icon provider` call for button content. For the VÀLid provider, it resolves `icon_path` from organization/module settings and falls back to `media/images/valid-icon.png`; for other providers it keeps `oauth_icon provider`. It rescues `Shakapacker::Manifest::MissingEntryError` to prevent crashes if the asset is missing.
|
|
215
|
+
|
|
216
|
+
- **`app/overrides/decidim/system/organizations/_omniauth_provider/add_icon_placeholder.html.erb.deface`** — Replaces the `icon_path` form row rendering in system settings with a module partial that adds a default-placeholder hint.
|
|
217
|
+
|
|
218
|
+
- **`app/overrides/decidim/system/organizations/_advanced_settings/settings_form.html.erb.deface`** — Inserts the trusted IDs settings partial at the top of the organization advanced settings panel.
|
|
219
|
+
|
|
220
|
+
- **`app/overrides/layouts/decidim/_head/add_trusted_ids_tags.html.erb.deface`** — Appends the `decidim_trusted_ids` stylesheet pack in the Decidim head layout so trusted IDs styles are available on pages that do not load them by default.
|
|
221
|
+
|
|
222
|
+
### Forms
|
|
223
|
+
|
|
224
|
+
- **`Decidim::TrustedIds::System::OrganizationFormOverride`** — Included into `Decidim::System::RegisterOrganizationForm` and `Decidim::System::UpdateOrganizationForm`. Adds:
|
|
225
|
+
- Census configuration fields (expiration days, TOS, census settings).
|
|
226
|
+
- `validate_icon_path`: validates that if an `icon_path` is provided for the VÀLid provider, it must follow the `media/images/filename.ext` format and the file must exist in the module's `app/packs/images/` directory. This is future-proof: any new icon added there will automatically pass validation. Blank values are always accepted — on save, the encrypted default path is stored automatically.
|
|
227
|
+
- `EncryptedOmniauthSettingsOverride` (prepended module): when the VÀLid provider is being enabled and `icon_path` is blank, sets the default path (`media/images/valid-icon.png`) via the jsonb sub-attribute setter before calling `super`, so the core encrypts it and stores it in the database. This prevents `external_icon("")` from being called and crashing. Uses `prepend` so `super` correctly calls the core's `encrypted_omniauth_settings`.
|
|
228
|
+
|
|
229
|
+
## Contributing
|
|
230
|
+
|
|
231
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/ConsorciAOC-PRJ/decidim-module-trusted-ids.
|
|
232
|
+
|
|
233
|
+
If you want to create your own authorization or OmniAuth methods, make sure to read the [CONTRIBUTING.md](CONTRIBUTING.md) file first.
|
|
234
|
+
|
|
235
|
+
### Developing
|
|
236
|
+
|
|
237
|
+
To start contributing to this project, first:
|
|
238
|
+
|
|
239
|
+
- Install the basic dependencies (such as Ruby and PostgreSQL)
|
|
240
|
+
- Clone this repository
|
|
241
|
+
|
|
242
|
+
Decidim's main repository also provides a Docker configuration file if you
|
|
243
|
+
prefer to use Docker instead of installing the dependencies locally on your
|
|
244
|
+
machine.
|
|
245
|
+
|
|
246
|
+
You can create the development app by running the following commands after
|
|
247
|
+
cloning this project:
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
bundle
|
|
251
|
+
DATABASE_USERNAME=<username> DATABASE_PASSWORD=<password> bundle exec rake development_app
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Note that the database user has to have rights to create and drop a database in
|
|
255
|
+
order to create the dummy test app database.
|
|
256
|
+
|
|
257
|
+
Then to test how the module works in Decidim, start the development server:
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
DATABASE_USERNAME=<username> DATABASE_PASSWORD=<password> bin/rails s
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Note that `bin/rails` is a convenient wrapper around the command `cd development_app; bundle exec rails`.
|
|
264
|
+
|
|
265
|
+
In case you are using [rbenv](https://github.com/rbenv/rbenv) and have the
|
|
266
|
+
[rbenv-vars](https://github.com/rbenv/rbenv-vars) plugin installed for it, you
|
|
267
|
+
can add the environment variables to the root directory of the project in a file
|
|
268
|
+
named `.rbenv-vars`. If these are defined for the environment, you can omit
|
|
269
|
+
defining these in the commands shown above.
|
|
270
|
+
|
|
271
|
+
#### Webpacker notes
|
|
272
|
+
|
|
273
|
+
As latests versions of Decidim, this repository uses Shakapacker for Rails. This means that compilation
|
|
274
|
+
of assets is required every time a Javascript or CSS file is modified. Usually, this happens
|
|
275
|
+
automatically, but in some cases (specially when actively changes that type of files) you want to
|
|
276
|
+
speed up the process.
|
|
277
|
+
|
|
278
|
+
To do that, start in a separate terminal than the one with `bin/rails s`, and BEFORE it, the following command:
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
bin/shakapacker-dev-server
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
#### Code Styling
|
|
285
|
+
|
|
286
|
+
Please follow the code styling defined by the different linters that ensure we
|
|
287
|
+
are all talking with the same language collaborating on the same project. This
|
|
288
|
+
project is set to follow the same rules that Decidim itself follows.
|
|
289
|
+
|
|
290
|
+
[Rubocop](https://rubocop.readthedocs.io/) linter is used for the Ruby language.
|
|
291
|
+
|
|
292
|
+
You can run the code styling checks by running the following commands from the
|
|
293
|
+
console:
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
bundle exec rubocop
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
To ease up following the style guide, you should install the plugin to your
|
|
300
|
+
favorite editor, such as:
|
|
301
|
+
|
|
302
|
+
- Sublime Text - [Sublime RuboCop](https://github.com/pderichs/sublime_rubocop)
|
|
303
|
+
- Visual Studio Code - [Rubocop for Visual Studio Code](https://github.com/misogi/vscode-ruby-rubocop)
|
|
304
|
+
|
|
305
|
+
### Testing
|
|
306
|
+
|
|
307
|
+
To run the tests run the following in the gem development path:
|
|
308
|
+
|
|
309
|
+
```bash
|
|
310
|
+
bundle
|
|
311
|
+
DATABASE_USERNAME=<username> DATABASE_PASSWORD=<password> bundle exec rake test_app
|
|
312
|
+
DATABASE_USERNAME=<username> DATABASE_PASSWORD=<password> bundle exec rspec
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
Note that the database user has to have rights to create and drop a database in
|
|
316
|
+
order to create the dummy test app database.
|
|
317
|
+
|
|
318
|
+
In case you are using [rbenv](https://github.com/rbenv/rbenv) and have the
|
|
319
|
+
[rbenv-vars](https://github.com/rbenv/rbenv-vars) plugin installed for it, you
|
|
320
|
+
can add these environment variables to the root directory of the project in a
|
|
321
|
+
file named `.rbenv-vars`. In this case, you can omit defining these in the
|
|
322
|
+
commands shown above.
|
|
323
|
+
|
|
324
|
+
### Test code coverage
|
|
325
|
+
|
|
326
|
+
Running tests automatically generates a code coverage report. To generate the complete report run all the tests using this command:
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
bundle exec rspec
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
This will generate a folder named `coverage` in the project root which contains
|
|
333
|
+
the code coverage report.
|
|
334
|
+
|
|
335
|
+
### Localization
|
|
336
|
+
|
|
337
|
+
If you would like to see this module in your own language, you can help with its
|
|
338
|
+
translation at Crowdin:
|
|
339
|
+
|
|
340
|
+
https://crowdin.com/project/decidim-trusted-ids
|
|
341
|
+
|
|
342
|
+
## License
|
|
343
|
+
|
|
344
|
+
This engine is distributed under the GNU AFFERO GENERAL PUBLIC LICENSE.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "decidim/dev/common_rake"
|
|
4
|
+
|
|
5
|
+
def install_module(path)
|
|
6
|
+
Dir.chdir(path) do
|
|
7
|
+
system("bundle exec rake decidim_trusted_ids:install:migrations")
|
|
8
|
+
system("bundle exec rake db:migrate")
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def seed_db(path)
|
|
13
|
+
Dir.chdir(path) do
|
|
14
|
+
system("bundle exec rake db:seed")
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
desc "Generates a dummy app for testing"
|
|
19
|
+
task test_app: "decidim:generate_external_test_app" do
|
|
20
|
+
ENV["RAILS_ENV"] = "test"
|
|
21
|
+
install_module("spec/decidim_dummy_app")
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
desc "Generates a development app."
|
|
25
|
+
task :development_app do
|
|
26
|
+
Bundler.with_original_env do
|
|
27
|
+
generate_decidim_app(
|
|
28
|
+
"development_app",
|
|
29
|
+
"--app_name",
|
|
30
|
+
"#{base_app_name}_development_app",
|
|
31
|
+
"--path",
|
|
32
|
+
"..",
|
|
33
|
+
"--recreate_db",
|
|
34
|
+
"--demo"
|
|
35
|
+
)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
install_module("development_app")
|
|
39
|
+
seed_db("development_app")
|
|
40
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module TrustedIds
|
|
5
|
+
module System
|
|
6
|
+
module CreateOrganizationOverride
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
include NeedsCensusConfig
|
|
9
|
+
|
|
10
|
+
included do
|
|
11
|
+
alias_method :trusted_ids_original_create_organization, :create_organization
|
|
12
|
+
|
|
13
|
+
def create_organization
|
|
14
|
+
organization = trusted_ids_original_create_organization
|
|
15
|
+
save_census_config!(organization)
|
|
16
|
+
organization
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module TrustedIds
|
|
5
|
+
module System
|
|
6
|
+
module NeedsCensusConfig
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
|
|
9
|
+
included do
|
|
10
|
+
def save_census_config!(organization)
|
|
11
|
+
conf = Decidim::TrustedIds::OrganizationConfig.find_or_initialize_by(organization: organization)
|
|
12
|
+
conf.handler = TrustedIds.census_authorization[:handler]
|
|
13
|
+
return if conf.handler.blank?
|
|
14
|
+
|
|
15
|
+
conf.settings = form.trusted_ids_census_settings
|
|
16
|
+
conf.tos = form.trusted_ids_census_tos
|
|
17
|
+
conf.expiration_days = form.trusted_ids_census_expiration_days
|
|
18
|
+
conf.save!
|
|
19
|
+
|
|
20
|
+
propagate = []
|
|
21
|
+
propagate << :expiration_days if form.census_expiration_apply_all_tenants
|
|
22
|
+
propagate << :tos if form.census_tos_apply_all_tenants
|
|
23
|
+
PropagateCensusConfigJob.perform_later(conf.id, propagate) if propagate.any?
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module TrustedIds
|
|
5
|
+
module System
|
|
6
|
+
module UpdateOrganizationOverride
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
include NeedsCensusConfig
|
|
9
|
+
|
|
10
|
+
included do
|
|
11
|
+
alias_method :trusted_ids_original_save_organization, :save_organization
|
|
12
|
+
|
|
13
|
+
def save_organization
|
|
14
|
+
trusted_ids_original_save_organization
|
|
15
|
+
save_census_config!(organization)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/concern"
|
|
4
|
+
|
|
5
|
+
module Decidim
|
|
6
|
+
module TrustedIds
|
|
7
|
+
module Admin
|
|
8
|
+
module ImpersonationsControllerOverride
|
|
9
|
+
extend ActiveSupport::Concern
|
|
10
|
+
|
|
11
|
+
included do
|
|
12
|
+
# normalize_provider_name is used in this builtin authorizations
|
|
13
|
+
helper Decidim::OmniauthHelper
|
|
14
|
+
|
|
15
|
+
# the internal 1st step verification shouldn't be used for impersonations as it is linked with an OAuth login
|
|
16
|
+
def other_available_authorization_handlers
|
|
17
|
+
Decidim::Verifications::Adapter.from_collection(
|
|
18
|
+
current_organization.available_authorization_handlers - [handler_name, "trusted_ids_handler"]
|
|
19
|
+
)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def available_authorization_handlers
|
|
23
|
+
Decidim::Verifications::Adapter.from_collection(
|
|
24
|
+
current_organization.available_authorization_handlers - ["trusted_ids_handler"]
|
|
25
|
+
)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/concern"
|
|
4
|
+
|
|
5
|
+
module Decidim
|
|
6
|
+
module TrustedIds
|
|
7
|
+
module CheckExistingAuthorizations
|
|
8
|
+
extend ActiveSupport::Concern
|
|
9
|
+
|
|
10
|
+
included do
|
|
11
|
+
# rubocop:disable Rails/LexicallyScopedActionFilter
|
|
12
|
+
before_action :check_existing_authorizations, only: [:new, :create]
|
|
13
|
+
before_action :check_parent_census_authorizations, only: [:new, :create]
|
|
14
|
+
# rubocop:enable Rails/LexicallyScopedActionFilter
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def check_existing_authorizations
|
|
19
|
+
return unless authorization&.granted?
|
|
20
|
+
|
|
21
|
+
flash[:alert] = I18n.t("decidim.verifications.authorizations.errors.already_verified")
|
|
22
|
+
redirect_to decidim.account_path
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def check_parent_census_authorizations
|
|
26
|
+
return unless handler_name.to_s == Decidim::TrustedIds.census_authorization[:handler].to_s
|
|
27
|
+
return if trusted_ids_authorization&.granted?
|
|
28
|
+
|
|
29
|
+
flash[:alert] = I18n.t("decidim.verifications.authorizations.errors.pending_authorization",
|
|
30
|
+
handler_name: I18n.t("decidim.authorization_handlers.trusted_ids_handler.name"))
|
|
31
|
+
redirect_to decidim.account_path
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def trusted_ids_authorization
|
|
35
|
+
@trusted_ids_authorization ||= Decidim::Authorization.find_by(user: current_user, name: "trusted_ids_handler")
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/concern"
|
|
4
|
+
|
|
5
|
+
module Decidim
|
|
6
|
+
module TrustedIds
|
|
7
|
+
module CheckOmniauthEmailOnLogin
|
|
8
|
+
extend ActiveSupport::Concern
|
|
9
|
+
|
|
10
|
+
included do
|
|
11
|
+
before_action :prevent_omniauth_login, only: Decidim::TrustedIds.omniauth_provider
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def prevent_omniauth_login
|
|
16
|
+
return unless user_signed_in?
|
|
17
|
+
return if current_user.email == verified_email
|
|
18
|
+
|
|
19
|
+
flash[:alert] = I18n.t("decidim.trusted_ids.sessions.different_omniauth_emails")
|
|
20
|
+
redirect_back fallback_location: account_path
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/concern"
|
|
4
|
+
|
|
5
|
+
module Decidim
|
|
6
|
+
module TrustedIds
|
|
7
|
+
module NeedsTrustedIdsSnippets
|
|
8
|
+
extend ActiveSupport::Concern
|
|
9
|
+
|
|
10
|
+
included do
|
|
11
|
+
helper_method :snippets
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def snippets
|
|
15
|
+
@snippets ||= Decidim::Snippets.new
|
|
16
|
+
|
|
17
|
+
unless @snippets.any?(:trusted_ids_global)
|
|
18
|
+
@snippets.add(:trusted_ids_global, ActionController::Base.helpers.stylesheet_pack_tag("decidim_trusted_ids"))
|
|
19
|
+
@snippets.add(:head, @snippets.for(:trusted_ids_global))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
@snippets
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module TrustedIds
|
|
5
|
+
module Verifications
|
|
6
|
+
class SuccessNotification < Decidim::Events::SimpleEvent
|
|
7
|
+
i18n_attributes :handler_name
|
|
8
|
+
|
|
9
|
+
def resource_path
|
|
10
|
+
Decidim::Verifications::Engine.routes.url_helpers.new_authorization_path(handler: authorization&.name)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def resource_url
|
|
14
|
+
Decidim::Verifications::Engine.routes.url_helpers.new_authorization_url(handler: authorization&.name, host: organization.host)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def handler_name
|
|
18
|
+
I18n.t("decidim.authorization_handlers.#{authorization&.name}.name")
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def resource_title
|
|
22
|
+
handler_name
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def authorization
|
|
26
|
+
return unless resource.is_a? Decidim::Authorization
|
|
27
|
+
|
|
28
|
+
@authorization ||= resource
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|