WIP - Inherits Conf.pm (#1661)

This commit is contained in:
Christophe Maudoux 2019-03-14 16:39:49 +01:00
parent 0a8c3c1049
commit 71fc765d01
10 changed files with 36 additions and 426 deletions

View File

@ -119,10 +119,6 @@
"namespace" : "lemonldap-ng-sessions"
},
"locationRules" : {
"auth.example.com" : {
"(?#checkUser)/checkuser" : "$uid eq \"dwho\"",
"default" : "deny"
},
"manager.__DNSDOMAIN__" : {
"(?#Configuration)^/(manager\\.html|conf/)" : "$uid eq \"dwho\"",
"(?#Notifications)/notifications" : "$uid eq \"dwho\" or $uid eq \"rtyler\"",

View File

@ -296,6 +296,7 @@ sub defaultValues {
'useRedirectOnError' => 1,
'useSafeJail' => 1,
'utotp2fActivation' => 0,
'viewerAllowDiff' => 1,
'viewerHiddenPK' => 'virtualHosts',
'webIDAuthnLevel' => 1,
'webIDExportedVars' => {},

View File

@ -133,7 +133,7 @@ sub init {
}
sub tplParams {
return ( VERSION => $VERSION, );
return ( VERSION => $VERSION, ALLOWDIFF => 0 );
}
sub javascript {

View File

@ -3558,6 +3558,10 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-
],
'type' => 'select'
},
'viewerAllowDiff' => {
'default' => 1,
'type' => 'bool'
},
'viewerHiddenPK' => {
'default' => 'virtualHosts',
'type' => 'text'

View File

@ -922,6 +922,11 @@ sub attributes {
documentation => 'ConfTree hidden primary keys',
flags => 'm',
},
viewerAllowDiff => {
type => 'bool',
default => 1,
documentation => 'Allow configuration comparator',
},
# Notification
oldNotifFormat => {

View File

@ -17,7 +17,7 @@ use URI::URL;
use feature 'state';
extends 'Lemonldap::NG::Common::Conf::RESTServer';
extends 'Lemonldap::NG::Manager::Conf';
our $VERSION = '2.0.3';
@ -52,18 +52,6 @@ sub addRoutes {
# READ
# Special keys
# ->addRoute(
# view => {
# ':cfgNum' => [
# qw(virtualHosts samlIDPMetaDataNodes samlSPMetaDataNodes
# applicationList oidcOPMetaDataNodes oidcRPMetaDataNodes
# casSrvMetaDataNodes casAppMetaDataNodes
# authChoiceModules grantSessionRules combModules
# openIdIDPList)
# ]
# },
# ['GET']
# )
->addRoute(
view => {
':cfgNum' => \@enabledPK
@ -72,102 +60,22 @@ sub addRoutes {
)
# Other keys
->addRoute( view => { ':cfgNum' => { '*' => 'getKey' } }, ['GET'] )
# Difference between confs
->addRoute( diff => { ':conf1' => { ':conf2' => 'diff' } } )
->addRoute( 'diff.html', undef, ['GET'] );
->addRoute( view => { ':cfgNum' => { '*' => 'getKey' } }, ['GET'] );
}
##@method public PSGI-JSON-response prx()
# Load file using posted URL and return its content
#
#@return PSGI JSON response
sub prx {
my ( $self, $req, @others ) = @_;
return $self->sendError( $req, 'There is no subkey for "prx"', 400 )
if (@others);
my $query = $req->jsonBodyToObj;
return $self->sendError( $req, 'Missing parameter', 400 )
unless ( $query->{url} );
return $self->sendError( $req, 'Bad parameter', 400 )
unless ( $query->{url} =~ m#^(?:f|ht)tps?://\w# );
$self->ua->timeout(10);
my $response = $self->ua->get( $query->{url} );
unless ( $response->code == 200 ) {
return $self->sendError( $req,
$response->code . " (" . $response->message . ")", 400 );
}
unless ( $response->header('Content-Type') =~
m#^(?:application/json|(?:application|text)/.*xml).*$# )
{
return $self->sendError( $req,
'Content refused for security reason (neither XML or JSON)', 400 );
}
return $self->sendJSONresponse( $req, { content => $response->content } );
$self->SUPER::prx( $req, @others );
}
######################
# IV. Upload methods #
######################
# - getConfByNum: override SUPER method to be able to use Zero
sub getConfByNum {
my ( $self, $cfgNum, @args ) = @_;
unless ( %{ $self->currentConf }
and $cfgNum == $self->currentConf->{cfgNum} )
{
my $tmp;
if ( $cfgNum == 0 ) {
require Lemonldap::NG::Manager::Conf::Zero;
$tmp = Lemonldap::NG::Manager::Conf::Zero::zeroConf();
$self->currentConf($tmp);
}
else {
$tmp = $self->SUPER::getConfByNum( $cfgNum, @args );
return undef unless ( defined $tmp );
}
}
return $cfgNum;
$self->SUPER::getConfByNum( $cfgNum, @args );
}
sub diff {
my ( $self, $req, @path ) = @_;
return $self->sendError( $req, 'to many arguments in path info', 400 )
if (@path);
my @cfgNum =
( scalar( $req->param('conf1') ), scalar( $req->param('conf2') ) );
my @conf;
$self->logger->debug(" Loading confs");
# Load the 2 configurations
for ( my $i = 0 ; $i < 2 ; $i++ ) {
if ( %{ $self->currentConf }
and $cfgNum[$i] == $self->currentConf->{cfgNum} )
{
$conf[$i] = $self->currentConf;
}
else {
$conf[$i] = $self->confAcc->getConf(
{ cfgNum => $cfgNum[$i], raw => 1, noCache => 1 } );
return $self->sendError(
$req,
"Configuration $cfgNum[$i] not available $Lemonldap::NG::Common::Conf::msg",
400
) unless ( $conf[$i] );
}
}
require Lemonldap::NG::Manager::Conf::Diff;
return $self->sendJSONresponse(
$req,
[
$self->Lemonldap::NG::Manager::Conf::Diff::diff(
$conf[0], $conf[1]
)
]
);
$self->SUPER::diff( $req, @path );
}
1;

View File

@ -169,40 +169,7 @@ llapp.controller 'TreeCtrl', [
$scope.downloadConf = () ->
window.open $scope.viewPrefix + $scope.currentCfg.cfgNum + '?full=1'
# # Main save function
# $scope.save = ->
# $scope.showModal('save.html').then ->
# $scope.waiting = true
# $scope.data.push
# id: "cfgLog"
# title: "cfgLog"
# data: if $scope.result then $scope.result else ''
# $http.post("#{window.viewPrefix}?cfgNum=#{$scope.currentCfg.cfgNum}#{if $scope.forceSave then "&force=1" else ''}", $scope.data).then (response) ->
# $scope.data.pop()
# _checkSaveResponse response.data
# ,(response) ->
# readError response
# $scope.data.pop()
# , ->
# console.log 'Saving canceled'
# $scope.showM = false
#
# # Raw save function
# $scope.saveRawConf = ($fileContent) ->
# $scope.waiting = true
# $http.post("#{window.viewPrefix}/raw", $fileContent).then (response) ->
# _checkSaveResponse(response.data)
# , readError
#
# # Restore raw conffunction
# $scope.restore = ->
# $scope.currentNode = null
# $scope.form = 'restore'
#
# # Cancel save function
# $scope.cancel = ->
# $scope.currentNode.data = null
# $scope.getKey($scope.currentNode)
# NODES MANAGEMENT
id = 1
@ -219,203 +186,6 @@ llapp.controller 'TreeCtrl', [
cs = cs.$parentNodeScope
return cs
# # Add grant rule entry
# $scope.newGrantRule = ->
# node = $scope._findContainer()
# l = node.nodes.length
# n = if l > 0 then l - 1 else 0
# node.nodes.push
# id: "#{node.id}/n#{id++}"
# title: 'New rule'
# re: 'Message'
# comment: 'New rule'
# data: '1'
# type: "grant"
#
# # Add rules entry
# $scope.newRule = ->
# node = $scope._findContainer()
# l = node.nodes.length
# n = if l > 0 then l - 1 else 0
# node.nodes.splice n, 0,
# id: "#{node.id}/n#{id++}"
# title: 'New rule'
# re: '^/new'
# comment: 'New rule'
# data: 'accept'
# type: "rule"
#
# # Add form replay
# $scope.newPost = ->
# node = $scope._findContainer()
# node.nodes.push
# id: "#{node.id}/n#{id++}"
# title: "/absolute/path/to/form"
# data: {}
# type: "post"
#
# $scope.newPostVar = ->
# $scope.currentNode.data.vars = [] unless $scope.currentNode.data.vars?
# $scope.currentNode.data.vars.push ['var1', '$uid']
#
# # Add auth chain entry to authChoice
# $scope.newAuthChoice = ->
# node = $scope._findContainer()
# node.nodes.push
# id: "#{node.id}/n#{id++}"
# title: "1_Key"
# data: ['Null', 'Null', 'Null']
# type: "authChoice"
# $scope.execFilters $scope._findScopeByKey 'authParams'
#
# # Add hash entry
# $scope.newHashEntry = ->
# node = $scope._findContainer()
# node.nodes.push
# id: "#{node.id}/n#{id++}"
# title: 'new'
# data: ''
# type: "keyText"
#
# # Menu cat entry
# $scope.newCat = ->
# cs = $scope.currentScope
# if cs.$modelValue.type == 'menuApp'
# cs = cs.$parentNodeScope
# cs.$modelValue.nodes.push
# id: "#{cs.$modelValue.id}/n#{id++}"
# title: "New category"
# type: "menuCat"
# nodes: []
#
# # Menu app entry
# $scope.newApp = ->
# cs = $scope.currentScope
# if cs.$modelValue.type == 'menuApp'
# cs = cs.$parentNodeScope
# cs.$modelValue.nodes.push
# id: "#{cs.$modelValue.id}/n#{id++}"
# title: "New application"
# type: "menuApp"
# data:
# description: "New app description"
# uri: "https://test.example.com/"
# logo: "network.png"
# display: "auto"
#
# # Combination module
# $scope.newCmbMod = ->
# node = $scope._findContainer()
# node.nodes.push
# id: "#{node.id}/n#{id++}"
# title: 'new'
# type: 'cmbModule'
# data:
# type: 'LDAP'
# for: '0'
# over: []
# $scope.execFilters $scope._findScopeByKey 'authParams'
#
# $scope.newCmbOver = ->
# d = $scope.currentNode.data
# d.over = [] unless d.over
# d.over.push ["new#{id++}", '']
#
# $scope.newChoiceOver = ->
# d = $scope.currentNode.data
# console.log "data", d
# d[5] = [] unless d[5]
# d[5].push ["new#{id++}", '']
#
# # Add host
# $scope.addHost = () ->
# cn = $scope.currentNode
# cn.data=[] unless cn.data
# cn.data.push
# k: "newHost"
# h: [{"k":"key","v":"uid"}]
#
# # SAML attribute entry
# $scope.addSamlAttribute = ->
# node = $scope._findContainer()
# node.nodes.push
# id: "#{node.id}/n#{id++}"
# title: 'new'
# type: 'samlAttribute'
# data: ['0', 'New', '', '']
#
# # Nodes with template
# $scope.addVhost = ->
# name = if $scope.domain then ".#{$scope.domain.data}" else '.example.com'
# $scope.message =
# title: 'virtualHostName'
# field: 'hostname'
# $scope.showModal('prompt.html', name).then ->
# n= $scope.result
# if n
# $scope.addTemplateNode n, 'virtualHost'
#
# $scope.duplicateVhost = ->
# name = if $scope.domain then ".#{$scope.domain.data}" else '.example.com'
# $scope.message =
# title: 'virtualHostName',
# field: 'hostname'
# $scope.showModal('prompt.html', name).then ->
# n = $scope.result
# return $scope.duplicateNode n, 'virtualHost', $scope.currentNode.title
#
# $scope.addSamlIDP = ->
# $scope.newTemplateNode 'samlIDPMetaDataNode', 'samlPartnerName', 'idp-example'
#
# $scope.addSamlSP = ->
# $scope.newTemplateNode 'samlSPMetaDataNode', 'samlPartnerName', 'sp-example'
#
# $scope.addOidcOp = ->
# $scope.newTemplateNode 'oidcOPMetaDataNode', 'oidcOPName', 'op-example'
#
# $scope.addOidcRp = ->
# $scope.newTemplateNode 'oidcRPMetaDataNode', 'oidcRPName', 'rp-example'
#
# $scope.addCasSrv = ->
# $scope.newTemplateNode 'casSrvMetaDataNode', 'casPartnerName', 'srv-example'
#
# $scope.addCasApp = ->
# $scope.newTemplateNode 'casAppMetaDataNode', 'casPartnerName', 'app-example'
#
# $scope.newTemplateNode = (type, title, init) ->
# $scope.message =
# title: title
# field: 'name'
# $scope.showModal('prompt.html', init).then ->
# name = $scope.result
# if (name)
# $scope.addTemplateNode name, type
#
# $scope.addTemplateNode = (name, type) ->
# cs = $scope.currentScope
# while cs.$modelValue.title != "#{type}s"
# cs = cs.$parentNodeScope
# t =
# id: "#{type}s/new__#{name}"
# title: name
# type: type
# nodes: templates type, "new__#{name}"
# setDefault t.nodes
# cs.$modelValue.nodes.push t
# cs.expand()
# return t
# setDefault = (node) ->
# for n in node
# if n.cnodes and n.default
# delete n.cnodes
# n._nodes = n.default
# if n._nodes
# setDefault n._nodes
# else if n.default or n.default == 0
# n.data = n.default
# node
_getAll = (node) ->
d = $q.defer()
d2 = $q.defer()
@ -439,25 +209,6 @@ llapp.controller 'TreeCtrl', [
d2.resolve()
return d2.promise
# $scope.duplicateNode = (name, type, idkey) ->
# cs = $scope.currentScope
# _getAll($scope.currentNode).then ->
# while cs.$modelValue.title != "#{type}s"
# cs = cs.$parentNodeScope
# t = JSON.parse JSON.stringify($scope.currentNode).replace(new RegExp(idkey, 'g'), 'new__' + name)
# t.id = "#{type}s/new__#{name}"
# t.title = name
# cs.$modelValue.nodes.push(t)
# return t
# $scope.del = (a, i) ->
# a.splice(i, 1)
# $scope.deleteEntry = ->
# p = $scope.currentScope.$parentNodeScope
# $scope.currentScope.remove()
# $scope.displayForm p
$scope.down = ->
id = $scope.currentNode.id
p = $scope.currentScope.$parentNodeScope.$modelValue
@ -577,16 +328,6 @@ llapp.controller 'TreeCtrl', [
scope = scope.$parentNodeScope
$scope.helpUrl = scope.$modelValue.help || 'start.html#configuration'
# Form management
#
# `currentNode` contains the last select node
#
# method `diplayForm()`:
# - set the `form` property to the name of the form to download
# (`text` by default or `home` for node without `type` property)
# - launch getKeys to set `node.data`
# - hide tree when in XS size
#
$scope.displayForm = (scope) ->
node = scope.$modelValue
if node.cnodes
@ -608,45 +349,6 @@ llapp.controller 'TreeCtrl', [
$scope.showT = false
setHelp scope
# $scope.keyWritable = (scope) ->
# node = scope.$modelValue
# # regexp-assemble of:
# # authChoice
# # keyText
# # cmbModule
# # virtualHost
# # rule
# # menuCat
# # menuApp
# # samlAttribute
# # samlIDPMetaDataNode
# # samlSPMetaDataNode
# return if node.type and node.type.match /^(?:(?:saml(?:(?:ID|S)PMetaDataNod|Attribut)|(?:cmbMod|r)ul|authChoic)e|(?:virtualHos|keyTex)t|menu(?:App|Cat))$/ then true else false
#
# RSA keys generation
# $scope.newRSAKey = ->
# $scope.showModal('password.html').then ->
# $scope.waiting = true
# currentNode = $scope.currentNode
# password = $scope.result
# $http.post("#{window.viewPrefix}/newRSAKey", {"password": password}).then (response) ->
# currentNode.data[0].data = response.data.private
# currentNode.data[1].data = password
# currentNode.data[2].data = response.data.public
# $scope.waiting = false
# , readError
# , ->
# console.log('New key cancelled')
# $scope.newRSAKeyNoPassword = ->
# $scope.waiting = true
# currentNode = $scope.currentNode
# $http.post("#{window.viewPrefix}/newRSAKey", {"password": ''}).then (response) ->
# currentNode.data[0].data = response.data.private
# currentNode.data[1].data = response.data.public
# $scope.waiting = false
# , readError
# method `getKey()`:
# - return a promise with the data:
# - from node when set
@ -771,23 +473,4 @@ llapp.controller 'TreeCtrl', [
console.log "Redirecting to /view/latest"
$location.path '/view/latest'
# File form function
#$scope.replaceContentByUrl = (node, url) ->
# $scope.waiting = true
# $http.post(window.scriptname + "prx", {url: url}).then (response) ->
# node.data = response.data.content
# $scope.waiting = false
# , readError
#$scope.replaceContent = (node, $fileContent) ->
# node.data = $fileContent
## Import Filesaver.js saveAs()
#$scope.saveAs = (content, type, filename) ->
# saveAs(new Blob([content], {"type": type}), filename)
## Save as pem, text,...
#$scope.saveAsPem = (cs,scope) ->
# scope.saveAs "#{cs.data[0].data}\n#{cs.data[2].data}", 'application/x-pem-file', "#{cs.title}.pem"
#$scope.saveAsText = (cs,scope) ->
# scope.saveAs cs.data, 'text/plain', "#{cs.title}.txt"
]

View File

@ -1,10 +1,14 @@
<div class="panel panel-default">
<div class="panel-heading">
<TMPL_IF NAME="ALLOWDIFF">
<h3 class="panel-title">
<span ng-if="!currentCfg.next" trspan="currentConfiguration"></span>
<span ng-if="currentCfg.next" trspan="loadedConfiguration"></span>
<i ng-if="currentCfg.prev">(<a trspan="diffWithPrevious" target="_blank" href="{{scriptname}}/diff.html#!/{{currentCfg.cfgNum}}" role="link"></a>)</i>
</h3>
</TMPL_IF>
</div>
<table class="table table-striped">
<tr>

View File

@ -22,17 +22,15 @@
<div class="navbar-collapse" ng-class="{'collapse':!showM}" id="formmenu">
<ul class="nav navbar-nav">
<li><a class="link" ng-click="home()"><i class="glyphicon glyphicon-home"></i></a></li>
<!--
<li>
<a id="save" class="link" ng-click="save()" tabIndex="-1">
<i class="glyphicon glyphicon-cloud-upload"></i>
{{translate('save')}}
</a>
</li>
<li >
<input id="forcesave" type="checkbox" ng-model="forceSave" uib-tooltip="{{translate('forceSave')}}" tooltip-placement="right" ng-show="confirmNeeded||currentCfg.next" role="checkbox" aria-label="Force save">
</li>
-->
<TMPL_IF NAME="ALLOWDIFF">
<li uib-dropdown>
<a id="navmenu" name="menu" uib-dropdown-toggle data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><i class="glyphicon glyphicon-cog"></i> {{translate('browse')}} <span class="caret"></span></a>
<ul uib-dropdown-menu aria-labelled-by="navmenu">
@ -41,6 +39,9 @@
<li><a class="link" ng-click="getCfg('latest')" title="Latest configuration"><i class="glyphicon glyphicon-refresh"></i> {{translate('latest')}}</a></li>
</ul>
</li>
</TMPL_IF>
<li><a class="link hidden-xs" ng-click="setShowHelp()"><i class="glyphicon" ng-class="{'glyphicon-eye-close': showH,'glyphicon-eye-open': !showH}" ></i> {{ translate((showH ? 'hideHelp' : 'showHelp')) }}</a></li>
<!--
<li ng-repeat="button in menu()" ng-include="'menubutton.html'"></li>
@ -52,6 +53,12 @@
<li ng-repeat="menulink in menulinks"><a href="{{menulink.target}}" role="row"><i ng-if="menulink.icon" class="glyphicon glyphicon-{{menulink.icon}}"></i> {{translate(menulink.title)}}</a></li>
<li ng-include="'languages.html'"></li>
</ul>
</li>
<li>
<i class="glyphicon glyphicon-lock"></i>
<u>{{translate('You are on Read-Only mode')}}</u>
</li>
</ul>
</div>

View File

@ -47,6 +47,8 @@ my @notManagedAttributes = (
# Loggers
'log4perlConfFile', 'userSyslogFacility', 'logger', 'sentryDsn',
'syslogFacility', 'userLogger', 'logLevel',
# Viewer
'viewerHiddenPK', 'viewerAllowDiff',
# Other ini-only prms
'configStorage', 'status', 'localStorageOptions', 'localStorage',