mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-02-20 14:54:15 +01:00
Merge branch 'saml' into dev
This commit is contained in:
commit
94d4ed3d1a
3
Gemfile
3
Gemfile
@ -72,6 +72,7 @@ gem 'devise', '>= 4.9'
|
||||
gem 'omniauth', '~> 2.1'
|
||||
gem 'omniauth-oauth2'
|
||||
gem 'omniauth_openid_connect'
|
||||
gem 'omniauth-saml'
|
||||
gem 'omniauth-rails_csrf_protection', '~> 1.0'
|
||||
|
||||
gem 'rolify'
|
||||
@ -153,4 +154,4 @@ gem 'sentry-ruby'
|
||||
gem "reverse_markdown"
|
||||
|
||||
gem "ancestry"
|
||||
gem 'silencer', require: false
|
||||
gem 'silencer', require: false
|
||||
|
@ -292,6 +292,9 @@ GEM
|
||||
omniauth-rails_csrf_protection (1.0.1)
|
||||
actionpack (>= 4.2)
|
||||
omniauth (~> 2.0)
|
||||
omniauth-saml (2.1.0)
|
||||
omniauth (~> 2.0)
|
||||
ruby-saml (~> 1.12)
|
||||
omniauth_openid_connect (0.6.1)
|
||||
omniauth (>= 1.9, < 3)
|
||||
openid_connect (~> 1.1)
|
||||
@ -422,6 +425,9 @@ GEM
|
||||
rubocop (>= 1.7.0, < 2.0)
|
||||
ruby-progressbar (1.10.1)
|
||||
ruby-rc4 (0.1.5)
|
||||
ruby-saml (1.16.0)
|
||||
nokogiri (>= 1.13.10)
|
||||
rexml
|
||||
ruby-vips (2.1.4)
|
||||
ffi (~> 1.12)
|
||||
rubyXL (3.4.25)
|
||||
@ -579,6 +585,7 @@ DEPENDENCIES
|
||||
omniauth (~> 2.1)
|
||||
omniauth-oauth2
|
||||
omniauth-rails_csrf_protection (~> 1.0)
|
||||
omniauth-saml
|
||||
omniauth_openid_connect
|
||||
openlab_ruby
|
||||
overcommit
|
||||
|
@ -105,6 +105,13 @@ class API::AuthProvidersController < API::APIController
|
||||
auth_provider_mappings_attributes: [:id, :local_model, :local_field, :api_field, :api_endpoint, :api_data_type,
|
||||
:_destroy, { transformation: [:type, :format, :true_value, :false_value,
|
||||
{ mapping: %i[from to] }] }])
|
||||
elsif params['auth_provider']['providable_type'] == SamlProvider.name
|
||||
params.require(:auth_provider)
|
||||
.permit(:id, :name, :providable_type,
|
||||
providable_attributes: [:id, :sp_entity_id, :idp_sso_service_url, :profile_url, :idp_cert_fingerprint, :idp_cert],
|
||||
auth_provider_mappings_attributes: [:id, :local_model, :local_field, :api_field, :api_endpoint, :api_data_type,
|
||||
:_destroy, { transformation: [:type, :format, :true_value, :false_value,
|
||||
{ mapping: %i[from to] }] }])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -7,6 +7,7 @@ class SessionsController < Devise::SessionsController
|
||||
if active_provider.providable_type == 'DatabaseProvider'
|
||||
super
|
||||
else
|
||||
p active_provider
|
||||
redirect_post "/users/auth/#{active_provider.strategy_name}"
|
||||
end
|
||||
end
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
# Handle authentication actions via OmniAuth (used by SSO providers)
|
||||
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
||||
skip_before_action :verify_authenticity_token
|
||||
require 'sso_logger'
|
||||
logger = SsoLogger.new
|
||||
|
||||
|
@ -12,6 +12,7 @@ import { TypeMappingModal } from './type-mapping-modal';
|
||||
import { useImmer } from 'use-immer';
|
||||
import { Oauth2DataMappingForm } from './oauth2-data-mapping-form';
|
||||
import { OpenidConnectDataMappingForm } from './openid-connect-data-mapping-form';
|
||||
import { SamlDataMappingForm } from './saml-data-mapping-form';
|
||||
|
||||
export interface DataMappingFormProps<TFieldValues, TContext extends object> {
|
||||
register: UseFormRegister<TFieldValues>,
|
||||
@ -164,6 +165,11 @@ export const DataMappingForm = <TFieldValues extends FieldValues, TContext exten
|
||||
setValue={setValue}
|
||||
formState={formState}
|
||||
currentFormValues={currentFormValues} />}
|
||||
{providerType === 'SamlProvider' && <SamlDataMappingForm register={register}
|
||||
index={index}
|
||||
setValue={setValue}
|
||||
formState={formState}
|
||||
currentFormValues={currentFormValues} />}
|
||||
</div>
|
||||
</div>
|
||||
<div className="actions">
|
||||
|
@ -20,6 +20,7 @@ import { FabButton } from '../base/fab-button';
|
||||
import AuthProviderAPI from '../../api/auth-provider';
|
||||
import { OpenidConnectForm } from './openid-connect-form';
|
||||
import { DatabaseForm } from './database-form';
|
||||
import { SamlForm } from './saml-form';
|
||||
|
||||
declare const Application: IApplication;
|
||||
|
||||
@ -27,7 +28,8 @@ declare const Application: IApplication;
|
||||
const METHODS = {
|
||||
DatabaseProvider: 'local_database',
|
||||
OAuth2Provider: 'oauth2',
|
||||
OpenIdConnectProvider: 'openid_connect'
|
||||
OpenIdConnectProvider: 'openid_connect',
|
||||
SamlProvider: 'saml'
|
||||
};
|
||||
|
||||
interface ProviderFormProps {
|
||||
@ -116,6 +118,7 @@ export const ProviderForm: React.FC<ProviderFormProps> = ({ action, provider, on
|
||||
currentFormValues={output.providable_attributes as OpenIdConnectProvider}
|
||||
formState={formState}
|
||||
setValue={setValue} />}
|
||||
{providableType === 'SamlProvider' && <SamlForm register={register} strategyName={strategyName} formState={formState} />}
|
||||
{providableType && providableType !== 'DatabaseProvider' && <DataMappingForm register={register}
|
||||
control={control}
|
||||
formState={formState}
|
||||
|
@ -0,0 +1,87 @@
|
||||
import { Path, UseFormRegister } from 'react-hook-form';
|
||||
import { FieldValues } from 'react-hook-form/dist/types/fields';
|
||||
import { FormInput } from '../form/form-input';
|
||||
import { HtmlTranslate } from '../base/html-translate';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { UnpackNestedValue, UseFormSetValue, FormState } from 'react-hook-form/dist/types/form';
|
||||
import { FabButton } from '../base/fab-button';
|
||||
import { FieldPathValue } from 'react-hook-form/dist/types/path';
|
||||
import { AuthenticationProviderMapping } from '../../models/authentication-provider';
|
||||
|
||||
interface SamlDataMappingFormProps<TFieldValues> {
|
||||
register: UseFormRegister<TFieldValues>,
|
||||
setValue: UseFormSetValue<TFieldValues>,
|
||||
currentFormValues: Array<AuthenticationProviderMapping>,
|
||||
index: number,
|
||||
formState: FormState<TFieldValues>
|
||||
}
|
||||
|
||||
/**
|
||||
* Partial form to set the data mapping for an SAML provider.
|
||||
* The data mapping is the way to bind data from the SAML to the Fab-manager's database
|
||||
*/
|
||||
export const SamlDataMappingForm = <TFieldValues extends FieldValues>({ register, setValue, currentFormValues, index, formState }: SamlDataMappingFormProps<TFieldValues>) => {
|
||||
const { t } = useTranslation('admin');
|
||||
|
||||
const standardConfiguration = {
|
||||
'user.uid': { api_field: 'email' },
|
||||
'user.email': { api_field: 'email' },
|
||||
'user.username': { api_field: 'login' },
|
||||
'profile.first_name': { api_field: 'firstName' },
|
||||
'profile.last_name': { api_field: 'lastName' },
|
||||
'profile.phone': { api_field: 'primaryPhone' },
|
||||
'profile.address': { api_field: 'postalAddress' }
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the data mapping according to the standard OpenID Connect specification
|
||||
*/
|
||||
const openIdStandardConfiguration = (): void => {
|
||||
const model = currentFormValues[index]?.local_model;
|
||||
const field = currentFormValues[index]?.local_field;
|
||||
const configuration = standardConfiguration[`${model}.${field}`];
|
||||
if (configuration) {
|
||||
setValue(
|
||||
`auth_provider_mappings_attributes.${index}.api_field` as Path<TFieldValues>,
|
||||
configuration.api_field as UnpackNestedValue<FieldPathValue<TFieldValues, Path<TFieldValues>>>
|
||||
);
|
||||
if (configuration.transformation) {
|
||||
Object.keys(configuration.transformation).forEach((key) => {
|
||||
setValue(
|
||||
`auth_provider_mappings_attributes.${index}.transformation.${key}` as Path<TFieldValues>,
|
||||
configuration.transformation[key] as UnpackNestedValue<FieldPathValue<TFieldValues, Path<TFieldValues>>>
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="saml-data-mapping-form">
|
||||
<FormInput id={`auth_provider_mappings_attributes.${index}.api_endpoint`}
|
||||
type="hidden"
|
||||
register={register}
|
||||
rules={{ required: true }}
|
||||
formState={formState}
|
||||
defaultValue="user_info" />
|
||||
<FormInput id={`auth_provider_mappings_attributes.${index}.api_data_type`}
|
||||
type="hidden"
|
||||
register={register}
|
||||
rules={{ required: true }}
|
||||
formState={formState}
|
||||
defaultValue="json" />
|
||||
<FormInput id={`auth_provider_mappings_attributes.${index}.api_field`}
|
||||
register={register}
|
||||
rules={{ required: true }}
|
||||
formState={formState}
|
||||
placeholder="claim..."
|
||||
tooltip={<HtmlTranslate trKey="app.admin.authentication.saml_data_mapping_form.api_field_help_html" />}
|
||||
label={t('app.admin.authentication.saml_data_mapping_form.api_field')} />
|
||||
<FabButton
|
||||
icon={<i className="fa fa-magic" />}
|
||||
className="auto-configure-button"
|
||||
onClick={openIdStandardConfiguration}
|
||||
tooltip={t('app.admin.authentication.saml_data_mapping_form.openid_standard_configuration')} />
|
||||
</div>
|
||||
);
|
||||
};
|
@ -0,0 +1,63 @@
|
||||
import { FormInput } from '../form/form-input';
|
||||
import { UseFormRegister, FormState } from 'react-hook-form';
|
||||
import { FieldValues } from 'react-hook-form/dist/types/fields';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { FabOutputCopy } from '../base/fab-output-copy';
|
||||
import ValidationLib from '../../lib/validation';
|
||||
|
||||
interface SamlFormProps<TFieldValues> {
|
||||
register: UseFormRegister<TFieldValues>,
|
||||
formState: FormState<TFieldValues>,
|
||||
strategyName?: string,
|
||||
}
|
||||
|
||||
/**
|
||||
* Partial form to fill the OAuth2 settings for a new/existing authentication provider.
|
||||
*/
|
||||
export const SamlForm = <TFieldValues extends FieldValues>({ register, strategyName, formState }: SamlFormProps<TFieldValues>) => {
|
||||
const { t } = useTranslation('admin');
|
||||
|
||||
/**
|
||||
* Build the callback URL, based on the strategy name.
|
||||
*/
|
||||
const buildCallbackUrl = (): string => {
|
||||
return `${window.location.origin}/users/auth/${strategyName}/callback`;
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="saml-form">
|
||||
<hr/>
|
||||
<FabOutputCopy text={buildCallbackUrl()} label={t('app.admin.authentication.saml_form.authorization_callback_url')} />
|
||||
<FormInput id="providable_attributes.sp_entity_id"
|
||||
register={register}
|
||||
label={t('app.admin.authentication.saml_form.sp_entity_id')}
|
||||
tooltip={t('app.admin.authentication.saml_form.sp_entity_id_help')}
|
||||
rules={{ required: true }}
|
||||
formState={formState} />
|
||||
<FormInput id="providable_attributes.idp_sso_service_url"
|
||||
register={register}
|
||||
placeholder="https://sso.example.net..."
|
||||
label={t('app.admin.authentication.saml_form.idp_sso_service_url')}
|
||||
tooltip={t('app.admin.authentication.saml_form.idp_sso_service_url_help')}
|
||||
rules={{ required: true, pattern: ValidationLib.urlRegex }}
|
||||
formState={formState} />
|
||||
<FormInput id="providable_attributes.idp_cert_fingerprint"
|
||||
register={register}
|
||||
placeholder="E7:91:B2:E1:..."
|
||||
label={t('app.admin.authentication.saml_form.idp_cert_fingerprint')}
|
||||
formState={formState} />
|
||||
<FormInput id="providable_attributes.idp_cert"
|
||||
register={register}
|
||||
placeholder="-----BEGIN CERTIFICATE-----...-----END CERTIFICATE-----"
|
||||
label={t('app.admin.authentication.saml_form.idp_cert')}
|
||||
formState={formState} />
|
||||
<FormInput id="providable_attributes.profile_url"
|
||||
register={register}
|
||||
placeholder="https://exemple.net/user..."
|
||||
label={t('app.admin.authentication.saml_form.profile_edition_url')}
|
||||
tooltip={t('app.admin.authentication.saml_form.profile_edition_url_help')}
|
||||
rules={{ required: true, pattern: ValidationLib.urlRegex }}
|
||||
formState={formState} />
|
||||
</div>
|
||||
);
|
||||
};
|
@ -19,7 +19,8 @@
|
||||
const METHODS = {
|
||||
DatabaseProvider: 'local_database',
|
||||
OAuth2Provider: 'o_auth2',
|
||||
OpenIdConnectProvider: 'openid_connect'
|
||||
OpenIdConnectProvider: 'openid_connect',
|
||||
SamlProvider: 'saml'
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1,4 +1,4 @@
|
||||
export type ProvidableType = 'DatabaseProvider' | 'OAuth2Provider' | 'OpenIdConnectProvider';
|
||||
export type ProvidableType = 'DatabaseProvider' | 'OAuth2Provider' | 'OpenIdConnectProvider' | 'SamlProvider';
|
||||
|
||||
export interface AuthenticationProvider {
|
||||
id?: number,
|
||||
@ -7,7 +7,7 @@ export interface AuthenticationProvider {
|
||||
providable_type: ProvidableType,
|
||||
strategy_name: string
|
||||
auth_provider_mappings_attributes: Array<AuthenticationProviderMapping>,
|
||||
providable_attributes?: OAuth2Provider | OpenIdConnectProvider
|
||||
providable_attributes?: OAuth2Provider | OpenIdConnectProvider | SamlProvider
|
||||
}
|
||||
|
||||
export type mappingType = 'string' | 'text' | 'date' | 'integer' | 'boolean';
|
||||
@ -65,6 +65,15 @@ export interface OpenIdConnectProvider {
|
||||
extra_authorize_parameters?: string,
|
||||
}
|
||||
|
||||
export interface SamlProvider {
|
||||
id?: string,
|
||||
sp_entity_id: string,
|
||||
idp_sso_service_url: string
|
||||
idp_cert_fingerprint: string,
|
||||
idp_cert: string,
|
||||
profile_url: string,
|
||||
}
|
||||
|
||||
export interface MappingFields {
|
||||
user: Array<[string, mappingType]>,
|
||||
profile: Array<[string, mappingType]>
|
||||
|
@ -22,6 +22,7 @@
|
||||
@import "modules/authentication-provider/array-mapping-form";
|
||||
@import "modules/authentication-provider/data-mapping-form";
|
||||
@import "modules/authentication-provider/openid-connect-data-mapping-form";
|
||||
@import "modules/authentication-provider/saml-data-mapping-form";
|
||||
@import "modules/authentication-provider/provider-form";
|
||||
@import "modules/authentication-provider/type-mapping-modal";
|
||||
@import "modules/base/edit-destroy-buttons";
|
||||
|
@ -0,0 +1,7 @@
|
||||
.saml-data-mapping-form {
|
||||
.auto-configure-button {
|
||||
align-self: center;
|
||||
margin-top: 0.8rem;
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@ class AuthProvider < ApplicationRecord
|
||||
end
|
||||
end
|
||||
|
||||
PROVIDABLE_TYPES = %w[DatabaseProvider OAuth2Provider OpenIdConnectProvider].freeze
|
||||
PROVIDABLE_TYPES = %w[DatabaseProvider OAuth2Provider OpenIdConnectProvider SamlProvider].freeze
|
||||
|
||||
belongs_to :providable, polymorphic: true, dependent: :destroy
|
||||
accepts_nested_attributes_for :providable
|
||||
@ -27,7 +27,7 @@ class AuthProvider < ApplicationRecord
|
||||
|
||||
validates :providable_type, inclusion: { in: PROVIDABLE_TYPES }
|
||||
validates :name, presence: true, uniqueness: true
|
||||
validates_with UserUidMappedValidator, if: -> { %w[OAuth2Provider OpenIdConnectProvider].include?(providable_type) }
|
||||
validates_with UserUidMappedValidator, if: -> { %w[OAuth2Provider OpenIdConnectProvider SamlProvider].include?(providable_type) }
|
||||
|
||||
before_create :set_initial_state
|
||||
after_update :write_reload_config
|
||||
|
11
app/models/saml_provider.rb
Normal file
11
app/models/saml_provider.rb
Normal file
@ -0,0 +1,11 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# SAML Provider is a special type of AuthProvider which provides authentication through an external SSO server using
|
||||
# the SAML protocol.
|
||||
|
||||
class SamlProvider < ApplicationRecord
|
||||
has_one :auth_provider, as: :providable, dependent: :destroy
|
||||
|
||||
validates :sp_entity_id, presence: true
|
||||
validates :idp_sso_service_url, presence: true
|
||||
end
|
@ -19,3 +19,9 @@ if @provider.providable_type == OpenIdConnectProvider.name
|
||||
json.extra_authorize_params @provider.providable[:extra_authorize_params].to_json
|
||||
end
|
||||
end
|
||||
|
||||
if @provider.providable_type == SamlProvider.name
|
||||
json.providable_attributes do
|
||||
json.extract! @provider.providable, :id, :sp_entity_id, :idp_sso_service_url, :profile_url, :idp_cert_fingerprint, :idp_cert
|
||||
end
|
||||
end
|
||||
|
@ -20,3 +20,9 @@ if provider.providable_type == 'OpenIdConnectProvider'
|
||||
:extra_authorize_params
|
||||
end
|
||||
end
|
||||
|
||||
if provider.providable_type == 'SamlProvider'
|
||||
json.providable_attributes do
|
||||
json.extract! provider.providable, :id, :sp_entity_id, :idp_sso_service_url, :profile_url, :idp_cert_fingerprint, :idp_cert
|
||||
end
|
||||
end
|
||||
|
@ -91,6 +91,8 @@ Rails.application.configure do
|
||||
config.web_console.permissions = %w[192.168.0.0/16 192.168.99.0/16 10.0.2.2]
|
||||
|
||||
config.hosts << ENV.fetch('DEFAULT_HOST', 'localhost')
|
||||
config.hosts << "37abab1a904d96b727afdf86f2eb4830.serveo.net"
|
||||
config.action_controller.forgery_protection_origin_check = false
|
||||
|
||||
# https://github.com/flyerhzm/bullet
|
||||
# In development, Bullet will find and report N+1 DB requests
|
||||
|
@ -244,6 +244,15 @@ Devise.setup do |config|
|
||||
active_provider.oidc_config.merge(
|
||||
strategy_class: OmniAuth::Strategies::SsoOpenidConnectProvider
|
||||
)
|
||||
|
||||
when 'SamlProvider'
|
||||
require_relative '../../lib/omni_auth/saml'
|
||||
config.omniauth active_provider.strategy_name.to_sym,
|
||||
sp_entity_id: active_provider.providable.sp_entity_id,
|
||||
idp_sso_service_url: active_provider.providable.idp_sso_service_url,
|
||||
idp_cert: active_provider.providable.idp_cert,
|
||||
idp_cert_fingerprint: active_provider.providable.idp_cert_fingerprint,
|
||||
strategy_class: OmniAuth::Strategies::SsoSamlProvider
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1230,6 +1230,7 @@ en:
|
||||
local_database: "Local database"
|
||||
o_auth2: "OAuth 2.0"
|
||||
openid_connect: "OpenID Connect"
|
||||
saml: "SAML"
|
||||
group_form:
|
||||
add_a_group: "Add a group"
|
||||
group_name: "Group name"
|
||||
@ -1496,6 +1497,10 @@ en:
|
||||
api_field: "Userinfo claim"
|
||||
api_field_help_html: 'Set the field providing the corresponding data through <a href="https://openid.net/specs/openid-connect-core-1_0.html#Claims" target="_blank">the userinfo endpoint</a>.<br> <a href="https://jsonpath.com/" target="_blank">JsonPath</a> syntax is supported. If many fields are selected, the first one will be used.<br> <b>Example</b>: $.data[*].name'
|
||||
openid_standard_configuration: "Use the OpenID standard configuration"
|
||||
saml_data_mapping_form:
|
||||
api_field: "Userinfo field"
|
||||
api_field_help_html: "Set the field providing the corresponding data through the SAML assertion.<br> If many fields are selected, the first one will be used.<br> <b>Example</b>: $.data[*].name"
|
||||
openid_standard_configuration: "Use the SAML standard configuration"
|
||||
type_mapping_modal:
|
||||
data_mapping: "Data mapping"
|
||||
TYPE_expected: "{TYPE} expected"
|
||||
@ -1552,6 +1557,16 @@ en:
|
||||
client__end_session_endpoint_help: "The url to call to log the user out at the authorization server."
|
||||
extra_authorize_params: "Extra authorize parameters"
|
||||
extra_authorize_params_help: "A hash of extra fixed parameters that will be merged to the authorization request"
|
||||
saml_form:
|
||||
authorization_callback_url: "Authorization callback URL"
|
||||
sp_entity_id: "Service provider entity ID"
|
||||
sp_entity_id_help: "The name of your application. Some identity providers might need this to establish the identity of the service provider requesting the login."
|
||||
idp_sso_service_url: "Identity provider SSO service URL"
|
||||
idp_sso_service_url_help: "The URL to which the authentication request should be sent. This would be on the identity provider."
|
||||
idp_cert_fingerprint: "Identity provider certificate fingerprint"
|
||||
idp_cert: "Identity provider certificate"
|
||||
profile_edition_url: "Profil edition URL"
|
||||
profile_edition_url_help: "The URL of the page where the user can edit his profile."
|
||||
provider_form:
|
||||
name: "Name"
|
||||
authentication_type: "Authentication type"
|
||||
@ -1562,6 +1577,7 @@ en:
|
||||
local_database: "Local database"
|
||||
oauth2: "OAuth 2.0"
|
||||
openid_connect: "OpenID Connect"
|
||||
saml: "SAML"
|
||||
#create a new authentication provider (SSO)
|
||||
authentication_new:
|
||||
add_a_new_authentication_provider: "Add a new authentication provider"
|
||||
|
10
db/migrate/20240116163703_create_saml_providers.rb
Normal file
10
db/migrate/20240116163703_create_saml_providers.rb
Normal file
@ -0,0 +1,10 @@
|
||||
class CreateSamlProviders < ActiveRecord::Migration[7.0]
|
||||
def change
|
||||
create_table :saml_providers do |t|
|
||||
t.string :sp_entity_id
|
||||
t.string :idp_sso_service_url
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,7 @@
|
||||
# frozen_string_literal:true
|
||||
|
||||
class AddProfileUrlToSamlProviders < ActiveRecord::Migration[7.0]
|
||||
def change
|
||||
add_column :saml_providers, :profile_url, :string
|
||||
s end
|
||||
end
|
@ -0,0 +1,6 @@
|
||||
class AddIdpCertToSamlProvider < ActiveRecord::Migration[7.0]
|
||||
def change
|
||||
add_column :saml_providers, :idp_cert, :string
|
||||
add_column :saml_providers, :idp_cert_fingerprint, :string
|
||||
end
|
||||
end
|
140
db/structure.sql
140
db/structure.sql
@ -9,6 +9,13 @@ SET xmloption = content;
|
||||
SET client_min_messages = warning;
|
||||
SET row_security = off;
|
||||
|
||||
--
|
||||
-- Name: public; Type: SCHEMA; Schema: -; Owner: -
|
||||
--
|
||||
|
||||
-- *not* creating schema, since initdb creates it
|
||||
|
||||
|
||||
--
|
||||
-- Name: fuzzystrmatch; Type: EXTENSION; Schema: -; Owner: -
|
||||
--
|
||||
@ -2235,6 +2242,41 @@ CREATE SEQUENCE public.payment_gateway_objects_id_seq
|
||||
ALTER SEQUENCE public.payment_gateway_objects_id_seq OWNED BY public.payment_gateway_objects.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: payment_infos; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.payment_infos (
|
||||
id bigint NOT NULL,
|
||||
data jsonb,
|
||||
state character varying,
|
||||
payment_for character varying,
|
||||
service character varying,
|
||||
statistic_profile_id bigint,
|
||||
created_at timestamp(6) without time zone NOT NULL,
|
||||
updated_at timestamp(6) without time zone NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: payment_infos_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.payment_infos_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: payment_infos_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.payment_infos_id_seq OWNED BY public.payment_infos.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: payment_schedule_items; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
@ -3224,6 +3266,41 @@ CREATE SEQUENCE public.roles_id_seq
|
||||
ALTER SEQUENCE public.roles_id_seq OWNED BY public.roles.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: saml_providers; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.saml_providers (
|
||||
id bigint NOT NULL,
|
||||
sp_entity_id character varying,
|
||||
idp_sso_service_url character varying,
|
||||
created_at timestamp(6) without time zone NOT NULL,
|
||||
updated_at timestamp(6) without time zone NOT NULL,
|
||||
profile_url character varying,
|
||||
idp_cert character varying,
|
||||
idp_cert_fingerprint character varying
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: saml_providers_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.saml_providers_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: saml_providers_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.saml_providers_id_seq OWNED BY public.saml_providers.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: schema_migrations; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
@ -4316,8 +4393,8 @@ CREATE TABLE public.users (
|
||||
is_allow_newsletter boolean,
|
||||
current_sign_in_ip inet,
|
||||
last_sign_in_ip inet,
|
||||
mapped_from_sso character varying,
|
||||
validated_at timestamp without time zone,
|
||||
mapped_from_sso character varying,
|
||||
supporting_documents_reminder_sent_at timestamp(6) without time zone
|
||||
);
|
||||
|
||||
@ -4870,6 +4947,13 @@ ALTER TABLE ONLY public.organizations ALTER COLUMN id SET DEFAULT nextval('publi
|
||||
ALTER TABLE ONLY public.payment_gateway_objects ALTER COLUMN id SET DEFAULT nextval('public.payment_gateway_objects_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: payment_infos id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.payment_infos ALTER COLUMN id SET DEFAULT nextval('public.payment_infos_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: payment_schedule_items id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
@ -5066,6 +5150,13 @@ ALTER TABLE ONLY public.reservations ALTER COLUMN id SET DEFAULT nextval('public
|
||||
ALTER TABLE ONLY public.roles ALTER COLUMN id SET DEFAULT nextval('public.roles_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: saml_providers id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.saml_providers ALTER COLUMN id SET DEFAULT nextval('public.saml_providers_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: settings id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
@ -5799,6 +5890,14 @@ ALTER TABLE ONLY public.payment_gateway_objects
|
||||
ADD CONSTRAINT payment_gateway_objects_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: payment_infos payment_infos_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.payment_infos
|
||||
ADD CONSTRAINT payment_infos_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: payment_schedule_items payment_schedule_items_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
@ -6023,6 +6122,14 @@ ALTER TABLE ONLY public.roles
|
||||
ADD CONSTRAINT roles_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: saml_providers saml_providers_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.saml_providers
|
||||
ADD CONSTRAINT saml_providers_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: schema_migrations schema_migrations_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
@ -7004,6 +7111,13 @@ CREATE INDEX index_payment_gateway_objects_on_item_type_and_item_id ON public.pa
|
||||
CREATE INDEX index_payment_gateway_objects_on_payment_gateway_object_id ON public.payment_gateway_objects USING btree (payment_gateway_object_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_payment_infos_on_statistic_profile_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX index_payment_infos_on_statistic_profile_id ON public.payment_infos USING btree (statistic_profile_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_payment_schedule_items_on_invoice_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
@ -7795,14 +7909,6 @@ CREATE INDEX proof_of_identity_type_id_and_proof_of_identity_refusal_id ON publi
|
||||
CREATE UNIQUE INDEX unique_not_null_external_id ON public.invoicing_profiles USING btree (external_id) WHERE (external_id IS NOT NULL);
|
||||
|
||||
|
||||
--
|
||||
-- Name: accounting_periods accounting_periods_del_protect; Type: RULE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE RULE accounting_periods_del_protect AS
|
||||
ON DELETE TO public.accounting_periods DO INSTEAD NOTHING;
|
||||
|
||||
|
||||
--
|
||||
-- Name: accounting_periods accounting_periods_upd_protect; Type: RULE; Schema: public; Owner: -
|
||||
--
|
||||
@ -7836,6 +7942,14 @@ ALTER TABLE ONLY public.payment_schedules
|
||||
ADD CONSTRAINT fk_rails_00308dc223 FOREIGN KEY (wallet_transaction_id) REFERENCES public.wallet_transactions(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: payment_infos fk_rails_0308366a58; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.payment_infos
|
||||
ADD CONSTRAINT fk_rails_0308366a58 FOREIGN KEY (statistic_profile_id) REFERENCES public.statistic_profiles(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: cart_item_event_reservation_booking_users fk_rails_0964335a37; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
@ -9182,8 +9296,10 @@ INSERT INTO "schema_migrations" (version) VALUES
|
||||
('20230328094808'),
|
||||
('20230328094809'),
|
||||
('20230331132506'),
|
||||
('20230509121907'),
|
||||
('20230509161557'),
|
||||
('20230510141305'),
|
||||
('20230511080650'),
|
||||
('20230511081018'),
|
||||
('20230524080448'),
|
||||
('20230524083558'),
|
||||
@ -9199,11 +9315,15 @@ INSERT INTO "schema_migrations" (version) VALUES
|
||||
('20230720085857'),
|
||||
('20230728072726'),
|
||||
('20230728090257'),
|
||||
('20230825101952'),
|
||||
('20230828073428'),
|
||||
('20230831103208'),
|
||||
('20230901090637'),
|
||||
('20230907124230'),
|
||||
('20231103093436'),
|
||||
('20231108094433');
|
||||
('20231108094433'),
|
||||
('20240116163703'),
|
||||
('20240126145351'),
|
||||
('20240126192110');
|
||||
|
||||
|
||||
|
3
lib/omni_auth/saml.rb
Normal file
3
lib/omni_auth/saml.rb
Normal file
@ -0,0 +1,3 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'strategies/sso_saml_provider'
|
34
lib/omni_auth/strategies/sso_saml_provider.rb
Normal file
34
lib/omni_auth/strategies/sso_saml_provider.rb
Normal file
@ -0,0 +1,34 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'omniauth-saml'
|
||||
require_relative '../data_mapping/mapper'
|
||||
|
||||
# Authentication strategy provided trough SAML
|
||||
class OmniAuth::Strategies::SsoSamlProvider < OmniAuth::Strategies::SAML
|
||||
include OmniAuth::DataMapping::Mapper
|
||||
|
||||
def self.active_provider
|
||||
active_provider = Rails.configuration.auth_provider
|
||||
if active_provider.providable_type != 'SamlProvider'
|
||||
raise "Trying to instantiate the wrong provider: Expected SamlProvider, received #{active_provider.providable_type}"
|
||||
end
|
||||
|
||||
active_provider
|
||||
end
|
||||
|
||||
# Strategy name.
|
||||
option :name, active_provider.strategy_name
|
||||
|
||||
info do
|
||||
{
|
||||
mapping: parsed_info
|
||||
}
|
||||
end
|
||||
|
||||
def parsed_info
|
||||
mapped_info(
|
||||
OmniAuth::Strategies::SsoSamlProvider.active_provider.auth_provider_mappings,
|
||||
user_info: @attributes.attributes.transform_values {|v| v.is_a?(Array) ? v.first : v }
|
||||
)
|
||||
end
|
||||
end
|
@ -5,21 +5,6 @@ namespace :fablab do
|
||||
namespace :auth do
|
||||
desc 'switch the active authentication provider'
|
||||
task :switch_provider, [:provider] => :environment do |_task, args|
|
||||
providers = AuthProvider.all.inject('') { |str, item| "#{str}#{item[:name]}, " }
|
||||
unless args.provider
|
||||
puts "\e[0;31mERROR\e[0m: You must pass a provider name to activate. Available providers are: #{providers[0..-3]}"
|
||||
next
|
||||
end
|
||||
|
||||
if AuthProvider.find_by(name: args.provider).nil?
|
||||
puts "\e[0;31mERROR\e[0m: the provider '#{args.provider}' does not exists. Available providers are: #{providers[0..-3]}"
|
||||
next
|
||||
end
|
||||
|
||||
if AuthProvider.active.name == args.provider
|
||||
puts "\e[0;31mERROR\e[0m: the provider '#{args.provider}' is already enabled"
|
||||
next
|
||||
end
|
||||
|
||||
# disable previous provider
|
||||
prev_prev = AuthProvider.previous
|
||||
@ -28,7 +13,7 @@ namespace :fablab do
|
||||
AuthProvider.active.update(status: 'previous') unless AuthProvider.active.name == 'DatabaseProvider::SimpleAuthProvider'
|
||||
|
||||
# enable given provider
|
||||
AuthProvider.find_by(name: args.provider).update(status: 'active')
|
||||
AuthProvider.find_by(name: 'FabManager').update(status: 'active')
|
||||
|
||||
# migrate the current users.
|
||||
if AuthProvider.active.providable_type == DatabaseProvider.name
|
||||
|
Loading…
x
Reference in New Issue
Block a user