If you don't need the id before saving the object, you should use new instead of new_with_id. new_with_id should only be used if you need the id before the object is saved.
91 lines
3.4 KiB
Ruby
91 lines
3.4 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require_relative "../model"
|
|
require "excon"
|
|
|
|
class OidcProvider < Sequel::Model
|
|
one_to_many :locked_domains
|
|
|
|
def self.name_for_ubid(ubid)
|
|
OidcProvider[UBID.to_uuid(ubid)]&.display_name
|
|
end
|
|
|
|
# Register a new OIDC Provider using their OIDC discovery information.
|
|
# If the customer who wants to use the provider provides a client ID and
|
|
# client secret, pass those. If the OIDC provider supports anonymous
|
|
# dynamic client registration, you don't need to provide a client id
|
|
# and secret, and this will use dynamic client registration to register
|
|
# a new client. If the OIDC provider does not provide OIDC discovery
|
|
# information, you'll need to be provided all OIDC information and
|
|
# create the instance manually using OidcProvider.create.
|
|
def self.register(display_name, url, client_id: nil, client_secret: nil)
|
|
# new_with_id needed for callback_url before saving
|
|
oidc_provider = new_with_id(display_name:)
|
|
|
|
uri = URI(url)
|
|
unless url.end_with?("/.well-known/openid-configuration")
|
|
uri.path += "/.well-known/openid-configuration"
|
|
end
|
|
response = Excon.get(uri.to_s, headers: {"Accept" => "application/json"}, expects: 200)
|
|
config_info = JSON.parse(response.body)
|
|
url = config_info.fetch("issuer")
|
|
authorization_endpoint = URI(config_info.fetch("authorization_endpoint")).path
|
|
token_endpoint = URI(config_info.fetch("token_endpoint")).path
|
|
userinfo_endpoint = URI(config_info.fetch("userinfo_endpoint")).path
|
|
jwks_uri = config_info.fetch("jwks_uri")
|
|
|
|
unless client_id && client_secret
|
|
response = Excon.post(config_info["registration_endpoint"],
|
|
headers: {"Accept" => "application/json", "Content-Type" => "application/json"},
|
|
body: {
|
|
client_name: "Ubicloud",
|
|
redirect_uris: [oidc_provider.callback_url],
|
|
scopes: "openid email"
|
|
}.to_json)
|
|
|
|
registration_info = JSON.parse(response.body)
|
|
raise "Unable to register with oidc provider: #{response.status} #{registration_info.inspect}" unless response.status == 201
|
|
client_id = registration_info.fetch("client_id")
|
|
client_secret = registration_info.fetch("client_secret")
|
|
registration_client_uri = registration_info["registration_client_uri"]
|
|
registration_access_token = registration_info["registration_access_token"]
|
|
end
|
|
|
|
oidc_provider.update(
|
|
url:,
|
|
client_id:,
|
|
client_secret:,
|
|
authorization_endpoint:,
|
|
token_endpoint:,
|
|
userinfo_endpoint:,
|
|
jwks_uri:,
|
|
registration_client_uri:,
|
|
registration_access_token:
|
|
)
|
|
end
|
|
|
|
plugin ResourceMethods, encrypted_columns: [:client_secret, :registration_access_token]
|
|
|
|
def callback_url
|
|
"#{Config.base_url}/auth/#{ubid}/callback"
|
|
end
|
|
end
|
|
|
|
# Table: oidc_provider
|
|
# Columns:
|
|
# id | uuid | PRIMARY KEY
|
|
# client_id | text | NOT NULL
|
|
# client_secret | text | NOT NULL
|
|
# display_name | text | NOT NULL
|
|
# url | text | NOT NULL
|
|
# authorization_endpoint | text | NOT NULL
|
|
# token_endpoint | text | NOT NULL
|
|
# userinfo_endpoint | text | NOT NULL
|
|
# jwks_uri | text | NOT NULL
|
|
# registration_client_uri | text |
|
|
# registration_access_token | text |
|
|
# Indexes:
|
|
# oidc_provider_pkey | PRIMARY KEY btree (id)
|
|
# Referenced By:
|
|
# locked_domain | locked_domain_oidc_provider_id_fkey | (oidc_provider_id) REFERENCES oidc_provider(id)
|