mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-01-19 08:52:25 +01:00
(ui) automatically test for discovery endpoint
This commit is contained in:
parent
9ef2e251b0
commit
79bb235eaa
9
app/frontend/src/javascript/api/clients/sso-client.ts
Normal file
9
app/frontend/src/javascript/api/clients/sso-client.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
|
||||
function client (host: string): AxiosInstance {
|
||||
return axios.create({
|
||||
baseURL: host
|
||||
});
|
||||
}
|
||||
|
||||
export default client;
|
13
app/frontend/src/javascript/api/external/sso.ts
vendored
Normal file
13
app/frontend/src/javascript/api/external/sso.ts
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
import ssoClient from '../clients/sso-client';
|
||||
import { AxiosResponse } from 'axios';
|
||||
import { OpenIdConfiguration } from '../../models/sso';
|
||||
|
||||
export default class SsoClient {
|
||||
/**
|
||||
* @see https://openid.net/specs/openid-connect-discovery-1_0.html
|
||||
*/
|
||||
static async openIdConfiguration (host: string): Promise<OpenIdConfiguration> {
|
||||
const res: AxiosResponse<OpenIdConfiguration> = await ssoClient(host).get('.well-known/openid-configuration');
|
||||
return res?.data;
|
||||
}
|
||||
}
|
@ -1,26 +1,75 @@
|
||||
import React from 'react';
|
||||
import { UseFormRegister } from 'react-hook-form';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Path, UseFormRegister } from 'react-hook-form';
|
||||
import { FieldValues } from 'react-hook-form/dist/types/fields';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { FormInput } from '../form/form-input';
|
||||
import { FormSelect } from '../form/form-select';
|
||||
import { Control } from 'react-hook-form/dist/types/form';
|
||||
import { Control, FormState, UnpackNestedValue, UseFormSetValue } from 'react-hook-form/dist/types/form';
|
||||
import { HtmlTranslate } from '../base/html-translate';
|
||||
import { OpenIdConnectProvider } from '../../models/authentication-provider';
|
||||
import SsoClient from '../../api/external/sso';
|
||||
import { FieldPathValue } from 'react-hook-form/dist/types/path';
|
||||
|
||||
interface OpenidConnectFormProps<TFieldValues, TContext extends object> {
|
||||
register: UseFormRegister<TFieldValues>,
|
||||
control: Control<TFieldValues, TContext>,
|
||||
currentFormValues: OpenIdConnectProvider
|
||||
currentFormValues: OpenIdConnectProvider,
|
||||
formState: FormState<TFieldValues>,
|
||||
setValue: UseFormSetValue<TFieldValues>,
|
||||
}
|
||||
|
||||
export const OpenidConnectForm = <TFieldValues extends FieldValues, TContext extends object>({ register, control, currentFormValues }: OpenidConnectFormProps<TFieldValues, TContext>) => {
|
||||
export const OpenidConnectForm = <TFieldValues extends FieldValues, TContext extends object>({ register, control, currentFormValues, formState, setValue }: OpenidConnectFormProps<TFieldValues, TContext>) => {
|
||||
const { t } = useTranslation('admin');
|
||||
|
||||
// saves the state of the discovery endpoint
|
||||
const [discoveryAvailable, setDiscoveryAvailable] = useState<boolean>(false);
|
||||
|
||||
// when we have detected a discovery endpoint, we mark it as available
|
||||
useEffect(() => {
|
||||
setValue(
|
||||
'providable_attributes.discovery' as Path<TFieldValues>,
|
||||
discoveryAvailable as UnpackNestedValue<FieldPathValue<TFieldValues, Path<TFieldValues>>>
|
||||
);
|
||||
}, [discoveryAvailable]);
|
||||
|
||||
// when the component is mounted, we try to discover the discovery endpoint for the current configuration (if any)
|
||||
useEffect(() => {
|
||||
checkForDiscoveryEndpoint({ target: { value: currentFormValues?.issuer } } as React.ChangeEvent<HTMLInputElement>);
|
||||
}, []);
|
||||
|
||||
// regular expression to validate the the input fields
|
||||
const endpointRegex = /^\/?([-._~:?#[\]@!$&'()*+,;=%\w]+\/?)*$/;
|
||||
const urlRegex = /^(https?:\/\/)([\da-z.-]+)\.([-a-z0-9.]{2,30})([/\w .-]*)*\/?$/;
|
||||
|
||||
/**
|
||||
* If the discovery endpoint is available, the user will be able to choose to use it or not.
|
||||
* Otherwise, he will need to end the client configuration manually.
|
||||
*/
|
||||
const buildDiscoveryOptions = () => {
|
||||
if (discoveryAvailable) {
|
||||
return [
|
||||
{ value: true, label: t('app.admin.authentication.openid_connect_form.discovery_enabled') },
|
||||
{ value: false, label: t('app.admin.authentication.openid_connect_form.discovery_disabled') }
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
{ value: false, label: t('app.admin.authentication.openid_connect_form.discovery_disabled') }
|
||||
];
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback that check for the existence of the .well-known/openid-configuration endpoint, for the given issuer.
|
||||
* This callback is triggered when the user changes the issuer field.
|
||||
*/
|
||||
const checkForDiscoveryEndpoint = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
SsoClient.openIdConfiguration(e.target.value).then(() => {
|
||||
setDiscoveryAvailable(true);
|
||||
}).catch(() => {
|
||||
setDiscoveryAvailable(false);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="openid-connect-form">
|
||||
<hr/>
|
||||
@ -29,15 +78,16 @@ export const OpenidConnectForm = <TFieldValues extends FieldValues, TContext ext
|
||||
label={t('app.admin.authentication.openid_connect_form.issuer')}
|
||||
placeholder="https://sso.exemple.com"
|
||||
tooltip={t('app.admin.authentication.openid_connect_form.issuer_help')}
|
||||
rules={{ required: true, pattern: urlRegex }} />
|
||||
rules={{ required: true, pattern: urlRegex }}
|
||||
onChange={checkForDiscoveryEndpoint}
|
||||
debounce={400}
|
||||
warning={!discoveryAvailable && { 'providable_attributes.issuer': { message: t('app.admin.authentication.openid_connect_form.discovery_unavailable') } }}
|
||||
formState={formState} />
|
||||
<FormSelect id="providable_attributes.discovery"
|
||||
label={t('app.admin.authentication.openid_connect_form.discovery')}
|
||||
tooltip={t('app.admin.authentication.openid_connect_form.discovery_help')}
|
||||
options={[
|
||||
{ value: true, label: t('app.admin.authentication.openid_connect_form.discovery_enabled') },
|
||||
{ value: false, label: t('app.admin.authentication.openid_connect_form.discovery_disabled') }
|
||||
]}
|
||||
valueDefault={true}
|
||||
options={buildDiscoveryOptions()}
|
||||
valueDefault={discoveryAvailable}
|
||||
control={control} />
|
||||
<FormSelect id="providable_attributes.client_auth_method"
|
||||
label={t('app.admin.authentication.openid_connect_form.client_auth_method')}
|
||||
@ -73,17 +123,6 @@ export const OpenidConnectForm = <TFieldValues extends FieldValues, TContext ext
|
||||
]}
|
||||
clearable
|
||||
control={control} />
|
||||
<FormSelect id="providable_attributes.display"
|
||||
label={t('app.admin.authentication.openid_connect_form.display')}
|
||||
tooltip={<HtmlTranslate trKey="app.admin.authentication.openid_connect_form.display_help_html" />}
|
||||
options={[
|
||||
{ value: 'page', label: t('app.admin.authentication.openid_connect_form.display_page') },
|
||||
{ value: 'popup', label: t('app.admin.authentication.openid_connect_form.display_popup') },
|
||||
{ value: 'touch', label: t('app.admin.authentication.openid_connect_form.display_touch') },
|
||||
{ value: 'wap', label: t('app.admin.authentication.openid_connect_form.display_wap') }
|
||||
]}
|
||||
clearable
|
||||
control={control} />
|
||||
<FormSelect id="providable_attributes.prompt"
|
||||
label={t('app.admin.authentication.openid_connect_form.prompt')}
|
||||
tooltip={<HtmlTranslate trKey="app.admin.authentication.openid_connect_form.prompt_help_html" />}
|
||||
|
@ -37,7 +37,7 @@ type selectProvidableTypeOption = { value: string, label: string };
|
||||
* Form to create or update an authentication provider.
|
||||
*/
|
||||
export const ProviderForm: React.FC<ProviderFormProps> = ({ action, provider, onError, onSuccess }) => {
|
||||
const { handleSubmit, register, control } = useForm<AuthenticationProvider>({ defaultValues: { ...provider } });
|
||||
const { handleSubmit, register, control, formState, setValue } = useForm<AuthenticationProvider>({ defaultValues: { ...provider } });
|
||||
const output = useWatch<AuthenticationProvider>({ control });
|
||||
const [providableType, setProvidableType] = useState<string>(provider?.providable_type);
|
||||
const [strategyName, setStrategyName] = useState<string>(provider?.strategy_name);
|
||||
@ -103,7 +103,11 @@ export const ProviderForm: React.FC<ProviderFormProps> = ({ action, provider, on
|
||||
rules={{ required: true }} />
|
||||
{providableType === 'DatabaseProvider' && <DatabaseForm register={register} />}
|
||||
{providableType === 'OAuth2Provider' && <Oauth2Form register={register} strategyName={strategyName} />}
|
||||
{providableType === 'OpenIdConnectProvider' && <OpenidConnectForm register={register} control={control} currentFormValues={output.providable_attributes as OpenIdConnectProvider} />}
|
||||
{providableType === 'OpenIdConnectProvider' && <OpenidConnectForm register={register}
|
||||
control={control}
|
||||
currentFormValues={output.providable_attributes as OpenIdConnectProvider}
|
||||
formState={formState}
|
||||
setValue={setValue} />}
|
||||
{providableType && providableType !== 'DatabaseProvider' && <DataMappingForm register={register} control={control} />}
|
||||
<div className="main-actions">
|
||||
<FabButton type="submit" className="submit-button">{t('app.admin.authentication.provider_form.save')}</FabButton>
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, { InputHTMLAttributes, ReactNode } from 'react';
|
||||
import React, { InputHTMLAttributes, ReactNode, useCallback, useEffect, useState } from 'react';
|
||||
import { FieldPathValue } from 'react-hook-form';
|
||||
import { debounce as _debounce, get as _get } from 'lodash';
|
||||
import { FieldValues } from 'react-hook-form/dist/types/fields';
|
||||
import { FieldPath } from 'react-hook-form/dist/types/path';
|
||||
import { FormComponent } from '../../models/form-component';
|
||||
@ -11,20 +12,48 @@ interface FormInputProps<TFieldValues> extends InputHTMLAttributes<HTMLInputElem
|
||||
icon?: ReactNode,
|
||||
addOn?: ReactNode,
|
||||
addOnClassName?: string,
|
||||
debounce?: number,
|
||||
}
|
||||
|
||||
/**
|
||||
* This component is a template for an input component to use within React Hook Form
|
||||
*/
|
||||
export const FormInput = <TFieldValues extends FieldValues>({ id, register, label, tooltip, defaultValue, icon, className, rules, readOnly, disabled, type, addOn, addOnClassName, placeholder, error, step }: FormInputProps<TFieldValues>) => {
|
||||
export const FormInput = <TFieldValues extends FieldValues>({ id, register, label, tooltip, defaultValue, icon, className, rules, readOnly, disabled, type, addOn, addOnClassName, placeholder, error, warning, formState, step, onChange, debounce }: FormInputProps<TFieldValues>) => {
|
||||
const [isDirty, setIsDirty] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setIsDirty(_get(formState?.dirtyFields, id));
|
||||
}, [formState]);
|
||||
|
||||
/**
|
||||
* Debounced (ie. temporised) version of the 'on change' callback.
|
||||
*/
|
||||
const debouncedOnChange = debounce ? useCallback(_debounce(onChange, debounce), [debounce]) : null;
|
||||
|
||||
/**
|
||||
* Handle the change of content in the input field, and trigger the parent callback, if any
|
||||
*/
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (typeof onChange === 'function') {
|
||||
if (debouncedOnChange) {
|
||||
debouncedOnChange(e);
|
||||
} else {
|
||||
onChange(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Compose classnames from props
|
||||
const classNames = `
|
||||
form-input form-item ${className || ''}
|
||||
${type === 'hidden' ? 'is-hidden' : ''}
|
||||
${error && error[id] ? 'is-incorrect' : ''}
|
||||
${rules && rules.required ? 'is-required' : ''}
|
||||
${readOnly ? 'is-readOnly' : ''}
|
||||
${disabled ? 'is-disabled' : ''}`;
|
||||
const classNames = [
|
||||
'form-input form-item',
|
||||
`${className || ''}`,
|
||||
`${type === 'hidden' ? 'is-hidden' : ''}`,
|
||||
`${isDirty && error && error[id] ? 'is-incorrect' : ''}`,
|
||||
`${isDirty && warning && warning[id] ? 'is-warned' : ''}`,
|
||||
`${rules && rules.required ? 'is-required' : ''}`,
|
||||
`${readOnly ? 'is-readonly' : ''}`,
|
||||
`${disabled ? 'is-disabled' : ''}`
|
||||
].join(' ');
|
||||
|
||||
return (
|
||||
<label className={classNames}>
|
||||
@ -41,7 +70,8 @@ export const FormInput = <TFieldValues extends FieldValues>({ id, register, labe
|
||||
{...register(id as FieldPath<TFieldValues>, {
|
||||
...rules,
|
||||
valueAsNumber: type === 'number',
|
||||
value: defaultValue as FieldPathValue<TFieldValues, FieldPath<TFieldValues>>
|
||||
value: defaultValue as FieldPathValue<TFieldValues, FieldPath<TFieldValues>>,
|
||||
onChange: (e) => { handleChange(e); }
|
||||
})}
|
||||
type={type}
|
||||
step={step}
|
||||
@ -50,7 +80,8 @@ export const FormInput = <TFieldValues extends FieldValues>({ id, register, labe
|
||||
placeholder={placeholder} />
|
||||
{addOn && <span className={`addon ${addOnClassName || ''}`}>{addOn}</span>}
|
||||
</div>
|
||||
{(error && error[id]) && <div className="form-item-error">{error[id].message}</div> }
|
||||
{(isDirty && error && error[id]) && <div className="form-item-error">{error[id].message}</div> }
|
||||
{(isDirty && warning && warning[id]) && <div className="form-item-warning">{warning[id].message}</div> }
|
||||
</label>
|
||||
);
|
||||
};
|
||||
|
@ -29,11 +29,13 @@ type selectOption<TOptionValue> = { value: TOptionValue, label: string };
|
||||
* It is a multi-select component.
|
||||
*/
|
||||
export const FormMultiSelect = <TFieldValues extends FieldValues, TContext extends object, TOptionValue>({ id, label, tooltip, className, control, placeholder, options, valuesDefault, error, rules, disabled, onChange }: FormSelectProps<TFieldValues, TContext, TOptionValue>) => {
|
||||
const classNames = `
|
||||
form-multi-select form-item ${className || ''}
|
||||
${error && error[id] ? 'is-incorrect' : ''}
|
||||
${rules && rules.required ? 'is-required' : ''}
|
||||
${disabled ? 'is-disabled' : ''}`;
|
||||
const classNames = [
|
||||
'form-multi-select form-item',
|
||||
`${className || ''}`,
|
||||
`${error && error[id] ? 'is-incorrect' : ''}`,
|
||||
`${rules && rules.required ? 'is-required' : ''}`,
|
||||
`${disabled ? 'is-disabled' : ''}`
|
||||
].join(' ');
|
||||
|
||||
/**
|
||||
* The following callback will trigger the onChange callback, if it was passed to this component,
|
||||
@ -73,6 +75,7 @@ export const FormMultiSelect = <TFieldValues extends FieldValues, TContext exten
|
||||
isMulti />
|
||||
} />
|
||||
</div>
|
||||
{(error && error[id]) && <div className="form-item-error">{error[id].message}</div> }
|
||||
</label>
|
||||
);
|
||||
};
|
||||
|
@ -30,11 +30,13 @@ type selectOption<TOptionValue> = { value: TOptionValue, label: string };
|
||||
* This component is a wrapper for react-select to use with react-hook-form
|
||||
*/
|
||||
export const FormSelect = <TFieldValues extends FieldValues, TContext extends object, TOptionValue>({ id, label, tooltip, className, control, placeholder, options, valueDefault, error, rules, disabled, onChange, readOnly, clearable }: FormSelectProps<TFieldValues, TContext, TOptionValue>) => {
|
||||
const classNames = `
|
||||
form-select form-item ${className || ''}
|
||||
${error && error[id] ? 'is-incorrect' : ''}
|
||||
${rules && rules.required ? 'is-required' : ''}
|
||||
${disabled ? 'is-disabled' : ''}`;
|
||||
const classNames = [
|
||||
'form-select form-item',
|
||||
`${className || ''}`,
|
||||
`${error && error[id] ? 'is-incorrect' : ''}`,
|
||||
`${rules && rules.required ? 'is-required' : ''}`,
|
||||
`${disabled ? 'is-disabled' : ''}`
|
||||
].join(' ');
|
||||
|
||||
/**
|
||||
* The following callback will trigger the onChange callback, if it was passed to this component,
|
||||
@ -74,6 +76,7 @@ export const FormSelect = <TFieldValues extends FieldValues, TContext extends ob
|
||||
options={options} />
|
||||
} />
|
||||
</div>
|
||||
{(error && error[id]) && <div className="form-item-error">{error[id].message}</div> }
|
||||
</label>
|
||||
);
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { FieldErrors, UseFormRegister, Validate } from 'react-hook-form';
|
||||
import { Control } from 'react-hook-form/dist/types/form';
|
||||
import { Control, FormState } from 'react-hook-form/dist/types/form';
|
||||
|
||||
export type ruleTypes<TFieldValues> = {
|
||||
required?: boolean | string,
|
||||
@ -14,11 +14,15 @@ export type ruleTypes<TFieldValues> = {
|
||||
export interface FormComponent<TFieldValues> {
|
||||
register: UseFormRegister<TFieldValues>,
|
||||
error?: FieldErrors,
|
||||
warning?: FieldErrors,
|
||||
rules?: ruleTypes<TFieldValues>,
|
||||
formState?: FormState<TFieldValues>;
|
||||
}
|
||||
|
||||
export interface FormControlledComponent<TFieldValues, TContext extends object> {
|
||||
control: Control<TFieldValues, TContext>,
|
||||
error?: FieldErrors,
|
||||
warning?: FieldErrors,
|
||||
rules?: ruleTypes<TFieldValues>,
|
||||
formState?: FormState<TFieldValues>;
|
||||
}
|
||||
|
15
app/frontend/src/javascript/models/sso.ts
Normal file
15
app/frontend/src/javascript/models/sso.ts
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
export interface OpenIdConfiguration {
|
||||
authorization_endpoint: string;
|
||||
token_endpoint: string;
|
||||
userinfo_endpoint: string;
|
||||
jwks_uri: string;
|
||||
registration_endpoint: string;
|
||||
scopes_supported: string[];
|
||||
response_types_supported: string[];
|
||||
response_modes_supported: string[];
|
||||
grant_types_supported: string[];
|
||||
subject_types_supported: string[];
|
||||
id_token_signing_alg_values_supported: string[];
|
||||
code_challenge_methods_supported: string[];
|
||||
}
|
@ -140,6 +140,14 @@
|
||||
background-color: var(--error-lightest);
|
||||
}
|
||||
}
|
||||
&.is-warned &-field {
|
||||
border-color: var(--warning);
|
||||
.icon {
|
||||
color: var(--warning);
|
||||
border-color: var(--warning);
|
||||
background-color: var(--warning-lightest);
|
||||
}
|
||||
}
|
||||
&.is-disabled &-field input,
|
||||
&.is-readOnly &-field input {
|
||||
background-color: var(--gray-soft-light);
|
||||
@ -149,4 +157,8 @@
|
||||
margin-top: 0.4rem;
|
||||
color: var(--error);
|
||||
}
|
||||
&-warning {
|
||||
margin-top: 0.4rem;
|
||||
color: var(--warning);
|
||||
}
|
||||
}
|
||||
|
@ -228,14 +228,16 @@ Devise.setup do |config|
|
||||
# up on your models and hooks.
|
||||
# config.omniauth :github, 'APP_ID', 'APP_SECRET', :scope => 'user,public_repo'
|
||||
|
||||
require_relative '../../lib/omni_auth/omni_auth'
|
||||
active_provider = AuthProvider.active
|
||||
if active_provider.providable_type == OAuth2Provider.name
|
||||
require_relative '../../lib/omni_auth/oauth2'
|
||||
config.omniauth OmniAuth::Strategies::SsoOauth2Provider.name.to_sym,
|
||||
active_provider.providable.client_id,
|
||||
active_provider.providable.client_secret
|
||||
elsif active_provider.providable_type == OpenIdConnectProvider.name
|
||||
config.omniauth :openid_connect, active_provider.config
|
||||
require_relative '../../lib/omni_auth/openid_connect'
|
||||
config.omniauth OmniAuth::Strategies::SsoOpenidConnectProvider.name.to_sym,
|
||||
active_provider.providable.config
|
||||
end
|
||||
|
||||
# ==> Warden configuration
|
||||
|
@ -1101,6 +1101,7 @@ en:
|
||||
issuer_help: "Root url for the authorization server."
|
||||
discovery: "Discovery"
|
||||
discovery_help: "Should OpenID discovery be used. This is recommended if the IDP provides a discovery endpoint."
|
||||
discovery_unavailable: "Discovery is unavailable for the configured issuer."
|
||||
discovery_enabled: "Enable discovery"
|
||||
discovery_disabled: "Disable discovery"
|
||||
client_auth_method: "Client authentication method"
|
||||
@ -1119,12 +1120,6 @@ en:
|
||||
response_mode_fragment: "Fragment"
|
||||
response_mode_form_post: "Form post"
|
||||
response_mode_web_message: "Web message"
|
||||
display: "Display"
|
||||
display_help_html: "How the authorization server should display the authorization page to the user. <br> <b>Page</b> - the authorization page is displayed in a new browser window. <br> <b>Popup</b> - the authorization page is displayed in a popup window. <br> <b>Touch</b> - the authorization page is displayed consistently with devices that leverages a touch interface. <br> <b>Wap</b> - the authorization page is displayed consistently with a "feature phone" type display."
|
||||
display_page: "Page"
|
||||
display_popup: "Popup"
|
||||
display_touch: "Touch"
|
||||
display_wap: "WAP"
|
||||
prompt: "Prompt"
|
||||
prompt_help_html: "Which OpenID pages the user will be shown. <br> <b>None</b> - no authentication or consent user interface pages are shown. <br> <b>Login</b> - the authorization server prompt the user for reauthentication. <br> <b>Consent</b> - the authorization server prompt the user for consent before returning information to Fab-manager. <br> <b>Select account</b> - the authorization server prompt the user to select a user account."
|
||||
prompt_none: "None"
|
||||
|
3
lib/omni_auth/oauth2.rb
Normal file
3
lib/omni_auth/oauth2.rb
Normal file
@ -0,0 +1,3 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'strategies/sso_oauth2_provider'
|
@ -1,7 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
active_provider = AuthProvider.active
|
||||
|
||||
if active_provider.providable_type != DatabaseProvider.name
|
||||
require_relative "strategies/sso_#{active_provider.provider_type}_provider"
|
||||
end
|
3
lib/omni_auth/openid_connect.rb
Normal file
3
lib/omni_auth/openid_connect.rb
Normal file
@ -0,0 +1,3 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'strategies/sso_openid_connect_provider'
|
22
lib/omni_auth/strategies/sso_openid_connect_provider.rb
Normal file
22
lib/omni_auth/strategies/sso_openid_connect_provider.rb
Normal file
@ -0,0 +1,22 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'omniauth_openid_connect'
|
||||
|
||||
module OmniAuth::Strategies
|
||||
# Authentication strategy provided trough OpenID Connect
|
||||
class SsoOpenidConnectProvider < OmniAuth::Strategies::OpenIDConnect
|
||||
|
||||
def self.active_provider
|
||||
active_provider = AuthProvider.active
|
||||
if active_provider.providable_type != OpenIdConnectProvider.name
|
||||
raise "Trying to instantiate the wrong provider: Expected OpenIdConnectProvider, received #{active_provider.providable_type}"
|
||||
end
|
||||
|
||||
active_provider
|
||||
end
|
||||
|
||||
# Strategy name.
|
||||
option :name, active_provider.strategy_name
|
||||
|
||||
end
|
||||
end
|
Loading…
x
Reference in New Issue
Block a user