Merge BRANCH-2.0 with master

This commit is contained in:
Deon George 2023-03-03 16:32:49 +11:00
commit f90706d140
409 changed files with 29818 additions and 4735 deletions

8
.dockerignore Normal file
View File

@ -0,0 +1,8 @@
.dockerignore
.editorconfig
.env.testing
.git*
package.json
phpunit.xml
webpack.mix.js
yarn.lock

18
.editorconfig Normal file
View File

@ -0,0 +1,18 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = tab
insert_final_newline = false
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.{yml,yaml}]
indent_size = 2
[docker-compose.yml]
indent_size = 4

51
.env.example Normal file
View File

@ -0,0 +1,51 @@
APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost
LOG_CHANNEL=stack
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=
BROADCAST_DRIVER=log
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=null
MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
LDAP_HOST=
LDAP_BASE_DN=
LDAP_USERNAME=
LDAP_PASSWORD=

51
.env.testing Normal file
View File

@ -0,0 +1,51 @@
APP_NAME=Laravel
APP_ENV=dev
APP_KEY=base64:KvIecx8zoy6RjcbJM8s98ZKs9IDGUHFVqBRn3Awfmso=
APP_DEBUG=true
APP_URL=http://localhost
LOG_CHANNEL=stack
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret
BROADCAST_DRIVER=log
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
LDAP_HOST=ldap
LDAP_PORT=389
LDAP_BASE_DN="dc=Test"
LDAP_USERNAME="cn=admin,dc=Test"
LDAP_PASSWORD="test"
LDAP_CACHE=false

5
.gitattributes vendored Normal file
View File

@ -0,0 +1,5 @@
* text=auto
*.css linguist-vendored
*.scss linguist-vendored
*.js linguist-vendored
CHANGELOG.md export-ignore

15
.gitignore vendored
View File

@ -1,3 +1,12 @@
config/config.php
queries/custom_*
templates/*/custom_*
/node_modules
/public/hot
/public/storage
/storage/*.key
/vendor
.env
.env.backup
.phpunit.result.cache
Homestead.json
Homestead.yaml
npm-debug.log
yarn-error.log

14
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,14 @@
stages:
- test
- build
# This folder is cached between builds
# http://docs.gitlab.com/ce/ci/yaml/README.html#cache
cache:
key: ${CI_JOB_NAME_SLUG}-${CI_COMMIT_REF_SLUG}
paths:
- vendor/
include:
- .gitlab-test.yml
- .gitlab-docker-x86_64.yml

27
.gitlab-docker-x86_64.yml Normal file
View File

@ -0,0 +1,27 @@
docker:
variables:
VERSION: latest
DOCKER_HOST: tcp://docker:2375
stage: build
image: docker:latest
services:
- docker:dind
before_script:
- docker info && docker version
- echo "$CI_JOB_TOKEN" | docker login -u "$CI_REGISTRY_USER" "$CI_REGISTRY" --password-stdin
- if [ -n "$GITHUB_TOKEN" ]; then cat $GITHUB_TOKEN |base64 -d > auth.json; fi
script:
- if [ -f init ]; then chmod 500 init; fi
- echo -n ${CI_COMMIT_SHORT_SHA} > VERSION
- rm -rf vendor/ database/schema database/seeders database/factories/*
- docker build -f docker/Dockerfile -t ${CI_REGISTRY_IMAGE}:${VERSION} .
- docker push ${CI_REGISTRY_IMAGE}:${VERSION}
tags:
- docker
- x86_64
only:
- BRANCH-2.0

49
.gitlab-test.yml Normal file
View File

@ -0,0 +1,49 @@
test:
image: ${CI_REGISTRY}/leenooks/php:8.1-fpm-alpine-ldap-test
stage: test
# NOTE: This service is dependant on project file configuration, which is not there if the cache was deleted
# resulting in the testing to fail on the first run.
services:
- name: osixia/openldap:latest
alias: ldap
command: ["--loglevel","debug"]
variables:
LDAP_SEED_INTERNAL_LDIF_PATH: "${CI_PROJECT_DIR}/tests/server/openldap/data"
LDAP_SEED_INTERNAL_SCHEMA_PATH: "${CI_PROJECT_DIR}/tests/server/openldap/schema"
LDAP_BASE_DN: "dc=Test"
LDAP_DOMAIN: "Test"
LDAP_ADMIN_PASSWORD: test
LDAP_HOST: ldap
LDAP_PORT: 389
#CI_DEBUG_SERVICES: "true"
tags:
- php
only:
- BRANCH-2.0
before_script:
- mv .env.testing .env
# Install Composer and project dependencies.
- mkdir -p ${COMPOSER_HOME}
- if [ -n "$GITHUB_TOKEN" ]; then cat $GITHUB_TOKEN |base64 -d > ${COMPOSER_HOME}/auth.json; fi
- composer install
# Generate an application key. Re-cache.
- php artisan key:generate
script:
# Sleep if we need to, in case we want to jump in and see what is going on during the test
- if [ -n "$DEBUG_PAUSE" ]; then echo "Pausing for $DEBUG_PAUSE seconds, so you can jump into the containers"; sleep $DEBUG_PAUSE; fi
# run laravel tests
- XDEBUG_MODE=coverage php vendor/bin/phpunit --coverage-text --colors=never
# run frontend tests
# if you have any task for testing frontend
# set it in your package.json script
# comment this out if you don't have a frontend test
# npm test

View File

@ -1,23 +0,0 @@
For install instructions in non-English languages, see the wiki:
http://phpldapadmin.sourceforge.net
* Requirements
phpLDAPadmin requires the following:
a. A web server (Apache, IIS, etc).
b. PHP 5.5.0 or newer (with LDAP support)
* To install
1. Unpack the archive (if you're reading this, you already did that).
2. Put the resulting 'phpldapadmin' directory somewhere in your webroot.
3. Copy 'config.php.example' to 'config.php' and edit to taste (this is in the config/ directory).
4. Then, point your browser to the phpldapadmin directory.
* For additional help
See the wiki:
http://phpldapadmin.sourceforge.net
Join our mailing list:
https://lists.sourceforge.net/lists/listinfo/phpldapadmin-devel

View File

@ -1,20 +1,33 @@
# phpLDAPadmin
phpLDAPadmin is a web based LDAP data management tool for system administrators. It is commonly known and referred by many as "PLA".
A primary goal of PLA is to be as intuitive as possible - so it is certainly possible for end users to use it as well, for example, to manage their data in an LDAP server.
PLA is designed to be compliant with LDAP RFCs, enabling it to be used with any LDAP server.
If you come across an LDAP server, where PLA exhibits problems, please open an issue with full details of the problem so that we can have it fixed.
## History
Initially created in 2002 by David Smith, it was taken over by Deon George (aka leenooks) in 2005.
For up to date information on PLA, please head to the [wiki](https://github.com/leenooks/phpLDAPadmin/wiki).
Since 2003 many things have changed - initial development was done in CVS and the project was hosted on Sourceforge.
In 2009, CVS was swapped out for GIT, and in around 2011 the project was moved to Github.
> **NOTE**: GIT **master** is currently in active development, and as such functionality may be missing, broken or not working as expected.
>
> If you are after a working version of PLA, please use one of the tagged releases.
The PLA v1.2.x stream was created in July 2009.
## Demo
If you havent seen PLA in action, you can head here to the [demo](https://demo.phpldapadmin.org) site.
Work on PLA v2 has started and some information on that is below. Soon `master` will be updated and `BRANCH-2.0` will be visible in git. Until then, a sneak peak of v2 is available [here](https://phpldapadmin.servio.leenooks.net)
## Getting Help
The best place to get help with PLA (new and old) is on [Stack Overflow](https://stackoverflow.com/tags/phpldapadmin/info).
## Found a bug?
If you have found a bug, and can provide detailed instructions so that it can be reproduced, please open an [issue](https://github.com/leenooks/phpLDAPadmin/issues) and provide those details.
Before opening a ticket, please check to see if it hasnt already been reported, and if it has, please provide any additional information that will help it be fixed.
*TIP*: Issues opened with:
* details enabling the problem to be reproduced,
* including (if appropriate) an LDIF with the data that exhibits the problem,
* a patch (or a git pull request) to fix the problem
will be looked at first :)
## THANK YOU
Over the years, many, many, many people have supported PLA with either their time, their coding or with financial donations.
@ -22,69 +35,5 @@ I have tried to send an email to acknowledge each contribution, and if you haven
Again, Thank You.
## Future
Web development, tools, approaches and technology has come along way since 2009 and some talented folks have created some fantastic tools.
With that PLA is going under a major revamp in preparation for v2 and will aim to use those existing creations to help speed up the revamp effort.
Some of the creations planned to be used in v2 include:
* Laravel (https://laravel.com)
* adldap2/adldap2 (https://github.com/Adldap2/Adldap2)
* JQuery (https://jquery.com)
* FancyTree (https://github.com/mar10/fancytree)
* ArchitectUI (https://architectui.com)
PLA v1.2.x will be archived into [BRANCH-1.2](https://github.com/leenooks/phpLDAPadmin/tree/BRANCH-1.2), and `master` will be changed to reflect the new v2 work and effort.
If you plan to use PLA, and cannot use an installation from your OS package, please use [BRANCH-1.2](https://github.com/leenooks/phpLDAPadmin/tree/BRANCH-1.2) while progress is made in master for v2.
If you like the cutting edge, feel free to try out `master`, but expect problems, bugs and missing functionality.
If you have extended v2 and would like to contribute your extension, or if you find a way to fix something that is broken or missing please submit a pull request.
Alternatively, you can get take a peek at the work so far by using our docker container, which is built automatically after testing passes.
The [demo](http://demo.phpldapadmin.org) site, will also be running the same docker container. (See below for details.)
In summary, for the time being, expect `master` to be buggy and broken, and I'll update this readme as enhancements progress.
## Installation
The following instructions will be for PLA v2 when its commited to GIT. Checkback regularly, as it will be pushed when its is semi functional.
### Installation on your server
#### Prerequisites
* A HTTP server (eg: Apache, Nginx)
* PHP (minimum version 7.2) https://www.php.net
* Composer https://getcomposer.org
* GIT
#### Installation
1. Checkout the code from github
```bash
git clone https://github.com/leenooks/phpLDAPadmin.git
```
1. Install composer dependencies.
```bash
composer install
```
1. Edit your `.env` file as appropriate
copy `.env.example` to `.env` as a start.
1. Configure your webserver to have PLA's root in the `public` directory
### Using Docker
Instructions to come.
## Getting Help
The best place to get help with PLA (new and old) is on Stack Overflow (https://stackoverflow.com/tags/phpldapadmin/info)
## Found a bug?
If you have found a bug, and can provide detailed instructions so that it can be reproduced, please open an [issue](https://github.com/leenooks/phpLDAPadmin/issues) and provide those details.
Before opening a ticket, please check to see if it hasnt already been reported, and if it has, please provide any additional information that will help it be fixed.
*TIP*: Issues opened with reproducible details accompanied with a patch (or a pull request) to fix the problem will be looked at first.
## License
[LICENSE](LICENSE)

View File

@ -1 +1 @@
RELEASE-1.2.5
GIT

3
app/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
q*
!public/
!.gitignore

View File

@ -1,33 +1,45 @@
<?php
/**
* Classes and functions for the template engine.
*
* @author The phpLDAPadmin development team
* @package phpLDAPadmin
*/
namespace App\Classes\LDAP;
use Illuminate\Support\Collection;
use App\Classes\LDAP\Schema\AttributeType;
/**
* Represents an attribute of a template.
*
* @package phpLDAPadmin
* @subpackage Templates
* Represents an attribute of an LDAP Object
*/
class Attribute {
# Attribute Name
public $name;
class Attribute
{
// Attribute Name
protected string $name;
protected ?AttributeType $schema = NULL;
/*
# Source of this attribute definition
protected $source;
*/
# Current and Old Values
protected $oldvalues = array();
protected $values = array();
// Current and Old Values
protected Collection $values;
# MIN/MAX number of values
protected $min_value_count = -1;
protected $max_value_count = -1;
// Can this attribute be deleted
protected bool $is_deletable = FALSE;
# Is the attribute internal
protected $internal = false;
// Is this attribute an internal attribute
protected bool $is_internal = FALSE;
// Is this attribute the RDN?
protected bool $is_rdn = FALSE;
protected Collection $required_by;
// MIN/MAX number of values
protected int $min_values_count = 0;
protected int $max_values_count = 0;
/*
# Has the attribute been modified
protected $modified = false;
# Is the attribute being deleted because of an object class removal
@ -69,7 +81,6 @@ class Attribute {
public $page = 1;
public $order = 255;
public $ordersort = 255;
public $rdn = false;
# Schema Aliases for this attribute (stored in lowercase)
protected $aliases = array();
@ -77,37 +88,18 @@ class Attribute {
# Configuration for automatically generated values
protected $autovalue = array();
protected $postvalue = array();
*/
public function __construct($name,$values,$server_id,$source=null) {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
public function __construct(string $name,array $values)
{
$this->name = $name;
$this->values = collect($values);
$server = $_SESSION[APPCONFIG]->getServer($server_id);
$sattr = $server->getSchemaAttribute($name);
if ($sattr) {
$this->name = $sattr->getName(false);
$this->setLDAPdetails($sattr);
} else
$this->name = $name;
$this->source = $source;
# XML attributes are shown by default
switch ($source) {
case 'XML': $this->show();
$this->setXML($values);
break;
default:
if (! isset($values['values']))
debug_dump_backtrace('no index "values"',1);
$this->initValue($values['values']);
}
// No need to load our schema for internal attributes
if (! $this->is_internal)
$this->schema = config('server')->schema('attributetypes',$name);
/*
# Should this attribute be hidden
if ($server->isAttrHidden($this->name))
$this->forcehide = true;
@ -119,6 +111,97 @@ class Attribute {
# Should this attribute value be unique
if ($server->isAttrUnique($this->name))
$this->unique = true;
*/
}
public function __get(string $key): mixed
{
return match ($key) {
// Can this attribute have more values
'can_addvalues' => $this->schema && (! $this->schema->is_single_value) && ((! $this->max_values_count) || ($this->values->count() < $this->max_values_count)),
// Schema attribute description
'description' => $this->schema ? $this->schema->{$key} : NULL,
// Attribute hints
'hints' => $this->hints(),
// Is this an internal attribute
'is_internal' => isset($this->{$key}) && $this->{$key},
// We prefer the name as per the schema if it exists
'name' => $this->schema ? $this->schema->{$key} : $this->{$key},
// Attribute name in lower case
'name_lc' => strtolower($this->name),
// Is this attribute the RDN
'rdn' => $this->is_rdn,
default => throw new \Exception('Unknown key:' . $key),
};
}
/**
* Determine how we render this attribute's value
*
* @return string
*/
public function __toString(): string
{
return $this->values->join('<br>');
}
/**
* Return an instance of this attribute that is deletable.
* This is primarily used for rendering to know if to render delete options.
*
* @return Attribute
*/
public function deletable(): self
{
$clone = clone $this;
if (! $this->required_by->count())
$clone->is_deletable = TRUE;
return $clone;
}
/**
* Return the hints about this attribute, ie: RDN, Required, etc
*
* @return array
*/
public function hints(): array
{
$result = collect();
// Is this Attribute an RDN
if ($this->is_rdn)
$result->put(__('rdn'),__('This attribute is required for the RDN'));
// If this attribute name is an alias for the schema attribute name
// @todo
// objectClasses requiring this attribute
// eg: $result->put('required','Required by objectClasses: a,b');
if ($this->required_by->count())
$result->put(__('required'),sprintf('%s: %s',__('Required Attribute by ObjectClass(es)'),$this->required_by->join(',')));
return $result->toArray();
}
/**
* Set the objectclasses that require this attribute
*
* @param Collection $oc
* @return Collection
*/
public function required_by(Collection $oc): Collection
{
return $this->required_by = ($this->schema
? $oc->intersect($this->schema->required_by_object_classes)
: collect());
}
public function setRDN(): void
{
$this->is_rdn = TRUE;
}
/**
@ -127,7 +210,7 @@ class Attribute {
* @param boolean $lower - Return the attribute in normal or lower case (default lower)
* @param boolean $real - Return the real attribute name (with ;binary, or just the name)
* @return string Attribute name
*/
*
public function getName($lower=true,$real=false) {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs,$this->name);
@ -168,7 +251,7 @@ class Attribute {
/**
* Autovalue is called after the attribute is initialised, and thus the values from the ldap server will be set.
*/
*
public function autoValue($new_val) {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
@ -258,64 +341,6 @@ class Attribute {
}
}
public function getValue($i) {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
if (isset($this->values[$i]))
return $this->values[$i];
else
return null;
}
public function getOldValue($i) {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
if (isset($this->oldvalues[$i]))
return $this->oldvalues[$i];
else
return null;
}
public function getMinValueCount() {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->min_value_count);
return $this->min_value_count;
}
public function setMinValueCount($min) {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
$this->min_value_count = $min;
}
public function getMaxValueCount() {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->max_value_count);
return $this->max_value_count;
}
public function setMaxValueCount($max) {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
$this->max_value_count = $max;
}
public function haveMoreValues() {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
if ($this->getMaxValueCount() < 0 || ($this->getValueCount() < $this->getMaxValueCount()))
return true;
else
return false;
}
public function justModified() {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
@ -347,20 +372,6 @@ class Attribute {
$this->justModified();
}
public function isInternal() {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->internal);
return $this->internal;
}
public function setInternal() {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
$this->internal = true;
}
public function isRequired() {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
@ -637,30 +648,11 @@ class Attribute {
return $this->verify;
}
public function setRDN($rdn) {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs);
$this->rdn = $rdn;
}
/**
* Return if this attribute is an RDN attribute
*
* @return boolean
*/
public function isRDN() {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs,$this->rdn);
return $this->rdn;
}
/**
* Capture all the LDAP details we are interested in
*
* @param sattr Schema Attribute
*/
*
private function setLDAPdetails($sattr) {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
@ -680,7 +672,7 @@ class Attribute {
/**
* Return a list of aliases for this Attribute (as defined by the schema)
* This list will be lowercase.
*/
*
public function getAliases() {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->aliases);
@ -846,7 +838,7 @@ class Attribute {
/**
* Display the values removed in an attribute.
*/
*
public function getRemovedValues() {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
@ -856,7 +848,7 @@ class Attribute {
/**
* Display the values removed in an attribute.
*/
*
public function getAddedValues() {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
@ -872,7 +864,7 @@ class Attribute {
*
* @param string $attr_name The name of the attribute to examine.
* @return string
*/
*
private function real_attr_name() {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',5,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->name);
@ -882,7 +874,7 @@ class Attribute {
/**
* Does this attribute need supporting JS
*/
*
public function needJS($type=null) {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
@ -913,5 +905,5 @@ class Attribute {
} else
debug_dump_backtrace(sprintf('Unknown JS request %s',$type),1);
}
}
?>
*/
}

View File

@ -0,0 +1,12 @@
<?php
namespace App\Classes\LDAP\Attribute;
use App\Classes\LDAP\Attribute;
/**
* Represents an attribute whose values are binary
*/
class Binary extends Attribute
{
}

View File

@ -0,0 +1,41 @@
<?php
namespace App\Classes\LDAP\Attribute\Binary;
use App\Classes\LDAP\Attribute\Binary;
/**
* Represents an JpegPhoto Attribute
*/
final class JpegPhoto extends Binary
{
public function __construct(string $name,array $values)
{
parent::__construct($name,$values);
$this->internal = FALSE;
}
public function __toString(): string
{
// We'll use finfo to try and figure out what type of image is stored
$f = new \finfo;
$result = '<table class="table table-borderless p-0 m-0"><tr>';
foreach ($this->values as $value) {
switch ($x=$f->buffer($value,FILEINFO_MIME_TYPE)) {
case 'image/jpeg':
default:
$result .= sprintf('<td><img class="jpegphoto" src="data:%s;base64, %s" />%s</td>',
$x,
base64_encode($value),
$this->is_deletable ? sprintf('<br><span class="btn btn-sm btn-danger"><i class="fas fa-trash-alt"></i> %s</span>',__('Delete')) : '');
}
}
$result .= '</tr></table>';
return $result;
}
}

View File

@ -0,0 +1,57 @@
<?php
namespace App\Classes\LDAP\Attribute;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Log;
use App\Classes\LDAP\Attribute;
/**
* This factory is used to return LDAP attributes as an object
*
* If there is no specific Attribute defined, then the default Attribute::class is return
*/
class Factory
{
private const LOGKEY = 'LAf';
/**
* Map of attributes to appropriate class
*/
public const map = [
'createtimestamp' => Internal\Timestamp::class,
'creatorsname' => Internal\EntryDN::class,
'entrycsn' => Internal\EntryCSN::class,
'entrydn' => Internal\EntryDN::class,
'entryuuid' => Internal\EntryUUID::class,
'gidnumber' => GidNumber::class,
'hassubordinates' => Internal\HasSubordinates::class,
'jpegphoto' => Binary\JpegPhoto::class,
'modifytimestamp' => Internal\Timestamp::class,
'modifiersname' => Internal\EntryDN::class,
'objectclass' => ObjectClass::class,
'structuralobjectclass' => Internal\StructuralObjectClass::class,
'subschemasubentry' => Internal\SubschemaSubentry::class,
'supportedcontrol' => Schema\OID::class,
'supportedextension' => Schema\OID::class,
'supportedfeatures' => Schema\OID::class,
'supportedsaslmechanisms' => Schema\Mechanisms::class,
'userpassword' => Password::class,
];
/**
* Create the new Object for an attribute
*
* @param string $attribute
* @param array $values
* @return Attribute
*/
public static function create(string $attribute,array $values): Attribute
{
$class = Arr::get(self::map,$attribute,Attribute::class);
Log::debug(sprintf('%s:Creating LDAP Attribute [%s] as [%s]',static::LOGKEY,$attribute,$class));
return new $class($attribute,$values);
}
}

View File

@ -0,0 +1,12 @@
<?php
namespace App\Classes\LDAP\Attribute;
use App\Classes\LDAP\Attribute;
/**
* Represents an GidNumber Attribute
*/
final class GidNumber extends Attribute
{
}

View File

@ -0,0 +1,13 @@
<?php
namespace App\Classes\LDAP\Attribute;
use App\Classes\LDAP\Attribute;
/**
* Represents an attribute whose values are internal
*/
abstract class Internal extends Attribute
{
protected bool $is_internal = TRUE;
}

View File

@ -0,0 +1,12 @@
<?php
namespace App\Classes\LDAP\Attribute\Internal;
use App\Classes\LDAP\Attribute\Internal;
/**
* Represents an EntryCSN Attribute
*/
final class EntryCSN extends Internal
{
}

View File

@ -0,0 +1,12 @@
<?php
namespace App\Classes\LDAP\Attribute\Internal;
use App\Classes\LDAP\Attribute\Internal;
/**
* Represents an EntryDN Attribute
*/
final class EntryDN extends Internal
{
}

View File

@ -0,0 +1,12 @@
<?php
namespace App\Classes\LDAP\Attribute\Internal;
use App\Classes\LDAP\Attribute\Internal;
/**
* Represents an EntryUUID Attribute
*/
final class EntryUUID extends Internal
{
}

View File

@ -0,0 +1,12 @@
<?php
namespace App\Classes\LDAP\Attribute\Internal;
use App\Classes\LDAP\Attribute\Internal;
/**
* Represents an HasSubordinates Attribute
*/
final class HasSubordinates extends Internal
{
}

View File

@ -0,0 +1,12 @@
<?php
namespace App\Classes\LDAP\Attribute\Internal;
use App\Classes\LDAP\Attribute\Internal;
/**
* Represents an StructuralObjectClass Attribute
*/
final class StructuralObjectClass extends Internal
{
}

View File

@ -0,0 +1,12 @@
<?php
namespace App\Classes\LDAP\Attribute\Internal;
use App\Classes\LDAP\Attribute\Internal;
/**
* Represents an SubschemaSubentry Attribute
*/
final class SubschemaSubentry extends Internal
{
}

View File

@ -0,0 +1,18 @@
<?php
namespace App\Classes\LDAP\Attribute\Internal;
use Carbon\Carbon;
use App\Classes\LDAP\Attribute\Internal;
/**
* Represents an attribute whose values are timestamps
*/
final class Timestamp extends Internal
{
public function __toString(): string
{
return Carbon::createFromTimestamp(strtotime($this->values[0]))->format(config('ldap.datetime_format','Y-m-d H:i:s'));
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace App\Classes\LDAP\Attribute;
use App\Classes\LDAP\Attribute;
/**
* Represents an ObjectClass Attribute
*/
final class ObjectClass extends Attribute
{
public function __toString(): string
{
return $this->values->sort()->join('<br>');
}
}

View File

@ -0,0 +1,17 @@
<?php
namespace App\Classes\LDAP\Attribute;
use App\Classes\LDAP\Attribute;
/**
* Represents an attribute whose values are passwords
*/
class Password extends Attribute
{
public function __toString(): string
{
return str_repeat('*',10)
.sprintf('<br><span class="btn btn-sm btn-outline-dark"><i class="fas fa-user-check"></i> %s</span>',__('Check Password'));
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace App\Classes\LDAP\Attribute;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Cache;
use App\Classes\LDAP\Attribute;
/**
* Represents an attribute whose values are schema related
*/
abstract class Schema extends Attribute
{
protected bool $internal = TRUE;
protected static function _get(string $filename,string $string,string $key): ?string
{
$array = Cache::remember($filename,86400,function() use ($filename) {
try {
$f = fopen($filename,'r');
} catch (\Exception $e) {
return NULL;
}
$result = collect();
while (! feof($f)) {
$line = trim(fgets($f));
if (! $line OR preg_match('/^#/',$line))
continue;
$fields = explode(':',$line);
$result->put($x=Arr::get($fields,0),[
'title'=>Arr::get($fields,1,$x),
'ref'=>Arr::get($fields,2),
'desc'=>Arr::get($fields,3,__('No description available, can you help with one?')),
]);
}
fclose($f);
return $result;
});
return Arr::get(($array ? $array->get($string) : []),$key);
}
}

View File

@ -0,0 +1,48 @@
<?php
namespace App\Classes\LDAP\Attribute\Schema;
use App\Classes\LDAP\Attribute\Schema;
/**
* Represents a Mechanisms Attribute
*/
final class Mechanisms extends Schema
{
public function __toString(): string
{
return $this->values
->transform(function($item) {
$format = sprintf('<abbr class="pb-1" title="%s"><i class="fas fa-book pr-2"></i>%s</abbr>%s<p class="mb-0">%s</p>',
$item,
static::get($item,'title'),
($x=static::get($item,'ref')) ? sprintf('<abbr class="pl-2" title="%s"><i class="fas fa-comment-dots"></i></abbr>',$x) : '',
static::get($item,'desc'),
);
return $format;
})->join('<br>');
}
/**
* Given an SASL Mechanism name, returns a verbose description of the Mechanism.
* This function parses ldap_supported_saslmechanisms.txt and looks up the specified
* Mechanism, and returns the verbose message defined in that file.
*
* <code>
* "SCRAM-SHA-1" => array:3 [
* "title" => "Salted Challenge Response Authentication Mechanism (SCRAM) SHA1"
* "ref" => "RFC 5802"
* "desc" => "This specification describes a family of authentication mechanisms called the Salted Challenge Response Authentication Mechanism (SCRAM) which addresses the req ▶"
* ]
* </code>
*
* @param string $string The SASL Mechanism (ie, "SCRAM-SHA-1") of interest.
* @param string $key The title|ref|desc to return
* @return string|NULL
*/
protected static function get(string $string,string $key): ?string
{
return parent::_get(config_path('ldap_supported_saslmechanisms.txt'),$string,$key);
}
}

View File

@ -0,0 +1,53 @@
<?php
namespace App\Classes\LDAP\Attribute\Schema;
use App\Classes\LDAP\Attribute\Schema;
/**
* Represents an OID Attribute
*/
final class OID extends Schema
{
public function __toString(): string
{
return $this->values
->transform(function($item) {
if (preg_match('/[0-9]+\.[0-9]+\.[0-9]+/',$item)) {
$format = sprintf('<abbr class="pb-1" title="%s"><i class="fas fa-list-ol pr-2"></i>%s</abbr>%s<p class="mb-0">%s</p>',
$item,
static::get($item,'title'),
($x=static::get($item,'ref')) ? sprintf('<abbr class="pl-2" title="%s"><i class="fas fa-comment-dots"></i></abbr>',$x) : '',
static::get($item,'desc'),
);
return $format;
} else
return $item;
})->join('<br>');
}
/**
* Given an LDAP OID number, returns a verbose description of the OID.
* This function parses ldap_supported_oids.txt and looks up the specified
* OID, and returns the verbose message defined in that file.
*
* <code>
* "1.3.6.1.4.1.4203.1.5.1" => array:3 [
* [title] => All Operational Attribute
* [ref] => RFC 3673
* [desc] => An LDAP extension which clients may use to request the return of all operational attributes.
* ]
* </code>
*
* @param string $string The OID number (ie, "1.3.6.1.4.1.4203.1.5.1") of the OID of interest.
* @param string $key The title|ref|desc to return
* @return string|null
* @testedby TranslateOidTest::testRootDSE()
*/
protected static function get(string $string,string $key): ?string
{
return parent::_get(config_path('ldap_supported_oids.txt'),$string,$key);
}
}

View File

@ -0,0 +1,595 @@
<?php
namespace App\Classes\LDAP\Schema;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
/**
* Represents an LDAP AttributeType
*
* @package phpLDAPadmin
* @subpackage Schema
*/
class AttributeType extends Base {
// The attribute from which this attribute inherits (if any)
private ?string $sup_attribute = NULL;
// Array of AttributeTypes which inherit from this one
private Collection $children;
// The equality rule used
private ?string $equality = NULL;
// The ordering of the attributeType
private ?string $ordering = NULL;
// Supports substring matching?
private ?string $sub_str_rule = NULL;
// The full syntax string, ie 1.2.3.4{16}
private ?string $syntax = NULL;
private ?string $syntax_oid = NULL;
// boolean: is single valued only?
private bool $is_single_value = FALSE;
// boolean: is collective?
private bool $is_collective = FALSE;
// boolean: can use modify?
private bool $is_no_user_modification = FALSE;
// The usage string set by the LDAP schema
private ?string $usage = NULL;
// An array of alias attribute names, strings
private Collection $aliases;
// The max number of characters this attribute can be
private ?int $max_length = NULL;
// A string description of the syntax type (taken from the LDAPSyntaxes)
/**
* @deprecated - reference syntaxes directly if possible
* @var string
*/
private ?string $type = NULL;
// An array of objectClasses which use this attributeType (must be set by caller)
private Collection $used_in_object_classes;
// A list of object class names that require this attribute type.
private Collection $required_by_object_classes;
// This attribute has been forced a MAY attribute by the configuration.
private bool $forced_as_may = FALSE;
/**
* Creates a new AttributeType object from a raw LDAP AttributeType string.
*
* eg: ( 2.5.4.0 NAME 'objectClass' DESC 'RFC4512: object classes of the entity' EQUALITY objectIdentifierMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )
*/
public function __construct(string $line) {
Log::debug(sprintf('Parsing AttributeType [%s]',$line));
parent::__construct($line);
$strings = preg_split('/[\s,]+/',$line,-1,PREG_SPLIT_DELIM_CAPTURE);
// Init
$this->children = collect();
$this->aliases = collect();
$this->used_in_object_classes = collect();
$this->required_by_object_classes = collect();
for ($i=0; $i < count($strings); $i++) {
switch ($strings[$i]) {
case '(':
case ')':
break;
case 'NAME':
// @note Some schema's return a (' instead of a ( '
if ($strings[$i+1] != '(' && ! preg_match('/^\(/',$strings[$i+1])) {
do {
$this->name .= (strlen($this->name) ? ' ' : '').$strings[++$i];
} while (! preg_match("/\'$/s",$strings[$i]));
// This attribute has no aliases
//$this->aliases = collect();
} else {
$i++;
do {
// In case we came here becaues of a ('
if (preg_match('/^\(/',$strings[$i]))
$strings[$i] = preg_replace('/^\(/','',$strings[$i]);
else
$i++;
$this->name .= (strlen($this->name) ? ' ' : '').$strings[++$i];
} while (! preg_match("/\'$/s",$strings[$i]));
// Add alias names for this attribute
while ($strings[++$i] != ')') {
$alias = $strings[$i];
$alias = preg_replace("/^\'(.*)\'$/",'$1',$alias);
$this->addAlias($alias);
}
}
$this->name = preg_replace("/^\'(.*)\'$/",'$1',$this->name);
Log::debug(sprintf('- Case NAME returned (%s)',$this->name),['aliases'=>$this->aliases]);
break;
case 'DESC':
do {
$this->description .= (strlen($this->description) ? ' ' : '').$strings[++$i];
} while (! preg_match("/\'$/s",$strings[$i]));
$this->description = preg_replace("/^\'(.*)\'$/",'$1',$this->description);
Log::debug(sprintf('- Case DESC returned (%s)',$this->description));
break;
case 'OBSOLETE':
$this->is_obsolete = TRUE;
Log::debug(sprintf('- Case OBSOLETE returned (%s)',$this->is_obsolete));
break;
case 'SUP':
$i++;
$this->sup_attribute = preg_replace("/^\'(.*)\'$/",'$1',$strings[$i]);
Log::debug(sprintf('- Case SUP returned (%s)',$this->sup_attribute));
break;
case 'EQUALITY':
$this->equality = $strings[++$i];
Log::debug(sprintf('- Case EQUALITY returned (%s)',$this->equality));
break;
case 'ORDERING':
$this->ordering = $strings[++$i];
Log::debug(sprintf('- Case ORDERING returned (%s)',$this->ordering));
break;
case 'SUBSTR':
$this->sub_str_rule = $strings[++$i];
Log::debug(sprintf('- Case SUBSTR returned (%s)',$this->sub_str_rule));
break;
case 'SYNTAX':
$this->syntax = $strings[++$i];
$this->syntax_oid = preg_replace('/{\d+}$/','',$this->syntax);
Log::debug(sprintf('/ Evaluating SYNTAX returned (%s) [%s]',$this->syntax,$this->syntax_oid));
// Does this SYNTAX string specify a max length (ie, 1.2.3.4{16})
$m = [];
if (preg_match('/{(\d+)}$/',$this->syntax,$m))
$this->max_length = $m[1];
else
$this->max_length = NULL;
if ($i < count($strings) - 1 && $strings[$i+1] == '{')
do {
$this->name .= ' '.$strings[++$i];
} while ($strings[$i] != '}');
$this->syntax = preg_replace("/^\'(.*)\'$/",'$1',$this->syntax);
$this->syntax_oid = preg_replace("/^\'(.*)\'$/",'$1',$this->syntax_oid);
Log::debug(sprintf('- Case SYNTAX returned (%s) [%s] {%d}',$this->syntax,$this->syntax_oid,$this->max_length));
break;
case 'SINGLE-VALUE':
$this->is_single_value = TRUE;
Log::debug(sprintf('- Case SINGLE-VALUE returned (%s)',$this->is_single_value));
break;
case 'COLLECTIVE':
$this->is_collective = TRUE;
Log::debug(sprintf('- Case COLLECTIVE returned (%s)',$this->is_collective));
break;
case 'NO-USER-MODIFICATION':
$this->is_no_user_modification = TRUE;
Log::debug(sprintf('- Case NO-USER-MODIFICATION returned (%s)',$this->is_no_user_modification));
break;
case 'USAGE':
$this->usage = $strings[++$i];
Log::debug(sprintf('- Case USAGE returned (%s)',$this->usage));
break;
// @note currently not captured
case 'X-ORDERED':
Log::error(sprintf('- Case X-ORDERED returned (%s)',$strings[++$i]));
break;
// @note currently not captured
case 'X-ORIGIN':
$value = '';
do {
$value .= (strlen($value) ? ' ' : '').$strings[++$i];
} while (! preg_match("/\'$/s",$strings[$i]));
Log::error(sprintf('- Case X-ORIGIN returned (%s)',$value));
break;
default:
if (preg_match('/[\d\.]+/i',$strings[$i]) && ($i === 1)) {
$this->oid = $strings[$i];
Log::debug(sprintf('- Case default returned (%s)',$this->oid));
} elseif ($strings[$i])
Log::alert(sprintf('! Case default discovered a value NOT parsed (%s)',$strings[$i]),['line'=>$line]);
}
}
}
public function __clone()
{
// When we clone, we need to break the reference to
$this->aliases = clone $this->aliases;
}
public function __get(string $key): mixed
{
switch ($key) {
case 'aliases': return $this->aliases;
case 'children': return $this->children;
case 'forced_as_may': return $this->forced_as_may;
case 'is_collective': return $this->is_collective;
case 'is_no_user_modification': return $this->is_no_user_modification;
case 'is_single_value': return $this->is_single_value;
case 'equality': return $this->equality;
case 'max_length': return $this->max_length;
case 'ordering': return $this->ordering;
case 'required_by_object_classes': return $this->required_by_object_classes;
case 'sub_str_rule': return $this->sub_str_rule;
case 'sup_attribute': return $this->sup_attribute;
case 'syntax': return $this->syntax;
case 'syntax_oid': return $this->syntax_oid;
case 'type': return $this->type;
case 'usage': return $this->usage;
case 'used_in_object_classes': return $this->used_in_object_classes;
default: return parent::__get($key);
}
}
/**
* Adds an attribute name to the alias array.
*
* @param string $alias The name of a new attribute to add to this attribute's list of aliases.
*/
public function addAlias(string $alias): void
{
$this->aliases->push($alias);
}
/**
* Children of this attribute type that inherit from this one
*
* @param string $child
* @return void
*/
public function addChild(string $child): void
{
$this->children->push($child);
}
/**
* Adds an objectClass name to this attribute's list of "required by" objectClasses,
* that is the list of objectClasses which must have this attribute.
*
* @param string $name The name of the objectClass to add.
*/
public function addRequiredByObjectClass(string $name): void
{
if ($this->required_by_object_classes->search($name) === FALSE)
$this->required_by_object_classes->push($name);
}
/**
* Adds an objectClass name to this attribute's list of "used in" objectClasses,
* that is the list of objectClasses which provide this attribute.
*
* @param string $name The name of the objectClass to add.
*/
public function addUsedInObjectClass(string $name): void
{
if ($this->used_in_object_classes->search($name) === FALSE)
$this->used_in_object_classes->push($name);
}
/**
* Gets the names of attributes that are an alias for this attribute (if any).
*
* @return Collection An array of names of attributes which alias this attribute or
* an empty array if no attribute aliases this object.
* @deprecated use class->aliases
*/
public function getAliases(): Collection
{
return $this->aliases;
}
/**
* Gets this attribute's equality string
*
* @return string
* @deprecated use $this->equality
*/
public function getEquality()
{
return $this->equality;
}
/**
* Gets whether this attribute is collective.
*
* @return boolean Returns TRUE if this attribute is collective and FALSE otherwise.
* @deprecated use $this->is_collective
*/
public function getIsCollective(): bool
{
return $this->is_collective;
}
/**
* Gets whether this attribute is not modifiable by users.
*
* @return boolean Returns TRUE if this attribute is not modifiable by users.
* @deprecated use $this->is_no_user_modification
*/
public function getIsNoUserModification(): bool
{
return $this->is_no_user_modification;
}
/**
* Gets whether this attribute is single-valued. If this attribute only supports single values, TRUE
* is returned. If this attribute supports multiple values, FALSE is returned.
*
* @return boolean Returns TRUE if this attribute is single-valued or FALSE otherwise.
* @deprecated use class->is_single_value
*/
public function getIsSingleValue(): bool
{
return $this->is_single_value;
}
/**
* Gets this attribute's the maximum length. If no maximum is defined by the LDAP server, NULL is returned.
*
* @return int The maximum length (in characters) of this attribute or NULL if no maximum is specified.
* @deprecated use $this->max_length;
*/
public function getMaxLength()
{
return $this->max_length;
}
/**
* Gets this attribute's ordering specification.
*
* @return string
* @deprecated use $this->ordering
*/
public function getOrdering(): string
{
return $this->ordering;
}
/**
* Gets the list of "required by" objectClasses, that is the list of objectClasses
* which provide must have attribute.
*
* @return array An array of names of objectclasses (strings) which provide this attribute
*/
public function getRequiredByObjectClasses() {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',9,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->required_by_object_classes);
return $this->required_by_object_classes;
}
/**
* Gets this attribute's substring matching specification
*
* @return string
* @deprecated use $this->sub_str_rule;
*/
public function getSubstr() {
return $this->sub_str_rule;
}
/**
* Gets this attribute's parent attribute (if any). If this attribute does not
* inherit from another attribute, NULL is returned.
*
* @return string
* @deprecated use $class->sup_attribute directly
*/
public function getSupAttribute() {
return $this->sup_attribute;
}
/**
* Gets this attribute's syntax OID. Differs from getSyntaxString() in that this
* function only returns the actual OID with any length specification removed.
* Ie, if the syntax string is "1.2.3.4{16}", this function only retruns
* "1.2.3.4".
*
* @return string The syntax OID string.
* @deprecated use $this->syntax_oid;
*/
public function getSyntaxOID()
{
return $this->syntax_oid;
}
/**
* Gets this attribute's raw syntax string (ie: "1.2.3.4{16}").
*
* @return string The raw syntax string
*/
public function getSyntaxString() {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',9,1,__FILE__,__LINE__,__METHOD__,$fargs,$this->syntax);
return $this->syntax;
}
/**
* Gets this attribute's type
*
* @return string The attribute's type.
* @deprecated use $this->type;
*/
public function getType()
{
return $this->type;
}
/**
* Gets this attribute's usage string as defined by the LDAP server
*
* @return string
* @deprecated use $this->usage
*/
public function getUsage()
{
return $this->usage;
}
/**
* Gets the list of "used in" objectClasses, that is the list of objectClasses
* which provide this attribute.
*
* @return Collection An array of names of objectclasses (strings) which provide this attribute
* @deprecated use $this->used_in_object_classes
*/
public function getUsedInObjectClasses(): Collection
{
return $this->used_in_object_classes;
}
/**
* Returns whether the specified attribute is an alias for this one (based on this attribute's alias list).
*
* @param string $attr_name The name of the attribute to check.
* @return boolean TRUE if the specified attribute is an alias for this one, or FALSE otherwise.
*/
public function isAliasFor($attr_name) {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',9,0,__FILE__,__LINE__,__METHOD__,$fargs);
foreach ($this->aliases as $alias_attr_name)
if (strcasecmp($alias_attr_name,$attr_name) == 0)
return TRUE;
return FALSE;
}
/**
* @return bool
* @deprecated use $this->forced_as_may
*/
public function isForceMay(): bool
{
return $this->forced_as_may;
}
/**
* Removes an attribute name from this attribute's alias array.
*
* @param string $alias The name of the attribute to remove.
*/
public function removeAlias(string $alias): void
{
if (($x=$this->aliases->search($alias)) !== FALSE)
$this->aliases->forget($x);
}
/**
* Given a list of object classes, determine if this is a required attribute
*
* @param Collection $oc List of objectclasses to compare.
* @return Collection
*/
public function required_by(Collection $oc): Collection
{
return $oc->diff($this->required_by_object_classes);
}
/**
* Sets this attribute's list of aliases.
*
* @param Collection $aliases The array of alias names (strings)
* @deprecated use $this->aliases =
*/
public function setAliases(Collection $aliases): void
{
$this->aliases = $aliases;
}
/**
* This function will mark this attribute as a forced MAY attribute
*/
public function setForceMay() {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',9,1,__FILE__,__LINE__,__METHOD__,$fargs);
$this->forced_as_may = TRUE;
}
/**
* Sets whether this attribute is single-valued.
*
* @param boolean $is
*/
public function setIsSingleValue(bool $is): void
{
$this->is_single_value = $is;
}
/**
* Sets this attribute's SUP attribute (ie, the attribute from which this attribute inherits).
*
* @param string $attr The name of the new parent (SUP) attribute
*/
public function setSupAttribute(string $attr): void
{
$this->sup_attribute = trim($attr);
}
/**
* Sets this attribute's type.
*
* @param string $type The new type.
*/
public function setType($type) {
if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
debug_log('Entered (%%)',9,1,__FILE__,__LINE__,__METHOD__,$fargs);
$this->type = $type;
}
}

View File

@ -0,0 +1,110 @@
<?php
namespace App\Classes\LDAP\Schema;
use App\Exceptions\InvalidUsage;
/**
* Generic parent class for all schema items.
*
* A schema item is an ObjectClass, an AttributeBype, a MatchingRule, or a Syntax.
* All schema items have at least two things in common: An OID and a Description.
*/
abstract class Base {
// Record the LDAP String
private string $line;
// The schema item's name.
protected ?string $name = NULL;
// The OID of this schema item.
protected string $oid;
# The description of this schema item.
protected ?string $description = NULL;
// Boolean value indicating whether this objectClass is obsolete
private bool $is_obsolete = FALSE;
public function __construct(string $line)
{
$this->line = $line;
}
public function __get(string $key): mixed
{
switch ($key) {
case 'description': return $this->description;
case 'is_obsolete': return $this->is_obsolete;
case 'line': return $this->line;
case 'name': return $this->name;
case 'name_lc': return strtolower($this->name);
case 'oid': return $this->oid;
default:
throw new InvalidUsage('Unknown key:'.$key);
}
}
/**
* @return string
* @deprecated replace with $class->description
*/
public function getDescription(): string
{
return $this->description;
}
/**
* Gets whether this item is flagged as obsolete by the LDAP server.
*
* @deprecated replace with $this->is_obsolete
*/
public function getIsObsolete(): bool
{
return $this->is_obsolete;
}
/**
* Return the objects name.
*
* @param boolean $lower Return the name in lower case (default)
* @return string The name
* @deprecated use object->name
*/
public function getName(bool $lower=TRUE): string
{
return $lower ? strtolower($this->name) : $this->name;
}
/**
* Return the objects name.
*
* @return string The name
* @deprecated use object->oid
*/
public function getOID(): string
{
return $this->oid;
}
public function setDescription(string $desc): void
{
$this->description = $desc;
}
/**
* Sets this attribute's name.
*
* @param string $name The new name to give this attribute.
*/
public function setName($name): void
{
$this->name = $name;
}
public function setOID(string $oid): void
{
$this->oid = $oid;
}
}

View File

@ -0,0 +1,79 @@
<?php
namespace App\Classes\LDAP\Schema;
use Illuminate\Support\Facades\Log;
/**
* Represents an LDAP Syntax
*
* @package phpLDAPadmin
* @subpackage Schema
*/
class LDAPSyntax extends Base {
// Is human readable?
private ?bool $is_not_human_readable = NULL;
// Binary transfer required?
private ?bool $binary_transfer_required = NULL;
/**
* Creates a new Syntax object from a raw LDAP syntax string.
*/
public function __construct(string $line) {
Log::debug(sprintf('Parsing LDAPSyntax [%s]',$line));
parent::__construct($line);
$strings = preg_split('/[\s,]+/',$line,-1,PREG_SPLIT_DELIM_CAPTURE);
for ($i=0; $i<count($strings); $i++) {
switch($strings[$i]) {
case '(':
case ')':
break;
case 'DESC':
do {
$this->description .= (strlen($this->description) ? ' ' : '').$strings[++$i];
} while (! preg_match("/\'$/s",$strings[$i]));
$this->description = preg_replace("/^\'(.*)\'$/",'$1',$this->description);
Log::debug(sprintf('- Case DESC returned (%s)',$this->description));
break;
case 'X-BINARY-TRANSFER-REQUIRED':
$this->binary_transfer_required = (str_replace("'",'',$strings[++$i]) === 'TRUE');
Log::debug(sprintf('- Case X-BINARY-TRANSFER-REQUIRED returned (%s)',$this->binary_transfer_required));
break;
case 'X-NOT-HUMAN-READABLE':
$this->is_not_human_readable = (str_replace("'",'',$strings[++$i]) === 'TRUE');
Log::debug(sprintf('- Case X-NOT-HUMAN-READABLE returned (%s)',$this->is_not_human_readable));
break;
default:
if (preg_match('/[\d\.]+/i',$strings[$i]) && ($i === 1)) {
$this->oid = $strings[$i];
Log::debug(sprintf('- Case default returned (%s)',$this->oid));
} elseif ($strings[$i])
Log::alert(sprintf('! Case default discovered a value NOT parsed (%s)',$strings[$i]),['line'=>$line]);
}
}
}
public function __get(string $key): mixed
{
switch ($key) {
case 'binary_transfer_required': return $this->binary_transfer_required;
case 'is_not_human_readable': return $this->is_not_human_readable;
default: return parent::__get($key);
}
}
}

View File

@ -0,0 +1,142 @@
<?php
namespace App\Classes\LDAP\Schema;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
/**
* Represents an LDAP MatchingRule
*
* @package phpLDAPadmin
* @subpackage Schema
*/
class MatchingRule extends Base {
// This rule's syntax OID
private ?string $syntax = NULL;
// An array of attribute names who use this MatchingRule
private Collection $used_by_attrs;
/**
* Creates a new MatchingRule object from a raw LDAP MatchingRule string.
*/
function __construct(string $line) {
Log::debug(sprintf('Parsing MatchingRule [%s]',$line));
parent::__construct($line);
$strings = preg_split('/[\s,]+/',$line,-1,PREG_SPLIT_DELIM_CAPTURE);
// Init
$this->used_by_attrs = collect();
for ($i=0; $i<count($strings); $i++) {
switch ($strings[$i]) {
case '(':
case ')':
break;
case 'NAME':
if ($strings[$i+1] != '(') {
do {
$this->name .= (strlen($this->name) ? ' ' : '').$strings[++$i];
} while (! preg_match("/\'$/s",$strings[$i]));
} else {
$i++;
do {
$this->name .= (strlen($this->name) ? ' ' : '').$strings[++$i];
} while (! preg_match("/\'$/s",$strings[$i]));
do {
$i++;
} while (! preg_match('/\)+\)?/',$strings[$i]));
}
$this->name = preg_replace("/^\'/",'',$this->name);
$this->name = preg_replace("/\'$/",'',$this->name);
Log::debug(sprintf(sprintf('- Case NAME returned (%s)',$this->name)));
break;
case 'DESC':
do {
$this->description .= (strlen($this->description) ? ' ' : '').$strings[++$i];
} while (! preg_match("/\'$/s",$strings[$i]));
$this->description = preg_replace("/^\'(.*)\'$/",'$1',$this->description);
Log::debug(sprintf('- Case DESC returned (%s)',$this->description));
break;
case 'OBSOLETE':
$this->is_obsolete = TRUE;
Log::debug(sprintf('- Case OBSOLETE returned (%s)',$this->is_obsolete));
break;
case 'SYNTAX':
$this->syntax = $strings[++$i];
Log::debug(sprintf('- Case SYNTAX returned (%s)',$this->syntax));
break;
default:
if (preg_match('/[\d\.]+/i',$strings[$i]) && ($i === 1)) {
$this->oid = $strings[$i];
Log::debug(sprintf('- Case default returned (%s)',$this->oid));
} elseif ($strings[$i])
Log::alert(sprintf('! Case default discovered a value NOT parsed (%s)',$strings[$i]),['line'=>$line]);
}
}
}
public function __get(string $key): mixed
{
switch ($key) {
case 'syntax': return $this->syntax;
case 'used_by_attrs': return $this->used_by_attrs;
default: return parent::__get($key);
}
}
/**
* Adds an attribute name to the list of attributes who use this MatchingRule
*/
public function addUsedByAttr(string $name): void
{
$name = trim($name);
if ($this->used_by_attrs->search($name) === FALSE)
$this->used_by_attrs->push($name);
}
/**
* Gets an array of attribute names (strings) which use this MatchingRule
*
* @return array The array of attribute names (strings).
* @deprecated use $this->used_by_attrs
*/
public function getUsedByAttrs()
{
return $this->used_by_attrs;
}
/**
* Sets the list of used_by_attrs to the array specified by $attrs;
*
* @param Collection $attrs The array of attribute names (strings) which use this MatchingRule
*/
public function setUsedByAttrs(Collection $attrs): void
{
$this->used_by_attrs = $attrs;
}
}

View File

@ -0,0 +1,99 @@
<?php
namespace App\Classes\LDAP\Schema;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
/**
* Represents an LDAP schema matchingRuleUse entry
*
* @package phpLDAPadmin
* @subpackage Schema
*/
class MatchingRuleUse extends Base {
// An array of attribute names who use this MatchingRule
private Collection $used_by_attrs;
function __construct(string $line) {
Log::debug(sprintf('Parsing MatchingRuleUse [%s]',$line));
parent::__construct($line);
$strings = preg_split('/[\s,]+/',$line,-1,PREG_SPLIT_DELIM_CAPTURE);
// Init
$this->used_by_attrs = collect();
for ($i=0; $i<count($strings); $i++) {
switch ($strings[$i]) {
case '(':
case ')':
break;
case 'NAME':
if ($strings[$i+1] != '(') {
do {
$this->name .= (strlen($this->name) ? ' ' : '').$strings[++$i];
} while (! preg_match("/\'$/s",$strings[$i]));
} else {
$i++;
do {
$this->name .= (strlen($this->name) ? ' ' : '').$strings[++$i];
} while (! preg_match("/\'$/s",$strings[$i]));
do {
$i++;
} while (! preg_match('/\)+\)?/',$strings[$i]));
}
$this->name = preg_replace("/^\'(.*)\'$/",'$1',$this->name);
Log::debug(sprintf(sprintf('- Case NAME returned (%s)',$this->name)));
break;
case 'APPLIES':
if ($strings[$i+1] != '(') {
// Has a single attribute name
$this->used_by_attrs = collect($strings[++$i]);
} else {
// Has multiple attribute names
while ($strings[++$i] != ')') {
$new_attr = $strings[++$i];
$new_attr = preg_replace("/^\'(.*)\'$/",'$1',$new_attr);
$this->used_by_attrs->push($new_attr);
}
}
Log::debug(sprintf('- Case APPLIES returned (%s)',$this->used_by_attrs->join(',')));
break;
default:
if (preg_match('/[\d\.]+/i',$strings[$i]) && ($i === 1)) {
$this->oid = $strings[$i];
Log::debug(sprintf('- Case default returned (%s)',$this->oid));
} elseif ($strings[$i])
Log::alert(sprintf('! Case default discovered a value NOT parsed (%s)',$strings[$i]),['line'=>$line]);
}
}
}
/**
* Gets an array of attribute names (strings) which use this MatchingRuleUse object.
*
* @return array The array of attribute names (strings).
* @deprecated use $this->used_by_attrs
*/
public function getUsedByAttrs()
{
return $this->used_by_attrs;
}
}

View File

@ -0,0 +1,526 @@
<?php
namespace App\Classes\LDAP\Schema;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use App\Classes\LDAP\Server;
use App\Exceptions\InvalidUsage;
use App\Ldap\Entry;
/**
* Represents an LDAP Schema objectClass
*
* @package phpLDAPadmin
* @subpackage Schema
*/
class ObjectClass extends Base {
// The server ID that this objectclass belongs to.
private Server $server;
// Array of objectClass names from which this objectClass inherits
private Collection $sup_classes;
// One of STRUCTURAL, ABSTRACT, or AUXILIARY
private int $type;
// Arrays of attribute names that this objectClass requires
private Collection $must_attrs;
// Arrays of attribute names that this objectClass allows, but does not require
private Collection $may_attrs;
// Arrays of attribute names that this objectClass has been forced to MAY attrs, due to configuration
private Collection $may_force;
// Array of objectClasses which inherit from this one
private Collection $child_objectclasses;
private bool $is_obsolete;
/* ObjectClass Types */
private const OC_STRUCTURAL = 0x01;
private const OC_ABSTRACT = 0x02;
private const OC_AUXILIARY = 0x03;
/**
* Creates a new ObjectClass object given a raw LDAP objectClass string.
*
* eg: ( 2.5.6.0 NAME 'top' DESC 'top of the superclass chain' ABSTRACT MUST objectClass )
*/
public function __construct(string $line,Server $server)
{
parent::__construct($line);
Log::debug(sprintf('Parsing ObjectClass [%s]',$line));
$strings = preg_split('/[\s,]+/',$line,-1,PREG_SPLIT_DELIM_CAPTURE);
// Init
$this->server = $server;
$this->may_attrs = collect();
$this->may_force = collect();
$this->must_attrs = collect();
$this->sup_classes = collect();
$this->child_objectclasses = collect();
for ($i=0; $i < count($strings); $i++) {
switch ($strings[$i]) {
case '(':
case ')':
break;
case 'NAME':
if ($strings[$i+1] != '(') {
do {
$this->name .= (strlen($this->name) ? ' ' : '').$strings[++$i];
} while (! preg_match('/\'$/s',$strings[$i]));
} else {
$i++;
do {
$this->name .= (strlen($this->name) ? ' ' : '').$strings[++$i];
} while (! preg_match('/\'$/s',$strings[$i]));
do {
$i++;
} while (! preg_match('/\)+\)?/',$strings[$i]));
}
$this->name = preg_replace("/^\'(.*)\'$/",'$1',$this->name);
Log::debug(sprintf(sprintf('- Case NAME returned (%s)',$this->name)));
break;
case 'DESC':
do {
$this->description .= (strlen($this->description) ? ' ' : '').$strings[++$i];
} while (! preg_match('/\'$/s',$strings[$i]));
$this->description = preg_replace("/^\'(.*)\'$/",'$1',$this->description);
Log::debug(sprintf('- Case DESC returned (%s)',$this->description));
break;
case 'OBSOLETE':
$this->is_obsolete = TRUE;
Log::debug(sprintf('- Case OBSOLETE returned (%s)',$this->is_obsolete));
break;
case 'SUP':
if ($strings[$i+1] != '(') {
$this->sup_classes->push(preg_replace("/'/",'',$strings[++$i]));
} else {
$i++;
do {
$i++;
if ($strings[$i] != '$')
$this->sup_classes->push(preg_replace("/'/",'',$strings[$i]));
} while (! preg_match('/\)+\)?/',$strings[$i+1]));
}
Log::debug(sprintf('- Case SUP returned (%s)',$this->sup_classes->join(',')));
break;
case 'ABSTRACT':
$this->type = self::OC_ABSTRACT;
Log::debug(sprintf('- Case ABSTRACT returned (%s)',$this->type));
break;
case 'STRUCTURAL':
$this->type = self::OC_STRUCTURAL;
Log::debug(sprintf('- Case STRUCTURAL returned (%s)',$this->type));
break;
case 'AUXILIARY':
$this->type = self::OC_AUXILIARY;
Log::debug(sprintf('- Case AUXILIARY returned (%s)',$this->type));
break;
case 'MUST':
$attrs = collect();
$i = $this->parseList(++$i,$strings,$attrs);
Log::debug(sprintf('= parseList returned %d (%s)',$i,$attrs->join(',')));
foreach ($attrs as $string) {
$attr = new ObjectClassAttribute($string,$this->name);
if ($server->isForceMay($attr->getName())) {
$this->may_force->push($attr);
$this->may_attrs->push($attr);
} else
$this->must_attrs->push($attr);
}
Log::debug(sprintf('- Case MUST returned (%s) (%s)',$this->must_attrs->join(','),$this->may_force->join(',')));
break;
case 'MAY':
$attrs = collect();
$i = $this->parseList(++$i,$strings,$attrs);
Log::debug(sprintf('parseList returned %d (%s)',$i,$attrs->join(',')));
foreach ($attrs as $string) {
$attr = new ObjectClassAttribute($string,$this->name);
$this->may_attrs->push($attr);
}
Log::debug(sprintf('- Case MAY returned (%s)',$this->may_attrs->join(',')));
break;
default:
if (preg_match('/[\d\.]+/i',$strings[$i]) && ($i === 1)) {
$this->oid = $strings[$i];
Log::debug(sprintf('- Case default returned (%s)',$this->oid));
} elseif ($strings[$i])
Log::alert(sprintf('! Case default discovered a value NOT parsed (%s)',$strings[$i]),['line'=>$line]);
}
}
}
public function __get(string $key): mixed
{
switch ($key) {
case 'sup':
return $this->sup_classes;
case 'type_name':
switch ($this->type) {
case self::OC_STRUCTURAL: return 'Structural';
case self::OC_ABSTRACT: return 'Abstract';
case self::OC_AUXILIARY: return 'Auxiliary';
default:
throw new InvalidUsage('Unknown ObjectClass Type: '.$this->type);
}
default: return parent::__get($key);
}
}
/**
* Adds an objectClass to the list of objectClasses that inherit
* from this objectClass.
*
* @param String $name The name of the objectClass to add
*/
public function addChildObjectClass(string $name): void
{
if ($this->child_objectclasses->search($name) === FALSE) {
$this->child_objectclasses->push($name);
}
}
/**
* Behaves identically to addMustAttrs, but it operates on the MAY
* attributes of this objectClass.
*
* @param array $attr An array of attribute names (strings) to add.
*/
private function addMayAttrs(array $attr): void
{
if (! is_array($attr) || ! count($attr))
return;
$this->may_attrs = $this->may_attrs->merge($attr)->unique();
}
/**
* Adds the specified array of attributes to this objectClass' list of
* MUST attributes. The resulting array of must attributes will contain
* unique members.
*
* @param array $attr An array of attribute names (strings) to add.
*/
private function addMustAttrs(array $attr): void
{
if (! is_array($attr) || ! count($attr))
return;
$this->must_attrs = $this->must_attrs->merge($attr)->unique();
}
/**
* @return Collection
* @deprecated use $this->may_force
*/
public function getForceMayAttrs(): Collection
{
return $this->may_force;
}
/**
* Gets an array of AttributeType objects that entries of this ObjectClass may define.
* This differs from getMayAttrNames in that it returns an array of AttributeType objects
*
* @param bool $parents Also get the may attrs of our parents.
* @return Collection The array of allowed AttributeType objects.
*
* @throws InvalidUsage
* @see getMustAttrNames
* @see getMustAttrs
* @see getMayAttrNames
* @see AttributeType
*/
public function getMayAttrs(bool $parents=FALSE): Collection
{
// If we dont need our parents, then we'll just return ours.
if (! $parents)
return $this->may_attrs->sortBy(function($item) { return strtolower($item->name.$item->source); });
$attrs = $this->may_attrs;
foreach ($this->getParents() as $object_class) {
$sc = $this->server->schema('objectclasses',$object_class);
$attrs = $attrs->merge($sc->getMayAttrs($parents));
}
// Remove any duplicates
$attrs = $attrs->unique(function($item) { return $item->name; });
// Return a sorted list
return $attrs->sortBy(function($item) { return strtolower($item->name.$item->source); });
}
/**
* Gets an array of attribute names (strings) that entries of this ObjectClass must define.
* This differs from getMayAttrs in that it returns an array of strings rather than
* array of AttributeType objects
*
* @param bool $parents An array of ObjectClass objects to use when traversing
* the inheritance tree. This presents some what of a bootstrapping problem
* as we must fetch all objectClasses to determine through inheritance which
* attributes this objectClass provides.
* @return Collection The array of allowed attribute names (strings).
*
* @throws InvalidUsage
* @see getMustAttrs
* @see getMayAttrs
* @see getMustAttrNames
*/
public function getMayAttrNames(bool $parents=FALSE): Collection
{
return $this->getMayAttrs($parents)->ppluck('name');
}
/**
* Gets an array of AttributeType objects that entries of this ObjectClass must define.
* This differs from getMustAttrNames in that it returns an array of AttributeType objects
*
* @param bool $parents Also get the must attrs of our parents.
* @return Collection The array of required AttributeType objects.
*
* @throws InvalidUsage
* @see getMustAttrNames
* @see getMayAttrs
* @see getMayAttrNames
*/
public function getMustAttrs(bool $parents=FALSE): Collection
{
// If we dont need our parents, then we'll just return ours.
if (! $parents)
return $this->must_attrs->sortBy(function($item) { return strtolower($item->name.$item->source); });
$attrs = $this->must_attrs;
foreach ($this->getParents() as $object_class) {
$sc = $this->server->schema('objectclasses',$object_class);
$attrs = $attrs->merge($sc->getMustAttrs($parents));
}
// Remove any duplicates
$attrs = $attrs->unique(function($item) { return $item->name; });
// Return a sorted list
return $attrs->sortBy(function($item) { return strtolower($item->name.$item->source); });
}
/**
* Gets an array of attribute names (strings) that entries of this ObjectClass must define.
* This differs from getMustAttrs in that it returns an array of strings rather than
* array of AttributeType objects
*
* @param bool $parents An array of ObjectClass objects to use when traversing
* the inheritance tree. This presents some what of a bootstrapping problem
* as we must fetch all objectClasses to determine through inheritance which
* attributes this objectClass provides.
* @return Collection The array of allowed attribute names (strings).
*
* @throws InvalidUsage
* @see getMustAttrs
* @see getMayAttrs
* @see getMayAttrNames
*/
public function getMustAttrNames(bool $parents=FALSE): Collection
{
return $this->getMustAttrs($parents)->ppluck('name');
}
/**
* This will return all our parent ObjectClass Objects
*/
public function getParents(): Collection
{
// If the only class is 'top', then we have no more parents
if (($this->sup_classes->count() === 1) && (strtolower($this->sup_classes->first()) === 'top'))
return collect();
$result = collect();
foreach ($this->sup_classes as $object_class) {
$result->push($object_class);
$oc = $this->server->schema('objectclasses',$object_class);
if ($oc)
$result = $result->merge($oc->getParents());
}
return $result;
}
/**
* Determine if an array is listed in the may_force attrs
*/
public function isForceMay(string $attr): bool
{
return $this->may_force->ppluck('name')->contains($attr);
}
/**
* Return if this objectClass is related to $oclass
*
* @param array $oclass ObjectClasses that this attribute may be related to
* @return bool
* @throws InvalidUsage
*/
public function isRelated(array $oclass): bool
{
// If I am in the array, we'll just return false
if (in_array_ignore_case($this->name,$oclass))
return FALSE;
foreach ($oclass as $object_class) {
$oc = $this->server->schema('objectclasses',$object_class);
if ($oc->isStructural() && in_array_ignore_case($this->name,$oc->getParents()))
return TRUE;
}
return FALSE;
}
public function isStructural(): bool
{
return $this->type === self::OC_STRUCTURAL;
}
/**
* Parse an LDAP schema list
*
* A list starts with a ( followed by a list of attributes separated by $ terminated by )
* The first token can therefore be a ( or a (NAME or a (NAME)
* The last token can therefore be a ) or NAME)
* The last token may be terminated by more than one bracket
*/
private function parseList(int $i,array $strings,Collection &$attrs): int
{
$string = $strings[$i];
if (! preg_match('/^\(/',$string)) {
// A bareword only - can be terminated by a ) if the last item
if (preg_match('/\)+$/',$string))
$string = preg_replace('/\)+$/','',$string);
$attrs->push($string);
} elseif (preg_match('/^\(.*\)$/',$string)) {
$string = preg_replace('/^\(/','',$string);
$string = preg_replace('/\)+$/','',$string);
$attrs->push($string);
} else {
// Handle the opening cases first
if ($string === '(') {
$i++;
} elseif (preg_match('/^\(./',$string)) {
$string = preg_replace('/^\(/','',$string);
$attrs->push($string);
$i++;
}
// Token is either a name, a $ or a ')'
// NAME can be terminated by one or more ')'
while (! preg_match('/\)+$/',$strings[$i])) {
$string = $strings[$i];
if ($string === '$') {
$i++;
continue;
}
if (preg_match('/\)$/',$string))
$string = preg_replace('/\)+$/','',$string);
else
$i++;
$attrs->push($string);
}
}
$attrs = $attrs->sort();
return $i;
}
/**
* Returns the array of objectClass names which inherit from this objectClass.
*
* @return Collection Names of objectClasses which inherit from this objectClass.
* @deprecated use $this->child_objectclasses
*/
public function getChildObjectClasses(): Collection
{
return $this->child_objectclasses;
}
/**
* Gets the objectClass names from which this objectClass inherits.
*
* @return array An array of objectClass names (strings)
* @deprecated use $this->sup_classes;
*/
public function getSupClasses() {
return $this->sup_classes;
}
/**
* Gets the type of this objectClass: STRUCTURAL, ABSTRACT, or AUXILIARY.
*
* @deprecated use $this->type_name
*/
public function getType()
{
return $this->type;
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace App\Classes\LDAP\Schema;
/**
* A simple class for representing AttributeTypes used only by the ObjectClass class.
*
* Users should never instantiate this class. It represents an attribute internal to
* an ObjectClass. If PHP supported inner-classes and variable permissions, this would
* be interior to class ObjectClass and flagged private. The reason this class is used
* and not the "real" class AttributeType is because this class supports the notion of
* a "source" objectClass, meaning that it keeps track of which objectClass originally
* specified it. This class is therefore used by the class ObjectClass to determine
* inheritance.
*/
class ObjectClassAttribute extends Base {
// This Attribute's root.
private string $source;
/**
* Creates a new ObjectClassAttribute with specified name and source objectClass.
*
* @param string $name the name of the new attribute.
* @param string $source the name of the ObjectClass which specifies this attribute.
*/
public function __construct($name,$source)
{
$this->name = $name;
$this->source = $source;
}
public function __get(string $key): mixed
{
switch ($key) {
case 'source':
return $this->source;
default: return parent::__get($key);
}
}
}

520
app/Classes/LDAP/Server.php Normal file
View File

@ -0,0 +1,520 @@
<?php
namespace App\Classes\LDAP;
use Carbon\Carbon;
use Exception;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Log;
use LdapRecord\LdapRecordException;
use LdapRecord\Models\Model;
use LdapRecord\Query\Collection as LDAPCollection;
use LdapRecord\Query\ObjectNotFoundException;
use App\Classes\LDAP\Schema\{AttributeType,Base,LDAPSyntax,MatchingRule,MatchingRuleUse,ObjectClass};
use App\Exceptions\InvalidUsage;
use App\Ldap\Entry;
class Server
{
// This servers schema objectclasses
private Collection $attributetypes;
private Collection $ldapsyntaxes;
private Collection $matchingrules;
private Collection $matchingruleuse;
private Collection $objectclasses;
// Valid items that can be fetched
public const schema_types = [
'objectclasses',
'attributetypes',
'ldapsyntaxes',
'matchingrules',
];
public function __get(string $key): mixed
{
switch ($key) {
case 'attributetypes': return $this->attributetypes;
case 'ldapsyntaxes': return $this->ldapsyntaxes;
case 'matchingrules': return $this->matchingrules;
case 'objectclasses': return $this->objectclasses;
default:
throw new Exception('Unknown key:'.$key);
}
}
/* STATIC METHODS */
/**
* Gets the root DN of the specified LDAPServer, or throws an exception if it
* can't find it.
*
* @param null $connection Return a collection of baseDNs
* @param bool $objects Return a collection of Entry Models
* @return Collection
* @throws ObjectNotFoundException
* @testedin GetBaseDNTest::testBaseDNExists();
*/
public static function baseDNs($connection=NULL,bool $objects=TRUE): Collection
{
$cachetime = Carbon::now()->addSeconds(Config::get('ldap.cache.time'));
try {
$base = self::rootDSE($connection,$cachetime);
/**
* LDAP Error Codes:
* https://ldap.com/ldap-result-code-reference/
* + success 0
* + operationsError 1
* + protocolError 2
* + timeLimitExceeded 3
* + sizeLimitExceeded 4
* + compareFalse 5
* + compareTrue 6
* + authMethodNotSupported 7
* + strongerAuthRequired 8
* + referral 10
* + adminLimitExceeded 11
* + unavailableCriticalExtension 12
* + confidentialityRequired 13
* + saslBindInProgress 14
* + noSuchAttribute 16
* + undefinedAttributeType 17
* + inappropriateMatching 18
* + constraintViolation 19
* + attributeOrValueExists 20
* + invalidAttributeSyntax 21
* + noSuchObject 32
* + aliasProblem 33
* + invalidDNSyntax 34
* + isLeaf 35
* + aliasDereferencingProblem 36
* + inappropriateAuthentication 48
* + invalidCredentials 49
* + insufficientAccessRights 50
* + busy 51
* + unavailable 52
* + unwillingToPerform 53
* + loopDetect 54
* + sortControlMissing 60
* + offsetRangeError 61
* + namingViolation 64
* + objectClassViolation 65
* + notAllowedOnNonLeaf 66
* + notAllowedOnRDN 67
* + entryAlreadyExists 68
* + objectClassModsProhibited 69
* + resultsTooLarge 70
* + affectsMultipleDSAs 71
* + virtualListViewError or controlError 76
* + other 80
* + serverDown 81
* + localError 82
* + encodingError 83
* + decodingError 84
* + timeout 85
* + authUnknown 86
* + filterError 87
* + userCanceled 88
* + paramError 89
* + noMemory 90
* + connectError 91
* + notSupported 92
* + controlNotFound 93
* + noResultsReturned 94
* + moreResultsToReturn 95
* + clientLoop 96
* + referralLimitExceeded 97
* + invalidResponse 100
* + ambiguousResponse 101
* + tlsNotSupported 112
* + intermediateResponse 113
* + unknownType 114
* + canceled 118
* + noSuchOperation 119
* + tooLate 120
* + cannotCancel 121
* + assertionFailed 122
* + authorizationDenied 123
* + e-syncRefreshRequired 4096
* + noOperation 16654
*
* LDAP Tag Codes:
* + A client bind operation 97
* + The entry for which you were searching 100
* + The result from a search operation 101
* + The result from a modify operation 103
* + The result from an add operation 105
* + The result from a delete operation 107
* + The result from a modify DN operation 109
* + The result from a compare operation 111
* + A search reference when the entry you perform your search on holds a referral to the entry you require.
* + Search references are expressed in terms of a referral.
* 115
* + A result from an extended operation 120
*/
// If we cannot get to our LDAP server we'll head straight to the error page
} catch (LdapRecordException $e) {
switch ($e->getDetailedError()->getErrorCode()) {
case 49:
abort(401,$e->getDetailedError()->getErrorMessage());
default:
abort(597,$e->getDetailedError()->getErrorMessage());
}
}
if (! $objects)
return collect($base->namingcontexts);
/**
* @note While we are caching our baseDNs, it seems if we have more than 1,
* our caching doesnt generate a hit on a subsequent call to this function (before the cache expires).
* IE: If we have 5 baseDNs, it takes 5 calls to this function to case them all.
* @todo Possibly a bug wtih ldaprecord, so need to investigate
*/
$result = collect();
foreach ($base->namingcontexts as $dn) {
$result->push((new Entry)->cache($cachetime)->findOrFail($dn));
}
return $result;
}
/**
* Obtain the rootDSE for the server, that gives us server information
*
* @param null $connection
* @return Entry|null
* @throws ObjectNotFoundException
* @testedin TranslateOidTest::testRootDSE();
*/
public static function rootDSE($connection=NULL,Carbon $cachetime=NULL): ?Model
{
$e = new Entry;
return Entry::on($connection ?? $e->getConnectionName())
->cache($cachetime)
->in(NULL)
->read()
->select(['+'])
->whereHas('objectclass')
->firstOrFail();
}
/**
* Get the Schema DN
*
* @param $connection
* @return string
* @throws ObjectNotFoundException
*/
public static function schemaDN($connection=NULL): string
{
$cachetime = Carbon::now()->addSeconds(Config::get('ldap.cache.time'));
return collect(self::rootDSE($connection,$cachetime)->subschemasubentry)->first();
}
/**
* Query the server for a DN and return its children and if those children have children.
*
* @param string $dn
* @return LDAPCollection|NULL
*/
public function children(string $dn): ?LDAPCollection
{
return ($x=(new Entry)
->query()
->cache(Carbon::now()->addSeconds(Config::get('ldap.cache.time')))
->select(['*','hassubordinates'])
->setDn($dn)
->listing()
->get()) ? $x : NULL;
}
/**
* Fetch a DN from the server
*
* @param string $dn
* @param array $attrs
* @return Entry|null
*/
public function fetch(string $dn,array $attrs=['*','+']): ?Entry
{
return ($x=(new Entry)
->query()
->cache(Carbon::now()->addSeconds(Config::get('ldap.cache.time')))
->select($attrs)
->find($dn)) ? $x : NULL;
}
/**
* This function determines if the specified attribute is contained in the force_may list
* as configured in config.php.
*
* @return boolean True if the specified attribute is configured to be force as a may attribute
*/
public function isForceMay($attr_name): bool
{
return in_array($attr_name,config('pla.force_may',[]));
}
/**
* Return the server's schema
*
* @param string $item Schema Item to Fetch
* @param string|null $key
* @return Collection|Base|NULL
* @throws InvalidUsage
*/
public function schema(string $item,string $key=NULL): Collection|Base|NULL
{
// Ensure our item to fetch is lower case
$item = strtolower($item);
if ($key)
$key = strtolower($key);
// This error message is not localized as only developers should ever see it
if (! in_array($item,self::schema_types))
throw new InvalidUsage('Invalid request to fetch schema: '.$item);
$result = Cache::remember('schema'.$item,config('ldap.cache.time'),function() use ($item) {
// First pass if we have already retrieved the schema item
switch ($item) {
case 'attributetypes':
if (isset($this->attributetypes))
return $this->attributetypes;
else
$this->attributetypes = collect();
break;
case 'ldapsyntaxes':
if (isset($this->ldapsyntaxes))
return $this->ldapsyntaxes;
else
$this->ldapsyntaxes = collect();
break;
case 'matchingrules':
if (isset($this->matchingrules))
return $this->matchingrules;
else
$this->matchingrules = collect();
break;
/*
case 'matchingruleuse':
if (isset($this->matchingruleuse))
return is_null($key) ? $this->matchingruleuse : $this->matchingruleuse->get($key);
else
$this->matchingruleuse = collect();
break;
*/
case 'objectclasses':
if (isset($this->objectclasses))
return $this->objectclasses;
else
$this->objectclasses = collect();
break;
// Shouldnt get here
default:
throw new InvalidUsage('Invalid request to fetch schema: '.$item);
}
// Try to get the schema DN from the specified entry.
$schema_dn = $this->schemaDN();
$schema = $this->fetch($schema_dn);
switch ($item) {
case 'attributetypes':
Log::debug('Attribute Types');
// build the array of attribueTypes
//$syntaxes = $this->SchemaSyntaxes($dn);
foreach ($schema->{$item} as $line) {
if (is_null($line) || ! strlen($line))
continue;
$o = new AttributeType($line);
$this->attributetypes->put($o->name_lc,$o);
/*
if (isset($syntaxes[$attr->getSyntaxOID()])) {
$syntax = $syntaxes[$attr->getSyntaxOID()];
$attr->setType($syntax->getDescription());
}
$this->attributetypes[$attr->getName()] = $attr;
*/
/**
* bug 856832: create an entry in the $attrs_oid array too. This
* will be a ref to the $attrs entry for maintenance and performance
* reasons
*/
//$attrs_oid[$attr->getOID()] = &$attrs[$attr->getName()];
}
// go back and add data from aliased attributeTypes
foreach ($this->attributetypes as $o) {
/* foreach of the attribute's aliases, create a new entry in the attrs array
* with its name set to the alias name, and all other data copied.*/
if ($o->aliases->count()) {
Log::debug(sprintf('\ Attribute [%s] has the following aliases [%s]',$o->name,$o->aliases->join(',')));
foreach ($o->aliases as $alias) {
$new_attr = clone $o;
$new_attr->setName($alias);
$new_attr->addAlias($o->name);
$new_attr->removeAlias($alias);
$this->attributetypes->put(strtolower($alias),$new_attr);
}
}
}
// Now go through and reference the parent/child relationships
foreach ($this->attributetypes as $o)
if ($o->sup_attribute) {
$parent = strtolower($o->sup_attribute);
if ($this->attributetypes->has($parent) !== FALSE)
$this->attributetypes[$parent]->addChild($o->name);
}
// go through any children and add details if the child doesnt have them (ie, cn inherits name)
// @todo This doesnt traverse children properly, so children of children may not get the settings they should
foreach ($this->attributetypes as $parent) {
foreach ($parent->children as $child) {
$child = strtolower($child);
/* only overwrite the child's SINGLE-VALUE property if the parent has it set, and the child doesnt
* (note: All LDAP attributes default to multi-value if not explicitly set SINGLE-VALUE) */
if (! is_null($parent->is_single_value) && is_null($this->attributetypes[$child]->is_single_value))
$this->attributetypes[$child]->setIsSingleValue($parent->is_single_value);
}
}
// Add the used in and required_by values.
foreach ($this->schema('objectclasses') as $object_class) {
$must_attrs = $object_class->getMustAttrNames();
$may_attrs = $object_class->getMayAttrNames();
$oclass_attrs = $must_attrs->merge($may_attrs)->unique();
// Add Used In.
foreach ($oclass_attrs as $attr_name)
if ($this->attributetypes->has(strtolower($attr_name)))
$this->attributetypes[strtolower($attr_name)]->addUsedInObjectClass($object_class->name);
// Add Required By.
foreach ($must_attrs as $attr_name)
if ($this->attributetypes->has(strtolower($attr_name)))
$this->attributetypes[strtolower($attr_name)]->addRequiredByObjectClass($object_class->name);
// Force May
foreach ($object_class->getForceMayAttrs() as $attr_name)
if ($this->attributetypes->has(strtolower($attr_name->name)))
$this->attributetypes[strtolower($attr_name->name)]->setForceMay();
}
return $this->attributetypes;
case 'ldapsyntaxes':
Log::debug('LDAP Syntaxes');
foreach ($schema->{$item} as $line) {
if (is_null($line) || ! strlen($line))
continue;
$o = new LDAPSyntax($line);
$this->ldapsyntaxes->put(strtolower($o->oid),$o);
}
return $this->ldapsyntaxes;
case 'matchingrules':
Log::debug('Matching Rules');
$this->matchingruleuse = collect();
foreach ($schema->{$item} as $line) {
if (is_null($line) || ! strlen($line))
continue;
$o = new MatchingRule($line);
$this->matchingrules->put($o->name_lc,$o);
}
/*
* For each MatchingRuleUse entry, add the attributes who use it to the
* MatchingRule in the $rules array.
*/
if ($schema->matchingruleuse) {
foreach ($schema->matchingruleuse as $line) {
if (is_null($line) || ! strlen($line))
continue;
$o = new MatchingRuleUse($line);
$this->matchingruleuse->put($o->name_lc,$o);
if ($this->matchingrules->has($o->name_lc) !== FALSE)
$this->matchingrules[$o->name_lc]->setUsedByAttrs($o->getUsedByAttrs());
}
} else {
/* No MatchingRuleUse entry in the subschema, so brute-forcing
* the reverse-map for the "$rule->getUsedByAttrs()" data.*/
foreach ($this->schema('attributetypes') as $attr) {
$rule_key = strtolower($attr->getEquality());
if ($this->matchingrules->has($rule_key) !== FALSE)
$this->matchingrules[$rule_key]->addUsedByAttr($attr->name);
}
}
return $this->matchingrules;
case 'objectclasses':
Log::debug('Object Classes');
foreach ($schema->{$item} as $line) {
if (is_null($line) || ! strlen($line))
continue;
$o = new ObjectClass($line,$this);
$this->objectclasses->put($o->name_lc,$o);
}
// Now go through and reference the parent/child relationships
foreach ($this->objectclasses as $o)
foreach ($o->getSupClasses() as $parent) {
$parent = strtolower($parent);
if ($this->objectclasses->has($parent) !== FALSE)
$this->objectclasses[$parent]->addChildObjectClass($o->name);
}
return $this->objectclasses;
}
});
return is_null($key) ? $result : $result->get($key);
}
public function schemaSyntaxName(string $oid): ?LDAPSyntax
{
return $this->schema('ldapsyntaxes',$oid);
}
}

41
app/Console/Kernel.php Normal file
View File

@ -0,0 +1,41 @@
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands = [
//
];
/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
// $schedule->command('inspire')->hourly();
}
/**
* Register the commands for the application.
*
* @return void
*/
protected function commands()
{
$this->load(__DIR__.'/Commands');
require base_path('routes/console.php');
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace App\Exceptions;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Throwable;
class Handler extends ExceptionHandler
{
/**
* A list of exception types with their corresponding custom log levels.
*
* @var array<class-string<\Throwable>, \Psr\Log\LogLevel::*>
*/
protected $levels = [
//
];
/**
* A list of the exception types that are not reported.
*
* @var array<int, class-string<\Throwable>>
*/
protected $dontReport = [
//
];
/**
* A list of the inputs that are never flashed to the session on validation exceptions.
*
* @var array<int, string>
*/
protected $dontFlash = [
'current_password',
'password',
'password_confirmation',
];
/**
* Register the exception handling callbacks for the application.
*
* @return void
*/
public function register()
{
$this->reportable(function (Throwable $e) {
//
});
}
}

View File

@ -0,0 +1,10 @@
<?php
namespace App\Exceptions;
use Exception;
class InvalidUsage extends Exception
{
//
}

View File

@ -0,0 +1,64 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Log;
use LdapRecord\Query\Collection;
use App\Classes\LDAP\Server;
class APIController extends Controller
{
/**
* @param Request $request
* @return Collection
*/
public function children(Request $request): Collection
{
$levels = $request->query('depth',1);
$dn = Crypt::decryptString($request->query('key'));
Log::debug(sprintf('%s: Query [%s] - Levels [%d]',__METHOD__,$dn,$levels));
return (config('server'))
->children($dn)
->transform(function($item) {
return [
'title'=>$item->getRdn(),
'item'=>Crypt::encryptString($item->getDn()),
'icon'=>$item->icon(),
'lazy'=>Arr::get($item->getAttribute('hassubordinates'),0) == 'TRUE',
'tooltip'=>$item->getDn(),
];
});
}
public function schema_view(Request $request)
{
$server = new Server;
switch($request->type) {
case 'objectclasses':
return view('frames.schema.objectclasses')
->with('objectclasses',$server->schema('objectclasses')->sortBy(function($item) { return strtolower($item->name); }));
case 'attributetypes':
return view('frames.schema.attributetypes')
->with('server',$server)
->with('attributetypes',$server->schema('attributetypes')->sortBy(function($item) { return strtolower($item->name); }));
case 'ldapsyntaxes':
return view('frames.schema.ldapsyntaxes')
->with('ldapsyntaxes',$server->schema('ldapsyntaxes')->sortBy(function($item) { return strtolower($item->description); }));
case 'matchingrules':
return view('frames.schema.matchingrules')
->with('matchingrules',$server->schema('matchingrules')->sortBy(function($item) { return strtolower($item->name); }));
default:
abort(404);
}
}
}

View File

@ -0,0 +1,94 @@
<?php
namespace App\Http\Controllers\Auth;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cookie;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
class LoginController extends Controller
{
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* @var string
*/
protected $redirectTo = RouteServiceProvider::HOME;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
}
protected function credentials(Request $request): array
{
return [
'mail' => $request->get('email'),
'password' => $request->get('password'),
];
}
/**
* We need to delete our encrypted username/password cookies
*
* @note The rest of this function is the same as a normal laravel logout as in AuthenticatesUsers::class
* @param Request $request
* @return \Illuminate\Contracts\Foundation\Application|JsonResponse|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|mixed
*/
public function logout(Request $request)
{
// Delete our LDAP authentication cookies
Cookie::queue(Cookie::forget('username_encrypt'));
Cookie::queue(Cookie::forget('password_encrypt'));
$this->guard()->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
if ($response = $this->loggedOut($request)) {
return $response;
}
return $request->wantsJson()
? new JsonResponse([], 204)
: redirect('/');
}
/**
*
* Show our themed login page
*/
public function showLoginForm()
{
$login_note = '';
if (file_exists('login_note.txt'))
$login_note = file_get_contents('login_note.txt');
return view('architect::auth.login')->with('login_note',$login_note);
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
}

View File

@ -0,0 +1,136 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\File;
use LdapRecord\Query\ObjectNotFoundException;
use App\Classes\LDAP\Server;
use App\Exceptions\InvalidUsage;
class HomeController extends Controller
{
/**
* Debug Page
*
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
*/
public function debug()
{
return view('debug');
}
/**
* Application home page
*/
public function home()
{
$base = Server::baseDNs() ?: collect();
return view('home')
->with('server',config('ldap.connections.default.name'))
->with('bases',$base->transform(function($item) {
return [
'title'=>$item->getRdn(),
'item'=>Crypt::encryptString($item->getDn()),
'lazy'=>TRUE,
'icon'=>'fa-fw fas fa-sitemap',
'tooltip'=>$item->getDn(),
];
}));
}
/**
* LDAP Server INFO
*
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
* @throws ObjectNotFoundException
*/
public function info()
{
// Load our attributes
$s = config('server');
$s->schema('objectclasses');
$s->schema('attributetypes');
return view('frames.info')
->with('s',$s);
}
/**
* Render a specific DN
*
* @param Request $request
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
*/
public function dn_frame(Request $request)
{
$dn = Crypt::decryptString($request->post('key'));
return view('frames.dn')
->with('o',config('server')->fetch($dn))
->with('dn',$dn);
}
/**
* Show the Schema Viewer
*
* @note Our route will validate that types are valid.
* @param Request $request
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
* @throws InvalidUsage
*/
public function schema_frame(Request $request)
{
$s = config('server');
// If an invalid key, we'll 404
if ($request->type && $request->key && ($s->schema($request->type)->has($request->key) === FALSE))
abort(404);
return view('frames.schema')
->with('type',$request->type)
->with('key',$request->key);
}
/**
* Sort the attributes
*
* @param Collection $attrs
* @return Collection
*/
private function sortAttrs(Collection $attrs): Collection
{
return $attrs->sortKeys();
}
/**
* Return the image for the logged in user or anonymous
*
* @param Request $request
* @return mixed
*/
public function user_image(Request $request)
{
$image = NULL;
$content = NULL;
if (Auth::check()) {
$image = Arr::get(Auth::user()->getAttribute('jpegphoto'),0);
$content = 'image/jpeg';
}
if (! $image) {
$image = File::get('../resources/images/user-secret-solid.svg');
$content = 'image/svg+xml';
}
return response($image)
->header('Content-Type',$content);
}
}

82
app/Http/Kernel.php Normal file
View File

@ -0,0 +1,82 @@
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
use App\Http\Middleware\{ApplicationSession,CheckUpdate,SwapinAuthUser};
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* @var array
*/
protected $middleware = [
// \App\Http\Middleware\TrustHosts::class,
\App\Http\Middleware\TrustProxies::class,
\Fruitcake\Cors\HandleCors::class,
\App\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
];
/**
* The application's route middleware groups.
*
* @var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
SwapinAuthUser::class,
\Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
ApplicationSession::class,
CheckUpdate::class,
],
'api' => [
'throttle:60,1',
\App\Http\Middleware\EncryptCookies::class,
SwapinAuthUser::class,
ApplicationSession::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* @var array
*/
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'localize' => \Mcamara\LaravelLocalization\Middleware\LaravelLocalizationRoutes::class,
'localizationRedirect' => \Mcamara\LaravelLocalization\Middleware\LaravelLocalizationRedirectFilter::class,
'localeSessionRedirect' => \Mcamara\LaravelLocalization\Middleware\LocaleSessionRedirect::class,
'localeCookieRedirect' => \Mcamara\LaravelLocalization\Middleware\LocaleCookieRedirect::class,
'localeViewPath' => \Mcamara\LaravelLocalization\Middleware\LaravelLocalizationViewPath::class
];
}

View File

@ -0,0 +1,29 @@
<?php
namespace App\Http\Middleware;
use App\Classes\LDAP\Server;
use App\Ldap\User;
use Closure;
/**
* This sets up our application session with any required values, ultimately for cache optimisation reasons
*/
class ApplicationSession
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request,Closure $next)
{
view()->share('user', auth()->user() ?: new User);
\Config::set('server',new Server);
return $next($request);
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
class Authenticate extends Middleware
{
/**
* Get the path the user should be redirected to when they are not authenticated.
*
* @param \Illuminate\Http\Request $request
* @return string|null
*/
protected function redirectTo($request)
{
if (! $request->expectsJson()) {
return route('login');
}
}
}

View File

@ -0,0 +1,17 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode as Middleware;
class CheckForMaintenanceMode extends Middleware
{
/**
* The URIs that should be reachable while maintenance mode is enabled.
*
* @var array
*/
protected $except = [
//
];
}

View File

@ -0,0 +1,55 @@
<?php
namespace App\Http\Middleware;
use Closure;
use GuzzleHttp\Client;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
class CheckUpdate
{
private const UPDATE_SERVER = 'https://version.phpldapadmin.org';
private const UPDATE_TIME = 60*60*6;
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
\Config::set('update_available',Cache::get('upstream_version'));
return $next($request);
}
/**
* Handle tasks after the response has been sent to the browser.
*
* @return void
*/
public function terminate()
{
Cache::remember('upstream_version',self::UPDATE_TIME,function() {
// CURL call to URL to see if there is a new version
Log::debug(sprintf('CU_:Checking for updates for [%s]',config('app.version')));
$client = new Client;
$response = $client->request('POST',sprintf('%s/%s',self::UPDATE_SERVER,strtolower(config('app.version'))));
if ($response->getStatusCode() === 200) {
$result = json_decode($response->getBody());
Log::debug(sprintf('CU_:- Update server returned...'),['update'=>$result]);
return $result;
}
return NULL;
});
}
}

View File

@ -0,0 +1,17 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;
class EncryptCookies extends Middleware
{
/**
* The names of the cookies that should not be encrypted.
*
* @var array
*/
protected $except = [
//
];
}

View File

@ -0,0 +1,27 @@
<?php
namespace App\Http\Middleware;
use App\Providers\RouteServiceProvider;
use Closure;
use Illuminate\Support\Facades\Auth;
class RedirectIfAuthenticated
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string|null $guard
* @return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
return redirect(RouteServiceProvider::HOME);
}
return $next($request);
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Cookie;
// use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Log;
// use Illuminate\Support\Facades\Session;
use LdapRecord\Container;
use App\Ldap\Connection;
class SwapinAuthUser
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
$key = config('ldap.default');
/*
// Rebuild our connection with the authenticated user.
if (Session::has('username_encrypt') && Session::has('password_encrypt')) {
Config::set('ldap.connections.'.$key.'.username',Crypt::decryptString(Session::get('username_encrypt')));
Config::set('ldap.connections.'.$key.'.password',Crypt::decryptString(Session::get('password_encrypt')));
} else
*/
if (Cookie::has('username_encrypt') && Cookie::has('password_encrypt')) {
Config::set('ldap.connections.'.$key.'.username',Cookie::get('username_encrypt'));
Config::set('ldap.connections.'.$key.'.password',Cookie::get('password_encrypt'));
Log::debug('Swapping out configured LDAP credentials with the user\'s cookie.');
}
// We need to override our Connection object so that we can store and retrieve the logged in user and swap out the credentials to use them.
Container::getInstance()->addConnection(new Connection(config('ldap.connections.'.$key)),$key);
return $next($request);
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\TrimStrings as Middleware;
class TrimStrings extends Middleware
{
/**
* The names of the attributes that should not be trimmed.
*
* @var array
*/
protected $except = [
'password',
'password_confirmation',
];
}

View File

@ -0,0 +1,20 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Http\Middleware\TrustHosts as Middleware;
class TrustHosts extends Middleware
{
/**
* Get the host patterns that should be trusted.
*
* @return array
*/
public function hosts()
{
return [
$this->allSubdomainsOfApplicationUrl(),
];
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Http\Middleware\TrustProxies as Middleware;
use Illuminate\Http\Request;
class TrustProxies extends Middleware
{
/**
* The trusted proxies for this application.
*
* @var array<int, string>|string|null
*/
protected $proxies;
/**
* The headers that should be used to detect proxies.
*
* @var int
*/
protected $headers =
Request::HEADER_X_FORWARDED_FOR |
Request::HEADER_X_FORWARDED_HOST |
Request::HEADER_X_FORWARDED_PORT |
Request::HEADER_X_FORWARDED_PROTO |
Request::HEADER_X_FORWARDED_AWS_ELB;
}

View File

@ -0,0 +1,17 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
{
/**
* The URIs that should be excluded from CSRF verification.
*
* @var array
*/
protected $except = [
//
];
}

20
app/Ldap/Connection.php Normal file
View File

@ -0,0 +1,20 @@
<?php
namespace App\Ldap;
use LdapRecord\Connection as ConnectionBase;
use LdapRecord\LdapInterface;
class Connection extends ConnectionBase
{
public function __construct($config = [], LdapInterface $ldap = null)
{
parent::__construct($config,$ldap);
// We need to override this so that we use our own Guard, that stores the users credentials in the session
$this->authGuardResolver = function () {
return new Guard($this->ldap, $this->configuration);
};
}
}

172
app/Ldap/Entry.php Normal file
View File

@ -0,0 +1,172 @@
<?php
namespace App\Ldap;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use LdapRecord\Models\Model;
use App\Classes\LDAP\Attribute;
use App\Classes\LDAP\Attribute\Factory;
class Entry extends Model
{
/* OVERRIDES */
public function getAttributes(): array
{
static $result = NULL;
if (is_null($result)) {
$result = collect();
foreach (parent::getAttributes() as $attribute => $value) {
$o = Factory::create($attribute,$value);
// Set the rdn flag
if (preg_match('/^'.$attribute.'=/i',$this->dn))
$o->setRDN();
// Set required flag
$o->required_by(collect($this->getAttribute('objectclass')));
$result->put($attribute,$o);
}
$sort = collect(config('ldap.attr_display_order',[]))->transform(function($item) { return strtolower($item); });
// Order the attributes
$result = $result->sortBy([function(Attribute $a,Attribute $b) use ($sort): int {
if ($a === $b)
return 0;
// Check if $a/$b are in the configuration to be sorted first, if so get it's key
$a_key = $sort->search($a->name_lc);
$b_key = $sort->search($b->name_lc);
// If the keys were not in the sort list, set the key to be the count of elements (ie: so it is last to be sorted)
if ($a_key === FALSE)
$a_key = $sort->count()+1;
if ($b_key === FALSE)
$b_key = $sort->count()+1;
// Case where neither $a, nor $b are in ldap.attr_display_order, $a_key = $b_key = one greater than num elements.
// So we sort them alphabetically
if ($a_key === $b_key)
return strcasecmp($a->name,$b->name);
// Case where at least one attribute or its friendly name is in $attrs_display_order
// return -1 if $a before $b in $attrs_display_order
return ($a_key < $b_key) ? -1 : 1;
} ])->toArray();
}
return $result;
}
/* ATTRIBUTES */
/**
* Return a key to use for sorting
*
* @todo This should be the DN in reverse order
* @return string
*/
public function getSortKeyAttribute(): string
{
return $this->getDn();
}
/* METHODS */
/**
* Return a list of LDAP internal attributes
*
* @return Collection
*/
public function getInternalAttributes(): Collection
{
return collect($this->getAttributes())->filter(function($item) {
return $item->is_internal;
});
}
/**
* Return this list of user attributes
*
* @return Collection
*/
public function getVisibleAttributes(): Collection
{
return collect($this->getAttributes())->filter(function($item) {
return ! $item->is_internal;
});
}
/**
* Return an icon for a DN based on objectClass
*
* @return string
*/
public function icon(): string
{
$objectclasses = array_map('strtolower',$this->objectclass);
// Return icon based upon objectClass value
if (in_array('person',$objectclasses) ||
in_array('organizationalperson',$objectclasses) ||
in_array('inetorgperson',$objectclasses) ||
in_array('account',$objectclasses) ||
in_array('posixaccount',$objectclasses))
return 'fas fa-user';
elseif (in_array('organization',$objectclasses))
return 'fas fa-university';
elseif (in_array('organizationalunit',$objectclasses))
return 'fas fa-object-group';
elseif (in_array('posixgroup',$objectclasses) ||
in_array('groupofnames',$objectclasses) ||
in_array('groupofuniquenames',$objectclasses) ||
in_array('group',$objectclasses))
return 'fas fa-users';
elseif (in_array('dcobject',$objectclasses) ||
in_array('domainrelatedobject',$objectclasses) ||
in_array('domain',$objectclasses) ||
in_array('builtindomain',$objectclasses))
return 'fas fa-network-wired';
elseif (in_array('alias',$objectclasses))
return 'fas fa-theater-masks';
elseif (in_array('country',$objectclasses))
return sprintf('flag %s',strtolower(Arr::get($this->c,0)));
elseif (in_array('device',$objectclasses))
return 'fas fa-mobile-alt';
elseif (in_array('document',$objectclasses))
return 'fas fa-file-alt';
elseif (in_array('iphost',$objectclasses))
return 'fas fa-wifi';
elseif (in_array('room',$objectclasses))
return 'fas fa-door-open';
elseif (in_array('server',$objectclasses))
return 'fas fa-server';
elseif (in_array('openldaprootdse',$objectclasses))
return 'fas fa-info';
// Default
return 'fa-fw fas fa-cog';
}
}

29
app/Ldap/Guard.php Normal file
View File

@ -0,0 +1,29 @@
<?php
namespace App\Ldap;
use Illuminate\Support\Facades\Cookie;
// use Illuminate\Support\Facades\Crypt;
use LdapRecord\Auth\Guard as GuardBase;
class Guard extends GuardBase
{
public function attempt($username, $password, $stayBound = false)
{
if ($result = parent::attempt($username,$password,$stayBound)) {
/*
* We can either use our session or cookies to store this. If using session, then Http/Kernel needs to be
* updated to start a session for API calls.
// We need to store our password so that we can swap in the user in during SwapinAuthUser::class middleware
request()->session()->put('username_encrypt',Crypt::encryptString($username));
request()->session()->put('password_encrypt',Crypt::encryptString($password));
*/
// For our API calls, we store the cookie - which our cookies are already encrypted
Cookie::queue('username_encrypt',$username);
Cookie::queue('password_encrypt',$password);
}
return $result;
}
}

View File

@ -0,0 +1,75 @@
<?php
namespace App\Ldap;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Support\Str;
use LdapRecord\Laravel\Events\Auth\DiscoveredWithCredentials;
use LdapRecord\Laravel\LdapUserRepository as LdapUserRepositoryBase;
use LdapRecord\Models\Model;
use App\Classes\LDAP\Server;
class LdapUserRepository extends LdapUserRepositoryBase
{
/**
* Retrieve a user by the given credentials.
*
* @param array $credentials
*
* @return Model|null
* @throws \LdapRecord\Query\ObjectNotFoundException
*/
public function findByCredentials(array $credentials = []): ?Model
{
if (empty($credentials)) {
return NULL;
}
// Look for a user using all our baseDNs
foreach (Server::baseDNs() as $base) {
$query = $this->query()->setBaseDn($base);
foreach ($credentials as $key => $value) {
if (Str::contains($key, $this->bypassCredentialKeys)) {
continue;
}
if (is_array($value) || $value instanceof Arrayable) {
$query->whereIn($key, $value);
} else {
$query->where($key, $value);
}
}
if (! is_null($user = $query->first())) {
event(new DiscoveredWithCredentials($user));
return $user;
}
}
return NULL;
}
/**
* Get a user by their object GUID.
*
* @param string $guid
*
* @return Model|null
* @throws \LdapRecord\Query\ObjectNotFoundException
*/
public function findByGuid($guid): ?Model
{
// Look for a user using all our baseDNs
foreach (Server::baseDNs() as $base) {
$user = $this->query()->setBaseDn($base)->findByGuid($guid);
if ($user)
return $user;
}
return NULL;
}
}

27
app/Ldap/User.php Normal file
View File

@ -0,0 +1,27 @@
<?php
namespace App\Ldap;
use Laravel\Passport\HasApiTokens;
use LdapRecord\Models\OpenLDAP\User as Model;
class User extends Model
{
use HasApiTokens;
/**
* The object classes of the LDAP model.
*
* @var array
*/
public static $objectClasses = [
'posixAccount',
];
/* METHODS */
public function getDn(): string
{
return $this->exists ? parent::getDn() : 'Anonymous';
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace App\Providers;
use Illuminate\Support\Collection;
use Illuminate\Support\ServiceProvider;
use LdapRecord\Configuration\DomainConfiguration;
use LdapRecord\Laravel\LdapRecord;
use App\Ldap\LdapUserRepository;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
// Add a new option available to be set in the configuration:
DomainConfiguration::extend('name', $default = null);
// Use our LdapUserRepository to support multiple baseDN querying
LdapRecord::locateUsersUsing(LdapUserRepository::class);
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
$this->loadViewsFrom(__DIR__.'/../../resources/themes/architect/views/','architect');
// Enable pluck on collections to work on private values
Collection::macro('ppluck', function ($attr) {
return $this->map(function (object $item) use ($attr) {
return $item->{$attr};
})->values();
});
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\Providers;
// use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* The model to policy mappings for the application.
*
* @var array<class-string, class-string>
*/
protected $policies = [
// 'App\Models\Model' => 'App\Policies\ModelPolicy',
];
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
//
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Broadcast;
use Illuminate\Support\ServiceProvider;
class BroadcastServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Broadcast::routes();
require base_path('routes/channels.php');
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\Providers;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [];
/**
* Register any events for your application.
*
* @return void
*/
public function boot()
{
parent::boot();
//
}
}

View File

@ -0,0 +1,52 @@
<?php
namespace App\Providers;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Facades\Route;
class RouteServiceProvider extends ServiceProvider
{
/**
* The path to the "home" route for your application.
*
* Typically, users are redirected here after authentication.
*
* @var string
*/
public const HOME = '/';
/**
* Define your route model bindings, pattern filters, and other route configuration.
*
* @return void
*/
public function boot()
{
$this->configureRateLimiting();
$this->routes(function () {
Route::middleware('api')
->prefix('api')
->group(base_path('routes/api.php'));
Route::middleware('web')
->group(base_path('routes/web.php'));
});
}
/**
* Configure the rate limiters for the application.
*
* @return void
*/
protected function configureRateLimiting()
{
RateLimiter::for('api', function (Request $request) {
return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
});
}
}

53
artisan Executable file
View File

@ -0,0 +1,53 @@
#!/usr/bin/env php
<?php
define('LARAVEL_START', microtime(true));
/*
|--------------------------------------------------------------------------
| Register The Auto Loader
|--------------------------------------------------------------------------
|
| Composer provides a convenient, automatically generated class loader
| for our application. We just need to utilize it! We'll require it
| into the script here so that we do not have to worry about the
| loading of any of our classes manually. It's great to relax.
|
*/
require __DIR__.'/vendor/autoload.php';
$app = require_once __DIR__.'/bootstrap/app.php';
/*
|--------------------------------------------------------------------------
| Run The Artisan Application
|--------------------------------------------------------------------------
|
| When we run the console application, the current CLI command will be
| executed in this console and the response sent back to a terminal
| or another output device for the developers. Here goes nothing!
|
*/
$kernel = $app->make(Illuminate\Contracts\Console\Kernel::class);
$status = $kernel->handle(
$input = new Symfony\Component\Console\Input\ArgvInput,
new Symfony\Component\Console\Output\ConsoleOutput
);
/*
|--------------------------------------------------------------------------
| Shutdown The Application
|--------------------------------------------------------------------------
|
| Once Artisan has finished running, we will fire off the shutdown events
| so that any final work may be done by the application before we shut
| down the process. This is the last thing to happen to the request.
|
*/
$kernel->terminate($input, $status);
exit($status);

55
bootstrap/app.php Normal file
View File

@ -0,0 +1,55 @@
<?php
/*
|--------------------------------------------------------------------------
| Create The Application
|--------------------------------------------------------------------------
|
| The first thing we will do is create a new Laravel application instance
| which serves as the "glue" for all the components of Laravel, and is
| the IoC container for the system binding all of the various parts.
|
*/
$app = new Illuminate\Foundation\Application(
$_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);
/*
|--------------------------------------------------------------------------
| Bind Important Interfaces
|--------------------------------------------------------------------------
|
| Next, we need to bind some important interfaces into the container so
| we will be able to resolve them when needed. The kernels serve the
| incoming requests to this application from both the web and CLI.
|
*/
$app->singleton(
Illuminate\Contracts\Http\Kernel::class,
App\Http\Kernel::class
);
$app->singleton(
Illuminate\Contracts\Console\Kernel::class,
App\Console\Kernel::class
);
$app->singleton(
Illuminate\Contracts\Debug\ExceptionHandler::class,
App\Exceptions\Handler::class
);
/*
|--------------------------------------------------------------------------
| Return The Application
|--------------------------------------------------------------------------
|
| This script returns the application instance. The instance is given to
| the calling script so we can separate the building of the instances
| from the actual running of the application and sending responses.
|
*/
return $app;

2
bootstrap/cache/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore

67
composer.json Normal file
View File

@ -0,0 +1,67 @@
{
"name": "laravel/laravel",
"type": "project",
"description": "The Laravel Framework.",
"keywords": ["framework","laravel"],
"license": "MIT",
"require": {
"php": "^8.0.2",
"directorytree/ldaprecord-laravel": "^2",
"fideloper/proxy": "^4.4",
"fruitcake/laravel-cors": "^2.0",
"guzzlehttp/guzzle": "^7.2",
"laravel/framework": "^9.19",
"laravel/passport": "^10.1",
"laravel/ui": "^3.2",
"mcamara/laravel-localization": "^1.7"
},
"require-dev": {
"barryvdh/laravel-debugbar": "^3.5",
"fakerphp/faker": "^1.9.1",
"mockery/mockery": "^1.4.4",
"nunomaduro/collision": "^6.1",
"phpunit/phpunit": "^9.5.10"
},
"autoload": {
"psr-4": {
"App\\": "app/",
"Database\\Factories\\": "database/factories/",
"Database\\Seeders\\": "database/seeders/"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
}
},
"repositories": [
{
"type": "vcs",
"url": "https://dev.leenooks.net/leenooks/laravel"
}
],
"scripts": {
"post-autoload-dump": [
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
"@php artisan package:discover --ansi"
],
"post-root-package-install": [
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
],
"post-create-project-cmd": [
"@php artisan key:generate --ansi"
]
},
"extra": {
"laravel": {
"dont-discover": []
}
},
"config": {
"optimize-autoloader": true,
"preferred-install": "dist",
"sort-packages": true
},
"minimum-stability": "stable",
"prefer-stable": true
}

8966
composer.lock generated Normal file

File diff suppressed because it is too large Load Diff

203
config/app.php Normal file
View File

@ -0,0 +1,203 @@
<?php
use Illuminate\Support\Facades\Facade;
return [
/*
|--------------------------------------------------------------------------
| Application Name
|--------------------------------------------------------------------------
|
| This value is the name of your application. This value is used when the
| framework needs to place the application's name in a notification or
| any other location as required by the application or its packages.
|
*/
'name' => 'PLA',
'name_html_long' => '<b>php</b>LDAPadmin',
'version' => (trim(file_get_contents(__DIR__.'/../public/VERSION')) ?? 'UNKNOWN').'-'.(trim(file_get_contents(__DIR__.'/../VERSION')) ?? 'UNKNOWN'),
/*
|--------------------------------------------------------------------------
| Application Environment
|--------------------------------------------------------------------------
|
| This value determines the "environment" your application is currently
| running in. This may determine how you prefer to configure various
| services the application utilizes. Set this in your ".env" file.
|
*/
'env' => env('APP_ENV', 'production'),
/*
|--------------------------------------------------------------------------
| Application Debug Mode
|--------------------------------------------------------------------------
|
| When your application is in debug mode, detailed error messages with
| stack traces will be shown on every error that occurs within your
| application. If disabled, a simple generic error page is shown.
|
*/
'debug' => (bool) env('APP_DEBUG', false),
/*
|--------------------------------------------------------------------------
| Application URL
|--------------------------------------------------------------------------
|
| This URL is used by the console to properly generate URLs when using
| the Artisan command line tool. You should set this to the root of
| your application so that it is used when running Artisan tasks.
|
*/
'url' => env('APP_URL', 'http://localhost'),
'asset_url' => env('ASSET_URL', null),
/*
|--------------------------------------------------------------------------
| Application Timezone
|--------------------------------------------------------------------------
|
| Here you may specify the default timezone for your application, which
| will be used by the PHP date and date-time functions. We have gone
| ahead and set this to a sensible default for you out of the box.
|
*/
'timezone' => 'UTC',
/*
|--------------------------------------------------------------------------
| Application Locale Configuration
|--------------------------------------------------------------------------
|
| The application locale determines the default locale that will be used
| by the translation service provider. You are free to set this value
| to any of the locales which will be supported by the application.
|
*/
'locale' => 'en',
/*
|--------------------------------------------------------------------------
| Application Fallback Locale
|--------------------------------------------------------------------------
|
| The fallback locale determines the locale to use when the current one
| is not available. You may change the value to correspond to any of
| the language folders that are provided through your application.
|
*/
'fallback_locale' => 'en',
/*
|--------------------------------------------------------------------------
| Faker Locale
|--------------------------------------------------------------------------
|
| This locale will be used by the Faker PHP library when generating fake
| data for your database seeds. For example, this will be used to get
| localized telephone numbers, street address information and more.
|
*/
'faker_locale' => 'en_US',
/*
|--------------------------------------------------------------------------
| Encryption Key
|--------------------------------------------------------------------------
|
| This key is used by the Illuminate encrypter service and should be set
| to a random, 32 character string, otherwise these encrypted strings
| will not be safe. Please do this before deploying an application!
|
*/
'key' => env('APP_KEY'),
'cipher' => 'AES-256-CBC',
/*
|--------------------------------------------------------------------------
| Autoloaded Service Providers
|--------------------------------------------------------------------------
|
| The service providers listed here will be automatically loaded on the
| request to your application. Feel free to add your own services to
| this array to grant expanded functionality to your applications.
|
*/
'providers' => [
/*
* Laravel Framework Service Providers...
*/
Illuminate\Auth\AuthServiceProvider::class,
Illuminate\Broadcasting\BroadcastServiceProvider::class,
Illuminate\Bus\BusServiceProvider::class,
Illuminate\Cache\CacheServiceProvider::class,
Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
Illuminate\Cookie\CookieServiceProvider::class,
Illuminate\Database\DatabaseServiceProvider::class,
Illuminate\Encryption\EncryptionServiceProvider::class,
Illuminate\Filesystem\FilesystemServiceProvider::class,
Illuminate\Foundation\Providers\FoundationServiceProvider::class,
Illuminate\Hashing\HashServiceProvider::class,
Illuminate\Mail\MailServiceProvider::class,
Illuminate\Notifications\NotificationServiceProvider::class,
Illuminate\Pagination\PaginationServiceProvider::class,
Illuminate\Pipeline\PipelineServiceProvider::class,
Illuminate\Queue\QueueServiceProvider::class,
Illuminate\Redis\RedisServiceProvider::class,
Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
Illuminate\Session\SessionServiceProvider::class,
Illuminate\Translation\TranslationServiceProvider::class,
Illuminate\Validation\ValidationServiceProvider::class,
Illuminate\View\ViewServiceProvider::class,
/*
* Package Service Providers...
*/
/*
* Application Service Providers...
*/
App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class,
// App\Providers\BroadcastServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
/*
* Other Service Providers...
*/
],
/*
|--------------------------------------------------------------------------
| Class Aliases
|--------------------------------------------------------------------------
|
| This array of class aliases will be registered when this application
| is started. However, feel free to register as many as you wish as
| the aliases are "lazy" loaded so they don't hinder performance.
|
*/
'aliases' => Facade::defaultAliases()->merge([
// 'ExampleClass' => App\Example\ExampleClass::class,
])->toArray(),
];

122
config/auth.php Normal file
View File

@ -0,0 +1,122 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Authentication Defaults
|--------------------------------------------------------------------------
|
| This option controls the default authentication "guard" and password
| reset options for your application. You may change these defaults
| as required, but they're a perfect start for most applications.
|
*/
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
/*
|--------------------------------------------------------------------------
| Authentication Guards
|--------------------------------------------------------------------------
|
| Next, you may define every authentication guard for your application.
| Of course, a great default configuration has been defined for you
| here which uses session storage and the Eloquent user provider.
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| Supported: "session", "token"
|
*/
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'ldap',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
'hash' => false,
],
],
/*
|--------------------------------------------------------------------------
| User Providers
|--------------------------------------------------------------------------
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| If you have multiple user tables or models you may configure multiple
| sources which represent each model / table. These sources may then
| be assigned to any extra authentication guards you have defined.
|
| Supported: "database", "eloquent"
|
*/
'providers' => [
'users' => [
'driver' => 'ldap',
'model' => App\Ldap\User::class,
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
'ldap' => [
'driver' => 'ldap',
'model' => App\Ldap\User::class,
],
],
/*
|--------------------------------------------------------------------------
| Resetting Passwords
|--------------------------------------------------------------------------
|
| You may specify multiple password reset configurations if you have more
| than one user table or model in the application and you want to have
| separate password reset settings based on the specific user types.
|
| The expire time is the number of minutes that the reset token should be
| considered valid. This security feature keeps tokens short-lived so
| they have less time to be guessed. You may change this as needed.
|
*/
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
'throttle' => 60,
],
],
/*
|--------------------------------------------------------------------------
| Password Confirmation Timeout
|--------------------------------------------------------------------------
|
| Here you may define the amount of seconds before a password confirmation
| times out and the user is prompted to re-enter their password via the
| confirmation screen. By default, the timeout lasts for three hours.
|
*/
'password_timeout' => 10800,
];

59
config/broadcasting.php Normal file
View File

@ -0,0 +1,59 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Broadcaster
|--------------------------------------------------------------------------
|
| This option controls the default broadcaster that will be used by the
| framework when an event needs to be broadcast. You may set this to
| any of the connections defined in the "connections" array below.
|
| Supported: "pusher", "redis", "log", "null"
|
*/
'default' => env('BROADCAST_DRIVER', 'null'),
/*
|--------------------------------------------------------------------------
| Broadcast Connections
|--------------------------------------------------------------------------
|
| Here you may define all of the broadcast connections that will be used
| to broadcast events to other systems or over websockets. Samples of
| each available type of connection are provided inside this array.
|
*/
'connections' => [
'pusher' => [
'driver' => 'pusher',
'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_APP_SECRET'),
'app_id' => env('PUSHER_APP_ID'),
'options' => [
'cluster' => env('PUSHER_APP_CLUSTER'),
'useTLS' => true,
],
],
'redis' => [
'driver' => 'redis',
'connection' => 'default',
],
'log' => [
'driver' => 'log',
],
'null' => [
'driver' => 'null',
],
],
];

104
config/cache.php Normal file
View File

@ -0,0 +1,104 @@
<?php
use Illuminate\Support\Str;
return [
/*
|--------------------------------------------------------------------------
| Default Cache Store
|--------------------------------------------------------------------------
|
| This option controls the default cache connection that gets used while
| using this caching library. This connection is used when another is
| not explicitly specified when executing a given caching function.
|
| Supported: "apc", "array", "database", "file",
| "memcached", "redis", "dynamodb"
|
*/
'default' => env('CACHE_DRIVER', 'file'),
/*
|--------------------------------------------------------------------------
| Cache Stores
|--------------------------------------------------------------------------
|
| Here you may define all of the cache "stores" for your application as
| well as their drivers. You may even define multiple stores for the
| same cache driver to group types of items stored in your caches.
|
*/
'stores' => [
'apc' => [
'driver' => 'apc',
],
'array' => [
'driver' => 'array',
'serialize' => false,
],
'database' => [
'driver' => 'database',
'table' => 'cache',
'connection' => null,
],
'file' => [
'driver' => 'file',
'path' => storage_path('framework/cache/data'),
],
'memcached' => [
'driver' => 'memcached',
'persistent_id' => env('MEMCACHED_PERSISTENT_ID'),
'sasl' => [
env('MEMCACHED_USERNAME'),
env('MEMCACHED_PASSWORD'),
],
'options' => [
// Memcached::OPT_CONNECT_TIMEOUT => 2000,
],
'servers' => [
[
'host' => env('MEMCACHED_HOST', '127.0.0.1'),
'port' => env('MEMCACHED_PORT', 11211),
'weight' => 100,
],
],
],
'redis' => [
'driver' => 'redis',
'connection' => 'cache',
],
'dynamodb' => [
'driver' => 'dynamodb',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
'table' => env('DYNAMODB_CACHE_TABLE', 'cache'),
'endpoint' => env('DYNAMODB_ENDPOINT'),
],
],
/*
|--------------------------------------------------------------------------
| Cache Key Prefix
|--------------------------------------------------------------------------
|
| When utilizing a RAM based store such as APC or Memcached, there might
| be other applications utilizing the same cache. So, we'll specify a
| value to get prefixed to all our keys so we can avoid collisions.
|
*/
'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache'),
];

View File

@ -249,29 +249,6 @@ $config->custom->appearance['friendly_attrs'] = array(
// $config->custom->modify_member['posixfilter'] = '(uid=*)';
// $config->custom->modify_member['posixgroupattr'] = 'memberUid';
/*********************************************
* Support for attrs display order *
*********************************************/
/* Use this array if you want to have your attributes displayed in a specific
order. You can use default attribute names or their fridenly names.
For example, "sn" will be displayed right after "givenName". All the other
attributes that are not specified in this array will be displayed after in
alphabetical order. */
// $config->custom->appearance['attr_display_order'] = array();
# $config->custom->appearance['attr_display_order'] = array(
# 'givenName',
# 'sn',
# 'cn',
# 'displayName',
# 'uid',
# 'uidNumber',
# 'gidNumber',
# 'homeDirectory',
# 'mail',
# 'userPassword'
# );
/*********************************************
* Define your LDAP servers in this section *
*********************************************/
@ -507,15 +484,6 @@ $servers->setValue('server','name','My LDAP Server');
// $servers->setValue('server','custom_attrs',array(''));
# $servers->setValue('server','custom_attrs',array('nsRoleDN','nsRole','nsAccountLock'));
/* These attributes will be forced to MAY attributes and become option in the
templates. If they are not defined in the templates, then they wont appear
as per normal template processing. You may want to do this because your LDAP
server may automatically calculate a default value.
In Fedora Directory Server using the DNA Plugin one could ignore uidNumber,
gidNumber and sambaSID. */
// $servers->setValue('server','force_may',array(''));
# $servers->setValue('server','force_may',array('uidNumber','gidNumber','sambaSID'));
/*********************************************
* Unique attributes *
*********************************************/

34
config/cors.php Normal file
View File

@ -0,0 +1,34 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Cross-Origin Resource Sharing (CORS) Configuration
|--------------------------------------------------------------------------
|
| Here you may configure your settings for cross-origin resource sharing
| or "CORS". This determines what cross-origin operations may execute
| in web browsers. You are free to adjust these settings as needed.
|
| To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
|
*/
'paths' => ['api/*', 'sanctum/csrf-cookie'],
'allowed_methods' => ['*'],
'allowed_origins' => ['*'],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => false,
];

147
config/database.php Normal file
View File

@ -0,0 +1,147 @@
<?php
use Illuminate\Support\Str;
return [
/*
|--------------------------------------------------------------------------
| Default Database Connection Name
|--------------------------------------------------------------------------
|
| Here you may specify which of the database connections below you wish
| to use as your default connection for all database work. Of course
| you may use many connections at once using the Database library.
|
*/
'default' => env('DB_CONNECTION', 'mysql'),
/*
|--------------------------------------------------------------------------
| Database Connections
|--------------------------------------------------------------------------
|
| Here are each of the database connections setup for your application.
| Of course, examples of configuring each database platform that is
| supported by Laravel is shown below to make development simple.
|
|
| All database work in Laravel is done through the PHP PDO facilities
| so make sure you have the driver for your particular database of
| choice installed on your machine before you begin development.
|
*/
'connections' => [
'sqlite' => [
'driver' => 'sqlite',
'url' => env('DATABASE_URL'),
'database' => env('DB_DATABASE', database_path('database.sqlite')),
'prefix' => '',
'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
],
'mysql' => [
'driver' => 'mysql',
'url' => env('DATABASE_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],
'pgsql' => [
'driver' => 'pgsql',
'url' => env('DATABASE_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '5432'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'prefix' => '',
'prefix_indexes' => true,
'schema' => 'public',
'sslmode' => 'prefer',
],
'sqlsrv' => [
'driver' => 'sqlsrv',
'url' => env('DATABASE_URL'),
'host' => env('DB_HOST', 'localhost'),
'port' => env('DB_PORT', '1433'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'prefix' => '',
'prefix_indexes' => true,
],
],
/*
|--------------------------------------------------------------------------
| Migration Repository Table
|--------------------------------------------------------------------------
|
| This table keeps track of all the migrations that have already run for
| your application. Using this information, we can determine which of
| the migrations on disk haven't actually been run in the database.
|
*/
'migrations' => 'migrations',
/*
|--------------------------------------------------------------------------
| Redis Databases
|--------------------------------------------------------------------------
|
| Redis is an open source, fast, and advanced key-value store that also
| provides a richer body of commands than a typical key-value system
| such as APC or Memcached. Laravel makes it easy to dig right in.
|
*/
'redis' => [
'client' => env('REDIS_CLIENT', 'phpredis'),
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
],
'default' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_DB', '0'),
],
'cache' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_CACHE_DB', '1'),
],
],
];

85
config/filesystems.php Normal file
View File

@ -0,0 +1,85 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Filesystem Disk
|--------------------------------------------------------------------------
|
| Here you may specify the default filesystem disk that should be used
| by the framework. The "local" disk, as well as a variety of cloud
| based disks are available to your application. Just store away!
|
*/
'default' => env('FILESYSTEM_DRIVER', 'local'),
/*
|--------------------------------------------------------------------------
| Default Cloud Filesystem Disk
|--------------------------------------------------------------------------
|
| Many applications store files both locally and in the cloud. For this
| reason, you may specify a default "cloud" driver here. This driver
| will be bound as the Cloud disk implementation in the container.
|
*/
'cloud' => env('FILESYSTEM_CLOUD', 's3'),
/*
|--------------------------------------------------------------------------
| Filesystem Disks
|--------------------------------------------------------------------------
|
| Here you may configure as many filesystem "disks" as you wish, and you
| may even configure multiple disks of the same driver. Defaults have
| been setup for each driver as an example of the required options.
|
| Supported Drivers: "local", "ftp", "sftp", "s3"
|
*/
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
],
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
],
's3' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
'url' => env('AWS_URL'),
'endpoint' => env('AWS_ENDPOINT'),
],
],
/*
|--------------------------------------------------------------------------
| Symbolic Links
|--------------------------------------------------------------------------
|
| Here you may configure the symbolic links that will be created when the
| `storage:link` Artisan command is executed. The array keys should be
| the locations of the links and the values should be their targets.
|
*/
'links' => [
public_path('storage') => storage_path('app/public'),
],
];

52
config/hashing.php Normal file
View File

@ -0,0 +1,52 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Hash Driver
|--------------------------------------------------------------------------
|
| This option controls the default hash driver that will be used to hash
| passwords for your application. By default, the bcrypt algorithm is
| used; however, you remain free to modify this option if you wish.
|
| Supported: "bcrypt", "argon", "argon2id"
|
*/
'driver' => 'bcrypt',
/*
|--------------------------------------------------------------------------
| Bcrypt Options
|--------------------------------------------------------------------------
|
| Here you may specify the configuration options that should be used when
| passwords are hashed using the Bcrypt algorithm. This will allow you
| to control the amount of time it takes to hash the given password.
|
*/
'bcrypt' => [
'rounds' => env('BCRYPT_ROUNDS', 10),
],
/*
|--------------------------------------------------------------------------
| Argon Options
|--------------------------------------------------------------------------
|
| Here you may specify the configuration options that should be used when
| passwords are hashed using the Argon algorithm. These will allow you
| to control the amount of time it takes to hash the given password.
|
*/
'argon' => [
'memory' => 1024,
'threads' => 2,
'time' => 2,
],
];

View File

@ -0,0 +1,348 @@
<?php
return [
// Uncomment the languages that your site supports - or add new ones.
// These are sorted by the native name, which is the order you might show them in a language selector.
// Regional languages are sorted by their base language, so "British English" sorts as "English, British"
'supportedLocales' => [
'dev' => ['name' => 'Development', 'script' => 'Latn', 'native' => 'Development', 'regional' => ''],
//'ace' => ['name' => 'Achinese', 'script' => 'Latn', 'native' => 'Aceh', 'regional' => ''],
//'af' => ['name' => 'Afrikaans', 'script' => 'Latn', 'native' => 'Afrikaans', 'regional' => 'af_ZA'],
//'agq' => ['name' => 'Aghem', 'script' => 'Latn', 'native' => 'Aghem', 'regional' => ''],
//'ak' => ['name' => 'Akan', 'script' => 'Latn', 'native' => 'Akan', 'regional' => 'ak_GH'],
//'an' => ['name' => 'Aragonese', 'script' => 'Latn', 'native' => 'aragonés', 'regional' => 'an_ES'],
//'cch' => ['name' => 'Atsam', 'script' => 'Latn', 'native' => 'Atsam', 'regional' => ''],
//'gn' => ['name' => 'Guaraní', 'script' => 'Latn', 'native' => 'Avañeẽ', 'regional' => ''],
//'ae' => ['name' => 'Avestan', 'script' => 'Latn', 'native' => 'avesta', 'regional' => ''],
//'ay' => ['name' => 'Aymara', 'script' => 'Latn', 'native' => 'aymar aru', 'regional' => 'ay_PE'],
//'az' => ['name' => 'Azerbaijani (Latin)', 'script' => 'Latn', 'native' => 'azərbaycanca', 'regional' => 'az_AZ'],
//'id' => ['name' => 'Indonesian', 'script' => 'Latn', 'native' => 'Bahasa Indonesia', 'regional' => 'id_ID'],
//'ms' => ['name' => 'Malay', 'script' => 'Latn', 'native' => 'Bahasa Melayu', 'regional' => 'ms_MY'],
//'bm' => ['name' => 'Bambara', 'script' => 'Latn', 'native' => 'bamanakan', 'regional' => ''],
//'jv' => ['name' => 'Javanese (Latin)', 'script' => 'Latn', 'native' => 'Basa Jawa', 'regional' => ''],
//'su' => ['name' => 'Sundanese', 'script' => 'Latn', 'native' => 'Basa Sunda', 'regional' => ''],
//'bh' => ['name' => 'Bihari', 'script' => 'Latn', 'native' => 'Bihari', 'regional' => ''],
//'bi' => ['name' => 'Bislama', 'script' => 'Latn', 'native' => 'Bislama', 'regional' => ''],
//'nb' => ['name' => 'Norwegian Bokmål', 'script' => 'Latn', 'native' => 'Bokmål', 'regional' => 'nb_NO'],
//'bs' => ['name' => 'Bosnian', 'script' => 'Latn', 'native' => 'bosanski', 'regional' => 'bs_BA'],
//'br' => ['name' => 'Breton', 'script' => 'Latn', 'native' => 'brezhoneg', 'regional' => 'br_FR'],
//'ca' => ['name' => 'Catalan', 'script' => 'Latn', 'native' => 'català', 'regional' => 'ca_ES'],
//'ch' => ['name' => 'Chamorro', 'script' => 'Latn', 'native' => 'Chamoru', 'regional' => ''],
//'ny' => ['name' => 'Chewa', 'script' => 'Latn', 'native' => 'chiCheŵa', 'regional' => ''],
//'kde' => ['name' => 'Makonde', 'script' => 'Latn', 'native' => 'Chimakonde', 'regional' => ''],
//'sn' => ['name' => 'Shona', 'script' => 'Latn', 'native' => 'chiShona', 'regional' => ''],
//'co' => ['name' => 'Corsican', 'script' => 'Latn', 'native' => 'corsu', 'regional' => ''],
//'cy' => ['name' => 'Welsh', 'script' => 'Latn', 'native' => 'Cymraeg', 'regional' => 'cy_GB'],
//'da' => ['name' => 'Danish', 'script' => 'Latn', 'native' => 'dansk', 'regional' => 'da_DK'],
//'se' => ['name' => 'Northern Sami', 'script' => 'Latn', 'native' => 'davvisámegiella', 'regional' => 'se_NO'],
//'de' => ['name' => 'German', 'script' => 'Latn', 'native' => 'Deutsch', 'regional' => 'de_DE'],
//'luo' => ['name' => 'Luo', 'script' => 'Latn', 'native' => 'Dholuo', 'regional' => ''],
//'nv' => ['name' => 'Navajo', 'script' => 'Latn', 'native' => 'Diné bizaad', 'regional' => ''],
//'dua' => ['name' => 'Duala', 'script' => 'Latn', 'native' => 'duálá', 'regional' => ''],
//'et' => ['name' => 'Estonian', 'script' => 'Latn', 'native' => 'eesti', 'regional' => 'et_EE'],
//'na' => ['name' => 'Nauru', 'script' => 'Latn', 'native' => 'Ekakairũ Naoero', 'regional' => ''],
//'guz' => ['name' => 'Ekegusii', 'script' => 'Latn', 'native' => 'Ekegusii', 'regional' => ''],
'en' => ['name' => 'English', 'script' => 'Latn', 'native' => 'English', 'regional' => 'en_GB'],
//'en-AU' => ['name' => 'Australian English', 'script' => 'Latn', 'native' => 'Australian English', 'regional' => 'en_AU'],
//'en-GB' => ['name' => 'British English', 'script' => 'Latn', 'native' => 'British English', 'regional' => 'en_GB'],
//'en-CA' => ['name' => 'Canadian English', 'script' => 'Latn', 'native' => 'Canadian English', 'regional' => 'en_CA'],
//'en-US' => ['name' => 'U.S. English', 'script' => 'Latn', 'native' => 'U.S. English', 'regional' => 'en_US'],
//'es' => ['name' => 'Spanish', 'script' => 'Latn', 'native' => 'español', 'regional' => 'es_ES'],
//'eo' => ['name' => 'Esperanto', 'script' => 'Latn', 'native' => 'esperanto', 'regional' => ''],
//'eu' => ['name' => 'Basque', 'script' => 'Latn', 'native' => 'euskara', 'regional' => 'eu_ES'],
//'ewo' => ['name' => 'Ewondo', 'script' => 'Latn', 'native' => 'ewondo', 'regional' => ''],
//'ee' => ['name' => 'Ewe', 'script' => 'Latn', 'native' => 'eʋegbe', 'regional' => ''],
//'fil' => ['name' => 'Filipino', 'script' => 'Latn', 'native' => 'Filipino', 'regional' => 'fil_PH'],
//'fr' => ['name' => 'French', 'script' => 'Latn', 'native' => 'français', 'regional' => 'fr_FR'],
//'fr-CA' => ['name' => 'Canadian French', 'script' => 'Latn', 'native' => 'français canadien', 'regional' => 'fr_CA'],
//'fy' => ['name' => 'Western Frisian', 'script' => 'Latn', 'native' => 'frysk', 'regional' => 'fy_DE'],
//'fur' => ['name' => 'Friulian', 'script' => 'Latn', 'native' => 'furlan', 'regional' => 'fur_IT'],
//'fo' => ['name' => 'Faroese', 'script' => 'Latn', 'native' => 'føroyskt', 'regional' => 'fo_FO'],
//'gaa' => ['name' => 'Ga', 'script' => 'Latn', 'native' => 'Ga', 'regional' => ''],
//'ga' => ['name' => 'Irish', 'script' => 'Latn', 'native' => 'Gaeilge', 'regional' => 'ga_IE'],
//'gv' => ['name' => 'Manx', 'script' => 'Latn', 'native' => 'Gaelg', 'regional' => 'gv_GB'],
//'sm' => ['name' => 'Samoan', 'script' => 'Latn', 'native' => 'Gagana faa Sāmoa', 'regional' => ''],
//'gl' => ['name' => 'Galician', 'script' => 'Latn', 'native' => 'galego', 'regional' => 'gl_ES'],
//'ki' => ['name' => 'Kikuyu', 'script' => 'Latn', 'native' => 'Gikuyu', 'regional' => ''],
//'gd' => ['name' => 'Scottish Gaelic', 'script' => 'Latn', 'native' => 'Gàidhlig', 'regional' => 'gd_GB'],
//'ha' => ['name' => 'Hausa', 'script' => 'Latn', 'native' => 'Hausa', 'regional' => 'ha_NG'],
//'bez' => ['name' => 'Bena', 'script' => 'Latn', 'native' => 'Hibena', 'regional' => ''],
//'ho' => ['name' => 'Hiri Motu', 'script' => 'Latn', 'native' => 'Hiri Motu', 'regional' => ''],
//'hr' => ['name' => 'Croatian', 'script' => 'Latn', 'native' => 'hrvatski', 'regional' => 'hr_HR'],
//'bem' => ['name' => 'Bemba', 'script' => 'Latn', 'native' => 'Ichibemba', 'regional' => 'bem_ZM'],
//'io' => ['name' => 'Ido', 'script' => 'Latn', 'native' => 'Ido', 'regional' => ''],
//'ig' => ['name' => 'Igbo', 'script' => 'Latn', 'native' => 'Igbo', 'regional' => 'ig_NG'],
//'rn' => ['name' => 'Rundi', 'script' => 'Latn', 'native' => 'Ikirundi', 'regional' => ''],
//'ia' => ['name' => 'Interlingua', 'script' => 'Latn', 'native' => 'interlingua', 'regional' => 'ia_FR'],
//'iu-Latn' => ['name' => 'Inuktitut (Latin)', 'script' => 'Latn', 'native' => 'Inuktitut', 'regional' => 'iu_CA'],
//'sbp' => ['name' => 'Sileibi', 'script' => 'Latn', 'native' => 'Ishisangu', 'regional' => ''],
//'nd' => ['name' => 'North Ndebele', 'script' => 'Latn', 'native' => 'isiNdebele', 'regional' => ''],
//'nr' => ['name' => 'South Ndebele', 'script' => 'Latn', 'native' => 'isiNdebele', 'regional' => 'nr_ZA'],
//'xh' => ['name' => 'Xhosa', 'script' => 'Latn', 'native' => 'isiXhosa', 'regional' => 'xh_ZA'],
//'zu' => ['name' => 'Zulu', 'script' => 'Latn', 'native' => 'isiZulu', 'regional' => 'zu_ZA'],
//'it' => ['name' => 'Italian', 'script' => 'Latn', 'native' => 'italiano', 'regional' => 'it_IT'],
//'ik' => ['name' => 'Inupiaq', 'script' => 'Latn', 'native' => 'Iñupiaq', 'regional' => 'ik_CA'],
//'dyo' => ['name' => 'Jola-Fonyi', 'script' => 'Latn', 'native' => 'joola', 'regional' => ''],
//'kea' => ['name' => 'Kabuverdianu', 'script' => 'Latn', 'native' => 'kabuverdianu', 'regional' => ''],
//'kaj' => ['name' => 'Jju', 'script' => 'Latn', 'native' => 'Kaje', 'regional' => ''],
//'mh' => ['name' => 'Marshallese', 'script' => 'Latn', 'native' => 'Kajin M̧ajeļ', 'regional' => 'mh_MH'],
//'kl' => ['name' => 'Kalaallisut', 'script' => 'Latn', 'native' => 'kalaallisut', 'regional' => 'kl_GL'],
//'kln' => ['name' => 'Kalenjin', 'script' => 'Latn', 'native' => 'Kalenjin', 'regional' => ''],
//'kr' => ['name' => 'Kanuri', 'script' => 'Latn', 'native' => 'Kanuri', 'regional' => ''],
//'kcg' => ['name' => 'Tyap', 'script' => 'Latn', 'native' => 'Katab', 'regional' => ''],
//'kw' => ['name' => 'Cornish', 'script' => 'Latn', 'native' => 'kernewek', 'regional' => 'kw_GB'],
//'naq' => ['name' => 'Nama', 'script' => 'Latn', 'native' => 'Khoekhoegowab', 'regional' => ''],
//'rof' => ['name' => 'Rombo', 'script' => 'Latn', 'native' => 'Kihorombo', 'regional' => ''],
//'kam' => ['name' => 'Kamba', 'script' => 'Latn', 'native' => 'Kikamba', 'regional' => ''],
//'kg' => ['name' => 'Kongo', 'script' => 'Latn', 'native' => 'Kikongo', 'regional' => ''],
//'jmc' => ['name' => 'Machame', 'script' => 'Latn', 'native' => 'Kimachame', 'regional' => ''],
//'rw' => ['name' => 'Kinyarwanda', 'script' => 'Latn', 'native' => 'Kinyarwanda', 'regional' => 'rw_RW'],
//'asa' => ['name' => 'Kipare', 'script' => 'Latn', 'native' => 'Kipare', 'regional' => ''],
//'rwk' => ['name' => 'Rwa', 'script' => 'Latn', 'native' => 'Kiruwa', 'regional' => ''],
//'saq' => ['name' => 'Samburu', 'script' => 'Latn', 'native' => 'Kisampur', 'regional' => ''],
//'ksb' => ['name' => 'Shambala', 'script' => 'Latn', 'native' => 'Kishambaa', 'regional' => ''],
//'swc' => ['name' => 'Congo Swahili', 'script' => 'Latn', 'native' => 'Kiswahili ya Kongo', 'regional' => ''],
//'sw' => ['name' => 'Swahili', 'script' => 'Latn', 'native' => 'Kiswahili', 'regional' => 'sw_KE'],
//'dav' => ['name' => 'Dawida', 'script' => 'Latn', 'native' => 'Kitaita', 'regional' => ''],
//'teo' => ['name' => 'Teso', 'script' => 'Latn', 'native' => 'Kiteso', 'regional' => ''],
//'khq' => ['name' => 'Koyra Chiini', 'script' => 'Latn', 'native' => 'Koyra ciini', 'regional' => ''],
//'ses' => ['name' => 'Songhay', 'script' => 'Latn', 'native' => 'Koyraboro senni', 'regional' => ''],
//'mfe' => ['name' => 'Morisyen', 'script' => 'Latn', 'native' => 'kreol morisien', 'regional' => ''],
//'ht' => ['name' => 'Haitian', 'script' => 'Latn', 'native' => 'Kreyòl ayisyen', 'regional' => 'ht_HT'],
//'kj' => ['name' => 'Kuanyama', 'script' => 'Latn', 'native' => 'Kwanyama', 'regional' => ''],
//'ksh' => ['name' => 'Kölsch', 'script' => 'Latn', 'native' => 'Kölsch', 'regional' => ''],
//'ebu' => ['name' => 'Kiembu', 'script' => 'Latn', 'native' => 'Kĩembu', 'regional' => ''],
//'mer' => ['name' => 'Kimîîru', 'script' => 'Latn', 'native' => 'Kĩmĩrũ', 'regional' => ''],
//'lag' => ['name' => 'Langi', 'script' => 'Latn', 'native' => 'Kɨlaangi', 'regional' => ''],
//'lah' => ['name' => 'Lahnda', 'script' => 'Latn', 'native' => 'Lahnda', 'regional' => ''],
//'la' => ['name' => 'Latin', 'script' => 'Latn', 'native' => 'latine', 'regional' => ''],
//'lv' => ['name' => 'Latvian', 'script' => 'Latn', 'native' => 'latviešu', 'regional' => 'lv_LV'],
//'to' => ['name' => 'Tongan', 'script' => 'Latn', 'native' => 'lea fakatonga', 'regional' => ''],
//'lt' => ['name' => 'Lithuanian', 'script' => 'Latn', 'native' => 'lietuvių', 'regional' => 'lt_LT'],
//'li' => ['name' => 'Limburgish', 'script' => 'Latn', 'native' => 'Limburgs', 'regional' => 'li_BE'],
//'ln' => ['name' => 'Lingala', 'script' => 'Latn', 'native' => 'lingála', 'regional' => ''],
//'lg' => ['name' => 'Ganda', 'script' => 'Latn', 'native' => 'Luganda', 'regional' => 'lg_UG'],
//'luy' => ['name' => 'Oluluyia', 'script' => 'Latn', 'native' => 'Luluhia', 'regional' => ''],
//'lb' => ['name' => 'Luxembourgish', 'script' => 'Latn', 'native' => 'Lëtzebuergesch', 'regional' => 'lb_LU'],
//'hu' => ['name' => 'Hungarian', 'script' => 'Latn', 'native' => 'magyar', 'regional' => 'hu_HU'],
//'mgh' => ['name' => 'Makhuwa-Meetto', 'script' => 'Latn', 'native' => 'Makua', 'regional' => ''],
//'mg' => ['name' => 'Malagasy', 'script' => 'Latn', 'native' => 'Malagasy', 'regional' => 'mg_MG'],
//'mt' => ['name' => 'Maltese', 'script' => 'Latn', 'native' => 'Malti', 'regional' => 'mt_MT'],
//'mtr' => ['name' => 'Mewari', 'script' => 'Latn', 'native' => 'Mewari', 'regional' => ''],
//'mua' => ['name' => 'Mundang', 'script' => 'Latn', 'native' => 'Mundang', 'regional' => ''],
//'mi' => ['name' => 'Māori', 'script' => 'Latn', 'native' => 'Māori', 'regional' => 'mi_NZ'],
//'nl' => ['name' => 'Dutch', 'script' => 'Latn', 'native' => 'Nederlands', 'regional' => 'nl_NL'],
//'nmg' => ['name' => 'Kwasio', 'script' => 'Latn', 'native' => 'ngumba', 'regional' => ''],
//'yav' => ['name' => 'Yangben', 'script' => 'Latn', 'native' => 'nuasue', 'regional' => ''],
//'nn' => ['name' => 'Norwegian Nynorsk', 'script' => 'Latn', 'native' => 'nynorsk', 'regional' => 'nn_NO'],
//'oc' => ['name' => 'Occitan', 'script' => 'Latn', 'native' => 'occitan', 'regional' => 'oc_FR'],
//'ang' => ['name' => 'Old English', 'script' => 'Runr', 'native' => 'Old English', 'regional' => ''],
//'xog' => ['name' => 'Soga', 'script' => 'Latn', 'native' => 'Olusoga', 'regional' => ''],
//'om' => ['name' => 'Oromo', 'script' => 'Latn', 'native' => 'Oromoo', 'regional' => 'om_ET'],
//'ng' => ['name' => 'Ndonga', 'script' => 'Latn', 'native' => 'OshiNdonga', 'regional' => ''],
//'hz' => ['name' => 'Herero', 'script' => 'Latn', 'native' => 'Otjiherero', 'regional' => ''],
//'uz-Latn' => ['name' => 'Uzbek (Latin)', 'script' => 'Latn', 'native' => 'oʼzbekcha', 'regional' => 'uz_UZ'],
//'nds' => ['name' => 'Low German', 'script' => 'Latn', 'native' => 'Plattdüütsch', 'regional' => 'nds_DE'],
//'pl' => ['name' => 'Polish', 'script' => 'Latn', 'native' => 'polski', 'regional' => 'pl_PL'],
//'pt' => ['name' => 'Portuguese', 'script' => 'Latn', 'native' => 'português', 'regional' => 'pt_PT'],
//'pt-BR' => ['name' => 'Brazilian Portuguese', 'script' => 'Latn', 'native' => 'português do Brasil', 'regional' => 'pt_BR'],
//'ff' => ['name' => 'Fulah', 'script' => 'Latn', 'native' => 'Pulaar', 'regional' => 'ff_SN'],
//'pi' => ['name' => 'Pahari-Potwari', 'script' => 'Latn', 'native' => 'Pāli', 'regional' => ''],
//'aa' => ['name' => 'Afar', 'script' => 'Latn', 'native' => 'Qafar', 'regional' => 'aa_ER'],
//'ty' => ['name' => 'Tahitian', 'script' => 'Latn', 'native' => 'Reo Māohi', 'regional' => ''],
//'ksf' => ['name' => 'Bafia', 'script' => 'Latn', 'native' => 'rikpa', 'regional' => ''],
//'ro' => ['name' => 'Romanian', 'script' => 'Latn', 'native' => 'română', 'regional' => 'ro_RO'],
//'cgg' => ['name' => 'Chiga', 'script' => 'Latn', 'native' => 'Rukiga', 'regional' => ''],
//'rm' => ['name' => 'Romansh', 'script' => 'Latn', 'native' => 'rumantsch', 'regional' => ''],
//'qu' => ['name' => 'Quechua', 'script' => 'Latn', 'native' => 'Runa Simi', 'regional' => ''],
//'nyn' => ['name' => 'Nyankole', 'script' => 'Latn', 'native' => 'Runyankore', 'regional' => ''],
//'ssy' => ['name' => 'Saho', 'script' => 'Latn', 'native' => 'Saho', 'regional' => ''],
//'sc' => ['name' => 'Sardinian', 'script' => 'Latn', 'native' => 'sardu', 'regional' => 'sc_IT'],
//'de-CH' => ['name' => 'Swiss High German', 'script' => 'Latn', 'native' => 'Schweizer Hochdeutsch', 'regional' => 'de_CH'],
//'gsw' => ['name' => 'Swiss German', 'script' => 'Latn', 'native' => 'Schwiizertüütsch', 'regional' => ''],
//'trv' => ['name' => 'Taroko', 'script' => 'Latn', 'native' => 'Seediq', 'regional' => ''],
//'seh' => ['name' => 'Sena', 'script' => 'Latn', 'native' => 'sena', 'regional' => ''],
//'nso' => ['name' => 'Northern Sotho', 'script' => 'Latn', 'native' => 'Sesotho sa Leboa', 'regional' => 'nso_ZA'],
//'st' => ['name' => 'Southern Sotho', 'script' => 'Latn', 'native' => 'Sesotho', 'regional' => 'st_ZA'],
//'tn' => ['name' => 'Tswana', 'script' => 'Latn', 'native' => 'Setswana', 'regional' => 'tn_ZA'],
//'sq' => ['name' => 'Albanian', 'script' => 'Latn', 'native' => 'shqip', 'regional' => 'sq_AL'],
//'sid' => ['name' => 'Sidamo', 'script' => 'Latn', 'native' => 'Sidaamu Afo', 'regional' => 'sid_ET'],
//'ss' => ['name' => 'Swati', 'script' => 'Latn', 'native' => 'Siswati', 'regional' => 'ss_ZA'],
//'sk' => ['name' => 'Slovak', 'script' => 'Latn', 'native' => 'slovenčina', 'regional' => 'sk_SK'],
//'sl' => ['name' => 'Slovene', 'script' => 'Latn', 'native' => 'slovenščina', 'regional' => 'sl_SI'],
//'so' => ['name' => 'Somali', 'script' => 'Latn', 'native' => 'Soomaali', 'regional' => 'so_SO'],
//'sr-Latn' => ['name' => 'Serbian (Latin)', 'script' => 'Latn', 'native' => 'Srpski', 'regional' => 'sr_RS'],
//'sh' => ['name' => 'Serbo-Croatian', 'script' => 'Latn', 'native' => 'srpskohrvatski', 'regional' => ''],
//'fi' => ['name' => 'Finnish', 'script' => 'Latn', 'native' => 'suomi', 'regional' => 'fi_FI'],
//'sv' => ['name' => 'Swedish', 'script' => 'Latn', 'native' => 'svenska', 'regional' => 'sv_SE'],
//'sg' => ['name' => 'Sango', 'script' => 'Latn', 'native' => 'Sängö', 'regional' => ''],
//'tl' => ['name' => 'Tagalog', 'script' => 'Latn', 'native' => 'Tagalog', 'regional' => 'tl_PH'],
//'tzm-Latn' => ['name' => 'Central Atlas Tamazight (Latin)', 'script' => 'Latn', 'native' => 'Tamazight', 'regional' => ''],
//'kab' => ['name' => 'Kabyle', 'script' => 'Latn', 'native' => 'Taqbaylit', 'regional' => 'kab_DZ'],
//'twq' => ['name' => 'Tasawaq', 'script' => 'Latn', 'native' => 'Tasawaq senni', 'regional' => ''],
//'shi' => ['name' => 'Tachelhit (Latin)', 'script' => 'Latn', 'native' => 'Tashelhit', 'regional' => ''],
//'nus' => ['name' => 'Nuer', 'script' => 'Latn', 'native' => 'Thok Nath', 'regional' => ''],
//'vi' => ['name' => 'Vietnamese', 'script' => 'Latn', 'native' => 'Tiếng Việt', 'regional' => 'vi_VN'],
//'tg-Latn' => ['name' => 'Tajik (Latin)', 'script' => 'Latn', 'native' => 'tojikī', 'regional' => 'tg_TJ'],
//'lu' => ['name' => 'Luba-Katanga', 'script' => 'Latn', 'native' => 'Tshiluba', 'regional' => 've_ZA'],
//'ve' => ['name' => 'Venda', 'script' => 'Latn', 'native' => 'Tshivenḓa', 'regional' => ''],
//'tw' => ['name' => 'Twi', 'script' => 'Latn', 'native' => 'Twi', 'regional' => ''],
//'tr' => ['name' => 'Turkish', 'script' => 'Latn', 'native' => 'Türkçe', 'regional' => 'tr_TR'],
//'ale' => ['name' => 'Aleut', 'script' => 'Latn', 'native' => 'Unangax tunuu', 'regional' => ''],
//'ca-valencia' => ['name' => 'Valencian', 'script' => 'Latn', 'native' => 'valencià', 'regional' => ''],
//'vai-Latn' => ['name' => 'Vai (Latin)', 'script' => 'Latn', 'native' => 'Viyamíĩ', 'regional' => ''],
//'vo' => ['name' => 'Volapük', 'script' => 'Latn', 'native' => 'Volapük', 'regional' => ''],
//'fj' => ['name' => 'Fijian', 'script' => 'Latn', 'native' => 'vosa Vakaviti', 'regional' => ''],
//'wa' => ['name' => 'Walloon', 'script' => 'Latn', 'native' => 'Walon', 'regional' => 'wa_BE'],
//'wae' => ['name' => 'Walser', 'script' => 'Latn', 'native' => 'Walser', 'regional' => 'wae_CH'],
//'wen' => ['name' => 'Sorbian', 'script' => 'Latn', 'native' => 'Wendic', 'regional' => ''],
//'wo' => ['name' => 'Wolof', 'script' => 'Latn', 'native' => 'Wolof', 'regional' => 'wo_SN'],
//'ts' => ['name' => 'Tsonga', 'script' => 'Latn', 'native' => 'Xitsonga', 'regional' => 'ts_ZA'],
//'dje' => ['name' => 'Zarma', 'script' => 'Latn', 'native' => 'Zarmaciine', 'regional' => ''],
//'yo' => ['name' => 'Yoruba', 'script' => 'Latn', 'native' => 'Èdè Yorùbá', 'regional' => 'yo_NG'],
// 'de-AT' => ['name' => 'Austrian German', 'script' => 'Latn', 'native' => 'Österreichisches Deutsch', 'regional' => 'de_AT'],
//'is' => ['name' => 'Icelandic', 'script' => 'Latn', 'native' => 'íslenska', 'regional' => 'is_IS'],
//'cs' => ['name' => 'Czech', 'script' => 'Latn', 'native' => 'čeština', 'regional' => 'cs_CZ'],
//'bas' => ['name' => 'Basa', 'script' => 'Latn', 'native' => 'Ɓàsàa', 'regional' => ''],
//'mas' => ['name' => 'Masai', 'script' => 'Latn', 'native' => 'ɔl-Maa', 'regional' => ''],
//'haw' => ['name' => 'Hawaiian', 'script' => 'Latn', 'native' => 'ʻŌlelo Hawaiʻi', 'regional' => ''],
//'el' => ['name' => 'Greek', 'script' => 'Grek', 'native' => 'Ελληνικά', 'regional' => 'el_GR'],
//'uz' => ['name' => 'Uzbek (Cyrillic)', 'script' => 'Cyrl', 'native' => 'Ўзбек', 'regional' => 'uz_UZ'],
//'az-Cyrl' => ['name' => 'Azerbaijani (Cyrillic)', 'script' => 'Cyrl', 'native' => 'Азәрбајҹан', 'regional' => 'uz_UZ'],
//'ab' => ['name' => 'Abkhazian', 'script' => 'Cyrl', 'native' => 'Аҧсуа', 'regional' => ''],
//'os' => ['name' => 'Ossetic', 'script' => 'Cyrl', 'native' => 'Ирон', 'regional' => 'os_RU'],
//'ky' => ['name' => 'Kyrgyz', 'script' => 'Cyrl', 'native' => 'Кыргыз', 'regional' => 'ky_KG'],
//'sr' => ['name' => 'Serbian (Cyrillic)', 'script' => 'Cyrl', 'native' => 'Српски', 'regional' => 'sr_RS'],
//'av' => ['name' => 'Avaric', 'script' => 'Cyrl', 'native' => 'авар мацӀ', 'regional' => ''],
//'ady' => ['name' => 'Adyghe', 'script' => 'Cyrl', 'native' => 'адыгэбзэ', 'regional' => ''],
//'ba' => ['name' => 'Bashkir', 'script' => 'Cyrl', 'native' => 'башҡорт теле', 'regional' => ''],
//'be' => ['name' => 'Belarusian', 'script' => 'Cyrl', 'native' => 'беларуская', 'regional' => 'be_BY'],
//'bg' => ['name' => 'Bulgarian', 'script' => 'Cyrl', 'native' => 'български', 'regional' => 'bg_BG'],
//'kv' => ['name' => 'Komi', 'script' => 'Cyrl', 'native' => 'коми кыв', 'regional' => ''],
//'mk' => ['name' => 'Macedonian', 'script' => 'Cyrl', 'native' => 'македонски', 'regional' => 'mk_MK'],
//'mn' => ['name' => 'Mongolian (Cyrillic)', 'script' => 'Cyrl', 'native' => 'монгол', 'regional' => 'mn_MN'],
//'ce' => ['name' => 'Chechen', 'script' => 'Cyrl', 'native' => 'нохчийн мотт', 'regional' => 'ce_RU'],
//'ru' => ['name' => 'Russian', 'script' => 'Cyrl', 'native' => 'русский', 'regional' => 'ru_RU'],
//'sah' => ['name' => 'Yakut', 'script' => 'Cyrl', 'native' => 'саха тыла', 'regional' => ''],
//'tt' => ['name' => 'Tatar', 'script' => 'Cyrl', 'native' => 'татар теле', 'regional' => 'tt_RU'],
//'tg' => ['name' => 'Tajik (Cyrillic)', 'script' => 'Cyrl', 'native' => 'тоҷикӣ', 'regional' => 'tg_TJ'],
//'tk' => ['name' => 'Turkmen', 'script' => 'Cyrl', 'native' => 'түркменче', 'regional' => 'tk_TM'],
//'uk' => ['name' => 'Ukrainian', 'script' => 'Cyrl', 'native' => 'українська', 'regional' => 'uk_UA'],
//'cv' => ['name' => 'Chuvash', 'script' => 'Cyrl', 'native' => 'чӑваш чӗлхи', 'regional' => 'cv_RU'],
//'cu' => ['name' => 'Church Slavic', 'script' => 'Cyrl', 'native' => 'ѩзыкъ словѣньскъ', 'regional' => ''],
//'kk' => ['name' => 'Kazakh', 'script' => 'Cyrl', 'native' => 'қазақ тілі', 'regional' => 'kk_KZ'],
//'hy' => ['name' => 'Armenian', 'script' => 'Armn', 'native' => 'Հայերեն', 'regional' => 'hy_AM'],
//'yi' => ['name' => 'Yiddish', 'script' => 'Hebr', 'native' => 'ייִדיש', 'regional' => 'yi_US'],
//'he' => ['name' => 'Hebrew', 'script' => 'Hebr', 'native' => 'עברית', 'regional' => 'he_IL'],
//'ug' => ['name' => 'Uyghur', 'script' => 'Arab', 'native' => 'ئۇيغۇرچە', 'regional' => 'ug_CN'],
//'ur' => ['name' => 'Urdu', 'script' => 'Arab', 'native' => 'اردو', 'regional' => 'ur_PK'],
//'ar' => ['name' => 'Arabic', 'script' => 'Arab', 'native' => 'العربية', 'regional' => 'ar_AE'],
//'uz-Arab' => ['name' => 'Uzbek (Arabic)', 'script' => 'Arab', 'native' => 'اۉزبېک', 'regional' => ''],
//'tg-Arab' => ['name' => 'Tajik (Arabic)', 'script' => 'Arab', 'native' => 'تاجیکی', 'regional' => 'tg_TJ'],
//'sd' => ['name' => 'Sindhi', 'script' => 'Arab', 'native' => 'سنڌي', 'regional' => 'sd_IN'],
//'fa' => ['name' => 'Persian', 'script' => 'Arab', 'native' => 'فارسی', 'regional' => 'fa_IR'],
//'pa-Arab' => ['name' => 'Punjabi (Arabic)', 'script' => 'Arab', 'native' => 'پنجاب', 'regional' => 'pa_IN'],
//'ps' => ['name' => 'Pashto', 'script' => 'Arab', 'native' => 'پښتو', 'regional' => 'ps_AF'],
//'ks' => ['name' => 'Kashmiri (Arabic)', 'script' => 'Arab', 'native' => 'کأشُر', 'regional' => 'ks_IN'],
//'ku' => ['name' => 'Kurdish', 'script' => 'Arab', 'native' => 'کوردی', 'regional' => 'ku_TR'],
//'dv' => ['name' => 'Divehi', 'script' => 'Thaa', 'native' => 'ދިވެހިބަސް', 'regional' => 'dv_MV'],
//'ks-Deva' => ['name' => 'Kashmiri (Devaganari)', 'script' => 'Deva', 'native' => 'कॉशुर', 'regional' => 'ks_IN'],
//'kok' => ['name' => 'Konkani', 'script' => 'Deva', 'native' => 'कोंकणी', 'regional' => 'kok_IN'],
//'doi' => ['name' => 'Dogri', 'script' => 'Deva', 'native' => 'डोगरी', 'regional' => 'doi_IN'],
//'ne' => ['name' => 'Nepali', 'script' => 'Deva', 'native' => 'नेपाली', 'regional' => ''],
//'pra' => ['name' => 'Prakrit', 'script' => 'Deva', 'native' => 'प्राकृत', 'regional' => ''],
//'brx' => ['name' => 'Bodo', 'script' => 'Deva', 'native' => 'बड़ो', 'regional' => 'brx_IN'],
//'bra' => ['name' => 'Braj', 'script' => 'Deva', 'native' => 'ब्रज भाषा', 'regional' => ''],
//'mr' => ['name' => 'Marathi', 'script' => 'Deva', 'native' => 'मराठी', 'regional' => 'mr_IN'],
//'mai' => ['name' => 'Maithili', 'script' => 'Tirh', 'native' => 'मैथिली', 'regional' => 'mai_IN'],
//'raj' => ['name' => 'Rajasthani', 'script' => 'Deva', 'native' => 'राजस्थानी', 'regional' => ''],
//'sa' => ['name' => 'Sanskrit', 'script' => 'Deva', 'native' => 'संस्कृतम्', 'regional' => 'sa_IN'],
//'hi' => ['name' => 'Hindi', 'script' => 'Deva', 'native' => 'हिन्दी', 'regional' => 'hi_IN'],
//'as' => ['name' => 'Assamese', 'script' => 'Beng', 'native' => 'অসমীয়া', 'regional' => 'as_IN'],
//'bn' => ['name' => 'Bengali', 'script' => 'Beng', 'native' => 'বাংলা', 'regional' => 'bn_BD'],
//'mni' => ['name' => 'Manipuri', 'script' => 'Beng', 'native' => 'মৈতৈ', 'regional' => 'mni_IN'],
//'pa' => ['name' => 'Punjabi (Gurmukhi)', 'script' => 'Guru', 'native' => 'ਪੰਜਾਬੀ', 'regional' => 'pa_IN'],
//'gu' => ['name' => 'Gujarati', 'script' => 'Gujr', 'native' => 'ગુજરાતી', 'regional' => 'gu_IN'],
//'or' => ['name' => 'Oriya', 'script' => 'Orya', 'native' => 'ଓଡ଼ିଆ', 'regional' => 'or_IN'],
//'ta' => ['name' => 'Tamil', 'script' => 'Taml', 'native' => 'தமிழ்', 'regional' => 'ta_IN'],
//'te' => ['name' => 'Telugu', 'script' => 'Telu', 'native' => 'తెలుగు', 'regional' => 'te_IN'],
//'kn' => ['name' => 'Kannada', 'script' => 'Knda', 'native' => 'ಕನ್ನಡ', 'regional' => 'kn_IN'],
//'ml' => ['name' => 'Malayalam', 'script' => 'Mlym', 'native' => 'മലയാളം', 'regional' => 'ml_IN'],
//'si' => ['name' => 'Sinhala', 'script' => 'Sinh', 'native' => 'සිංහල', 'regional' => 'si_LK'],
//'th' => ['name' => 'Thai', 'script' => 'Thai', 'native' => 'ไทย', 'regional' => 'th_TH'],
//'lo' => ['name' => 'Lao', 'script' => 'Laoo', 'native' => 'ລາວ', 'regional' => 'lo_LA'],
//'bo' => ['name' => 'Tibetan', 'script' => 'Tibt', 'native' => 'པོད་སྐད་', 'regional' => 'bo_IN'],
//'dz' => ['name' => 'Dzongkha', 'script' => 'Tibt', 'native' => 'རྫོང་ཁ', 'regional' => 'dz_BT'],
//'my' => ['name' => 'Burmese', 'script' => 'Mymr', 'native' => 'မြန်မာဘာသာ', 'regional' => 'my_MM'],
//'ka' => ['name' => 'Georgian', 'script' => 'Geor', 'native' => 'ქართული', 'regional' => 'ka_GE'],
//'byn' => ['name' => 'Blin', 'script' => 'Ethi', 'native' => 'ብሊን', 'regional' => 'byn_ER'],
//'tig' => ['name' => 'Tigre', 'script' => 'Ethi', 'native' => 'ትግረ', 'regional' => 'tig_ER'],
//'ti' => ['name' => 'Tigrinya', 'script' => 'Ethi', 'native' => 'ትግርኛ', 'regional' => 'ti_ET'],
//'am' => ['name' => 'Amharic', 'script' => 'Ethi', 'native' => 'አማርኛ', 'regional' => 'am_ET'],
//'wal' => ['name' => 'Wolaytta', 'script' => 'Ethi', 'native' => 'ወላይታቱ', 'regional' => 'wal_ET'],
//'chr' => ['name' => 'Cherokee', 'script' => 'Cher', 'native' => 'ᏣᎳᎩ', 'regional' => ''],
//'iu' => ['name' => 'Inuktitut (Canadian Aboriginal Syllabics)', 'script' => 'Cans', 'native' => 'ᐃᓄᒃᑎᑐᑦ', 'regional' => 'iu_CA'],
//'oj' => ['name' => 'Ojibwa', 'script' => 'Cans', 'native' => 'ᐊᓂᔑᓈᐯᒧᐎᓐ', 'regional' => ''],
//'cr' => ['name' => 'Cree', 'script' => 'Cans', 'native' => 'ᓀᐦᐃᔭᐍᐏᐣ', 'regional' => ''],
//'km' => ['name' => 'Khmer', 'script' => 'Khmr', 'native' => 'ភាសាខ្មែរ', 'regional' => 'km_KH'],
//'mn-Mong' => ['name' => 'Mongolian (Mongolian)', 'script' => 'Mong', 'native' => 'ᠮᠣᠨᠭᠭᠣᠯ ᠬᠡᠯᠡ', 'regional' => 'mn_MN'],
//'shi-Tfng' => ['name' => 'Tachelhit (Tifinagh)', 'script' => 'Tfng', 'native' => 'ⵜⴰⵎⴰⵣⵉⵖⵜ', 'regional' => ''],
//'tzm' => ['name' => 'Central Atlas Tamazight (Tifinagh)','script' => 'Tfng', 'native' => 'ⵜⴰⵎⴰⵣⵉⵖⵜ', 'regional' => ''],
//'yue' => ['name' => 'Yue', 'script' => 'Hant', 'native' => '廣州話', 'regional' => 'yue_HK'],
//'ja' => ['name' => 'Japanese', 'script' => 'Jpan', 'native' => '日本語', 'regional' => 'ja_JP'],
//'zh' => ['name' => 'Chinese (Simplified)', 'script' => 'Hans', 'native' => '简体中文', 'regional' => 'zh_CN'],
//'zh-Hant' => ['name' => 'Chinese (Traditional)', 'script' => 'Hant', 'native' => '繁體中文', 'regional' => 'zh_CN'],
//'ii' => ['name' => 'Sichuan Yi', 'script' => 'Yiii', 'native' => 'ꆈꌠꉙ', 'regional' => ''],
//'vai' => ['name' => 'Vai (Vai)', 'script' => 'Vaii', 'native' => 'ꕙꔤ', 'regional' => ''],
//'jv-Java' => ['name' => 'Javanese (Javanese)', 'script' => 'Java', 'native' => 'ꦧꦱꦗꦮ', 'regional' => ''],
//'ko' => ['name' => 'Korean', 'script' => 'Hang', 'native' => '한국어', 'regional' => 'ko_KR'],
],
// Requires middleware `LaravelSessionRedirect.php`.
//
// Automatically determine locale from browser (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language)
// on first call if it's not defined in the URL. Redirect user to computed localized url.
// For example, if users browser language is `de`, and `de` is active in the array `supportedLocales`,
// the `/about` would be redirected to `/de/about`.
//
// The locale will be stored in session and only be computed from browser
// again if the session expires.
//
// If false, system will take app.php locale attribute
'useAcceptLanguageHeader' => true,
// If `hideDefaultLocaleInURL` is true, then a url without locale
// is identical with the same url with default locale.
// For example, if `en` is default locale, then `/en/about` and `/about`
// would be identical.
//
// If in addition the middleware `LaravelLocalizationRedirectFilter` is active, then
// every url with default locale is redirected to url without locale.
// For example, `/en/about` would be redirected to `/about`.
// It is recommended to use `hideDefaultLocaleInURL` only in
// combination with the middleware `LaravelLocalizationRedirectFilter`
// to avoid duplicate content (SEO).
//
// If `useAcceptLanguageHeader` is true, then the first time
// the locale will be determined from browser and redirect to that language.
// After that, `hideDefaultLocaleInURL` behaves as usual.
'hideDefaultLocaleInURL' => true,
// If you want to display the locales in particular order in the language selector you should write the order here.
//CAUTION: Please consider using the appropriate locale code otherwise it will not work
//Example: 'localesOrder' => ['es','en'],
'localesOrder' => [],
// If you want to use custom lang url segments like 'at' instead of 'de-AT', you can use the mapping to tallow the LanguageNegotiator to assign the descired locales based on HTTP Accept Language Header. For example you want ot use 'at', so map HTTP Accept Language Header 'de-AT' to 'at' (['de-AT' => 'at']).
'localesMapping' => [],
// Locale suffix for LC_TIME and LC_MONETARY
// Defaults to most common ".UTF-8". Set to blank on Windows systems, change to ".utf8" on CentOS and similar.
'utf8suffix' => env('LARAVELLOCALIZATION_UTF8SUFFIX', '.UTF-8'),
// URLs which should not be processed, e.g. '/nova', '/nova/*', '/nova-api/*' or specific application URLs
// Defaults to []
'urlsIgnored' => ['/skipped'],
];

114
config/ldap.php Normal file
View File

@ -0,0 +1,114 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Default LDAP Connection Name
|--------------------------------------------------------------------------
|
| Here you may specify which of the LDAP connections below you wish
| to use as your default connection for all LDAP operations. Of
| course you may add as many connections you'd like below.
|
*/
'default' => env('LDAP_CONNECTION', 'default'),
/*
|--------------------------------------------------------------------------
| LDAP Connections
|--------------------------------------------------------------------------
|
| Below you may configure each LDAP connection your application requires
| access to. Be sure to include a valid base DN - otherwise you may
| not receive any results when performing LDAP search operations.
|
*/
'connections' => [
'default' => [
'hosts' => [env('LDAP_HOST', '127.0.0.1')],
'username' => env('LDAP_USERNAME', 'cn=user,dc=local,dc=com'),
'password' => env('LDAP_PASSWORD', 'secret'),
'port' => env('LDAP_PORT', 389),
'base_dn' => env('LDAP_BASE_DN', 'dc=local,dc=com'),
'timeout' => env('LDAP_TIMEOUT', 5),
'use_ssl' => env('LDAP_SSL', false),
'use_tls' => env('LDAP_TLS', false),
'name' => env('LDAP_NAME','LDAP Server'),
],
],
/*
|--------------------------------------------------------------------------
| LDAP Logging
|--------------------------------------------------------------------------
|
| When LDAP logging is enabled, all LDAP search and authentication
| operations are logged using the default application logging
| driver. This can assist in debugging issues and more.
|
*/
'logging' => env('LDAP_LOGGING', true),
/*
|--------------------------------------------------------------------------
| LDAP Cache
|--------------------------------------------------------------------------
|
| LDAP caching enables the ability of caching search results using the
| query builder. This is great for running expensive operations that
| may take many seconds to complete, such as a pagination request.
|
*/
'cache' => [
'enabled' => env('LDAP_CACHE', false),
'driver' => env('CACHE_DRIVER', 'file'),
'time' => env('LDAP_CACHE_TIME',5*60), // Seconds
],
/*
|--------------------------------------------------------------------------
| Support for attrs display order
|--------------------------------------------------------------------------
|
| Use this array if you want to have your attributes displayed in a specific
| order. Case is not important.
|
| For example, "sn" will be displayed right after "givenName". All the other
| attributes that are not specified in this array will be displayed after in
| alphabetical order.
|
*/
'attr_display_order' => [],
/*
'attr_display_order' => [
'givenName',
'sn',
'cn',
'displayName',
'uid',
'uidNumber',
'gidNumber',
'homeDirectory',
'mail',
'userPassword'
],
*/
/*
|--------------------------------------------------------------------------
| Custom Date Format
|--------------------------------------------------------------------------
|
| Configuration to determine how date fields will be displayed.
|
*/
'datetime_format' => 'Y-m-d H:i:s',
];

