mirror of
https://github.com/System-End/identity-vault.git
synced 2026-04-19 16:28:21 +00:00
feat: credential rotation for OAuth apps (#178)
This commit is contained in:
parent
73f87f0f9f
commit
e04d3e1119
10 changed files with 58 additions and 10 deletions
|
|
@ -1,5 +1,5 @@
|
|||
class Backend::ProgramsController < Backend::ApplicationController
|
||||
before_action :set_program, only: [ :show, :edit, :update, :destroy ]
|
||||
before_action :set_program, only: [ :show, :edit, :update, :destroy, :rotate_credentials ]
|
||||
|
||||
hint :list_navigation, on: :index
|
||||
hint :back_navigation, on: :index
|
||||
|
|
@ -61,6 +61,13 @@ class Backend::ProgramsController < Backend::ApplicationController
|
|||
redirect_to backend_programs_path, notice: "Program was successfully deleted."
|
||||
end
|
||||
|
||||
def rotate_credentials
|
||||
authorize @program
|
||||
@program.rotate_credentials!
|
||||
redirect_to backend_program_path(@program), notice: "Credentials have been rotated. Make sure to update any integrations using the old secret/API key."
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def set_program
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
class DeveloperAppsController < ApplicationController
|
||||
before_action :require_developer_mode
|
||||
before_action :set_app, only: [ :show, :edit, :update, :destroy ]
|
||||
before_action :set_app, only: [ :show, :edit, :update, :destroy, :rotate_credentials ]
|
||||
|
||||
def index
|
||||
@apps = current_identity.owned_developer_apps.order(created_at: :desc)
|
||||
|
|
@ -43,6 +43,11 @@ class DeveloperAppsController < ApplicationController
|
|||
redirect_to developer_apps_path, notice: t(".success"), status: :see_other
|
||||
end
|
||||
|
||||
def rotate_credentials
|
||||
@app.rotate_credentials!
|
||||
redirect_to developer_app_path(@app), notice: t(".success")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def require_developer_mode
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ class Identity::ReapAgedOutUsersJob < ApplicationJob
|
|||
queue_as :default
|
||||
|
||||
def perform
|
||||
aged_out = Identity.where(ysws_eligible: true, hq_override: [false, nil])
|
||||
aged_out = Identity.where(ysws_eligible: true, hq_override: [ false, nil ])
|
||||
.where("birthday <= ?", 19.years.ago.to_date)
|
||||
|
||||
reaped_count = 0
|
||||
|
|
@ -15,4 +15,4 @@ class Identity::ReapAgedOutUsersJob < ApplicationJob
|
|||
|
||||
Rails.logger.info "ReapAgedOutUsersJob: marked #{reaped_count} #{"user".pluralize reaped_count} as alumni and ineligible"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -95,6 +95,12 @@ class Program < ApplicationRecord
|
|||
onboarding_scenario_class&.new(identity)
|
||||
end
|
||||
|
||||
def rotate_credentials!
|
||||
self.secret = SecureRandom.hex(32)
|
||||
self.program_key = "prgmk." + SecureRandom.hex(32)
|
||||
save!
|
||||
end
|
||||
|
||||
def self.find_by_redirect_uri_host(url)
|
||||
return nil if url.blank?
|
||||
begin
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ class ProgramPolicy < ApplicationPolicy
|
|||
|
||||
def update_onboarding_scenario? = user&.super_admin?
|
||||
|
||||
def rotate_credentials? = user_is_program_manager?
|
||||
|
||||
class Scope < Scope
|
||||
def resolve
|
||||
if user.program_manager? || user.super_admin?
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ class AnalyticsService
|
|||
totals.map do |scenario, total|
|
||||
prom = promoted[scenario] || 0
|
||||
rate = total > 0 ? ((prom.to_f / total) * 100).round(1) : 0
|
||||
[scenario || "default", { total: total, promoted: prom, rate: rate }]
|
||||
[ scenario || "default", { total: total, promoted: prom, rate: rate } ]
|
||||
end.sort_by { |_, v| -v[:total] }.to_h
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -60,6 +60,11 @@
|
|||
<label>api key</label>
|
||||
<input type="text" value="<%= @program.program_key %>" readonly onclick="this.select()" data-click-to-copy autocomplete="off">
|
||||
</div>
|
||||
<% if policy(@program).rotate_credentials? %>
|
||||
<div class="form-row" style="margin-top: 0.5rem;">
|
||||
<%= link_to "rotate secret & api key", rotate_credentials_backend_program_path(@program), method: :post, data: { confirm: "are you sure? this will invalidate the current secret and api key. any integrations using them will break." }, class: "btn btn-danger" %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% if @program.redirect_uri.present? %>
|
||||
|
|
|
|||
|
|
@ -37,8 +37,13 @@
|
|||
<% end %>
|
||||
<small class="usn" style="display: block; margin-top: 0.25rem;"><%= t ".auth_link_hint" %></small>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<div>
|
||||
<%= button_to t(".rotate_credentials"), rotate_credentials_developer_app_path(@app), method: :post, class: "danger small-btn",
|
||||
form: { "hx-confirm": t(".rotate_confirm") } %>
|
||||
<small class="usn" style="display: block; margin-top: 0.25rem;"><%= t ".rotate_hint" %></small>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section-card" style="margin-bottom: 1.5rem;">
|
||||
<h3><%= t ".configuration" %></h3>
|
||||
|
|
|
|||
|
|
@ -157,6 +157,9 @@ en:
|
|||
edit: Edit
|
||||
delete: Delete
|
||||
delete_confirm: Are you sure you want to delete this app? This cannot be undone.
|
||||
rotate_credentials: Rotate Secret & API Key
|
||||
rotate_confirm: Are you sure? This will invalidate your current client secret and API key, breaking any existing integrations using those credentials.
|
||||
rotate_hint: If your credentials have been compromised, you can rotate them to generate new ones. Just make sure to update your integration with the new credentials afterward!
|
||||
client_id: Client ID
|
||||
click_to_copy_client_id: click to copy client ID
|
||||
blank_slate:
|
||||
|
|
@ -183,6 +186,9 @@ en:
|
|||
edit_app: Edit App
|
||||
delete_app: Delete App
|
||||
delete_confirm: Are you sure you want to delete this app? This action cannot be undone and will revoke all existing tokens.
|
||||
rotate_credentials: Rotate Secret & API Key
|
||||
rotate_confirm: Are you sure? This will generate a new client secret and API key. The old ones will stop working immediately.
|
||||
rotate_hint: If your credentials have been compromised, rotate them here.
|
||||
new:
|
||||
title: Create New OAuth App
|
||||
back_to_apps: ← Back to Apps
|
||||
|
|
@ -218,6 +224,8 @@ en:
|
|||
success: OAuth app updated successfully!
|
||||
destroy:
|
||||
success: OAuth app deleted successfully!
|
||||
rotate_credentials:
|
||||
success: OAuth app credentials rotated successfully!
|
||||
require_developer_mode:
|
||||
developer_mode_required: Developer mode is not enabled for your account.
|
||||
set_app:
|
||||
|
|
@ -671,4 +679,4 @@ en:
|
|||
delete_confirm: Are you sure you want to delete this address?
|
||||
add_new: Add a new address
|
||||
add_button: Add Address
|
||||
done: Done
|
||||
done: Done
|
||||
|
|
|
|||
|
|
@ -226,7 +226,12 @@ Rails.application.routes.draw do
|
|||
end
|
||||
end
|
||||
|
||||
resources :programs
|
||||
resources :programs do
|
||||
member do
|
||||
post :rotate_credentials
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
post "/break_glass", to: "break_glass#create"
|
||||
|
||||
|
|
@ -356,7 +361,12 @@ Rails.application.routes.draw do
|
|||
|
||||
resources :authorized_applications, only: [ :index, :destroy ]
|
||||
|
||||
resources :developer_apps, path: "developer/apps"
|
||||
resources :developer_apps, path: "developer/apps" do
|
||||
member do
|
||||
post :rotate_credentials
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
namespace :api do
|
||||
namespace :v1 do
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue