omniauth-proconnect 0.2.0 → 0.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 65c3097417b5ba5fc2e4a794a05c278377ec3c377dafe26b9f0ec4a9432a1c09
4
- data.tar.gz: 5a6777dabb9bc4243fa3ec392654e16791eeb5af2c9ee50dbae828e299c2c7b6
3
+ metadata.gz: d7f69d22759a84bda39c5b20a6d631c116ddecf85ad9e0f64039a11f3e4fbf98
4
+ data.tar.gz: 625c7d42937c3cdb64c1dd1b85b61f72ddf606ee1ebedea30253b3979b5cf2e5
5
5
  SHA512:
6
- metadata.gz: 3acfe7bb5f8ba66bd845462bbfdfbd42f877c0acecdd80a9611efe0d9ddcbb129d7f7842ea1a0970ce83e7a566c2eb0b5c697cd5046015a41434d810786b7690
7
- data.tar.gz: c50de51e6dc16a754d75e8acfa58ac8439c7323962154612108edf3fcd8a025b8e14f6411834961d3838afff3ef161fa828a9c26f5916a41f4838c9164fe3fbe
6
+ metadata.gz: 7730f981481a35c7987dc1f1756715ddf773182fc3f7f0ee502237899e46aa9c05d3219a8bb63ef951728711cd9f334e5a79ba0ec603d1f891e1c93ef7ec3f19
7
+ data.tar.gz: ffeab52d87c2ec7043de16c4dadcf66c4bbb534b4b02b79818772345b96807a7da1d2f703d50c98ff98d64535f73d9696067d834550a404092afdac395705654
data/.rubocop.yml CHANGED
@@ -1,3 +1,5 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
1
3
  AllCops:
2
4
  TargetRubyVersion: 3.1
3
5
 
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,20 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2025-05-23 15:10:03 UTC using RuboCop version 1.75.4.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 1
10
+ # Configuration parameters: CountComments, CountAsOne.
11
+ Metrics/ClassLength:
12
+ Max: 123
13
+
14
+ # Offense count: 1
15
+ # Configuration parameters: AllowedConstants.
16
+ Style/Documentation:
17
+ Exclude:
18
+ - 'spec/**/*'
19
+ - 'test/**/*'
20
+ - 'lib/omniauth/proconnect.rb'
data/README.md CHANGED
@@ -17,6 +17,13 @@ qui malgré son degré de maturité supérieure semble à l'abandon aussi.
17
17
 
18
18
  ## Utilisation
19
19
 
20
+ Une fois que vous avez créé votre application sur [l'espace
21
+ partenaires de
22
+ ProConnect](https://partenaires.proconnect.gouv.fr/apps) et identifié
23
+ vos endpoints grâce à leur [documentation
24
+ technique](https://partenaires.proconnect.gouv.fr/docs/fournisseur-service/implementation_technique)
25
+ :
26
+
20
27
  1. installer la gem `bundle add omniauth-proconnect` ;
21
28
  2. configurer une nouvelle stratégie pour OmniAuth :
22
29
 
@@ -52,6 +59,63 @@ end
52
59
  redirect_to "/auth/proconnect/logout"
53
60
  ```
54
61
 
62
+ ## Informations retournées
63
+
64
+ Les [informations retournées par
65
+ ProConnect](https://partenaires.proconnect.gouv.fr/docs/fournisseur-service/scope-claims)
66
+ sont mises à diposition dans le hash OmniAuth
67
+ (`request.env["omniauth.auth"]`) :
68
+
69
+ * la partie `info` contient tout ce qui peut être standardisé [selon
70
+ le Auth Hash Schema d'Omniauth](https://github.com/omniauth/omniauth/wiki/Auth-Hash-Schema)
71
+ * le reste/l'intégralité est disponible dans `extra`.
72
+
73
+ Exemple :
74
+
75
+ ```json
76
+ {
77
+ "provider": "proconnect",
78
+ "uid": "e7a41249-123d-46b7-b362-5f00d3166ea1",
79
+ "info": {
80
+ "email": "test@gouv.fr",
81
+ "first_name": null,
82
+ "last_name": null,
83
+ "name": "",
84
+ "phone": null,
85
+ "provider": "proconnect",
86
+ "uid": "e7a41249-123d-46b7-b362-5f00d3166ea1"
87
+ },
88
+ "credentials": {},
89
+ "extra": {
90
+ "raw_info": {
91
+ "sub": "e7a41249-123d-46b7-b362-5f00d3166ea1",
92
+ "email": "test@gouv.fr",
93
+ "siret": "13002526500013",
94
+ "aud": "f90c1231117ec6f731af9f93a07c54ff372130c17a3bbad43488699865d85c64",
95
+ "exp": 1748010049,
96
+ "iat": 1748009989,
97
+ "iss": "https://issuer-oidc.gouv.fr/api/v42"
98
+ }
99
+ }
100
+ }
101
+ ```
102
+
103
+ ```ruby
104
+ class SessionsController < ApplicationController
105
+ def create
106
+ data = request.env["omniauth.auth"]
107
+
108
+ email = data.info.email
109
+ siret = data.extra.raw_info.siret
110
+
111
+ # or, if you're feeling fancy
112
+ data => { info: { email: }, extra: { raw_info: { siret: } } }
113
+
114
+ # [...]
115
+ end
116
+ end
117
+ ```
118
+
55
119
  ## Contribution
56
120
 
57
121
  La stratégie est loin d'être complète ; n'hésitez pas à contribuer des
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Omniauth
4
4
  class Proconnect
5
- VERSION = "0.2.0"
5
+ VERSION = "0.4"
6
6
  end
7
7
  end
@@ -6,149 +6,161 @@ require "json/jwt"
6
6
 
7
7
  require_relative "proconnect/version"
8
8
 
9
- module Omniauth
10
- class Proconnect
11
- class Error < StandardError; end
12
-
13
- include OmniAuth::Strategy
14
-
15
- option :name, "proconnect"
16
- option :client_id
17
- option :client_secret
18
- option :proconnect_domain
19
- option :redirect_uri
20
- option :post_logout_redirect_uri
21
- option :scope, "openid email given_name usual_name"
22
-
23
- def setup_phase
24
- discover_endpoint!
25
- end
9
+ module OmniAuth
10
+ module Strategies
11
+ class Proconnect
12
+ class Error < StandardError; end
13
+
14
+ include OmniAuth::Strategy
15
+
16
+ option :name, "proconnect"
17
+ option :client_id
18
+ option :client_secret
19
+ option :proconnect_domain
20
+ option :redirect_uri
21
+ option :post_logout_redirect_uri
22
+ option :scope, "openid email given_name usual_name"
23
+
24
+ def setup_phase
25
+ discover_endpoint!
26
+ end
26
27
 
27
- def request_phase
28
- redirect(authorization_uri)
29
- end
28
+ def request_phase
29
+ redirect(authorization_uri)
30
+ end
30
31
 
31
- def callback_phase
32
- verify_state!(request.params["state"])
32
+ def callback_phase
33
+ verify_state!(request.params["state"])
33
34
 
34
- exchange_authorization_code!(request.params["code"])
35
- .then { |response| store_tokens!(response) }
36
- .then { get_userinfo! }
37
- .then { |response| @userinfo = JSON::JWT.decode(response.body, :skip_verification) }
38
- .then { super }
39
- end
35
+ exchange_authorization_code!(request.params["code"])
36
+ .then { |response| store_tokens!(response) }
37
+ .then { get_userinfo! }
38
+ .then { |response| @userinfo = JSON::JWT.decode(response.body, :skip_verification) }
39
+ .then { super }
40
+ end
40
41
 
41
- def other_phase
42
- if on_logout_path?
43
- engage_logout!
44
- else
45
- @app.call(env)
42
+ def other_phase
43
+ if on_logout_path?
44
+ engage_logout!
45
+ else
46
+ call_app!
47
+ end
46
48
  end
47
- end
48
49
 
49
- def uid
50
- session["omniauth.pc.id_token"]["sub"]
51
- end
50
+ # userinfo-operating DSL from OmniAuth
51
+ uid do
52
+ @userinfo["sub"]
53
+ end
52
54
 
53
- def info
54
- {
55
- email: @userinfo["email"]
56
- }
57
- end
55
+ info do
56
+ {
57
+ email: @userinfo["email"],
58
+ first_name: @userinfo["given_name"],
59
+ last_name: @userinfo["usual_name"],
60
+ name: [@userinfo["given_name"], @userinfo["usual_name"]].compact.join(" "),
61
+ phone: @userinfo["phone_number"],
62
+ provider: "proconnect",
63
+ uid: @userinfo["sub"]
64
+ }
65
+ end
58
66
 
59
- private
67
+ extra do
68
+ { raw_info: @userinfo }
69
+ end
60
70
 
61
- def connection
62
- @connection ||= Faraday.new(url: options[:proconnect_domain]) do |c|
63
- c.response :json
64
- c.response :raise_error
71
+ private
72
+
73
+ def connection
74
+ @connection ||= Faraday.new(url: options[:proconnect_domain]) do |c|
75
+ c.response :json
76
+ c.response :raise_error
77
+ end
65
78
  end
66
- end
67
79
 
68
- def discovered_configuration
69
- @discovered_configuration ||= discover_endpoint!
70
- end
80
+ def discovered_configuration
81
+ @discovered_configuration ||= discover_endpoint!
82
+ end
71
83
 
72
- def discover_endpoint!
73
- connection
74
- .get(".well-known/openid-configuration")
75
- .body
76
- end
84
+ def discover_endpoint!
85
+ connection.get(".well-known/openid-configuration").body
86
+ end
77
87
 
78
- def authorization_uri
79
- URI(discovered_configuration["authorization_endpoint"]).tap do |endpoint|
80
- endpoint.query = URI.encode_www_form(
81
- response_type: "code",
82
- client_id: options[:client_id],
83
- redirect_uri: options[:redirect_uri],
84
- scope: options[:scope],
85
- state: store_new_state!,
86
- nonce: store_new_nonce!
87
- )
88
+ def authorization_uri
89
+ URI(discovered_configuration["authorization_endpoint"]).tap do |endpoint|
90
+ endpoint.query = URI.encode_www_form(
91
+ response_type: "code",
92
+ client_id: options[:client_id],
93
+ redirect_uri: options[:redirect_uri],
94
+ scope: options[:scope],
95
+ state: store_new_state!,
96
+ nonce: store_new_nonce!
97
+ )
98
+ end
88
99
  end
89
- end
90
100
 
91
- def end_session_uri
92
- URI(discovered_configuration["end_session_endpoint"]).tap do |endpoint|
93
- endpoint.query = URI.encode_www_form(
94
- id_token_hint: session["omniauth.pc.id_token"],
95
- state: current_state,
96
- post_logout_redirect_uri: options[:post_logout_redirect_uri]
97
- )
101
+ def end_session_uri
102
+ URI(discovered_configuration["end_session_endpoint"]).tap do |endpoint|
103
+ endpoint.query = URI.encode_www_form(
104
+ id_token_hint: session["omniauth.pc.id_token"],
105
+ state: current_state,
106
+ post_logout_redirect_uri: options[:post_logout_redirect_uri]
107
+ )
108
+ end
98
109
  end
99
- end
100
110
 
101
- def exchange_authorization_code!(code)
102
- connection.post(URI(discovered_configuration["token_endpoint"]),
103
- URI.encode_www_form(
104
- grant_type: "authorization_code",
105
- client_id: options[:client_id],
106
- client_secret: options[:client_secret],
107
- redirect_uri: options[:redirect_uri],
108
- code: code,
109
- scope: options[:scope]
110
- ))
111
- end
111
+ def exchange_authorization_code!(code)
112
+ connection.post(URI(discovered_configuration["token_endpoint"]),
113
+ URI.encode_www_form(
114
+ grant_type: "authorization_code",
115
+ client_id: options[:client_id],
116
+ client_secret: options[:client_secret],
117
+ redirect_uri: options[:redirect_uri],
118
+ code: code
119
+ ))
120
+ end
112
121
 
113
- def store_tokens!(response)
114
- response.tap do |res|
115
- %w[access id refresh].each do |name|
116
- session["omniauth.pc.#{name}_token"] = res.body["#{name}_token"]
122
+ def store_tokens!(response)
123
+ response.tap do |res|
124
+ %w[access id refresh].each do |name|
125
+ session["omniauth.pc.#{name}_token"] = res.body["#{name}_token"]
126
+ end
117
127
  end
118
128
  end
119
- end
120
129
 
121
- def get_userinfo!
122
- endpoint = URI(discovered_configuration["userinfo_endpoint"])
123
- token = session["omniauth.pc.access_token"]
130
+ def get_userinfo!
131
+ endpoint = URI(discovered_configuration["userinfo_endpoint"])
132
+ token = session["omniauth.pc.access_token"]
124
133
 
125
- connection.get(endpoint, {}, "Authorization" => "Bearer #{token}")
126
- end
134
+ connection.get(endpoint, {}, "Authorization" => "Bearer #{token}")
135
+ end
127
136
 
128
- def engage_logout!
129
- redirect end_session_uri
130
- end
137
+ def engage_logout!
138
+ redirect end_session_uri
139
+ end
131
140
 
132
- def on_logout_path?
133
- # FIXME: maybe don't hardcode this
134
- request.path.end_with?("#{request_path}/logout")
135
- end
141
+ def on_logout_path?
142
+ # FIXME: maybe don't hardcode this
143
+ request.path.end_with?("#{request_path}/logout")
144
+ end
136
145
 
137
- def store_new_state!
138
- session["omniauth.state"] = SecureRandom.hex(16)
139
- end
146
+ def store_new_state!
147
+ session["omniauth.state"] = SecureRandom.hex(16)
148
+ end
140
149
 
141
- def current_state
142
- session["omniauth.state"]
143
- end
150
+ def current_state
151
+ session["omniauth.state"]
152
+ end
144
153
 
145
- def store_new_nonce!
146
- session["omniauth.nonce"] = SecureRandom.hex(16)
147
- end
154
+ def store_new_nonce!
155
+ session["omniauth.nonce"] = SecureRandom.hex(16)
156
+ end
148
157
 
149
- def verify_state!(other_state)
150
- if other_state != current_state
151
- raise "a request came back with a different 'state' parameter than what we had last stored."
158
+ def verify_state!(other_state)
159
+ # rubocop:disable Style/GuardClause
160
+ if other_state != current_state
161
+ raise "a request came back with a different 'state' parameter than what we had last stored."
162
+ end
163
+ # rubocop:enable Style/GuardClause
152
164
  end
153
165
  end
154
166
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omniauth-proconnect
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: '0.4'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stéphane Maniaci
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-04-30 00:00:00.000000000 Z
10
+ date: 2025-05-23 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: faraday
@@ -51,8 +51,9 @@ dependencies:
51
51
  - - ">="
52
52
  - !ruby/object:Gem::Version
53
53
  version: '0'
54
- description: An OmniAuth strategy for ProConnect, an official OIDC solution for French
55
- professionnals to login.
54
+ description: |
55
+ An OmniAuth strategy for ProConnect, an official
56
+ OIDC solution for French professionnals to login.
56
57
  email:
57
58
  - stephane.maniaci@gmail.com
58
59
  executables: []
@@ -61,6 +62,7 @@ extra_rdoc_files: []
61
62
  files:
62
63
  - ".rspec"
63
64
  - ".rubocop.yml"
65
+ - ".rubocop_todo.yml"
64
66
  - LICENSE.txt
65
67
  - README.md
66
68
  - Rakefile