View File

@ -0,0 +1,190 @@
# If you find some reliable and more meaningful descriptions to these OIDS,
# then please let the phpldapadmin development know so that this file can be
# more descriptive.
# Format
# OID:Title:RFC Ref:Detail
1.2.826.0.1.334810.2.3:LDAP_CONTROL_VALUESRETURNFILTER
1.2.826.0.1.3344810.2.3:Matched Values Control:RFC 3876:Describes a control for the LDAP v3 that is used to return a subset of attribute values from an entry. Specifically, only those values that match a 'values return' filter. Without support for this control, a client must retrieve all of an attribute's values and search for specific values locally.
1.2.826.0.1050.11.1.1:Read-Only LDAP Server
1.2.826.0.1050.11.2.1:Read-Write LDAP Server
1.2.826.0.1050.11.3.1:White Pages Application LDAP Server
1.2.826.0.1050.11.4.1:Certificate Application LDAP Server
1.2.826.0.1050.11.5.1:Single Sign On Application LDAP Server
1.2.840.113549.6.0.0:Signed Operation
1.2.840.113549.6.0.1:Demand Signed Result
1.2.840.113549.6.0.2:Signed Result RFC 2649
1.2.840.113556.1.4.319:Simple Paged Results Manipulation Control Extension:RFC 2696:This control extension allows a client to control the rate at which an LDAP server returns the results of an LDAP search operation. This control may be useful when the LDAP client has limited resources and may not be able to process the entire result set from a given LDAP query, or when the LDAP client is connected over a low-bandwidth connection.
1.2.840.113556.1.4.417:Show deleted control::The LDAP_SERVER_SHOW_DELETED_OID control is used with an extended LDAP search function to specify that the search results include any deleted objects that match the search filter.
1.2.840.113556.1.4.473:LDAP Server Sort Result extension:draft-ietf-ldapext-sorting-01:This control is included in the searchRequest message as part of the controls field of the LDAPMessage.
1.2.840.113556.1.4.474:LDAP Server Sort Result extension response control::This control is included in the searchResultDone message as part of the controls field of the LDAPMessage
1.2.840.113556.1.4.521:Cross-domain move control::The LDAP_SERVER_CROSSDOM_MOVE_TARGET_OID control is used with an extended LDAP rename function to move an LDAP object from one domain to another. The control specifies the DNS hostname of the domain controller in the destination domain.
1.2.840.113556.1.4.528:Server search notification control::The LDAP_SERVER_NOTIFICATION_OID control is used with an extended LDAP asynchronous search function to register the client to be notified when changes are made to an object in Active Directory.
1.2.840.113556.1.4.529:Extended DN control::The LDAP_SERVER_EXTENDED_DN_OID control is used with an extended LDAP search function to request an extended form of an Active Directory object distinguished name. The extended form includes a string representation of the object objectGUID property. For security principal objects such as users, groups, and computers, the extended form also includes a string representation of the object objectSID property.
1.2.840.113556.1.4.616:LDAP_CONTROL_REFERRALS
1.2.840.113556.1.4.619:Lazy commit control::The LDAP_SERVER_LAZY_COMMIT_OID control is used to instruct the server to return the results of a DS modification command, such as add, delete, or replace, after it has been completed in memory, but before it has been committed to disk. The server can then return results quickly, and save the data to disk without holding the client.
1.2.840.113556.1.4.800:LDAP_CAP_ACTIVE_DIRECTORY_OID::This is an Actrive Directory Server (Win2k and later).
1.2.840.113556.1.4.801:Security descriptor flags control::The LDAP_SERVER_SD_FLAGS_OID control is used to pass flags to the server to control various security descriptor results.
1.2.840.113556.1.4.802:Attribute Range Option::Server supports the Range property enabling clients to incremental retrieve values from multivalue attributes.
1.2.840.113556.1.4.803:LDAP_MATCHING_RULE_BIT_AND
1.2.840.113556.1.4.804:LDAP_MATCHING_RULE_BIT_OR
1.2.840.113556.1.4.805:Tree Delete::The LDAP_SERVER_TREE_DELETE_OID control is used with an extended LDAP delete function to delete an entire subtree in the directory.
1.2.840.113556.1.4.841:Directory synchronization control::The LDAP_SERVER_DIRSYNC_OID control enables an application to search the directory for objects changed from a previous state. It is also used with the extended LDAP search functions such as ldap_search_ext.
1.2.840.113556.1.4.906:Microsoft Large Integer
1.2.840.113556.1.4.970:Get stats control (Stateless)
1.2.840.113556.1.4.1302:Microsoft OID used with DEN Attributes
1.2.840.113556.1.4.1338:Verify name control::The LDAP_SERVER_VERIFY_NAME_OID control is used with extended LDAP add and modify requests to instruct the DC accepting the update which DC it should verify with, the existence of any DN attribute values.
1.2.840.113556.1.4.1339:LDAP_SERVER_DOMAIN_SCOPE_OID::The LDAP_SERVER_DOMAIN_SCOPE_OID control is used to instruct the LDAP server not to generate any referrals when completing a request. This control also limits any search using it to a single naming context.
1.2.840.113556.1.4.1340:Search options control:: The LDAP_SERVER_SEARCH_OPTIONS_OID control is used to pass flags to the server to control various search behaviors.
1.2.840.113556.1.4.1413:LDAP ease modify restrictions::Allows an LDAP modify to work under less restrictive conditions. Without it, a delete will fail if an attribute does not exist, and an add will fail if an attribute already exists.
1.2.840.113556.1.4.1504:Attribute scoped query control::The LDAP_SERVER_ASQ_OID control is used with an extended LDAP search function to force the query to be based on a specific DN-valued attribute. Only one source attribute can be specified with this control and the search request is limited to base object scoped queries.
1.2.840.113556.1.4.1670:LDAP_CAP_ACTIVE_DIRECTORY_V51_OID::This server is a Whistler Active Directory server (Win2k3 and later).
1.2.840.113556.1.4.1781:Fast concurrent bind extended operation::The Microsoft LDAP API will send an extended request with this name to Active Directory to request that all binds on this connection be processed as 'fast' binds.
1.2.840.113556.1.4.1791:LDAP_CAP_ACTIVE_DIRECTORY_LDAP_INTEG_OID::LDAP server is capable of doing signing and sealing on an NTLM authenticated connection, and that the server is capable of performing subsequent binds on a signed or sealed connection.
1.2.840.113556.1.4.1852:LDAP_SERVER_QUOTA_CONTROL_OID::The LDAP_SERVER_QUOTA_CONTROL_OID control is used to pass the SID of a security principal, whose quota is being queried, to the server in a LDAP search operation.
1.3.6.1.1.7.1:LCUP Sync Request Control. RFC 3928 control
1.3.6.1.1.7.2:LCUP Sync Update Control. RFC 3928 control
1.3.6.1.1.7.3:LCUP Sync Done Control. RFC 3928 control
1.3.6.1.1.8:Cancel Operation. RFC 3909 extension
1.3.6.1.1.12:Assertion Control:RFC 4511:The assertion control allows the client to specify a condition that must be true for the operation to be processed normally.
1.3.6.1.1.13.1:Pre-Read Controls::The Pre-Read request control, indicates that a copy of the entry before application of update is to be returned.
1.3.6.1.1.13.2:Post-Read Controls::The Pre-Read request control, indicates that a copy of the entry before application of update is to be returned.
1.3.6.1.1.14:Modify-Increment Extension:RFC 4525:An extension to the Lightweight Directory Access Protocol (LDAP) Modify operation to support an increment capability.
1.3.6.1.1.22:Dont Use Copy Control:RFC 6171:When the control is attached to an LDAP request, the requested operation MUST NOT be performed on copied information. That is, the requested operation MUST be performed on original information.
1.3.6.1.4.1.42.2.27.8.5.1:passwordPolicyRequest
1.3.6.1.4.1.42.2.27.9.5.2:GetEffectiveRights control::May be used to determine what operations a given user may perform on a specified entry.
1.3.6.1.4.1.1466.101.119.1:Dynamic Directory Services Refresh Request:RFC 2589
1.3.6.1.4.1.1466.20036:LDAP_NOTICE_OF_DISCONNECTION
1.3.6.1.4.1.1466.20037:Transport Layer Security Extension:RFC 2830:This operation provides for TLS establishment in an LDAP association and is defined in terms of an LDAP extended request.
1.3.6.1.4.1.1466.29539.1:LDAP_CONTROL_ATTR_SIZELIMIT
1.3.6.1.4.1.1466.29539.2:LDAP_CONTROL_NO_COPY
1.3.6.1.4.1.1466.29539.3:LDAP_CONTROL_PARTIAL_COPY
1.3.6.1.4.1.1466.29539.5:LDAP_CONTROL_NO_CHAINING
1.3.6.1.4.1.1466.29539.7:LDAP_CONTROL_ALIAS_ON_UPDATE
1.3.6.1.4.1.1466.29539.10:LDAP_CONTROL_TRIGGER
1.3.6.1.4.1.1466.29539.12:nsTransmittedControl
1.3.6.1.4.1.4203.1.5.1:All Operational Attribute:RFC 3673:An LDAP extension which clients may use to request the return of all operational attributes.
1.3.6.1.4.1.4203.1.5.2:Requesting Attributes by Object Class:draft-zeilenga-ldap-adlist-10.txt:Extends LDAP to support a mechanism that LDAP clients may use to request the return of all attributes of an object class.
1.3.6.1.4.1.4203.1.5.3:LDAP Absolute True and False Filters:draft-zeilenga-ldap-t-f-10.txt:Implementations of this extension SHALL allow 'and' and 'or' choices with zero filter elements.
1.3.6.1.4.1.4203.1.5.4:Language Tags:RFC 3866:Supports storing attributes with language tag options in the DIT
1.3.6.1.4.1.4203.1.5.5:Language Ranges:RFC 3866:Supports language range matching of attributes with language tag options stored in the DIT
1.3.6.1.4.1.4203.1.9.1.1:LDAP Content Synchronization Control:draft=zeilenga-ldup-sync-06.txt:The operation allows a client to maintain a copy of a fragment of directory information tree. It supports both polling for changes and listening for changes. The operation is defined as an extension of the LDAP Search Operation.
1.3.6.1.4.1.4203.1.10.1:Subentries in LDAP:RFC 3672:The subentries control MAY be sent with a searchRequest to control the visibility of entries and subentries which are within scope. Non-visible entries or subentries are not returned in response to the request.
1.3.6.1.4.1.4203.1.10.2:LDAP No-Op Control:draft-zeilenga-ldap-noop-02.txt:The No-Op control can be used to disable the normal effect of an operation. The control can be used to discover how a server might react to a particular update request without updating the directory.
1.3.6.1.4.1.4203.1.11.1:LDAP Password Modify Extended Operation:RFC 3062:An LDAP extended operation to allow modification of user passwords which is not dependent upon the form of the authentication identity nor the password storage mechanism used.
1.3.6.1.4.1.4203.1.11.2:LDAP Cancel Extended Operation
1.3.6.1.4.1.4203.1.11.3:Who Am I? Extended Operation:draft-zeilenga-ldap-authzid-10.txt:This specification provides a mechanism for Lightweight Directory Access Protocol (LDAP) clients to obtain the authorization identity which the server has associated with the user or application entity.
1.3.6.1.4.1.4203.666.5.1:Subentries Control
1.3.6.1.4.1.4203.666.5.2:NO OP Control
1.3.18.0.2.12.1:The ACL credential controls provide a method to flow a subject's credentials associated with a bind.
1.3.18.0.2.12.5:tranExtOpInit
1.3.18.0.2.12.6:tranExtOpInit
2.16.840.1.113531.18.2.1:LDAP_C_SETOPTIONS_OID
2.16.840.1.113531.18.2.2:LDAP_C_SETDONTUSECOPY_OID
2.16.840.1.113531.18.2.3:LDAP_C_SETLOCALSCOPE_OID
2.16.840.1.113531.18.2.4:Return operational attributes as well as user attributes
2.16.840.1.113531.18.2.5:Return only subentries
2.16.840.1.113531.18.2.6:LDAP_C_SETUSEALIAS_OID
2.16.840.1.113531.18.2.7:LDAP_C_SETPREFERCHAIN_OID
2.16.840.1.113531.18.2.8:LDAP_C_SETX500DN_OID
2.16.840.1.113531.18.2.9:LDAP_C_SETCOPYSHALLDO_OID
2.16.840.1.113531.18.2.10:LDAP_C_SETDONTMAPATTRS_OID
2.16.840.1.113531.18.2.11:Return normal entries as well as sub-entries
2.16.840.1.113719.1.27.99.1:Superior References
2.16.840.1.113719.1.27.100.1:ndsToLdapResponse
2.16.840.1.113719.1.27.100.2:ndsToLdapRequest
2.16.840.1.113719.1.27.100.3:createNamingContextRequest
2.16.840.1.113719.1.27.100.4:createNamingContextResponse
2.16.840.1.113719.1.27.100.5:mergeNamingContextRequest
2.16.840.1.113719.1.27.100.6:mergeNamingContextResponse
2.16.840.1.113719.1.27.100.7:addReplicaRequest
2.16.840.1.113719.1.27.100.8:addReplicaResponse
2.16.840.1.113719.1.27.100.9:refreshLDAPServerRequest
2.16.840.1.113719.1.27.100.10:refreshLDAPServerResponse
2.16.840.1.113719.1.27.100.11:removeReplicaRequest
2.16.840.1.113719.1.27.100.12:removeReplicaResponse
2.16.840.1.113719.1.27.100.13:namingContextEntryCountRequest
2.16.840.1.113719.1.27.100.14:namingContextEntryCountResponse
2.16.840.1.113719.1.27.100.15:changeReplicaTypeRequest
2.16.840.1.113719.1.27.100.16:changeReplicaTypeResponse
2.16.840.1.113719.1.27.100.17:getReplicaInfoRequest
2.16.840.1.113719.1.27.100.18:getReplicaInfoResponse
2.16.840.1.113719.1.27.100.19:listReplicaRequest
2.16.840.1.113719.1.27.100.20:listReplicaResponse
2.16.840.1.113719.1.27.100.21:receiveAllUpdatesRequest
2.16.840.1.113719.1.27.100.22:receiveAllUpdatesResponse
2.16.840.1.113719.1.27.100.23:sendAllUpdatesRequest
2.16.840.1.113719.1.27.100.24:sendAllUpdatesResponse
2.16.840.1.113719.1.27.100.25:requestNamingContextSyncRequest
2.16.840.1.113719.1.27.100.26:requestNamingContextSyncResponse
2.16.840.1.113719.1.27.100.27:requestSchemaSyncRequest
2.16.840.1.113719.1.27.100.28:requestSchemaSyncResponse
2.16.840.1.113719.1.27.100.29:abortNamingContextOperationRequest
2.16.840.1.113719.1.27.100.30:abortNamingContextOperationResponse
2.16.840.1.113719.1.27.100.31:Get Bind DN Request
2.16.840.1.113719.1.27.100.32:Get Bind DN Response
2.16.840.1.113719.1.27.100.33:Get Effective Privileges Request
2.16.840.1.113719.1.27.100.34:Get Effective Privileges Response
2.16.840.1.113719.1.27.100.35:Set Replication Filter Request
2.16.840.1.113719.1.27.100.36:Set Replication Filter Response
2.16.840.1.113719.1.27.100.37:Get Replication Filter Request
2.16.840.1.113719.1.27.100.38:Get Replication Filter Response
2.16.840.1.113719.1.27.100.39:Create Orphan Partition Request
2.16.840.1.113719.1.27.100.40:Create Orphan Partition Response
2.16.840.1.113719.1.27.100.41:Remove Orphan Partition Request
2.16.840.1.113719.1.27.100.42:Remove Orphan Partition Response
2.16.840.1.113719.1.27.100.43:Trigger Backlinker Request
2.16.840.1.113719.1.27.100.44:Trigger Backlinker Response
2.16.840.1.113719.1.27.100.47:Trigger Janitor Request
2.16.840.1.113719.1.27.100.48:Trigger Janitor Response
2.16.840.1.113719.1.27.100.49:Trigger Limber Request
2.16.840.1.113719.1.27.100.50:Trigger Limber Response
2.16.840.1.113719.1.27.100.51:Trigger Skulker Request
2.16.840.1.113719.1.27.100.52:Trigger Skulker Response
2.16.840.1.113719.1.27.100.53:Trigger Schema Synch Request
2.16.840.1.113719.1.27.100.54:Trigger Schema Synch Response
2.16.840.1.113719.1.27.100.55:Trigger Partition Purge Request
2.16.840.1.113719.1.27.100.56:Trigger Partition Purge Response
2.16.840.1.113719.1.27.100.79:Monitor Events Request
2.16.840.1.113719.1.27.100.80:Monitor Events Response
2.16.840.1.113719.1.27.100.81:Event Notification
2.16.840.1.113719.1.27.101.1:Duplicate Entry Request
2.16.840.1.113719.1.27.101.2:DuplicateSearchResult
2.16.840.1.113719.1.27.101.3:DuplicateEntryResponseDone
2.16.840.1.113719.1.27.101.5:Simple Password
2.16.840.1.113719.1.27.101.6:Forward Reference
2.16.840.1.113719.1.142.100.1:startFramedProtocolRequest
2.16.840.1.113719.1.142.100.2:startFramedProtocolResponse
2.16.840.1.113719.1.142.100.3:ReplicationUpdate
2.16.840.1.113719.1.142.100.4:endFramedProtocolRequest
2.16.840.1.113719.1.142.100.5:endFramedProtocolResponse
2.16.840.1.113719.1.142.100.6:lburpOperationRequest
2.16.840.1.113719.1.142.100.7:lburpOperationResponse
2.16.840.1.113730.3.4:Netscape LDAPv3 controls
2.16.840.1.113730.3.4.2:ManageDsaIT Control:RFC 3296:The client may provide the ManageDsaIT control with an operation to indicate that the operation is intended to manage objects within the DSA (server) Information Tree. The control causes Directory-specific entries (DSEs), regardless of type, to be treated as normal entries allowing clients to interrogate and update these entries using LDAP operations.
2.16.840.1.113730.3.4.3:Persistent Search LDAPv3 control
2.16.840.1.113730.3.4.4:Netscape Password Expired LDAPv3 control
2.16.840.1.113730.3.4.5:Netscape Password Expiring LDAPv3 control
2.16.840.1.113730.3.4.6:Netscape NT Synchronization Client LDAPv3 control
2.16.840.1.113730.3.4.7:Entry Change Notification LDAPv3 control
2.16.840.1.113730.3.4.8:Transaction ID Request Control
2.16.840.1.113730.3.4.9:VLV Request LDAPv3 control::As defined in the 'LDAPv3 Extensions for Virtual List View' IETF document.
2.16.840.1.113730.3.4.10:VLV Response LDAPv3 control::As defined in the 'LDAPv3 Extensions for Virtual List View' IETF document.
2.16.840.1.113730.3.4.11:Transaction ID Response Control
2.16.840.1.113730.3.4.12:Proxied Authorization (version 1) control:draft-weltman-ldapv3-proxy-05:For assuming the identity of another entry for the duration of a request. This has been replaced by a new 'version 2' Proxied Authorization control.
2.16.840.1.113730.3.4.13:iPlanet Directory Server Replication Update Information Control
2.16.840.1.113730.3.4.14:iPlanet Directory Server 'search on specific backend' control
2.16.840.1.113730.3.4.15:Authentication Response Control
2.16.840.1.113730.3.4.16:Authentication Request Control
2.16.840.1.113730.3.4.17:Real Attributes Only Request Control
2.16.840.1.113730.3.4.18:LDAP Proxied Authorization Control:draft-weltman-ldapv3-proxy-06.txt:The Proxied Authorization Control allows a client to request that an operation be processed under a provided authorization identity [AUTH] instead of as the current authorization identity associated with the connection.
2.16.840.1.113730.3.4.19:Virtual Attributes Only Request Control
2.16.840.1.113730.3.4.20:Use One Backend
2.16.840.1.113730.3.4.999:iPlanet Replication Modrdn Extra Mods Control
2.16.840.1.113730.3.5.3:iPlanet Start Replication Request Extended Operation
2.16.840.1.113730.3.5.4:iPlanet Replication Response Extended Operation
2.16.840.1.113730.3.5.5:iPlanet End Replication Request Extended Operation
2.16.840.1.113730.3.5.6:iPlanet Replication Entry Request Extended Operation
2.16.840.1.113730.3.5.7:iPlanet Bulk Import Start Extended Operation
2.16.840.1.113730.3.5.8:iPlanet Bulk Import Finished Extended Operation
2.16.840.1.113730.3.5.9:iPlanet Digest authentication calculation

View File

@ -0,0 +1,16 @@
# If you find some reliable and more meaningful descriptions to these SASL Mechanisms,
# then please let the phpldapadmin development know so that this file can be
# more descriptive.
# Format
# Mechanisms:Title:RFC Ref:Detail
SCRAM-SHA-1:Salted Challenge Response Authentication Mechanism (SCRAM) SHA1:RFC 5802:This specification describes a family of authentication mechanisms called the Salted Challenge Response Authentication Mechanism (SCRAM) which addresses the requirements necessary to deploy a challenge- response mechanism more widely than past attempts.
SCRAM-SHA-256:Salted Challenge Response Authentication Mechanism (SCRAM) SHA256:RFC 7677:The SCRAM-SHA-256 and SCRAM-SHA-256-PLUS SASL mechanisms are defined in the same way that SCRAM-SHA-1 and SCRAM-SHA-1-PLUS are defined in [RFC5802], except that the hash function for HMAC() and H() uses SHA-256 instead of SHA-1 [RFC6234].
GS2-IAKERB:Initial and Pass Through Authentication Using Kerberos V5 and the GSS-API:draft-ietf-krb-wg-iakerb-02:Extends [RFC4120] and [RFC4121] such that the client can communicate with the KDC using a Generic Security Service Application Program Interface (GSS-API) [RFC2743] acceptor as the proxy.
GS2-KRB5:Family of mechanisms supports arbitrary GSS-API mechanisms in SASL::GS2 is a protocol bridge between GSS-API and SASL, and allows every GSS-API mechanism that supports mutual authentication and channel bindings to be used as a SASL mechanism. This implements Kerberos V5 authentication.
GSSAPI:Generic Security Services Application Program Interface:RFC 2744:The Generic Security Service Application Program Interface (GSSAPI, also GSS-API) is an application programming interface for programs to access security services.
GSS-SPNEGO:GSS-SPNEGO security mechanism for LDAP bind requests:RFC 4178:The DC accepts the GSS-SPNEGO security mechanism for LDAP bind requests. This mechanism is documented in [RFC4178]. Active Directory supports Kerberos (see [MS-KILE]) and NTLM (see [MS-NLMP]) when using GSS-SPNEGO.
DIGEST-MD5:HTTP Digest compatible (partially) challenge-response scheme based upon MD5, offering a data security layer:RFC 2831:In Digest-MD5, the LDAP server sends data that includes various authentication options that it is willing to support plus a special token to the LDAP client. The client responds by sending an encrypted response that indicates the authentication options that it has selected. The response is encrypted in such a way that proves that the client knows its password. The LDAP server then decrypts and verifies the client's response.
OTP:One-Time Password Mechanism:RFC 2444:
CRAM-MD5:Simple challenge-response scheme based on HMAC-MD5:RFC 2195:When using the CRAM-MD5 mechanism, the LDAP server sends some data to the LDAP client. The client responds by encrypting the data with its password by using the MD5 algorithm. The LDAP server then uses the client's stored password to determine whether the client used the right password.
NTLM:MS Windows NT LAN Manager authentication mechanism:MS Proprietary:

122
config/logging.php Normal file
View File

@ -0,0 +1,122 @@
<?php
use Monolog\Handler\NullHandler;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\SyslogUdpHandler;
return [
/*
|--------------------------------------------------------------------------
| Default Log Channel
|--------------------------------------------------------------------------
|
| This option defines the default log channel that gets used when writing
| messages to the logs. The name specified in this option should match
| one of the channels defined in the "channels" configuration array.
|
*/
'default' => env('LOG_CHANNEL', 'stack'),
/*
|--------------------------------------------------------------------------
| Deprecations Log Channel
|--------------------------------------------------------------------------
|
| This option controls the log channel that should be used to log warnings
| regarding deprecated PHP and library features. This allows you to get
| your application ready for upcoming major versions of dependencies.
|
*/
'deprecations' => [
'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'),
'trace' => false,
],
/*
|--------------------------------------------------------------------------
| Log Channels
|--------------------------------------------------------------------------
|
| Here you may configure the log channels for your application. Out of
| the box, Laravel uses the Monolog PHP logging library. This gives
| you a variety of powerful log handlers / formatters to utilize.
|
| Available Drivers: "single", "daily", "slack", "syslog",
| "errorlog", "monolog",
| "custom", "stack"
|
*/
'channels' => [
'stack' => [
'driver' => 'stack',
'channels' => ['daily'],
'ignore_exceptions' => false,
],
'single' => [
'driver' => 'single',
'path' => storage_path('logs/laravel.log'),
'level' => env('LOG_LEVEL', 'debug'),
],
'daily' => [
'driver' => 'daily',
'path' => storage_path('logs/laravel.log'),
'level' => env('LOG_LEVEL', 'debug'),
'days' => 14,
],
'slack' => [
'driver' => 'slack',
'url' => env('LOG_SLACK_WEBHOOK_URL'),
'username' => 'Laravel Log',
'emoji' => ':boom:',
'level' => env('LOG_LEVEL', 'critical'),
],
'papertrail' => [
'driver' => 'monolog',
'level' => env('LOG_LEVEL', 'debug'),
'handler' => env('LOG_PAPERTRAIL_HANDLER', SyslogUdpHandler::class),
'handler_with' => [
'host' => env('PAPERTRAIL_URL'),
'port' => env('PAPERTRAIL_PORT'),
'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'),
],
],
'stderr' => [
'driver' => 'monolog',
'level' => env('LOG_LEVEL', 'debug'),
'handler' => StreamHandler::class,
'formatter' => env('LOG_STDERR_FORMATTER'),
'with' => [
'stream' => 'php://stderr',
],
],
'syslog' => [
'driver' => 'syslog',
'level' => env('LOG_LEVEL', 'debug'),
],
'errorlog' => [
'driver' => 'errorlog',
'level' => env('LOG_LEVEL', 'debug'),
],
'null' => [
'driver' => 'monolog',
'handler' => NullHandler::class,
],
'emergency' => [
'path' => storage_path('logs/laravel.log'),
],
],
];

110
config/mail.php Normal file
View File

@ -0,0 +1,110 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Mailer
|--------------------------------------------------------------------------
|
| This option controls the default mailer that is used to send any email
| messages sent by your application. Alternative mailers may be setup
| and used as needed; however, this mailer will be used by default.
|
*/
'default' => env('MAIL_MAILER', 'smtp'),
/*
|--------------------------------------------------------------------------
| Mailer Configurations
|--------------------------------------------------------------------------
|
| Here you may configure all of the mailers used by your application plus
| their respective settings. Several examples have been configured for
| you and you are free to add your own as your application requires.
|
| Laravel supports a variety of mail "transport" drivers to be used while
| sending an e-mail. You will specify which one you are using for your
| mailers below. You are free to add additional mailers as required.
|
| Supported: "smtp", "sendmail", "mailgun", "ses",
| "postmark", "log", "array"
|
*/
'mailers' => [
'smtp' => [
'transport' => 'smtp',
'host' => env('MAIL_HOST', 'smtp.mailgun.org'),
'port' => env('MAIL_PORT', 587),
'encryption' => env('MAIL_ENCRYPTION', 'tls'),
'username' => env('MAIL_USERNAME'),
'password' => env('MAIL_PASSWORD'),
'timeout' => null,
'auth_mode' => null,
],
'ses' => [
'transport' => 'ses',
],
'mailgun' => [
'transport' => 'mailgun',
],
'postmark' => [
'transport' => 'postmark',
],
'sendmail' => [
'transport' => 'sendmail',
'path' => '/usr/sbin/sendmail -bs',
],
'log' => [
'transport' => 'log',
'channel' => env('MAIL_LOG_CHANNEL'),
],
'array' => [
'transport' => 'array',
],
],
/*
|--------------------------------------------------------------------------
| Global "From" Address
|--------------------------------------------------------------------------
|
| You may wish for all e-mails sent by your application to be sent from
| the same address. Here, you may specify a name and address that is
| used globally for all e-mails that are sent by your application.
|
*/
'from' => [
'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),
'name' => env('MAIL_FROM_NAME', 'Example'),
],
/*
|--------------------------------------------------------------------------
| Markdown Mail Settings
|--------------------------------------------------------------------------
|
| If you are using Markdown based email rendering, you may configure your
| theme and component paths here, allowing you to customize the design
| of the emails. Or, you may simply stick with the Laravel defaults!
|
*/
'markdown' => [
'theme' => 'default',
'paths' => [
resource_path('views/vendor/mail'),
],
],
];

16
config/pla.php Normal file
View File

@ -0,0 +1,16 @@
<?php
return [
/**
* These attributes will be forced to MAY attributes and become optional in the
* templates. If they are not defined in the templates, then they wont appear
* as per normal template processing. You may want to do this because your LDAP
* server may automatically calculate a default value.
*
* In Fedora Directory Server using the DNA Plugin one could ignore uidNumber,
* gidNumber and sambaSID.
*
# 'force_may' => ['uidNumber','gidNumber','sambaSID'],
*/
'force_may' => [],
];

89
config/queue.php Normal file
View File

@ -0,0 +1,89 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Queue Connection Name
|--------------------------------------------------------------------------
|
| Laravel's queue API supports an assortment of back-ends via a single
| API, giving you convenient access to each back-end using the same
| syntax for every one. Here you may define a default connection.
|
*/
'default' => env('QUEUE_CONNECTION', 'sync'),
/*
|--------------------------------------------------------------------------
| Queue Connections
|--------------------------------------------------------------------------
|
| Here you may configure the connection information for each server that
| is used by your application. A default configuration has been added
| for each back-end shipped with Laravel. You are free to add more.
|
| Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null"
|
*/
'connections' => [
'sync' => [
'driver' => 'sync',
],
'database' => [
'driver' => 'database',
'table' => 'jobs',
'queue' => 'default',
'retry_after' => 90,
],
'beanstalkd' => [
'driver' => 'beanstalkd',
'host' => 'localhost',
'queue' => 'default',
'retry_after' => 90,
'block_for' => 0,
],
'sqs' => [
'driver' => 'sqs',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'),
'queue' => env('SQS_QUEUE', 'your-queue-name'),
'suffix' => env('SQS_SUFFIX'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
],
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => env('REDIS_QUEUE', 'default'),
'retry_after' => 90,
'block_for' => null,
],
],
/*
|--------------------------------------------------------------------------
| Failed Queue Jobs
|--------------------------------------------------------------------------
|
| These options configure the behavior of failed queue job logging so you
| can control which database and table are used to store the jobs that
| have failed. You may change them to any database / table you wish.
|
*/
'failed' => [
'driver' => env('QUEUE_FAILED_DRIVER', 'database'),
'database' => env('DB_CONNECTION', 'mysql'),
'table' => 'failed_jobs',
],
];

