omniauth-entra-id 3.0.1 → 3.1.1

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: 8558b73bf91e883370f1545996ad524af244f85a42f2226d959f7ec5ff1aad7c
4
- data.tar.gz: 20d399da5278f50bd30e286011d27f5b9bf0927137d45897ac5d3222dcdb9973
3
+ metadata.gz: f88d4d932a03e4edf7a69461140c83eab2a408c1c61798acc5e26bedfdf0519f
4
+ data.tar.gz: 78928ac033c9a312d47491c7414f0fee3962144d97bbae3150a519ff7226c6bb
5
5
  SHA512:
6
- metadata.gz: aec624842a87a29eda78e9015fb3b82313ec17f8538b6d62ea8f9adf7b86d89df3f349d2880729a20c703c26a91b84a2feb69abf177080495117a00b3801f80b
7
- data.tar.gz: 8e2528b185ad7577504a592cb09663e1891035c10ea65e856019374eafa03aa81c8e932bc1aedbbbdfbf1db17ede59c36cac76cb8f5088c0b47573cdeac13a1f
6
+ metadata.gz: f1333c75cc62116751fbb81277b8139597cc8cb776f17cfd6acae367b4d2d9f94ad8e00cafdac68ec26bd1ac8a2157333246da52b07e3145c3ca44d74d4a3865
7
+ data.tar.gz: f9b3ab664ca1275af9d6b8bfbe3714c47080d3c506a2188833bfa9adbc5ee32c77fed8e2f758ee22071c7d503e45c601913cbb9c19ef6e15f2ddf3b828369bbb
data/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Change Log
2
2
 
3
+ ## v3.1.1 (2025-09-12)
4
+
5
+ * Validates the JWT `iss` (issuer) claim for `consumers` tenants properly, using the global GUID for that use case, resolving #51 (reported by @2called-chaos)
6
+
7
+ ## v3.1.0 (2025-06-17)
8
+
9
+ * Provides a way to ignore TID when constructing a user UID, easing migration from v2.x, via the new `ignore_tid` option, resolving #42 (reported by @s-andringa)
10
+ * Handles a missing (`nil`) TID, via #46 (thanks to @frenkel)
11
+ * Ruby 3.4 "officially" supported through coverage in CI, via #47 (thanks to @hakeem0114)
12
+ * Supports JWT gem v2.9.x or v3.x, via #48 (thanks to @djpremier)
13
+
3
14
  ## v3.0.1 (2024-11-21)
4
15
 
5
16
  * Fixes a minor error in [`UPGRADING.md`](UPGRADING.md) reported in #38, via #40 (thanks to @kennethgeerts)
