mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2024-12-02 13:24:20 +01:00
(api) validate auth providers data
+ remove legacy code
This commit is contained in:
parent
04ae91a7d1
commit
70803ee41b
@ -10,6 +10,7 @@ import { FormSelect } from '../form/form-select';
|
|||||||
import { Oauth2Form } from './oauth2-form';
|
import { Oauth2Form } from './oauth2-form';
|
||||||
import { DataMappingForm } from './data-mapping-form';
|
import { DataMappingForm } from './data-mapping-form';
|
||||||
import { FabButton } from '../base/fab-button';
|
import { FabButton } from '../base/fab-button';
|
||||||
|
import AuthProviderAPI from '../../api/auth-provider';
|
||||||
|
|
||||||
declare const Application: IApplication;
|
declare const Application: IApplication;
|
||||||
|
|
||||||
@ -41,11 +42,11 @@ export const ProviderForm: React.FC<ProviderFormProps> = ({ action, provider, on
|
|||||||
* Callback triggered when the form is submitted: process with the provider creation or update.
|
* Callback triggered when the form is submitted: process with the provider creation or update.
|
||||||
*/
|
*/
|
||||||
const onSubmit: SubmitHandler<AuthenticationProvider> = (data: AuthenticationProvider) => {
|
const onSubmit: SubmitHandler<AuthenticationProvider> = (data: AuthenticationProvider) => {
|
||||||
if (data) {
|
AuthProviderAPI[action](data).then(() => {
|
||||||
onSuccess('Provider created successfully');
|
onSuccess(t(`app.shared.authentication.${action}_success`));
|
||||||
} else {
|
}).catch(error => {
|
||||||
onError('Failed to created provider');
|
onError(error);
|
||||||
}
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -46,114 +46,6 @@ const check_oauth2_id_is_mapped = function (mappings) {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides a set of common callback methods and data to the $scope parameter. These methods are used
|
|
||||||
* in the various authentication providers' controllers.
|
|
||||||
*
|
|
||||||
* Provides :
|
|
||||||
* - $scope.authMethods
|
|
||||||
* - $scope.mappingFields
|
|
||||||
* - $scope.cancel()
|
|
||||||
* - $scope.methodName()
|
|
||||||
* - $scope.defineDataMapping(mapping)
|
|
||||||
*
|
|
||||||
* Requires :
|
|
||||||
* - mappingFieldsPromise: retrieved by AuthProvider.mapping_fields()
|
|
||||||
* - $state (Ui-Router) [ 'app.admin.members' ]
|
|
||||||
* - _t : translation method
|
|
||||||
*/
|
|
||||||
class AuthenticationController {
|
|
||||||
constructor ($scope, $state, $uibModal, _t, mappingFieldsPromise) {
|
|
||||||
// list of supported authentication methods
|
|
||||||
$scope.authMethods = METHODS;
|
|
||||||
|
|
||||||
// list of fields that can be mapped through the SSO
|
|
||||||
$scope.mappingFields = mappingFieldsPromise;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the admin's view to the members list page
|
|
||||||
*/
|
|
||||||
$scope.cancel = function () { $state.go('app.admin.members'); };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a localized string for the provided method
|
|
||||||
*/
|
|
||||||
$scope.methodName = function (method) {
|
|
||||||
return _t('app.shared.authentication.' + METHODS[method]);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open a modal allowing to specify the data mapping for the given field
|
|
||||||
*/
|
|
||||||
$scope.defineDataMapping = function (mapping) {
|
|
||||||
$uibModal.open({
|
|
||||||
templateUrl: '/admin/authentications/_data_mapping.html',
|
|
||||||
size: 'md',
|
|
||||||
resolve: {
|
|
||||||
field () { return mapping; },
|
|
||||||
datatype () {
|
|
||||||
for (const field of Array.from($scope.mappingFields[mapping.local_model])) {
|
|
||||||
if (field[0] === mapping.local_field) {
|
|
||||||
return field[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
controller: ['$scope', '$uibModalInstance', 'field', 'datatype', function ($scope, $uibModalInstance, field, datatype) {
|
|
||||||
// parent field
|
|
||||||
$scope.field = field;
|
|
||||||
// expected data type
|
|
||||||
$scope.datatype = datatype;
|
|
||||||
// data transformation rules
|
|
||||||
$scope.transformation =
|
|
||||||
{ rules: field.transformation || { type: datatype } };
|
|
||||||
// available transformation formats
|
|
||||||
$scope.formats = {
|
|
||||||
date: [
|
|
||||||
{
|
|
||||||
label: 'ISO 8601',
|
|
||||||
value: 'iso8601'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'RFC 2822',
|
|
||||||
value: 'rfc2822'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'RFC 3339',
|
|
||||||
value: 'rfc3339'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Timestamp (s)',
|
|
||||||
value: 'timestamp-s'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Timestamp (ms)',
|
|
||||||
value: 'timestamp-ms'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create a new mapping between anything and an expected integer
|
|
||||||
$scope.addIntegerMapping = function () {
|
|
||||||
if (!angular.isArray($scope.transformation.rules.mapping)) {
|
|
||||||
$scope.transformation.rules.mapping = [];
|
|
||||||
}
|
|
||||||
return $scope.transformation.rules.mapping.push({ from: '', to: 0 });
|
|
||||||
};
|
|
||||||
|
|
||||||
// close and save the modifications
|
|
||||||
$scope.ok = function () { $uibModalInstance.close($scope.transformation.rules); };
|
|
||||||
|
|
||||||
// do not save the modifications
|
|
||||||
$scope.cancel = function () { $uibModalInstance.dismiss(); };
|
|
||||||
}]
|
|
||||||
})
|
|
||||||
.result.finally(null).then(function (transfo_rules) { mapping.transformation = transfo_rules; });
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page listing all authentication providers
|
* Page listing all authentication providers
|
||||||
*/
|
*/
|
||||||
@ -323,9 +215,6 @@ Application.Controllers.controller('NewAuthenticationController', ['$scope', '$s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Using the AuthenticationController
|
|
||||||
return new AuthenticationController($scope, $state, $uibModal, _t, mappingFieldsPromise);
|
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -359,7 +248,18 @@ Application.Controllers.controller('EditAuthenticationController', ['$scope', '$
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Using the AuthenticationController
|
/**
|
||||||
return new AuthenticationController($scope, $state, $uibModal, _t, mappingFieldsPromise);
|
* Shows a success message forwarded from a child react component
|
||||||
|
*/
|
||||||
|
$scope.onSuccess = function (message) {
|
||||||
|
growl.success(message);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback triggered by react components
|
||||||
|
*/
|
||||||
|
$scope.onError = function (message) {
|
||||||
|
growl.error(message);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
@ -3,7 +3,7 @@ import { Control } from 'react-hook-form/dist/types/form';
|
|||||||
|
|
||||||
export type ruleTypes<TFieldValues> = {
|
export type ruleTypes<TFieldValues> = {
|
||||||
required?: boolean | string,
|
required?: boolean | string,
|
||||||
pattern?: RegExp | {value: RegExp, message: string},
|
pattern?: RegExp | { value: RegExp, message: string },
|
||||||
minLength?: number,
|
minLength?: number,
|
||||||
maxLength?: number,
|
maxLength?: number,
|
||||||
min?: number,
|
min?: number,
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
<div class="modal-header">
|
|
||||||
<h3 class="modal-title"><span translate>{{ 'app.shared.authentication.data_mapping' }}</span> : {{field.local_field}}</h3>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body m-lg">
|
|
||||||
<div>
|
|
||||||
<span translate>{{ 'app.shared.authentication.expected_data_type' }}</span> : {{datatype}}
|
|
||||||
</div>
|
|
||||||
<form name="mappingForm" class="m-t-md">
|
|
||||||
<ng-switch on="datatype">
|
|
||||||
|
|
||||||
<!-- BOOLEAN -->
|
|
||||||
<div ng-switch-when="boolean">
|
|
||||||
<label for="add_mapping" translate>{{ 'app.shared.authentication.mappings' }}</label>
|
|
||||||
<ul class="list-unstyled">
|
|
||||||
<li class="m-t-sm m-l">
|
|
||||||
<input type="text"
|
|
||||||
name="true_value"
|
|
||||||
id="true_value"
|
|
||||||
class="form-control inline width-35 m-r "
|
|
||||||
ng-model="transformation.rules.false_value">
|
|
||||||
<i class="fa fa-arrows-h"></i>
|
|
||||||
<label for="true_value" class="m-l">true</label>
|
|
||||||
</li>
|
|
||||||
<li class="m-t-sm m-l">
|
|
||||||
<input type="text"
|
|
||||||
name="false_value"
|
|
||||||
id="false_value"
|
|
||||||
class="form-control inline width-35 m-r "
|
|
||||||
ng-model="transformation.rules.true_value">
|
|
||||||
<i class="fa fa-arrows-h"></i>
|
|
||||||
<label for="false_value" class="m-l">false</label>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- DATE -->
|
|
||||||
<div ng-switch-when="date">
|
|
||||||
<label for="date_format" translate>{{ 'app.shared.authentication.input_format' }}</label>
|
|
||||||
<select name="date_format"
|
|
||||||
id="date_format"
|
|
||||||
class="form-control"
|
|
||||||
ng-model="transformation.rules.format"
|
|
||||||
ng-options="format.value as format.label for format in formats.date">
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- INTEGER -->
|
|
||||||
<div ng-switch-when="integer">
|
|
||||||
<label for="add_mapping" translate>{{ 'app.shared.authentication.mappings' }}</label>
|
|
||||||
<button class="btn btn-default pull-right" ng-click="addIntegerMapping()"><i class="fa fa-plus"></i></button>
|
|
||||||
<ul class="list-unstyled">
|
|
||||||
<li ng-repeat="map in transformation.rules.mapping" class="m-t-sm m-l">
|
|
||||||
<input type="text" class="form-control inline width-35 m-r " ng-model="map.from">
|
|
||||||
<i class="fa fa-arrows-h"></i>
|
|
||||||
<input type="number" class="form-control inline width-35 m-l" ng-model="map.to">
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</ng-switch>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button class="btn btn-primary" ng-click="ok()" ng-disabled="!mappingForm.$valid" ng-if="datatype != 'string' && datatype != 'text'" translate>{{ 'app.shared.buttons.confirm' }}</button>
|
|
||||||
<button class="btn btn-warning" ng-click="cancel()" translate>{{ 'app.shared.buttons.cancel' }}</button>
|
|
||||||
</div>
|
|
@ -1,30 +0,0 @@
|
|||||||
<div class="form-group" ng-class="{'has-error': providerForm['auth_provider[name]'].$dirty && providerForm['auth_provider[name]'].$invalid}">
|
|
||||||
<label for="provider_name" class="col-sm-3 control-label" translate>{{ 'app.shared.authentication.name' }}</label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<input type="text"
|
|
||||||
ng-model="provider.name"
|
|
||||||
class="form-control"
|
|
||||||
name="auth_provider[name]"
|
|
||||||
id="provider_name"
|
|
||||||
ng-disabled="mode == 'edition'"
|
|
||||||
required />
|
|
||||||
<span class="help-block" ng-show="providerForm['auth_provider[name]'].$dirty && providerForm['auth_provider[name]'].$error.required" translate>{{ 'app.shared.authentication.provider_name_is_required' }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group" ng-class="{'has-error': providerForm['auth_provider[providable_type]'].$dirty && providerForm['auth_provider[providable_type]'].$invalid}">
|
|
||||||
<label for="provider_type" class="col-sm-3 control-label" translate>{{ 'app.shared.authentication.authentication_type' }}</label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<select ng-model="provider.providable_type"
|
|
||||||
ng-change="updateProvidable()"
|
|
||||||
class="form-control"
|
|
||||||
name="auth_provider[providable_type]"
|
|
||||||
id="provider_type"
|
|
||||||
ng-options="key as methodName(key) for (key, value) in authMethods"
|
|
||||||
ng-disabled="mode == 'edition'"
|
|
||||||
required>
|
|
||||||
</select>
|
|
||||||
<input type="hidden" name="auth_provider[type]" ng-value="provider.type" />
|
|
||||||
<span class="help-block" ng-show="providerForm['auth_provider[providable_type]'].$dirty && providerForm['auth_provider[providable_type]'].$error.required" translate>{{ 'app.shared.authentication.authentication_type_is_required' }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -1,104 +0,0 @@
|
|||||||
<hr/>
|
|
||||||
|
|
||||||
<div class="form-group" ng-class="{'has-error': providerForm['auth_provider[base_url]'].$dirty && providerForm['auth_provider[base_url]'].$invalid}">
|
|
||||||
<label for="provider_base_url" class="col-sm-3 control-label" translate>{{ 'app.shared.oauth2.common_url' }}</label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<input type="text"
|
|
||||||
ng-model="provider.providable_attributes.base_url"
|
|
||||||
class="form-control"
|
|
||||||
name="auth_provider[base_url]"
|
|
||||||
id="provider_base_url"
|
|
||||||
placeholder="https://sso.example.net..."
|
|
||||||
required
|
|
||||||
url>
|
|
||||||
<span class="help-block" ng-show="providerForm['auth_provider[base_url]'].$dirty && providerForm['auth_provider[base_url]'].$error.required" translate>{{ 'app.shared.oauth2.common_url_is_required' }}</span>
|
|
||||||
<span class="help-block" ng-show="providerForm['auth_provider[base_url]'].$error.url" translate>{{ 'app.shared.oauth2.provided_url_is_not_a_valid_url' }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group" ng-class="{'has-error': providerForm['auth_provider[authorization_endpoint]'].$dirty && providerForm['auth_provider[authorization_endpoint]'].$invalid}">
|
|
||||||
<label for="provider_authorization_endpoint" class="col-sm-3 control-label" translate>{{ 'app.shared.oauth2.authorization_endpoint' }}</label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<input type="text"
|
|
||||||
ng-model="provider.providable_attributes.authorization_endpoint"
|
|
||||||
class="form-control"
|
|
||||||
name="auth_provider[authorization_endpoint]"
|
|
||||||
id="provider_authorization_endpoint"
|
|
||||||
placeholder="/oauth2/auth..."
|
|
||||||
required
|
|
||||||
endpoint>
|
|
||||||
<span class="help-block" ng-show="providerForm['auth_provider[authorization_endpoint]'].$dirty && providerForm['auth_provider[authorization_url]'].$error.required" translate>{{ 'app.shared.oauth2.oauth2_authorization_endpoint_is_required' }}</span>
|
|
||||||
<span class="help-block" ng-show="providerForm['auth_provider[authorization_endpoint]'].$error.endpoint" translate>{{ 'app.shared.oauth2.provided_endpoint_is_not_valid' }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group" ng-class="{'has-error': providerForm['auth_provider[token_endpoint]'].$dirty && providerForm['auth_provider[token_endpoint]'].$invalid}">
|
|
||||||
<label for="provider_token_endpoint" class="col-sm-3 control-label" translate>{{ 'app.shared.oauth2.token_acquisition_endpoint' }}</label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<input type="text"
|
|
||||||
ng-model="provider.providable_attributes.token_endpoint"
|
|
||||||
class="form-control"
|
|
||||||
name="auth_provider[token_endpoint]"
|
|
||||||
id="provider_token_endpoint"
|
|
||||||
placeholder="/oauth2/token..."
|
|
||||||
required
|
|
||||||
endpoint>
|
|
||||||
<span class="help-block" ng-show="providerForm['auth_provider[token_endpoint]'].$dirty && providerForm['auth_provider[token_endpoint]'].$error.required" translate>{{ 'app.shared.oauth2.oauth2_token_acquisition_endpoint_is_required' }}</span>
|
|
||||||
<span class="help-block" ng-show="providerForm['auth_provider[token_endpoint]'].$error.endpoint" translate>{{ 'app.shared.oauth2.provided_endpoint_is_not_valid' }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group" ng-class="{'has-error': providerForm['auth_provider[profile_url]'].$dirty && providerForm['auth_provider[profile_url]'].$invalid}">
|
|
||||||
<label for="provider_profile_url" class="col-sm-3 control-label" translate>{{ 'app.shared.oauth2.profil_edition_url' }}</label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<input type="text"
|
|
||||||
ng-model="provider.providable_attributes.profile_url"
|
|
||||||
class="form-control"
|
|
||||||
name="auth_provider[profile_url]"
|
|
||||||
id="provider_profile_url"
|
|
||||||
placeholder="https://exemple.net/user..."
|
|
||||||
required
|
|
||||||
url>
|
|
||||||
<span class="help-block" ng-show="providerForm['auth_provider[profile_url]'].$dirty && providerForm['auth_provider[profile_url]'].$error.required" translate>{{ 'app.shared.oauth2.profile_edition_url_is_required' }}</span>
|
|
||||||
<span class="help-block" ng-show="providerForm['auth_provider[profile_url]'].$error.url" translate>{{ 'app.shared.oauth2.provided_url_is_not_a_valid_url' }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group" ng-class="{'has-error': providerForm['auth_provider[client_id]'].$dirty && providerForm['auth_provider[client_id]'].$invalid}">
|
|
||||||
<label for="provider_client_id" class="col-sm-3 control-label" translate>{{ 'app.shared.oauth2.client_identifier' }}</label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<input type="text"
|
|
||||||
ng-model="provider.providable_attributes.client_id"
|
|
||||||
class="form-control"
|
|
||||||
name="auth_provider[client_id]"
|
|
||||||
id="provider_client_id"
|
|
||||||
required>
|
|
||||||
<span class="help-block" ng-show="providerForm['auth_provider[client_id]'].$dirty && providerForm['auth_provider[client_id]'].$error.required" translate>{{ 'app.shared.oauth2.oauth2_client_identifier_is_required' }} {{ 'obtain_it_when_registering_with_your_provider' }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group" ng-class="{'has-error': providerForm['auth_provider[client_secret]'].$dirty && providerForm['auth_provider[client_secret]'].$invalid}">
|
|
||||||
<label for="provider_client_secret" class="col-sm-3 control-label" translate>{{ 'app.shared.oauth2.client_secret' }}</label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<input type="text"
|
|
||||||
ng-model="provider.providable_attributes.client_secret"
|
|
||||||
class="form-control"
|
|
||||||
name="auth_provider[client_secret]"
|
|
||||||
id="provider_client_secret"
|
|
||||||
required>
|
|
||||||
<span class="help-block" ng-show="providerForm['auth_provider[client_secret]'].$dirty && providerForm['auth_provider[client_secret]'].$error.required" translate>{{ 'app.shared.oauth2.oauth2_client_secret_is_required' }} {{ 'obtain_it_when_registering_with_your_provider' }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group" ng-class="{'has-error': providerForm['auth_provider[scopes]'].$dirty && providerForm['auth_provider[scopes]'].$invalid}">
|
|
||||||
<label for="provider_client_secret" class="col-sm-3 control-label" translate>{{ 'app.shared.oauth2.scopes' }}</label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<input type="text"
|
|
||||||
ng-model="provider.providable_attributes.scopes"
|
|
||||||
class="form-control"
|
|
||||||
name="auth_provider[scopes]"
|
|
||||||
id="provider_scopes"
|
|
||||||
placeholder="profile,email...">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<ng-include src="'/admin/authentications/_oauth2_mapping.html'"></ng-include>
|
|
@ -1,80 +0,0 @@
|
|||||||
<h4 class="m-l m-t-xl" translate>{{ 'app.shared.oauth2.define_the_fields_mapping' }}</h4>
|
|
||||||
|
|
||||||
|
|
||||||
<button type="button" class="btn btn-success m-l m-b" ng-click="newMapping = {}"><i class="fa fa-plus"></i> {{ 'app.shared.oauth2.add_a_match' | translate }}</button>
|
|
||||||
<table class="table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th translate>{{ 'app.shared.oauth2.model' }}</th>
|
|
||||||
<th translate>{{ 'app.shared.oauth2.field' }}</th>
|
|
||||||
<th translate>{{ 'app.shared.oauth2.api_endpoint_url' }}</th>
|
|
||||||
<th translate>{{ 'app.shared.oauth2.api_type' }}</th>
|
|
||||||
<th translate>{{ 'app.shared.oauth2.api_fields' }}</th>
|
|
||||||
<th style="width: 6.4em;"></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr ng-repeat="m in provider.providable_attributes.auth_provider_mappings_attributes" ng-if="!m._destroy">
|
|
||||||
<td class="text-c">{{m.local_model}}</td>
|
|
||||||
<td>{{m.local_field}}</td>
|
|
||||||
<td>{{m.api_endpoint}}</td>
|
|
||||||
<td>{{m.api_data_type}}</td>
|
|
||||||
<td>{{m.api_field}}</td>
|
|
||||||
<td>
|
|
||||||
<button class="btn btn-info" ng-click="defineDataMapping(m)">
|
|
||||||
<i class="fa fa-info-circle"></i>
|
|
||||||
</button>
|
|
||||||
<button class="btn btn-danger" ng-click="m._destroy = true">
|
|
||||||
<i class="fa fa-trash-o"></i>
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr ng-show="newMapping" ng-form="mappingForm" isolate-form>
|
|
||||||
<td ng-class="{'has-error': mappingForm['auth_mapping[local_model]'].$dirty && mappingForm['auth_mapping[local_model]'].$invalid}">
|
|
||||||
<select class="form-control text-c"
|
|
||||||
name="auth_mapping[local_model]"
|
|
||||||
ng-options="model as model for (model, fields) in mappingFields"
|
|
||||||
ng-model="newMapping.local_model"
|
|
||||||
required>
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
<td ng-class="{'has-error': mappingForm['auth_mapping[local_field]'].$dirty && mappingForm['auth_mapping[local_field]'].$invalid}">
|
|
||||||
<select class="form-control"
|
|
||||||
name="auth_mapping[local_field]"
|
|
||||||
ng-options="field[0] as field[0] for field in mappingFields[newMapping.local_model]"
|
|
||||||
ng-model="newMapping.local_field"
|
|
||||||
required>
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
<td ng-class="{'has-error': mappingForm['auth_mapping[api_endpoint]'].$dirty && mappingForm['auth_mapping[api_endpoint]'].$invalid}">
|
|
||||||
<input type="text"
|
|
||||||
class="form-control"
|
|
||||||
placeholder="/api/resource..."
|
|
||||||
ng-model="newMapping.api_endpoint"
|
|
||||||
name="auth_mapping[api_endpoint]"
|
|
||||||
required/>
|
|
||||||
</td>
|
|
||||||
<td ng-class="{'has-error': mappingForm['auth_mapping[api_data_type]'].$dirty && mappingForm['auth_mapping[api_data_type]'].$invalid}">
|
|
||||||
<select class="form-control"
|
|
||||||
ng-model="newMapping.api_data_type"
|
|
||||||
name="auth_mapping[api_data_type]"
|
|
||||||
required>
|
|
||||||
<option value="json">JSON</option>
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
<td ng-class="{'has-error': mappingForm['auth_mapping[api_field]'].$dirty && mappingForm['auth_mapping[api_field]'].$invalid}">
|
|
||||||
<input type="text"
|
|
||||||
class="form-control help-cursor"
|
|
||||||
placeholder="field_name"
|
|
||||||
ng-model="newMapping.api_field"
|
|
||||||
name="auth_mapping[api_field]"
|
|
||||||
title="{{ 'app.shared.oauth2.api_field_help' | translate }}"
|
|
||||||
required/>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<button type="button" class="btn btn-success" ng-disabled="mappingForm.$invalid" ng-click="provider.auth_provider_mappings_attributes.push(newMapping); newMapping = null;"><i class="fa fa-check"></i></button>
|
|
||||||
<button type="button" class="btn btn-danger" ng-click="newMapping = null"><i class="fa fa-times"></i></button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
@ -35,14 +35,10 @@
|
|||||||
|
|
||||||
<section class="panel panel-default bg-light m-lg">
|
<section class="panel panel-default bg-light m-lg">
|
||||||
<div class="panel-body m-r">
|
<div class="panel-body m-r">
|
||||||
<ng-include src="'/admin/authentications/_form.html'"></ng-include>
|
|
||||||
<ng-include src="'/admin/authentications/_oauth2.html'" ng-if="provider.providable_type == 'OAuth2Provider'"></ng-include>
|
|
||||||
</div> <!-- ./panel-body -->
|
|
||||||
|
|
||||||
|
<provider-form action="'update'" on-success="onSuccess" on-error="onError" provider="provider"></provider-form>
|
||||||
<div class="panel-footer no-padder">
|
|
||||||
<input type="button" value="{{ 'app.shared.buttons.confirm_changes' | translate }}" class="r-b btn-valid btn btn-warning btn-block p-lg btn-lg text-u-c" ng-disabled="providerForm.$invalid" ng-click="updateProvider()"/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
@ -21,6 +21,9 @@ class AuthProvider < ApplicationRecord
|
|||||||
has_many :auth_provider_mappings, dependent: :destroy
|
has_many :auth_provider_mappings, dependent: :destroy
|
||||||
accepts_nested_attributes_for :auth_provider_mappings, allow_destroy: true
|
accepts_nested_attributes_for :auth_provider_mappings, allow_destroy: true
|
||||||
|
|
||||||
|
validates :providable_type, inclusion: { in: PROVIDABLE_TYPES }
|
||||||
|
validates :name, presence: true, uniqueness: true
|
||||||
|
|
||||||
before_create :set_initial_state
|
before_create :set_initial_state
|
||||||
|
|
||||||
def build_providable(params)
|
def build_providable(params)
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
class DatabaseProvider < ApplicationRecord
|
class DatabaseProvider < ApplicationRecord
|
||||||
has_one :auth_provider, as: :providable, dependent: :destroy
|
has_one :auth_provider, as: :providable, dependent: :destroy
|
||||||
|
|
||||||
|
validates_with DatabaseProviderValidator
|
||||||
|
|
||||||
def profile_url
|
def profile_url
|
||||||
'/#!/dashboard/profile'
|
'/#!/dashboard/profile'
|
||||||
end
|
end
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
class OAuth2Provider < ApplicationRecord
|
class OAuth2Provider < ApplicationRecord
|
||||||
has_one :auth_provider, as: :providable
|
has_one :auth_provider, as: :providable
|
||||||
|
|
||||||
|
validates_with OAuth2ProviderValidator
|
||||||
|
|
||||||
def domain
|
def domain
|
||||||
URI(base_url).scheme + '://' + URI(base_url).host
|
URI(base_url).scheme + '://' + URI(base_url).host
|
||||||
end
|
end
|
||||||
|
10
app/validators/database_provider_validator.rb
Normal file
10
app/validators/database_provider_validator.rb
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Validates there's only one database provider
|
||||||
|
class DatabaseProviderValidator < ActiveModel::Validator
|
||||||
|
def validate(record)
|
||||||
|
return if DatabaseProvider.count.zero?
|
||||||
|
|
||||||
|
record.errors[:id] << I18n.t('app.admin.authentication_new.a_local_database_provider_already_exists_unable_to_create_another')
|
||||||
|
end
|
||||||
|
end
|
12
app/validators/o_auth2_provider_validator.rb
Normal file
12
app/validators/o_auth2_provider_validator.rb
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Validates the presence of the User.uid mapping
|
||||||
|
class OAuth2ProviderValidator < ActiveModel::Validator
|
||||||
|
def validate(record)
|
||||||
|
return if record.auth_provider.auth_provider_mappings.any? do |mapping|
|
||||||
|
mapping.local_model == 'user' && mapping.local_field == 'uid'
|
||||||
|
end
|
||||||
|
|
||||||
|
record.errors.add(:uid, I18n.t('app.admin.authentication_new.it_is_required_to_set_the_matching_between_User.uid_and_the_API_to_add_this_provider'))
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue
Block a user