decidim-suomifi 0.18.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.
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Suomifi
5
+ module Verification
6
+ class AuthorizationsController < ::Decidim::ApplicationController
7
+ skip_before_action :store_current_location
8
+
9
+ def new
10
+ # Do enforce the permission here because it would cause
11
+ # re-authorizations not to work as the authorization already exists.
12
+ # In case the user wants to re-authorize themselves, they can just
13
+ # hit this endpoint again.
14
+ redirect_to decidim.user_suomifi_omniauth_authorize_path
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ ---
2
+ en:
3
+ decidim:
4
+ authorization_handlers:
5
+ suomifi_eid:
6
+ explanation: Identify yourself using the Suomi.fi e-Identification service.
7
+ name: Suomi.fi e-Identification
8
+ suomifi:
9
+ omniauth_callbacks:
10
+ failure:
11
+ already_authorized: Another user has already authorized themselves with the same identity.
12
+ conditions: The authentication request was not handled within an allowed timeframe. Please try again.
13
+ identity_bound_to_other_user: Another user has already been identified using this identity. Please sign out and sign in again directly using Suomi.fi.
14
+ session_expiration: Authentication session expired. Please try again.
15
+ success_status: Authentication failed or cancelled. Please try again.
16
+ verification:
17
+ authorizations:
18
+ create:
19
+ success: You have been successfully authorized through Suomi.fi
20
+ destroy:
21
+ success: Authorization sucessfully reset.
@@ -0,0 +1,20 @@
1
+ fi:
2
+ decidim:
3
+ authorization_handlers:
4
+ suomifi_eid:
5
+ explanation: Tunnista itsesi Suomi.fi-tunnistuspalvelun avulla.
6
+ name: Suomi.fi tunnistus
7
+ suomifi:
8
+ omniauth_callbacks:
9
+ failure:
10
+ already_authorized: Toinen käyttäjä on tunnistanut itsensä jo samalla henkilöllisyydellä.
11
+ conditions: Tunnistuspyyntöä ei käsitelty sallitun aikarajan sisällä. Yritä uudestaan.
12
+ identity_bound_to_other_user: Toinen käyttäjä on jo tunnistanut itsensä tällä henkilöllisyydellä. Kirjaudu ulos ja kirjaudu uudestaan sisään käyttäen suoraan Suomi.fi-tunnistusta.
13
+ session_expiration: Tunnistusistunto vanhentui. Yritä uudestaan.
14
+ success_status: Tunnistus epäonnistui tai peruutettiin. Yritä uudestaan.
15
+ verification:
16
+ authorizations:
17
+ create:
18
+ success: Sinut on onnistuneesti tunnistettu Suomi.fi-palvelun avulla
19
+ destroy:
20
+ success: Varmennus tyhjennetty onnistuneesti.
@@ -0,0 +1,20 @@
1
+ sv:
2
+ decidim:
3
+ authorization_handlers:
4
+ suomifi_eid:
5
+ explanation: Identifiera dig själv med Suomi.fi-identifikation.
6
+ name: Suomi.fi-identifikation
7
+ suomifi:
8
+ omniauth_callbacks:
9
+ failure:
10
+ already_authorized: En annan användare har redan godkänt sig med samma identitet.
11
+ conditions: Autentiseringsbegäran hanterades inte inom en tillåten tidsram. Var god försök igen.
12
+ identity_bound_to_other_user: En annan användare har redan identifierats med denna identitet. Logga ut och logga in igen direkt med Suomi.fi.
13
+ session_expiration: Autentiseringssessionen har gått ut. Var god försök igen.
14
+ success_status: Autentiseringen misslyckades eller avbröts. Var god försök igen.
15
+ verification:
16
+ authorizations:
17
+ create:
18
+ success: Du har godkänts med Suomi.fi
19
+ destroy:
20
+ success: Tillståndet återställs efterhand.
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "omniauth"
4
+ require "omniauth-suomifi"
5
+ require "henkilotunnus"
6
+
7
+ require_relative "suomifi/version"
8
+ require_relative "suomifi/engine"
9
+ require_relative "suomifi/verification"
10
+ require_relative "suomifi/mail_interceptors"
11
+
12
+ module Decidim
13
+ module Suomifi
14
+ include ActiveSupport::Configurable
15
+
16
+ @configured = false
17
+
18
+ # :production - For Suomi.fi production environment
19
+ # :test - For Suomi.fi test environment
20
+ config_accessor :mode, instance_reader: false
21
+
22
+ # :limited - Limited scope
23
+ # :medium_extensive - Medium-extensive scope
24
+ # :extensive - Extensive scope
25
+ config_accessor :scope_of_data do
26
+ :medium_extensive
27
+ end
28
+
29
+ # Defines the auto email domain in case the person's email address is not
30
+ # stored in the Suomi.fi database. In case this is defined, the user will
31
+ # be automatically assigned an email such as
32
+ # "suomifi-identifier@auto-email-domain.fi" upon their registration.
33
+ config_accessor :auto_email_domain
34
+
35
+ config_accessor :sp_entity_id, instance_reader: false
36
+
37
+ # The certificate string for the application
38
+ config_accessor :certificate, instance_reader: false
39
+
40
+ # The private key string for the application
41
+ config_accessor :private_key, instance_reader: false
42
+
43
+ # The certificate file for the application
44
+ config_accessor :certificate_file
45
+
46
+ # The private key file for the application
47
+ config_accessor :private_key_file
48
+
49
+ # Extra configuration for the omniauth strategy
50
+ config_accessor :extra do
51
+ {}
52
+ end
53
+
54
+ # Allows customizing the authorization workflow e.g. for adding custom
55
+ # workflow options or configuring an action authorizer for the
56
+ # particular needs.
57
+ config_accessor :workflow_configurator do
58
+ lambda do |workflow|
59
+ # By default, expiration is set to 0 minutes which means it will
60
+ # never expire.
61
+ workflow.expires_in = 0.minutes
62
+ end
63
+ end
64
+
65
+ # Allows customizing how the authorization metadata gets collected from
66
+ # the SAML attributes passed from the authorization endpoint.
67
+ config_accessor :metadata_collector_class do
68
+ Decidim::Suomifi::Verification::MetadataCollector
69
+ end
70
+
71
+ def self.configured?
72
+ @configured
73
+ end
74
+
75
+ def self.configure
76
+ @configured = true
77
+ super
78
+ end
79
+
80
+ def self.mode
81
+ return config.mode if config.mode
82
+ return :production unless Rails.application.secrets.omniauth
83
+ return :production unless Rails.application.secrets.omniauth[:suomifi]
84
+
85
+ # Read the mode from the secrets
86
+ secrets = Rails.application.secrets.omniauth[:suomifi]
87
+ secrets[:mode] == "test" ? :test : :production
88
+ end
89
+
90
+ def self.sp_entity_id
91
+ return config.sp_entity_id if config.sp_entity_id
92
+
93
+ "#{application_host}/users/auth/suomifi/metadata"
94
+ end
95
+
96
+ def self.certificate
97
+ return File.read(certificate_file) if certificate_file
98
+
99
+ config.certificate
100
+ end
101
+
102
+ def self.private_key
103
+ return File.read(private_key_file) if private_key_file
104
+
105
+ config.private_key
106
+ end
107
+
108
+ def self.omniauth_settings
109
+ settings = {
110
+ mode: mode,
111
+ scope_of_data: scope_of_data,
112
+ sp_entity_id: sp_entity_id,
113
+ certificate: certificate,
114
+ private_key: private_key
115
+ }
116
+ settings.merge!(config.extra) if config.extra.is_a?(Hash)
117
+ settings
118
+ end
119
+
120
+ # Used to determine the default service provider entity ID in case not
121
+ # specifically set by the `sp_entity_id` configuration option.
122
+ def self.application_host
123
+ conf = Rails.application.config
124
+ url_options = conf.action_controller.default_url_options
125
+ url_options = conf.action_mailer.default_url_options if !url_options || !url_options[:host]
126
+ url_options ||= {}
127
+
128
+ host = url_options[:host]
129
+ port = url_options[:port]
130
+ if host.blank?
131
+ # Default to local development environment
132
+ host = "http://localhost"
133
+ port ||= 3000
134
+ end
135
+
136
+ return "#{host}:#{port}" if port && ![80, 443].include?(port.to_i)
137
+
138
+ host
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Suomifi
5
+ class Engine < ::Rails::Engine
6
+ isolate_namespace Decidim::Suomifi
7
+
8
+ routes do
9
+ devise_scope :user do
10
+ # Manually map the SAML omniauth routes for Devise because the default
11
+ # routes are mounted by core Decidim. This is because we want to map
12
+ # these routes to the local callbacks controller instead of the
13
+ # Decidim core.
14
+ # See: https://git.io/fjDz1
15
+ match(
16
+ "/users/auth/suomifi",
17
+ to: "omniauth_callbacks#passthru",
18
+ as: "user_suomifi_omniauth_authorize",
19
+ via: [:get, :post]
20
+ )
21
+
22
+ match(
23
+ "/users/auth/suomifi/callback",
24
+ to: "omniauth_callbacks#suomifi",
25
+ as: "user_suomifi_omniauth_callback",
26
+ via: [:get, :post]
27
+ )
28
+ end
29
+ end
30
+
31
+ initializer "decidim_suomifi.mount_routes", before: :add_routing_paths do
32
+ # Mount the engine routes to Decidim::Core::Engine because otherwise
33
+ # they would not get mounted properly. Note also that we need to prepend
34
+ # the routes in order for them to override Decidim's own routes for the
35
+ # "suomifi" authentication.
36
+ Decidim::Core::Engine.routes.prepend do
37
+ mount Decidim::Suomifi::Engine => "/"
38
+ end
39
+ end
40
+
41
+ initializer "decidim_suomifi.setup", before: "devise.omniauth" do
42
+ next unless Decidim::Suomifi.configured?
43
+
44
+ # Configure the SAML OmniAuth strategy for Devise
45
+ ::Devise.setup do |config|
46
+ config.omniauth(
47
+ :suomifi,
48
+ Decidim::Suomifi.omniauth_settings
49
+ )
50
+ end
51
+
52
+ # Customized version of Devise's OmniAuth failure app in order to handle
53
+ # the failures properly. Without this, the failure requests would end
54
+ # up in an ActionController::InvalidAuthenticityToken exception.
55
+ devise_failure_app = OmniAuth.config.on_failure
56
+ OmniAuth.config.on_failure = proc do |env|
57
+ if env["PATH_INFO"] =~ %r{^/users/auth/suomifi(/.*)?}
58
+ env["devise.mapping"] = ::Devise.mappings[:user]
59
+ Decidim::Suomifi::OmniauthCallbacksController.action(
60
+ :failure
61
+ ).call(env)
62
+ else
63
+ # Call the default for others.
64
+ devise_failure_app.call(env)
65
+ end
66
+ end
67
+ end
68
+
69
+ initializer "decidim_suomifi.omniauth_provider", after: :load_config_initializers do
70
+ next unless Decidim::Suomifi.configured?
71
+
72
+ Decidim::Suomifi::Engine.add_omniauth_provider
73
+
74
+ # This also needs to run as a callback for the reloader because
75
+ # otherwise the suomifi OmniAuth routes would not be added to the core
76
+ # engine because its routes are reloaded before e.g. the to_prepare hook
77
+ # runs in this engine. The OmniAuth provider needs to be added before
78
+ # the core routes are reloaded.
79
+ ActiveSupport::Reloader.to_run do
80
+ Decidim::Suomifi::Engine.add_omniauth_provider
81
+ end
82
+ end
83
+
84
+ initializer "decidim_suomifi.mail_interceptors" do
85
+ ActionMailer::Base.register_interceptor(
86
+ MailInterceptors::GeneratedRecipientsInterceptor
87
+ )
88
+ end
89
+
90
+ def self.add_omniauth_provider
91
+ # Add :suomifi to the Decidim omniauth providers
92
+ providers = ::Decidim::User::OMNIAUTH_PROVIDERS
93
+ unless providers.include?(:suomifi)
94
+ providers << :suomifi
95
+ ::Decidim::User.send(:remove_const, :OMNIAUTH_PROVIDERS)
96
+ ::Decidim::User.const_set(:OMNIAUTH_PROVIDERS, providers)
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Suomifi
5
+ module MailInterceptors
6
+ autoload :GeneratedRecipientsInterceptor, "decidim/suomifi/mail_interceptors/generated_recipients_interceptor"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Suomifi
5
+ module MailInterceptors
6
+ # Prevents sending emails to the auto-generated email addresses.
7
+ class GeneratedRecipientsInterceptor
8
+ def self.delivering_email(message)
9
+ return unless Decidim::Suomifi.auto_email_domain
10
+
11
+ # Regexp to match the auto-generated emails
12
+ regexp = /^suomifi-[a-z0-9]{32}@#{Decidim::Suomifi.auto_email_domain}$/
13
+
14
+ # Remove the auto-generated email from the message recipients
15
+ message.to = message.to.reject { |email| email =~ regexp } if message.to
16
+ message.cc = message.cc.reject { |email| email =~ regexp } if message.cc
17
+ message.bcc = message.bcc.reject { |email| email =~ regexp } if message.bcc
18
+
19
+ # Prevent delivery in case there are no recipients on the email
20
+ message.perform_deliveries = false if message.to.empty?
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Suomifi
5
+ module Test
6
+ class CertStore
7
+ attr_reader :certificate, :private_key, :sign_certificate, :sign_private_key
8
+
9
+ def initialize
10
+ # Certificates
11
+ certgen = OmniAuth::Suomifi::Test::CertificateGenerator.new
12
+ @certificate = certgen.certificate
13
+ @private_key = certgen.private_key
14
+
15
+ # Use local certificate and private key for signing because otherwise the
16
+ # locally signed SAMLResponse's signature cannot be properly validated as
17
+ # we cannot sign it using the actual environments private key which is
18
+ # unknown.
19
+ sign_certgen = OmniAuth::Suomifi::Test::CertificateGenerator.new
20
+ @sign_certificate = sign_certgen.certificate
21
+ @sign_private_key = sign_certgen.private_key
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Suomifi
5
+ module Test
6
+ class Runtime
7
+ # Ability to stub the requests already in the control class
8
+ include WebMock::API
9
+
10
+ def self.initializer(&block)
11
+ @block = block
12
+ end
13
+
14
+ def self.initialize
15
+ new.instance_initialize(&@block)
16
+ end
17
+
18
+ def self.load_app
19
+ engine_spec_dir = File.join(Dir.pwd, "spec")
20
+
21
+ require "#{Decidim::Dev.dummy_app_path}/config/environment"
22
+
23
+ Dir["#{engine_spec_dir}/shared/**/*.rb"].each { |f| require f }
24
+
25
+ require "paper_trail/frameworks/rspec"
26
+
27
+ require "decidim/dev/test/spec_helper"
28
+ end
29
+
30
+ def self.cert_store
31
+ @cert_store ||= CertStore.new
32
+ end
33
+
34
+ def instance_initialize
35
+ yield self
36
+
37
+ # Setup the Suomi.fi OmniAuth strategy for Devise
38
+ # ::Devise.setup do |config|
39
+ # config.omniauth(
40
+ # :suomifi,
41
+ # Decidim::Suomifi.omniauth_settings
42
+ # )
43
+ # end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "verification/metadata_collector"
4
+ require_relative "verification/manager"
5
+ require_relative "verification/engine"