data/README.md CHANGED
@@ -104,19 +104,20 @@ To have your application authenticate with Entra via a client secret, specify `c
104
104
 
105
105
  If you're using the client assertion flow, you need to register your certificate in the Entra portal. For more information, please see [the documentation](https://learn.microsoft.com/en-us/entra/identity-platform/certificate-credentials).
106
106
 
107
- | Option | Use |
108
- | ------ | --- |
109
- | `client_id` | **Mandatory.** Client ID for the 'application' (integration) configured on the Entra side. Found via the Entra UI. |
110
- | `client_secret` | **Mandatory for client secret flow.** Client secret for the 'application' (integration) configured on the Entra side. Found via the Entra UI. Don't give this if using client assertion flow. |
111
- | `certificate_path` | **Mandatory for client assertion flow.** Don't give this if using a client secret instead of client assertion. This should be the filepath to a PKCS#12 file. |
112
- | `tenant_id` | **Mandatory for client assertion flow.** Entra Tenant ID for multi-tenanted use. Default is `common`. Forms part of the Entra OAuth URL - `{base}/{tenant_id}/oauth2/v2.0/...` |
113
- | `base_url` | Location of Entra login page, for specialised requirements; default is `OmniAuth::Strategies::EntraId::BASE_URL` (at the time of writing, this is `https://login.microsoftonline.com`). |
114
- | `tenant_name` | For what is currently known by its old name of "Azure ActiveDirectory B2C" (and only active if `custom_policy` is also provided - see below), set the tenancy name to constructs the correct B2C endpoint of `{tenant_name}.b2clogin.com/{tenant_name}.onmicrosoft.com/{custom_policy>}" and uses that for auth calls. This is a convenience feature; the `base_entra_url` option could also be manually built up in the same way. |
115
- | `custom_policy` | Custom policy. Default is nil. Used in conjunction with `tenant_name`- see above. |
116
- | `authorize_params` | Additional parameters passed as URL query data in the initial OAuth redirection to Microsoft. See below for more. Empty Hash default. |
117
- | `domain_hint` | If defined, sets (overwriting, if already present) `domain_hint` inside `authorize_params`. Default `nil` / none. |
118
- | `scope` | If defined, sets (overwriting, if already present) `scope` inside `authorize_params`. Default is `OmniAuth::Strategies::EntraId::DEFAULT_SCOPE` (at the time of writing, this is `'openid profile email'`). |
119
- | `adfs?` or `adfs` | If set to `true`, modifies the URLs so they work with an on-premise AD FS server (Active Directory Federation Services). In order to use this you also need to set the `base_url` correctly and fill the `tenant_id` with `'adfs'`. Note that the option name variation without the question mark only works for directly-specified options; provider classes must always define an override method called `adfs?`. |
107
+ | Option | Use |
108
+ | ----------------------------- | --- |
109
+ | `client_id` | **Mandatory.** Client ID for the 'application' (integration) configured on the Entra side. Found via the Entra UI. |
110
+ | `client_secret` | **Mandatory for client secret flow.** Client secret for the 'application' (integration) configured on the Entra side. Found via the Entra UI. Don't give this if using client assertion flow. |
111
+ | `certificate_path` | **Mandatory for client assertion flow.** Don't give this if using a client secret instead of client assertion. This should be the filepath to a PKCS#12 file. |
112
+ | `tenant_id` | **Mandatory for client assertion flow.** Entra Tenant ID for multi-tenanted use. Default is `common`. Forms part of the Entra OAuth URL - `{base}/{tenant_id}/oauth2/v2.0/...` |
113
+ | `base_url` | Location of Entra login page, for specialised requirements; default is `OmniAuth::Strategies::EntraId::BASE_URL` (at the time of writing, this is `https://login.microsoftonline.com`). |
114
+ | `tenant_name` | For what is currently known by its old name of "Azure ActiveDirectory B2C" (and only active if `custom_policy` is also provided - see below), set the tenancy name to constructs the correct B2C endpoint of `{tenant_name}.b2clogin.com/{tenant_name}.onmicrosoft.com/{custom_policy>}" and uses that for auth calls. This is a convenience feature; the `base_entra_url` option could also be manually built up in the same way. |
115
+ | `custom_policy` | Custom policy. Default is nil. Used in conjunction with `tenant_name`- see above. |
116
+ | `authorize_params` | Additional parameters passed as URL query data in the initial OAuth redirection to Microsoft. See below for more. Empty Hash default. |
117
+ | `domain_hint` | If defined, sets (overwriting, if already present) `domain_hint` inside `authorize_params`. Default `nil` / none. |
118
+ | `scope` | If defined, sets (overwriting, if already present) `scope` inside `authorize_params`. Default is `OmniAuth::Strategies::EntraId::DEFAULT_SCOPE` (at the time of writing, this is `'openid profile email'`). |
119
+ | `ìgnore_tid?` or `ignore_tid` | If set to `true`, tenant ID (TID) is *not* included for a user's UID from Entra. Use if you are confident that an Entra OID will be globally unique and have existing OID-only UIDs in use. Default is `false`; both TID and OID are used to form a UID. Note that the option name variation without the question mark only works for directly-specified options; provider classes must always define an override method called `ignore_tid?`. |
120
+ | `adfs?` or `adfs` | If set to `true`, modifies the URLs so they work with an on-premise AD FS server (Active Directory Federation Services). In order to use this you also need to set the `base_url` correctly and fill the `tenant_id` with `'adfs'`. Note that the option name variation without the question mark only works for directly-specified options; provider classes must always define an override method called `adfs?`. |
120
121
 
121
122
  In addition, as a special case, if the request URL contains a query parameter `prompt`, then this will be written into `authorize_params` under that key, overwriting if present any other value there. Note that this comes from the current request URL at the time OAuth flow is commencing, _not_ via static options Hash data or via a custom provider class - but you _could_ just as easily set `scope` inside a custom `authorize_params` returned from a provider class, as shown in an example later; the request URL query mechanism is just another way of doing the same thing.
122
123
 
data/UPGRADING.md CHANGED
@@ -73,9 +73,11 @@ This change is for UIDs and is the main reason for creating a V3 gem, whether or
73
73
  * The UID returned by OmniAuth for a user previously depended upon the `oid` (object ID) returned by Microsoft. As noted in #33 and fixed in #34, this _might not be unique_ and tenant ID (`tid`) is supposed to be considered too.
74
74
  * Out-of-box, Entra ID will do this. If you were an Azure ActiveDirectory V2 (old-name gem, version 2.x) user, then you will have been receiving different UIDs based only on the `oid` from Microsoft.
75
75
  * **The change of OID might break the connection between a previously-registered and logged in user and a new login** as usually, you need to store the OmniAuth UID somewhere alongside or within your User records when a user is "connected to" an external OAuth service such as Entra ID.
76
+ * **However, there is a strong argument that TID is not needed** - see https://github.com/pond/omniauth-entra-id/issues/42 for a good argument to that end.
76
77
 
77
- You have two options, should the issue affect you (and it almost certainly will).
78
+ You have three options, should the issue affect you (and it almost certainly will).
78
79
 
80
+ * If you are confident that you still only need the OID, set the `ignore_tid` option to `true` alongside `client_id` and `client_secret` in your OmniAuth Entra ID initialiser or your custom provider class given to that initialiser, if you use one. See the top-level `README.md` for more.
79
81
  * If you can determine the tenant IDs for all users in your database, you can just migrate the UIDs. The new UID is just a simple concatenation of tenant ID and object ID, so treating the UID as a string, add the tenant ID as a prefix without any other changes in your migration and things should work fine thereafter.
80
82
  * Otherwise, you should lazy-migrate:
81
83
  - As usual, in your OAuth callback handler, `request.env['omniauth.auth'].uid` gives the UID - but now that's the "new" Entra gem's value which includes tenant ID.
@@ -1,8 +1,8 @@
1
1
  module OmniAuth
2
2
  module Entra
3
3
  module Id
4
- VERSION = "3.0.1"
5
- DATE = "2024-11-21"
4
+ VERSION = "3.1.1"
5
+ DATE = "2025-09-12"
6
6
  end
7
7
  end
8
8
  end
@@ -9,14 +9,18 @@ module OmniAuth
9
9
 
10
10
  option :name, 'entra_id'
11
11
  option :tenant_provider, nil
12
+ option :ignore_tid, false
12
13
  option :jwt_leeway, 60
13
14
 
14
- DEFAULT_SCOPE = 'openid profile email'
15
- COMMON_TENANT_ID = 'common'
16
- AD_FS_TENANT_ID = 'adfs'
15
+ DEFAULT_SCOPE = 'openid profile email'
16
+ COMMON_TENANT_ID = 'common'
17
+ AD_FS_TENANT_ID = 'adfs'
18
+ ORGANIZATIONS_TENANT_ID = 'organizations'
19
+ CONSUMERS_TENANT_ID = 'consumers'
20
+ CONSUMERS_TENANT_GUID = '9188040d-6c67-4c5b-b112-36a304b66dad'
17
21
 
18
- # The tenant_provider must return client_id, client_secret and,
19
- # optionally, tenant_id and base_url.
22
+ # The tenant_provider argument is how the provider class is eventually
23
+ # passed to us, if one is used instead of an options Hash.
20
24
  #
21
25
  args [:tenant_provider]
22
26
 
@@ -58,6 +62,7 @@ module OmniAuth
58
62
  options.custom_policy = provider.custom_policy if provider.respond_to?(:custom_policy)
59
63
  options.authorize_params = provider.authorize_params if provider.respond_to?(:authorize_params)
60
64
  options.authorize_params.domain_hint = provider.domain_hint if provider.respond_to?(:domain_hint) && provider.domain_hint
65
+ options.ignore_tid = provider.ignore_tid? if provider.respond_to?(:ignore_tid?) && provider.ignore_tid?
61
66
  options.authorize_params.prompt = request.params['prompt'] if defined?(request) && request.params['prompt']
62
67
 
63
68
  options.authorize_params.scope = if defined?(request) && request.params['scope']
@@ -88,14 +93,32 @@ module OmniAuth
88
93
 
89
94
  uid do
90
95
  #
91
- # https://learn.microsoft.com/en-us/entra/identity-platform/migrate-off-email-claim-authorization
96
+ # Note 1:
97
+ #
98
+ # https://learn.microsoft.com/en-us/entra/identity-platform/migrate-off-email-claim-authorization
92
99
  #
93
100
  # OID alone might not be unique; TID must be included. An alternative
94
101
  # would be to use 'sub' but this is only unique in client/app
95
102
  # registration context. If a different app registration is used, the
96
- # 'sub' values can be different too.
103
+ # 'sub' values can be different too...
104
+ #
105
+ # Note 2:
106
+ #
107
+ # https://github.com/pond/omniauth-entra-id/issues/42
97
108
  #
98
- raw_info['tid'] + raw_info['oid']
109
+ # ...but not everyone agrees on the necessity of a TID and if migrating
110
+ # from an earlier version of this gem where user data already includes
111
+ # OID-only identifiers, you might elect to avoid a difficult migration
112
+ # by opting out - set the "ignore_tid" option to 'true'.
113
+ #
114
+ # NB: If the TID is missing or blank the UID uses only the OID, just as
115
+ # if the "ignore_tid" option were set.
116
+ #
117
+ if options.ignore_tid? || raw_info['tid'].nil?
118
+ raw_info['oid']
119
+ else
120
+ raw_info['tid'] + raw_info['oid']
121
+ end
99
122
  end
100
123
 
101
124
  info do
@@ -140,6 +163,8 @@ module OmniAuth
140
163
  # for AD FS local instances, as we don't put a valid tenant ID in its
141
164
  # place, but "adfs" (see AD_FS_TENANT_ID) instead.
142
165
  #
166
+ # TODO: Unclear about approach to use for ORGANIZATIONS_TENANT_ID.
167
+ #
143
168
  do_not_verify = (
144
169
  options.tenant_id.nil? ||
145
170
  options.tenant_id == COMMON_TENANT_ID ||
@@ -148,22 +173,22 @@ module OmniAuth
148
173
 
149
174
  issuer = if do_not_verify
150
175
  nil
176
+ elsif options.tenant_id == CONSUMERS_TENANT_ID
177
+ "#{options.base_url || BASE_URL}/#{CONSUMERS_TENANT_GUID}/v2.0"
151
178
  else
152
179
  "#{options.base_url || BASE_URL}/#{options.tenant_id}/v2.0"
153
180
  end
154
181
 
155
182
  # https://learn.microsoft.com/en-us/entra/identity-platform/id-tokens#validate-tokens
156
183
  #
157
- JWT::Verify.verify_claims(
158
- id_token_data,
159
- verify_iss: !issuer.nil?,
160
- iss: issuer,
161
- verify_aud: true,
162
- aud: options.client_id,
163
- verify_expiration: true,
164
- verify_not_before: true,
165
- leeway: options[:jwt_leeway]
166
- )
184
+ verify_params = {
185
+ aud: options.client_id,
186
+ exp: { leeway: options.jwt_leeway },
187
+ nbf: { leeway: options.jwt_leeway }
188
+ }
189
+ verify_params[:iss] = issuer unless issuer.nil?
190
+
191
+ ::JWT::Claims.verify_payload!(id_token_data, verify_params)
167
192
 
168
193
  auth_token_data = begin
169
194
  ::JWT.decode(access_token.token, nil, false).first
@@ -14,7 +14,7 @@ Gem::Specification.new do |s|
14
14
  s.authors = [ 'RIPA Global' ]
15
15
  s.email = [ 'dev@ripaglobal.com' ]
16
16
  s.licenses = [ 'MIT' ]
17
- s.homepage = 'https://github.com/RIPAGlobal/omniauth-entra-id'
17
+ s.homepage = 'https://github.com/pond/omniauth-entra-id'
18
18
 
19
19
  s.required_ruby_version = Gem::Requirement.new('>= 3.0.0')
20
20
  s.require_paths = ['lib']
@@ -39,15 +39,16 @@ Gem::Specification.new do |s|
39
39
  }
40
40
 
41
41
  s.metadata = {
42
- 'homepage_uri' => 'https://www.ripaglobal.com/',
43
- 'bug_tracker_uri' => 'https://github.com/RIPAGlobal/omniauth-entra-id/issues/',
44
- 'changelog_uri' => 'https://github.com/RIPAGlobal/omniauth-entra-id/blob/master/CHANGELOG.md',
45
- 'source_code_uri' => 'https://github.com/RIPAGlobal/omniauth-entra-id'
42
+ 'homepage_uri' => s.homepage,
43
+ 'bug_tracker_uri' => 'https://github.com/pond/omniauth-entra-id/issues/',
44
+ 'changelog_uri' => 'https://github.com/pond/omniauth-entra-id/blob/master/CHANGELOG.md',
45
+ 'source_code_uri' => 'https://github.com/pond/omniauth-entra-id'
46
46
  }
47
47
 
48
- s.add_runtime_dependency('omniauth-oauth2', '~> 1.8')
48
+ s.add_runtime_dependency 'jwt', '>= 2.9.2'
49
+ s.add_runtime_dependency 'omniauth-oauth2', '~> 1.8'
49
50
 
50
- s.add_development_dependency('debug', '~> 1.9 ')
51
- s.add_development_dependency('rake', '~> 13.2 ')
52
- s.add_development_dependency('rspec', '~> 3.13')
51
+ s.add_development_dependency 'debug', '~> 1.11'
52
+ s.add_development_dependency 'rake', '~> 13.3'
53
+ s.add_development_dependency 'rspec', '~> 3.13'
53
54
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omniauth-entra-id
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.1
4
+ version: 3.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - RIPA Global
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-11-21 00:00:00.000000000 Z
11
+ date: 2025-09-12 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: jwt
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 2.9.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 2.9.2
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: omniauth-oauth2
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -30,28 +44,28 @@ dependencies:
30
44
  requirements:
31
45
  - - "~>"
32
46
  - !ruby/object:Gem::Version
33
- version: '1.9'
47
+ version: '1.11'
34
48
  type: :development
35
49
  prerelease: false
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
52
  - - "~>"
39
53
  - !ruby/object:Gem::Version
40
- version: '1.9'
54
+ version: '1.11'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rake
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
59
  - - "~>"
46
60
  - !ruby/object:Gem::Version
47
- version: '13.2'
61
+ version: '13.3'
48
62
  type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
- version: '13.2'
68
+ version: '13.3'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: rspec
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -86,14 +100,14 @@ files:
86
100
  - lib/omniauth/entra_id/version.rb
87
101
  - lib/omniauth/strategies/entra_id.rb
88
102
  - omniauth-entra-id.gemspec
89
- homepage: https://github.com/RIPAGlobal/omniauth-entra-id
103
+ homepage: https://github.com/pond/omniauth-entra-id
90
104
  licenses:
91
105
  - MIT
92
106
  metadata:
93
- homepage_uri: https://www.ripaglobal.com/
94
- bug_tracker_uri: https://github.com/RIPAGlobal/omniauth-entra-id/issues/
95
- changelog_uri: https://github.com/RIPAGlobal/omniauth-entra-id/blob/master/CHANGELOG.md
96
- source_code_uri: https://github.com/RIPAGlobal/omniauth-entra-id
107
+ homepage_uri: https://github.com/pond/omniauth-entra-id
108
+ bug_tracker_uri: https://github.com/pond/omniauth-entra-id/issues/
109
+ changelog_uri: https://github.com/pond/omniauth-entra-id/blob/master/CHANGELOG.md
110
+ source_code_uri: https://github.com/pond/omniauth-entra-id
97
111
  post_install_message:
98
112
  rdoc_options: []
99
113
  require_paths:
@@ -109,7 +123,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
109
123
  - !ruby/object:Gem::Version
110
124
  version: '0'
111
125
  requirements: []
112
- rubygems_version: 3.5.21
126
+ rubygems_version: 3.5.16
113
127
  signing_key:
114
128
  specification_version: 4
115
129
  summary: OAuth 2 authentication with the Entra ID API.