flow editing
This commit is contained in:
parent
04d3d26cb1
commit
930fc66ebf
14 changed files with 530 additions and 34 deletions
|
@ -1102,6 +1102,48 @@ module.config([ '$routeProvider', function($routeProvider) {
|
||||||
},
|
},
|
||||||
controller : 'AuthenticationFlowsCtrl'
|
controller : 'AuthenticationFlowsCtrl'
|
||||||
})
|
})
|
||||||
|
.when('/realms/:realm/authentication/flows/:flow/create/execution', {
|
||||||
|
templateUrl : resourceUrl + '/partials/create-execution.html',
|
||||||
|
resolve : {
|
||||||
|
realm : function(RealmLoader) {
|
||||||
|
return RealmLoader();
|
||||||
|
},
|
||||||
|
parentFlow : function(AuthenticationFlowLoader) {
|
||||||
|
return AuthenticationFlowLoader();
|
||||||
|
},
|
||||||
|
formActionProviders : function(AuthenticationFormActionProvidersLoader) {
|
||||||
|
return AuthenticationFormActionProvidersLoader();
|
||||||
|
},
|
||||||
|
authenticatorProviders : function(AuthenticatorProvidersLoader) {
|
||||||
|
return AuthenticatorProvidersLoader();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
controller : 'CreateExecutionCtrl'
|
||||||
|
})
|
||||||
|
.when('/realms/:realm/authentication/flows/:flow/create/flow/execution', {
|
||||||
|
templateUrl : resourceUrl + '/partials/create-flow-execution.html',
|
||||||
|
resolve : {
|
||||||
|
realm : function(RealmLoader) {
|
||||||
|
return RealmLoader();
|
||||||
|
},
|
||||||
|
parentFlow : function(AuthenticationFlowLoader) {
|
||||||
|
return AuthenticationFlowLoader();
|
||||||
|
},
|
||||||
|
formProviders : function(AuthenticationFormProvidersLoader) {
|
||||||
|
return AuthenticationFormProvidersLoader();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
controller : 'CreateExecutionFlowCtrl'
|
||||||
|
})
|
||||||
|
.when('/realms/:realm/authentication/create/flow', {
|
||||||
|
templateUrl : resourceUrl + '/partials/create-flow.html',
|
||||||
|
resolve : {
|
||||||
|
realm : function(RealmLoader) {
|
||||||
|
return RealmLoader();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
controller : 'CreateFlowCtrl'
|
||||||
|
})
|
||||||
.when('/realms/:realm/authentication/required-actions', {
|
.when('/realms/:realm/authentication/required-actions', {
|
||||||
templateUrl : resourceUrl + '/partials/required-actions.html',
|
templateUrl : resourceUrl + '/partials/required-actions.html',
|
||||||
resolve : {
|
resolve : {
|
||||||
|
|
|
@ -1616,8 +1616,91 @@ module.controller('IdentityProviderMapperCreateCtrl', function($scope, realm, id
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
module.controller('AuthenticationFlowsCtrl', function($scope, realm, flows, selectedFlow,
|
module.controller('CreateFlowCtrl', function($scope, realm,
|
||||||
AuthenticationFlowsCopy, AuthenticationFlowExecutions,
|
AuthenticationFlows,
|
||||||
|
Notifications, $location) {
|
||||||
|
$scope.realm = realm;
|
||||||
|
$scope.flow = {
|
||||||
|
alias: "",
|
||||||
|
providerId: "basic-flow",
|
||||||
|
description: "",
|
||||||
|
topLevel: true,
|
||||||
|
builtIn: false
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.save = function() {
|
||||||
|
AuthenticationFlows.save({realm: realm.realm, flow: ""}, $scope.flow, function() {
|
||||||
|
$location.url("/realms/" + realm.realm + "/authentication/flows/" + $scope.flow.alias);
|
||||||
|
Notifications.success("Flow Created.");
|
||||||
|
})
|
||||||
|
}
|
||||||
|
$scope.cancel = function() {
|
||||||
|
$location.url("/realms/" + realm.realm + "/authentication/flows");
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
module.controller('CreateExecutionFlowCtrl', function($scope, realm, parentFlow, formProviders,
|
||||||
|
CreateExecutionFlow,
|
||||||
|
Notifications, $location) {
|
||||||
|
$scope.realm = realm;
|
||||||
|
$scope.formProviders = formProviders;
|
||||||
|
$scope.flow = {
|
||||||
|
alias: "",
|
||||||
|
type: "basic-flow",
|
||||||
|
description: ""
|
||||||
|
}
|
||||||
|
$scope.provider = {};
|
||||||
|
if (formProviders.length > 0) {
|
||||||
|
$scope.provider = formProviders[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.save = function() {
|
||||||
|
$scope.flow.provider = $scope.provider.id;
|
||||||
|
CreateExecutionFlow.save({realm: realm.realm, alias: parentFlow.alias}, $scope.flow, function() {
|
||||||
|
$location.url("/realms/" + realm.realm + "/authentication/flows/" + parentFlow.alias);
|
||||||
|
Notifications.success("Flow Created.");
|
||||||
|
})
|
||||||
|
}
|
||||||
|
$scope.cancel = function() {
|
||||||
|
$location.url("/realms/" + realm.realm + "/authentication/flows/" + parentFlow.alias);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
module.controller('CreateExecutionCtrl', function($scope, realm, parentFlow, formActionProviders, authenticatorProviders,
|
||||||
|
CreateExecution,
|
||||||
|
Notifications, $location) {
|
||||||
|
$scope.realm = realm;
|
||||||
|
$scope.parentFlow = parentFlow;
|
||||||
|
console.log('parentFlow.providerId: ' + parentFlow.providerId);
|
||||||
|
if (parentFlow.providerId == 'form-flow') {
|
||||||
|
$scope.providers = formActionProviders;
|
||||||
|
} else {
|
||||||
|
$scope.providers = authenticatorProviders;
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.provider = {};
|
||||||
|
if ($scope.providers.length > 0) {
|
||||||
|
$scope.provider = $scope.providers[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.save = function() {
|
||||||
|
var execution = {
|
||||||
|
provider: $scope.provider.id
|
||||||
|
}
|
||||||
|
CreateExecution.save({realm: realm.realm, alias: parentFlow.alias}, execution, function() {
|
||||||
|
$location.url("/realms/" + realm.realm + "/authentication/flows/" + parentFlow.alias);
|
||||||
|
Notifications.success("Execution Created.");
|
||||||
|
})
|
||||||
|
}
|
||||||
|
$scope.cancel = function() {
|
||||||
|
$location.url("/realms/" + realm.realm + "/authentication/flows/" + parentFlow.alias);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
module.controller('AuthenticationFlowsCtrl', function($scope, $route, realm, flows, selectedFlow,
|
||||||
|
AuthenticationFlows, AuthenticationFlowsCopy, AuthenticationFlowExecutions,
|
||||||
AuthenticationExecution, AuthenticationExecutionRaisePriority, AuthenticationExecutionLowerPriority,
|
AuthenticationExecution, AuthenticationExecutionRaisePriority, AuthenticationExecutionLowerPriority,
|
||||||
$modal, Notifications, CopyDialog, $location) {
|
$modal, Notifications, CopyDialog, $location) {
|
||||||
$scope.realm = realm;
|
$scope.realm = realm;
|
||||||
|
@ -1637,12 +1720,12 @@ module.controller('AuthenticationFlowsCtrl', function($scope, realm, flows, sele
|
||||||
var setupForm = function() {
|
var setupForm = function() {
|
||||||
AuthenticationFlowExecutions.query({realm: realm.realm, alias: $scope.flow.alias}, function(data) {
|
AuthenticationFlowExecutions.query({realm: realm.realm, alias: $scope.flow.alias}, function(data) {
|
||||||
$scope.executions = data;
|
$scope.executions = data;
|
||||||
$scope.flowmax = 0;
|
$scope.choicesmax = 0;
|
||||||
$scope.levelmax = 0;
|
$scope.levelmax = 0;
|
||||||
for (var i = 0; i < $scope.executions.length; i++ ) {
|
for (var i = 0; i < $scope.executions.length; i++ ) {
|
||||||
var execution = $scope.executions[i];
|
var execution = $scope.executions[i];
|
||||||
if (execution.requirementChoices.length > $scope.flowmax) {
|
if (execution.requirementChoices.length > $scope.choicesmax) {
|
||||||
$scope.flowmax = execution.requirementChoices.length;
|
$scope.choicesmax = execution.requirementChoices.length;
|
||||||
}
|
}
|
||||||
if (execution.level > $scope.levelmax) {
|
if (execution.level > $scope.levelmax) {
|
||||||
$scope.levelmax = execution.level;
|
$scope.levelmax = execution.level;
|
||||||
|
@ -1657,12 +1740,16 @@ module.controller('AuthenticationFlowsCtrl', function($scope, realm, flows, sele
|
||||||
for (var i = 0; i < $scope.executions.length; i++ ) {
|
for (var i = 0; i < $scope.executions.length; i++ ) {
|
||||||
var execution = $scope.executions[i];
|
var execution = $scope.executions[i];
|
||||||
execution.empties = [];
|
execution.empties = [];
|
||||||
for (j = 0; j < $scope.flowmax - execution.requirementChoices.length; j++) {
|
for (j = 0; j < $scope.choicesmax - execution.requirementChoices.length; j++) {
|
||||||
execution.empties.push(j);
|
execution.empties.push(j);
|
||||||
}
|
}
|
||||||
execution.levels = [];
|
execution.preLevels = [];
|
||||||
for (j = 0; j < execution.level; j++) {
|
for (j = 0; j < execution.level; j++) {
|
||||||
execution.levels.push(j);
|
execution.preLevels.push(j);
|
||||||
|
}
|
||||||
|
execution.postLevels = [];
|
||||||
|
for (j = execution.level; j < $scope.levelmax; j++) {
|
||||||
|
execution.postLevels.push(j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1679,6 +1766,39 @@ module.controller('AuthenticationFlowsCtrl', function($scope, realm, flows, sele
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.removeFlow = function() {
|
||||||
|
AuthenticationFlows.remove({realm: realm, flow: flow.id}, function() {
|
||||||
|
$route.reload();
|
||||||
|
Notifications.success("Flow removed");
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.addFlow = function() {
|
||||||
|
$location.url("/realms/" + realm.realm + '/authentication/flows/' + $scope.flow.id + '/create/flow/execution');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.addSubFlow = function(execution) {
|
||||||
|
$location.url("/realms/" + realm.realm + '/authentication/flows/' + execution.flowId + '/create/flow/execution');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.addSubFlowExecution = function(execution) {
|
||||||
|
$location.url("/realms/" + realm.realm + '/authentication/flows/' + execution.flowId + '/create/execution');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.addExecution = function() {
|
||||||
|
$location.url("/realms/" + realm.realm + '/authentication/flows/' + $scope.flow.id + '/create/execution');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.createFlow = function() {
|
||||||
|
$location.url("/realms/" + realm.realm + '/authentication/create/flow');
|
||||||
|
}
|
||||||
|
|
||||||
$scope.updateExecution = function(execution) {
|
$scope.updateExecution = function(execution) {
|
||||||
var copy = angular.copy(execution);
|
var copy = angular.copy(execution);
|
||||||
delete copy.empties;
|
delete copy.empties;
|
||||||
|
|
|
@ -353,12 +353,46 @@ module.factory('IdentityProviderMapperLoader', function(Loader, IdentityProvider
|
||||||
|
|
||||||
module.factory('AuthenticationFlowsLoader', function(Loader, AuthenticationFlows, $route, $q) {
|
module.factory('AuthenticationFlowsLoader', function(Loader, AuthenticationFlows, $route, $q) {
|
||||||
return Loader.query(AuthenticationFlows, function() {
|
return Loader.query(AuthenticationFlows, function() {
|
||||||
|
return {
|
||||||
|
realm : $route.current.params.realm,
|
||||||
|
flow: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.factory('AuthenticationFormProvidersLoader', function(Loader, AuthenticationFormProviders, $route, $q) {
|
||||||
|
return Loader.query(AuthenticationFormProviders, function() {
|
||||||
return {
|
return {
|
||||||
realm : $route.current.params.realm
|
realm : $route.current.params.realm
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
module.factory('AuthenticationFormActionProvidersLoader', function(Loader, AuthenticationFormActionProviders, $route, $q) {
|
||||||
|
return Loader.query(AuthenticationFormActionProviders, function() {
|
||||||
|
return {
|
||||||
|
realm : $route.current.params.realm
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.factory('AuthenticatorProvidersLoader', function(Loader, AuthenticatorProviders, $route, $q) {
|
||||||
|
return Loader.query(AuthenticatorProviders, function() {
|
||||||
|
return {
|
||||||
|
realm : $route.current.params.realm
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.factory('AuthenticationFlowLoader', function(Loader, AuthenticationFlows, $route, $q) {
|
||||||
|
return Loader.get(AuthenticationFlows, function() {
|
||||||
|
return {
|
||||||
|
realm : $route.current.params.realm,
|
||||||
|
flow: $route.current.params.flow
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
module.factory('AuthenticationConfigDescriptionLoader', function(Loader, AuthenticationConfigDescription, $route, $q) {
|
module.factory('AuthenticationConfigDescriptionLoader', function(Loader, AuthenticationConfigDescription, $route, $q) {
|
||||||
return Loader.get(AuthenticationConfigDescription, function () {
|
return Loader.get(AuthenticationConfigDescription, function () {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -1172,11 +1172,46 @@ module.factory('AuthenticationFlowExecutions', function($resource) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
module.factory('CreateExecutionFlow', function($resource) {
|
||||||
|
return $resource(authUrl + '/admin/realms/:realm/authentication/flows/:alias/executions/flow', {
|
||||||
|
realm : '@realm',
|
||||||
|
alias : '@alias'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.factory('CreateExecution', function($resource) {
|
||||||
|
return $resource(authUrl + '/admin/realms/:realm/authentication/flows/:alias/executions/execution', {
|
||||||
|
realm : '@realm',
|
||||||
|
alias : '@alias'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
module.factory('AuthenticationFlows', function($resource) {
|
module.factory('AuthenticationFlows', function($resource) {
|
||||||
return $resource(authUrl + '/admin/realms/:realm/authentication/flows', {
|
return $resource(authUrl + '/admin/realms/:realm/authentication/flows/:flow', {
|
||||||
|
realm : '@realm',
|
||||||
|
flow: '@flow'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.factory('AuthenticationFormProviders', function($resource) {
|
||||||
|
return $resource(authUrl + '/admin/realms/:realm/authentication/form-providers', {
|
||||||
realm : '@realm'
|
realm : '@realm'
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
module.factory('AuthenticationFormActionProviders', function($resource) {
|
||||||
|
return $resource(authUrl + '/admin/realms/:realm/authentication/form-action-providers', {
|
||||||
|
realm : '@realm'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.factory('AuthenticatorProviders', function($resource) {
|
||||||
|
return $resource(authUrl + '/admin/realms/:realm/authentication/authenticator-providers', {
|
||||||
|
realm : '@realm'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
module.factory('AuthenticationFlowsCopy', function($resource) {
|
module.factory('AuthenticationFlowsCopy', function($resource) {
|
||||||
return $resource(authUrl + '/admin/realms/:realm/authentication/flows/:alias/copy', {
|
return $resource(authUrl + '/admin/realms/:realm/authentication/flows/:alias/copy', {
|
||||||
realm : '@realm',
|
realm : '@realm',
|
||||||
|
|
|
@ -6,15 +6,16 @@
|
||||||
<table class="table table-striped table-bordered">
|
<table class="table table-striped table-bordered">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th colspan="{{levelmax + 1 + flowmax + 4}}" class="kc-table-actions">
|
<th colspan="{{levelmax + 1 + choicesmax + 4}}" class="kc-table-actions">
|
||||||
<div class="dropdown pull-left">
|
<div class="dropdown pull-left">
|
||||||
<select class="form-control" ng-model="flow"
|
<select class="form-control" ng-model="flow"
|
||||||
ng-options="(flow.alias|capitalize) for flow in flows"
|
ng-options="(flow.alias|capitalize) for flow in flows"
|
||||||
data-ng-change="setupForm()">
|
data-ng-change="setupForm()">
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<i class="fa fa-question-circle text-muted" tooltip="{{flow.description}}" tooltip-placement="right"> </i>
|
||||||
<div class="pull-right" data-ng-show="access.manageRealm">
|
<div class="pull-right" data-ng-show="access.manageRealm">
|
||||||
<button class="btn btn-default" data-ng-click="newFlow()">New</button>
|
<button class="btn btn-default" data-ng-click="createFlow()">New</button>
|
||||||
<button class="btn btn-default" data-ng-click="copyFlow()">Copy</button>
|
<button class="btn btn-default" data-ng-click="copyFlow()">Copy</button>
|
||||||
<button class="btn btn-default" data-ng-hide="flow.builtIn" data-ng-click="removeFlow()">Delete</button>
|
<button class="btn btn-default" data-ng-hide="flow.builtIn" data-ng-click="removeFlow()">Delete</button>
|
||||||
<button class="btn btn-default" data-ng-hide="flow.builtIn" data-ng-click="addExecution()">Add Execution</button>
|
<button class="btn btn-default" data-ng-hide="flow.builtIn" data-ng-click="addExecution()">Add Execution</button>
|
||||||
|
@ -24,15 +25,15 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr data-ng-hide="executions.length == 0">
|
<tr data-ng-hide="executions.length == 0">
|
||||||
<th colspan="{{levelmax + 1}}">Auth Type</th>
|
<th colspan="{{levelmax + 1}}">Auth Type</th>
|
||||||
<th colspan="{{flowmax}}">Requirement</th>
|
<th colspan="{{choicesmax}}">Requirement</th>
|
||||||
<th colspan="3">Actions</th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr ng-repeat="execution in executions" data-ng-show="executions.length > 0">
|
<tr ng-repeat="execution in executions" data-ng-show="executions.length > 0">
|
||||||
<td ng-repeat="lev in execution.levels"></td>
|
<td ng-repeat="lev in execution.preLevels"></td>
|
||||||
<td><button data-ng-hide="flow.builtIn || $first" class="btn btn-default" data-ng-click="raisePriority(execution)"><i class="fa fa-angle-up"></i></button><button data-ng-hide="flow.builtIn || $last" class="btn btn-default" data-ng-click="lowerPriority(execution)"><i class="fa fa-angle-down"></i></button> {{execution.displayName|capitalize}}</td>
|
<td><button data-ng-hide="flow.builtIn || $first" class="btn btn-default" data-ng-click="raisePriority(execution)"><i class="fa fa-angle-up"></i></button><button data-ng-hide="flow.builtIn || $last" class="btn btn-default" data-ng-click="lowerPriority(execution)"><i class="fa fa-angle-down"></i></button> {{execution.displayName|capitalize}}</td>
|
||||||
<td data-ng-show="execution.level == 0" ng-repeat="levmax in levelmaxempties"></td>
|
<td ng-repeat="lev in execution.postLevels"></td>
|
||||||
<td ng-repeat="choice in execution.requirementChoices">
|
<td ng-repeat="choice in execution.requirementChoices">
|
||||||
<label >
|
<label >
|
||||||
<input type="radio" ng-model="execution.requirement" ng-value="choice" ng-change="updateExecution(execution)">
|
<input type="radio" ng-model="execution.requirement" ng-value="choice" ng-change="updateExecution(execution)">
|
||||||
|
@ -41,20 +42,21 @@
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
<td ng-repeat="emptee in execution.empties"></td>
|
<td ng-repeat="emptee in execution.empties"></td>
|
||||||
<td data-ng-hide="flow.builtIn" class="kc-action-cell">
|
<td>
|
||||||
<button class="btn btn-default btn-block btn-sm" data-ng-click="removeExecution(execution)">Delete</button>
|
<ul class="nav navbar-nav navbar-utility" data-ng-hide="flow.builtIn && !execution.configurable">
|
||||||
</td>
|
<li class="dropdown">
|
||||||
<td data-ng-hide="flow.builtIn || !execution.authenticationFlow" class="kc-action-cell">
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||||
<button class="btn btn-default btn-block btn-sm" data-ng-click="addSubFlowExecution(execution)">Add Execution</button>
|
Actions <b class="caret"></b>
|
||||||
</td>
|
</a>
|
||||||
<td data-ng-hide="flow.builtIn || !execution.authenticationFlow" class="kc-action-cell">
|
<ul class="dropdown-menu" >
|
||||||
<button class="btn btn-default btn-block btn-sm" data-ng-click="addSubFlowExecution(execution)">Add Flow</button>
|
<li data-ng-hide="flow.builtIn"><a href="" ng-click="removeExecution(execution)">Delete</a></li>
|
||||||
</td>
|
<li data-ng-hide="flow.builtIn || !execution.authenticationFlow"><a href="" ng-click="addSubFlowExecution(execution)">Add Execution</a></li>
|
||||||
<td data-ng-show="execution.configurable && execution.authenticationConfig == null" class="kc-action-cell">
|
<li data-ng-hide="flow.builtIn || !execution.authenticationFlow"><a href="" ng-click="addSubFlow(execution)">Add Flow</a></li>
|
||||||
<button data-ng-show="execution.configurable && execution.authenticationConfig == null" class="btn btn-default btn-block btn-sm" kc-open="/create/authentication/{{realm.realm}}/execution/{{execution.id}}/provider/{{execution.providerId}}">Config</button>
|
<li data-ng-show="execution.configurable && execution.authenticationConfig == null"><a href="#/create/authentication/{{realm.realm}}/execution/{{execution.id}}/provider/{{execution.providerId}}">Config</a></li>
|
||||||
</td>
|
<li data-ng-show="execution.configurable && execution.authenticationConfig != null"><a href="#/realms/{{realm.realm}}/authentication/config/{{execution.providerId}}/{{execution.authenticationConfig}}">Config</a></li>
|
||||||
<td data-ng-show="execution.configurable && execution.authenticationConfig != null" class="kc-action-cell">
|
</ul>
|
||||||
<button data-ng-show="execution.configurable && execution.authenticationConfig != null" class="btn btn-default btn-block btn-sm" kc-open="/realms/{{realm.realm}}/authentication/config/{{execution.providerId}}/{{execution.authenticationConfig}}">Config</button>
|
</li>
|
||||||
|
</ul>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr data-ng-show="executions.length == 0">
|
<tr data-ng-show="executions.length == 0">
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
|
||||||
|
<div>
|
||||||
|
<h1 data-ng-show="parentFlow.providerId == 'basic-flow'">Create Authenticator Execution</h1>
|
||||||
|
<h1 data-ng-show="parentFlow.providerId == 'for-flow'">Create Form Action Execution</h1>
|
||||||
|
</div>
|
||||||
|
<kc-tabs-authentication></kc-tabs-authentication>
|
||||||
|
<form class="form-horizontal" name="clientForm" novalidate kc-read-only="!access.manageRealm">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-md-2 control-label" for="provider">Provider</label>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<div>
|
||||||
|
<select class="form-control" id="provider"
|
||||||
|
ng-model="provider"
|
||||||
|
ng-options="provider.id for provider in providers">
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<kc-tooltip>{{provider.description}}</kc-tooltip>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-md-10 col-md-offset-2">
|
||||||
|
<button kc-save>Save</button>
|
||||||
|
<button type="button" class="btn btn-default" ng-click="cancel()">Cancel</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<kc-menu></kc-menu>
|
|
@ -0,0 +1,55 @@
|
||||||
|
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
|
||||||
|
<h1>Create Execution Flow</h1>
|
||||||
|
|
||||||
|
<kc-tabs-authentication></kc-tabs-authentication>
|
||||||
|
|
||||||
|
<form class="form-horizontal" name="clientForm" novalidate kc-read-only="!access.manageRealm">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-md-2 control-label" for="alias">Alias </label>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<input class="form-control" type="text" id="alias" name="alias" data-ng-model="flow.alias" autofocus>
|
||||||
|
</div>
|
||||||
|
<kc-tooltip>Specifies display name for the flow.</kc-tooltip>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-md-2 control-label" for="description">Description </label>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<textarea class="form-control" rows="5" cols="50" id="description" name="description" data-ng-model="flow.description"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-md-2 control-label" for="flowType">Flow Type</label>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<div>
|
||||||
|
<select class="form-control" id="flowType"
|
||||||
|
ng-model="flow.type">
|
||||||
|
<option value="basic-flow">generic</option>
|
||||||
|
<option value="form-flow">form</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<kc-tooltip>What kind of form is it</kc-tooltip>
|
||||||
|
</div>
|
||||||
|
<div class="form-group" data-ng-show="flow.type == 'form-flow'">
|
||||||
|
<label class="col-md-2 control-label" for="provider">Form Provider</label>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<div>
|
||||||
|
<select class="form-control" id="provider"
|
||||||
|
ng-model="provider"
|
||||||
|
ng-options="provider.id for provider in formProviders">
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<kc-tooltip>{{provider.description}}</kc-tooltip>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-md-10 col-md-offset-2">
|
||||||
|
<button kc-save>Save</button>
|
||||||
|
<button type="button" class="btn btn-default" ng-click="cancel()">Cancel</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<kc-menu></kc-menu>
|
|
@ -0,0 +1,30 @@
|
||||||
|
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
|
||||||
|
<h1>Create Top Level Flow</h1>
|
||||||
|
|
||||||
|
<kc-tabs-authentication></kc-tabs-authentication>
|
||||||
|
|
||||||
|
<form class="form-horizontal" name="clientForm" novalidate kc-read-only="!access.manageRealm">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-md-2 control-label" for="alias">Alias </label>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<input class="form-control" type="text" id="alias" name="alias" data-ng-model="flow.alias" autofocus>
|
||||||
|
</div>
|
||||||
|
<kc-tooltip>Specifies display name for the flow.</kc-tooltip>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-md-2 control-label" for="description">Description </label>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<textarea class="form-control" rows="5" cols="50" id="description" name="description" data-ng-model="flow.description"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-md-10 col-md-offset-2">
|
||||||
|
<button kc-save>Save</button>
|
||||||
|
<button type="button" class="btn btn-default" ng-click="cancel()">Cancel</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<kc-menu></kc-menu>
|
|
@ -45,7 +45,7 @@ public class RegistrationPage implements FormAuthenticator, FormAuthenticatorFac
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getHelpText() {
|
public String getHelpText() {
|
||||||
return null;
|
return "This is the controller for the registration page";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -34,7 +34,7 @@ public class RegistrationPassword implements FormAction, FormActionFactory {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getHelpText() {
|
public String getHelpText() {
|
||||||
return null;
|
return "Validates that password matches password confirmation field. It also will store password in user's credential store.";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -31,7 +31,7 @@ public class RegistrationProfile implements FormAction, FormActionFactory {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getHelpText() {
|
public String getHelpText() {
|
||||||
return null;
|
return "Validates email, first name, and last name attributes and stores them in user data.";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -191,7 +191,7 @@ public class RegistrationRecaptcha implements FormAction, FormActionFactory, Con
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getHelpText() {
|
public String getHelpText() {
|
||||||
return null;
|
return "Adds Google Recaptcha button. Recaptchas verify that the entity that is registering is a human. This can only be used on the internet and must be configured after you add it.";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
private static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
||||||
|
|
|
@ -35,7 +35,7 @@ public class RegistrationUserCreation implements FormAction, FormActionFactory {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getHelpText() {
|
public String getHelpText() {
|
||||||
return null;
|
return "This action must always be first! Validates the username of the user in validation phase. In success phase, this will create the user in the database.";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -5,15 +5,22 @@ import org.jboss.resteasy.annotations.cache.NoCache;
|
||||||
import org.jboss.resteasy.spi.BadRequestException;
|
import org.jboss.resteasy.spi.BadRequestException;
|
||||||
import org.jboss.resteasy.spi.NotFoundException;
|
import org.jboss.resteasy.spi.NotFoundException;
|
||||||
import org.keycloak.authentication.AuthenticationFlow;
|
import org.keycloak.authentication.AuthenticationFlow;
|
||||||
|
import org.keycloak.authentication.Authenticator;
|
||||||
import org.keycloak.authentication.AuthenticatorUtil;
|
import org.keycloak.authentication.AuthenticatorUtil;
|
||||||
import org.keycloak.authentication.ConfigurableAuthenticatorFactory;
|
import org.keycloak.authentication.ConfigurableAuthenticatorFactory;
|
||||||
|
import org.keycloak.authentication.DefaultAuthenticationFlow;
|
||||||
|
import org.keycloak.authentication.FormAction;
|
||||||
|
import org.keycloak.authentication.FormAuthenticationFlow;
|
||||||
|
import org.keycloak.authentication.FormAuthenticator;
|
||||||
import org.keycloak.models.AuthenticationExecutionModel;
|
import org.keycloak.models.AuthenticationExecutionModel;
|
||||||
import org.keycloak.models.AuthenticationFlowModel;
|
import org.keycloak.models.AuthenticationFlowModel;
|
||||||
import org.keycloak.models.AuthenticatorConfigModel;
|
import org.keycloak.models.AuthenticatorConfigModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RequiredActionProviderModel;
|
import org.keycloak.models.RequiredActionProviderModel;
|
||||||
|
import org.keycloak.provider.ConfiguredProvider;
|
||||||
import org.keycloak.provider.ProviderConfigProperty;
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
|
import org.keycloak.provider.ProviderFactory;
|
||||||
import org.keycloak.representations.idm.ConfigPropertyRepresentation;
|
import org.keycloak.representations.idm.ConfigPropertyRepresentation;
|
||||||
import org.keycloak.utils.CredentialHelper;
|
import org.keycloak.utils.CredentialHelper;
|
||||||
|
|
||||||
|
@ -68,6 +75,7 @@ public class AuthenticationManagementResource {
|
||||||
protected Boolean authenticationFlow;
|
protected Boolean authenticationFlow;
|
||||||
protected String providerId;
|
protected String providerId;
|
||||||
protected String authenticationConfig;
|
protected String authenticationConfig;
|
||||||
|
protected String flowId;
|
||||||
protected int level;
|
protected int level;
|
||||||
protected int index;
|
protected int index;
|
||||||
|
|
||||||
|
@ -150,8 +158,59 @@ public class AuthenticationManagementResource {
|
||||||
public void setIndex(int index) {
|
public void setIndex(int index) {
|
||||||
this.index = index;
|
this.index = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getFlowId() {
|
||||||
|
return flowId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setFlowId(String flowId) {
|
||||||
|
this.flowId = flowId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("/form-providers")
|
||||||
|
@GET
|
||||||
|
@NoCache
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public List<Map<String, String>> getFormProviders() {
|
||||||
|
this.auth.requireView();
|
||||||
|
List<ProviderFactory> factories = session.getKeycloakSessionFactory().getProviderFactories(FormAuthenticator.class);
|
||||||
|
return buildProviderMetadata(factories);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("/authenticator-providers")
|
||||||
|
@GET
|
||||||
|
@NoCache
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public List<Map<String, String>> getAuthenticatorProviders() {
|
||||||
|
this.auth.requireView();
|
||||||
|
List<ProviderFactory> factories = session.getKeycloakSessionFactory().getProviderFactories(Authenticator.class);
|
||||||
|
return buildProviderMetadata(factories);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Map<String, String>> buildProviderMetadata(List<ProviderFactory> factories) {
|
||||||
|
List<Map<String, String>> providers = new LinkedList<>();
|
||||||
|
for (ProviderFactory factory : factories) {
|
||||||
|
Map<String, String> data = new HashMap<>();
|
||||||
|
data.put("id", factory.getId());
|
||||||
|
ConfiguredProvider configured = (ConfiguredProvider)factory;
|
||||||
|
data.put("description", configured.getHelpText());
|
||||||
|
providers.add(data);
|
||||||
|
}
|
||||||
|
return providers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("/form-action-providers")
|
||||||
|
@GET
|
||||||
|
@NoCache
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public List<Map<String, String>> getFormActionProviders() {
|
||||||
|
this.auth.requireView();
|
||||||
|
List<ProviderFactory> factories = session.getKeycloakSessionFactory().getProviderFactories(FormAction.class);
|
||||||
|
return buildProviderMetadata(factories);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Path("/flows")
|
@Path("/flows")
|
||||||
@GET
|
@GET
|
||||||
@NoCache
|
@NoCache
|
||||||
|
@ -183,6 +242,36 @@ public class AuthenticationManagementResource {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Path("/flows/{id}")
|
||||||
|
@GET
|
||||||
|
@NoCache
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public AuthenticationFlowModel getFlow(@PathParam("id") String id) {
|
||||||
|
this.auth.requireView();
|
||||||
|
|
||||||
|
AuthenticationFlowModel flow = realm.getAuthenticationFlowById(id);
|
||||||
|
if (flow == null) {
|
||||||
|
throw new NotFoundException("Could not find flow with id");
|
||||||
|
}
|
||||||
|
return flow;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("/flows/{id}")
|
||||||
|
@DELETE
|
||||||
|
@NoCache
|
||||||
|
public void deleteFlow(@PathParam("id") String id) {
|
||||||
|
this.auth.requireView();
|
||||||
|
|
||||||
|
AuthenticationFlowModel flow = realm.getAuthenticationFlowById(id);
|
||||||
|
if (flow == null) {
|
||||||
|
throw new NotFoundException("Could not find flow with id");
|
||||||
|
}
|
||||||
|
if (flow.isBuiltIn()) {
|
||||||
|
throw new BadRequestException("Can't delete built in flow");
|
||||||
|
}
|
||||||
|
realm.removeAuthenticationFlow(flow);
|
||||||
|
}
|
||||||
|
|
||||||
@Path("/flows/{flowAlias}/copy")
|
@Path("/flows/{flowAlias}/copy")
|
||||||
@POST
|
@POST
|
||||||
@NoCache
|
@NoCache
|
||||||
|
@ -233,6 +322,65 @@ public class AuthenticationManagementResource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Path("/flows/{flowAlias}/executions/flow")
|
||||||
|
@POST
|
||||||
|
@NoCache
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
public void addExecutionFlow(@PathParam("flowAlias") String flowAlias, Map<String, String> data) {
|
||||||
|
this.auth.requireManage();
|
||||||
|
|
||||||
|
AuthenticationFlowModel parentFlow = realm.getFlowByAlias(flowAlias);
|
||||||
|
if (parentFlow == null) {
|
||||||
|
throw new BadRequestException("Parent flow doesn't exists");
|
||||||
|
}
|
||||||
|
String alias = data.get("alias");
|
||||||
|
String type = data.get("type");
|
||||||
|
String provider = data.get("provider");
|
||||||
|
String description = data.get("description");
|
||||||
|
|
||||||
|
|
||||||
|
AuthenticationFlowModel newFlow = realm.getFlowByAlias(alias);
|
||||||
|
if (newFlow != null) {
|
||||||
|
throw new BadRequestException("New flow alias name already exists");
|
||||||
|
}
|
||||||
|
newFlow = new AuthenticationFlowModel();
|
||||||
|
newFlow.setAlias(alias);
|
||||||
|
newFlow.setDescription(description);
|
||||||
|
newFlow.setProviderId(type);
|
||||||
|
newFlow = realm.addAuthenticationFlow(newFlow);
|
||||||
|
AuthenticationExecutionModel execution = new AuthenticationExecutionModel();
|
||||||
|
execution.setParentFlow(parentFlow.getId());
|
||||||
|
execution.setFlowId(newFlow.getId());
|
||||||
|
execution.setRequirement(AuthenticationExecutionModel.Requirement.DISABLED);
|
||||||
|
execution.setAuthenticatorFlow(true);
|
||||||
|
execution.setAuthenticator(provider);
|
||||||
|
realm.addAuthenticatorExecution(execution);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("/flows/{flowAlias}/executions/execution")
|
||||||
|
@POST
|
||||||
|
@NoCache
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
public void addExecution(@PathParam("flowAlias") String flowAlias, Map<String, String> data) {
|
||||||
|
this.auth.requireManage();
|
||||||
|
|
||||||
|
AuthenticationFlowModel parentFlow = realm.getFlowByAlias(flowAlias);
|
||||||
|
if (parentFlow == null) {
|
||||||
|
throw new BadRequestException("Parent flow doesn't exists");
|
||||||
|
}
|
||||||
|
String provider = data.get("provider");
|
||||||
|
|
||||||
|
|
||||||
|
AuthenticationExecutionModel execution = new AuthenticationExecutionModel();
|
||||||
|
execution.setParentFlow(parentFlow.getId());
|
||||||
|
execution.setRequirement(AuthenticationExecutionModel.Requirement.DISABLED);
|
||||||
|
execution.setAuthenticatorFlow(false);
|
||||||
|
execution.setAuthenticator(provider);
|
||||||
|
realm.addAuthenticatorExecution(execution);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Path("/flows/{flowAlias}/executions")
|
@Path("/flows/{flowAlias}/executions")
|
||||||
@GET
|
@GET
|
||||||
@NoCache
|
@NoCache
|
||||||
|
@ -278,6 +426,7 @@ public class AuthenticationManagementResource {
|
||||||
rep.setId(execution.getId());
|
rep.setId(execution.getId());
|
||||||
rep.setAuthenticationFlow(execution.isAuthenticatorFlow());
|
rep.setAuthenticationFlow(execution.isAuthenticatorFlow());
|
||||||
rep.setRequirement(execution.getRequirement().name());
|
rep.setRequirement(execution.getRequirement().name());
|
||||||
|
rep.setFlowId(execution.getFlowId());
|
||||||
result.add(rep);
|
result.add(rep);
|
||||||
AuthenticationFlowModel subFlow = realm.getAuthenticationFlowById(execution.getFlowId());
|
AuthenticationFlowModel subFlow = realm.getAuthenticationFlowById(execution.getFlowId());
|
||||||
recurseExecutions(subFlow, result, level + 1);
|
recurseExecutions(subFlow, result, level + 1);
|
||||||
|
|
Loading…
Reference in a new issue