33
config/services.php Normal file
View File

@ -0,0 +1,33 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Third Party Services
|--------------------------------------------------------------------------
|
| This file is for storing the credentials for third party services such
| as Mailgun, Postmark, AWS and more. This file provides the de facto
| location for this type of information, allowing packages to have
| a conventional file to locate the various service credentials.
|
*/
'mailgun' => [
'domain' => env('MAILGUN_DOMAIN'),
'secret' => env('MAILGUN_SECRET'),
'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'),
],
'postmark' => [
'token' => env('POSTMARK_TOKEN'),
],
'ses' => [
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
],
];

201
config/session.php Normal file
View File

@ -0,0 +1,201 @@
<?php
use Illuminate\Support\Str;
return [
/*
|--------------------------------------------------------------------------
| Default Session Driver
|--------------------------------------------------------------------------
|
| This option controls the default session "driver" that will be used on
| requests. By default, we will use the lightweight native driver but
| you may specify any of the other wonderful drivers provided here.
|
| Supported: "file", "cookie", "database", "apc",
| "memcached", "redis", "dynamodb", "array"
|
*/
'driver' => env('SESSION_DRIVER', 'file'),
/*
|--------------------------------------------------------------------------
| Session Lifetime
|--------------------------------------------------------------------------
|
| Here you may specify the number of minutes that you wish the session
| to be allowed to remain idle before it expires. If you want them
| to immediately expire on the browser closing, set that option.
|
*/
'lifetime' => env('SESSION_LIFETIME', 120),
'expire_on_close' => false,
/*
|--------------------------------------------------------------------------
| Session Encryption
|--------------------------------------------------------------------------
|
| This option allows you to easily specify that all of your session data
| should be encrypted before it is stored. All encryption will be run
| automatically by Laravel and you can use the Session like normal.
|
*/
'encrypt' => false,
/*
|--------------------------------------------------------------------------
| Session File Location
|--------------------------------------------------------------------------
|
| When using the native session driver, we need a location where session
| files may be stored. A default has been set for you but a different
| location may be specified. This is only needed for file sessions.
|
*/
'files' => storage_path('framework/sessions'),
/*
|--------------------------------------------------------------------------
| Session Database Connection
|--------------------------------------------------------------------------
|
| When using the "database" or "redis" session drivers, you may specify a
| connection that should be used to manage these sessions. This should
| correspond to a connection in your database configuration options.
|
*/
'connection' => env('SESSION_CONNECTION', null),
/*
|--------------------------------------------------------------------------
| Session Database Table
|--------------------------------------------------------------------------
|
| When using the "database" session driver, you may specify the table we
| should use to manage the sessions. Of course, a sensible default is
| provided for you; however, you are free to change this as needed.
|
*/
'table' => 'sessions',
/*
|--------------------------------------------------------------------------
| Session Cache Store
|--------------------------------------------------------------------------
|
| While using one of the framework's cache driven session backends you may
| list a cache store that should be used for these sessions. This value
| must match with one of the application's configured cache "stores".
|
| Affects: "apc", "dynamodb", "memcached", "redis"
|
*/
'store' => env('SESSION_STORE', null),
/*
|--------------------------------------------------------------------------
| Session Sweeping Lottery
|--------------------------------------------------------------------------
|
| Some session drivers must manually sweep their storage location to get
| rid of old sessions from storage. Here are the chances that it will
| happen on a given request. By default, the odds are 2 out of 100.
|
*/
'lottery' => [2, 100],
/*
|--------------------------------------------------------------------------
| Session Cookie Name
|--------------------------------------------------------------------------
|
| Here you may change the name of the cookie used to identify a session
| instance by ID. The name specified here will get used every time a
| new session cookie is created by the framework for every driver.
|
*/
'cookie' => env(
'SESSION_COOKIE',
Str::slug(env('APP_NAME', 'laravel'), '_').'_session'
),
/*
|--------------------------------------------------------------------------
| Session Cookie Path
|--------------------------------------------------------------------------
|
| The session cookie path determines the path for which the cookie will
| be regarded as available. Typically, this will be the root path of
| your application but you are free to change this when necessary.
|
*/
'path' => '/',
/*
|--------------------------------------------------------------------------
| Session Cookie Domain
|--------------------------------------------------------------------------
|
| Here you may change the domain of the cookie used to identify a session
| in your application. This will determine which domains the cookie is
| available to in your application. A sensible default has been set.
|
*/
'domain' => env('SESSION_DOMAIN', null),
/*
|--------------------------------------------------------------------------
| HTTPS Only Cookies
|--------------------------------------------------------------------------
|
| By setting this option to true, session cookies will only be sent back
| to the server if the browser has a HTTPS connection. This will keep
| the cookie from being sent to you if it can not be done securely.
|
*/
'secure' => env('SESSION_SECURE_COOKIE'),
/*
|--------------------------------------------------------------------------
| HTTP Access Only
|--------------------------------------------------------------------------
|
| Setting this value to true will prevent JavaScript from accessing the
| value of the cookie and the cookie will only be accessible through
| the HTTP protocol. You are free to modify this option if needed.
|
*/
'http_only' => true,
/*
|--------------------------------------------------------------------------
| Same-Site Cookies
|--------------------------------------------------------------------------
|
| This option determines how your cookies behave when cross-site requests
| take place, and can be used to mitigate CSRF attacks. By default, we
| will set this value to "lax" since this is a secure default value.
|
| Supported: "lax", "strict", "none", null
|
*/
'same_site' => 'lax',
];

36
config/view.php Normal file
View File

@ -0,0 +1,36 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| View Storage Paths
|--------------------------------------------------------------------------
|
| Most templating systems load templates from disk. Here you may specify
| an array of paths that should be checked for your views. Of course
| the usual Laravel view path has already been registered for you.
|
*/
'paths' => [
resource_path('views'),
],
/*
|--------------------------------------------------------------------------
| Compiled View Path
|--------------------------------------------------------------------------
|
| This option determines where all the compiled Blade templates will be
| stored for your application. Typically, this is within the storage
| directory. However, as usual, you are free to change this value.
|
*/
'compiled' => env(
'VIEW_COMPILED_PATH',
realpath(storage_path('framework/views'))
),
];

2
database/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.sqlite
*.sqlite-journal

View File

@ -0,0 +1,30 @@
<?php
/** @var \Illuminate\Database\Eloquent\Factory $factory */
use App\User;
use Faker\Generator as Faker;
use Illuminate\Support\Str;
/*
|--------------------------------------------------------------------------
| Model Factories
|--------------------------------------------------------------------------
|
| This directory should contain each of the model factory definitions for
| your application. Factories provide a convenient way to generate new
| model instances for testing / seeding your application's database.
|
*/
/*
$factory->define(User::class, function (Faker $faker) {
return [
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
'remember_token' => Str::random(10),
];
});
*/

View File

@ -0,0 +1,16 @@
<?php
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* @return void
*/
public function run()
{
// $this->call(UserSeeder::class);
}
}

View File

@ -1,18 +0,0 @@
#!/bin/sh
for i in $(grep directory phpldapadmin-demo.conf|awk '{print $2}'); do
if [ -d $i ]; then
rm -f $i/*.dbb $i/*.bdb $i/__db.??? $i/alock $i/log.*
else
mkdir $i
fi
done
slapadd -b "dc=example.com" -l ldif-example.com
slapadd -b "dc=example,dc=com" -l ldif-example-com
slapadd -b "o=Simpsons" -l ldif-Simpsons
slapadd -b "o=Flintstones" -l ldif-Flintstones
for i in $(grep directory phpldapadmin-demo.conf|awk '{print $2}'); do
chown -R ldap:ldap $i
done

View File

@ -1,165 +0,0 @@
# LDIF Export for dc=example.com
# Server: C5: OpenLDAP 2.3.27: config (c5dev.leenooks.vpn)
# Search Scope: sub
# Search Filter: (objectClass=*)
# Total Entries: 23
#
# Generated by phpLDAPadmin (http://phpldapadmin.sourceforge.net) on April 26, 2011 9:13 pm
# Version: 1.2.0.5
#version: 1
# Entry 1: dc=example.com
dn: dc=example.com
dc: example.com
objectclass: dNSDomain
# Entry 2: cn=group,dc=example.com
dn: cn=group,dc=example.com
cn: group
gidnumber: 100
objectclass: posixGroup
objectclass: top
# Entry 3: ou=Bad DNs,dc=example.com
dn: ou=Bad DNs,dc=example.com
objectclass: organizationalUnit
ou: Bad DNs
# Entry 4: c=double plus \2B\2B,ou=Bad DNs,dc=example.com
dn: c=double plus \2B\2B,ou=Bad DNs,dc=example.com
c: double plus ++
objectclass: country
# Entry 5: c=end dollar$,ou=Bad DNs,dc=example.com
dn: c=end dollar$,ou=Bad DNs,dc=example.com
c: end dollar$
objectclass: country
# Entry 6: sn=sign@at+uid=multi-mixed,ou=Bad DNs,dc=example.com
dn: sn=sign@at+uid=multi-mixed,ou=Bad DNs,dc=example.com
cn: Test
objectclass: inetOrgPerson
sn: sign@at
uid: multi-mixed
# Entry 7: uid=angle\3Cleft,ou=Bad DNs,dc=example.com
dn: uid=angle\3Cleft,ou=Bad DNs,dc=example.com
cn: Test
objectclass: inetOrgPerson
sn: Test
uid: angle<left
# Entry 8: uid=angle\3Eright,ou=Bad DNs,dc=example.com
dn: uid=angle\3Eright,ou=Bad DNs,dc=example.com
cn: Test
objectclass: inetOrgPerson
sn: Test
uid: angle>right
# Entry 9: uid=brace(left,ou=Bad DNs,dc=example.com
dn: uid=brace(left,ou=Bad DNs,dc=example.com
cn: Test
objectclass: inetOrgPerson
sn: Test
uid: brace(left
# Entry 10: uid=brace)right,ou=Bad DNs,dc=example.com
dn: uid=brace)right,ou=Bad DNs,dc=example.com
cn: Test
objectclass: inetOrgPerson
sn: Test
uid: brace)right
# Entry 11: uid=colon:full,ou=Bad DNs,dc=example.com
dn: uid=colon:full,ou=Bad DNs,dc=example.com
cn: Test
objectclass: inetOrgPerson
sn: Test
uid: colon:full
# Entry 12: uid=colon\3Bsemi,ou=Bad DNs,dc=example.com
dn: uid=colon\3Bsemi,ou=Bad DNs,dc=example.com
cn: Test
objectclass: inetOrgPerson
sn: Test
uid: colon;semi
# Entry 13: uid=multi+uid=sign@at,ou=Bad DNs,dc=example.com
dn: uid=multi+uid=sign@at,ou=Bad DNs,dc=example.com
cn: Test
objectclass: inetOrgPerson
sn: Test
uid: multi
uid: sign@at
# Entry 14: uid=multi+uid=value,ou=Bad DNs,dc=example.com
dn: uid=multi+uid=value,ou=Bad DNs,dc=example.com
cn: Test
objectclass: inetOrgPerson
sn: Test
uid: multi
uid: value
# Entry 15: uid=quote\22double,ou=Bad DNs,dc=example.com
dn: uid=quote\22double,ou=Bad DNs,dc=example.com
cn: Test
objectclass: inetOrgPerson
sn: Test
uid: quote"double
# Entry 16: uid=quote'single,ou=Bad DNs,dc=example.com
dn: uid=quote'single,ou=Bad DNs,dc=example.com
cn: Test
objectclass: inetOrgPerson
sn: Test
uid: quote'single
# Entry 17: uid=sign%percent,ou=Bad DNs,dc=example.com
dn: uid=sign%percent,ou=Bad DNs,dc=example.com
cn: Test
objectclass: inetOrgPerson
sn: Test
uid: sign%percent
# Entry 18: uid=sign\2Bplus,ou=Bad DNs,dc=example.com
dn: uid=sign\2Bplus,ou=Bad DNs,dc=example.com
cn: Test
objectclass: inetOrgPerson
sn: Test
uid: sign+plus
# Entry 19: uid=sign\2Ccomma,ou=Bad DNs,dc=example.com
dn: uid=sign\2Ccomma,ou=Bad DNs,dc=example.com
cn: Test
objectclass: inetOrgPerson
sn: Test
uid: sign,comma
# Entry 20: uid=sign\3Bsemicolon@at,ou=Bad DNs,dc=example.com
dn: uid=sign\3Bsemicolon@at,ou=Bad DNs,dc=example.com
cn: Test
objectclass: inetOrgPerson
sn: Test
uid: sign;semicolon@at
# Entry 21: uid=sign\3Dequal,ou=Bad DNs,dc=example.com
dn: uid=sign\3Dequal,ou=Bad DNs,dc=example.com
cn: Test
objectclass: inetOrgPerson
sn: Test
uid: sign=equal
# Entry 22: uid=sign?question,ou=Bad DNs,dc=example.com
dn: uid=sign?question,ou=Bad DNs,dc=example.com
cn: Test
objectclass: inetOrgPerson
sn: Test
uid: sign?question
# Entry 23: uid=sign@at,ou=Bad DNs,dc=example.com
dn: uid=sign@at,ou=Bad DNs,dc=example.com
cn: Test
objectclass: inetOrgPerson
sn: Test
uid: sign@at

View File

@ -1,107 +0,0 @@
include /etc/openldap/schema/uidpool.schema
include /etc/openldap/schema/sudo.schema
include /etc/openldap/schema/autofs.schema
TLSCACertificateFile /etc/openldap/pla/ca-bundle.crt
TLSCertificateFile /etc/openldap/pla/slapd.crt
TLSCertificateKeyFile /etc/openldap/pla/slapd.key
access to dn.regex="o=Simpsons$" attrs=userpassword
by anonymous auth
by self write
by * none
access to dn.base="" by * read
access to dn.regex="dc=example.com$"
by dn.regex="o=Flintstones$" none
by dn.regex="o=Simpsons$" none
by * write
access to dn.regex="dc=example,dc=com$"
by dn.regex="o=Flintstones$" none
by dn.regex="o=Simpsons$" none
by * write
access to dn.regex="o=Flintstones$"
by dn.regex="o=Simpsons$" none
by self write
by dn.regex="cn=.*,ou=People,o=Flintstones" write
by * read
access to dn.regex="o=Simpsons$"
by dn.regex="o=Flintstones$" none
by self write
by dn.regex="cn=.*,ou=People,o=Simpsons" write
by * read
access to *
by * read
authz-policy any
database ldbm
suffix "dc=example.com"
rootdn "cn=Manager,dc=example.com"
rootpw NotAllowed
directory /var/lib/ldap/base-example.com
dirtyread
cachesize 2000
checkpoint 32 1
# Indices to maintain for this database
index objectClass eq,pres
index ou,cn,mail,surname,givenname eq,pres,sub
index uidNumber,gidNumber,loginShell eq,pres
index uid,memberUid eq,pres,sub
index nisMapName,nisMapEntry eq,pres,sub
database ldbm
suffix "dc=example,dc=com"
rootdn "cn=Manager,dc=example,dc=com"
rootpw NotAllowed
directory /var/lib/ldap/base-example-com
dirtyread
cachesize 2000
checkpoint 32 1
# Indices to maintain for this database
index objectClass eq,pres
index ou,cn,mail,surname,givenname eq,pres,sub
index uidNumber,gidNumber,loginShell eq,pres
index uid,memberUid eq,pres,sub
index nisMapName,nisMapEntry eq,pres,sub
database ldbm
suffix "o=Simpsons"
rootdn "cn=Manager,o=Simpsons"
rootpw NotAllowed
directory /var/lib/ldap/base-simpsons
dirtyread
cachesize 2000
checkpoint 32 1
# Indices to maintain for this database
index objectClass eq,pres
index ou,cn,mail,surname,givenname eq,pres,sub
index uidNumber,gidNumber,loginShell eq,pres
index uid,memberUid eq,pres,sub
index nisMapName,nisMapEntry eq,pres,sub
sasl-regexp uid=(.*),cn=(.*),cn=gssapi,cn=auth
ldap:///dc=example.com??sub?(&(uid=$1)(objectClass=inetOrgPerson))
database bdb
suffix "o=Flintstones"
rootdn "cn=Manager,o=Flintstones"
rootpw NotAllowed
directory /var/lib/ldap/base-flintstones
dirtyread
cachesize 2000
checkpoint 32 1
# Indices to maintain for this database
index objectClass eq,pres
index ou,cn,mail,surname,givenname eq,pres,sub
index uidNumber,gidNumber,loginShell eq,pres
index uid,memberUid eq,pres,sub
index nisMapName,nisMapEntry eq,pres,sub
database monitor
access to * by * read
database config
access to * by * read
rootdn cn=admin,cn=config
rootpw password

0
doc/uidpool.schema Executable file → Normal file
View File

Some files were not shown because too many files have changed in this diff Show More