Merge branch 'master' into feature/namespaced-controllers-5786
Conflicts: library/Icinga/Application/Web.php
This commit is contained in:
commit
392eee5a1f
|
@ -1,5 +1,11 @@
|
|||
# Exclude files related to git when generating an archive
|
||||
.git* export-ignore
|
||||
# Exclude Vagrant and Puppet related files when generating an archive
|
||||
.puppet* export-ignore
|
||||
Vagrantfile export-ignore
|
||||
|
||||
# Normalize puppet manifests' line endings to LF on checkin and prevent conversion to CRLF when the files are checked out
|
||||
.puppet* eol=lf
|
||||
|
||||
# Include version information on `git archive'
|
||||
/application/VERSION export-subst
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
<alexander.klimov@netways.de> <Alexander.Klimov@netways.de>
|
||||
<carloscesario@gmail.com> <ccesario@tecnomega.com.br>
|
||||
<christopher.ruell@netways.de> <Christopher.Ruell@netways.de>
|
||||
<gunnar.beutner@netways.de> <gunnar@beutner.name>
|
||||
Jannis Moßhammer <jannis.mosshammer@netways.de>
|
||||
<matthias.jentsch@netways.de> <mjentsch@localhost.int.netways.de>
|
||||
<michael.friedrich@netways.de> <Michael.Friedrich@netways.de>
|
||||
<michael.friedrich@netways.de> <michael.friedrich@gmail.com>
|
||||
<thomas.gelf@netways.de> <thomas@gelf.net>
|
||||
Thomas Gelf <thomas.gelf@netways.de> <root@squeeze-devel1.osmc.lab>
|
||||
Thomas Gelf <thomas.gelf@netways.de> <tgelf@tgelf-web2dep.(none)>
|
||||
Sylph Lin <sylph.lin@gmail.com>
|
|
@ -1,7 +1,8 @@
|
|||
---
|
||||
icingaweb2::config: /etc/icingaweb
|
||||
icingaweb2::log: /var/log/icingaweb/icingaweb.log
|
||||
icingaweb2::web_path: icingaweb
|
||||
icingaweb2::db_user: icingaweb
|
||||
icingaweb2::db_pass: icingaweb
|
||||
icingaweb2::db_name: icingaweb
|
||||
icingaweb2::config: /etc/icingaweb2
|
||||
icingaweb2::log: /var/log/icingaweb2/icingaweb2.log
|
||||
icingaweb2::web_path: icingaweb2
|
||||
icingaweb2::db_user: icingaweb2
|
||||
icingaweb2::db_pass: icingaweb2
|
||||
icingaweb2::db_name: icingaweb2
|
||||
icingaweb2::group: icingaweb2
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
set -e
|
||||
|
||||
if which puppet >/dev/null 2>&1; then
|
||||
exit 0
|
||||
exit 0
|
||||
fi
|
||||
|
||||
RELEASEVER=$(rpm -q --qf "%{VERSION}" $(rpm -q --whatprovides redhat-release))
|
||||
|
@ -20,7 +20,7 @@ esac
|
|||
|
||||
echo "Adding puppet repository.."
|
||||
rpm --import "https://yum.puppetlabs.com/RPM-GPG-KEY-puppetlabs"
|
||||
rpm -ivh $PUPPET >/dev/null
|
||||
rpm -Uvh $PUPPET >/dev/null
|
||||
|
||||
echo "Installing puppet.."
|
||||
yum install -y puppet >/dev/null
|
||||
|
|
|
@ -12,4 +12,6 @@ node default {
|
|||
file { '/etc/profile.d/env.sh':
|
||||
source => 'puppet:////vagrant/.puppet/files/etc/profile.d/env.sh'
|
||||
}
|
||||
@user { vagrant: ensure => present }
|
||||
User <| title == vagrant |> { groups +> hiera('icingaweb2::group') }
|
||||
}
|
||||
|
|
|
@ -15,10 +15,10 @@
|
|||
class epel {
|
||||
|
||||
yumrepo { 'epel':
|
||||
mirrorlist => "http://mirrors.fedoraproject.org/mirrorlist?repo=epel-6&arch=${::architecture}",
|
||||
mirrorlist => "http://mirrors.fedoraproject.org/mirrorlist?repo=epel-${::operatingsystemmajrelease}&arch=${::architecture}",
|
||||
enabled => '1',
|
||||
gpgcheck => '0',
|
||||
descr => "Extra Packages for Enterprise Linux 6 - ${::architecture}"
|
||||
descr => "Extra Packages for Enterprise Linux ${::operatingsystemmajrelease} - ${::architecture}"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,29 +10,22 @@
|
|||
#
|
||||
# icinga2::feature { 'example-feature'; }
|
||||
#
|
||||
define icinga2::feature ($source = undef) {
|
||||
define icinga2::feature ($ensure = 'present') {
|
||||
include icinga2
|
||||
|
||||
$target = "features-available/${name}"
|
||||
$cfgpath = '/etc/icinga2'
|
||||
$path = "${cfgpath}/features-enabled/${name}.conf"
|
||||
|
||||
if $source != undef {
|
||||
icinga2::config { $target:
|
||||
source => $source,
|
||||
}
|
||||
$action = $ensure ? {
|
||||
/(present)/ => 'enable',
|
||||
/(absent)/ => 'disable',
|
||||
}
|
||||
$test = $ensure ? {
|
||||
/(present)/ => '-e',
|
||||
/(absent)/ => '! -e',
|
||||
}
|
||||
|
||||
parent_dirs { $path:
|
||||
user => 'icinga',
|
||||
require => [
|
||||
User['icinga'],
|
||||
File['icinga2cfgDir']
|
||||
],
|
||||
}
|
||||
-> file { $path:
|
||||
ensure => link,
|
||||
target => "${cfgpath}/${target}.conf",
|
||||
exec { "icinga2-feature-${action}-${name}":
|
||||
unless => "/usr/bin/test ${test} /etc/icinga2/features-enabled/${name}.conf",
|
||||
command => "/usr/sbin/icinga2 feature ${action} ${name}",
|
||||
require => Package['icinga2'],
|
||||
notify => Service['icinga2'],
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ class icinga2 {
|
|||
include icinga_packages
|
||||
|
||||
package { [
|
||||
'icinga2', 'icinga2-doc', 'icinga2-debuginfo'
|
||||
'icinga2', 'icinga2-doc'
|
||||
]:
|
||||
ensure => latest,
|
||||
require => Class['icinga_packages'],
|
||||
|
@ -35,7 +35,7 @@ class icinga2 {
|
|||
links => follow,
|
||||
owner => 'icinga',
|
||||
group => 'icinga',
|
||||
mode => 6750,
|
||||
mode => '6750',
|
||||
}
|
||||
|
||||
icinga2::feature { [ 'statusdata', 'command', 'compatlog' ]: }
|
||||
|
|
|
@ -28,7 +28,8 @@ class icinga2_mysql {
|
|||
privileges => 'SELECT,INSERT,UPDATE,DELETE',
|
||||
schemafile => '/usr/share/icinga2-ido-mysql/schema/mysql.sql',
|
||||
}
|
||||
-> icinga2::feature { 'ido-mysql':
|
||||
-> icinga2::config { 'features-available/ido-mysql':
|
||||
source => 'puppet:///modules/icinga2_mysql',
|
||||
}
|
||||
-> icinga2::feature { 'ido-mysql': }
|
||||
}
|
||||
|
|
|
@ -11,7 +11,8 @@ class icinga2_pgsql {
|
|||
password => 'icinga2',
|
||||
schemafile => '/usr/share/icinga2-ido-pgsql/schema/pgsql.sql',
|
||||
}
|
||||
-> icinga2::feature { 'ido-pgsql':
|
||||
source => 'puppet:///modules/icinga2_pgsql',
|
||||
}
|
||||
# Because Icinga 2 does not handle more than one IDO connection properly, The ido-pgsql will not be enabled by default.
|
||||
# -> icinga2::feature { 'ido-pgsql':
|
||||
# source => 'puppet:///modules/icinga2_pgsql',
|
||||
# }
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#
|
||||
class icinga_packages {
|
||||
yumrepo { 'icinga_packages':
|
||||
baseurl => 'http://packages.icinga.org/epel/6/snapshot/',
|
||||
baseurl => "http://packages.icinga.org/epel/${::operatingsystemmajrelease}/snapshot/",
|
||||
enabled => '1',
|
||||
gpgcheck => '1',
|
||||
gpgkey => 'http://packages.icinga.org/icinga.key',
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
class icingaweb2::config (
|
||||
$config = hiera('icingaweb2::config')
|
||||
$config = hiera('icingaweb2::config'),
|
||||
$web_group = hiera('icingaweb2::group')
|
||||
) {
|
||||
group { 'icingaweb':
|
||||
group { $web_group:
|
||||
ensure => present,
|
||||
}
|
||||
|
||||
file { [ "${config}", "${config}/enabledModules", "${config}/modules", "${config}/preferences" ]:
|
||||
ensure => directory,
|
||||
owner => 'root',
|
||||
group => 'icingaweb',
|
||||
group => $web_group,
|
||||
mode => '2770',
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,21 @@
|
|||
define icingaweb2::config::general (
|
||||
$source,
|
||||
$config = hiera('icingaweb2::config'),
|
||||
$replace = true
|
||||
$config = hiera('icingaweb2::config'),
|
||||
$log = hiera('icingaweb2::log'),
|
||||
$web_path = hiera('icingaweb2::web_path'),
|
||||
$db_user = hiera('icingaweb2::db_user'),
|
||||
$db_pass = hiera('icingaweb2::db_pass'),
|
||||
$db_name = hiera('icingaweb2::db_name'),
|
||||
$web_group = hiera('icingaweb2::group'),
|
||||
$replace = true
|
||||
) {
|
||||
include icingaweb2::config
|
||||
|
||||
file { "${config}/${name}.ini":
|
||||
content => template("${source}/${name}.ini.erb"),
|
||||
owner => 'root',
|
||||
group => 'icingaweb',
|
||||
mode => 0660,
|
||||
group => $web_group,
|
||||
mode => '0660',
|
||||
replace => $replace,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
define icingaweb2::config::module (
|
||||
$module,
|
||||
$source,
|
||||
$config = hiera('icingaweb2::config'),
|
||||
$replace = true
|
||||
$config = hiera('icingaweb2::config'),
|
||||
$web_group = hiera('icingaweb2::group'),
|
||||
$replace = true
|
||||
) {
|
||||
include icingaweb2::config
|
||||
|
||||
|
@ -10,7 +11,7 @@ define icingaweb2::config::module (
|
|||
file { "${config}/modules/${module}":
|
||||
ensure => directory,
|
||||
owner => 'root',
|
||||
group => 'icingaweb',
|
||||
group => $web_group,
|
||||
mode => '2770',
|
||||
}
|
||||
}
|
||||
|
@ -18,8 +19,8 @@ define icingaweb2::config::module (
|
|||
file { "${config}/modules/${module}/${name}.ini":
|
||||
source => "${source}/modules/${module}/${name}.ini",
|
||||
owner => 'root',
|
||||
group => 'icingaweb',
|
||||
mode => 0660,
|
||||
group => $web_group,
|
||||
mode => '0660',
|
||||
replace => $replace,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Class: mysql
|
||||
#
|
||||
# This class installs the mysql server and client software.
|
||||
# This class installs the MySQL server and client software on a RHEL or CentOS
|
||||
#
|
||||
# Parameters:
|
||||
#
|
||||
|
@ -16,21 +16,39 @@ class mysql {
|
|||
|
||||
Exec { path => '/usr/bin' }
|
||||
|
||||
if versioncmp($::operatingsystemmajrelease, '7') >= 0 {
|
||||
$client_package_name = 'mariadb'
|
||||
$server_package_name = 'mariadb-server'
|
||||
$server_service_name = 'mariadb'
|
||||
$cnf = '/etc/my.cnf.d/server.cnf'
|
||||
$log_error = '/var/log/mariadb/mariadb.log'
|
||||
$pid_file = '/var/run/mariadb/mariadb.pid'
|
||||
} else {
|
||||
$client_package_name = 'mysql'
|
||||
$server_package_name = 'mysql-server'
|
||||
$server_service_name = 'mysqld'
|
||||
$cnf = '/etc/my.cnf'
|
||||
$log_error = '/var/log/mysqld.log'
|
||||
$pid_file = '/var/run/mysqld/mysqld.pid'
|
||||
}
|
||||
|
||||
package { [
|
||||
'mysql', 'mysql-server'
|
||||
$client_package_name, $server_package_name,
|
||||
]:
|
||||
ensure => latest,
|
||||
}
|
||||
|
||||
service { 'mysqld':
|
||||
ensure => running,
|
||||
service { $server_service_name:
|
||||
alias => 'mysqld',
|
||||
enable => true,
|
||||
require => Package['mysql-server']
|
||||
ensure => running,
|
||||
require => Package[$server_package_name],
|
||||
}
|
||||
|
||||
file { '/etc/my.cnf':
|
||||
file { $cnf:
|
||||
content => template('mysql/my.cnf.erb'),
|
||||
require => Package['mysql-server'],
|
||||
notify => Service['mysqld']
|
||||
notify => Service['mysqld'],
|
||||
recurse => true,
|
||||
require => Package[$server_package_name],
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,8 +104,8 @@ innodb_file_per_table
|
|||
innodb_log_file_size = 64M
|
||||
|
||||
[mysqld_safe]
|
||||
log-error=/var/log/mysqld.log
|
||||
pid-file=/var/run/mysqld/mysqld.pid
|
||||
log-error=<%= @log_error %>
|
||||
pid-file=<%= @pid_file %>
|
||||
|
||||
# Increase the amount of open files allowed per process. Warning: Make
|
||||
# sure you have set the global system limit high enough! The high value
|
||||
|
|
|
@ -20,6 +20,15 @@ class openldap {
|
|||
|
||||
service { 'slapd':
|
||||
ensure => running,
|
||||
require => Package['openldap-servers']
|
||||
require => Package['openldap-servers'],
|
||||
}
|
||||
|
||||
if versioncmp($::operatingsystemmajrelease, '7') >= 0 {
|
||||
openldap::schema{ 'core': }
|
||||
-> openldap::schema{ 'cosine': }
|
||||
-> openldap::schema{ 'inetorgperson': }
|
||||
-> openldap::schema{ 'nis': }
|
||||
-> openldap::schema{ 'misc': }
|
||||
-> openldap::schema{ 'openldap': }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
# define: openldap::schema
|
||||
#
|
||||
# Install a schema.
|
||||
#
|
||||
# Parameters:
|
||||
#
|
||||
# Actions:
|
||||
#
|
||||
# Requires:
|
||||
#
|
||||
# Sample Usage:
|
||||
#
|
||||
define openldap::schema {
|
||||
|
||||
include openldap
|
||||
|
||||
exec { "openldap-schema-${name}":
|
||||
command => "ldapadd -Y EXTERNAL -H ldapi:// -f /etc/openldap/schema/${name}.ldif",
|
||||
group => 'root',
|
||||
require => Service['slapd'],
|
||||
unless => "test -n \"$(find /etc/openldap/slapd.d/cn=config/cn=schema/ -name cn={*}${name}.ldif -print -quit)\"",
|
||||
user => 'root',
|
||||
}
|
||||
}
|
|
@ -25,7 +25,7 @@ define pgsql::database::create ($username, $password) {
|
|||
unless => "psql -tAc \"SELECT 1 FROM pg_roles WHERE rolname='${username}'\" | grep -q 1",
|
||||
command => "psql -c \"CREATE ROLE ${username} WITH LOGIN PASSWORD '${password}';\" && \
|
||||
createdb -O ${username} -E UTF8 -T template0 ${name} && \
|
||||
createlang plpgsql ${name}",
|
||||
(createlang plpgsql ${name} || true)",
|
||||
user => 'postgres',
|
||||
require => Class['pgsql']
|
||||
}
|
||||
|
|
|
@ -71,6 +71,11 @@ local icinga icinga trust
|
|||
host icinga icinga 127.0.0.1/32 trust
|
||||
host icinga icinga ::1/128 trust
|
||||
|
||||
# icinga2
|
||||
local icinga2 icinga2 trust
|
||||
host icinga2 icinga2 127.0.0.1/32 trust
|
||||
host icinga2 icinga2 ::1/128 trust
|
||||
|
||||
# icinga_unittest
|
||||
local icinga_unittest icinga_unittest trust
|
||||
host icinga_unittest icinga_unittest 127.0.0.1/32 trust
|
||||
|
@ -81,6 +86,11 @@ local icingaweb icingaweb trust
|
|||
host icingaweb icingaweb 127.0.0.1/32 trust
|
||||
host icingaweb icingaweb ::1/128 trust
|
||||
|
||||
# icingaweb2
|
||||
local <%= scope.function_hiera(['icingaweb2::db_user']) %> <%= scope.function_hiera(['icingaweb2::db_user']) %> trust
|
||||
host <%= scope.function_hiera(['icingaweb2::db_user']) %> <%= scope.function_hiera(['icingaweb2::db_user']) %> 127.0.0.1/32 trust
|
||||
host <%= scope.function_hiera(['icingaweb2::db_user']) %> <%= scope.function_hiera(['icingaweb2::db_user']) %> ::1/128 trust
|
||||
|
||||
# "local" is for Unix domain socket connections only
|
||||
local all all ident
|
||||
# IPv4 local connections:
|
||||
|
|
|
@ -20,24 +20,9 @@ class php {
|
|||
|
||||
package { 'php':
|
||||
ensure => latest,
|
||||
require => Package['apache'],
|
||||
notify => Service['apache']
|
||||
}
|
||||
# TODO(el): Always executed. Should be a resource
|
||||
-> exec { 'php-timezone':
|
||||
command => 'sed -re $\'s#^;?(date\\.timezone =).*$#\\1 "UTC"#\' -i /etc/php.ini',
|
||||
notify => Service['apache'],
|
||||
require => Package['apache'],
|
||||
}
|
||||
|
||||
file { '/etc/php.d/error_reporting.ini':
|
||||
content => template('php/error_reporting.ini.erb'),
|
||||
require => Package['php'],
|
||||
notify => Service['apache']
|
||||
}
|
||||
|
||||
file { '/etc/php.d/xdebug_settings.ini':
|
||||
content => template('php/xdebug_settings.ini.erb'),
|
||||
require => Package['php'],
|
||||
notify => Service['apache']
|
||||
}
|
||||
php::phpd { ['error_reporting', 'timezone', 'xdebug_settings' ]: }
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
# define: php::phpd
|
||||
#
|
||||
# Provision php.d config
|
||||
#
|
||||
# Parameters:
|
||||
#
|
||||
# Actions:
|
||||
#
|
||||
# Requires:
|
||||
#
|
||||
# Sample Usage:
|
||||
#
|
||||
define php::phpd {
|
||||
|
||||
include php
|
||||
|
||||
file { "/etc/php.d/$name.ini":
|
||||
content => template("php/$name.ini.erb"),
|
||||
notify => Service['apache'],
|
||||
require => Package['php'],
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
date.timezone = "UTC"
|
|
@ -0,0 +1,29 @@
|
|||
# Class: php_imagick
|
||||
#
|
||||
# This class installs the ImageMagick PHP module.
|
||||
#
|
||||
# Parameters:
|
||||
#
|
||||
# Actions:
|
||||
#
|
||||
# Requires:
|
||||
#
|
||||
# php
|
||||
#
|
||||
# Sample Usage:
|
||||
#
|
||||
# include php_imagick
|
||||
#
|
||||
class php_imagick {
|
||||
include php
|
||||
|
||||
$php_imagick = $::operatingsystem ? {
|
||||
/(Debian|Ubuntu)/ => 'php5-imagick',
|
||||
/(RedHat|CentOS|Fedora)/ => 'php-pecl-imagick',
|
||||
/(SLES|OpenSuSE)/ => 'php5-imagick',
|
||||
}
|
||||
|
||||
package { $php_imagick:
|
||||
ensure => latest,
|
||||
}
|
||||
}
|
|
@ -1,11 +1,12 @@
|
|||
# Class: icinga2_dev
|
||||
#
|
||||
# This class installs Icinga 2 w/ MySQL and provides Icinga 2 test configuration.
|
||||
# This class installs Icinga 2 w/ MySQL and PostgreSQL and provides Icinga 2 test configuration.
|
||||
#
|
||||
# Requires:
|
||||
#
|
||||
# icinga2_mysql
|
||||
# icinga2::config
|
||||
# icinga2::feature
|
||||
#
|
||||
# Sample Usage:
|
||||
#
|
||||
|
@ -18,7 +19,17 @@ class icinga2_dev {
|
|||
include monitoring_test_config
|
||||
|
||||
icinga2::config { [
|
||||
'conf.d/test-config', 'conf.d/commands', 'constants' ]:
|
||||
'conf.d/test-config', 'conf.d/commands', 'constants'
|
||||
]:
|
||||
source => 'puppet:///modules/icinga2_dev',
|
||||
}
|
||||
|
||||
icinga2::feature { 'api':
|
||||
ensure => absent,
|
||||
}
|
||||
|
||||
icinga2::feature { 'ido-pgsql':
|
||||
ensure => absent,
|
||||
require => Class['icinga2_pgsql'],
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ olcRootPW: {SSHA}N/2WMqT8q7cElh7KUQz+p9TJbjmKv/u9
|
|||
replace: olcRootDN
|
||||
olcRootDN: cn=admin,cn=config
|
||||
|
||||
dn: olcDatabase={2}bdb,cn=config
|
||||
dn: olcDatabase={2}hdb,cn=config
|
||||
changetype: modify
|
||||
replace: olcRootPW
|
||||
olcRootPW: {SSHA}MxMpLBo2/TSymoIBf/Sb5iQac7Wwiur5
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
class icingaweb2_dev (
|
||||
$config = hiera('icingaweb2::config'),
|
||||
$log = hiera('icingaweb2::log'),
|
||||
$web_path = hiera('icingaweb2::web_path'),
|
||||
$db_user = hiera('icingaweb2::db_user'),
|
||||
$db_pass = hiera('icingaweb2::db_pass'),
|
||||
$db_name = hiera('icingaweb2::db_name'),
|
||||
$config = hiera('icingaweb2::config'),
|
||||
$log = hiera('icingaweb2::log'),
|
||||
$web_path = hiera('icingaweb2::web_path'),
|
||||
$db_user = hiera('icingaweb2::db_user'),
|
||||
$db_pass = hiera('icingaweb2::db_pass'),
|
||||
$db_name = hiera('icingaweb2::db_name'),
|
||||
$web_group = hiera('icingaweb2::group'),
|
||||
) {
|
||||
include apache
|
||||
include php
|
||||
include php_imagick
|
||||
include icingaweb2::config
|
||||
include icingacli
|
||||
include icinga_packages
|
||||
|
@ -19,7 +21,7 @@ class icingaweb2_dev (
|
|||
}
|
||||
|
||||
# TODO(el): icinga-gui is not a icingaweb2_dev package
|
||||
package { [ 'php-pdo', 'php-ldap', 'php-phpunit-PHPUnit', 'icinga-gui' ]:
|
||||
package { [ 'php-gd', 'php-intl', 'php-pdo', 'php-ldap', 'php-phpunit-PHPUnit', 'icinga-gui' ]:
|
||||
ensure => latest,
|
||||
notify => Service['apache'],
|
||||
require => Class['icinga_packages'],
|
||||
|
@ -28,7 +30,7 @@ class icingaweb2_dev (
|
|||
Exec { path => '/usr/local/bin:/usr/bin:/bin' }
|
||||
|
||||
# TODO(el): Enabling/disabling modules should be a resource
|
||||
User <| alias == apache |> { groups +> 'icingaweb' }
|
||||
User <| alias == apache |> { groups +> $web_group }
|
||||
-> exec { 'enable-monitoring-module':
|
||||
command => 'icingacli module enable monitoring',
|
||||
user => 'apache',
|
||||
|
@ -50,7 +52,7 @@ class icingaweb2_dev (
|
|||
file { $log_dir:
|
||||
ensure => directory,
|
||||
owner => 'root',
|
||||
group => 'icingaweb',
|
||||
group => $web_group,
|
||||
mode => '2775'
|
||||
}
|
||||
|
||||
|
@ -88,7 +90,7 @@ class icingaweb2_dev (
|
|||
source => $name,
|
||||
}
|
||||
|
||||
icingaweb2::config::general { [ 'config', 'resources' ]:
|
||||
icingaweb2::config::general { [ 'config', 'resources', 'roles' ]:
|
||||
source => $name,
|
||||
replace => false,
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[autologin]
|
||||
backend = autologin
|
||||
backend = external
|
||||
|
||||
[icingaweb-mysql]
|
||||
backend = db
|
||||
|
|
|
@ -1,23 +1,38 @@
|
|||
Alias /<%= @web_path %> /vagrant/public
|
||||
Alias /<%= @web_path %> "/vagrant/public"
|
||||
|
||||
<Directory "/vagrant/public/">
|
||||
Options FollowSymLinks
|
||||
<Directory "/vagrant/public">
|
||||
Options SymLinksIfOwnerMatch
|
||||
AllowOverride None
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
|
||||
# SetEnv ICINGAWEB_CONFIGDIR <%= @config %>
|
||||
<IfModule mod_authz_core.c>
|
||||
# Apache 2.4
|
||||
<RequireAll>
|
||||
Require all granted
|
||||
</RequireAll>
|
||||
</IfModule>
|
||||
|
||||
<IfModule !mod_authz_core.c>
|
||||
# Apache 2.2
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
</IfModule>
|
||||
|
||||
SetEnv ICINGAWEB_CONFIGDIR <%= @config %>
|
||||
|
||||
EnableSendfile Off
|
||||
|
||||
RewriteEngine on
|
||||
RewriteBase /<%= @web_path %>/
|
||||
RewriteCond %{REQUEST_FILENAME} -s [OR]
|
||||
RewriteCond %{REQUEST_FILENAME} -l [OR]
|
||||
RewriteCond %{REQUEST_FILENAME} -d
|
||||
RewriteRule ^.*$ - [NC,L]
|
||||
RewriteRule ^.*$ index.php [NC,L]
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine on
|
||||
RewriteBase /<%= @web_path %>/
|
||||
RewriteCond %{REQUEST_FILENAME} -s [OR]
|
||||
RewriteCond %{REQUEST_FILENAME} -l [OR]
|
||||
RewriteCond %{REQUEST_FILENAME} -d
|
||||
RewriteRule ^.*$ - [NC,L]
|
||||
RewriteRule ^.*$ index.php [NC,L]
|
||||
</IfModule>
|
||||
|
||||
php_value xdebug.idekey PHPSTORM
|
||||
<IfModule !mod_rewrite.c>
|
||||
DirectoryIndex error_norewrite.html
|
||||
ErrorDocument 404 /error_norewrite.html
|
||||
</IfModule>
|
||||
</Directory>
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
[admins]
|
||||
users = icingaadmin
|
||||
permissions = *
|
|
@ -0,0 +1,32 @@
|
|||
Alexander A. Klimov <alexander.klimov@netways.de>
|
||||
Alexander Fuhr <alexander.fuhr@netways.de>
|
||||
ayoubabid <ayoubabid@users.noreply.github.com>
|
||||
baufrecht <baufrecht@users.noreply.github.com>
|
||||
Bence Nagy <bence@underyx.me>
|
||||
Bernd Erk <bernd.erk@icinga.org>
|
||||
Boden Garman <boden.garman@spintel.net.au>
|
||||
Carlos Cesario <carloscesario@gmail.com>
|
||||
Chris Rüll <christopher.ruell@netways.de>
|
||||
Daniel Shirley <aditaa@ig2ad.com>
|
||||
Davide Demuru <davide.demuru@buongiorno.com>
|
||||
Eric Lippmann <eric.lippmann@netways.de>
|
||||
Goran Rakic <grakic@devbase.net>
|
||||
Gunnar Beutner <gunnar.beutner@netways.de>
|
||||
Jannis Moßhammer <jannis.mosshammer@netways.de>
|
||||
Johannes Meyer <johannes.meyer@netways.de>
|
||||
Louis Sautier <sautier.louis@gmail.com>
|
||||
Marcus Cobden <marcus@marcuscobden.co.uk>
|
||||
Marius Hein <marius.hein@netways.de>
|
||||
Markus Frosch <markus@lazyfrosch.de>
|
||||
Matthias Jentsch <matthias.jentsch@netways.de>
|
||||
Michael Friedrich <michael.friedrich@netways.de>
|
||||
Paul Richards <paul@minimoo.org>
|
||||
rbelinsky <rbelinsky@dalet.com>
|
||||
Rene Moser <rene.moser@swisstxt.ch>
|
||||
rkcpi <thieme.sandra@gmail.com>
|
||||
Susanne Vestner-Ludwig <susanne.vestner-ludwig@inserteffect.com>
|
||||
Sylph Lin <sylph.lin@gmail.com>
|
||||
Thomas Gelf <thomas.gelf@netways.de>
|
||||
Tim Helfensdörfer <tim@visualappeal.de>
|
||||
Tom Ford <exptom@users.noreply.github.com>
|
||||
Ulf Lange <mopp@gmx.net>
|
|
@ -0,0 +1,130 @@
|
|||
## What's New in Version 2.0.0-rc1
|
||||
|
||||
### Changes
|
||||
|
||||
* Improve layout and look and feel in many ways
|
||||
* Apply host, service and custom variable restrictions to all monitoring objects
|
||||
* Add fullscreen mode (?showFullscreen)
|
||||
* User and group management
|
||||
* Comment and Downtime Detail View
|
||||
* Show icon_image in host/service views
|
||||
* Show Icinga program version in monitoring health
|
||||
|
||||
#### Features
|
||||
|
||||
* Feature 4139: Notify monitoring backend availability problems
|
||||
* Feature 4498: Allow to add columns to monitoring views via URL
|
||||
* Feature 6392: Resolve Icinga 2 runtime macros in action and notes URLs
|
||||
* Feature 6729: Fullscreen mode
|
||||
* Feature 7343: Fetch user groups from LDAP
|
||||
* Feature 7595: Remote connection resource configuration
|
||||
* Feature 7614: Right-align icons
|
||||
* Feature 7651: Add module information (module.info) to all core modules
|
||||
* Feature 8054: Host Groups should list number of hosts (as well as services)
|
||||
* Feature 8235: Show host and service notes in the host and service detail view
|
||||
* Feature 8247: Move notifications to the bottom of the page
|
||||
* Feature 8281: Improve layout of comments and downtimes in the host and service detail views
|
||||
* Feature 8310: Improve layout of performance data and check statistics in the host and service detail views
|
||||
* Feature 8565: Improve look and feel of the monitoring multi-select views
|
||||
* Feature 8613: IDO queries related to concrete objects should not depend on collations
|
||||
* Feature 8665: Show icon_image in the host and service detail views
|
||||
* Feature 8781: Automatically deselect rows when closing the detail area
|
||||
* Feature 8826: User and group management
|
||||
* Feature 8849: Show only three (or four) significant digits (e.g. in check execution time)
|
||||
* Feature 8877: Allow module developers to implement new/custom authentication methods
|
||||
* Feature 8886: Require mandatory parameters in controller actions and CLI commands
|
||||
* Feature 8902: Downtime detail view
|
||||
* Feature 8903: Comment detail view
|
||||
* Feature 9009: Apply host and service restrictions to related views as well
|
||||
* Feature 9203: Wizard: Validate that a resource is actually an IDO instance
|
||||
* Feature 9207: Show icinga program version in Monitoring Health
|
||||
* Feature 9223: Show the active ido endpoint in the monitoring health view
|
||||
* Feature 9284: Create a ServiceActionsHook
|
||||
* Feature 9300: Support icon_image_alt
|
||||
* Feature 9361: Refine UI for RC1
|
||||
* Feature 9377: Permission and restriction documentation
|
||||
* Feature 9379: Provide an about.md
|
||||
|
||||
#### Bugfixes
|
||||
|
||||
* Bug 6281: ShowController's hostAction() and serviceAction() do not respond with 400 for invalid/missing parameters and with 404 if the host or service wasn't found
|
||||
* Bug 6778: Duration and history time formatting isn't correct
|
||||
* Bug 6952: Unauthenticated users are provided helpful error messages
|
||||
* Bug 7151: Play nice with form-button-double-clickers
|
||||
* Bug 7165: Invalid host address leads to exception w/ PostgreSQL
|
||||
* Bug 7447: Commands sent over SSH are missing the -i option when using a ssh user aside from the webserver's user
|
||||
* Bug 7491: Switching from MySQL to PostgreSQL and vice versa doesn't change the port in the resource configuration
|
||||
* Bug 7642: Monitoring menu renderers should be moved to the monitoring module
|
||||
* Bug 7658: MenuItemRenderer is not so easy to extend
|
||||
* Bug 7876: Not all views can be added to the dashboard w/o breaking the layout
|
||||
* Bug 7931: Can't acknowledge multiple selected services which are in downtime
|
||||
* Bug 7997: Service-Detail-View tabs are changing their context when clicking the Host-Tab
|
||||
* Bug 7998: Navigating to the Services-Tab in the Service-Detail-View displays only the selected service
|
||||
* Bug 8006: Beautify command transport error exceptions
|
||||
* Bug 8205: List views should not show more than the five worst pies
|
||||
* Bug 8241: Take display_name into account when searching for host and service names
|
||||
* Bug 8334: Perfdata details partially hidden depending on the resolution
|
||||
* Bug 8339: Lib: SimpleQuery::paginate() must not fetch page and limit from request but use them from parameters
|
||||
* Bug 8343: Status summary does not respect restrictions
|
||||
* Bug 8363: Updating dashlets corrupts their URLs
|
||||
* Bug 8453: The filter column "_dev" is not allowed here
|
||||
* Bug 8472: Missing support for command line arguments in the format --arg=<value>
|
||||
* Bug 8474: Improve layout of dictionaries in the host and service detail views
|
||||
* Bug 8624: Delete multiple downtimes and comments at once
|
||||
* Bug 8696: Can't search for Icinga 2 custom variables
|
||||
* Bug 8705: Show all shell commands required to get ready in the setup wizard
|
||||
* Bug 8706: INI files should end with a newline character and should not contain superfluous newlines
|
||||
* Bug 8707: Wizard: setup seems to fail with just one DB user
|
||||
* Bug 8711: JS is logging "ugly" side exceptions
|
||||
* Bug 8731: Apply host restrictions to service views
|
||||
* Bug 8744: Performance data metrics with value 0 are not displayed
|
||||
* Bug 8747: Icinga 2 boolean variables not shown in the host and service detail views
|
||||
* Bug 8777: Server error: Service not found exception when service name begins or ends with whitespaces
|
||||
* Bug 8815: Only the first external command is sent over SSH when submitting commands for multiple selected hosts or services
|
||||
* Bug 8847: Missing indication that nothing was found in the docs when searching
|
||||
* Bug 8860: Host group view calculates states from service states; but states should be calculated from host states instead
|
||||
* Bug 8927: Tactical overview does not respect restrictions
|
||||
* Bug 8928: Host and service groups views do not respect restrictions
|
||||
* Bug 8929: Setup wizard does not validate whether the PostgreSQL user for creating the database owns the CREATE ROLE system privilege
|
||||
* Bug 8930: Error message about refused connection to the PostgreSQL database server displayed twice in the setup wizard
|
||||
* Bug 8934: Status text for ok/up becomes white when hovered
|
||||
* Bug 8941: Long plugin output makes the whole container horizontally scrollable instead of just the row containing the long plugin output
|
||||
* Bug 8950: Improve English for "The last one occured %s ago"
|
||||
* Bug 8953: LDAP encryption settings have no effect
|
||||
* Bug 8956: Can't login when creating the database connection for the preferences store fails
|
||||
* Bug 8957: Fall back on syslog if the logger's type directive is misconfigured
|
||||
* Bug 8958: Switching LDAP encryption to LDAPS doesn't change the port in the resource configuration
|
||||
* Bug 8960: Remove exclamation mark from the notification "Authentication order updated!"
|
||||
* Bug 8966: Show custom variables visually separated in the host and service detail views
|
||||
* Bug 8967: Remove right petrol border from plugin output in the host and service detail views
|
||||
* Bug 8972: Can't view Icinga Web 2's log file
|
||||
* Bug 8994: Uncaught exception on empty session.save_path()
|
||||
* Bug 9000: Only the first line of a stack trace is shown in the applications log view
|
||||
* Bug 9007: Misspelled host and service names in commands are not accepted by icinga
|
||||
* Bug 9008: Notification overview does not respect restrictions
|
||||
* Bug 9022: Browser title does not change in case of an error
|
||||
* Bug 9023: Toggling feature...
|
||||
* Bug 9025: A tooltip of the service grid's x-axe makes it difficult to click the title of the currently hovered column
|
||||
* Bug 9026: Add To Dashboard ... on the dashboard
|
||||
* Bug 9046: Detail View: Downtimes description misses space between duration and comment text
|
||||
* Bug 9056: Filter for host/servicegroup search doesn't work anymore
|
||||
* Bug 9057: contact_notify_host_timeperiod
|
||||
* Bug 9059: Can't initiate an ascending sort by host or service severity
|
||||
* Bug 9198: monitoring/command/feature/object does not grant the correct permissions
|
||||
* Bug 9202: The config\* permission does not permit to navigate to the configuration
|
||||
* Bug 9211: Empty filters are being rendered to SQL which leads to syntax errors
|
||||
* Bug 9214: Detect multitple icinga_instances entries and warn the user
|
||||
* Bug 9220: Centralize submission and apply handling of sort rules
|
||||
* Bug 9224: Allow anonymous LDAP binding
|
||||
* Bug 9281: Problem with Icingaweb 2 after PHP Upgrade 5.6.8 -> 5.6.9
|
||||
* Bug 9317: Web 2's ListController inherits from the monitoring module's base controller
|
||||
* Bug 9319: Downtimes overview does not respect restrictions
|
||||
* Bug 9350: Menu disappears in user group management view
|
||||
* Bug 9351: Timeline links are broken
|
||||
* Bug 9352: User list should be sorted
|
||||
* Bug 9353: Searching for users fails, at least with LDAP backend
|
||||
* Bug 9355: msldap seems not to be a first-class citizen
|
||||
* Bug 9378: Rpm calls usermod w/ invalid option on openSUSE
|
||||
* Bug 9384: Timeline+Role problem
|
||||
* Bug 9392: Command links seem to be broken
|
||||
|
263
README.md
263
README.md
|
@ -2,267 +2,26 @@
|
|||
|
||||
## Table of Contents
|
||||
|
||||
0. [General Information](#general information)
|
||||
0. [About](#about)
|
||||
1. [Installation](#installation)
|
||||
2. [Support](#support)
|
||||
3. [Vagrant - Virtual development environment](#vagrant)
|
||||
|
||||
## General Information
|
||||
## About
|
||||
|
||||
`Icinga Web 2` is the next generation monitoring web interface, framework
|
||||
and CLI tool developed by the [Icinga Project](https://www.icinga.org/community/team/).
|
||||
**Icinga Web 2** is the next generation open source monitoring web interface, framework
|
||||
and command-line interface developed by the [Icinga Project](https://www.icinga.org/), supporting Icinga 2,
|
||||
Icinga Core and any other monitoring backend compatible with the Livestatus Protocol.
|
||||
|
||||
Responsive and fast, rewritten from scratch supporting multiple backends and
|
||||
providing a CLI tool. Compatible with Icinga Core 2.x and 1.x.
|
||||
|
||||
Check the Icinga website for some [insights](https://www.icinga.org/icinga/screenshots/icinga-web-2/).
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> `Icinga Web 2` is still in development and not meant for production deployment.
|
||||
> Watch the [development roadmap](https://dev.icinga.org/projects/icingaweb2/roadmap)
|
||||
> and [Icinga website](https://www.icinga.org/) for release schedule updates!
|
||||

|
||||
|
||||
## Installation
|
||||
|
||||
Please navigate to [doc/installation.md](doc/installation.md) for updated details.
|
||||
For installing Icinga Web 2 please read [doc/installation.md](doc/installation.md).
|
||||
|
||||
## Support
|
||||
|
||||
Please head over to the [community support channels](https://www.icinga.org/icinga/faq/get-help/)
|
||||
in case of questions, bugs, etc.
|
||||
|
||||
Please make sure to provide the following details:
|
||||
|
||||
* OS, distribution, version
|
||||
* PHP and/or MySQL/PostgreSQL version
|
||||
* Which browser and its version
|
||||
* Screenshot and problem description
|
||||
|
||||
|
||||
## Vagrant
|
||||
|
||||
### Requirements
|
||||
|
||||
* Vagrant 1.2+
|
||||
* Virtualbox 4.2.16+
|
||||
* a fairly powerful hardware (quad core, 4gb ram, fast hdd)
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> The deployment of the virtual machine is tested against Vagrant starting with version 1.2.
|
||||
> Unfortunately older versions will not work.
|
||||
|
||||
### General
|
||||
|
||||
The Icinga Web 2 project ships with a Vagrant virtual machine that integrates
|
||||
the source code with various services and example data in a controlled
|
||||
environment. This enables developers and users to test Livestatus, status.dat,
|
||||
MySQL and PostgreSQL backends as well as the LDAP authentication. All you
|
||||
have to do is install Vagrant and run:
|
||||
|
||||
vagrant up
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> The first boot of the vm takes a fairly long time because
|
||||
> you'll download a plain CentOS base box and Vagrant will automatically
|
||||
> provision the environment on the first go.
|
||||
|
||||
After you should be able to browse [localhost:8080/icingaweb](http://localhost:8080/icingaweb).
|
||||
|
||||
### Environment
|
||||
|
||||
**Forwarded ports**:
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Proctocol</th>
|
||||
<th>Local port (virtual machine host)</th>
|
||||
<th>Remote port (the virtual machine)</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SSH</td>
|
||||
<td>2222</td>
|
||||
<td>22</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>HTTP</td>
|
||||
<td>8080</td>
|
||||
<td>80</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
**Installed packages**:
|
||||
|
||||
* Apache2 with PHP enabled
|
||||
* PHP with MySQL and PostgreSQL libraries
|
||||
* MySQL server and client software
|
||||
* PostgreSQL server and client software
|
||||
* [Icinga prerequisites](http://docs.icinga.org/latest/en/quickstart-idoutils.html#installpackages)
|
||||
* OpenLDAP servers and clients
|
||||
|
||||
**Installed users and groups**:
|
||||
|
||||
* User icinga with group icinga and icinga-cmd
|
||||
* Webserver user added to group icinga-cmd
|
||||
|
||||
**Installed software**:
|
||||
|
||||
* Icinga with IDOUtils using a MySQL database
|
||||
* Icinga with IDOUtils using a PostgreSQL database
|
||||
* Icinga 2
|
||||
|
||||
**Installed files**:
|
||||
|
||||
* `/usr/share/icinga/htpasswd.users` account information for logging into the Icinga classic web interface for both icinga instances
|
||||
* `/usr/lib64/nagios/plugins` Monitoring Plugins for all Icinga instances
|
||||
|
||||
#### Icinga with IDOUtils using a MySQL database
|
||||
|
||||
**Installation path**: `/usr/local/icinga-mysql`
|
||||
|
||||
**Services**:
|
||||
|
||||
* `icinga-mysql`
|
||||
* `ido2db-mysql`
|
||||
|
||||
Connect to the **icinga mysql database** using the following command:
|
||||
|
||||
mysql -u icinga -p icinga icinga
|
||||
|
||||
Access the **Classic UI** (CGIs) via [localhost:8080/icinga-mysql](http://localhost:8080/icinga-mysql).
|
||||
For **logging into** the Icinga classic web interface use user *icingaadmin* with password *icinga*.
|
||||
|
||||
#### Icinga with IDOUtils using a PostgreSQL database
|
||||
|
||||
**Installation path**: `/usr/local/icinga-pgsql`
|
||||
|
||||
**Services**:
|
||||
|
||||
* `icinga-pgsql`
|
||||
* `ido2db-pgsql`
|
||||
|
||||
Connect to the **icinga mysql database** using the following command:
|
||||
|
||||
sudo -u postgres psql -U icinga -d icinga
|
||||
|
||||
Access the **Classic UI** (CGIs) via [localhost:8080/icinga-pgsql](http://localhost:8080/icinga-pgsql).
|
||||
For **logging into** the Icinga classic web interface use user *icingaadmin* with password *icinga*.
|
||||
|
||||
#### Monitoring Test Config
|
||||
|
||||
Test config is added to both the MySQL and PostgreSQL Icinga instance utilizing the Perl module
|
||||
**Monitoring::Generator::TestConfig** to generate test config to **/usr/local/share/misc/monitoring_test_config**
|
||||
which is then copied to **<instance>/etc/conf.d/test_config/**.
|
||||
Configuration can be adjusted and recreated with **/usr/local/share/misc/monitoring_test_config/recreate.pl**.
|
||||
**Note** that you have to run
|
||||
|
||||
vagrant provision
|
||||
|
||||
in the host after any modification to the script just mentioned.
|
||||
|
||||
#### MK Livestatus
|
||||
|
||||
MK Livestatus is added to the Icinga installation using a MySQL database.
|
||||
|
||||
**Installation path**:
|
||||
|
||||
* `/usr/local/icinga-mysql/bin/unixcat`
|
||||
* `/usr/local/icinga-mysql/lib/mk-livestatus/livecheck`
|
||||
* `/usr/local/icinga-mysql/lib/mk-livestatus/livestatus.o`
|
||||
* `/usr/local/icinga-mysql/etc/modules/mk-livestatus.cfg`
|
||||
* `/usr/local/icinga-mysql/var/rw/live`
|
||||
|
||||
**Example usage**:
|
||||
|
||||
echo "GET hosts" | /usr/local/icinga-mysql/bin/unixcat /usr/local/icinga-mysql/var/rw/live
|
||||
|
||||
#### LDAP example data
|
||||
|
||||
The environment includes a openldap server with example data. *Domain* suffix is **dc=icinga,dc=org**.
|
||||
Administrator (*rootDN*) of the slapd configuration database is **cn=admin,cn=config** and the
|
||||
administrator (*rootDN*) of our database instance is **cn=admin,dc=icinga,dc=org**. Both share
|
||||
the *password* `admin`.
|
||||
|
||||
Examples to query the slapd configuration database:
|
||||
|
||||
ldapsearch -x -W -LLL -D cn=admin,cn=config -b cn=config dn
|
||||
ldapsearch -Y EXTERNAL -H ldapi:/// -LLL -b cn=config dn
|
||||
|
||||
Examples to query our database instance:
|
||||
|
||||
ldapsearch -x -W -LLL -D cn=admin,dc=icinga,dc=org -b dc=icinga,dc=org dn
|
||||
ldapsearch -Y EXTERNAL -H ldapi:/// -LLL -b dc=icinga,dc=org dn
|
||||
|
||||
This is what the **dc=icinga,dc=org** *DIT* looks like:
|
||||
|
||||
> dn: dc=icinga,dc=org
|
||||
>
|
||||
> dn: ou=people,dc=icinga,dc=org
|
||||
>
|
||||
> dn: ou=groups,dc=icinga,dc=org
|
||||
>
|
||||
> dn: cn=Users,ou=groups,dc=icinga,dc=org
|
||||
> cn: Users
|
||||
> uniqueMember: cn=Jon Doe,ou=people,dc=icinga,dc=org
|
||||
> uniqueMember: cn=Jane Smith,ou=people,dc=icinga,dc=org
|
||||
> uniqueMember: cn=John Q. Public,ou=people,dc=icinga,dc=org
|
||||
> uniqueMember: cn=Richard Roe,ou=people,dc=icinga,dc=org
|
||||
>
|
||||
> dn: cn=John Doe,ou=people,dc=icinga,dc=org
|
||||
> cn: John Doe
|
||||
> uid: jdoe
|
||||
>
|
||||
> dn: cn=Jane Smith,ou=people,dc=icinga,dc=org
|
||||
> cn: Jane Smith
|
||||
> uid: jsmith
|
||||
>
|
||||
> dn: cn=John Q. Public,ou=people,dc=icinga,dc=org
|
||||
> cn: John Q. Public
|
||||
> uid: jqpublic
|
||||
>
|
||||
> dn: cn=Richard Roe,ou=people,dc=icinga,dc=org
|
||||
> cn: Richard Roe
|
||||
> uid: rroe
|
||||
|
||||
All users share the password `password`.
|
||||
|
||||
#### Testing the code
|
||||
|
||||
All software required to run tests is installed in the virtual machine.
|
||||
In order to run all tests you have to execute the following commands:
|
||||
|
||||
vagrant ssh -c /vagrant/test/php/runtests
|
||||
vagrant ssh -c /vagrant/test/php/checkswag
|
||||
vagrant ssh -c /vagrant/test/js/runtests
|
||||
vagrant ssh -c /vagrant/test/js/checkswag
|
||||
vagrant ssh -c /vagrant/test/frontend/runtests
|
||||
|
||||
`runtests` will execute unit and regression tests and `checkswag` will report
|
||||
code style issues.
|
||||
|
||||
#### Icinga 2
|
||||
|
||||
Installed from the Icinga [snapshot package repository](http://packages.icinga.org/epel/).
|
||||
The configuration is located in `/etc/icinga2`.
|
||||
|
||||
**Example usage**:
|
||||
|
||||
/etc/init.d/icinga2 (start|stop|restart|reload)
|
||||
|
||||
|
||||
## Log into Icinga Web 2
|
||||
|
||||
If you've configure LDAP as authentication backend (which is the default) use the following login credentials:
|
||||
|
||||
> **Username**: jdoe
|
||||
> **Password**: password
|
||||
|
||||
Have a look at [LDAP example data](#ldap example data) for more accounts.
|
||||
|
||||
Using MySQL as backend:
|
||||
|
||||
> **Username**: icingaadmin
|
||||
> **Password**: icinga
|
||||
If you come across problems at some time, the [community support channels](https://support.icinga.org/)
|
||||
are good places to ask for advice from other users and give some in return.
|
||||
|
||||
For status updates check the [Icinga website](https://www.icinga.org/) and the
|
||||
[Icinga Web 2 development roadmap](https://dev.icinga.org/projects/icingaweb2/roadmap).
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
# Quality Assurance
|
||||
|
||||
Review and test the changes and issues for this version.
|
||||
https://dev.icinga.org/projects/icingaweb2/roadmap
|
||||
|
||||
# Release Workflow
|
||||
|
||||
Update the [.mailmap](.mailmap) and [AUTHORS](AUTHORS) files:
|
||||
|
||||
$ git log --use-mailmap | grep ^Author: | cut -f2- -d' ' | sort | uniq > AUTHORS
|
||||
|
||||
Update the version number in the [icingaweb2.spec] and [VERSION] files.
|
||||
|
||||
Update the [ChangeLog](ChangeLog) file using
|
||||
the changelog.py script.
|
||||
|
||||
Changelog:
|
||||
|
||||
$ ./changelog.py --version 2.0.0-rc1
|
||||
|
||||
Wordpress:
|
||||
|
||||
$ ./changelog.py --version 2.0.0-rc1 --html --links
|
||||
|
||||
Commit these changes to the "master" branch:
|
||||
|
||||
$ git commit -v -a -m "Release version <VERSION>"
|
||||
|
||||
For minor releases: Cherry-pick this commit into the "support" branch.
|
||||
|
||||
Create a signed tag (tags/v<VERSION>) on the "master" branch (for major
|
||||
releases) or the "support" branch (for minor releases).
|
||||
|
||||
$ git tag -m "Version <VERSION>" v<VERSION>
|
||||
|
||||
Push the tag.
|
||||
|
||||
$ git push --tags
|
||||
|
||||
For major releases: Create a new "support" branch:
|
||||
|
||||
$ git checkout master
|
||||
$ git checkout -b support/2.x
|
||||
$ git push -u origin support/2.x
|
||||
|
||||
# External Dependencies
|
||||
|
||||
## Build Server
|
||||
|
||||
### Linux
|
||||
|
||||
* Build the newly created git tag for Debian/RHEL/SuSE.
|
||||
* Provision the vagrant boxes and test the release packages.
|
||||
|
||||
## Github Release
|
||||
|
||||
Create a new release from the newly created git tag.
|
||||
https://github.com/Icinga/icingaweb2/releases
|
||||
|
||||
## Announcement
|
||||
|
||||
* Create a new blog post on www.icinga.org/blog
|
||||
* Send announcement mail to icinga-announce@lists.icinga.org
|
||||
* Social media: [Twitter](https://twitter.com/icinga), [Facebook](https://www.facebook.com/icinga), [G+](http://plus.google.com/+icinga), [Xing](https://www.xing.com/communities/groups/icinga-da4b-1060043), [LinkedIn](https://www.linkedin.com/groups/Icinga-1921830/about)
|
|
@ -1,10 +1,11 @@
|
|||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
|
||||
# Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+
|
||||
|
||||
VAGRANTFILE_API_VERSION = "2"
|
||||
VAGRANT_REQUIRED_VERSION = "1.5.0"
|
||||
|
||||
# Require 1.2.x at least
|
||||
if ! defined? Vagrant.require_version
|
||||
if Gem::Version.new(Vagrant::VERSION) < Gem::Version.new(VAGRANT_REQUIRED_VERSION)
|
||||
puts "Vagrant >= " + VAGRANT_REQUIRED_VERSION + " required. Your version is " + Vagrant::VERSION
|
||||
|
@ -21,13 +22,15 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
|||
config.vm.provision :shell, :path => ".puppet/manifests/puppet.sh"
|
||||
|
||||
config.vm.provider :virtualbox do |v, override|
|
||||
override.vm.box = "puppetlabs/centos-6.5-64-puppet"
|
||||
override.vm.box = "centos-71-x64-vbox"
|
||||
override.vm.box_url = "http://boxes.icinga.org/centos-71-x64-vbox.box"
|
||||
|
||||
v.customize ["modifyvm", :id, "--memory", "1024"]
|
||||
v.customize ["modifyvm", :id, "--cpus", "2"]
|
||||
end
|
||||
|
||||
config.vm.provider :parallels do |p, override|
|
||||
override.vm.box = "parallels/centos-6.5"
|
||||
override.vm.box = "parallels/centos-7.1"
|
||||
|
||||
p.name = "Icinga Web 2 Development"
|
||||
|
||||
|
@ -46,5 +49,6 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
|||
puppet.module_path = [ ".puppet/modules", ".puppet/profiles" ]
|
||||
puppet.manifests_path = ".puppet/manifests"
|
||||
puppet.manifest_file = "site.pp"
|
||||
puppet.options = "--parser=future"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
$Format:%H%d %ci$
|
|
@ -1,6 +1,5 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Clicommands;
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Clicommands;
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Clicommands;
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Clicommands;
|
||||
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
# namespace Icinga\Application\Controllers;
|
||||
|
||||
use Icinga\Web\Controller\ActionController;
|
||||
use Icinga\Application\Version;
|
||||
|
||||
class AboutController extends ActionController
|
||||
{
|
||||
public function indexAction()
|
||||
{
|
||||
$this->view->version = Version::get();
|
||||
}
|
||||
}
|
|
@ -1,145 +1,53 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
# namespace Icinga\Application\Controllers;
|
||||
|
||||
use Icinga\Authentication\Backend\AutoLoginBackend;
|
||||
use Icinga\Web\Controller\ActionController;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Forms\Authentication\LoginForm;
|
||||
use Icinga\Authentication\AuthChain;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Exception\AuthenticationException;
|
||||
use Icinga\Exception\NotReadableError;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\User;
|
||||
use Icinga\Web\Controller;
|
||||
use Icinga\Web\Cookie;
|
||||
use Icinga\Web\Url;
|
||||
|
||||
/**
|
||||
* Application wide controller for authentication
|
||||
*/
|
||||
class AuthenticationController extends ActionController
|
||||
class AuthenticationController extends Controller
|
||||
{
|
||||
/**
|
||||
* This controller does not require authentication
|
||||
*
|
||||
* @var bool
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $requiresAuthentication = false;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $innerLayout = 'inline';
|
||||
|
||||
/**
|
||||
* Log into the application
|
||||
*/
|
||||
public function loginAction()
|
||||
{
|
||||
if (@file_exists(Config::resolvePath('setup.token')) && !@file_exists(Config::resolvePath('config.ini'))) {
|
||||
$icinga = Icinga::app();
|
||||
if (($requiresSetup = $icinga->requiresSetup()) && $icinga->setupTokenExists()) {
|
||||
$this->redirectNow(Url::fromPath('setup'));
|
||||
}
|
||||
|
||||
$auth = $this->Auth();
|
||||
$this->view->form = $form = new LoginForm();
|
||||
$this->view->title = $this->translate('Icingaweb Login');
|
||||
|
||||
try {
|
||||
$redirectUrl = $this->view->form->getValue('redirect');
|
||||
if ($redirectUrl) {
|
||||
$redirectUrl = Url::fromPath($redirectUrl);
|
||||
} else {
|
||||
$redirectUrl = Url::fromPath('dashboard');
|
||||
}
|
||||
|
||||
if ($auth->isAuthenticated()) {
|
||||
$this->rerenderLayout()->redirectNow($redirectUrl);
|
||||
}
|
||||
|
||||
try {
|
||||
$config = Config::app('authentication');
|
||||
} catch (NotReadableError $e) {
|
||||
throw new ConfigurationError(
|
||||
$this->translate('Could not read your authentication.ini, no authentication methods are available.'),
|
||||
0,
|
||||
$e
|
||||
);
|
||||
}
|
||||
|
||||
$chain = new AuthChain($config);
|
||||
$request = $this->getRequest();
|
||||
if ($request->isPost() && $this->view->form->isValid($request->getPost())) {
|
||||
$user = new User($this->view->form->getValue('username'));
|
||||
$password = $this->view->form->getValue('password');
|
||||
$backendsTried = 0;
|
||||
$backendsWithError = 0;
|
||||
|
||||
$redirectUrl = $form->getValue('redirect');
|
||||
|
||||
if ($redirectUrl) {
|
||||
$redirectUrl = Url::fromPath($redirectUrl);
|
||||
} else {
|
||||
$redirectUrl = Url::fromPath('dashboard');
|
||||
}
|
||||
|
||||
foreach ($chain as $backend) {
|
||||
if ($backend instanceof AutoLoginBackend) {
|
||||
continue;
|
||||
}
|
||||
++$backendsTried;
|
||||
try {
|
||||
$authenticated = $backend->authenticate($user, $password);
|
||||
} catch (AuthenticationException $e) {
|
||||
Logger::error($e);
|
||||
++$backendsWithError;
|
||||
continue;
|
||||
}
|
||||
if ($authenticated === true) {
|
||||
$auth->setAuthenticated($user);
|
||||
$this->rerenderLayout()->redirectNow($redirectUrl);
|
||||
}
|
||||
}
|
||||
if ($backendsTried === 0) {
|
||||
$this->view->form->addError(
|
||||
$this->translate(
|
||||
'No authentication methods available. Did you create'
|
||||
. ' authentication.ini when setting up Icinga Web 2?'
|
||||
)
|
||||
);
|
||||
} else if ($backendsTried === $backendsWithError) {
|
||||
$this->view->form->addError(
|
||||
$this->translate(
|
||||
'All configured authentication methods failed.'
|
||||
. ' Please check the system log or Icinga Web 2 log for more information.'
|
||||
)
|
||||
);
|
||||
} elseif ($backendsWithError) {
|
||||
$this->view->form->addError(
|
||||
$this->translate(
|
||||
'Please note that not all authentication methods were available.'
|
||||
. ' Check the system log or Icinga Web 2 log for more information.'
|
||||
)
|
||||
);
|
||||
}
|
||||
if ($backendsTried > 0 && $backendsTried !== $backendsWithError) {
|
||||
$this->view->form->getElement('password')->addError($this->translate('Incorrect username or password'));
|
||||
}
|
||||
} elseif ($request->isGet()) {
|
||||
$user = new User('');
|
||||
foreach ($chain as $backend) {
|
||||
if ($backend instanceof AutoLoginBackend) {
|
||||
$authenticated = $backend->authenticate($user);
|
||||
if ($authenticated === true) {
|
||||
$auth->setAuthenticated($user);
|
||||
$this->rerenderLayout()->redirectNow(
|
||||
Url::fromPath(Url::fromRequest()->getParam('redirect', 'dashboard'))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$this->view->errorInfo = $e->getMessage();
|
||||
$form = new LoginForm();
|
||||
if ($this->Auth()->isAuthenticated()) {
|
||||
$this->redirectNow($form->getRedirectUrl());
|
||||
}
|
||||
|
||||
$this->view->configMissing = is_dir(Config::$configDir) === false;
|
||||
if (! $requiresSetup) {
|
||||
if (! $this->getRequest()->hasCookieSupport()) {
|
||||
echo $this->translate("Cookies must be enabled to run this application.\n");
|
||||
$this->getResponse()->setHttpResponseCode(403)->sendHeaders();
|
||||
exit();
|
||||
}
|
||||
$form->handleRequest();
|
||||
}
|
||||
$this->view->form = $form;
|
||||
$this->view->title = $this->translate('Icinga Web 2 Login');
|
||||
$this->view->requiresSetup = $requiresSetup;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -151,10 +59,12 @@ class AuthenticationController extends ActionController
|
|||
if (! $auth->isAuthenticated()) {
|
||||
$this->redirectToLogin();
|
||||
}
|
||||
$isRemoteUser = $auth->getUser()->isRemoteUser();
|
||||
// Get info whether the user is externally authenticated before removing authorization which destroys the
|
||||
// session and the user object
|
||||
$isExternalUser = $auth->getUser()->isExternalUser();
|
||||
$auth->removeAuthorization();
|
||||
if ($isRemoteUser === true) {
|
||||
$this->_response->setHttpResponseCode(401);
|
||||
if ($isExternalUser) {
|
||||
$this->getResponse()->setHttpResponseCode(401);
|
||||
} else {
|
||||
$this->redirectToLogin();
|
||||
}
|
||||
|
|
|
@ -1,41 +1,68 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
use Icinga\Web\Controller\ActionController;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Application\Modules\Module;
|
||||
use Icinga\Web\Widget;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Application\Modules\Module;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Exception\NotFoundError;
|
||||
use Icinga\Forms\Config\UserBackendConfigForm;
|
||||
use Icinga\Forms\Config\UserBackendReorderForm;
|
||||
use Icinga\Forms\Config\GeneralConfigForm;
|
||||
use Icinga\Forms\Config\AuthenticationBackendReorderForm;
|
||||
use Icinga\Forms\Config\AuthenticationBackendConfigForm;
|
||||
use Icinga\Forms\Config\ResourceConfigForm;
|
||||
use Icinga\Forms\ConfirmRemovalForm;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
|
||||
use Icinga\Security\SecurityException;
|
||||
use Icinga\Web\Controller;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Web\Url;
|
||||
use Icinga\Web\Widget;
|
||||
|
||||
/**
|
||||
* Application wide controller for application preferences
|
||||
* Application and module configuration
|
||||
*/
|
||||
class ConfigController extends ActionController
|
||||
class ConfigController extends Controller
|
||||
{
|
||||
public function init()
|
||||
/**
|
||||
* Create and return the tabs to display when showing application configuration
|
||||
*/
|
||||
public function createApplicationTabs()
|
||||
{
|
||||
$this->view->tabs = Widget::create('tabs')->add('index', array(
|
||||
'title' => $this->translate('Application'),
|
||||
'url' => 'config'
|
||||
))->add('authentication', array(
|
||||
'title' => $this->translate('Authentication'),
|
||||
'url' => 'config/authentication'
|
||||
))->add('resources', array(
|
||||
'title' => $this->translate('Resources'),
|
||||
'url' => 'config/resource'
|
||||
))->add('roles', array(
|
||||
'title' => $this->translate('Roles'),
|
||||
'url' => 'roles'
|
||||
$tabs = $this->getTabs();
|
||||
$tabs->add('general', array(
|
||||
'title' => $this->translate('Adjust the general configuration of Icinga Web 2'),
|
||||
'label' => $this->translate('General'),
|
||||
'url' => 'config/general',
|
||||
'baseTarget' => '_main'
|
||||
));
|
||||
$tabs->add('resource', array(
|
||||
'title' => $this->translate('Configure which resources are being utilized by Icinga Web 2'),
|
||||
'label' => $this->translate('Resources'),
|
||||
'url' => 'config/resource',
|
||||
'baseTarget' => '_main'
|
||||
));
|
||||
return $tabs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return the tabs to display when showing authentication configuration
|
||||
*/
|
||||
public function createAuthenticationTabs()
|
||||
{
|
||||
$tabs = $this->getTabs();
|
||||
$tabs->add('userbackend', array(
|
||||
'title' => $this->translate('Configure how users authenticate with and log into Icinga Web 2'),
|
||||
'label' => $this->translate('User Backends'),
|
||||
'url' => 'config/userbackend',
|
||||
'baseTarget' => '_main'
|
||||
));
|
||||
$tabs->add('usergroupbackend', array(
|
||||
'title' => $this->translate('Configure how users are associated with groups by Icinga Web 2'),
|
||||
'label' => $this->translate('User Group Backends'),
|
||||
'url' => 'usergroupbackend/list',
|
||||
'baseTarget' => '_main'
|
||||
));
|
||||
return $tabs;
|
||||
}
|
||||
|
||||
public function devtoolsAction()
|
||||
|
@ -44,16 +71,27 @@ class ConfigController extends ActionController
|
|||
}
|
||||
|
||||
/**
|
||||
* Index action, entry point for configuration
|
||||
* Redirect to the general configuration
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
$this->redirectNow('config/general');
|
||||
}
|
||||
|
||||
/**
|
||||
* General configuration
|
||||
*
|
||||
* @throws SecurityException If the user lacks the permission for configuring the general configuration
|
||||
*/
|
||||
public function generalAction()
|
||||
{
|
||||
$this->assertPermission('config/application/general');
|
||||
$form = new GeneralConfigForm();
|
||||
$form->setIniConfig(Config::app());
|
||||
$form->handleRequest();
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->view->tabs->activate('index');
|
||||
$this->createApplicationTabs()->activate('general');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -61,32 +99,50 @@ class ConfigController extends ActionController
|
|||
*/
|
||||
public function modulesAction()
|
||||
{
|
||||
$this->view->tabs = Widget::create('tabs')->add('modules', array(
|
||||
'title' => $this->translate('Modules'),
|
||||
'url' => 'config/modules'
|
||||
));
|
||||
|
||||
$this->view->tabs->activate('modules');
|
||||
$this->assertPermission('config/modules');
|
||||
// Overwrite tabs created in init
|
||||
// @TODO(el): This seems not natural to me. Module configuration should have its own controller.
|
||||
$this->view->tabs = Widget::create('tabs')
|
||||
->add('modules', array(
|
||||
'label' => $this->translate('Modules'),
|
||||
'title' => $this->translate('List intalled modules'),
|
||||
'url' => 'config/modules'
|
||||
))
|
||||
->activate('modules');
|
||||
$this->view->modules = Icinga::app()->getModuleManager()->select()
|
||||
->from('modules')
|
||||
->order('enabled', 'desc')
|
||||
->order('name')->paginate();
|
||||
->order('name');
|
||||
$this->setupLimitControl();
|
||||
$this->setupPaginationControl($this->view->modules);
|
||||
// TODO: Not working
|
||||
/*$this->setupSortControl(array(
|
||||
'name' => $this->translate('Modulename'),
|
||||
'path' => $this->translate('Installation Path'),
|
||||
'enabled' => $this->translate('State')
|
||||
));*/
|
||||
}
|
||||
|
||||
public function moduleAction()
|
||||
{
|
||||
$name = $this->getParam('name');
|
||||
$this->assertPermission('config/modules');
|
||||
$app = Icinga::app();
|
||||
$manager = $app->getModuleManager();
|
||||
$name = $this->getParam('name');
|
||||
if ($manager->hasInstalled($name)) {
|
||||
$this->view->moduleData = Icinga::app()->getModuleManager()->select()
|
||||
->from('modules')->where('name', $name)->fetchRow();
|
||||
$module = new Module($app, $name, $manager->getModuleDir($name));
|
||||
$this->view->moduleData = $manager->select()->from('modules')->where('name', $name)->fetchRow();
|
||||
if ($manager->hasLoaded($name)) {
|
||||
$module = $manager->getModule($name);
|
||||
} else {
|
||||
$module = new Module($app, $name, $manager->getModuleDir($name));
|
||||
}
|
||||
|
||||
$this->view->module = $module;
|
||||
$this->view->tabs = $module->getConfigTabs()->activate('info');
|
||||
} else {
|
||||
$this->view->module = false;
|
||||
$this->view->tabs = null;
|
||||
}
|
||||
$this->view->tabs = $module->getConfigTabs()->activate('info');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -94,11 +150,11 @@ class ConfigController extends ActionController
|
|||
*/
|
||||
public function moduleenableAction()
|
||||
{
|
||||
$this->assertPermission('config/modules');
|
||||
$module = $this->getParam('name');
|
||||
$manager = Icinga::app()->getModuleManager();
|
||||
try {
|
||||
$manager->enableModule($module);
|
||||
$manager->loadModule($module);
|
||||
Notification::success(sprintf($this->translate('Module "%s" enabled'), $module));
|
||||
$this->rerenderLayout()->reloadCss()->redirectNow('config/modules');
|
||||
} catch (Exception $e) {
|
||||
|
@ -114,6 +170,7 @@ class ConfigController extends ActionController
|
|||
*/
|
||||
public function moduledisableAction()
|
||||
{
|
||||
$this->assertPermission('config/modules');
|
||||
$module = $this->getParam('name');
|
||||
$manager = Icinga::app()->getModuleManager();
|
||||
try {
|
||||
|
@ -129,85 +186,144 @@ class ConfigController extends ActionController
|
|||
}
|
||||
|
||||
/**
|
||||
* Action for listing and reordering authentication backends
|
||||
* Action for listing and reordering user backends
|
||||
*/
|
||||
public function authenticationAction()
|
||||
public function userbackendAction()
|
||||
{
|
||||
$form = new AuthenticationBackendReorderForm();
|
||||
$this->assertPermission('config/application/userbackend');
|
||||
$form = new UserBackendReorderForm();
|
||||
$form->setIniConfig(Config::app('authentication'));
|
||||
$form->handleRequest();
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->view->tabs->activate('authentication');
|
||||
$this->render('authentication/reorder');
|
||||
$this->createAuthenticationTabs()->activate('userbackend');
|
||||
$this->render('userbackend/reorder');
|
||||
}
|
||||
|
||||
/**
|
||||
* Action for creating a new authentication backend
|
||||
* Create a new user backend
|
||||
*/
|
||||
public function createauthenticationbackendAction()
|
||||
public function createuserbackendAction()
|
||||
{
|
||||
$form = new AuthenticationBackendConfigForm();
|
||||
$form->setIniConfig(Config::app('authentication'));
|
||||
$form->setResourceConfig(ResourceFactory::getResourceConfigs());
|
||||
$form->setRedirectUrl('config/authentication');
|
||||
$form->handleRequest();
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->view->tabs->activate('authentication');
|
||||
$this->render('authentication/create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Action for editing authentication backends
|
||||
*/
|
||||
public function editauthenticationbackendAction()
|
||||
{
|
||||
$form = new AuthenticationBackendConfigForm();
|
||||
$form->setIniConfig(Config::app('authentication'));
|
||||
$form->setResourceConfig(ResourceFactory::getResourceConfigs());
|
||||
$form->setRedirectUrl('config/authentication');
|
||||
$form->handleRequest();
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->view->tabs->activate('authentication');
|
||||
$this->render('authentication/modify');
|
||||
}
|
||||
|
||||
/**
|
||||
* Action for removing a backend from the authentication list
|
||||
*/
|
||||
public function removeauthenticationbackendAction()
|
||||
{
|
||||
$form = new ConfirmRemovalForm(array(
|
||||
'onSuccess' => function ($form) {
|
||||
$configForm = new AuthenticationBackendConfigForm();
|
||||
$configForm->setIniConfig(Config::app('authentication'));
|
||||
$authBackend = $form->getRequest()->getQuery('auth_backend');
|
||||
|
||||
try {
|
||||
$configForm->remove($authBackend);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
Notification::error($e->getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
if ($configForm->save()) {
|
||||
Notification::success(sprintf(
|
||||
t('Authentication backend "%s" has been successfully removed'),
|
||||
$authBackend
|
||||
));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$this->assertPermission('config/application/userbackend');
|
||||
$form = new UserBackendConfigForm();
|
||||
$form->setRedirectUrl('config/userbackend');
|
||||
$form->setTitle($this->translate('Create New User Backend'));
|
||||
$form->addDescription($this->translate(
|
||||
'Create a new backend for authenticating your users. This backend'
|
||||
. ' will be added at the end of your authentication order.'
|
||||
));
|
||||
$form->setRedirectUrl('config/authentication');
|
||||
$form->setIniConfig(Config::app('authentication'));
|
||||
|
||||
try {
|
||||
$form->setResourceConfig(ResourceFactory::getResourceConfigs());
|
||||
} catch (ConfigurationError $e) {
|
||||
if ($this->hasPermission('config/application/resources')) {
|
||||
Notification::error($e->getMessage());
|
||||
$this->redirectNow('config/createresource');
|
||||
}
|
||||
|
||||
throw $e; // No permission for resource configuration, show the error
|
||||
}
|
||||
|
||||
$form->setOnSuccess(function (UserBackendConfigForm $form) {
|
||||
try {
|
||||
$form->add(array_filter($form->getValues()));
|
||||
} catch (Exception $e) {
|
||||
$form->error($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($form->save()) {
|
||||
Notification::success(t('User backend successfully created'));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
$form->handleRequest();
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->view->tabs->activate('authentication');
|
||||
$this->render('authentication/remove');
|
||||
$this->render('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit a user backend
|
||||
*/
|
||||
public function edituserbackendAction()
|
||||
{
|
||||
$this->assertPermission('config/application/userbackend');
|
||||
$backendName = $this->params->getRequired('backend');
|
||||
|
||||
$form = new UserBackendConfigForm();
|
||||
$form->setRedirectUrl('config/userbackend');
|
||||
$form->setTitle(sprintf($this->translate('Edit User Backend %s'), $backendName));
|
||||
$form->setIniConfig(Config::app('authentication'));
|
||||
$form->setOnSuccess(function (UserBackendConfigForm $form) use ($backendName) {
|
||||
try {
|
||||
$form->edit($backendName, array_map(
|
||||
function ($v) {
|
||||
return $v !== '' ? $v : null;
|
||||
},
|
||||
$form->getValues()
|
||||
));
|
||||
} catch (Exception $e) {
|
||||
$form->error($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($form->save()) {
|
||||
Notification::success(sprintf(t('User backend "%s" successfully updated'), $backendName));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
try {
|
||||
$form->load($backendName);
|
||||
$form->setResourceConfig(ResourceFactory::getResourceConfigs());
|
||||
$form->handleRequest();
|
||||
} catch (NotFoundError $_) {
|
||||
$this->httpNotFound(sprintf($this->translate('User backend "%s" not found'), $backendName));
|
||||
}
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->render('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a confirmation form to remove the backend identified by the 'backend' parameter
|
||||
*/
|
||||
public function removeuserbackendAction()
|
||||
{
|
||||
$this->assertPermission('config/application/userbackend');
|
||||
$backendName = $this->params->getRequired('backend');
|
||||
|
||||
$backendForm = new UserBackendConfigForm();
|
||||
$backendForm->setIniConfig(Config::app('authentication'));
|
||||
$form = new ConfirmRemovalForm();
|
||||
$form->setRedirectUrl('config/userbackend');
|
||||
$form->setTitle(sprintf($this->translate('Remove User Backend %s'), $backendName));
|
||||
$form->setOnSuccess(function (ConfirmRemovalForm $form) use ($backendName, $backendForm) {
|
||||
try {
|
||||
$backendForm->delete($backendName);
|
||||
} catch (Exception $e) {
|
||||
$form->error($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($backendForm->save()) {
|
||||
Notification::success(sprintf(t('User backend "%s" successfully removed'), $backendName));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
$form->handleRequest();
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->render('form');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -215,8 +331,9 @@ class ConfigController extends ActionController
|
|||
*/
|
||||
public function resourceAction()
|
||||
{
|
||||
$this->assertPermission('config/application/resources');
|
||||
$this->view->resources = Config::app('resources', true)->keys();
|
||||
$this->view->tabs->activate('resources');
|
||||
$this->createApplicationTabs()->activate('resource');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -224,7 +341,10 @@ class ConfigController extends ActionController
|
|||
*/
|
||||
public function createresourceAction()
|
||||
{
|
||||
$this->assertPermission('config/application/resources');
|
||||
$form = new ResourceConfigForm();
|
||||
$form->setTitle($this->translate('Create A New Resource'));
|
||||
$form->addDescription($this->translate('Resources are entities that provide data to Icinga Web 2.'));
|
||||
$form->setIniConfig(Config::app('resources'));
|
||||
$form->setRedirectUrl('config/resource');
|
||||
$form->handleRequest();
|
||||
|
@ -238,7 +358,9 @@ class ConfigController extends ActionController
|
|||
*/
|
||||
public function editresourceAction()
|
||||
{
|
||||
$this->assertPermission('config/application/resources');
|
||||
$form = new ResourceConfigForm();
|
||||
$form->setTitle($this->translate('Edit Existing Resource'));
|
||||
$form->setIniConfig(Config::app('resources'));
|
||||
$form->setRedirectUrl('config/resource');
|
||||
$form->handleRequest();
|
||||
|
@ -252,6 +374,7 @@ class ConfigController extends ActionController
|
|||
*/
|
||||
public function removeresourceAction()
|
||||
{
|
||||
$this->assertPermission('config/application/resources');
|
||||
$form = new ConfirmRemovalForm(array(
|
||||
'onSuccess' => function ($form) {
|
||||
$configForm = new ResourceConfigForm();
|
||||
|
@ -262,7 +385,7 @@ class ConfigController extends ActionController
|
|||
$configForm->remove($resource);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
Notification::error($e->getMessage());
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($configForm->save()) {
|
||||
|
@ -272,6 +395,7 @@ class ConfigController extends ActionController
|
|||
}
|
||||
}
|
||||
));
|
||||
$form->setTitle($this->translate('Remove Existing Resource'));
|
||||
$form->setRedirectUrl('config/resource');
|
||||
$form->handleRequest();
|
||||
|
||||
|
@ -280,9 +404,9 @@ class ConfigController extends ActionController
|
|||
$authConfig = Config::app('authentication');
|
||||
foreach ($authConfig as $backendName => $config) {
|
||||
if ($config->get('resource') === $resource) {
|
||||
$form->addError(sprintf(
|
||||
$form->addDescription(sprintf(
|
||||
$this->translate(
|
||||
'The resource "%s" is currently in use by the authentication backend "%s". ' .
|
||||
'The resource "%s" is currently utilized for authentication by user backend "%s". ' .
|
||||
'Removing the resource can result in noone being able to log in any longer.'
|
||||
),
|
||||
$resource,
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Forms\ConfirmRemovalForm;
|
||||
use Icinga\Forms\Dashboard\DashletForm;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Web\Controller\ActionController;
|
||||
use Icinga\Web\Request;
|
||||
use Icinga\Web\Url;
|
||||
use Icinga\Web\Widget\Dashboard;
|
||||
use Icinga\Web\Widget\Tabextension\DashboardSettings;
|
||||
|
@ -25,11 +22,11 @@ class DashboardController extends ActionController
|
|||
* @var Dashboard;
|
||||
*/
|
||||
private $dashboard;
|
||||
|
||||
|
||||
public function init()
|
||||
{
|
||||
$this->dashboard = new Dashboard();
|
||||
$this->dashboard->setUser($this->getRequest()->getUser());
|
||||
$this->dashboard->setUser($this->Auth()->getUser());
|
||||
$this->dashboard->load();
|
||||
}
|
||||
|
||||
|
@ -56,17 +53,19 @@ class DashboardController extends ActionController
|
|||
$dashlet = new Dashboard\Dashlet($form->getValue('dashlet'), $form->getValue('url'), $pane);
|
||||
$dashlet->setUserWidget();
|
||||
$pane->addDashlet($dashlet);
|
||||
$dashboardConfig = $dashboard->getConfig();
|
||||
try {
|
||||
$dashboard->write();
|
||||
} catch (\Zend_Config_Exception $e) {
|
||||
$dashboardConfig->saveIni();
|
||||
} catch (Exception $e) {
|
||||
$action->view->error = $e;
|
||||
$action->view->config = $dashboard->createWriter();
|
||||
$action->view->config = $dashboardConfig;
|
||||
$action->render('error');
|
||||
return false;
|
||||
}
|
||||
Notification::success(t('Dashlet created'));
|
||||
return true;
|
||||
});
|
||||
$form->setTitle($this->translate('Add Dashlet To Dashboard'));
|
||||
$form->setRedirectUrl('dashboard');
|
||||
$form->handleRequest();
|
||||
$this->view->form = $form;
|
||||
|
@ -78,7 +77,7 @@ class DashboardController extends ActionController
|
|||
$dashboard = $this->dashboard;
|
||||
$form = new DashletForm();
|
||||
$form->setDashboard($dashboard);
|
||||
$form->setSubmitLabel(t('Update Dashlet'));
|
||||
$form->setSubmitLabel($this->translate('Update Dashlet'));
|
||||
if (! $this->_request->getParam('pane')) {
|
||||
throw new Zend_Controller_Action_Exception(
|
||||
'Missing parameter "pane"',
|
||||
|
@ -117,17 +116,19 @@ class DashboardController extends ActionController
|
|||
$oldPane = $dashboard->getPane($form->getValue('org_pane'));
|
||||
$oldPane->removeDashlet($dashlet->getTitle());
|
||||
}
|
||||
$dashboardConfig = $dashboard->getConfig();
|
||||
try {
|
||||
$dashboard->write();
|
||||
} catch (\Zend_Config_Exception $e) {
|
||||
$dashboardConfig->saveIni();
|
||||
} catch (Exception $e) {
|
||||
$action->view->error = $e;
|
||||
$action->view->config = $dashboard->createWriter();
|
||||
$action->view->config = $dashboardConfig;
|
||||
$action->render('error');
|
||||
return false;
|
||||
}
|
||||
Notification::success(t('Dashlet updated'));
|
||||
return true;
|
||||
});
|
||||
$form->setTitle($this->translate('Edit Dashlet'));
|
||||
$form->setRedirectUrl('dashboard/settings');
|
||||
$form->handleRequest();
|
||||
$pane = $dashboard->getPane($this->getParam('pane'));
|
||||
|
@ -158,15 +159,16 @@ class DashboardController extends ActionController
|
|||
$dashlet = $this->_request->getParam('dashlet');
|
||||
$action = $this;
|
||||
$form->setOnSuccess(function (Form $form) use ($dashboard, $dashlet, $pane, $action) {
|
||||
$pane = $dashboard->getPane($pane);
|
||||
$pane->removeDashlet($dashlet);
|
||||
$dashboardConfig = $dashboard->getConfig();
|
||||
try {
|
||||
$pane = $dashboard->getPane($pane);
|
||||
$pane->removeDashlet($dashlet);
|
||||
$dashboard->write();
|
||||
$dashboardConfig->saveIni();
|
||||
Notification::success(t('Dashlet has been removed from') . ' ' . $pane->getTitle());
|
||||
return true;
|
||||
} catch (\Zend_Config_Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
$action->view->error = $e;
|
||||
$action->view->config = $dashboard->createWriter();
|
||||
$action->view->config = $dashboardConfig;
|
||||
$action->render('error');
|
||||
return false;
|
||||
} catch (ProgrammingError $e) {
|
||||
|
@ -175,6 +177,7 @@ class DashboardController extends ActionController
|
|||
}
|
||||
return false;
|
||||
});
|
||||
$form->setTitle($this->translate('Remove Dashlet From Dashboard'));
|
||||
$form->setRedirectUrl('dashboard/settings');
|
||||
$form->handleRequest();
|
||||
$this->view->pane = $pane;
|
||||
|
@ -196,15 +199,16 @@ class DashboardController extends ActionController
|
|||
$pane = $this->_request->getParam('pane');
|
||||
$action = $this;
|
||||
$form->setOnSuccess(function (Form $form) use ($dashboard, $pane, $action) {
|
||||
$pane = $dashboard->getPane($pane);
|
||||
$dashboard->removePane($pane->getTitle());
|
||||
$dashboardConfig = $dashboard->getConfig();
|
||||
try {
|
||||
$pane = $dashboard->getPane($pane);
|
||||
$dashboard->removePane($pane->getTitle());
|
||||
$dashboard->write();
|
||||
$dashboardConfig->saveIni();
|
||||
Notification::success(t('Dashboard has been removed') . ': ' . $pane->getTitle());
|
||||
return true;
|
||||
} catch (\Zend_Config_Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
$action->view->error = $e;
|
||||
$action->view->config = $dashboard->createWriter();
|
||||
$action->view->config = $dashboardConfig;
|
||||
$action->render('error');
|
||||
return false;
|
||||
} catch (ProgrammingError $e) {
|
||||
|
@ -213,6 +217,7 @@ class DashboardController extends ActionController
|
|||
}
|
||||
return false;
|
||||
});
|
||||
$form->setTitle($this->translate('Remove Dashboard'));
|
||||
$form->setRedirectUrl('dashboard/settings');
|
||||
$form->handleRequest();
|
||||
$this->view->pane = $pane;
|
||||
|
@ -241,14 +246,15 @@ class DashboardController extends ActionController
|
|||
$this->view->title = $this->dashboard->getActivePane()->getTitle() . ' :: Dashboard';
|
||||
if ($this->hasParam('remove')) {
|
||||
$this->dashboard->getActivePane()->removeDashlet($this->getParam('remove'));
|
||||
$this->dashboard->write();
|
||||
$this->dashboard->getConfig()->saveIni();
|
||||
$this->redirectNow(URL::fromRequest()->remove('remove'));
|
||||
}
|
||||
$this->view->tabs->add(
|
||||
'Add',
|
||||
array(
|
||||
'title' => '+',
|
||||
'url' => Url::fromPath('dashboard/new-dashlet')
|
||||
'label' => '+',
|
||||
'title' => 'Add a dashlet to an existing or new dashboard',
|
||||
'url' => Url::fromPath('dashboard/new-dashlet')
|
||||
)
|
||||
);
|
||||
$this->view->dashboard = $this->dashboard;
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
// namespace Icinga\Application\Controllers;
|
||||
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Web\Controller\ActionController;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Exception\Http\HttpMethodNotAllowedException;
|
||||
use Icinga\Exception\Http\HttpNotFoundException;
|
||||
use Icinga\Exception\MissingParameterException;
|
||||
use Icinga\Security\SecurityException;
|
||||
use Icinga\Web\Controller\ActionController;
|
||||
|
||||
/**
|
||||
* Application wide controller for displaying exceptions
|
||||
|
@ -36,7 +37,7 @@ class ErrorController extends ActionController
|
|||
$path = array_shift($path);
|
||||
$this->getResponse()->setHttpResponseCode(404);
|
||||
$this->view->message = $this->translate('Page not found.');
|
||||
if ($modules->hasInstalled($path) && ! $modules->hasEnabled($path)) {
|
||||
if ($this->Auth()->isAuthenticated() && $modules->hasInstalled($path) && ! $modules->hasEnabled($path)) {
|
||||
$this->view->message .= ' ' . sprintf(
|
||||
$this->translate('Enabling the "%s" module might help!'),
|
||||
$path
|
||||
|
@ -45,11 +46,30 @@ class ErrorController extends ActionController
|
|||
|
||||
break;
|
||||
default:
|
||||
$title = preg_replace('/\r?\n.*$/s', '', $exception->getMessage());
|
||||
$this->getResponse()->setHttpResponseCode(500);
|
||||
$this->view->title = 'Server error: ' . $title;
|
||||
switch (true) {
|
||||
case $exception instanceof HttpMethodNotAllowedException:
|
||||
$this->getResponse()->setHttpResponseCode(405);
|
||||
$this->getResponse()->setHeader('Allow', $exception->getAllowedMethods());
|
||||
break;
|
||||
case $exception instanceof HttpNotFoundException:
|
||||
$this->getResponse()->setHttpResponseCode(404);
|
||||
break;
|
||||
case $exception instanceof MissingParameterException:
|
||||
$this->getResponse()->setHttpResponseCode(400);
|
||||
$this->getResponse()->setHeader(
|
||||
'X-Status-Reason',
|
||||
'Missing parameter ' . $exception->getParameter()
|
||||
);
|
||||
break;
|
||||
case $exception instanceof SecurityException:
|
||||
$this->getResponse()->setHttpResponseCode(403);
|
||||
break;
|
||||
default:
|
||||
$this->getResponse()->setHttpResponseCode(500);
|
||||
break;
|
||||
}
|
||||
$this->view->message = $exception->getMessage();
|
||||
if ($this->getInvokeArg('displayExceptions') == true) {
|
||||
if ($this->getInvokeArg('displayExceptions')) {
|
||||
$this->view->stackTrace = $exception->getTraceAsString();
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
use Icinga\Web\Controller\ActionController;
|
||||
use Icinga\Filter\Filter;
|
||||
|
|
|
@ -0,0 +1,369 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Data\DataArray\ArrayDatasource;
|
||||
use Icinga\Data\Reducible;
|
||||
use Icinga\Data\Filter\Filter;
|
||||
use Icinga\Exception\NotFoundError;
|
||||
use Icinga\Forms\Config\UserGroup\AddMemberForm;
|
||||
use Icinga\Forms\Config\UserGroup\UserGroupForm;
|
||||
use Icinga\Web\Controller\AuthBackendController;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Web\Url;
|
||||
use Icinga\Web\Widget;
|
||||
|
||||
class GroupController extends AuthBackendController
|
||||
{
|
||||
/**
|
||||
* List all user groups of a single backend
|
||||
*/
|
||||
public function listAction()
|
||||
{
|
||||
$this->assertPermission('config/authentication/groups/show');
|
||||
$this->createListTabs()->activate('group/list');
|
||||
$backendNames = array_map(
|
||||
function ($b) { return $b->getName(); },
|
||||
$this->loadUserGroupBackends('Icinga\Data\Selectable')
|
||||
);
|
||||
if (empty($backendNames)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->view->backendSelection = new Form();
|
||||
$this->view->backendSelection->setAttrib('class', 'backend-selection');
|
||||
$this->view->backendSelection->setUidDisabled();
|
||||
$this->view->backendSelection->setMethod('GET');
|
||||
$this->view->backendSelection->setTokenDisabled();
|
||||
$this->view->backendSelection->addElement(
|
||||
'select',
|
||||
'backend',
|
||||
array(
|
||||
'autosubmit' => true,
|
||||
'label' => $this->translate('Usergroup Backend'),
|
||||
'multiOptions' => array_combine($backendNames, $backendNames),
|
||||
'value' => $this->params->get('backend')
|
||||
)
|
||||
);
|
||||
|
||||
$backend = $this->getUserGroupBackend($this->params->get('backend'));
|
||||
if ($backend === null) {
|
||||
$this->view->backend = null;
|
||||
return;
|
||||
}
|
||||
|
||||
$query = $backend->select(array('group_name'));
|
||||
$filterEditor = Widget::create('filterEditor')
|
||||
->setQuery($query)
|
||||
->setSearchColumns(array('group', 'user'))
|
||||
->preserveParams('limit', 'sort', 'dir', 'view', 'backend')
|
||||
->ignoreParams('page')
|
||||
->handleRequest($this->getRequest());
|
||||
$query->applyFilter($filterEditor->getFilter());
|
||||
$this->setupFilterControl($filterEditor);
|
||||
|
||||
$this->view->groups = $query;
|
||||
$this->view->backend = $backend;
|
||||
|
||||
$this->setupPaginationControl($query);
|
||||
$this->setupLimitControl();
|
||||
$this->setupSortControl(
|
||||
array(
|
||||
'group_name' => $this->translate('Group'),
|
||||
'created_at' => $this->translate('Created at'),
|
||||
'last_modified' => $this->translate('Last modified')
|
||||
),
|
||||
$query
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a group
|
||||
*/
|
||||
public function showAction()
|
||||
{
|
||||
$this->assertPermission('config/authentication/groups/show');
|
||||
$groupName = $this->params->getRequired('group');
|
||||
$backend = $this->getUserGroupBackend($this->params->getRequired('backend'));
|
||||
|
||||
$group = $backend->select(array(
|
||||
'group_name',
|
||||
'created_at',
|
||||
'last_modified'
|
||||
))->where('group_name', $groupName)->fetchRow();
|
||||
if ($group === false) {
|
||||
$this->httpNotFound(sprintf($this->translate('Group "%s" not found'), $groupName));
|
||||
}
|
||||
|
||||
$members = $backend
|
||||
->select()
|
||||
->from('group_membership', array('user_name'))
|
||||
->where('group_name', $groupName);
|
||||
|
||||
$filterEditor = Widget::create('filterEditor')
|
||||
->setQuery($members)
|
||||
->setSearchColumns(array('user'))
|
||||
->preserveParams('limit', 'sort', 'dir', 'view', 'backend', 'group')
|
||||
->ignoreParams('page')
|
||||
->handleRequest($this->getRequest());
|
||||
$members->applyFilter($filterEditor->getFilter());
|
||||
|
||||
$this->setupFilterControl($filterEditor);
|
||||
$this->setupPaginationControl($members);
|
||||
$this->setupLimitControl();
|
||||
$this->setupSortControl(
|
||||
array(
|
||||
'user_name' => $this->translate('Username'),
|
||||
'created_at' => $this->translate('Created at'),
|
||||
'last_modified' => $this->translate('Last modified')
|
||||
),
|
||||
$members
|
||||
);
|
||||
|
||||
$this->view->group = $group;
|
||||
$this->view->backend = $backend;
|
||||
$this->view->members = $members;
|
||||
$this->createShowTabs($backend->getName(), $groupName)->activate('group/show');
|
||||
|
||||
if ($this->hasPermission('config/authentication/groups/edit') && $backend instanceof Reducible) {
|
||||
$removeForm = new Form();
|
||||
$removeForm->setUidDisabled();
|
||||
$removeForm->setAction(
|
||||
Url::fromPath('group/removemember', array('backend' => $backend->getName(), 'group' => $groupName))
|
||||
);
|
||||
$removeForm->addElement('hidden', 'user_name', array(
|
||||
'isArray' => true,
|
||||
'decorators' => array('ViewHelper')
|
||||
));
|
||||
$removeForm->addElement('hidden', 'redirect', array(
|
||||
'value' => Url::fromPath('group/show', array(
|
||||
'backend' => $backend->getName(),
|
||||
'group' => $groupName
|
||||
)),
|
||||
'decorators' => array('ViewHelper')
|
||||
));
|
||||
$removeForm->addElement('button', 'btn_submit', array(
|
||||
'escape' => false,
|
||||
'type' => 'submit',
|
||||
'class' => 'link-like',
|
||||
'value' => 'btn_submit',
|
||||
'decorators' => array('ViewHelper'),
|
||||
'label' => $this->view->icon('trash'),
|
||||
'title' => $this->translate('Remove this member')
|
||||
));
|
||||
$this->view->removeForm = $removeForm;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a group
|
||||
*/
|
||||
public function addAction()
|
||||
{
|
||||
$this->assertPermission('config/authentication/groups/add');
|
||||
$backend = $this->getUserGroupBackend($this->params->getRequired('backend'), 'Icinga\Data\Extensible');
|
||||
$form = new UserGroupForm();
|
||||
$form->setRedirectUrl(Url::fromPath('group/list', array('backend' => $backend->getName())));
|
||||
$form->setRepository($backend);
|
||||
$form->add()->handleRequest();
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->render('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit a group
|
||||
*/
|
||||
public function editAction()
|
||||
{
|
||||
$this->assertPermission('config/authentication/groups/edit');
|
||||
$groupName = $this->params->getRequired('group');
|
||||
$backend = $this->getUserGroupBackend($this->params->getRequired('backend'), 'Icinga\Data\Updatable');
|
||||
|
||||
$form = new UserGroupForm();
|
||||
$form->setRedirectUrl(
|
||||
Url::fromPath('group/show', array('backend' => $backend->getName(), 'group' => $groupName))
|
||||
);
|
||||
$form->setRepository($backend);
|
||||
|
||||
try {
|
||||
$form->edit($groupName)->handleRequest();
|
||||
} catch (NotFoundError $_) {
|
||||
$this->httpNotFound(sprintf($this->translate('Group "%s" not found'), $groupName));
|
||||
}
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->render('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a group
|
||||
*/
|
||||
public function removeAction()
|
||||
{
|
||||
$this->assertPermission('config/authentication/groups/remove');
|
||||
$groupName = $this->params->getRequired('group');
|
||||
$backend = $this->getUserGroupBackend($this->params->getRequired('backend'), 'Icinga\Data\Reducible');
|
||||
|
||||
$form = new UserGroupForm();
|
||||
$form->setRedirectUrl(Url::fromPath('group/list', array('backend' => $backend->getName())));
|
||||
$form->setRepository($backend);
|
||||
|
||||
try {
|
||||
$form->remove($groupName)->handleRequest();
|
||||
} catch (NotFoundError $_) {
|
||||
$this->httpNotFound(sprintf($this->translate('Group "%s" not found'), $groupName));
|
||||
}
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->render('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a group member
|
||||
*/
|
||||
public function addmemberAction()
|
||||
{
|
||||
$this->assertPermission('config/authentication/groups/edit');
|
||||
$groupName = $this->params->getRequired('group');
|
||||
$backend = $this->getUserGroupBackend($this->params->getRequired('backend'), 'Icinga\Data\Extensible');
|
||||
|
||||
$form = new AddMemberForm();
|
||||
$form->setDataSource($this->fetchUsers())
|
||||
->setBackend($backend)
|
||||
->setGroupName($groupName)
|
||||
->setRedirectUrl(
|
||||
Url::fromPath('group/show', array('backend' => $backend->getName(), 'group' => $groupName))
|
||||
)
|
||||
->setUidDisabled();
|
||||
|
||||
try {
|
||||
$form->handleRequest();
|
||||
} catch (NotFoundError $_) {
|
||||
$this->httpNotFound(sprintf($this->translate('Group "%s" not found'), $groupName));
|
||||
}
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->render('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a group member
|
||||
*/
|
||||
public function removememberAction()
|
||||
{
|
||||
$this->assertPermission('config/authentication/groups/edit');
|
||||
$this->assertHttpMethod('POST');
|
||||
$groupName = $this->params->getRequired('group');
|
||||
$backend = $this->getUserGroupBackend($this->params->getRequired('backend'), 'Icinga\Data\Reducible');
|
||||
|
||||
$form = new Form(array(
|
||||
'onSuccess' => function ($form) use ($groupName, $backend) {
|
||||
foreach ($form->getValue('user_name') as $userName) {
|
||||
try {
|
||||
$backend->delete(
|
||||
'group_membership',
|
||||
Filter::matchAll(
|
||||
Filter::where('group_name', $groupName),
|
||||
Filter::where('user_name', $userName)
|
||||
)
|
||||
);
|
||||
Notification::success(sprintf(
|
||||
t('User "%s" has been removed from group "%s"'),
|
||||
$userName,
|
||||
$groupName
|
||||
));
|
||||
} catch (NotFoundError $e) {
|
||||
throw $e;
|
||||
} catch (Exception $e) {
|
||||
Notification::error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
$redirect = $form->getValue('redirect');
|
||||
if (! empty($redirect)) {
|
||||
$form->setRedirectUrl(htmlspecialchars_decode($redirect));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
));
|
||||
$form->setUidDisabled();
|
||||
$form->setSubmitLabel('btn_submit'); // Required to ensure that isSubmitted() is called
|
||||
$form->addElement('hidden', 'user_name', array('required' => true, 'isArray' => true));
|
||||
$form->addElement('hidden', 'redirect');
|
||||
|
||||
try {
|
||||
$form->handleRequest();
|
||||
} catch (NotFoundError $_) {
|
||||
$this->httpNotFound(sprintf($this->translate('Group "%s" not found'), $groupName));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and return all users from all user backends
|
||||
*
|
||||
* @return ArrayDatasource
|
||||
*/
|
||||
protected function fetchUsers()
|
||||
{
|
||||
$users = array();
|
||||
foreach ($this->loadUserBackends('Icinga\Data\Selectable') as $backend) {
|
||||
try {
|
||||
foreach ($backend->select(array('user_name')) as $row) {
|
||||
$users[] = $row;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
Logger::error($e);
|
||||
Notification::warning(sprintf(
|
||||
$this->translate('Failed to fetch any users from backend %s. Please check your log'),
|
||||
$backend->getName()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayDatasource($users);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the tabs to display when showing a group
|
||||
*
|
||||
* @param string $backendName
|
||||
* @param string $groupName
|
||||
*/
|
||||
protected function createShowTabs($backendName, $groupName)
|
||||
{
|
||||
$tabs = $this->getTabs();
|
||||
$tabs->add(
|
||||
'group/show',
|
||||
array(
|
||||
'title' => sprintf($this->translate('Show group %s'), $groupName),
|
||||
'label' => $this->translate('Group'),
|
||||
'icon' => 'users',
|
||||
'url' => Url::fromPath('group/show', array('backend' => $backendName, 'group' => $groupName))
|
||||
)
|
||||
);
|
||||
|
||||
return $tabs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the tabs to display when listing groups
|
||||
*/
|
||||
protected function createListTabs()
|
||||
{
|
||||
$tabs = $this->getTabs();
|
||||
$tabs->add(
|
||||
'group/list',
|
||||
array(
|
||||
'title' => $this->translate('List groups of user group backends'),
|
||||
'label' => $this->translate('Usergroups'),
|
||||
'icon' => 'users',
|
||||
'url' => 'group/list'
|
||||
)
|
||||
);
|
||||
|
||||
return $tabs;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
# namespace Icinga\Application\Controllers;
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
use Icinga\Web\MenuRenderer;
|
||||
use Icinga\Web\Controller\ActionController;
|
||||
|
@ -25,24 +24,4 @@ class LayoutController extends ActionController
|
|||
$menu = new MenuRenderer(Menu::load(), $url->getRelativeUrl());
|
||||
$this->view->menuRenderer = $menu->useCustomRenderer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the top bar
|
||||
*/
|
||||
public function topbarAction()
|
||||
{
|
||||
$topbarHtmlParts = array();
|
||||
|
||||
/** @var Hook\TopBarHook $hook */
|
||||
$hook = null;
|
||||
|
||||
foreach (Hook::all('TopBar') as $hook) {
|
||||
$topbarHtmlParts[] = $hook->getHtml($this->getRequest());
|
||||
}
|
||||
|
||||
$this->view->topbarHtmlParts = $topbarHtmlParts;
|
||||
|
||||
|
||||
$this->renderScript('parts/topbar.phtml');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
use Icinga\Module\Monitoring\Controller;
|
||||
use Icinga\Web\Url;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Protocol\File\FileReader;
|
||||
use \Zend_Controller_Action_Exception as ActionError;
|
||||
use Icinga\Web\Controller;
|
||||
use Icinga\Web\Url;
|
||||
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
||||
use Icinga\Web\Widget\Tabextension\OutputFormat;
|
||||
|
||||
/**
|
||||
* Class ListController
|
||||
|
@ -24,12 +25,12 @@ class ListController extends Controller
|
|||
protected function addTitleTab($action)
|
||||
{
|
||||
$this->getTabs()->add($action, array(
|
||||
'title' => ucfirst($action),
|
||||
'label' => ucfirst($action),
|
||||
'url' => Url::fromPath(
|
||||
'list/'
|
||||
. str_replace(' ', '', $action)
|
||||
)
|
||||
))->activate($action);
|
||||
))->extend(new OutputFormat())->extend(new DashboardAction())->activate($action);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -38,20 +39,20 @@ class ListController extends Controller
|
|||
public function applicationlogAction()
|
||||
{
|
||||
if (! Logger::writesToFile()) {
|
||||
throw new ActionError('Site not found', 404);
|
||||
$this->httpNotFound('Page not found');
|
||||
}
|
||||
|
||||
$this->addTitleTab('application log');
|
||||
$pattern = '/^(?<datetime>[0-9]{4}(-[0-9]{2}){2}' // date
|
||||
. 'T[0-9]{2}(:[0-9]{2}){2}([\\+\\-][0-9]{2}:[0-9]{2})?)' // time
|
||||
. ' - (?<loglevel>[A-Za-z]+)' // loglevel
|
||||
. ' - (?<message>.*)$/'; // message
|
||||
|
||||
$loggerWriter = Logger::getInstance()->getWriter();
|
||||
$resource = new FileReader(new ConfigObject(array(
|
||||
'filename' => $loggerWriter->getPath(),
|
||||
'fields' => $pattern
|
||||
'filename' => Config::app()->get('logging', 'file'),
|
||||
'fields' => '/(?<!.)(?<datetime>[0-9]{4}(?:-[0-9]{2}){2}' // date
|
||||
. 'T[0-9]{2}(?::[0-9]{2}){2}(?:[\+\-][0-9]{2}:[0-9]{2})?)' // time
|
||||
. ' - (?<loglevel>[A-Za-z]+) - (?<message>.*)(?!.)/msS' // loglevel, message
|
||||
)));
|
||||
$this->view->logData = $resource->select()->order('DESC')->paginate();
|
||||
$this->view->logData = $resource->select()->order('DESC');
|
||||
|
||||
$this->setupLimitControl();
|
||||
$this->setupPaginationControl($this->view->logData);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
use Icinga\Web\Controller\BasePreferenceController;
|
||||
use Icinga\Web\Url;
|
||||
use Icinga\Web\Widget\Tab;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Forms\PreferenceForm;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\User\Preferences\PreferencesStore;
|
||||
|
||||
/**
|
||||
|
@ -27,8 +26,9 @@ class PreferenceController extends BasePreferenceController
|
|||
return array(
|
||||
'preferences' => new Tab(
|
||||
array(
|
||||
'title' => t('Preferences'),
|
||||
'url' => Url::fromPath('/preference')
|
||||
'title' => t('Adjust the preferences of Icinga Web 2 according to your needs'),
|
||||
'label' => t('Preferences'),
|
||||
'url' => Url::fromPath('/preference')
|
||||
)
|
||||
)
|
||||
);
|
||||
|
@ -39,15 +39,17 @@ class PreferenceController extends BasePreferenceController
|
|||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
$storeConfig = Config::app()->getSection('preferences');
|
||||
if ($storeConfig->isEmpty()) {
|
||||
throw new ConfigurationError(t('You need to configure how to store preferences first.'));
|
||||
}
|
||||
|
||||
$config = Config::app()->getSection('global');
|
||||
$user = $this->getRequest()->getUser();
|
||||
|
||||
$form = new PreferenceForm();
|
||||
$form->setPreferences($user->getPreferences());
|
||||
$form->setStore(PreferencesStore::create($storeConfig, $user));
|
||||
if ($config->get('config_backend', 'ini') !== 'none') {
|
||||
$form->setStore(PreferencesStore::create(new ConfigObject(array(
|
||||
'store' => $config->get('config_backend', 'ini'),
|
||||
'resource' => $config->config_resource
|
||||
)), $user));
|
||||
}
|
||||
$form->handleRequest();
|
||||
|
||||
$this->view->form = $form;
|
||||
|
|
|
@ -1,41 +1,30 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Forms\ConfirmRemovalForm;
|
||||
use Icinga\Forms\Security\RoleForm;
|
||||
use Icinga\Web\Controller\ActionController;
|
||||
use Icinga\Web\Controller\AuthBackendController;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Web\Widget;
|
||||
|
||||
class RolesController extends ActionController
|
||||
class RoleController extends AuthBackendController
|
||||
{
|
||||
public function init()
|
||||
/**
|
||||
* List roles
|
||||
*/
|
||||
public function listAction()
|
||||
{
|
||||
$this->view->tabs = Widget::create('tabs')->add('index', array(
|
||||
'title' => $this->translate('Application'),
|
||||
'url' => 'config'
|
||||
))->add('authentication', array(
|
||||
'title' => $this->translate('Authentication'),
|
||||
'url' => 'config/authentication'
|
||||
))->add('resources', array(
|
||||
'title' => $this->translate('Resources'),
|
||||
'url' => 'config/resource'
|
||||
))->add('roles', array(
|
||||
'title' => $this->translate('Roles'),
|
||||
'url' => 'roles'
|
||||
));
|
||||
}
|
||||
|
||||
public function indexAction()
|
||||
{
|
||||
$this->view->tabs->activate('roles');
|
||||
$this->assertPermission('config/authentication/roles/show');
|
||||
$this->createListTabs()->activate('role/list');
|
||||
$this->view->roles = Config::app('roles', true);
|
||||
}
|
||||
|
||||
public function newAction()
|
||||
/**
|
||||
* Create a new role
|
||||
*/
|
||||
public function addAction()
|
||||
{
|
||||
$this->assertPermission('config/authentication/roles/add');
|
||||
$role = new RoleForm(array(
|
||||
'onSuccess' => function (RoleForm $role) {
|
||||
$name = $role->getElement('name')->getValue();
|
||||
|
@ -54,15 +43,23 @@ class RolesController extends ActionController
|
|||
}
|
||||
));
|
||||
$role
|
||||
->setTitle($this->translate('New Role'))
|
||||
->setSubmitLabel($this->translate('Create Role'))
|
||||
->setIniConfig(Config::app('roles', true))
|
||||
->setRedirectUrl('roles')
|
||||
->setRedirectUrl('role/list')
|
||||
->handleRequest();
|
||||
$this->view->form = $role;
|
||||
$this->render('form');
|
||||
}
|
||||
|
||||
public function updateAction()
|
||||
/**
|
||||
* Update a role
|
||||
*
|
||||
* @throws Zend_Controller_Action_Exception If the required parameter 'role' is missing or the role does not exist
|
||||
*/
|
||||
public function editAction()
|
||||
{
|
||||
$this->assertPermission('config/authentication/roles/edit');
|
||||
$name = $this->_request->getParam('role');
|
||||
if (empty($name)) {
|
||||
throw new Zend_Controller_Action_Exception(
|
||||
|
@ -71,6 +68,7 @@ class RolesController extends ActionController
|
|||
);
|
||||
}
|
||||
$role = new RoleForm();
|
||||
$role->setTitle(sprintf($this->translate('Update Role %s'), $name));
|
||||
$role->setSubmitLabel($this->translate('Update Role'));
|
||||
try {
|
||||
$role
|
||||
|
@ -99,14 +97,20 @@ class RolesController extends ActionController
|
|||
}
|
||||
return false;
|
||||
})
|
||||
->setRedirectUrl('roles')
|
||||
->setRedirectUrl('role/list')
|
||||
->handleRequest();
|
||||
$this->view->name = $name;
|
||||
$this->view->form = $role;
|
||||
$this->render('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a role
|
||||
*
|
||||
* @throws Zend_Controller_Action_Exception If the required parameter 'role' is missing or the role does not exist
|
||||
*/
|
||||
public function removeAction()
|
||||
{
|
||||
$this->assertPermission('config/authentication/roles/remove');
|
||||
$name = $this->_request->getParam('role');
|
||||
if (empty($name)) {
|
||||
throw new Zend_Controller_Action_Exception(
|
||||
|
@ -141,10 +145,32 @@ class RolesController extends ActionController
|
|||
}
|
||||
));
|
||||
$confirmation
|
||||
->setTitle(sprintf($this->translate('Remove Role %s'), $name))
|
||||
->setSubmitLabel($this->translate('Remove Role'))
|
||||
->setRedirectUrl('roles')
|
||||
->setRedirectUrl('role/list')
|
||||
->handleRequest();
|
||||
$this->view->name = $name;
|
||||
$this->view->form = $confirmation;
|
||||
$this->render('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the tabs to display when listing roles
|
||||
*/
|
||||
protected function createListTabs()
|
||||
{
|
||||
$tabs = $this->getTabs();
|
||||
$tabs->add(
|
||||
'role/list',
|
||||
array(
|
||||
'title' => $this->translate(
|
||||
'Configure roles to permit or restrict users and groups accessing Icinga Web 2'
|
||||
),
|
||||
'label' => $this->translate('Roles'),
|
||||
'url' => 'role/list',
|
||||
'baseTarget' => '_main'
|
||||
)
|
||||
);
|
||||
|
||||
return $tabs;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
use Icinga\Web\Controller\ActionController;
|
||||
use Icinga\Web\Widget;
|
||||
|
@ -13,7 +12,9 @@ class SearchController extends ActionController
|
|||
{
|
||||
public function indexAction()
|
||||
{
|
||||
$this->view->dashboard = SearchDashboard::search($this->params->get('q'));
|
||||
$searchDashboard = new SearchDashboard();
|
||||
$searchDashboard->setUser($this->Auth()->getUser());
|
||||
$this->view->dashboard = $searchDashboard->search($this->params->get('q'));
|
||||
|
||||
// NOTE: This renders the dashboard twice. Remove this once we can catch exceptions thrown in view scripts.
|
||||
$this->view->dashboard->render();
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
use Icinga\Web\Controller\ActionController;
|
||||
use Icinga\Application\Icinga;
|
||||
|
|
|
@ -0,0 +1,328 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Exception\NotFoundError;
|
||||
use Icinga\Forms\Config\User\CreateMembershipForm;
|
||||
use Icinga\Forms\Config\User\UserForm;
|
||||
use Icinga\Data\DataArray\ArrayDatasource;
|
||||
use Icinga\User;
|
||||
use Icinga\Web\Controller\AuthBackendController;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Web\Url;
|
||||
use Icinga\Web\Widget;
|
||||
|
||||
class UserController extends AuthBackendController
|
||||
{
|
||||
/**
|
||||
* List all users of a single backend
|
||||
*/
|
||||
public function listAction()
|
||||
{
|
||||
$this->assertPermission('config/authentication/users/show');
|
||||
$this->createListTabs()->activate('user/list');
|
||||
$backendNames = array_map(
|
||||
function ($b) { return $b->getName(); },
|
||||
$this->loadUserBackends('Icinga\Data\Selectable')
|
||||
);
|
||||
if (empty($backendNames)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->view->backendSelection = new Form();
|
||||
$this->view->backendSelection->setAttrib('class', 'backend-selection');
|
||||
$this->view->backendSelection->setUidDisabled();
|
||||
$this->view->backendSelection->setMethod('GET');
|
||||
$this->view->backendSelection->setTokenDisabled();
|
||||
$this->view->backendSelection->addElement(
|
||||
'select',
|
||||
'backend',
|
||||
array(
|
||||
'autosubmit' => true,
|
||||
'label' => $this->translate('Authentication Backend'),
|
||||
'multiOptions' => array_combine($backendNames, $backendNames),
|
||||
'value' => $this->params->get('backend')
|
||||
)
|
||||
);
|
||||
|
||||
$backend = $this->getUserBackend($this->params->get('backend'));
|
||||
if ($backend === null) {
|
||||
$this->view->backend = null;
|
||||
return;
|
||||
}
|
||||
|
||||
$query = $backend->select(array('user_name'));
|
||||
$filterEditor = Widget::create('filterEditor')
|
||||
->setQuery($query)
|
||||
->setSearchColumns(array('user'))
|
||||
->preserveParams('limit', 'sort', 'dir', 'view', 'backend')
|
||||
->ignoreParams('page')
|
||||
->handleRequest($this->getRequest());
|
||||
$query->applyFilter($filterEditor->getFilter());
|
||||
$this->setupFilterControl($filterEditor);
|
||||
|
||||
$this->view->users = $query;
|
||||
$this->view->backend = $backend;
|
||||
|
||||
$this->setupPaginationControl($query);
|
||||
$this->setupLimitControl();
|
||||
$this->setupSortControl(
|
||||
array(
|
||||
'user_name' => $this->translate('Username'),
|
||||
'is_active' => $this->translate('Active'),
|
||||
'created_at' => $this->translate('Created at'),
|
||||
'last_modified' => $this->translate('Last modified')
|
||||
),
|
||||
$query
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a user
|
||||
*/
|
||||
public function showAction()
|
||||
{
|
||||
$this->assertPermission('config/authentication/users/show');
|
||||
$userName = $this->params->getRequired('user');
|
||||
$backend = $this->getUserBackend($this->params->getRequired('backend'));
|
||||
|
||||
$user = $backend->select(array(
|
||||
'user_name',
|
||||
'is_active',
|
||||
'created_at',
|
||||
'last_modified'
|
||||
))->where('user_name', $userName)->fetchRow();
|
||||
if ($user === false) {
|
||||
$this->httpNotFound(sprintf($this->translate('User "%s" not found'), $userName));
|
||||
}
|
||||
|
||||
$memberships = $this->loadMemberships(new User($userName))->select();
|
||||
|
||||
$filterEditor = Widget::create('filterEditor')
|
||||
->setQuery($memberships)
|
||||
->setSearchColumns(array('group_name'))
|
||||
->preserveParams('limit', 'sort', 'dir', 'view', 'backend', 'user')
|
||||
->ignoreParams('page')
|
||||
->handleRequest($this->getRequest());
|
||||
$memberships->applyFilter($filterEditor->getFilter());
|
||||
|
||||
$this->setupFilterControl($filterEditor);
|
||||
$this->setupPaginationControl($memberships);
|
||||
$this->setupLimitControl();
|
||||
$this->setupSortControl(
|
||||
array(
|
||||
'group_name' => $this->translate('Group')
|
||||
),
|
||||
$memberships
|
||||
);
|
||||
|
||||
if ($this->hasPermission('config/authentication/groups/edit')) {
|
||||
$extensibleBackends = $this->loadUserGroupBackends('Icinga\Data\Extensible');
|
||||
$this->view->showCreateMembershipLink = ! empty($extensibleBackends);
|
||||
} else {
|
||||
$this->view->showCreateMembershipLink = false;
|
||||
}
|
||||
|
||||
$this->view->user = $user;
|
||||
$this->view->backend = $backend;
|
||||
$this->view->memberships = $memberships;
|
||||
$this->createShowTabs($backend->getName(), $userName)->activate('user/show');
|
||||
|
||||
if ($this->hasPermission('config/authentication/groups/edit')) {
|
||||
$removeForm = new Form();
|
||||
$removeForm->setUidDisabled();
|
||||
$removeForm->addElement('hidden', 'user_name', array(
|
||||
'isArray' => true,
|
||||
'value' => $userName,
|
||||
'decorators' => array('ViewHelper')
|
||||
));
|
||||
$removeForm->addElement('hidden', 'redirect', array(
|
||||
'value' => Url::fromPath('user/show', array(
|
||||
'backend' => $backend->getName(),
|
||||
'user' => $userName
|
||||
)),
|
||||
'decorators' => array('ViewHelper')
|
||||
));
|
||||
$removeForm->addElement('button', 'btn_submit', array(
|
||||
'escape' => false,
|
||||
'type' => 'submit',
|
||||
'class' => 'link-like',
|
||||
'value' => 'btn_submit',
|
||||
'decorators' => array('ViewHelper'),
|
||||
'label' => $this->view->icon('trash'),
|
||||
'title' => $this->translate('Cancel this membership')
|
||||
));
|
||||
$this->view->removeForm = $removeForm;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a user
|
||||
*/
|
||||
public function addAction()
|
||||
{
|
||||
$this->assertPermission('config/authentication/users/add');
|
||||
$backend = $this->getUserBackend($this->params->getRequired('backend'), 'Icinga\Data\Extensible');
|
||||
$form = new UserForm();
|
||||
$form->setRedirectUrl(Url::fromPath('user/list', array('backend' => $backend->getName())));
|
||||
$form->setRepository($backend);
|
||||
$form->add()->handleRequest();
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->render('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit a user
|
||||
*/
|
||||
public function editAction()
|
||||
{
|
||||
$this->assertPermission('config/authentication/users/edit');
|
||||
$userName = $this->params->getRequired('user');
|
||||
$backend = $this->getUserBackend($this->params->getRequired('backend'), 'Icinga\Data\Updatable');
|
||||
|
||||
$form = new UserForm();
|
||||
$form->setRedirectUrl(Url::fromPath('user/show', array('backend' => $backend->getName(), 'user' => $userName)));
|
||||
$form->setRepository($backend);
|
||||
|
||||
try {
|
||||
$form->edit($userName)->handleRequest();
|
||||
} catch (NotFoundError $_) {
|
||||
$this->httpNotFound(sprintf($this->translate('User "%s" not found'), $userName));
|
||||
}
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->render('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a user
|
||||
*/
|
||||
public function removeAction()
|
||||
{
|
||||
$this->assertPermission('config/authentication/users/remove');
|
||||
$userName = $this->params->getRequired('user');
|
||||
$backend = $this->getUserBackend($this->params->getRequired('backend'), 'Icinga\Data\Reducible');
|
||||
|
||||
$form = new UserForm();
|
||||
$form->setRedirectUrl(Url::fromPath('user/list', array('backend' => $backend->getName())));
|
||||
$form->setRepository($backend);
|
||||
|
||||
try {
|
||||
$form->remove($userName)->handleRequest();
|
||||
} catch (NotFoundError $_) {
|
||||
$this->httpNotFound(sprintf($this->translate('User "%s" not found'), $userName));
|
||||
}
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->render('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a membership for a user
|
||||
*/
|
||||
public function createmembershipAction()
|
||||
{
|
||||
$this->assertPermission('config/authentication/groups/edit');
|
||||
$userName = $this->params->getRequired('user');
|
||||
$backend = $this->getUserBackend($this->params->getRequired('backend'));
|
||||
|
||||
if ($backend->select()->where('user_name', $userName)->count() === 0) {
|
||||
$this->httpNotFound(sprintf($this->translate('User "%s" not found'), $userName));
|
||||
}
|
||||
|
||||
$backends = $this->loadUserGroupBackends('Icinga\Data\Extensible');
|
||||
if (empty($backends)) {
|
||||
throw new ConfigurationError($this->translate(
|
||||
'You\'ll need to configure at least one user group backend first that allows to create new memberships'
|
||||
));
|
||||
}
|
||||
|
||||
$form = new CreateMembershipForm();
|
||||
$form->setBackends($backends)
|
||||
->setUsername($userName)
|
||||
->setRedirectUrl(Url::fromPath('user/show', array('backend' => $backend->getName(), 'user' => $userName)))
|
||||
->handleRequest();
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->render('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and return the given user's groups from all user group backends
|
||||
*
|
||||
* @param User $user
|
||||
*
|
||||
* @return ArrayDatasource
|
||||
*/
|
||||
protected function loadMemberships(User $user)
|
||||
{
|
||||
$groups = $alreadySeen = array();
|
||||
foreach ($this->loadUserGroupBackends() as $backend) {
|
||||
try {
|
||||
foreach ($backend->getMemberships($user) as $groupName) {
|
||||
if (array_key_exists($groupName, $alreadySeen)) {
|
||||
continue; // Ignore duplicate memberships
|
||||
}
|
||||
|
||||
$alreadySeen[$groupName] = null;
|
||||
$groups[] = (object) array(
|
||||
'group_name' => $groupName,
|
||||
'backend' => $backend
|
||||
);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
Logger::error($e);
|
||||
Notification::warning(sprintf(
|
||||
$this->translate('Failed to fetch memberships from backend %s. Please check your log'),
|
||||
$backend->getName()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayDatasource($groups);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the tabs to display when showing a user
|
||||
*
|
||||
* @param string $backendName
|
||||
* @param string $userName
|
||||
*/
|
||||
protected function createShowTabs($backendName, $userName)
|
||||
{
|
||||
$tabs = $this->getTabs();
|
||||
$tabs->add(
|
||||
'user/show',
|
||||
array(
|
||||
'title' => sprintf($this->translate('Show user %s'), $userName),
|
||||
'label' => $this->translate('User'),
|
||||
'icon' => 'user',
|
||||
'url' => Url::fromPath('user/show', array('backend' => $backendName, 'user' => $userName))
|
||||
)
|
||||
);
|
||||
|
||||
return $tabs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the tabs to display when listing users
|
||||
*/
|
||||
protected function createListTabs()
|
||||
{
|
||||
$tabs = $this->getTabs();
|
||||
$tabs->add(
|
||||
'user/list',
|
||||
array(
|
||||
'title' => $this->translate('List users of authentication backends'),
|
||||
'label' => $this->translate('Users'),
|
||||
'icon' => 'user',
|
||||
'url' => 'user/list'
|
||||
)
|
||||
);
|
||||
|
||||
return $tabs;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Exception\NotFoundError;
|
||||
use Icinga\Forms\ConfirmRemovalForm;
|
||||
use Icinga\Forms\Config\UserGroup\UserGroupBackendForm;
|
||||
use Icinga\Web\Controller;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Web\Url;
|
||||
|
||||
/**
|
||||
* Controller to configure user group backends
|
||||
*/
|
||||
class UsergroupbackendController extends Controller
|
||||
{
|
||||
/**
|
||||
* Initialize this controller
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->assertPermission('config/application/usergroupbackend');
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to this controller's list action
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
$this->redirectNow('usergroupbackend/list');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a list of all user group backends
|
||||
*/
|
||||
public function listAction()
|
||||
{
|
||||
$this->view->backendNames = Config::app('groups')->keys();
|
||||
$this->createListTabs()->activate('usergroupbackend');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new user group backend
|
||||
*/
|
||||
public function createAction()
|
||||
{
|
||||
$form = new UserGroupBackendForm();
|
||||
$form->setRedirectUrl('usergroupbackend/list');
|
||||
$form->setTitle($this->translate('Create New User Group Backend'));
|
||||
$form->addDescription($this->translate('Create a new backend to associate users and groups with.'));
|
||||
$form->setIniConfig(Config::app('groups'));
|
||||
$form->setOnSuccess(function (UserGroupBackendForm $form) {
|
||||
try {
|
||||
$form->add(array_filter($form->getValues()));
|
||||
} catch (Exception $e) {
|
||||
$form->error($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($form->save()) {
|
||||
Notification::success(t('User group backend successfully created'));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
$form->handleRequest();
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->render('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit an user group backend
|
||||
*/
|
||||
public function editAction()
|
||||
{
|
||||
$backendName = $this->params->getRequired('backend');
|
||||
|
||||
$form = new UserGroupBackendForm();
|
||||
$form->setRedirectUrl('usergroupbackend/list');
|
||||
$form->setTitle(sprintf($this->translate('Edit User Group Backend %s'), $backendName));
|
||||
$form->setIniConfig(Config::app('groups'));
|
||||
$form->setOnSuccess(function (UserGroupBackendForm $form) use ($backendName) {
|
||||
try {
|
||||
$form->edit($backendName, array_map(
|
||||
function ($v) {
|
||||
return $v !== '' ? $v : null;
|
||||
},
|
||||
$form->getValues()
|
||||
));
|
||||
} catch (Exception $e) {
|
||||
$form->error($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($form->save()) {
|
||||
Notification::success(sprintf(t('User group backend "%s" successfully updated'), $backendName));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
try {
|
||||
$form->load($backendName);
|
||||
$form->handleRequest();
|
||||
} catch (NotFoundError $_) {
|
||||
$this->httpNotFound(sprintf($this->translate('User group backend "%s" not found'), $backendName));
|
||||
}
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->render('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a user group backend
|
||||
*/
|
||||
public function removeAction()
|
||||
{
|
||||
$backendName = $this->params->getRequired('backend');
|
||||
|
||||
$backendForm = new UserGroupBackendForm();
|
||||
$backendForm->setIniConfig(Config::app('groups'));
|
||||
$form = new ConfirmRemovalForm();
|
||||
$form->setRedirectUrl('usergroupbackend/list');
|
||||
$form->setTitle(sprintf($this->translate('Remove User Group Backend %s'), $backendName));
|
||||
$form->setOnSuccess(function (ConfirmRemovalForm $form) use ($backendName, $backendForm) {
|
||||
try {
|
||||
$backendForm->delete($backendName);
|
||||
} catch (Exception $e) {
|
||||
$form->error($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($backendForm->save()) {
|
||||
Notification::success(sprintf(t('User group backend "%s" successfully removed'), $backendName));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
$form->handleRequest();
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->render('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the tabs for the application configuration
|
||||
*/
|
||||
protected function createListTabs()
|
||||
{
|
||||
$tabs = $this->getTabs();
|
||||
$tabs->add('userbackend', array(
|
||||
'title' => $this->translate('Configure how users authenticate with and log into Icinga Web 2'),
|
||||
'label' => $this->translate('User Backends'),
|
||||
'url' => 'config/userbackend'
|
||||
));
|
||||
$tabs->add('usergroupbackend', array(
|
||||
'title' => $this->translate('Configure how users are associated with groups by Icinga Web 2'),
|
||||
'label' => $this->translate('User Group Backends'),
|
||||
'url' => 'usergroupbackend/list'
|
||||
));
|
||||
return $tabs;
|
||||
}
|
||||
}
|
|
@ -37,3 +37,21 @@ Font license info
|
|||
Homepage: http://www.entypo.com
|
||||
|
||||
|
||||
## Fontelico
|
||||
|
||||
Copyright (C) 2012 by Fontello project
|
||||
|
||||
Author: Crowdsourced, for Fontello project
|
||||
License: SIL (http://scripts.sil.org/OFL)
|
||||
Homepage: http://fontello.com
|
||||
|
||||
|
||||
## Typicons
|
||||
|
||||
(c) Stephen Hutchings 2012
|
||||
|
||||
Author: Stephen Hutchings
|
||||
License: SIL (http://scripts.sil.org/OFL)
|
||||
Homepage: http://typicons.com/
|
||||
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ webfont pack. Details available in LICENSE.txt file.
|
|||
- If your project is open-source, usually, it will be ok to make LICENSE.txt
|
||||
file publically available in your repository.
|
||||
|
||||
- Fonts, used in Fontello, don't require to make clickable links on your site.
|
||||
- Fonts, used in Fontello, don't require a clickable link on your site.
|
||||
But any kind of additional authors crediting is welcome.
|
||||
================================================================================
|
||||
|
||||
|
@ -29,8 +29,8 @@ Comments on archive content
|
|||
|
||||
- LICENSE.txt - license info about source fonts, used to build your one.
|
||||
|
||||
- config.json - keeps your settings. You can import it back to fontello anytime,
|
||||
to continue your work
|
||||
- config.json - keeps your settings. You can import it back into fontello
|
||||
anytime, to continue your work
|
||||
|
||||
|
||||
Why so many CSS files ?
|
||||
|
@ -38,17 +38,17 @@ Why so many CSS files ?
|
|||
|
||||
Because we like to fit all your needs :)
|
||||
|
||||
- basic file, <your_font_name>.css - is usually enougth, in contains @font-face
|
||||
and character codes definition
|
||||
- basic file, <your_font_name>.css - is usually enough, it contains @font-face
|
||||
and character code definitions
|
||||
|
||||
- *-ie7.css - if you need IE7 support, but still don't wish to put char codes
|
||||
directly into html
|
||||
|
||||
- *-codes.css and *-ie7-codes.css - if you like to use your own @font-face
|
||||
rules, but still wish to benefit of css generation. That can be very
|
||||
convenient for automated assets build systems. When you need to update font -
|
||||
no needs to manually edit files, just override old version with archive
|
||||
content. See fontello source codes for example.
|
||||
rules, but still wish to benefit from css generation. That can be very
|
||||
convenient for automated asset build systems. When you need to update font -
|
||||
no need to manually edit files, just override old version with archive
|
||||
content. See fontello source code for examples.
|
||||
|
||||
- *-embedded.css - basic css file, but with embedded WOFF font, to avoid
|
||||
CORS issues in Firefox and IE9+, when fonts are hosted on the separate domain.
|
||||
|
@ -63,11 +63,11 @@ Because we like to fit all your needs :)
|
|||
Attention for server setup
|
||||
--------------------------
|
||||
|
||||
You MUST setup server to reply with proper `mime-types` for font files. In other
|
||||
case, some browsers will fail to show fonts.
|
||||
You MUST setup server to reply with proper `mime-types` for font files -
|
||||
otherwise some browsers will fail to show fonts.
|
||||
|
||||
Usually, `apache` already has necessary settings, but `nginx` and other
|
||||
webservers should be tuned. Here is list of mime types for our file extentions:
|
||||
webservers should be tuned. Here is list of mime types for our file extensions:
|
||||
|
||||
- `application/vnd.ms-fontobject` - eot
|
||||
- `application/x-font-woff` - woff
|
||||
|
|
|
@ -6,6 +6,12 @@
|
|||
"units_per_em": 1000,
|
||||
"ascent": 850,
|
||||
"glyphs": [
|
||||
{
|
||||
"uid": "9bc2902722abb366a213a052ade360bc",
|
||||
"css": "spin6",
|
||||
"code": 59508,
|
||||
"src": "fontelico"
|
||||
},
|
||||
{
|
||||
"uid": "9dd9e835aebe1060ba7190ad2b2ed951",
|
||||
"css": "search",
|
||||
|
@ -666,6 +672,30 @@
|
|||
"code": 59492,
|
||||
"src": "entypo"
|
||||
},
|
||||
{
|
||||
"uid": "c16a63e911bc47b46dc2a7129d2f0c46",
|
||||
"css": "down-small",
|
||||
"code": 59509,
|
||||
"src": "typicons"
|
||||
},
|
||||
{
|
||||
"uid": "58b78b6ca784d5c3db5beefcd9e18061",
|
||||
"css": "left-small",
|
||||
"code": 59510,
|
||||
"src": "typicons"
|
||||
},
|
||||
{
|
||||
"uid": "877a233d7fdca8a1d82615b96ed0d7a2",
|
||||
"css": "right-small",
|
||||
"code": 59511,
|
||||
"src": "typicons"
|
||||
},
|
||||
{
|
||||
"uid": "62bc6fe2a82e4864e2b94d4c0985ee0c",
|
||||
"css": "up-small",
|
||||
"code": 59512,
|
||||
"src": "typicons"
|
||||
},
|
||||
{
|
||||
"uid": "b90d80c250a9bbdd6cd3fe00e6351710",
|
||||
"css": "ok",
|
||||
|
|
|
@ -114,4 +114,9 @@
|
|||
.icon-chart-area:before { content: '\e870'; } /* '' */
|
||||
.icon-chart-bar:before { content: '\e871'; } /* '' */
|
||||
.icon-beaker:before { content: '\e872'; } /* '' */
|
||||
.icon-magic:before { content: '\e873'; } /* '' */
|
||||
.icon-magic:before { content: '\e873'; } /* '' */
|
||||
.icon-spin6:before { content: '\e874'; } /* '' */
|
||||
.icon-down-small:before { content: '\e875'; } /* '' */
|
||||
.icon-left-small:before { content: '\e876'; } /* '' */
|
||||
.icon-right-small:before { content: '\e877'; } /* '' */
|
||||
.icon-up-small:before { content: '\e878'; } /* '' */
|
File diff suppressed because one or more lines are too long
|
@ -114,4 +114,9 @@
|
|||
.icon-chart-area { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-chart-bar { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-beaker { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-magic { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-magic { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-spin6 { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-down-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-left-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-right-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-up-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
|
@ -125,4 +125,9 @@
|
|||
.icon-chart-area { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-chart-bar { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-beaker { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-magic { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-magic { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-spin6 { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-down-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-left-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-right-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
||||
.icon-up-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
|
|
@ -1,10 +1,10 @@
|
|||
@font-face {
|
||||
font-family: 'ifont';
|
||||
src: url('../font/ifont.eot?81587324');
|
||||
src: url('../font/ifont.eot?81587324#iefix') format('embedded-opentype'),
|
||||
url('../font/ifont.woff?81587324') format('woff'),
|
||||
url('../font/ifont.ttf?81587324') format('truetype'),
|
||||
url('../font/ifont.svg?81587324#ifont') format('svg');
|
||||
src: url('../font/ifont.eot?54745533');
|
||||
src: url('../font/ifont.eot?54745533#iefix') format('embedded-opentype'),
|
||||
url('../font/ifont.woff?54745533') format('woff'),
|
||||
url('../font/ifont.ttf?54745533') format('truetype'),
|
||||
url('../font/ifont.svg?54745533#ifont') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
|||
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||
@font-face {
|
||||
font-family: 'ifont';
|
||||
src: url('../font/ifont.svg?81587324#ifont') format('svg');
|
||||
src: url('../font/ifont.svg?54745533#ifont') format('svg');
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
@ -35,7 +35,7 @@
|
|||
/* For safety - reset parent styles, that can break glyph codes*/
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
|
||||
|
||||
/* fix buttons height, for twitter bootstrap */
|
||||
line-height: 1em;
|
||||
|
||||
|
@ -46,6 +46,10 @@
|
|||
/* you can be more comfortable with increased icons size */
|
||||
/* font-size: 120%; */
|
||||
|
||||
/* Font smoothing. That was taken from TWBS */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
|
||||
/* Uncomment for 3D effect */
|
||||
/* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
|
||||
}
|
||||
|
@ -165,4 +169,9 @@
|
|||
.icon-chart-area:before { content: '\e870'; } /* '' */
|
||||
.icon-chart-bar:before { content: '\e871'; } /* '' */
|
||||
.icon-beaker:before { content: '\e872'; } /* '' */
|
||||
.icon-magic:before { content: '\e873'; } /* '' */
|
||||
.icon-magic:before { content: '\e873'; } /* '' */
|
||||
.icon-spin6:before { content: '\e874'; } /* '' */
|
||||
.icon-down-small:before { content: '\e875'; } /* '' */
|
||||
.icon-left-small:before { content: '\e876'; } /* '' */
|
||||
.icon-right-small:before { content: '\e877'; } /* '' */
|
||||
.icon-up-small:before { content: '\e878'; } /* '' */
|
|
@ -227,8 +227,54 @@ body {
|
|||
.i-code {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="css/ifont.css">
|
||||
@font-face {
|
||||
font-family: 'ifont';
|
||||
src: url('./font/ifont.eot?11424534');
|
||||
src: url('./font/ifont.eot?11424534#iefix') format('embedded-opentype'),
|
||||
url('./font/ifont.woff?11424534') format('woff'),
|
||||
url('./font/ifont.ttf?11424534') format('truetype'),
|
||||
url('./font/ifont.svg?11424534#ifont') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
|
||||
.demo-icon
|
||||
{
|
||||
font-family: "ifont";
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
speak: none;
|
||||
|
||||
display: inline-block;
|
||||
text-decoration: inherit;
|
||||
width: 1em;
|
||||
margin-right: .2em;
|
||||
text-align: center;
|
||||
/* opacity: .8; */
|
||||
|
||||
/* For safety - reset parent styles, that can break glyph codes*/
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
|
||||
/* fix buttons height, for twitter bootstrap */
|
||||
line-height: 1em;
|
||||
|
||||
/* Animation center compensation - margins should be symmetric */
|
||||
/* remove if not needed */
|
||||
margin-left: .2em;
|
||||
|
||||
/* You can be more comfortable with increased icons size */
|
||||
/* font-size: 120%; */
|
||||
|
||||
/* Font smoothing. That was taken from TWBS */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
|
||||
/* Uncomment for 3D effect */
|
||||
/* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="css/animation.css"><!--[if IE 7]><link rel="stylesheet" href="css/ifont-ie7.css"><![endif]-->
|
||||
<script>
|
||||
function toggleCodes(on) {
|
||||
|
@ -255,178 +301,187 @@ body {
|
|||
</div>
|
||||
<div id="icons" class="container">
|
||||
<div class="row">
|
||||
<div title="Code: 0xe800" class="the-icons span3"><i class="icon-dashboard"></i> <span class="i-name">icon-dashboard</span><span class="i-code">0xe800</span></div>
|
||||
<div title="Code: 0xe801" class="the-icons span3"><i class="icon-user"></i> <span class="i-name">icon-user</span><span class="i-code">0xe801</span></div>
|
||||
<div title="Code: 0xe802" class="the-icons span3"><i class="icon-users"></i> <span class="i-name">icon-users</span><span class="i-code">0xe802</span></div>
|
||||
<div title="Code: 0xe803" class="the-icons span3"><i class="icon-ok"></i> <span class="i-name">icon-ok</span><span class="i-code">0xe803</span></div>
|
||||
<div title="Code: 0xe800" class="the-icons span3"><i class="demo-icon icon-dashboard"></i> <span class="i-name">icon-dashboard</span><span class="i-code">0xe800</span></div>
|
||||
<div title="Code: 0xe801" class="the-icons span3"><i class="demo-icon icon-user"></i> <span class="i-name">icon-user</span><span class="i-code">0xe801</span></div>
|
||||
<div title="Code: 0xe802" class="the-icons span3"><i class="demo-icon icon-users"></i> <span class="i-name">icon-users</span><span class="i-code">0xe802</span></div>
|
||||
<div title="Code: 0xe803" class="the-icons span3"><i class="demo-icon icon-ok"></i> <span class="i-name">icon-ok</span><span class="i-code">0xe803</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe804" class="the-icons span3"><i class="icon-cancel"></i> <span class="i-name">icon-cancel</span><span class="i-code">0xe804</span></div>
|
||||
<div title="Code: 0xe805" class="the-icons span3"><i class="icon-plus"></i> <span class="i-name">icon-plus</span><span class="i-code">0xe805</span></div>
|
||||
<div title="Code: 0xe806" class="the-icons span3"><i class="icon-minus"></i> <span class="i-name">icon-minus</span><span class="i-code">0xe806</span></div>
|
||||
<div title="Code: 0xe807" class="the-icons span3"><i class="icon-folder-empty"></i> <span class="i-name">icon-folder-empty</span><span class="i-code">0xe807</span></div>
|
||||
<div title="Code: 0xe804" class="the-icons span3"><i class="demo-icon icon-cancel"></i> <span class="i-name">icon-cancel</span><span class="i-code">0xe804</span></div>
|
||||
<div title="Code: 0xe805" class="the-icons span3"><i class="demo-icon icon-plus"></i> <span class="i-name">icon-plus</span><span class="i-code">0xe805</span></div>
|
||||
<div title="Code: 0xe806" class="the-icons span3"><i class="demo-icon icon-minus"></i> <span class="i-name">icon-minus</span><span class="i-code">0xe806</span></div>
|
||||
<div title="Code: 0xe807" class="the-icons span3"><i class="demo-icon icon-folder-empty"></i> <span class="i-name">icon-folder-empty</span><span class="i-code">0xe807</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe808" class="the-icons span3"><i class="icon-download"></i> <span class="i-name">icon-download</span><span class="i-code">0xe808</span></div>
|
||||
<div title="Code: 0xe809" class="the-icons span3"><i class="icon-upload"></i> <span class="i-name">icon-upload</span><span class="i-code">0xe809</span></div>
|
||||
<div title="Code: 0xe80a" class="the-icons span3"><i class="icon-git"></i> <span class="i-name">icon-git</span><span class="i-code">0xe80a</span></div>
|
||||
<div title="Code: 0xe80b" class="the-icons span3"><i class="icon-cubes"></i> <span class="i-name">icon-cubes</span><span class="i-code">0xe80b</span></div>
|
||||
<div title="Code: 0xe808" class="the-icons span3"><i class="demo-icon icon-download"></i> <span class="i-name">icon-download</span><span class="i-code">0xe808</span></div>
|
||||
<div title="Code: 0xe809" class="the-icons span3"><i class="demo-icon icon-upload"></i> <span class="i-name">icon-upload</span><span class="i-code">0xe809</span></div>
|
||||
<div title="Code: 0xe80a" class="the-icons span3"><i class="demo-icon icon-git"></i> <span class="i-name">icon-git</span><span class="i-code">0xe80a</span></div>
|
||||
<div title="Code: 0xe80b" class="the-icons span3"><i class="demo-icon icon-cubes"></i> <span class="i-name">icon-cubes</span><span class="i-code">0xe80b</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe80c" class="the-icons span3"><i class="icon-database"></i> <span class="i-name">icon-database</span><span class="i-code">0xe80c</span></div>
|
||||
<div title="Code: 0xe80d" class="the-icons span3"><i class="icon-gauge"></i> <span class="i-name">icon-gauge</span><span class="i-code">0xe80d</span></div>
|
||||
<div title="Code: 0xe80e" class="the-icons span3"><i class="icon-sitemap"></i> <span class="i-name">icon-sitemap</span><span class="i-code">0xe80e</span></div>
|
||||
<div title="Code: 0xe80f" class="the-icons span3"><i class="icon-sort-name-up"></i> <span class="i-name">icon-sort-name-up</span><span class="i-code">0xe80f</span></div>
|
||||
<div title="Code: 0xe80c" class="the-icons span3"><i class="demo-icon icon-database"></i> <span class="i-name">icon-database</span><span class="i-code">0xe80c</span></div>
|
||||
<div title="Code: 0xe80d" class="the-icons span3"><i class="demo-icon icon-gauge"></i> <span class="i-name">icon-gauge</span><span class="i-code">0xe80d</span></div>
|
||||
<div title="Code: 0xe80e" class="the-icons span3"><i class="demo-icon icon-sitemap"></i> <span class="i-name">icon-sitemap</span><span class="i-code">0xe80e</span></div>
|
||||
<div title="Code: 0xe80f" class="the-icons span3"><i class="demo-icon icon-sort-name-up"></i> <span class="i-name">icon-sort-name-up</span><span class="i-code">0xe80f</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe810" class="the-icons span3"><i class="icon-sort-name-down"></i> <span class="i-name">icon-sort-name-down</span><span class="i-code">0xe810</span></div>
|
||||
<div title="Code: 0xe811" class="the-icons span3"><i class="icon-megaphone"></i> <span class="i-name">icon-megaphone</span><span class="i-code">0xe811</span></div>
|
||||
<div title="Code: 0xe812" class="the-icons span3"><i class="icon-bug"></i> <span class="i-name">icon-bug</span><span class="i-code">0xe812</span></div>
|
||||
<div title="Code: 0xe813" class="the-icons span3"><i class="icon-tasks"></i> <span class="i-name">icon-tasks</span><span class="i-code">0xe813</span></div>
|
||||
<div title="Code: 0xe810" class="the-icons span3"><i class="demo-icon icon-sort-name-down"></i> <span class="i-name">icon-sort-name-down</span><span class="i-code">0xe810</span></div>
|
||||
<div title="Code: 0xe811" class="the-icons span3"><i class="demo-icon icon-megaphone"></i> <span class="i-name">icon-megaphone</span><span class="i-code">0xe811</span></div>
|
||||
<div title="Code: 0xe812" class="the-icons span3"><i class="demo-icon icon-bug"></i> <span class="i-name">icon-bug</span><span class="i-code">0xe812</span></div>
|
||||
<div title="Code: 0xe813" class="the-icons span3"><i class="demo-icon icon-tasks"></i> <span class="i-name">icon-tasks</span><span class="i-code">0xe813</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe814" class="the-icons span3"><i class="icon-filter"></i> <span class="i-name">icon-filter</span><span class="i-code">0xe814</span></div>
|
||||
<div title="Code: 0xe815" class="the-icons span3"><i class="icon-off"></i> <span class="i-name">icon-off</span><span class="i-code">0xe815</span></div>
|
||||
<div title="Code: 0xe816" class="the-icons span3"><i class="icon-book"></i> <span class="i-name">icon-book</span><span class="i-code">0xe816</span></div>
|
||||
<div title="Code: 0xe817" class="the-icons span3"><i class="icon-paste"></i> <span class="i-name">icon-paste</span><span class="i-code">0xe817</span></div>
|
||||
<div title="Code: 0xe814" class="the-icons span3"><i class="demo-icon icon-filter"></i> <span class="i-name">icon-filter</span><span class="i-code">0xe814</span></div>
|
||||
<div title="Code: 0xe815" class="the-icons span3"><i class="demo-icon icon-off"></i> <span class="i-name">icon-off</span><span class="i-code">0xe815</span></div>
|
||||
<div title="Code: 0xe816" class="the-icons span3"><i class="demo-icon icon-book"></i> <span class="i-name">icon-book</span><span class="i-code">0xe816</span></div>
|
||||
<div title="Code: 0xe817" class="the-icons span3"><i class="demo-icon icon-paste"></i> <span class="i-name">icon-paste</span><span class="i-code">0xe817</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe818" class="the-icons span3"><i class="icon-scissors"></i> <span class="i-name">icon-scissors</span><span class="i-code">0xe818</span></div>
|
||||
<div title="Code: 0xe819" class="the-icons span3"><i class="icon-globe"></i> <span class="i-name">icon-globe</span><span class="i-code">0xe819</span></div>
|
||||
<div title="Code: 0xe81a" class="the-icons span3"><i class="icon-cloud"></i> <span class="i-name">icon-cloud</span><span class="i-code">0xe81a</span></div>
|
||||
<div title="Code: 0xe81b" class="the-icons span3"><i class="icon-flash"></i> <span class="i-name">icon-flash</span><span class="i-code">0xe81b</span></div>
|
||||
<div title="Code: 0xe818" class="the-icons span3"><i class="demo-icon icon-scissors"></i> <span class="i-name">icon-scissors</span><span class="i-code">0xe818</span></div>
|
||||
<div title="Code: 0xe819" class="the-icons span3"><i class="demo-icon icon-globe"></i> <span class="i-name">icon-globe</span><span class="i-code">0xe819</span></div>
|
||||
<div title="Code: 0xe81a" class="the-icons span3"><i class="demo-icon icon-cloud"></i> <span class="i-name">icon-cloud</span><span class="i-code">0xe81a</span></div>
|
||||
<div title="Code: 0xe81b" class="the-icons span3"><i class="demo-icon icon-flash"></i> <span class="i-name">icon-flash</span><span class="i-code">0xe81b</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe81c" class="the-icons span3"><i class="icon-barchart"></i> <span class="i-name">icon-barchart</span><span class="i-code">0xe81c</span></div>
|
||||
<div title="Code: 0xe81d" class="the-icons span3"><i class="icon-down-dir"></i> <span class="i-name">icon-down-dir</span><span class="i-code">0xe81d</span></div>
|
||||
<div title="Code: 0xe81e" class="the-icons span3"><i class="icon-up-dir"></i> <span class="i-name">icon-up-dir</span><span class="i-code">0xe81e</span></div>
|
||||
<div title="Code: 0xe81f" class="the-icons span3"><i class="icon-left-dir"></i> <span class="i-name">icon-left-dir</span><span class="i-code">0xe81f</span></div>
|
||||
<div title="Code: 0xe81c" class="the-icons span3"><i class="demo-icon icon-barchart"></i> <span class="i-name">icon-barchart</span><span class="i-code">0xe81c</span></div>
|
||||
<div title="Code: 0xe81d" class="the-icons span3"><i class="demo-icon icon-down-dir"></i> <span class="i-name">icon-down-dir</span><span class="i-code">0xe81d</span></div>
|
||||
<div title="Code: 0xe81e" class="the-icons span3"><i class="demo-icon icon-up-dir"></i> <span class="i-name">icon-up-dir</span><span class="i-code">0xe81e</span></div>
|
||||
<div title="Code: 0xe81f" class="the-icons span3"><i class="demo-icon icon-left-dir"></i> <span class="i-name">icon-left-dir</span><span class="i-code">0xe81f</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe820" class="the-icons span3"><i class="icon-right-dir"></i> <span class="i-name">icon-right-dir</span><span class="i-code">0xe820</span></div>
|
||||
<div title="Code: 0xe821" class="the-icons span3"><i class="icon-down-open"></i> <span class="i-name">icon-down-open</span><span class="i-code">0xe821</span></div>
|
||||
<div title="Code: 0xe822" class="the-icons span3"><i class="icon-right-open"></i> <span class="i-name">icon-right-open</span><span class="i-code">0xe822</span></div>
|
||||
<div title="Code: 0xe823" class="the-icons span3"><i class="icon-up-open"></i> <span class="i-name">icon-up-open</span><span class="i-code">0xe823</span></div>
|
||||
<div title="Code: 0xe820" class="the-icons span3"><i class="demo-icon icon-right-dir"></i> <span class="i-name">icon-right-dir</span><span class="i-code">0xe820</span></div>
|
||||
<div title="Code: 0xe821" class="the-icons span3"><i class="demo-icon icon-down-open"></i> <span class="i-name">icon-down-open</span><span class="i-code">0xe821</span></div>
|
||||
<div title="Code: 0xe822" class="the-icons span3"><i class="demo-icon icon-right-open"></i> <span class="i-name">icon-right-open</span><span class="i-code">0xe822</span></div>
|
||||
<div title="Code: 0xe823" class="the-icons span3"><i class="demo-icon icon-up-open"></i> <span class="i-name">icon-up-open</span><span class="i-code">0xe823</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe824" class="the-icons span3"><i class="icon-left-open"></i> <span class="i-name">icon-left-open</span><span class="i-code">0xe824</span></div>
|
||||
<div title="Code: 0xe825" class="the-icons span3"><i class="icon-up-big"></i> <span class="i-name">icon-up-big</span><span class="i-code">0xe825</span></div>
|
||||
<div title="Code: 0xe826" class="the-icons span3"><i class="icon-right-big"></i> <span class="i-name">icon-right-big</span><span class="i-code">0xe826</span></div>
|
||||
<div title="Code: 0xe827" class="the-icons span3"><i class="icon-left-big"></i> <span class="i-name">icon-left-big</span><span class="i-code">0xe827</span></div>
|
||||
<div title="Code: 0xe824" class="the-icons span3"><i class="demo-icon icon-left-open"></i> <span class="i-name">icon-left-open</span><span class="i-code">0xe824</span></div>
|
||||
<div title="Code: 0xe825" class="the-icons span3"><i class="demo-icon icon-up-big"></i> <span class="i-name">icon-up-big</span><span class="i-code">0xe825</span></div>
|
||||
<div title="Code: 0xe826" class="the-icons span3"><i class="demo-icon icon-right-big"></i> <span class="i-name">icon-right-big</span><span class="i-code">0xe826</span></div>
|
||||
<div title="Code: 0xe827" class="the-icons span3"><i class="demo-icon icon-left-big"></i> <span class="i-name">icon-left-big</span><span class="i-code">0xe827</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe828" class="the-icons span3"><i class="icon-down-big"></i> <span class="i-name">icon-down-big</span><span class="i-code">0xe828</span></div>
|
||||
<div title="Code: 0xe829" class="the-icons span3"><i class="icon-resize-full-alt"></i> <span class="i-name">icon-resize-full-alt</span><span class="i-code">0xe829</span></div>
|
||||
<div title="Code: 0xe82a" class="the-icons span3"><i class="icon-resize-full"></i> <span class="i-name">icon-resize-full</span><span class="i-code">0xe82a</span></div>
|
||||
<div title="Code: 0xe82b" class="the-icons span3"><i class="icon-resize-small"></i> <span class="i-name">icon-resize-small</span><span class="i-code">0xe82b</span></div>
|
||||
<div title="Code: 0xe828" class="the-icons span3"><i class="demo-icon icon-down-big"></i> <span class="i-name">icon-down-big</span><span class="i-code">0xe828</span></div>
|
||||
<div title="Code: 0xe829" class="the-icons span3"><i class="demo-icon icon-resize-full-alt"></i> <span class="i-name">icon-resize-full-alt</span><span class="i-code">0xe829</span></div>
|
||||
<div title="Code: 0xe82a" class="the-icons span3"><i class="demo-icon icon-resize-full"></i> <span class="i-name">icon-resize-full</span><span class="i-code">0xe82a</span></div>
|
||||
<div title="Code: 0xe82b" class="the-icons span3"><i class="demo-icon icon-resize-small"></i> <span class="i-name">icon-resize-small</span><span class="i-code">0xe82b</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe82c" class="the-icons span3"><i class="icon-move"></i> <span class="i-name">icon-move</span><span class="i-code">0xe82c</span></div>
|
||||
<div title="Code: 0xe82d" class="the-icons span3"><i class="icon-resize-horizontal"></i> <span class="i-name">icon-resize-horizontal</span><span class="i-code">0xe82d</span></div>
|
||||
<div title="Code: 0xe82e" class="the-icons span3"><i class="icon-resize-vertical"></i> <span class="i-name">icon-resize-vertical</span><span class="i-code">0xe82e</span></div>
|
||||
<div title="Code: 0xe82f" class="the-icons span3"><i class="icon-zoom-in"></i> <span class="i-name">icon-zoom-in</span><span class="i-code">0xe82f</span></div>
|
||||
<div title="Code: 0xe82c" class="the-icons span3"><i class="demo-icon icon-move"></i> <span class="i-name">icon-move</span><span class="i-code">0xe82c</span></div>
|
||||
<div title="Code: 0xe82d" class="the-icons span3"><i class="demo-icon icon-resize-horizontal"></i> <span class="i-name">icon-resize-horizontal</span><span class="i-code">0xe82d</span></div>
|
||||
<div title="Code: 0xe82e" class="the-icons span3"><i class="demo-icon icon-resize-vertical"></i> <span class="i-name">icon-resize-vertical</span><span class="i-code">0xe82e</span></div>
|
||||
<div title="Code: 0xe82f" class="the-icons span3"><i class="demo-icon icon-zoom-in"></i> <span class="i-name">icon-zoom-in</span><span class="i-code">0xe82f</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe830" class="the-icons span3"><i class="icon-block"></i> <span class="i-name">icon-block</span><span class="i-code">0xe830</span></div>
|
||||
<div title="Code: 0xe831" class="the-icons span3"><i class="icon-zoom-out"></i> <span class="i-name">icon-zoom-out</span><span class="i-code">0xe831</span></div>
|
||||
<div title="Code: 0xe832" class="the-icons span3"><i class="icon-lightbulb"></i> <span class="i-name">icon-lightbulb</span><span class="i-code">0xe832</span></div>
|
||||
<div title="Code: 0xe833" class="the-icons span3"><i class="icon-clock"></i> <span class="i-name">icon-clock</span><span class="i-code">0xe833</span></div>
|
||||
<div title="Code: 0xe830" class="the-icons span3"><i class="demo-icon icon-block"></i> <span class="i-name">icon-block</span><span class="i-code">0xe830</span></div>
|
||||
<div title="Code: 0xe831" class="the-icons span3"><i class="demo-icon icon-zoom-out"></i> <span class="i-name">icon-zoom-out</span><span class="i-code">0xe831</span></div>
|
||||
<div title="Code: 0xe832" class="the-icons span3"><i class="demo-icon icon-lightbulb"></i> <span class="i-name">icon-lightbulb</span><span class="i-code">0xe832</span></div>
|
||||
<div title="Code: 0xe833" class="the-icons span3"><i class="demo-icon icon-clock"></i> <span class="i-name">icon-clock</span><span class="i-code">0xe833</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe834" class="the-icons span3"><i class="icon-volume-up"></i> <span class="i-name">icon-volume-up</span><span class="i-code">0xe834</span></div>
|
||||
<div title="Code: 0xe835" class="the-icons span3"><i class="icon-volume-down"></i> <span class="i-name">icon-volume-down</span><span class="i-code">0xe835</span></div>
|
||||
<div title="Code: 0xe836" class="the-icons span3"><i class="icon-volume-off"></i> <span class="i-name">icon-volume-off</span><span class="i-code">0xe836</span></div>
|
||||
<div title="Code: 0xe837" class="the-icons span3"><i class="icon-mute"></i> <span class="i-name">icon-mute</span><span class="i-code">0xe837</span></div>
|
||||
<div title="Code: 0xe834" class="the-icons span3"><i class="demo-icon icon-volume-up"></i> <span class="i-name">icon-volume-up</span><span class="i-code">0xe834</span></div>
|
||||
<div title="Code: 0xe835" class="the-icons span3"><i class="demo-icon icon-volume-down"></i> <span class="i-name">icon-volume-down</span><span class="i-code">0xe835</span></div>
|
||||
<div title="Code: 0xe836" class="the-icons span3"><i class="demo-icon icon-volume-off"></i> <span class="i-name">icon-volume-off</span><span class="i-code">0xe836</span></div>
|
||||
<div title="Code: 0xe837" class="the-icons span3"><i class="demo-icon icon-mute"></i> <span class="i-name">icon-mute</span><span class="i-code">0xe837</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe838" class="the-icons span3"><i class="icon-mic"></i> <span class="i-name">icon-mic</span><span class="i-code">0xe838</span></div>
|
||||
<div title="Code: 0xe839" class="the-icons span3"><i class="icon-endtime"></i> <span class="i-name">icon-endtime</span><span class="i-code">0xe839</span></div>
|
||||
<div title="Code: 0xe83a" class="the-icons span3"><i class="icon-starttime"></i> <span class="i-name">icon-starttime</span><span class="i-code">0xe83a</span></div>
|
||||
<div title="Code: 0xe83b" class="the-icons span3"><i class="icon-calendar-empty"></i> <span class="i-name">icon-calendar-empty</span><span class="i-code">0xe83b</span></div>
|
||||
<div title="Code: 0xe838" class="the-icons span3"><i class="demo-icon icon-mic"></i> <span class="i-name">icon-mic</span><span class="i-code">0xe838</span></div>
|
||||
<div title="Code: 0xe839" class="the-icons span3"><i class="demo-icon icon-endtime"></i> <span class="i-name">icon-endtime</span><span class="i-code">0xe839</span></div>
|
||||
<div title="Code: 0xe83a" class="the-icons span3"><i class="demo-icon icon-starttime"></i> <span class="i-name">icon-starttime</span><span class="i-code">0xe83a</span></div>
|
||||
<div title="Code: 0xe83b" class="the-icons span3"><i class="demo-icon icon-calendar-empty"></i> <span class="i-name">icon-calendar-empty</span><span class="i-code">0xe83b</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe83c" class="the-icons span3"><i class="icon-calendar"></i> <span class="i-name">icon-calendar</span><span class="i-code">0xe83c</span></div>
|
||||
<div title="Code: 0xe83d" class="the-icons span3"><i class="icon-wrench"></i> <span class="i-name">icon-wrench</span><span class="i-code">0xe83d</span></div>
|
||||
<div title="Code: 0xe83e" class="the-icons span3"><i class="icon-sliders"></i> <span class="i-name">icon-sliders</span><span class="i-code">0xe83e</span></div>
|
||||
<div title="Code: 0xe83f" class="the-icons span3"><i class="icon-services"></i> <span class="i-name">icon-services</span><span class="i-code">0xe83f</span></div>
|
||||
<div title="Code: 0xe83c" class="the-icons span3"><i class="demo-icon icon-calendar"></i> <span class="i-name">icon-calendar</span><span class="i-code">0xe83c</span></div>
|
||||
<div title="Code: 0xe83d" class="the-icons span3"><i class="demo-icon icon-wrench"></i> <span class="i-name">icon-wrench</span><span class="i-code">0xe83d</span></div>
|
||||
<div title="Code: 0xe83e" class="the-icons span3"><i class="demo-icon icon-sliders"></i> <span class="i-name">icon-sliders</span><span class="i-code">0xe83e</span></div>
|
||||
<div title="Code: 0xe83f" class="the-icons span3"><i class="demo-icon icon-services"></i> <span class="i-name">icon-services</span><span class="i-code">0xe83f</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe840" class="the-icons span3"><i class="icon-service"></i> <span class="i-name">icon-service</span><span class="i-code">0xe840</span></div>
|
||||
<div title="Code: 0xe841" class="the-icons span3"><i class="icon-phone"></i> <span class="i-name">icon-phone</span><span class="i-code">0xe841</span></div>
|
||||
<div title="Code: 0xe842" class="the-icons span3"><i class="icon-file-pdf"></i> <span class="i-name">icon-file-pdf</span><span class="i-code">0xe842</span></div>
|
||||
<div title="Code: 0xe843" class="the-icons span3"><i class="icon-file-word"></i> <span class="i-name">icon-file-word</span><span class="i-code">0xe843</span></div>
|
||||
<div title="Code: 0xe840" class="the-icons span3"><i class="demo-icon icon-service"></i> <span class="i-name">icon-service</span><span class="i-code">0xe840</span></div>
|
||||
<div title="Code: 0xe841" class="the-icons span3"><i class="demo-icon icon-phone"></i> <span class="i-name">icon-phone</span><span class="i-code">0xe841</span></div>
|
||||
<div title="Code: 0xe842" class="the-icons span3"><i class="demo-icon icon-file-pdf"></i> <span class="i-name">icon-file-pdf</span><span class="i-code">0xe842</span></div>
|
||||
<div title="Code: 0xe843" class="the-icons span3"><i class="demo-icon icon-file-word"></i> <span class="i-name">icon-file-word</span><span class="i-code">0xe843</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe844" class="the-icons span3"><i class="icon-file-excel"></i> <span class="i-name">icon-file-excel</span><span class="i-code">0xe844</span></div>
|
||||
<div title="Code: 0xe845" class="the-icons span3"><i class="icon-doc-text"></i> <span class="i-name">icon-doc-text</span><span class="i-code">0xe845</span></div>
|
||||
<div title="Code: 0xe846" class="the-icons span3"><i class="icon-trash"></i> <span class="i-name">icon-trash</span><span class="i-code">0xe846</span></div>
|
||||
<div title="Code: 0xe847" class="the-icons span3"><i class="icon-comment-empty"></i> <span class="i-name">icon-comment-empty</span><span class="i-code">0xe847</span></div>
|
||||
<div title="Code: 0xe844" class="the-icons span3"><i class="demo-icon icon-file-excel"></i> <span class="i-name">icon-file-excel</span><span class="i-code">0xe844</span></div>
|
||||
<div title="Code: 0xe845" class="the-icons span3"><i class="demo-icon icon-doc-text"></i> <span class="i-name">icon-doc-text</span><span class="i-code">0xe845</span></div>
|
||||
<div title="Code: 0xe846" class="the-icons span3"><i class="demo-icon icon-trash"></i> <span class="i-name">icon-trash</span><span class="i-code">0xe846</span></div>
|
||||
<div title="Code: 0xe847" class="the-icons span3"><i class="demo-icon icon-comment-empty"></i> <span class="i-name">icon-comment-empty</span><span class="i-code">0xe847</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe848" class="the-icons span3"><i class="icon-comment"></i> <span class="i-name">icon-comment</span><span class="i-code">0xe848</span></div>
|
||||
<div title="Code: 0xe849" class="the-icons span3"><i class="icon-chat"></i> <span class="i-name">icon-chat</span><span class="i-code">0xe849</span></div>
|
||||
<div title="Code: 0xe84a" class="the-icons span3"><i class="icon-chat-empty"></i> <span class="i-name">icon-chat-empty</span><span class="i-code">0xe84a</span></div>
|
||||
<div title="Code: 0xe84b" class="the-icons span3"><i class="icon-bell"></i> <span class="i-name">icon-bell</span><span class="i-code">0xe84b</span></div>
|
||||
<div title="Code: 0xe848" class="the-icons span3"><i class="demo-icon icon-comment"></i> <span class="i-name">icon-comment</span><span class="i-code">0xe848</span></div>
|
||||
<div title="Code: 0xe849" class="the-icons span3"><i class="demo-icon icon-chat"></i> <span class="i-name">icon-chat</span><span class="i-code">0xe849</span></div>
|
||||
<div title="Code: 0xe84a" class="the-icons span3"><i class="demo-icon icon-chat-empty"></i> <span class="i-name">icon-chat-empty</span><span class="i-code">0xe84a</span></div>
|
||||
<div title="Code: 0xe84b" class="the-icons span3"><i class="demo-icon icon-bell"></i> <span class="i-name">icon-bell</span><span class="i-code">0xe84b</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe84c" class="the-icons span3"><i class="icon-bell-alt"></i> <span class="i-name">icon-bell-alt</span><span class="i-code">0xe84c</span></div>
|
||||
<div title="Code: 0xe84d" class="the-icons span3"><i class="icon-attention-alt"></i> <span class="i-name">icon-attention-alt</span><span class="i-code">0xe84d</span></div>
|
||||
<div title="Code: 0xe84e" class="the-icons span3"><i class="icon-print"></i> <span class="i-name">icon-print</span><span class="i-code">0xe84e</span></div>
|
||||
<div title="Code: 0xe84f" class="the-icons span3"><i class="icon-edit"></i> <span class="i-name">icon-edit</span><span class="i-code">0xe84f</span></div>
|
||||
<div title="Code: 0xe84c" class="the-icons span3"><i class="demo-icon icon-bell-alt"></i> <span class="i-name">icon-bell-alt</span><span class="i-code">0xe84c</span></div>
|
||||
<div title="Code: 0xe84d" class="the-icons span3"><i class="demo-icon icon-attention-alt"></i> <span class="i-name">icon-attention-alt</span><span class="i-code">0xe84d</span></div>
|
||||
<div title="Code: 0xe84e" class="the-icons span3"><i class="demo-icon icon-print"></i> <span class="i-name">icon-print</span><span class="i-code">0xe84e</span></div>
|
||||
<div title="Code: 0xe84f" class="the-icons span3"><i class="demo-icon icon-edit"></i> <span class="i-name">icon-edit</span><span class="i-code">0xe84f</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe850" class="the-icons span3"><i class="icon-forward"></i> <span class="i-name">icon-forward</span><span class="i-code">0xe850</span></div>
|
||||
<div title="Code: 0xe851" class="the-icons span3"><i class="icon-reply"></i> <span class="i-name">icon-reply</span><span class="i-code">0xe851</span></div>
|
||||
<div title="Code: 0xe852" class="the-icons span3"><i class="icon-reply-all"></i> <span class="i-name">icon-reply-all</span><span class="i-code">0xe852</span></div>
|
||||
<div title="Code: 0xe853" class="the-icons span3"><i class="icon-eye"></i> <span class="i-name">icon-eye</span><span class="i-code">0xe853</span></div>
|
||||
<div title="Code: 0xe850" class="the-icons span3"><i class="demo-icon icon-forward"></i> <span class="i-name">icon-forward</span><span class="i-code">0xe850</span></div>
|
||||
<div title="Code: 0xe851" class="the-icons span3"><i class="demo-icon icon-reply"></i> <span class="i-name">icon-reply</span><span class="i-code">0xe851</span></div>
|
||||
<div title="Code: 0xe852" class="the-icons span3"><i class="demo-icon icon-reply-all"></i> <span class="i-name">icon-reply-all</span><span class="i-code">0xe852</span></div>
|
||||
<div title="Code: 0xe853" class="the-icons span3"><i class="demo-icon icon-eye"></i> <span class="i-name">icon-eye</span><span class="i-code">0xe853</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe854" class="the-icons span3"><i class="icon-tag"></i> <span class="i-name">icon-tag</span><span class="i-code">0xe854</span></div>
|
||||
<div title="Code: 0xe855" class="the-icons span3"><i class="icon-tags"></i> <span class="i-name">icon-tags</span><span class="i-code">0xe855</span></div>
|
||||
<div title="Code: 0xe856" class="the-icons span3"><i class="icon-lock-open-alt"></i> <span class="i-name">icon-lock-open-alt</span><span class="i-code">0xe856</span></div>
|
||||
<div title="Code: 0xe857" class="the-icons span3"><i class="icon-lock-open"></i> <span class="i-name">icon-lock-open</span><span class="i-code">0xe857</span></div>
|
||||
<div title="Code: 0xe854" class="the-icons span3"><i class="demo-icon icon-tag"></i> <span class="i-name">icon-tag</span><span class="i-code">0xe854</span></div>
|
||||
<div title="Code: 0xe855" class="the-icons span3"><i class="demo-icon icon-tags"></i> <span class="i-name">icon-tags</span><span class="i-code">0xe855</span></div>
|
||||
<div title="Code: 0xe856" class="the-icons span3"><i class="demo-icon icon-lock-open-alt"></i> <span class="i-name">icon-lock-open-alt</span><span class="i-code">0xe856</span></div>
|
||||
<div title="Code: 0xe857" class="the-icons span3"><i class="demo-icon icon-lock-open"></i> <span class="i-name">icon-lock-open</span><span class="i-code">0xe857</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe858" class="the-icons span3"><i class="icon-lock"></i> <span class="i-name">icon-lock</span><span class="i-code">0xe858</span></div>
|
||||
<div title="Code: 0xe859" class="the-icons span3"><i class="icon-home"></i> <span class="i-name">icon-home</span><span class="i-code">0xe859</span></div>
|
||||
<div title="Code: 0xe85a" class="the-icons span3"><i class="icon-info"></i> <span class="i-name">icon-info</span><span class="i-code">0xe85a</span></div>
|
||||
<div title="Code: 0xe85b" class="the-icons span3"><i class="icon-help"></i> <span class="i-name">icon-help</span><span class="i-code">0xe85b</span></div>
|
||||
<div title="Code: 0xe858" class="the-icons span3"><i class="demo-icon icon-lock"></i> <span class="i-name">icon-lock</span><span class="i-code">0xe858</span></div>
|
||||
<div title="Code: 0xe859" class="the-icons span3"><i class="demo-icon icon-home"></i> <span class="i-name">icon-home</span><span class="i-code">0xe859</span></div>
|
||||
<div title="Code: 0xe85a" class="the-icons span3"><i class="demo-icon icon-info"></i> <span class="i-name">icon-info</span><span class="i-code">0xe85a</span></div>
|
||||
<div title="Code: 0xe85b" class="the-icons span3"><i class="demo-icon icon-help"></i> <span class="i-name">icon-help</span><span class="i-code">0xe85b</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe85c" class="the-icons span3"><i class="icon-search"></i> <span class="i-name">icon-search</span><span class="i-code">0xe85c</span></div>
|
||||
<div title="Code: 0xe85d" class="the-icons span3"><i class="icon-flapping"></i> <span class="i-name">icon-flapping</span><span class="i-code">0xe85d</span></div>
|
||||
<div title="Code: 0xe85e" class="the-icons span3"><i class="icon-rewind"></i> <span class="i-name">icon-rewind</span><span class="i-code">0xe85e</span></div>
|
||||
<div title="Code: 0xe85f" class="the-icons span3"><i class="icon-chart-line"></i> <span class="i-name">icon-chart-line</span><span class="i-code">0xe85f</span></div>
|
||||
<div title="Code: 0xe85c" class="the-icons span3"><i class="demo-icon icon-search"></i> <span class="i-name">icon-search</span><span class="i-code">0xe85c</span></div>
|
||||
<div title="Code: 0xe85d" class="the-icons span3"><i class="demo-icon icon-flapping"></i> <span class="i-name">icon-flapping</span><span class="i-code">0xe85d</span></div>
|
||||
<div title="Code: 0xe85e" class="the-icons span3"><i class="demo-icon icon-rewind"></i> <span class="i-name">icon-rewind</span><span class="i-code">0xe85e</span></div>
|
||||
<div title="Code: 0xe85f" class="the-icons span3"><i class="demo-icon icon-chart-line"></i> <span class="i-name">icon-chart-line</span><span class="i-code">0xe85f</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe860" class="the-icons span3"><i class="icon-bell-off"></i> <span class="i-name">icon-bell-off</span><span class="i-code">0xe860</span></div>
|
||||
<div title="Code: 0xe861" class="the-icons span3"><i class="icon-bell-off-empty"></i> <span class="i-name">icon-bell-off-empty</span><span class="i-code">0xe861</span></div>
|
||||
<div title="Code: 0xe862" class="the-icons span3"><i class="icon-plug"></i> <span class="i-name">icon-plug</span><span class="i-code">0xe862</span></div>
|
||||
<div title="Code: 0xe863" class="the-icons span3"><i class="icon-eye-off"></i> <span class="i-name">icon-eye-off</span><span class="i-code">0xe863</span></div>
|
||||
<div title="Code: 0xe860" class="the-icons span3"><i class="demo-icon icon-bell-off"></i> <span class="i-name">icon-bell-off</span><span class="i-code">0xe860</span></div>
|
||||
<div title="Code: 0xe861" class="the-icons span3"><i class="demo-icon icon-bell-off-empty"></i> <span class="i-name">icon-bell-off-empty</span><span class="i-code">0xe861</span></div>
|
||||
<div title="Code: 0xe862" class="the-icons span3"><i class="demo-icon icon-plug"></i> <span class="i-name">icon-plug</span><span class="i-code">0xe862</span></div>
|
||||
<div title="Code: 0xe863" class="the-icons span3"><i class="demo-icon icon-eye-off"></i> <span class="i-name">icon-eye-off</span><span class="i-code">0xe863</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe864" class="the-icons span3"><i class="icon-reschedule"></i> <span class="i-name">icon-reschedule</span><span class="i-code">0xe864</span></div>
|
||||
<div title="Code: 0xe865" class="the-icons span3"><i class="icon-cw"></i> <span class="i-name">icon-cw</span><span class="i-code">0xe865</span></div>
|
||||
<div title="Code: 0xe866" class="the-icons span3"><i class="icon-host"></i> <span class="i-name">icon-host</span><span class="i-code">0xe866</span></div>
|
||||
<div title="Code: 0xe867" class="the-icons span3"><i class="icon-thumbs-up"></i> <span class="i-name">icon-thumbs-up</span><span class="i-code">0xe867</span></div>
|
||||
<div title="Code: 0xe864" class="the-icons span3"><i class="demo-icon icon-reschedule"></i> <span class="i-name">icon-reschedule</span><span class="i-code">0xe864</span></div>
|
||||
<div title="Code: 0xe865" class="the-icons span3"><i class="demo-icon icon-cw"></i> <span class="i-name">icon-cw</span><span class="i-code">0xe865</span></div>
|
||||
<div title="Code: 0xe866" class="the-icons span3"><i class="demo-icon icon-host"></i> <span class="i-name">icon-host</span><span class="i-code">0xe866</span></div>
|
||||
<div title="Code: 0xe867" class="the-icons span3"><i class="demo-icon icon-thumbs-up"></i> <span class="i-name">icon-thumbs-up</span><span class="i-code">0xe867</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe868" class="the-icons span3"><i class="icon-thumbs-down"></i> <span class="i-name">icon-thumbs-down</span><span class="i-code">0xe868</span></div>
|
||||
<div title="Code: 0xe869" class="the-icons span3"><i class="icon-spinner"></i> <span class="i-name">icon-spinner</span><span class="i-code">0xe869</span></div>
|
||||
<div title="Code: 0xe86a" class="the-icons span3"><i class="icon-attach"></i> <span class="i-name">icon-attach</span><span class="i-code">0xe86a</span></div>
|
||||
<div title="Code: 0xe86b" class="the-icons span3"><i class="icon-keyboard"></i> <span class="i-name">icon-keyboard</span><span class="i-code">0xe86b</span></div>
|
||||
<div title="Code: 0xe868" class="the-icons span3"><i class="demo-icon icon-thumbs-down"></i> <span class="i-name">icon-thumbs-down</span><span class="i-code">0xe868</span></div>
|
||||
<div title="Code: 0xe869" class="the-icons span3"><i class="demo-icon icon-spinner"></i> <span class="i-name">icon-spinner</span><span class="i-code">0xe869</span></div>
|
||||
<div title="Code: 0xe86a" class="the-icons span3"><i class="demo-icon icon-attach"></i> <span class="i-name">icon-attach</span><span class="i-code">0xe86a</span></div>
|
||||
<div title="Code: 0xe86b" class="the-icons span3"><i class="demo-icon icon-keyboard"></i> <span class="i-name">icon-keyboard</span><span class="i-code">0xe86b</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe86c" class="the-icons span3"><i class="icon-menu"></i> <span class="i-name">icon-menu</span><span class="i-code">0xe86c</span></div>
|
||||
<div title="Code: 0xe86d" class="the-icons span3"><i class="icon-wifi"></i> <span class="i-name">icon-wifi</span><span class="i-code">0xe86d</span></div>
|
||||
<div title="Code: 0xe86e" class="the-icons span3"><i class="icon-moon"></i> <span class="i-name">icon-moon</span><span class="i-code">0xe86e</span></div>
|
||||
<div title="Code: 0xe86f" class="the-icons span3"><i class="icon-chart-pie"></i> <span class="i-name">icon-chart-pie</span><span class="i-code">0xe86f</span></div>
|
||||
<div title="Code: 0xe86c" class="the-icons span3"><i class="demo-icon icon-menu"></i> <span class="i-name">icon-menu</span><span class="i-code">0xe86c</span></div>
|
||||
<div title="Code: 0xe86d" class="the-icons span3"><i class="demo-icon icon-wifi"></i> <span class="i-name">icon-wifi</span><span class="i-code">0xe86d</span></div>
|
||||
<div title="Code: 0xe86e" class="the-icons span3"><i class="demo-icon icon-moon"></i> <span class="i-name">icon-moon</span><span class="i-code">0xe86e</span></div>
|
||||
<div title="Code: 0xe86f" class="the-icons span3"><i class="demo-icon icon-chart-pie"></i> <span class="i-name">icon-chart-pie</span><span class="i-code">0xe86f</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe870" class="the-icons span3"><i class="icon-chart-area"></i> <span class="i-name">icon-chart-area</span><span class="i-code">0xe870</span></div>
|
||||
<div title="Code: 0xe871" class="the-icons span3"><i class="icon-chart-bar"></i> <span class="i-name">icon-chart-bar</span><span class="i-code">0xe871</span></div>
|
||||
<div title="Code: 0xe872" class="the-icons span3"><i class="icon-beaker"></i> <span class="i-name">icon-beaker</span><span class="i-code">0xe872</span></div>
|
||||
<div title="Code: 0xe873" class="the-icons span3"><i class="icon-magic"></i> <span class="i-name">icon-magic</span><span class="i-code">0xe873</span></div>
|
||||
<div title="Code: 0xe870" class="the-icons span3"><i class="demo-icon icon-chart-area"></i> <span class="i-name">icon-chart-area</span><span class="i-code">0xe870</span></div>
|
||||
<div title="Code: 0xe871" class="the-icons span3"><i class="demo-icon icon-chart-bar"></i> <span class="i-name">icon-chart-bar</span><span class="i-code">0xe871</span></div>
|
||||
<div title="Code: 0xe872" class="the-icons span3"><i class="demo-icon icon-beaker"></i> <span class="i-name">icon-beaker</span><span class="i-code">0xe872</span></div>
|
||||
<div title="Code: 0xe873" class="the-icons span3"><i class="demo-icon icon-magic"></i> <span class="i-name">icon-magic</span><span class="i-code">0xe873</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe874" class="the-icons span3"><i class="demo-icon icon-spin6 animate-spin"></i> <span class="i-name">icon-spin6</span><span class="i-code">0xe874</span></div>
|
||||
<div title="Code: 0xe875" class="the-icons span3"><i class="demo-icon icon-down-small"></i> <span class="i-name">icon-down-small</span><span class="i-code">0xe875</span></div>
|
||||
<div title="Code: 0xe876" class="the-icons span3"><i class="demo-icon icon-left-small"></i> <span class="i-name">icon-left-small</span><span class="i-code">0xe876</span></div>
|
||||
<div title="Code: 0xe877" class="the-icons span3"><i class="demo-icon icon-right-small"></i> <span class="i-name">icon-right-small</span><span class="i-code">0xe877</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div title="Code: 0xe878" class="the-icons span3"><i class="demo-icon icon-up-small"></i> <span class="i-name">icon-up-small</span><span class="i-code">0xe878</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container footer">Generated by <a href="http://fontello.com">fontello.com</a></div>
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,9 @@
|
|||
# fontello-ifont font files moved
|
||||
|
||||
New target is: public/font
|
||||
|
||||
The font directory has been moved to the public structure because of
|
||||
Internet Explorer version 8 compatibility. The common way for browsers is to
|
||||
include the binary embeded font type in the javascript. IE8 falls back and
|
||||
include one of the provided font sources. Therefore it is important to have
|
||||
the font files available public and exported by the HTTP server.
|
|
@ -1,28 +1,36 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms\Authentication;
|
||||
|
||||
use Icinga\Authentication\Auth;
|
||||
use Icinga\Authentication\User\ExternalBackend;
|
||||
use Icinga\User;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Url;
|
||||
|
||||
/**
|
||||
* Class LoginForm
|
||||
* Form for user authentication
|
||||
*/
|
||||
class LoginForm extends Form
|
||||
{
|
||||
/**
|
||||
* Initialize this login form
|
||||
* Redirect URL
|
||||
*/
|
||||
const REDIRECT_URL = 'dashboard';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setRequiredCue(null);
|
||||
$this->setName('form_login');
|
||||
$this->setSubmitLabel(t('Login'));
|
||||
$this->setSubmitLabel($this->translate('Login'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
|
@ -31,8 +39,8 @@ class LoginForm extends Form
|
|||
'username',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Username'),
|
||||
'placeholder' => t('Please enter your username...'),
|
||||
'label' => $this->translate('Username'),
|
||||
'placeholder' => $this->translate('Please enter your username...'),
|
||||
'class' => false === isset($formData['username']) ? 'autofocus' : ''
|
||||
)
|
||||
);
|
||||
|
@ -41,8 +49,8 @@ class LoginForm extends Form
|
|||
'password',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Password'),
|
||||
'placeholder' => t('...and your password'),
|
||||
'label' => $this->translate('Password'),
|
||||
'placeholder' => $this->translate('...and your password'),
|
||||
'class' => isset($formData['username']) ? 'autofocus' : ''
|
||||
)
|
||||
);
|
||||
|
@ -54,4 +62,83 @@ class LoginForm extends Form
|
|||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRedirectUrl()
|
||||
{
|
||||
$redirect = null;
|
||||
if ($this->created) {
|
||||
$redirect = $this->getElement('redirect')->getValue();
|
||||
}
|
||||
if (empty($redirect)) {
|
||||
$redirect = static::REDIRECT_URL;
|
||||
}
|
||||
return Url::fromPath($redirect);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function onSuccess()
|
||||
{
|
||||
$auth = Auth::getInstance();
|
||||
$authChain = $auth->getAuthChain();
|
||||
$authChain->setSkipExternalBackends(true);
|
||||
$user = new User($this->getElement('username')->getValue());
|
||||
$password = $this->getElement('password')->getValue();
|
||||
$authenticated = $authChain->authenticate($user, $password);
|
||||
if ($authenticated) {
|
||||
$auth->setAuthenticated($user);
|
||||
$this->getResponse()->setRerenderLayout(true);
|
||||
return true;
|
||||
}
|
||||
switch ($authChain->getError()) {
|
||||
case $authChain::EEMPTY:
|
||||
$this->addError($this->translate(
|
||||
'No authentication methods available.'
|
||||
. ' Did you create authentication.ini when setting up Icinga Web 2?'
|
||||
));
|
||||
break;
|
||||
case $authChain::EFAIL:
|
||||
$this->addError($this->translate(
|
||||
'All configured authentication methods failed.'
|
||||
. ' Please check the system log or Icinga Web 2 log for more information.'
|
||||
));
|
||||
break;
|
||||
/** @noinspection PhpMissingBreakStatementInspection */
|
||||
case $authChain::ENOTALL:
|
||||
$this->addError($this->translate(
|
||||
'Please note that not all authentication methods were available.'
|
||||
. ' Check the system log or Icinga Web 2 log for more information.'
|
||||
));
|
||||
// Move to default
|
||||
default:
|
||||
$this->getElement('password')->addError($this->translate('Incorrect username or password'));
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function onRequest()
|
||||
{
|
||||
$auth = Auth::getInstance();
|
||||
$onlyExternal = true;
|
||||
// TODO(el): This may be set on the auth chain once iterated. See Auth::authExternal().
|
||||
foreach ($auth->getAuthChain() as $backend) {
|
||||
if (! $backend instanceof ExternalBackend) {
|
||||
$onlyExternal = false;
|
||||
}
|
||||
}
|
||||
if ($onlyExternal) {
|
||||
$this->addError($this->translate(
|
||||
'You\'re currently not authenticated using any of the web server\'s authentication mechanisms.'
|
||||
. ' Make sure you\'ll configure such, otherwise you\'ll not be able to login.'
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms;
|
||||
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\User\Preferences;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Web\Session;
|
||||
use Icinga\Web\Url;
|
||||
|
||||
/**
|
||||
* Form class to adjust user auto refresh preferences
|
||||
*/
|
||||
class AutoRefreshForm extends Form
|
||||
{
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_auto_refresh');
|
||||
// Post against the current location
|
||||
$this->setAction('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust preferences and persist them
|
||||
*
|
||||
* @see Form::onSuccess()
|
||||
*/
|
||||
public function onSuccess()
|
||||
{
|
||||
/** @var Preferences $preferences */
|
||||
$preferences = $this->getRequest()->getUser()->getPreferences();
|
||||
$icingaweb = $preferences->get('icingaweb');
|
||||
|
||||
if ((bool) $preferences->getValue('icingaweb', 'auto_refresh', true) === false) {
|
||||
$icingaweb['auto_refresh'] = '1';
|
||||
$notification = $this->translate('Auto refresh successfully enabled');
|
||||
} else {
|
||||
$icingaweb['auto_refresh'] = '0';
|
||||
$notification = $this->translate('Auto refresh successfully disabled');
|
||||
}
|
||||
$preferences->icingaweb = $icingaweb;
|
||||
|
||||
Session::getSession()->user->setPreferences($preferences);
|
||||
Notification::success($notification);
|
||||
|
||||
$this->getResponse()->setHeader('X-Icinga-Rerender-Layout', 'yes');
|
||||
$this->setRedirectUrl(Url::fromRequest()->without('renderLayout'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$preferences = $this->getRequest()->getUser()->getPreferences();
|
||||
|
||||
if ((bool) $preferences->getValue('icingaweb', 'auto_refresh', true) === false) {
|
||||
$value = $this->translate('Enable auto refresh');
|
||||
} else {
|
||||
$value = $this->translate('Disable auto refresh');
|
||||
}
|
||||
|
||||
$this->addElements(array(
|
||||
array(
|
||||
'button',
|
||||
'btn_submit',
|
||||
array(
|
||||
'ignore' => true,
|
||||
'type' => 'submit',
|
||||
'value' => $value,
|
||||
'decorators' => array('ViewHelper'),
|
||||
'escape' => false,
|
||||
'class' => 'link-like'
|
||||
)
|
||||
)
|
||||
));
|
||||
}
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Forms\Config\Authentication;
|
||||
|
||||
use Zend_Validate_Callback;
|
||||
use Icinga\Web\Form;
|
||||
|
||||
/**
|
||||
* Form class for adding/modifying autologin authentication backends
|
||||
*/
|
||||
class AutologinBackendForm extends Form
|
||||
{
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_config_authbackend_autologin');
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$this->addElement(
|
||||
'text',
|
||||
'name',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Backend Name'),
|
||||
'description' => t(
|
||||
'The name of this authentication provider that is used to differentiate it from others'
|
||||
),
|
||||
'validators' => array(
|
||||
array(
|
||||
'Regex',
|
||||
false,
|
||||
array(
|
||||
'pattern' => '/^[^\\[\\]:]+$/',
|
||||
'messages' => array(
|
||||
'regexNotMatch' => 'The backend name cannot contain \'[\', \']\' or \':\'.'
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'strip_username_regexp',
|
||||
array(
|
||||
'label' => t('Filter Pattern'),
|
||||
'description' => t('The regular expression to use to strip specific parts off from usernames. Leave empty if you do not want to strip off anything'),
|
||||
'value' => '/\@[^$]+$/',
|
||||
'validators' => array(
|
||||
new Zend_Validate_Callback(function ($value) {
|
||||
return @preg_match($value, '') !== false;
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'hidden',
|
||||
'backend',
|
||||
array(
|
||||
'disabled' => true,
|
||||
'value' => 'autologin'
|
||||
)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the configuration by creating a backend and requesting the user count
|
||||
*
|
||||
* Returns always true as autologin backends are just "passive" backends. (The webserver authenticates users.)
|
||||
*
|
||||
* @param Form $form The form to fetch the configuration values from
|
||||
*
|
||||
* @return bool Whether validation succeeded or not
|
||||
*/
|
||||
public static function isValidAuthenticationBackend(Form $form)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,130 +0,0 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Forms\Config\Authentication;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Authentication\Backend\DbUserBackend;
|
||||
|
||||
/**
|
||||
* Form class for adding/modifying database authentication backends
|
||||
*/
|
||||
class DbBackendForm extends Form
|
||||
{
|
||||
/**
|
||||
* The database resource names the user can choose from
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $resources;
|
||||
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_config_authbackend_db');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the resource names the user can choose from
|
||||
*
|
||||
* @param array $resources The resources to choose from
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setResources(array $resources)
|
||||
{
|
||||
$this->resources = $resources;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$this->addElement(
|
||||
'text',
|
||||
'name',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Backend Name'),
|
||||
'description' => t(
|
||||
'The name of this authentication provider that is used to differentiate it from others'
|
||||
),
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'select',
|
||||
'resource',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Database Connection'),
|
||||
'description' => t('The database connection to use for authenticating with this provider'),
|
||||
'multiOptions' => false === empty($this->resources)
|
||||
? array_combine($this->resources, $this->resources)
|
||||
: array()
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'hidden',
|
||||
'backend',
|
||||
array(
|
||||
'disabled' => true,
|
||||
'value' => 'db'
|
||||
)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the selected resource is a valid database authentication backend
|
||||
*
|
||||
* @see Form::onSuccess()
|
||||
*/
|
||||
public function onSuccess()
|
||||
{
|
||||
if (false === static::isValidAuthenticationBackend($this)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the configuration by creating a backend and requesting the user count
|
||||
*
|
||||
* @param Form $form The form to fetch the configuration values from
|
||||
*
|
||||
* @return bool Whether validation succeeded or not
|
||||
*/
|
||||
public static function isValidAuthenticationBackend(Form $form)
|
||||
{
|
||||
try {
|
||||
$dbUserBackend = new DbUserBackend(ResourceFactory::createResource($form->getResourceConfig()));
|
||||
if ($dbUserBackend->count() < 1) {
|
||||
$form->addError(t('No users found under the specified database backend'));
|
||||
return false;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$form->addError(sprintf(t('Using the specified backend failed: %s'), $e->getMessage()));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the configuration for the chosen resource
|
||||
*
|
||||
* @return ConfigObject
|
||||
*/
|
||||
public function getResourceConfig()
|
||||
{
|
||||
return ResourceFactory::getResourceConfig($this->getValue('resource'));
|
||||
}
|
||||
}
|
|
@ -1,165 +0,0 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Forms\Config\Authentication;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Exception\AuthenticationException;
|
||||
use Icinga\Authentication\Backend\LdapUserBackend;
|
||||
|
||||
/**
|
||||
* Form class for adding/modifying LDAP authentication backends
|
||||
*/
|
||||
class LdapBackendForm extends Form
|
||||
{
|
||||
/**
|
||||
* The ldap resource names the user can choose from
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $resources;
|
||||
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_config_authbackend_ldap');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the resource names the user can choose from
|
||||
*
|
||||
* @param array $resources The resources to choose from
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setResources(array $resources)
|
||||
{
|
||||
$this->resources = $resources;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$this->addElement(
|
||||
'text',
|
||||
'name',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Backend Name'),
|
||||
'description' => t(
|
||||
'The name of this authentication provider that is used to differentiate it from others'
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'select',
|
||||
'resource',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('LDAP Resource'),
|
||||
'description' => t('The resource to use for authenticating with this provider'),
|
||||
'multiOptions' => false === empty($this->resources)
|
||||
? array_combine($this->resources, $this->resources)
|
||||
: array()
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'user_class',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('LDAP User Object Class'),
|
||||
'description' => t('The object class used for storing users on the ldap server'),
|
||||
'value' => 'inetOrgPerson'
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'user_name_attribute',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('LDAP User Name Attribute'),
|
||||
'description' => t('The attribute name used for storing the user name on the ldap server'),
|
||||
'value' => 'uid'
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'hidden',
|
||||
'backend',
|
||||
array(
|
||||
'disabled' => true,
|
||||
'value' => 'ldap'
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'base_dn',
|
||||
array(
|
||||
'required' => false,
|
||||
'label' => t('Base DN'),
|
||||
'description' => t('The path where users can be found on the ldap server. ' .
|
||||
' Leave empty to select all users available on the specified resource.')
|
||||
)
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the selected resource is a valid ldap authentication backend
|
||||
*
|
||||
* @see Form::onSuccess()
|
||||
*/
|
||||
public function onSuccess()
|
||||
{
|
||||
if (false === static::isValidAuthenticationBackend($this)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the configuration by creating a backend and requesting the user count
|
||||
*
|
||||
* @param Form $form The form to fetch the configuration values from
|
||||
*
|
||||
* @return bool Whether validation succeeded or not
|
||||
*/
|
||||
public static function isValidAuthenticationBackend(Form $form)
|
||||
{
|
||||
try {
|
||||
$ldapUserBackend = new LdapUserBackend(
|
||||
ResourceFactory::createResource($form->getResourceConfig()),
|
||||
$form->getElement('user_class')->getValue(),
|
||||
$form->getElement('user_name_attribute')->getValue(),
|
||||
$form->getElement('base_dn')->getValue()
|
||||
);
|
||||
$ldapUserBackend->assertAuthenticationPossible();
|
||||
} catch (AuthenticationException $e) {
|
||||
$form->addError($e->getMessage());
|
||||
return false;
|
||||
} catch (Exception $e) {
|
||||
$form->addError(sprintf(t('Unable to validate authentication: %s'), $e->getMessage()));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the configuration for the chosen resource
|
||||
*
|
||||
* @return ConfigObject
|
||||
*/
|
||||
public function getResourceConfig()
|
||||
{
|
||||
return ResourceFactory::getResourceConfig($this->getValue('resource'));
|
||||
}
|
||||
}
|
|
@ -1,344 +0,0 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Forms\Config;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Icinga\Forms\ConfigForm;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Application\Platform;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Forms\Config\Authentication\DbBackendForm;
|
||||
use Icinga\Forms\Config\Authentication\LdapBackendForm;
|
||||
use Icinga\Forms\Config\Authentication\AutologinBackendForm;
|
||||
|
||||
class AuthenticationBackendConfigForm extends ConfigForm
|
||||
{
|
||||
/**
|
||||
* The available resources split by type
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $resources;
|
||||
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_config_authbackend');
|
||||
$this->setSubmitLabel(t('Save Changes'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the resource configuration to use
|
||||
*
|
||||
* @param Config $resources The resource configuration
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setResourceConfig(Config $resourceConfig)
|
||||
{
|
||||
$resources = array();
|
||||
foreach ($resourceConfig as $name => $resource) {
|
||||
$resources[strtolower($resource->type)][] = $name;
|
||||
}
|
||||
|
||||
$this->resources = $resources;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a form object for the given backend type
|
||||
*
|
||||
* @param string $type The backend type for which to return a form
|
||||
*
|
||||
* @return Form
|
||||
*/
|
||||
public function getBackendForm($type)
|
||||
{
|
||||
if ($type === 'db') {
|
||||
$form = new DbBackendForm();
|
||||
$form->setResources(isset($this->resources['db']) ? $this->resources['db'] : array());
|
||||
} elseif ($type === 'ldap') {
|
||||
$form = new LdapBackendForm();
|
||||
$form->setResources(isset($this->resources['ldap']) ? $this->resources['ldap'] : array());
|
||||
} elseif ($type === 'autologin') {
|
||||
$form = new AutologinBackendForm();
|
||||
} else {
|
||||
throw new InvalidArgumentException(sprintf(t('Invalid backend type "%s" provided'), $type));
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a particular authentication backend
|
||||
*
|
||||
* The backend to add is identified by the array-key `name'.
|
||||
*
|
||||
* @param array $values The values to extend the configuration with
|
||||
*
|
||||
* @return self
|
||||
*
|
||||
* @throws InvalidArgumentException In case the backend does already exist
|
||||
*/
|
||||
public function add(array $values)
|
||||
{
|
||||
$name = isset($values['name']) ? $values['name'] : '';
|
||||
if (! $name) {
|
||||
throw new InvalidArgumentException(t('Authentication backend name missing'));
|
||||
} elseif ($this->config->hasSection($name)) {
|
||||
throw new InvalidArgumentException(t('Authentication backend already exists'));
|
||||
}
|
||||
|
||||
unset($values['name']);
|
||||
$this->config->setSection($name, $values);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit a particular authentication backend
|
||||
*
|
||||
* @param string $name The name of the backend to edit
|
||||
* @param array $values The values to edit the configuration with
|
||||
*
|
||||
* @return array The edited backend configuration
|
||||
*
|
||||
* @throws InvalidArgumentException In case the backend does not exist
|
||||
*/
|
||||
public function edit($name, array $values)
|
||||
{
|
||||
if (! $name) {
|
||||
throw new InvalidArgumentException(t('Old authentication backend name missing'));
|
||||
} elseif (! ($newName = isset($values['name']) ? $values['name'] : '')) {
|
||||
throw new InvalidArgumentException(t('New authentication backend name missing'));
|
||||
} elseif (! $this->config->hasSection($name)) {
|
||||
throw new InvalidArgumentException(t('Unknown authentication backend provided'));
|
||||
}
|
||||
|
||||
$backendConfig = $this->config->getSection($name);
|
||||
if ($newName !== $name) {
|
||||
// Only remove the old entry if it has changed as the order gets screwed when editing backend names
|
||||
$this->config->removeSection($name);
|
||||
}
|
||||
|
||||
unset($values['name']);
|
||||
$this->config->setSection($newName, $backendConfig->merge($values));
|
||||
return $backendConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given authentication backend
|
||||
*
|
||||
* @param string $name The name of the backend to remove
|
||||
*
|
||||
* @return array The removed backend configuration
|
||||
*
|
||||
* @throws InvalidArgumentException In case the backend does not exist
|
||||
*/
|
||||
public function remove($name)
|
||||
{
|
||||
if (! $name) {
|
||||
throw new InvalidArgumentException(t('Authentication backend name missing'));
|
||||
} elseif (! $this->config->hasSection($name)) {
|
||||
throw new InvalidArgumentException(t('Unknown authentication backend provided'));
|
||||
}
|
||||
|
||||
$backendConfig = $this->config->getSection($name);
|
||||
$this->config->removeSection($name);
|
||||
return $backendConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the given authentication backend up or down in order
|
||||
*
|
||||
* @param string $name The name of the backend to be moved
|
||||
* @param int $position The new (absolute) position of the backend
|
||||
*
|
||||
* @return self
|
||||
*
|
||||
* @throws InvalidArgumentException In case the backend does not exist
|
||||
*/
|
||||
public function move($name, $position)
|
||||
{
|
||||
if (! $name) {
|
||||
throw new InvalidArgumentException(t('Authentication backend name missing'));
|
||||
} elseif (! $this->config->hasSection($name)) {
|
||||
throw new InvalidArgumentException(t('Unknown authentication backend provided'));
|
||||
}
|
||||
|
||||
$backendOrder = $this->config->keys();
|
||||
array_splice($backendOrder, array_search($name, $backendOrder), 1);
|
||||
array_splice($backendOrder, $position, 0, $name);
|
||||
|
||||
$newConfig = array();
|
||||
foreach ($backendOrder as $backendName) {
|
||||
$newConfig[$backendName] = $this->config->getSection($backendName);
|
||||
}
|
||||
|
||||
$config = Config::fromArray($newConfig);
|
||||
$this->config = $config->setConfigFile($this->config->getConfigFile());
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or edit an authentication backend and save the configuration
|
||||
*
|
||||
* Performs a connectivity validation using the submitted values. A checkbox is
|
||||
* added to the form to skip the check if it fails and redirection is aborted.
|
||||
*
|
||||
* @see Form::onSuccess()
|
||||
*/
|
||||
public function onSuccess()
|
||||
{
|
||||
if (($el = $this->getElement('force_creation')) === null || false === $el->isChecked()) {
|
||||
$backendForm = $this->getBackendForm($this->getElement('type')->getValue());
|
||||
if (false === $backendForm::isValidAuthenticationBackend($this)) {
|
||||
$this->addElement($this->getForceCreationCheckbox());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$authBackend = $this->request->getQuery('auth_backend');
|
||||
try {
|
||||
if ($authBackend === null) { // create new backend
|
||||
$this->add($this->getValues());
|
||||
$message = t('Authentication backend "%s" has been successfully created');
|
||||
} else { // edit existing backend
|
||||
$this->edit($authBackend, $this->getValues());
|
||||
$message = t('Authentication backend "%s" has been successfully changed');
|
||||
}
|
||||
} catch (InvalidArgumentException $e) {
|
||||
Notification::error($e->getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->save()) {
|
||||
Notification::success(sprintf($message, $this->getElement('name')->getValue()));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the form in case an authentication backend is being edited
|
||||
*
|
||||
* @see Form::onRequest()
|
||||
*
|
||||
* @throws ConfigurationError In case the backend name is missing in the request or is invalid
|
||||
*/
|
||||
public function onRequest()
|
||||
{
|
||||
$authBackend = $this->request->getQuery('auth_backend');
|
||||
if ($authBackend !== null) {
|
||||
if ($authBackend === '') {
|
||||
throw new ConfigurationError(t('Authentication backend name missing'));
|
||||
} elseif (! $this->config->hasSection($authBackend)) {
|
||||
throw new ConfigurationError(t('Unknown authentication backend provided'));
|
||||
} elseif ($this->config->getSection($authBackend)->backend === null) {
|
||||
throw new ConfigurationError(sprintf(t('Backend "%s" has no `backend\' setting'), $authBackend));
|
||||
}
|
||||
|
||||
$configValues = $this->config->getSection($authBackend)->toArray();
|
||||
$configValues['type'] = $configValues['backend'];
|
||||
$configValues['name'] = $authBackend;
|
||||
$this->populate($configValues);
|
||||
} elseif (empty($this->resources)) {
|
||||
$autologinBackends = array_filter(
|
||||
$this->config->toArray(),
|
||||
function ($authBackendCfg) {
|
||||
return isset($authBackendCfg['backend']) && $authBackendCfg['backend'] === 'autologin';
|
||||
}
|
||||
);
|
||||
|
||||
if (false === empty($autologinBackends)) {
|
||||
throw new ConfigurationError(t('Could not find any resources for authentication'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a checkbox to be displayed at the beginning of the form
|
||||
* which allows the user to skip the connection validation
|
||||
*
|
||||
* @return Zend_Form_Element
|
||||
*/
|
||||
protected function getForceCreationCheckbox()
|
||||
{
|
||||
return $this->createElement(
|
||||
'checkbox',
|
||||
'force_creation',
|
||||
array(
|
||||
'order' => 0,
|
||||
'ignore' => true,
|
||||
'label' => t('Force Changes'),
|
||||
'description' => t('Check this box to enforce changes without connectivity validation')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$backendTypes = array();
|
||||
$backendType = isset($formData['type']) ? $formData['type'] : null;
|
||||
|
||||
if (isset($this->resources['db'])) {
|
||||
$backendTypes['db'] = t('Database');
|
||||
}
|
||||
if (isset($this->resources['ldap']) && ($backendType === 'ldap' || Platform::extensionLoaded('ldap'))) {
|
||||
$backendTypes['ldap'] = 'LDAP';
|
||||
}
|
||||
|
||||
$autologinBackends = array_filter(
|
||||
$this->config->toArray(),
|
||||
function ($authBackendCfg) {
|
||||
return isset($authBackendCfg['backend']) && $authBackendCfg['backend'] === 'autologin';
|
||||
}
|
||||
);
|
||||
if ($backendType === 'autologin' || empty($autologinBackends)) {
|
||||
$backendTypes['autologin'] = t('Autologin');
|
||||
}
|
||||
|
||||
if ($backendType === null) {
|
||||
$backendType = key($backendTypes);
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
'select',
|
||||
'type',
|
||||
array(
|
||||
'ignore' => true,
|
||||
'required' => true,
|
||||
'autosubmit' => true,
|
||||
'label' => t('Backend Type'),
|
||||
'description' => t('The type of the resource to use for this authenticaton provider'),
|
||||
'multiOptions' => $backendTypes
|
||||
)
|
||||
);
|
||||
|
||||
if (isset($formData['force_creation']) && $formData['force_creation']) {
|
||||
// In case another error occured and the checkbox was displayed before
|
||||
$this->addElement($this->getForceCreationCheckbox());
|
||||
}
|
||||
|
||||
$this->addElements($this->getBackendForm($backendType)->createElements($formData)->getElements());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the configuration for the chosen resource
|
||||
*
|
||||
* @return ConfigObject
|
||||
*/
|
||||
public function getResourceConfig()
|
||||
{
|
||||
return ResourceFactory::getResourceConfig($this->getValue('resource'));
|
||||
}
|
||||
}
|
|
@ -1,16 +1,12 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms\Config\General;
|
||||
|
||||
use DateTimeZone;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Util\Translator;
|
||||
use Icinga\Web\Form;
|
||||
|
||||
|
||||
/**
|
||||
* Form class to modify the general application configuration
|
||||
*/
|
||||
|
@ -33,10 +29,10 @@ class ApplicationConfigForm extends Form
|
|||
'text',
|
||||
'global_module_path',
|
||||
array(
|
||||
'label' => t('Module Path'),
|
||||
'label' => $this->translate('Module Path'),
|
||||
'required' => true,
|
||||
'value' => implode(':', Icinga::app()->getModuleManager()->getModuleDirs()),
|
||||
'description' => t(
|
||||
'description' => $this->translate(
|
||||
'Contains the directories that will be searched for available modules, separated by '
|
||||
. 'colons. Modules that don\'t exist in these directories can still be symlinked in '
|
||||
. 'the module folder, but won\'t show up in the list of disabled modules.'
|
||||
|
@ -46,19 +42,19 @@ class ApplicationConfigForm extends Form
|
|||
|
||||
$this->addElement(
|
||||
'select',
|
||||
'preferences_type',
|
||||
'global_config_backend',
|
||||
array(
|
||||
'required' => true,
|
||||
'autosubmit' => true,
|
||||
'label' => t('User Preference Storage Type'),
|
||||
'label' => $this->translate('User Preference Storage Type'),
|
||||
'multiOptions' => array(
|
||||
'ini' => t('File System (INI Files)'),
|
||||
'db' => t('Database'),
|
||||
'null' => t('Don\'t Store Preferences')
|
||||
'ini' => $this->translate('File System (INI Files)'),
|
||||
'db' => $this->translate('Database'),
|
||||
'none' => $this->translate('Don\'t Store Preferences')
|
||||
)
|
||||
)
|
||||
);
|
||||
if (isset($formData['preferences_type']) && $formData['preferences_type'] === 'db') {
|
||||
if (isset($formData['global_config_backend']) && $formData['global_config_backend'] === 'db') {
|
||||
$backends = array();
|
||||
foreach (ResourceFactory::getResourceConfigs()->toArray() as $name => $resource) {
|
||||
if ($resource['type'] === 'db') {
|
||||
|
@ -68,11 +64,11 @@ class ApplicationConfigForm extends Form
|
|||
|
||||
$this->addElement(
|
||||
'select',
|
||||
'preferences_resource',
|
||||
'global_config_resource',
|
||||
array(
|
||||
'required' => true,
|
||||
'multiOptions' => $backends,
|
||||
'label' => t('Database Connection')
|
||||
'label' => $this->translate('Database Connection')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms\Config\General;
|
||||
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Form\Validator\WritablePathValidator;
|
||||
|
||||
class LoggingConfigForm extends Form
|
||||
{
|
||||
|
@ -31,12 +28,12 @@ class LoggingConfigForm extends Form
|
|||
array(
|
||||
'required' => true,
|
||||
'autosubmit' => true,
|
||||
'label' => t('Logging Type'),
|
||||
'description' => t('The type of logging to utilize.'),
|
||||
'label' => $this->translate('Logging Type'),
|
||||
'description' => $this->translate('The type of logging to utilize.'),
|
||||
'multiOptions' => array(
|
||||
'syslog' => 'Syslog',
|
||||
'file' => t('File', 'app.config.logging.type'),
|
||||
'none' => t('None', 'app.config.logging.type')
|
||||
'file' => $this->translate('File', 'app.config.logging.type'),
|
||||
'none' => $this->translate('None', 'app.config.logging.type')
|
||||
)
|
||||
)
|
||||
);
|
||||
|
@ -47,13 +44,13 @@ class LoggingConfigForm extends Form
|
|||
'logging_level',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Logging Level'),
|
||||
'description' => t('The maximum logging level to emit.'),
|
||||
'label' => $this->translate('Logging Level'),
|
||||
'description' => $this->translate('The maximum logging level to emit.'),
|
||||
'multiOptions' => array(
|
||||
Logger::$levels[Logger::ERROR] => t('Error', 'app.config.logging.level'),
|
||||
Logger::$levels[Logger::WARNING] => t('Warning', 'app.config.logging.level'),
|
||||
Logger::$levels[Logger::INFO] => t('Information', 'app.config.logging.level'),
|
||||
Logger::$levels[Logger::DEBUG] => t('Debug', 'app.config.logging.level')
|
||||
Logger::$levels[Logger::ERROR] => $this->translate('Error', 'app.config.logging.level'),
|
||||
Logger::$levels[Logger::WARNING] => $this->translate('Warning', 'app.config.logging.level'),
|
||||
Logger::$levels[Logger::INFO] => $this->translate('Information', 'app.config.logging.level'),
|
||||
Logger::$levels[Logger::DEBUG] => $this->translate('Debug', 'app.config.logging.level')
|
||||
)
|
||||
)
|
||||
);
|
||||
|
@ -65,9 +62,12 @@ class LoggingConfigForm extends Form
|
|||
'logging_application',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Application Prefix'),
|
||||
'description' => t('The name of the application by which to prefix syslog messages.'),
|
||||
'value' => 'icingaweb',
|
||||
'label' => $this->translate('Application Prefix'),
|
||||
'description' => $this->translate(
|
||||
'The name of the application by which to prefix syslog messages.'
|
||||
),
|
||||
'requirement' => $this->translate('The application prefix must not contain whitespace.'),
|
||||
'value' => 'icingaweb2',
|
||||
'validators' => array(
|
||||
array(
|
||||
'Regex',
|
||||
|
@ -75,7 +75,9 @@ class LoggingConfigForm extends Form
|
|||
array(
|
||||
'pattern' => '/^[^\W]+$/',
|
||||
'messages' => array(
|
||||
'regexNotMatch' => 'The application prefix cannot contain any whitespaces.'
|
||||
'regexNotMatch' => $this->translate(
|
||||
'The application prefix must not contain whitespace.'
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -91,8 +93,8 @@ class LoggingConfigForm extends Form
|
|||
// 'logging_facility',
|
||||
// array(
|
||||
// 'required' => true,
|
||||
// 'label' => t('Facility'),
|
||||
// 'description' => t('The syslog facility to utilize.'),
|
||||
// 'label' => $this->translate('Facility'),
|
||||
// 'description' => $this->translate('The syslog facility to utilize.'),
|
||||
// 'multiOptions' => array(
|
||||
// 'user' => 'LOG_USER'
|
||||
// )
|
||||
|
@ -104,24 +106,14 @@ class LoggingConfigForm extends Form
|
|||
'logging_file',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('File path'),
|
||||
'description' => t('The full path to the log file to write messages to.'),
|
||||
'value' => $this->getDefaultLogDir(),
|
||||
'validators' => array(new WritablePathValidator())
|
||||
'label' => $this->translate('File path'),
|
||||
'description' => $this->translate('The full path to the log file to write messages to.'),
|
||||
'value' => '/var/log/icingaweb2/icingaweb2.log',
|
||||
'validators' => array('WritablePathValidator')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default logging directory for type 'file'
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getDefaultLogDir()
|
||||
{
|
||||
return realpath(Icinga::app()->getApplicationDir('../var/log/icingaweb.log'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms\Config;
|
||||
|
||||
|
@ -20,7 +19,8 @@ class GeneralConfigForm extends ConfigForm
|
|||
public function init()
|
||||
{
|
||||
$this->setName('form_config_general');
|
||||
$this->setSubmitLabel(t('Save Changes'));
|
||||
$this->setSubmitLabel($this->translate('Save Changes'));
|
||||
$this->setTitle($this->translate('General Configuration'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -52,7 +52,7 @@ class GeneralConfigForm extends ConfigForm
|
|||
}
|
||||
|
||||
if ($this->save()) {
|
||||
Notification::success(t('New configuration has successfully been stored'));
|
||||
Notification::success($this->translate('New configuration has successfully been stored'));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms\Config\Resource;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Application\Platform;
|
||||
|
||||
/**
|
||||
|
@ -24,7 +20,9 @@ class DbResourceForm extends Form
|
|||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
* Create and add elements to this form
|
||||
*
|
||||
* @param array $formData The data sent by the user
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
|
@ -41,8 +39,8 @@ class DbResourceForm extends Form
|
|||
'name',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Resource Name'),
|
||||
'description' => t('The unique name of this resource')
|
||||
'label' => $this->translate('Resource Name'),
|
||||
'description' => $this->translate('The unique name of this resource')
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
|
@ -50,8 +48,9 @@ class DbResourceForm extends Form
|
|||
'db',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Database Type'),
|
||||
'description' => t('The type of SQL database'),
|
||||
'autosubmit' => true,
|
||||
'label' => $this->translate('Database Type'),
|
||||
'description' => $this->translate('The type of SQL database'),
|
||||
'multiOptions' => $dbChoices
|
||||
)
|
||||
);
|
||||
|
@ -60,8 +59,8 @@ class DbResourceForm extends Form
|
|||
'host',
|
||||
array (
|
||||
'required' => true,
|
||||
'label' => t('Host'),
|
||||
'description' => t('The hostname of the database'),
|
||||
'label' => $this->translate('Host'),
|
||||
'description' => $this->translate('The hostname of the database'),
|
||||
'value' => 'localhost'
|
||||
)
|
||||
);
|
||||
|
@ -69,10 +68,11 @@ class DbResourceForm extends Form
|
|||
'number',
|
||||
'port',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Port'),
|
||||
'description' => t('The port to use'),
|
||||
'value' => 3306
|
||||
'required' => true,
|
||||
'preserveDefault' => true,
|
||||
'label' => $this->translate('Port'),
|
||||
'description' => $this->translate('The port to use'),
|
||||
'value' => ! array_key_exists('db', $formData) || $formData['db'] === 'mysql' ? 3306 : 5432
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
|
@ -80,8 +80,8 @@ class DbResourceForm extends Form
|
|||
'dbname',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Database Name'),
|
||||
'description' => t('The name of the database to use')
|
||||
'label' => $this->translate('Database Name'),
|
||||
'description' => $this->translate('The name of the database to use')
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
|
@ -89,8 +89,8 @@ class DbResourceForm extends Form
|
|||
'username',
|
||||
array (
|
||||
'required' => true,
|
||||
'label' => t('Username'),
|
||||
'description' => t('The user name to use for authentication')
|
||||
'label' => $this->translate('Username'),
|
||||
'description' => $this->translate('The user name to use for authentication')
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
|
@ -99,43 +99,11 @@ class DbResourceForm extends Form
|
|||
array(
|
||||
'required' => true,
|
||||
'renderPassword' => true,
|
||||
'label' => t('Password'),
|
||||
'description' => t('The password to use for authentication')
|
||||
'label' => $this->translate('Password'),
|
||||
'description' => $this->translate('The password to use for authentication')
|
||||
)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the current configuration points to a valid resource
|
||||
*
|
||||
* @see Form::onSuccess()
|
||||
*/
|
||||
public function onSuccess()
|
||||
{
|
||||
if (false === static::isValidResource($this)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the resource configuration by trying to connect with it
|
||||
*
|
||||
* @param Form $form The form to fetch the configuration values from
|
||||
*
|
||||
* @return bool Whether validation succeeded or not
|
||||
*/
|
||||
public static function isValidResource(Form $form)
|
||||
{
|
||||
try {
|
||||
$resource = ResourceFactory::createResource(new ConfigObject($form->getValues()));
|
||||
$resource->getConnection()->getConnection();
|
||||
} catch (Exception $e) {
|
||||
$form->addError(t('Connectivity validation failed, connection to the given resource not possible.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms\Config\Resource;
|
||||
|
||||
use Zend_Validate_Callback;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Form\Validator\ReadablePathValidator;
|
||||
|
||||
/**
|
||||
* Form class for adding/modifying file resources
|
||||
|
@ -30,8 +29,8 @@ class FileResourceForm extends Form
|
|||
'name',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Resource Name'),
|
||||
'description' => t('The unique name of this resource')
|
||||
'label' => $this->translate('Resource Name'),
|
||||
'description' => $this->translate('The unique name of this resource')
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
|
@ -39,18 +38,27 @@ class FileResourceForm extends Form
|
|||
'filename',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Filepath'),
|
||||
'description' => t('The filename to fetch information from'),
|
||||
'validators' => array(new ReadablePathValidator())
|
||||
'label' => $this->translate('Filepath'),
|
||||
'description' => $this->translate('The filename to fetch information from'),
|
||||
'validators' => array('ReadablePathValidator')
|
||||
)
|
||||
);
|
||||
$callbackValidator = new Zend_Validate_Callback(function ($value) {
|
||||
return @preg_match($value, '') !== false;
|
||||
});
|
||||
$callbackValidator->setMessage(
|
||||
$this->translate('"%value%" is not a valid regular expression.'),
|
||||
Zend_Validate_Callback::INVALID_VALUE
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'fields',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Pattern'),
|
||||
'description' => t('The regular expression by which to identify columns')
|
||||
'label' => $this->translate('Pattern'),
|
||||
'description' => $this->translate('The pattern by which to identify columns.'),
|
||||
'requirement' => $this->translate('The column pattern must be a valid regular expression.'),
|
||||
'validators' => array($callbackValidator)
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms\Config\Resource;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Protocol\Ldap\LdapConnection;
|
||||
|
||||
/**
|
||||
* Form class for adding/modifying ldap resources
|
||||
|
@ -23,17 +20,23 @@ class LdapResourceForm extends Form
|
|||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
* Create and add elements to this form
|
||||
*
|
||||
* @param array $formData The data sent by the user
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$defaultPort = ! array_key_exists('encryption', $formData) || $formData['encryption'] !== LdapConnection::LDAPS
|
||||
? 389
|
||||
: 636;
|
||||
|
||||
$this->addElement(
|
||||
'text',
|
||||
'name',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Resource Name'),
|
||||
'description' => t('The unique name of this resource')
|
||||
'label' => $this->translate('Resource Name'),
|
||||
'description' => $this->translate('The unique name of this resource')
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
|
@ -41,8 +44,10 @@ class LdapResourceForm extends Form
|
|||
'hostname',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Host'),
|
||||
'description' => t('The hostname or address of the LDAP server to use for authentication'),
|
||||
'label' => $this->translate('Host'),
|
||||
'description' => $this->translate(
|
||||
'The hostname or address of the LDAP server to use for authentication'
|
||||
),
|
||||
'value' => 'localhost'
|
||||
)
|
||||
);
|
||||
|
@ -50,79 +55,80 @@ class LdapResourceForm extends Form
|
|||
'number',
|
||||
'port',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Port'),
|
||||
'description' => t('The port of the LDAP server to use for authentication'),
|
||||
'value' => 389
|
||||
'required' => true,
|
||||
'preserveDefault' => true,
|
||||
'label' => $this->translate('Port'),
|
||||
'description' => $this->translate('The port of the LDAP server to use for authentication'),
|
||||
'value' => $defaultPort
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'select',
|
||||
'encryption',
|
||||
array(
|
||||
'required' => true,
|
||||
'autosubmit' => true,
|
||||
'label' => $this->translate('Encryption'),
|
||||
'description' => $this->translate(
|
||||
'Whether to encrypt communication. Choose STARTTLS or LDAPS for encrypted communication or'
|
||||
. ' none for unencrypted communication'
|
||||
),
|
||||
'multiOptions' => array(
|
||||
'none' => $this->translate('None', 'resource.ldap.encryption'),
|
||||
LdapConnection::STARTTLS => 'STARTTLS',
|
||||
LdapConnection::LDAPS => 'LDAPS'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if (isset($formData['encryption']) && $formData['encryption'] !== 'none') {
|
||||
// TODO(jom): Do not show this checkbox unless the connection is actually failing due to certificate errors
|
||||
$this->addElement(
|
||||
'checkbox',
|
||||
'reqcert',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => $this->translate('Require Certificate'),
|
||||
'description' => $this->translate(
|
||||
'When checked, the LDAP server must provide a valid and known (trusted) certificate.'
|
||||
),
|
||||
'value' => 1
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
'text',
|
||||
'root_dn',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Root DN'),
|
||||
'description' => t('Only the root and its child nodes will be accessible on this resource.')
|
||||
'label' => $this->translate('Root DN'),
|
||||
'description' => $this->translate(
|
||||
'Only the root and its child nodes will be accessible on this resource.'
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'bind_dn',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Bind DN'),
|
||||
'description' => t('The user dn to use for querying the ldap server')
|
||||
'label' => $this->translate('Bind DN'),
|
||||
'description' => $this->translate(
|
||||
'The user dn to use for querying the ldap server. Leave the dn and password empty for attempting'
|
||||
. ' an anonymous bind'
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'password',
|
||||
'bind_pw',
|
||||
array(
|
||||
'required' => true,
|
||||
'renderPassword' => true,
|
||||
'label' => t('Bind Password'),
|
||||
'description' => t('The password to use for querying the ldap server')
|
||||
'label' => $this->translate('Bind Password'),
|
||||
'description' => $this->translate('The password to use for querying the ldap server')
|
||||
)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the current configuration points to a valid resource
|
||||
*
|
||||
* @see Form::onSuccess()
|
||||
*/
|
||||
public function onSuccess()
|
||||
{
|
||||
if (false === static::isValidResource($this)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the resource configuration by trying to connect with it
|
||||
*
|
||||
* @param Form $form The form to fetch the configuration values from
|
||||
*
|
||||
* @return bool Whether validation succeeded or not
|
||||
*/
|
||||
public static function isValidResource(Form $form)
|
||||
{
|
||||
try {
|
||||
$resource = ResourceFactory::createResource(new ConfigObject($form->getValues()));
|
||||
if (false === $resource->testCredentials(
|
||||
$form->getElement('bind_dn')->getValue(),
|
||||
$form->getElement('bind_pw')->getValue()
|
||||
)
|
||||
) {
|
||||
throw new Exception();
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$form->addError(t('Connectivity validation failed, connection to the given resource not possible.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms\Config\Resource;
|
||||
|
||||
|
@ -33,8 +32,8 @@ class LivestatusResourceForm extends Form
|
|||
'name',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Resource Name'),
|
||||
'description' => t('The unique name of this resource')
|
||||
'label' => $this->translate('Resource Name'),
|
||||
'description' => $this->translate('The unique name of this resource')
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
|
@ -42,9 +41,9 @@ class LivestatusResourceForm extends Form
|
|||
'socket',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Socket'),
|
||||
'description' => t('The path to your livestatus socket used for querying monitoring data'),
|
||||
'value' => realpath(Icinga::app()->getApplicationDir() . '/../var/rw/livestatus')
|
||||
'label' => $this->translate('Socket'),
|
||||
'description' => $this->translate('The path to your livestatus socket used for querying monitoring data'),
|
||||
'value' => '/var/run/icinga2/cmd/livestatus'
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -75,8 +74,10 @@ class LivestatusResourceForm extends Form
|
|||
try {
|
||||
$resource = ResourceFactory::createResource(new ConfigObject($form->getValues()));
|
||||
$resource->connect()->disconnect();
|
||||
} catch (Exception $e) {
|
||||
$form->addError(t('Connectivity validation failed, connection to the given resource not possible.'));
|
||||
} catch (Exception $_) {
|
||||
$form->addError(
|
||||
$form->translate('Connectivity validation failed, connection to the given resource not possible.')
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms\Config\Resource;
|
||||
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Forms\Config\ResourceConfigForm;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Util\File;
|
||||
use Zend_Validate_Callback;
|
||||
|
||||
/**
|
||||
* Form class for adding/modifying ssh identity resources
|
||||
*/
|
||||
class SshResourceForm extends Form
|
||||
{
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_config_resource_ssh');
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$this->addElement(
|
||||
'text',
|
||||
'name',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => $this->translate('Resource Name'),
|
||||
'description' => $this->translate('The unique name of this resource')
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'user',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => $this->translate('User'),
|
||||
'description' => $this->translate(
|
||||
'User to log in as on the remote Icinga instance. Please note that key-based SSH login must be'
|
||||
. ' possible for this user'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if ($this->getRequest()->getActionName() != 'editresource') {
|
||||
|
||||
$callbackValidator = new Zend_Validate_Callback(function ($value) {
|
||||
if (openssl_pkey_get_private($value) === false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
$callbackValidator->setMessage(
|
||||
$this->translate('The given SSH key is invalid'),
|
||||
Zend_Validate_Callback::INVALID_VALUE
|
||||
);
|
||||
|
||||
$this->addElement(
|
||||
'textarea',
|
||||
'private_key',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => $this->translate('Private Key'),
|
||||
'description' => $this->translate('The private key which will be used for the SSH connections'),
|
||||
'class' => 'resource ssh-identity',
|
||||
'validators' => array($callbackValidator)
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$resourceName = $formData['name'];
|
||||
$this->addElement(
|
||||
'note',
|
||||
'private_key_note',
|
||||
array(
|
||||
'escape' => false,
|
||||
'label' => $this->translate('Private Key'),
|
||||
'value' => sprintf(
|
||||
'<a href="%1$s" data-base-target="_next" title="%2$s" aria-label="%2$s">%3$s</a>',
|
||||
$this->getView()->url('config/removeresource', array('resource' => $resourceName)),
|
||||
sprintf($this->translate(
|
||||
'Remove the %s resource'
|
||||
), $resourceName),
|
||||
$this->translate('To modify the private key you must recreate this resource.')
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the assigned key to the resource
|
||||
*
|
||||
* @param ConfigObject $config
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function beforeRemove(ConfigObject $config)
|
||||
{
|
||||
$file = $config->private_key;
|
||||
|
||||
if (file_exists($file)) {
|
||||
unlink($file);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the assigned key to the resource
|
||||
*
|
||||
* @param ResourceConfigForm $form
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function beforeAdd(ResourceConfigForm $form)
|
||||
{
|
||||
$configDir = Icinga::app()->getConfigDir();
|
||||
$user = $form->getElement('user')->getValue();
|
||||
|
||||
$filePath = $configDir . '/ssh/' . $user;
|
||||
|
||||
if (! file_exists($filePath)) {
|
||||
$file = File::create($filePath, 0600);
|
||||
} else {
|
||||
$form->error(
|
||||
sprintf($form->translate('The private key for the user "%s" is already exists.'), $user)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
$file->fwrite($form->getElement('private_key')->getValue());
|
||||
|
||||
$form->getElement('private_key')->setValue($configDir . '/ssh/' . $user);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,18 +1,23 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms\Config;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Application\Platform;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Data\Inspectable;
|
||||
use Icinga\Data\Inspection;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Forms\ConfigForm;
|
||||
use Icinga\Forms\Config\Resource\DbResourceForm;
|
||||
use Icinga\Forms\Config\Resource\FileResourceForm;
|
||||
use Icinga\Forms\Config\Resource\LdapResourceForm;
|
||||
use Icinga\Forms\Config\Resource\LivestatusResourceForm;
|
||||
use Icinga\Application\Platform;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Forms\Config\Resource\SshResourceForm;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Notification;
|
||||
|
||||
class ResourceConfigForm extends ConfigForm
|
||||
{
|
||||
|
@ -22,7 +27,8 @@ class ResourceConfigForm extends ConfigForm
|
|||
public function init()
|
||||
{
|
||||
$this->setName('form_config_resource');
|
||||
$this->setSubmitLabel(t('Save Changes'));
|
||||
$this->setSubmitLabel($this->translate('Save Changes'));
|
||||
$this->setValidatePartial(true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -42,8 +48,10 @@ class ResourceConfigForm extends ConfigForm
|
|||
return new LivestatusResourceForm();
|
||||
} elseif ($type === 'file') {
|
||||
return new FileResourceForm();
|
||||
} elseif ($type === 'ssh') {
|
||||
return new SshResourceForm();
|
||||
} else {
|
||||
throw new InvalidArgumentException(sprintf(t('Invalid resource type "%s" provided'), $type));
|
||||
throw new InvalidArgumentException(sprintf($this->translate('Invalid resource type "%s" provided'), $type));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,17 +62,17 @@ class ResourceConfigForm extends ConfigForm
|
|||
*
|
||||
* @param array $values The values to extend the configuration with
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*
|
||||
* @thrwos InvalidArgumentException In case the resource does already exist
|
||||
* @throws InvalidArgumentException In case the resource does already exist
|
||||
*/
|
||||
public function add(array $values)
|
||||
{
|
||||
$name = isset($values['name']) ? $values['name'] : '';
|
||||
if (! $name) {
|
||||
throw new InvalidArgumentException(t('Resource name missing'));
|
||||
throw new InvalidArgumentException($this->translate('Resource name missing'));
|
||||
} elseif ($this->config->hasSection($name)) {
|
||||
throw new InvalidArgumentException(t('Resource already exists'));
|
||||
throw new InvalidArgumentException($this->translate('Resource already exists'));
|
||||
}
|
||||
|
||||
unset($values['name']);
|
||||
|
@ -85,11 +93,11 @@ class ResourceConfigForm extends ConfigForm
|
|||
public function edit($name, array $values)
|
||||
{
|
||||
if (! $name) {
|
||||
throw new InvalidArgumentException(t('Old resource name missing'));
|
||||
throw new InvalidArgumentException($this->translate('Old resource name missing'));
|
||||
} elseif (! ($newName = isset($values['name']) ? $values['name'] : '')) {
|
||||
throw new InvalidArgumentException(t('New resource name missing'));
|
||||
throw new InvalidArgumentException($this->translate('New resource name missing'));
|
||||
} elseif (! $this->config->hasSection($name)) {
|
||||
throw new InvalidArgumentException(t('Unknown resource provided'));
|
||||
throw new InvalidArgumentException($this->translate('Unknown resource provided'));
|
||||
}
|
||||
|
||||
$resourceConfig = $this->config->getSection($name);
|
||||
|
@ -111,12 +119,17 @@ class ResourceConfigForm extends ConfigForm
|
|||
public function remove($name)
|
||||
{
|
||||
if (! $name) {
|
||||
throw new InvalidArgumentException(t('Resource name missing'));
|
||||
throw new InvalidArgumentException($this->translate('Resource name missing'));
|
||||
} elseif (! $this->config->hasSection($name)) {
|
||||
throw new InvalidArgumentException(t('Unknown resource provided'));
|
||||
throw new InvalidArgumentException($this->translate('Unknown resource provided'));
|
||||
}
|
||||
|
||||
$resourceConfig = $this->config->getSection($name);
|
||||
$resourceForm = $this->getResourceForm($resourceConfig->type);
|
||||
if (method_exists($resourceForm, 'beforeRemove')) {
|
||||
$resourceForm::beforeRemove($resourceConfig);
|
||||
}
|
||||
|
||||
$this->config->removeSection($name);
|
||||
return $resourceConfig;
|
||||
}
|
||||
|
@ -131,9 +144,12 @@ class ResourceConfigForm extends ConfigForm
|
|||
*/
|
||||
public function onSuccess()
|
||||
{
|
||||
$resourceForm = $this->getResourceForm($this->getElement('type')->getValue());
|
||||
|
||||
if (($el = $this->getElement('force_creation')) === null || false === $el->isChecked()) {
|
||||
$resourceForm = $this->getResourceForm($this->getElement('type')->getValue());
|
||||
if (method_exists($resourceForm, 'isValidResource') && false === $resourceForm::isValidResource($this)) {
|
||||
$inspection = static::inspectResource($this);
|
||||
if ($inspection !== null && $inspection->hasError()) {
|
||||
$this->error($inspection->getError());
|
||||
$this->addElement($this->getForceCreationCheckbox());
|
||||
return false;
|
||||
}
|
||||
|
@ -142,15 +158,20 @@ class ResourceConfigForm extends ConfigForm
|
|||
$resource = $this->request->getQuery('resource');
|
||||
try {
|
||||
if ($resource === null) { // create new resource
|
||||
if (method_exists($resourceForm, 'beforeAdd')) {
|
||||
if (! $resourceForm::beforeAdd($this)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$this->add($this->getValues());
|
||||
$message = t('Resource "%s" has been successfully created');
|
||||
$message = $this->translate('Resource "%s" has been successfully created');
|
||||
} else { // edit existing resource
|
||||
$this->edit($resource, $this->getValues());
|
||||
$message = t('Resource "%s" has been successfully changed');
|
||||
$message = $this->translate('Resource "%s" has been successfully changed');
|
||||
}
|
||||
} catch (InvalidArgumentException $e) {
|
||||
Notification::error($e->getMessage());
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->save()) {
|
||||
|
@ -172,9 +193,9 @@ class ResourceConfigForm extends ConfigForm
|
|||
$resource = $this->request->getQuery('resource');
|
||||
if ($resource !== null) {
|
||||
if ($resource === '') {
|
||||
throw new ConfigurationError(t('Resource name missing'));
|
||||
throw new ConfigurationError($this->translate('Resource name missing'));
|
||||
} elseif (! $this->config->hasSection($resource)) {
|
||||
throw new ConfigurationError(t('Unknown resource provided'));
|
||||
throw new ConfigurationError($this->translate('Unknown resource provided'));
|
||||
}
|
||||
|
||||
$configValues = $this->config->getSection($resource)->toArray();
|
||||
|
@ -197,8 +218,8 @@ class ResourceConfigForm extends ConfigForm
|
|||
array(
|
||||
'order' => 0,
|
||||
'ignore' => true,
|
||||
'label' => t('Force Changes'),
|
||||
'description' => t('Check this box to enforce changes without connectivity validation')
|
||||
'label' => $this->translate('Force Changes'),
|
||||
'description' => $this->translate('Check this box to enforce changes without connectivity validation')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -211,14 +232,15 @@ class ResourceConfigForm extends ConfigForm
|
|||
$resourceType = isset($formData['type']) ? $formData['type'] : 'db';
|
||||
|
||||
$resourceTypes = array(
|
||||
'file' => t('File'),
|
||||
'file' => $this->translate('File'),
|
||||
'livestatus' => 'Livestatus',
|
||||
'ssh' => $this->translate('SSH Identity'),
|
||||
);
|
||||
if ($resourceType === 'ldap' || Platform::extensionLoaded('ldap')) {
|
||||
$resourceTypes['ldap'] = 'LDAP';
|
||||
}
|
||||
if ($resourceType === 'db' || Platform::hasMysqlSupport() || Platform::hasPostgresqlSupport()) {
|
||||
$resourceTypes['db'] = t('SQL Database');
|
||||
$resourceTypes['db'] = $this->translate('SQL Database');
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
|
@ -227,8 +249,8 @@ class ResourceConfigForm extends ConfigForm
|
|||
array(
|
||||
'required' => true,
|
||||
'autosubmit' => true,
|
||||
'label' => t('Resource Type'),
|
||||
'description' => t('The type of resource'),
|
||||
'label' => $this->translate('Resource Type'),
|
||||
'description' => $this->translate('The type of resource'),
|
||||
'multiOptions' => $resourceTypes,
|
||||
'value' => $resourceType
|
||||
)
|
||||
|
@ -241,4 +263,103 @@ class ResourceConfigForm extends ConfigForm
|
|||
|
||||
$this->addElements($this->getResourceForm($resourceType)->createElements($formData)->getElements());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a resource by using the given form's values and return its inspection results
|
||||
*
|
||||
* @param Form $form
|
||||
*
|
||||
* @return Inspection
|
||||
*/
|
||||
public static function inspectResource(Form $form)
|
||||
{
|
||||
if ($form->getValue('type') !== 'ssh') {
|
||||
$resource = ResourceFactory::createResource(new ConfigObject($form->getValues()));
|
||||
if ($resource instanceof Inspectable) {
|
||||
return $resource->inspect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the configured resource's inspection checks and show the result, if necessary
|
||||
*
|
||||
* This will only run any validation if the user pushed the 'resource_validation' button.
|
||||
*
|
||||
* @param array $formData
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isValidPartial(array $formData)
|
||||
{
|
||||
if ($this->getElement('resource_validation')->isChecked() && parent::isValid($formData)) {
|
||||
$inspection = static::inspectResource($this);
|
||||
if ($inspection !== null) {
|
||||
$join = function ($e) use (& $join) {
|
||||
return is_string($e) ? $e : join("\n", array_map($join, $e));
|
||||
};
|
||||
$this->addElement(
|
||||
'note',
|
||||
'inspection_output',
|
||||
array(
|
||||
'order' => 0,
|
||||
'value' => '<strong>' . $this->translate('Validation Log') . "</strong>\n\n"
|
||||
. join("\n", array_map($join, $inspection->toArray())),
|
||||
'decorators' => array(
|
||||
'ViewHelper',
|
||||
array('HtmlTag', array('tag' => 'pre', 'class' => 'log-output')),
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if ($inspection->hasError()) {
|
||||
$this->warning(sprintf(
|
||||
$this->translate('Failed to successfully validate the configuration: %s'),
|
||||
$inspection->getError()
|
||||
));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$this->info($this->translate('The configuration has been successfully validated.'));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a submit button to this form and one to manually validate the configuration
|
||||
*
|
||||
* Calls parent::addSubmitButton() to add the submit button.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addSubmitButton()
|
||||
{
|
||||
parent::addSubmitButton()
|
||||
->getElement('btn_submit')
|
||||
->setDecorators(array('ViewHelper'));
|
||||
|
||||
$this->addElement(
|
||||
'submit',
|
||||
'resource_validation',
|
||||
array(
|
||||
'ignore' => true,
|
||||
'label' => $this->translate('Validate Configuration'),
|
||||
'decorators' => array('ViewHelper')
|
||||
)
|
||||
);
|
||||
$this->addDisplayGroup(
|
||||
array('btn_submit', 'resource_validation'),
|
||||
'submit_validation',
|
||||
array(
|
||||
'decorators' => array(
|
||||
'FormElements',
|
||||
array('HtmlTag', array('tag' => 'div', 'class' => 'control-group'))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,191 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms\Config\User;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Data\DataArray\ArrayDatasource;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Notification;
|
||||
|
||||
/**
|
||||
* Form for creating one or more group memberships
|
||||
*/
|
||||
class CreateMembershipForm extends Form
|
||||
{
|
||||
/**
|
||||
* The user group backends to fetch groups from
|
||||
*
|
||||
* Each backend must implement the Icinga\Data\Extensible and Icinga\Data\Selectable interface.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $backends;
|
||||
|
||||
/**
|
||||
* The username to create memberships for
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $userName;
|
||||
|
||||
/**
|
||||
* Set the user group backends to fetch groups from
|
||||
*
|
||||
* @param array $backends
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setBackends($backends)
|
||||
{
|
||||
$this->backends = $backends;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the username to create memberships for
|
||||
*
|
||||
* @param string $userName
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setUsername($userName)
|
||||
{
|
||||
$this->userName = $userName;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and add elements to this form
|
||||
*
|
||||
* @param array $formData The data sent by the user
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$query = $this->createDataSource()->select()->from('group', array('group_name', 'backend_name'));
|
||||
|
||||
$options = array();
|
||||
foreach ($query as $row) {
|
||||
$options[$row->backend_name . ';' . $row->group_name] = $row->group_name . ' (' . $row->backend_name . ')';
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
'multiselect',
|
||||
'groups',
|
||||
array(
|
||||
'required' => true,
|
||||
'multiOptions' => $options,
|
||||
'label' => $this->translate('Groups'),
|
||||
'description' => sprintf(
|
||||
$this->translate('Select one or more groups where to add %s as member'),
|
||||
$this->userName
|
||||
),
|
||||
'class' => 'grant-permissions'
|
||||
)
|
||||
);
|
||||
|
||||
$this->setTitle(sprintf($this->translate('Create memberships for %s'), $this->userName));
|
||||
$this->setSubmitLabel($this->translate('Create'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantly redirect back in case the user is already a member of all groups
|
||||
*/
|
||||
public function onRequest()
|
||||
{
|
||||
if ($this->createDataSource()->select()->from('group')->count() === 0) {
|
||||
Notification::info(sprintf($this->translate('User %s is already a member of all groups'), $this->userName));
|
||||
$this->getResponse()->redirectAndExit($this->getRedirectUrl());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the memberships for the user
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function onSuccess()
|
||||
{
|
||||
$backendMap = array();
|
||||
foreach ($this->backends as $backend) {
|
||||
$backendMap[$backend->getName()] = $backend;
|
||||
}
|
||||
|
||||
$single = null;
|
||||
foreach ($this->getValue('groups') as $backendAndGroup) {
|
||||
list($backendName, $groupName) = explode(';', $backendAndGroup, 2);
|
||||
try {
|
||||
$backendMap[$backendName]->insert(
|
||||
'group_membership',
|
||||
array(
|
||||
'group_name' => $groupName,
|
||||
'user_name' => $this->userName
|
||||
)
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
Notification::error(sprintf(
|
||||
$this->translate('Failed to add "%s" as group member for "%s"'),
|
||||
$this->userName,
|
||||
$groupName
|
||||
));
|
||||
$this->error($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
$single = $single === null;
|
||||
}
|
||||
|
||||
if ($single) {
|
||||
Notification::success(
|
||||
sprintf($this->translate('Membership for group %s created successfully'), $groupName)
|
||||
);
|
||||
} else {
|
||||
Notification::success($this->translate('Memberships created successfully'));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a data source to fetch all groups from all backends where the user is not already a member of
|
||||
*
|
||||
* @return ArrayDatasource
|
||||
*/
|
||||
protected function createDataSource()
|
||||
{
|
||||
$groups = $failures = array();
|
||||
foreach ($this->backends as $backend) {
|
||||
try {
|
||||
$memberships = $backend
|
||||
->select()
|
||||
->from('group_membership', array('group_name'))
|
||||
->where('user_name', $this->userName)
|
||||
->fetchColumn();
|
||||
foreach ($backend->select(array('group_name')) as $row) {
|
||||
if (! in_array($row->group_name, $memberships)) { // TODO(jom): Apply this as native query filter
|
||||
$row->backend_name = $backend->getName();
|
||||
$groups[] = $row;
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$failures[] = array($backend->getName(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($groups) && !empty($failures)) {
|
||||
// In case there are only failures, throw the very first exception again
|
||||
throw $failures[0][1];
|
||||
} elseif (! empty($failures)) {
|
||||
foreach ($failures as $failure) {
|
||||
Logger::error($failure[1]);
|
||||
Notification::warning(sprintf(
|
||||
$this->translate('Failed to fetch any groups from backend %s. Please check your log'),
|
||||
$failure[0]
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayDatasource($groups);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,175 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms\Config\User;
|
||||
|
||||
use Icinga\Data\Filter\Filter;
|
||||
use Icinga\Forms\RepositoryForm;
|
||||
|
||||
class UserForm extends RepositoryForm
|
||||
{
|
||||
/**
|
||||
* Create and add elements to this form to insert or update a user
|
||||
*
|
||||
* @param array $formData The data sent by the user
|
||||
*/
|
||||
protected function createInsertElements(array $formData)
|
||||
{
|
||||
$this->addElement(
|
||||
'checkbox',
|
||||
'is_active',
|
||||
array(
|
||||
'required' => true,
|
||||
'value' => true,
|
||||
'label' => $this->translate('Active'),
|
||||
'description' => $this->translate('Prevents the user from logging in if unchecked')
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'user_name',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => $this->translate('Username')
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'password',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => $this->translate('Password')
|
||||
)
|
||||
);
|
||||
|
||||
$this->setTitle($this->translate('Add a new user'));
|
||||
$this->setSubmitLabel($this->translate('Add'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and add elements to this form to update a user
|
||||
*
|
||||
* @param array $formData The data sent by the user
|
||||
*/
|
||||
protected function createUpdateElements(array $formData)
|
||||
{
|
||||
$this->createInsertElements($formData);
|
||||
|
||||
$this->addElement(
|
||||
'text',
|
||||
'password',
|
||||
array(
|
||||
'label' => $this->translate('Password')
|
||||
)
|
||||
);
|
||||
|
||||
$this->setTitle(sprintf($this->translate('Edit user %s'), $this->getIdentifier()));
|
||||
$this->setSubmitLabel($this->translate('Save'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a user
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function onUpdateSuccess()
|
||||
{
|
||||
if (parent::onUpdateSuccess()) {
|
||||
if (($newName = $this->getValue('user_name')) !== $this->getIdentifier()) {
|
||||
$this->getRedirectUrl()->setParam('user', $newName);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all form element values
|
||||
*
|
||||
* Strips off the password if null or the empty string.
|
||||
*
|
||||
* @param bool $suppressArrayNotation
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getValues($suppressArrayNotation = false)
|
||||
{
|
||||
$values = parent::getValues($suppressArrayNotation);
|
||||
if (! $values['password']) {
|
||||
unset($values['password']);
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and add elements to this form to delete a user
|
||||
*
|
||||
* @param array $formData The data sent by the user
|
||||
*/
|
||||
protected function createDeleteElements(array $formData)
|
||||
{
|
||||
$this->setTitle(sprintf($this->translate('Remove user %s?'), $this->getIdentifier()));
|
||||
$this->setSubmitLabel($this->translate('Yes'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a filter to use when updating or deleting a user
|
||||
*
|
||||
* @return Filter
|
||||
*/
|
||||
protected function createFilter()
|
||||
{
|
||||
return Filter::where('user_name', $this->getIdentifier());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a notification message to use when inserting a user
|
||||
*
|
||||
* @param bool $success true or false, whether the operation was successful
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getInsertMessage($success)
|
||||
{
|
||||
if ($success) {
|
||||
return $this->translate('User added successfully');
|
||||
} else {
|
||||
return $this->translate('Failed to add user');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a notification message to use when updating a user
|
||||
*
|
||||
* @param bool $success true or false, whether the operation was successful
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getUpdateMessage($success)
|
||||
{
|
||||
if ($success) {
|
||||
return sprintf($this->translate('User "%s" has been edited'), $this->getIdentifier());
|
||||
} else {
|
||||
return sprintf($this->translate('Failed to edit user "%s"'), $this->getIdentifier());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a notification message to use when deleting a user
|
||||
*
|
||||
* @param bool $success true or false, whether the operation was successful
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getDeleteMessage($success)
|
||||
{
|
||||
if ($success) {
|
||||
return sprintf($this->translate('User "%s" has been removed'), $this->getIdentifier());
|
||||
} else {
|
||||
return sprintf($this->translate('Failed to remove user "%s"'), $this->getIdentifier());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms\Config\UserBackend;
|
||||
|
||||
use Icinga\Web\Form;
|
||||
|
||||
/**
|
||||
* Form class for adding/modifying database user backends
|
||||
*/
|
||||
class DbBackendForm extends Form
|
||||
{
|
||||
/**
|
||||
* The database resource names the user can choose from
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $resources;
|
||||
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_config_authbackend_db');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the resource names the user can choose from
|
||||
*
|
||||
* @param array $resources The resources to choose from
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setResources(array $resources)
|
||||
{
|
||||
$this->resources = $resources;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and add elements to this form
|
||||
*
|
||||
* @param array $formData
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$this->addElement(
|
||||
'text',
|
||||
'name',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => $this->translate('Backend Name'),
|
||||
'description' => $this->translate(
|
||||
'The name of this authentication provider that is used to differentiate it from others'
|
||||
),
|
||||
'validators' => array(
|
||||
array(
|
||||
'Regex',
|
||||
false,
|
||||
array(
|
||||
'pattern' => '/^[^\\[\\]:]+$/',
|
||||
'messages' => array(
|
||||
'regexNotMatch' => $this->translate(
|
||||
'The name cannot contain \'[\', \']\' or \':\'.'
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'select',
|
||||
'resource',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => $this->translate('Database Connection'),
|
||||
'description' => $this->translate(
|
||||
'The database connection to use for authenticating with this provider'
|
||||
),
|
||||
'multiOptions' => !empty($this->resources)
|
||||
? array_combine($this->resources, $this->resources)
|
||||
: array()
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'hidden',
|
||||
'backend',
|
||||
array(
|
||||
'disabled' => true,
|
||||
'value' => 'db'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms\Config\UserBackend;
|
||||
|
||||
use Zend_Validate_Callback;
|
||||
use Icinga\Web\Form;
|
||||
|
||||
/**
|
||||
* Form class for adding/modifying user backends of type "external"
|
||||
*/
|
||||
class ExternalBackendForm extends Form
|
||||
{
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_config_authbackend_external');
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$this->addElement(
|
||||
'text',
|
||||
'name',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => $this->translate('Backend Name'),
|
||||
'description' => $this->translate(
|
||||
'The name of this authentication provider that is used to differentiate it from others'
|
||||
),
|
||||
'validators' => array(
|
||||
array(
|
||||
'Regex',
|
||||
false,
|
||||
array(
|
||||
'pattern' => '/^[^\\[\\]:]+$/',
|
||||
'messages' => array(
|
||||
'regexNotMatch' => $this->translate(
|
||||
'The backend name cannot contain \'[\', \']\' or \':\'.'
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
$callbackValidator = new Zend_Validate_Callback(function ($value) {
|
||||
return @preg_match($value, '') !== false;
|
||||
});
|
||||
$callbackValidator->setMessage(
|
||||
$this->translate('"%value%" is not a valid regular expression.'),
|
||||
Zend_Validate_Callback::INVALID_VALUE
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'strip_username_regexp',
|
||||
array(
|
||||
'label' => $this->translate('Filter Pattern'),
|
||||
'description' => $this->translate(
|
||||
'The filter to use to strip specific parts off from usernames.'
|
||||
. ' Leave empty if you do not want to strip off anything.'
|
||||
),
|
||||
'requirement' => $this->translate('The filter pattern must be a valid regular expression.'),
|
||||
'validators' => array($callbackValidator)
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'hidden',
|
||||
'backend',
|
||||
array(
|
||||
'disabled' => true,
|
||||
'value' => 'external'
|
||||
)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the configuration by creating a backend and requesting the user count
|
||||
*
|
||||
* Returns always true as backends of type "external" are just "passive" backends.
|
||||
*
|
||||
* @param Form $form The form to fetch the configuration values from
|
||||
*
|
||||
* @return bool Whether validation succeeded or not
|
||||
*/
|
||||
public static function isValidUserBackend(Form $form)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,241 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms\Config\UserBackend;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Web\Form;
|
||||
|
||||
/**
|
||||
* Form class for adding/modifying LDAP user backends
|
||||
*/
|
||||
class LdapBackendForm extends Form
|
||||
{
|
||||
/**
|
||||
* The ldap resource names the user can choose from
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $resources;
|
||||
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_config_authbackend_ldap');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the resource names the user can choose from
|
||||
*
|
||||
* @param array $resources The resources to choose from
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setResources(array $resources)
|
||||
{
|
||||
$this->resources = $resources;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and add elements to this form
|
||||
*
|
||||
* @param array $formData
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$isAd = isset($formData['type']) ? $formData['type'] === 'msldap' : false;
|
||||
|
||||
$this->addElement(
|
||||
'text',
|
||||
'name',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => $this->translate('Backend Name'),
|
||||
'description' => $this->translate(
|
||||
'The name of this authentication provider that is used to differentiate it from others.'
|
||||
),
|
||||
'validators' => array(
|
||||
array(
|
||||
'Regex',
|
||||
false,
|
||||
array(
|
||||
'pattern' => '/^[^\\[\\]:]+$/',
|
||||
'messages' => array(
|
||||
'regexNotMatch' => $this->translate(
|
||||
'The name cannot contain \'[\', \']\' or \':\'.'
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'select',
|
||||
'resource',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => $this->translate('LDAP Connection'),
|
||||
'description' => $this->translate(
|
||||
'The LDAP connection to use for authenticating with this provider.'
|
||||
),
|
||||
'multiOptions' => !empty($this->resources)
|
||||
? array_combine($this->resources, $this->resources)
|
||||
: array()
|
||||
)
|
||||
);
|
||||
|
||||
$baseDn = null;
|
||||
$hasAdOid = false;
|
||||
if (! $isAd && !empty($this->resources)) {
|
||||
$this->addElement(
|
||||
'button',
|
||||
'discovery_btn',
|
||||
array(
|
||||
'type' => 'submit',
|
||||
'value' => 'discovery_btn',
|
||||
'label' => $this->translate('Discover', 'A button to discover LDAP capabilities'),
|
||||
'title' => $this->translate(
|
||||
'Push to fill in the chosen connection\'s default settings.'
|
||||
),
|
||||
'decorators' => array(
|
||||
array('ViewHelper', array('separator' => '')),
|
||||
array('HtmlTag', array('tag' => 'div', 'class' => 'element'))
|
||||
),
|
||||
'formnovalidate' => 'formnovalidate'
|
||||
)
|
||||
);
|
||||
$this->addDisplayGroup(
|
||||
array('resource', 'discovery_btn'),
|
||||
'connection_discovery',
|
||||
array(
|
||||
'decorators' => array(
|
||||
'FormElements',
|
||||
array('HtmlTag', array('tag' => 'div', 'class' => 'control-group'))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if ($this->getElement('discovery_btn')->isChecked()) {
|
||||
$connection = ResourceFactory::create(
|
||||
isset($formData['resource']) ? $formData['resource'] : reset($this->resources)
|
||||
);
|
||||
|
||||
try {
|
||||
$capabilities = $connection->bind()->getCapabilities();
|
||||
$baseDn = $capabilities->getDefaultNamingContext();
|
||||
$hasAdOid = $capabilities->isActiveDirectory();
|
||||
} catch (Exception $e) {
|
||||
$this->warning(sprintf(
|
||||
$this->translate('Failed to discover the chosen LDAP connection: %s'),
|
||||
$e->getMessage()
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($isAd || $hasAdOid) {
|
||||
// ActiveDirectory defaults
|
||||
$userClass = 'user';
|
||||
$filter = '!(objectClass=computer)';
|
||||
$userNameAttribute = 'sAMAccountName';
|
||||
} else {
|
||||
// OpenLDAP defaults
|
||||
$userClass = 'inetOrgPerson';
|
||||
$filter = null;
|
||||
$userNameAttribute = 'uid';
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
'text',
|
||||
'user_class',
|
||||
array(
|
||||
'preserveDefault' => true,
|
||||
'required' => ! $isAd,
|
||||
'ignore' => $isAd,
|
||||
'disabled' => $isAd ?: null,
|
||||
'label' => $this->translate('LDAP User Object Class'),
|
||||
'description' => $this->translate('The object class used for storing users on the LDAP server.'),
|
||||
'value' => $userClass
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'filter',
|
||||
array(
|
||||
'preserveDefault' => true,
|
||||
'allowEmpty' => true,
|
||||
'value' => $filter,
|
||||
'label' => $this->translate('LDAP Filter'),
|
||||
'description' => $this->translate(
|
||||
'An additional filter to use when looking up users using the specified connection. '
|
||||
. 'Leave empty to not to use any additional filter rules.'
|
||||
),
|
||||
'requirement' => $this->translate(
|
||||
'The filter needs to be expressed as standard LDAP expression.'
|
||||
. ' (e.g. &(foo=bar)(bar=foo) or foo=bar)'
|
||||
),
|
||||
'validators' => array(
|
||||
array(
|
||||
'Callback',
|
||||
false,
|
||||
array(
|
||||
'callback' => function ($v) {
|
||||
// This is not meant to be a full syntax check. It will just
|
||||
// ensure that we can safely strip unnecessary parentheses.
|
||||
$v = trim($v);
|
||||
return ! $v || $v[0] !== '(' || (
|
||||
strpos($v, ')(') !== false ? substr($v, -2) === '))' : substr($v, -1) === ')'
|
||||
);
|
||||
},
|
||||
'messages' => array(
|
||||
'callbackValue' => $this->translate('The filter is invalid. Please check your syntax.')
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'user_name_attribute',
|
||||
array(
|
||||
'preserveDefault' => true,
|
||||
'required' => ! $isAd,
|
||||
'ignore' => $isAd,
|
||||
'disabled' => $isAd ?: null,
|
||||
'label' => $this->translate('LDAP User Name Attribute'),
|
||||
'description' => $this->translate(
|
||||
'The attribute name used for storing the user name on the LDAP server.'
|
||||
),
|
||||
'value' => $userNameAttribute
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'hidden',
|
||||
'backend',
|
||||
array(
|
||||
'disabled' => true,
|
||||
'value' => $isAd ? 'msldap' : 'ldap'
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'base_dn',
|
||||
array(
|
||||
'preserveDefault' => true,
|
||||
'required' => false,
|
||||
'label' => $this->translate('LDAP Base DN'),
|
||||
'description' => $this->translate(
|
||||
'The path where users can be found on the LDAP server. Leave ' .
|
||||
'empty to select all users available using the specified connection.'
|
||||
),
|
||||
'value' => $baseDn
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,485 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms\Config;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Authentication\User\UserBackend;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Exception\IcingaException;
|
||||
use Icinga\Exception\NotFoundError;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Data\Inspectable;
|
||||
use Icinga\Data\Inspection;
|
||||
use Icinga\Forms\ConfigForm;
|
||||
use Icinga\Forms\Config\UserBackend\ExternalBackendForm;
|
||||
use Icinga\Forms\Config\UserBackend\DbBackendForm;
|
||||
use Icinga\Forms\Config\UserBackend\LdapBackendForm;
|
||||
use Icinga\Web\Form;
|
||||
|
||||
/**
|
||||
* Form for managing user backends
|
||||
*/
|
||||
class UserBackendConfigForm extends ConfigForm
|
||||
{
|
||||
/**
|
||||
* The available user backend resources split by type
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $resources;
|
||||
|
||||
/**
|
||||
* The backend to load when displaying the form for the first time
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $backendToLoad;
|
||||
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_config_authbackend');
|
||||
$this->setSubmitLabel($this->translate('Save Changes'));
|
||||
$this->setValidatePartial(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the resource configuration to use
|
||||
*
|
||||
* @param Config $resourceConfig The resource configuration
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws ConfigurationError In case there are no valid resources for authentication available
|
||||
*/
|
||||
public function setResourceConfig(Config $resourceConfig)
|
||||
{
|
||||
$resources = array();
|
||||
foreach ($resourceConfig as $name => $resource) {
|
||||
if (in_array($resource->type, array('db', 'ldap'))) {
|
||||
$resources[$resource->type][] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($resources)) {
|
||||
$externalBackends = $this->config->toArray();
|
||||
array_walk(
|
||||
$externalBackends,
|
||||
function (& $authBackendCfg) {
|
||||
if (! isset($authBackendCfg['backend']) || $authBackendCfg['backend'] !== 'external') {
|
||||
$authBackendCfg = null;
|
||||
}
|
||||
}
|
||||
);
|
||||
if (count(array_filter($externalBackends)) > 0 && (
|
||||
$this->backendToLoad === null || !isset($externalBackends[$this->backendToLoad])
|
||||
)) {
|
||||
throw new ConfigurationError($this->translate(
|
||||
'Could not find any valid user backend resources.'
|
||||
. ' Please configure a resource for authentication first.'
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
$this->resources = $resources;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a form object for the given backend type
|
||||
*
|
||||
* @param string $type The backend type for which to return a form
|
||||
*
|
||||
* @return Form
|
||||
*
|
||||
* @throws InvalidArgumentException In case the given backend type is invalid
|
||||
*/
|
||||
public function getBackendForm($type)
|
||||
{
|
||||
switch ($type)
|
||||
{
|
||||
case 'db':
|
||||
$form = new DbBackendForm();
|
||||
$form->setResources(isset($this->resources['db']) ? $this->resources['db'] : array());
|
||||
break;
|
||||
case 'ldap':
|
||||
case 'msldap':
|
||||
$form = new LdapBackendForm();
|
||||
$form->setResources(isset($this->resources['ldap']) ? $this->resources['ldap'] : array());
|
||||
break;
|
||||
case 'external':
|
||||
$form = new ExternalBackendForm();
|
||||
break;
|
||||
default:
|
||||
throw new InvalidArgumentException(
|
||||
sprintf($this->translate('Invalid backend type "%s" provided'), $type)
|
||||
);
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the form with the given backend's config
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws NotFoundError In case no backend with the given name is found
|
||||
*/
|
||||
public function load($name)
|
||||
{
|
||||
if (! $this->config->hasSection($name)) {
|
||||
throw new NotFoundError('No user backend called "%s" found', $name);
|
||||
}
|
||||
|
||||
$this->backendToLoad = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new user backend
|
||||
*
|
||||
* The backend to add is identified by the array-key `name'.
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws InvalidArgumentException In case $data does not contain a backend name
|
||||
* @throws IcingaException In case a backend with the same name already exists
|
||||
*/
|
||||
public function add(array $data)
|
||||
{
|
||||
if (! isset($data['name'])) {
|
||||
throw new InvalidArgumentException('Key \'name\' missing');
|
||||
}
|
||||
|
||||
$backendName = $data['name'];
|
||||
if ($this->config->hasSection($backendName)) {
|
||||
throw new IcingaException(
|
||||
$this->translate('A user backend with the name "%s" does already exist'),
|
||||
$backendName
|
||||
);
|
||||
}
|
||||
|
||||
unset($data['name']);
|
||||
$this->config->setSection($backendName, $data);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit a user backend
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $data
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws NotFoundError In case no backend with the given name is found
|
||||
*/
|
||||
public function edit($name, array $data)
|
||||
{
|
||||
if (! $this->config->hasSection($name)) {
|
||||
throw new NotFoundError('No user backend called "%s" found', $name);
|
||||
}
|
||||
|
||||
$backendConfig = $this->config->getSection($name);
|
||||
if (isset($data['name'])) {
|
||||
if ($data['name'] !== $name) {
|
||||
$this->config->removeSection($name);
|
||||
$name = $data['name'];
|
||||
}
|
||||
|
||||
unset($data['name']);
|
||||
}
|
||||
|
||||
$backendConfig->merge($data);
|
||||
foreach ($backendConfig->toArray() as $k => $v) {
|
||||
if ($v === null) {
|
||||
unset($backendConfig->$k);
|
||||
}
|
||||
}
|
||||
|
||||
$this->config->setSection($name, $backendConfig);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a user backend
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function delete($name)
|
||||
{
|
||||
$this->config->removeSection($name);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the given user backend up or down in order
|
||||
*
|
||||
* @param string $name The name of the backend to be moved
|
||||
* @param int $position The new (absolute) position of the backend
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws NotFoundError In case no backend with the given name is found
|
||||
*/
|
||||
public function move($name, $position)
|
||||
{
|
||||
if (! $this->config->hasSection($name)) {
|
||||
throw new NotFoundError('No user backend called "%s" found', $name);
|
||||
}
|
||||
|
||||
$backendOrder = $this->config->keys();
|
||||
array_splice($backendOrder, array_search($name, $backendOrder), 1);
|
||||
array_splice($backendOrder, $position, 0, $name);
|
||||
|
||||
$newConfig = array();
|
||||
foreach ($backendOrder as $backendName) {
|
||||
$newConfig[$backendName] = $this->config->getSection($backendName);
|
||||
}
|
||||
|
||||
$config = Config::fromArray($newConfig);
|
||||
$this->config = $config->setConfigFile($this->config->getConfigFile());
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and add elements to this form
|
||||
*
|
||||
* @param array $formData
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$backendTypes = array();
|
||||
$backendType = isset($formData['type']) ? $formData['type'] : null;
|
||||
|
||||
if (isset($this->resources['db'])) {
|
||||
$backendTypes['db'] = $this->translate('Database');
|
||||
}
|
||||
if (isset($this->resources['ldap'])) {
|
||||
$backendTypes['ldap'] = 'LDAP';
|
||||
$backendTypes['msldap'] = 'ActiveDirectory';
|
||||
}
|
||||
|
||||
$externalBackends = array_filter(
|
||||
$this->config->toArray(),
|
||||
function ($authBackendCfg) {
|
||||
return isset($authBackendCfg['backend']) && $authBackendCfg['backend'] === 'external';
|
||||
}
|
||||
);
|
||||
if ($backendType === 'external' || empty($externalBackends)) {
|
||||
$backendTypes['external'] = $this->translate('External');
|
||||
}
|
||||
|
||||
if ($backendType === null) {
|
||||
$backendType = key($backendTypes);
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
'select',
|
||||
'type',
|
||||
array(
|
||||
'ignore' => true,
|
||||
'required' => true,
|
||||
'autosubmit' => true,
|
||||
'label' => $this->translate('Backend Type'),
|
||||
'description' => $this->translate(
|
||||
'The type of the resource to use for this authenticaton provider'
|
||||
),
|
||||
'multiOptions' => $backendTypes
|
||||
)
|
||||
);
|
||||
|
||||
if (isset($formData['skip_validation']) && $formData['skip_validation']) {
|
||||
// In case another error occured and the checkbox was displayed before
|
||||
$this->addSkipValidationCheckbox();
|
||||
}
|
||||
|
||||
$this->addSubForm($this->getBackendForm($backendType)->create($formData), 'backend_form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the configuration of the backend to load
|
||||
*/
|
||||
public function onRequest()
|
||||
{
|
||||
if ($this->backendToLoad) {
|
||||
$data = $this->config->getSection($this->backendToLoad)->toArray();
|
||||
$data['name'] = $this->backendToLoad;
|
||||
$data['type'] = $data['backend'];
|
||||
$this->populate($data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all form element values
|
||||
*
|
||||
* @param bool $suppressArrayNotation Ignored
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getValues($suppressArrayNotation = false)
|
||||
{
|
||||
$values = parent::getValues();
|
||||
$values = array_merge($values, $values['backend_form']);
|
||||
unset($values['backend_form']);
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the given values are valid
|
||||
*
|
||||
* @param array $formData The data to validate
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid($formData)
|
||||
{
|
||||
if (! parent::isValid($formData)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (($el = $this->getElement('skip_validation')) === null || false === $el->isChecked()) {
|
||||
$inspection = static::inspectUserBackend($this);
|
||||
if ($inspection && $inspection->hasError()) {
|
||||
$this->error($inspection->getError());
|
||||
if ($el === null) {
|
||||
$this->addSkipValidationCheckbox();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a user backend by using the given form's values and return its inspection results
|
||||
*
|
||||
* Returns null for non-inspectable backends.
|
||||
*
|
||||
* @param Form $form
|
||||
*
|
||||
* @return Inspection|null
|
||||
*/
|
||||
public static function inspectUserBackend(Form $form)
|
||||
{
|
||||
$backend = UserBackend::create(null, new ConfigObject($form->getValues()));
|
||||
if ($backend instanceof Inspectable) {
|
||||
return $backend->inspect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a checkbox to the form by which the user can skip the connection validation
|
||||
*/
|
||||
protected function addSkipValidationCheckbox()
|
||||
{
|
||||
$this->addElement(
|
||||
'checkbox',
|
||||
'skip_validation',
|
||||
array(
|
||||
'order' => 0,
|
||||
'ignore' => true,
|
||||
'required' => true,
|
||||
'label' => $this->translate('Skip Validation'),
|
||||
'description' => $this->translate(
|
||||
'Check this box to enforce changes without validating that authentication is possible.'
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the configured backend's inspection checks and show the result, if necessary
|
||||
*
|
||||
* This will only run any validation if the user pushed the 'backend_validation' button.
|
||||
*
|
||||
* @param array $formData
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isValidPartial(array $formData)
|
||||
{
|
||||
if ($this->getElement('backend_validation')->isChecked() && parent::isValid($formData)) {
|
||||
$inspection = static::inspectUserBackend($this);
|
||||
if ($inspection !== null) {
|
||||
$join = function ($e) use (& $join) {
|
||||
return is_string($e) ? $e : join("\n", array_map($join, $e));
|
||||
};
|
||||
$this->addElement(
|
||||
'note',
|
||||
'inspection_output',
|
||||
array(
|
||||
'order' => 0,
|
||||
'value' => '<strong>' . $this->translate('Validation Log') . "</strong>\n\n"
|
||||
. join("\n", array_map($join, $inspection->toArray())),
|
||||
'decorators' => array(
|
||||
'ViewHelper',
|
||||
array('HtmlTag', array('tag' => 'pre', 'class' => 'log-output')),
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if ($inspection->hasError()) {
|
||||
$this->warning(sprintf(
|
||||
$this->translate('Failed to successfully validate the configuration: %s'),
|
||||
$inspection->getError()
|
||||
));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$this->info($this->translate('The configuration has been successfully validated.'));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a submit button to this form and one to manually validate the configuration
|
||||
*
|
||||
* Calls parent::addSubmitButton() to add the submit button.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addSubmitButton()
|
||||
{
|
||||
parent::addSubmitButton()
|
||||
->getElement('btn_submit')
|
||||
->setDecorators(array('ViewHelper'));
|
||||
|
||||
$this->addElement(
|
||||
'submit',
|
||||
'backend_validation',
|
||||
array(
|
||||
'ignore' => true,
|
||||
'label' => $this->translate('Validate Configuration'),
|
||||
'decorators' => array('ViewHelper')
|
||||
)
|
||||
);
|
||||
$this->addDisplayGroup(
|
||||
array('btn_submit', 'backend_validation'),
|
||||
'submit_validation',
|
||||
array(
|
||||
'decorators' => array(
|
||||
'FormElements',
|
||||
array('HtmlTag', array('tag' => 'div', 'class' => 'control-group'))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
|
@ -1,14 +1,13 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms\Config;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Forms\ConfigForm;
|
||||
use Icinga\Exception\NotFoundError;
|
||||
use Icinga\Web\Notification;
|
||||
|
||||
class AuthenticationBackendReorderForm extends ConfigForm
|
||||
class UserBackendReorderForm extends ConfigForm
|
||||
{
|
||||
/**
|
||||
* Initialize this form
|
||||
|
@ -30,7 +29,9 @@ class AuthenticationBackendReorderForm extends ConfigForm
|
|||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
* Create and add elements to this form
|
||||
*
|
||||
* @param array $formData
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
|
@ -39,9 +40,7 @@ class AuthenticationBackendReorderForm extends ConfigForm
|
|||
}
|
||||
|
||||
/**
|
||||
* Update the authentication backend order and save the configuration
|
||||
*
|
||||
* @see Form::onSuccess()
|
||||
* Update the user backend order and save the configuration
|
||||
*/
|
||||
public function onSuccess()
|
||||
{
|
||||
|
@ -52,24 +51,24 @@ class AuthenticationBackendReorderForm extends ConfigForm
|
|||
|
||||
try {
|
||||
if ($configForm->move($backendName, $position)->save()) {
|
||||
Notification::success(t('Authentication order updated!'));
|
||||
Notification::success($this->translate('Authentication order updated'));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (InvalidArgumentException $e) {
|
||||
Notification::error($e->getMessage());
|
||||
} catch (NotFoundError $_) {
|
||||
Notification::error(sprintf($this->translate('User backend "%s" not found'), $backendName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the config form for authentication backends
|
||||
* Return the config form for user backends
|
||||
*
|
||||
* @return ConfigForm
|
||||
*/
|
||||
protected function getConfigForm()
|
||||
{
|
||||
$form = new AuthenticationBackendConfigForm();
|
||||
$form = new UserBackendConfigForm();
|
||||
$form->setIniConfig($this->config);
|
||||
return $form;
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms\Config\UserGroup;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Data\Extensible;
|
||||
use Icinga\Data\Filter\Filter;
|
||||
use Icinga\Data\Selectable;
|
||||
use Icinga\Exception\NotFoundError;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Notification;
|
||||
|
||||
/**
|
||||
* Form for adding one or more group members
|
||||
*/
|
||||
class AddMemberForm extends Form
|
||||
{
|
||||
/**
|
||||
* The data source to fetch users from
|
||||
*
|
||||
* @var Selectable
|
||||
*/
|
||||
protected $ds;
|
||||
|
||||
/**
|
||||
* The user group backend to use
|
||||
*
|
||||
* @var Extensible
|
||||
*/
|
||||
protected $backend;
|
||||
|
||||
/**
|
||||
* The group to add members for
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $groupName;
|
||||
|
||||
/**
|
||||
* Set the data source to fetch users from
|
||||
*
|
||||
* @param Selectable $ds
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setDataSource(Selectable $ds)
|
||||
{
|
||||
$this->ds = $ds;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the user group backend to use
|
||||
*
|
||||
* @param Extensible $backend
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setBackend(Extensible $backend)
|
||||
{
|
||||
$this->backend = $backend;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the group to add members for
|
||||
*
|
||||
* @param string $groupName
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setGroupName($groupName)
|
||||
{
|
||||
$this->groupName = $groupName;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and add elements to this form
|
||||
*
|
||||
* @param array $formData The data sent by the user
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
// TODO(jom): Fetching already existing members to prevent the user from mistakenly creating duplicate
|
||||
// memberships (no matter whether the data source permits it or not, a member does never need to be
|
||||
// added more than once) should be kept at backend level (GroupController::fetchUsers) but this does
|
||||
// not work currently as our ldap protocol stuff is unable to handle our filter implementation..
|
||||
$members = $this->backend
|
||||
->select()
|
||||
->from('group_membership', array('user_name'))
|
||||
->where('group_name', $this->groupName)
|
||||
->fetchColumn();
|
||||
$filter = empty($members) ? Filter::matchAll() : Filter::not(Filter::where('user_name', $members));
|
||||
|
||||
$users = $this->ds->select()->from('user', array('user_name'))->applyFilter($filter)->fetchColumn();
|
||||
if (! empty($users)) {
|
||||
$this->addElement(
|
||||
'multiselect',
|
||||
'user_name',
|
||||
array(
|
||||
'multiOptions' => array_combine($users, $users),
|
||||
'label' => $this->translate('Backend Users'),
|
||||
'description' => $this->translate(
|
||||
'Select one or more users (fetched from your user backends) to add as group member'
|
||||
),
|
||||
'class' => 'grant-permissions'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
'textarea',
|
||||
'users',
|
||||
array(
|
||||
'required' => empty($users),
|
||||
'label' => $this->translate('Users'),
|
||||
'description' => $this->translate(
|
||||
'Provide one or more usernames separated by comma to add as group member'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$this->setTitle(sprintf($this->translate('Add members for group %s'), $this->groupName));
|
||||
$this->setSubmitLabel($this->translate('Add'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the members for the group
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function onSuccess()
|
||||
{
|
||||
$userNames = $this->getValue('user_name') ?: array();
|
||||
if (($users = $this->getValue('users'))) {
|
||||
$userNames = array_merge($userNames, array_map('trim', explode(',', $users)));
|
||||
}
|
||||
|
||||
if (empty($userNames)) {
|
||||
$this->info($this->translate(
|
||||
'Please provide at least one username, either by choosing one '
|
||||
. 'in the list or by manually typing one in the text box below'
|
||||
));
|
||||
return false;
|
||||
}
|
||||
|
||||
$single = null;
|
||||
foreach ($userNames as $userName) {
|
||||
try {
|
||||
$this->backend->insert(
|
||||
'group_membership',
|
||||
array(
|
||||
'group_name' => $this->groupName,
|
||||
'user_name' => $userName
|
||||
)
|
||||
);
|
||||
} catch (NotFoundError $e) {
|
||||
throw $e; // Trigger 404, the group name is initially accessed as GET parameter
|
||||
} catch (Exception $e) {
|
||||
Notification::error(sprintf(
|
||||
$this->translate('Failed to add "%s" as group member for "%s"'),
|
||||
$userName,
|
||||
$this->groupName
|
||||
));
|
||||
$this->error($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
$single = $single === null;
|
||||
}
|
||||
|
||||
if ($single) {
|
||||
Notification::success(sprintf($this->translate('Group member "%s" added successfully'), $userName));
|
||||
} else {
|
||||
Notification::success($this->translate('Group members added successfully'));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms\Config\UserGroup;
|
||||
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Web\Form;
|
||||
|
||||
/**
|
||||
* Form for managing database user group backends
|
||||
*/
|
||||
class DbUserGroupBackendForm extends Form
|
||||
{
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_config_dbusergroupbackend');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and add elements to this form
|
||||
*
|
||||
* @param array $formData
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$this->addElement(
|
||||
'text',
|
||||
'name',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => $this->translate('Backend Name'),
|
||||
'description' => $this->translate(
|
||||
'The name of this user group backend that is used to differentiate it from others'
|
||||
),
|
||||
'validators' => array(
|
||||
array(
|
||||
'Regex',
|
||||
false,
|
||||
array(
|
||||
'pattern' => '/^[^\\[\\]:]+$/',
|
||||
'messages' => array(
|
||||
'regexNotMatch' => $this->translate(
|
||||
'The name cannot contain \'[\', \']\' or \':\'.'
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$resourceNames = $this->getDatabaseResourceNames();
|
||||
$this->addElement(
|
||||
'select',
|
||||
'resource',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => $this->translate('Database Connection'),
|
||||
'description' => $this->translate('The database connection to use for this backend'),
|
||||
'multiOptions' => empty($resourceNames) ? array() : array_combine($resourceNames, $resourceNames)
|
||||
)
|
||||
);
|
||||
|
||||
$this->addElement(
|
||||
'hidden',
|
||||
'backend',
|
||||
array(
|
||||
'disabled' => true, // Prevents the element from being submitted, see #7717
|
||||
'value' => 'db'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the names of all configured database resources
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getDatabaseResourceNames()
|
||||
{
|
||||
$names = array();
|
||||
foreach (ResourceFactory::getResourceConfigs() as $name => $config) {
|
||||
if (strtolower($config->type) === 'db') {
|
||||
$names[] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
return $names;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,331 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms\Config\UserGroup;
|
||||
|
||||
use Icinga\Authentication\User\UserBackend;
|
||||
use Icinga\Authentication\UserGroup\LdapUserGroupBackend;
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Protocol\Ldap\LdapConnection;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Notification;
|
||||
|
||||
/**
|
||||
* Form for managing LDAP user group backends
|
||||
*/
|
||||
class LdapUserGroupBackendForm extends Form
|
||||
{
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_config_ldapusergroupbackend');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and add elements to this form
|
||||
*
|
||||
* @param array $formData
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$this->addElement(
|
||||
'text',
|
||||
'name',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => $this->translate('Backend Name'),
|
||||
'description' => $this->translate(
|
||||
'The name of this user group backend that is used to differentiate it from others'
|
||||
),
|
||||
'validators' => array(
|
||||
array(
|
||||
'Regex',
|
||||
false,
|
||||
array(
|
||||
'pattern' => '/^[^\\[\\]:]+$/',
|
||||
'messages' => array(
|
||||
'regexNotMatch' => $this->translate(
|
||||
'The name cannot contain \'[\', \']\' or \':\'.'
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$resourceNames = $this->getLdapResourceNames();
|
||||
$this->addElement(
|
||||
'select',
|
||||
'resource',
|
||||
array(
|
||||
'required' => true,
|
||||
'autosubmit' => true,
|
||||
'label' => $this->translate('LDAP Connection'),
|
||||
'description' => $this->translate('The LDAP connection to use for this backend.'),
|
||||
'multiOptions' => array_combine($resourceNames, $resourceNames)
|
||||
)
|
||||
);
|
||||
$resource = ResourceFactory::create(
|
||||
isset($formData['resource']) && in_array($formData['resource'], $resourceNames)
|
||||
? $formData['resource']
|
||||
: $resourceNames[0]
|
||||
);
|
||||
|
||||
$userBackendNames = $this->getLdapUserBackendNames($resource);
|
||||
if (! empty($userBackendNames)) {
|
||||
$userBackends = array_combine($userBackendNames, $userBackendNames);
|
||||
$userBackends['none'] = $this->translate('None', 'usergroupbackend.ldap.user_backend');
|
||||
} else {
|
||||
$userBackends = array('none' => $this->translate('None', 'usergroupbackend.ldap.user_backend'));
|
||||
}
|
||||
$this->addElement(
|
||||
'select',
|
||||
'user_backend',
|
||||
array(
|
||||
'required' => true,
|
||||
'autosubmit' => true,
|
||||
'label' => $this->translate('User Backend'),
|
||||
'description' => $this->translate('The user backend to link with this user group backend.'),
|
||||
'multiOptions' => $userBackends
|
||||
)
|
||||
);
|
||||
|
||||
$groupBackend = new LdapUserGroupBackend($resource);
|
||||
if ($formData['type'] === 'ldap') {
|
||||
$defaults = $groupBackend->getOpenLdapDefaults();
|
||||
$groupConfigDisabled = $userConfigDisabled = null; // MUST BE null, do NOT change this to false!
|
||||
} else { // $formData['type'] === 'msldap'
|
||||
$defaults = $groupBackend->getActiveDirectoryDefaults();
|
||||
$groupConfigDisabled = $userConfigDisabled = true;
|
||||
}
|
||||
|
||||
$this->createGroupConfigElements($defaults, $groupConfigDisabled);
|
||||
if (count($userBackends) === 1 || (isset($formData['user_backend']) && $formData['user_backend'] === 'none')) {
|
||||
$this->createUserConfigElements($defaults, $userConfigDisabled);
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
'hidden',
|
||||
'backend',
|
||||
array(
|
||||
'disabled' => true, // Prevents the element from being submitted, see #7717
|
||||
'value' => $formData['type']
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and add all elements to this form required for the group configuration
|
||||
*
|
||||
* @param ConfigObject $defaults
|
||||
* @param null|bool $disabled
|
||||
*/
|
||||
protected function createGroupConfigElements(ConfigObject $defaults, $disabled)
|
||||
{
|
||||
$this->addElement(
|
||||
'text',
|
||||
'group_class',
|
||||
array(
|
||||
'preserveDefault' => true,
|
||||
'ignore' => $disabled,
|
||||
'disabled' => $disabled,
|
||||
'label' => $this->translate('LDAP Group Object Class'),
|
||||
'description' => $this->translate('The object class used for storing groups on the LDAP server.'),
|
||||
'value' => $defaults->group_class
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'group_filter',
|
||||
array(
|
||||
'preserveDefault' => true,
|
||||
'allowEmpty' => true,
|
||||
'label' => $this->translate('LDAP Group Filter'),
|
||||
'description' => $this->translate(
|
||||
'An additional filter to use when looking up groups using the specified connection. '
|
||||
. 'Leave empty to not to use any additional filter rules.'
|
||||
),
|
||||
'requirement' => $this->translate(
|
||||
'The filter needs to be expressed as standard LDAP expression, without'
|
||||
. ' outer parentheses. (e.g. &(foo=bar)(bar=foo) or foo=bar)'
|
||||
),
|
||||
'validators' => array(
|
||||
array(
|
||||
'Callback',
|
||||
false,
|
||||
array(
|
||||
'callback' => function ($v) {
|
||||
return strpos($v, '(') !== 0;
|
||||
},
|
||||
'messages' => array(
|
||||
'callbackValue' => $this->translate('The filter must not be wrapped in parantheses.')
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
'value' => $defaults->group_filter
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'group_name_attribute',
|
||||
array(
|
||||
'preserveDefault' => true,
|
||||
'ignore' => $disabled,
|
||||
'disabled' => $disabled,
|
||||
'label' => $this->translate('LDAP Group Name Attribute'),
|
||||
'description' => $this->translate(
|
||||
'The attribute name used for storing a group\'s name on the LDAP server.'
|
||||
),
|
||||
'value' => $defaults->group_name_attribute
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'base_dn',
|
||||
array(
|
||||
'preserveDefault' => true,
|
||||
'label' => $this->translate('LDAP Group Base DN'),
|
||||
'description' => $this->translate(
|
||||
'The path where groups can be found on the LDAP server. Leave ' .
|
||||
'empty to select all users available using the specified connection.'
|
||||
),
|
||||
'value' => $defaults->base_dn
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and add all elements to this form required for the user configuration
|
||||
*
|
||||
* @param ConfigObject $defaults
|
||||
* @param null|bool $disabled
|
||||
*/
|
||||
protected function createUserConfigElements(ConfigObject $defaults, $disabled)
|
||||
{
|
||||
$this->addElement(
|
||||
'text',
|
||||
'user_class',
|
||||
array(
|
||||
'preserveDefault' => true,
|
||||
'ignore' => $disabled,
|
||||
'disabled' => $disabled,
|
||||
'label' => $this->translate('LDAP User Object Class'),
|
||||
'description' => $this->translate('The object class used for storing users on the LDAP server.'),
|
||||
'value' => $defaults->user_class
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'user_filter',
|
||||
array(
|
||||
'preserveDefault' => true,
|
||||
'allowEmpty' => true,
|
||||
'label' => $this->translate('LDAP User Filter'),
|
||||
'description' => $this->translate(
|
||||
'An additional filter to use when looking up users using the specified connection. '
|
||||
. 'Leave empty to not to use any additional filter rules.'
|
||||
),
|
||||
'requirement' => $this->translate(
|
||||
'The filter needs to be expressed as standard LDAP expression, without'
|
||||
. ' outer parentheses. (e.g. &(foo=bar)(bar=foo) or foo=bar)'
|
||||
),
|
||||
'validators' => array(
|
||||
array(
|
||||
'Callback',
|
||||
false,
|
||||
array(
|
||||
'callback' => function ($v) {
|
||||
return strpos($v, '(') !== 0;
|
||||
},
|
||||
'messages' => array(
|
||||
'callbackValue' => $this->translate('The filter must not be wrapped in parantheses.')
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
'value' => $defaults->user_filter
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'user_name_attribute',
|
||||
array(
|
||||
'preserveDefault' => true,
|
||||
'ignore' => $disabled,
|
||||
'disabled' => $disabled,
|
||||
'label' => $this->translate('LDAP User Name Attribute'),
|
||||
'description' => $this->translate(
|
||||
'The attribute name used for storing a user\'s name on the LDAP server.'
|
||||
),
|
||||
'value' => $defaults->user_name_attribute
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'user_base_dn',
|
||||
array(
|
||||
'preserveDefault' => true,
|
||||
'label' => $this->translate('LDAP User Base DN'),
|
||||
'description' => $this->translate(
|
||||
'The path where users can be found on the LDAP server. Leave ' .
|
||||
'empty to select all users available using the specified connection.'
|
||||
),
|
||||
'value' => $defaults->user_base_dn
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the names of all configured LDAP resources
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getLdapResourceNames()
|
||||
{
|
||||
$names = array();
|
||||
foreach (ResourceFactory::getResourceConfigs() as $name => $config) {
|
||||
if (in_array(strtolower($config->type), array('ldap', 'msldap'))) {
|
||||
$names[] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($names)) {
|
||||
Notification::error(
|
||||
$this->translate('No LDAP resources available. Please configure an LDAP resource first.')
|
||||
);
|
||||
$this->getResponse()->redirectAndExit('config/createresource');
|
||||
}
|
||||
|
||||
return $names;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the names of all configured LDAP user backends
|
||||
*
|
||||
* @param LdapConnection $resource
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getLdapUserBackendNames(LdapConnection $resource)
|
||||
{
|
||||
$names = array();
|
||||
foreach (UserBackend::getBackendConfigs() as $name => $config) {
|
||||
if (in_array(strtolower($config->backend), array('ldap', 'msldap'))) {
|
||||
$backendResource = ResourceFactory::create($config->resource);
|
||||
if (
|
||||
$backendResource->getHostname() === $resource->getHostname()
|
||||
&& $backendResource->getPort() === $resource->getPort()
|
||||
) {
|
||||
$names[] = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $names;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,216 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms\Config\UserGroup;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Icinga\Exception\IcingaException;
|
||||
use Icinga\Exception\NotFoundError;
|
||||
use Icinga\Forms\ConfigForm;
|
||||
|
||||
/**
|
||||
* Form for managing user group backends
|
||||
*/
|
||||
class UserGroupBackendForm extends ConfigForm
|
||||
{
|
||||
/**
|
||||
* The backend to load when displaying the form for the first time
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $backendToLoad;
|
||||
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_config_usergroupbackend');
|
||||
$this->setSubmitLabel($this->translate('Save Changes'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a form object for the given backend type
|
||||
*
|
||||
* @param string $type The backend type for which to return a form
|
||||
*
|
||||
* @return Form
|
||||
*
|
||||
* @throws InvalidArgumentException In case the given backend type is invalid
|
||||
*/
|
||||
public function getBackendForm($type)
|
||||
{
|
||||
switch ($type)
|
||||
{
|
||||
case 'db':
|
||||
return new DbUserGroupBackendForm();
|
||||
case 'ldap':
|
||||
case 'msldap':
|
||||
return new LdapUserGroupBackendForm();
|
||||
default:
|
||||
throw new InvalidArgumentException(
|
||||
sprintf($this->translate('Invalid backend type "%s" provided'), $type)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the form with the given backend's config
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws NotFoundError In case no backend with the given name is found
|
||||
*/
|
||||
public function load($name)
|
||||
{
|
||||
if (! $this->config->hasSection($name)) {
|
||||
throw new NotFoundError('No user group backend called "%s" found', $name);
|
||||
}
|
||||
|
||||
$this->backendToLoad = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new user group backend
|
||||
*
|
||||
* The backend to add is identified by the array-key `name'.
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws InvalidArgumentException In case $data does not contain a backend name
|
||||
* @throws IcingaException In case a backend with the same name already exists
|
||||
*/
|
||||
public function add(array $data)
|
||||
{
|
||||
if (! isset($data['name'])) {
|
||||
throw new InvalidArgumentException('Key \'name\' missing');
|
||||
}
|
||||
|
||||
$backendName = $data['name'];
|
||||
if ($this->config->hasSection($backendName)) {
|
||||
throw new IcingaException('A user group backend with the name "%s" does already exist', $backendName);
|
||||
}
|
||||
|
||||
unset($data['name']);
|
||||
$this->config->setSection($backendName, $data);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit a user group backend
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $data
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws NotFoundError In case no backend with the given name is found
|
||||
*/
|
||||
public function edit($name, array $data)
|
||||
{
|
||||
if (! $this->config->hasSection($name)) {
|
||||
throw new NotFoundError('No user group backend called "%s" found', $name);
|
||||
}
|
||||
|
||||
$backendConfig = $this->config->getSection($name);
|
||||
if (isset($data['name'])) {
|
||||
if ($data['name'] !== $name) {
|
||||
$this->config->removeSection($name);
|
||||
$name = $data['name'];
|
||||
}
|
||||
|
||||
unset($data['name']);
|
||||
}
|
||||
|
||||
$backendConfig->merge($data);
|
||||
foreach ($backendConfig->toArray() as $k => $v) {
|
||||
if ($v === null) {
|
||||
unset($backendConfig->$k);
|
||||
}
|
||||
}
|
||||
|
||||
$this->config->setSection($name, $backendConfig);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a user group backend
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function delete($name)
|
||||
{
|
||||
$this->config->removeSection($name);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and add elements to this form
|
||||
*
|
||||
* @param array $formData
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
// TODO(jom): We did not think about how to configure custom group backends yet!
|
||||
$backendTypes = array(
|
||||
'db' => $this->translate('Database'),
|
||||
'ldap' => 'LDAP',
|
||||
'msldap' => 'ActiveDirectory'
|
||||
);
|
||||
|
||||
$backendType = isset($formData['type']) ? $formData['type'] : null;
|
||||
if ($backendType === null) {
|
||||
$backendType = key($backendTypes);
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
'select',
|
||||
'type',
|
||||
array(
|
||||
'ignore' => true,
|
||||
'required' => true,
|
||||
'autosubmit' => true,
|
||||
'label' => $this->translate('Backend Type'),
|
||||
'description' => $this->translate('The type of this user group backend'),
|
||||
'multiOptions' => $backendTypes
|
||||
)
|
||||
);
|
||||
|
||||
$this->addSubForm($this->getBackendForm($backendType)->create($formData), 'backend_form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the configuration of the backend to load
|
||||
*/
|
||||
public function onRequest()
|
||||
{
|
||||
if ($this->backendToLoad) {
|
||||
$data = $this->config->getSection($this->backendToLoad)->toArray();
|
||||
$data['type'] = $data['backend'];
|
||||
$data['name'] = $this->backendToLoad;
|
||||
$this->populate($data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all form element values
|
||||
*
|
||||
* @param bool $suppressArrayNotation Ignored
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getValues($suppressArrayNotation = false)
|
||||
{
|
||||
$values = parent::getValues();
|
||||
$values = array_merge($values, $values['backend_form']);
|
||||
unset($values['backend_form']);
|
||||
return $values;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms\Config\UserGroup;
|
||||
|
||||
use Icinga\Data\Filter\Filter;
|
||||
use Icinga\Forms\RepositoryForm;
|
||||
|
||||
class UserGroupForm extends RepositoryForm
|
||||
{
|
||||
/**
|
||||
* Create and add elements to this form to insert or update a group
|
||||
*
|
||||
* @param array $formData The data sent by the user
|
||||
*/
|
||||
protected function createInsertElements(array $formData)
|
||||
{
|
||||
$this->addElement(
|
||||
'text',
|
||||
'group_name',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => $this->translate('Group Name')
|
||||
)
|
||||
);
|
||||
|
||||
if ($this->shouldInsert()) {
|
||||
$this->setTitle($this->translate('Add a new group'));
|
||||
$this->setSubmitLabel($this->translate('Add'));
|
||||
} else { // $this->shouldUpdate()
|
||||
$this->setTitle(sprintf($this->translate('Edit group %s'), $this->getIdentifier()));
|
||||
$this->setSubmitLabel($this->translate('Save'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a group
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function onUpdateSuccess()
|
||||
{
|
||||
if (parent::onUpdateSuccess()) {
|
||||
if (($newName = $this->getValue('group_name')) !== $this->getIdentifier()) {
|
||||
$this->getRedirectUrl()->setParam('group', $newName);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and add elements to this form to delete a group
|
||||
*
|
||||
* @param array $formData The data sent by the user
|
||||
*/
|
||||
protected function createDeleteElements(array $formData)
|
||||
{
|
||||
$this->setTitle(sprintf($this->translate('Remove group %s?'), $this->getIdentifier()));
|
||||
$this->addDescription($this->translate(
|
||||
'Note that all users that are currently a member of this group will'
|
||||
. ' have their membership cleared automatically.'
|
||||
));
|
||||
$this->setSubmitLabel($this->translate('Yes'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a filter to use when updating or deleting a group
|
||||
*
|
||||
* @return Filter
|
||||
*/
|
||||
protected function createFilter()
|
||||
{
|
||||
return Filter::where('group_name', $this->getIdentifier());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a notification message to use when inserting a group
|
||||
*
|
||||
* @param bool $success true or false, whether the operation was successful
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getInsertMessage($success)
|
||||
{
|
||||
if ($success) {
|
||||
return $this->translate('Group added successfully');
|
||||
} else {
|
||||
return $this->translate('Failed to add group');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a notification message to use when updating a group
|
||||
*
|
||||
* @param bool $success true or false, whether the operation was successful
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getUpdateMessage($success)
|
||||
{
|
||||
if ($success) {
|
||||
return sprintf($this->translate('Group "%s" has been edited'), $this->getIdentifier());
|
||||
} else {
|
||||
return sprintf($this->translate('Failed to edit group "%s"'), $this->getIdentifier());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a notification message to use when deleting a group
|
||||
*
|
||||
* @param bool $success true or false, whether the operation was successful
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getDeleteMessage($success)
|
||||
{
|
||||
if ($success) {
|
||||
return sprintf($this->translate('Group "%s" has been removed'), $this->getIdentifier());
|
||||
} else {
|
||||
return sprintf($this->translate('Failed to remove group "%s"'), $this->getIdentifier());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms;
|
||||
|
||||
|
@ -8,7 +7,6 @@ use Exception;
|
|||
use Zend_Form_Decorator_Abstract;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\File\Ini\IniWriter;
|
||||
|
||||
/**
|
||||
* Form base-class providing standard functionality for configuration forms
|
||||
|
@ -27,7 +25,7 @@ class ConfigForm extends Form
|
|||
*
|
||||
* @param Config $config The configuration to use
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function setIniConfig(Config $config)
|
||||
{
|
||||
|
@ -44,21 +42,14 @@ class ConfigForm extends Form
|
|||
*/
|
||||
public function save()
|
||||
{
|
||||
$writer = new IniWriter(
|
||||
array(
|
||||
'config' => $this->config,
|
||||
'filename' => $this->config->getConfigFile()
|
||||
)
|
||||
);
|
||||
|
||||
try {
|
||||
$writer->write();
|
||||
$this->config->saveIni();
|
||||
} catch (Exception $e) {
|
||||
$this->addDecorator('ViewScript', array(
|
||||
'viewModule' => 'default',
|
||||
'viewScript' => 'showConfiguration.phtml',
|
||||
'errorMessage' => $e->getMessage(),
|
||||
'configString' => $writer->render(),
|
||||
'configString' => $this->config,
|
||||
'filePath' => $this->config->getConfigFile(),
|
||||
'placement' => Zend_Form_Decorator_Abstract::PREPEND
|
||||
));
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms;
|
||||
|
||||
|
@ -12,11 +11,11 @@ use Icinga\Web\Form;
|
|||
class ConfirmRemovalForm extends Form
|
||||
{
|
||||
/**
|
||||
* Initalize this form
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_confirm_removal');
|
||||
$this->setSubmitLabel(t('Confirm Removal'));
|
||||
$this->getSubmitLabel() ?: $this->setSubmitLabel($this->translate('Confirm Removal'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms\Dashboard;
|
||||
|
||||
|
@ -26,7 +25,7 @@ class DashletForm extends Form
|
|||
{
|
||||
$this->setName('form_dashboard_addurl');
|
||||
if (! $this->getSubmitLabel()) {
|
||||
$this->setSubmitLabel(t('Add To Dashboard'));
|
||||
$this->setSubmitLabel($this->translate('Add To Dashboard'));
|
||||
}
|
||||
$this->setAction(URL::fromRequest());
|
||||
}
|
||||
|
@ -66,9 +65,10 @@ class DashletForm extends Form
|
|||
'url',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Url'),
|
||||
'description' =>
|
||||
t('Enter url being loaded in the dashlet. You can paste the full URL, including filters.')
|
||||
'label' => $this->translate('Url'),
|
||||
'description' => $this->translate(
|
||||
'Enter url being loaded in the dashlet. You can paste the full URL, including filters.'
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
|
@ -76,8 +76,22 @@ class DashletForm extends Form
|
|||
'dashlet',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Dashlet Title'),
|
||||
'description' => t('Enter a title for the dashlet.')
|
||||
'label' => $this->translate('Dashlet Title'),
|
||||
'description' => $this->translate('Enter a title for the dashlet.'),
|
||||
'validators' => array(
|
||||
array(
|
||||
'Regex',
|
||||
false,
|
||||
array(
|
||||
'pattern' => '/^[^\\[\\]]+$/',
|
||||
'messages' => array(
|
||||
'regexNotMatch' => $this->translate(
|
||||
'The name cannot contain \'[\' or \']\'.'
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
|
@ -95,9 +109,8 @@ class DashletForm extends Form
|
|||
'pane',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t("New Dashboard Title"),
|
||||
'description' =>
|
||||
t('Enter a title for the new pane.')
|
||||
'label' => $this->translate("New Dashboard Title"),
|
||||
'description' => $this->translate('Enter a title for the new pane.')
|
||||
)
|
||||
);
|
||||
} else {
|
||||
|
@ -106,10 +119,9 @@ class DashletForm extends Form
|
|||
'pane',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Dashboard'),
|
||||
'label' => $this->translate('Dashboard'),
|
||||
'multiOptions' => $panes,
|
||||
'description' =>
|
||||
t('Select a pane you want to add the dashlet.')
|
||||
'description' => $this->translate('Select a pane you want to add the dashlet.')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -118,10 +130,10 @@ class DashletForm extends Form
|
|||
'checkbox',
|
||||
'create_new_pane',
|
||||
array(
|
||||
'autosubmit' => true,
|
||||
'required' => false,
|
||||
'label' => t('New dashboard'),
|
||||
'class' => 'autosubmit',
|
||||
'description' => t('Check this box if you want to add the dashlet to a new dashboard')
|
||||
'label' => $this->translate('New dashboard'),
|
||||
'description' => $this->translate('Check this box if you want to add the dashlet to a new dashboard')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -150,9 +162,9 @@ class DashletForm extends Form
|
|||
$this->populate(array(
|
||||
'pane' => $dashlet->getPane()->getName(),
|
||||
'org_pane' => $dashlet->getPane()->getName(),
|
||||
'dashlet' => $dashlet->getTitle(),
|
||||
'org_dashlet' => $dashlet->getTitle(),
|
||||
'url' => $dashlet->getUrl()
|
||||
'dashlet' => $dashlet->getTitle(),
|
||||
'org_dashlet' => $dashlet->getTitle(),
|
||||
'url' => $dashlet->getUrl()->getRelativeUrl()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms;
|
||||
|
||||
|
@ -25,51 +24,11 @@ class LdapDiscoveryForm extends Form
|
|||
'text',
|
||||
'domain',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Search Domain'),
|
||||
'description' => t('Search this domain for records of available servers.'),
|
||||
'label' => $this->translate('Search Domain'),
|
||||
'description' => $this->translate('Search this domain for records of available servers.'),
|
||||
)
|
||||
);
|
||||
|
||||
if (false) {
|
||||
$this->addElement(
|
||||
'note',
|
||||
'additional_description',
|
||||
array(
|
||||
'value' => t('No Ldap servers found on this domain.'
|
||||
. ' You can try to specify host and port and try again, or just skip this step and '
|
||||
. 'configure the server manually.'
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'hostname',
|
||||
array(
|
||||
'required' => false,
|
||||
'label' => t('Host'),
|
||||
'description' => t('IP or host name to search.'),
|
||||
)
|
||||
);
|
||||
|
||||
$this->addElement(
|
||||
'text',
|
||||
'port',
|
||||
array(
|
||||
'required' => false,
|
||||
'label' => t('Port'),
|
||||
'description' => t('Port', 389),
|
||||
)
|
||||
);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isValid($data)
|
||||
{
|
||||
if (false === parent::isValid($data)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms;
|
||||
|
||||
use Exception;
|
||||
use DateTimeZone;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Authentication\Manager;
|
||||
use Icinga\Authentication\Auth;
|
||||
use Icinga\User\Preferences;
|
||||
use Icinga\User\Preferences\PreferencesStore;
|
||||
use Icinga\Util\TimezoneDetect;
|
||||
|
@ -41,6 +40,7 @@ class PreferenceForm extends Form
|
|||
public function init()
|
||||
{
|
||||
$this->setName('form_config_preferences');
|
||||
$this->setTitle($this->translate('Preferences'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -48,7 +48,7 @@ class PreferenceForm extends Form
|
|||
*
|
||||
* @param Preferences $preferences The preferences to work with
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function setPreferences(Preferences $preferences)
|
||||
{
|
||||
|
@ -61,17 +61,18 @@ class PreferenceForm extends Form
|
|||
*
|
||||
* @param PreferencesStore $store The preference store to use
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function setStore(PreferencesStore $store)
|
||||
{
|
||||
$this->store = $store;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist preferences
|
||||
*
|
||||
* @return self
|
||||
* @return $this
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
|
@ -86,7 +87,7 @@ class PreferenceForm extends Form
|
|||
*/
|
||||
public function onSuccess()
|
||||
{
|
||||
$this->preferences = new Preferences($this->store->load());
|
||||
$this->preferences = new Preferences($this->store ? $this->store->load() : array());
|
||||
|
||||
$webPreferences = $this->preferences->get('icingaweb', array());
|
||||
foreach ($this->getValues() as $key => $value) {
|
||||
|
@ -103,11 +104,11 @@ class PreferenceForm extends Form
|
|||
Session::getSession()->user->setPreferences($this->preferences);
|
||||
|
||||
try {
|
||||
if ($this->getElement('btn_submit_preferences')->isChecked()) {
|
||||
if ($this->store && $this->getElement('btn_submit_preferences')->isChecked()) {
|
||||
$this->save();
|
||||
Notification::success(t('Preferences successfully saved'));
|
||||
Notification::success($this->translate('Preferences successfully saved'));
|
||||
} else {
|
||||
Notification::success(t('Preferences successfully saved for the current session'));
|
||||
Notification::success($this->translate('Preferences successfully saved for the current session'));
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
Logger::error($e);
|
||||
|
@ -122,7 +123,7 @@ class PreferenceForm extends Form
|
|||
*/
|
||||
public function onRequest()
|
||||
{
|
||||
$auth = Manager::getInstance();
|
||||
$auth = Auth::getInstance();
|
||||
$values = $auth->getUser()->getPreferences()->get('icingaweb');
|
||||
|
||||
if (! isset($values['language'])) {
|
||||
|
@ -142,13 +143,13 @@ class PreferenceForm extends Form
|
|||
public function createElements(array $formData)
|
||||
{
|
||||
$languages = array();
|
||||
$languages['autodetect'] = sprintf(t('Browser (%s)', 'preferences.form'), $this->getLocale());
|
||||
$languages['autodetect'] = sprintf($this->translate('Browser (%s)', 'preferences.form'), $this->getLocale());
|
||||
foreach (Translator::getAvailableLocaleCodes() as $language) {
|
||||
$languages[$language] = $language;
|
||||
}
|
||||
|
||||
$tzList = array();
|
||||
$tzList['autodetect'] = sprintf(t('Browser (%s)', 'preferences.form'), $this->getDefaultTimezone());
|
||||
$tzList['autodetect'] = sprintf($this->translate('Browser (%s)', 'preferences.form'), $this->getDefaultTimezone());
|
||||
foreach (DateTimeZone::listIdentifiers() as $tz) {
|
||||
$tzList[$tz] = $tz;
|
||||
}
|
||||
|
@ -158,8 +159,8 @@ class PreferenceForm extends Form
|
|||
'language',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Your Current Language'),
|
||||
'description' => t('Use the following language to display texts and messages'),
|
||||
'label' => $this->translate('Your Current Language'),
|
||||
'description' => $this->translate('Use the following language to display texts and messages'),
|
||||
'multiOptions' => $languages,
|
||||
'value' => substr(setlocale(LC_ALL, 0), 0, 5)
|
||||
)
|
||||
|
@ -170,8 +171,8 @@ class PreferenceForm extends Form
|
|||
'timezone',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Your Current Timezone'),
|
||||
'description' => t('Use the following timezone for dates and times'),
|
||||
'label' => $this->translate('Your Current Timezone'),
|
||||
'description' => $this->translate('Use the following timezone for dates and times'),
|
||||
'multiOptions' => $tzList,
|
||||
'value' => $this->getDefaultTimezone()
|
||||
)
|
||||
|
@ -182,33 +183,40 @@ class PreferenceForm extends Form
|
|||
'show_benchmark',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Use benchmark')
|
||||
'label' => $this->translate('Use benchmark')
|
||||
)
|
||||
);
|
||||
|
||||
$this->addElement(
|
||||
'submit',
|
||||
'btn_submit_preferences',
|
||||
'checkbox',
|
||||
'auto_refresh',
|
||||
array(
|
||||
'ignore' => true,
|
||||
'label' => t('Save to the Preferences'),
|
||||
'decorators' => array(
|
||||
'ViewHelper',
|
||||
array('HtmlTag', array('tag' => 'div'))
|
||||
)
|
||||
'required' => false,
|
||||
'label' => $this->translate('Enable auto refresh'),
|
||||
'description' => $this->translate('This option allows you to enable or to disable the global page content auto refresh'),
|
||||
'value' => 1
|
||||
)
|
||||
);
|
||||
|
||||
if ($this->store) {
|
||||
$this->addElement(
|
||||
'submit',
|
||||
'btn_submit_preferences',
|
||||
array(
|
||||
'ignore' => true,
|
||||
'label' => $this->translate('Save to the Preferences'),
|
||||
'decorators' => array('ViewHelper')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
'submit',
|
||||
'btn_submit_session',
|
||||
array(
|
||||
'ignore' => true,
|
||||
'label' => t('Save for the current Session'),
|
||||
'decorators' => array(
|
||||
'ViewHelper',
|
||||
array('HtmlTag', array('tag' => 'div'))
|
||||
)
|
||||
'label' => $this->translate('Save for the current Session'),
|
||||
'decorators' => array('ViewHelper')
|
||||
)
|
||||
);
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue