standard_id 0.22.0 → 0.23.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 +4 -4
- data/app/controllers/standard_id/api/oauth/callback/providers_controller.rb +17 -1
- data/app/controllers/standard_id/api/oauth/tokens_controller.rb +26 -0
- data/lib/generators/standard_id/install/templates/standard_id.rb +5 -0
- data/lib/standard_id/config/schema.rb +9 -0
- data/lib/standard_id/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ed15fb7068e789bc80676ae7d191b1b154c79adeedc60a58aa55c3c5e5e1c29f
|
|
4
|
+
data.tar.gz: 95cce0258343786169a8afcda56c91534e96f684b74f2764b7c8a66d838c4aab
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 41efa2cbf81c06d2bbc8747b68bb8f1f76a13684eda0512710d4bdc756132cfd1765c7b2d1580d938e326eb3ad19e04e6b627cc86d27f27bb1c718803864cadb
|
|
7
|
+
data.tar.gz: 07c359414b5800fd8151e5915bef1c51044cca4285c796c16c43e05c9593f903c8071c6da257d826cb3273d678c35faed27700807442f67e16ee1cc2cf3bcd28
|
|
@@ -19,7 +19,7 @@ module StandardId
|
|
|
19
19
|
].freeze
|
|
20
20
|
|
|
21
21
|
def callback
|
|
22
|
-
provider_response =
|
|
22
|
+
provider_response = fetch_provider_user_info
|
|
23
23
|
social_info = provider_response[:user_info]
|
|
24
24
|
provider_tokens = provider_response[:tokens]
|
|
25
25
|
account = find_or_create_account_from_social(social_info)
|
|
@@ -45,6 +45,22 @@ module StandardId
|
|
|
45
45
|
|
|
46
46
|
private
|
|
47
47
|
|
|
48
|
+
# Mirror of the web callback's OAuthError handling: emit
|
|
49
|
+
# SOCIAL_AUTH_FAILED for infrastructure-level provider failures
|
|
50
|
+
# (HTTP/DNS/SSL/timeouts surfaced as OAuthError by provider
|
|
51
|
+
# implementations) so host apps can observe provider outages on the
|
|
52
|
+
# API flow too. Scoped to the provider call — OAuthError subclasses
|
|
53
|
+
# raised later in the flow (SocialLinkError, InvalidRequestError,
|
|
54
|
+
# ...) are policy/client errors, not infrastructure failures, and
|
|
55
|
+
# must not emit. The error re-raises into the standard
|
|
56
|
+
# handle_oauth_error JSON response.
|
|
57
|
+
def fetch_provider_user_info
|
|
58
|
+
get_user_info_from_provider(flow: resolve_flow_for(provider.provider_name))
|
|
59
|
+
rescue StandardId::OAuthError => e
|
|
60
|
+
emit_social_auth_failed(e)
|
|
61
|
+
raise
|
|
62
|
+
end
|
|
63
|
+
|
|
48
64
|
def resolve_flow_for(connection)
|
|
49
65
|
return :mobile unless connection == "apple"
|
|
50
66
|
|
|
@@ -21,6 +21,7 @@ module StandardId
|
|
|
21
21
|
}.freeze
|
|
22
22
|
|
|
23
23
|
before_action :extract_client_credentials_from_basic_auth
|
|
24
|
+
before_action :enforce_per_audience_rate_limit, only: :create
|
|
24
25
|
|
|
25
26
|
def create
|
|
26
27
|
response_data = flow_strategy_class.new(flow_strategy_params, request).execute
|
|
@@ -29,6 +30,31 @@ module StandardId
|
|
|
29
30
|
|
|
30
31
|
private
|
|
31
32
|
|
|
33
|
+
# Per-audience tightening on top of the global api_token_per_ip
|
|
34
|
+
# ceiling (rate_limits.api_token_per_audience_per_ip). Hand-rolled
|
|
35
|
+
# rather than the Rails rate_limit DSL on purpose: the DSL counts
|
|
36
|
+
# every request that reaches the action — a `by:` block returning nil
|
|
37
|
+
# does NOT exempt a request, it collapses into a shared bucket keyed
|
|
38
|
+
# without the discriminator (["rate-limit", scope, name, nil].compact),
|
|
39
|
+
# so one audience's rule would throttle every other audience's
|
|
40
|
+
# traffic. Here only requests that target a configured audience
|
|
41
|
+
# increment that audience's per-IP counter.
|
|
42
|
+
def enforce_per_audience_rate_limit
|
|
43
|
+
limits = StandardId.config.rate_limits.api_token_per_audience_per_ip
|
|
44
|
+
return if limits.blank?
|
|
45
|
+
|
|
46
|
+
Array(params[:audience]).each do |audience|
|
|
47
|
+
next unless audience.is_a?(String)
|
|
48
|
+
|
|
49
|
+
cap = limits[audience] || limits[audience.to_sym]
|
|
50
|
+
next if cap.blank?
|
|
51
|
+
|
|
52
|
+
cache_key = "rate-limit:#{self.class.controller_path}:api_token_per_audience:#{audience}:#{request.remote_ip}"
|
|
53
|
+
count = StandardId::RateLimitHandling::RATE_LIMIT_STORE.increment(cache_key, 1, expires_in: 15.minutes)
|
|
54
|
+
raise ActionController::TooManyRequests if count && count > cap.to_i
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
32
58
|
# Support HTTP Basic authentication for client credentials (RFC 6749 Section 2.3.1)
|
|
33
59
|
def extract_client_credentials_from_basic_auth
|
|
34
60
|
auth_header = request.headers["Authorization"]
|
|
@@ -368,6 +368,11 @@ StandardId.configure do |c|
|
|
|
368
368
|
# c.rate_limits.api_passwordless_start_per_target = 5 # per 15 minutes
|
|
369
369
|
# c.rate_limits.api_token_per_ip = 30 # per 15 minutes
|
|
370
370
|
|
|
371
|
+
# Optional per-audience tightening on top of api_token_per_ip. Only token
|
|
372
|
+
# requests targeting a configured audience count toward its cap (per IP,
|
|
373
|
+
# per 15 minutes); unlisted audiences are governed by the global ceiling.
|
|
374
|
+
# c.rate_limits.api_token_per_audience_per_ip = { "mobile_app" => 10 }
|
|
375
|
+
|
|
371
376
|
# ---------------------------------------------------------------------------
|
|
372
377
|
# Observability
|
|
373
378
|
# ---------------------------------------------------------------------------
|
|
@@ -328,6 +328,15 @@ StandardId::ConfigSchema.define do
|
|
|
328
328
|
field :api_passwordless_start_per_target, type: :integer, default: 5 # per 15 minutes
|
|
329
329
|
field :api_token_per_ip, type: :integer, default: 30 # per 15 minutes
|
|
330
330
|
|
|
331
|
+
# Optional per-audience tightening on top of the api_token_per_ip
|
|
332
|
+
# ceiling. A Hash of audience => max token requests per IP per 15
|
|
333
|
+
# minutes, e.g. `{ "mobile_app" => 10, "partner_api" => 30 }`. Only
|
|
334
|
+
# requests targeting a configured audience count toward that audience's
|
|
335
|
+
# limit; audiences without an entry are governed solely by the global
|
|
336
|
+
# api_token_per_ip ceiling. A request must pass both its audience cap
|
|
337
|
+
# and the global cap.
|
|
338
|
+
field :api_token_per_audience_per_ip, type: :hash, default: -> { {} }
|
|
339
|
+
|
|
331
340
|
# Dynamic client registration (RFC 7591) — throttle the open registration
|
|
332
341
|
# endpoint by IP so an enabled deployment can't be flooded with client rows.
|
|
333
342
|
field :dynamic_registration_per_ip, type: :integer, default: 10 # per hour
|
data/lib/standard_id/version.rb
CHANGED