app ldap connect
This commit is contained in:
parent
c6cce8700e
commit
41e11123da
4
.env
4
.env
|
@ -31,7 +31,7 @@ LDAP_USERNAME=uid # Attribut id d'un user
|
|||
LDAP_FIRSTNAME=givenname # Attribut firstname d'un user
|
||||
LDAP_LASTNAME=sn # Attribut lastname d'un user
|
||||
LDAP_EMAIL=mail # Attribut email d'un user
|
||||
LDAP_AVATAR=jpegPhoto # Attribut avatar d'un user
|
||||
LDAP_AVATAR=jpegphoto # Attribut avatar d'un user
|
||||
LDAP_MEMBEROF=memberof # Attribut memberof d'un user
|
||||
LDAP_GROUPGID=gidnumber # Attribut gid d'un groupe
|
||||
LDAP_GROUPNAME=cn # Attribut name d'un groupe
|
||||
|
@ -67,7 +67,7 @@ OAUTH_USERNAME=username
|
|||
OAUTH_EMAIL=email
|
||||
OAUTH_LASTNAME=lastname
|
||||
OAUTH_FIRSTNAME=firstname
|
||||
OAUTH_AVATAR=
|
||||
OAUTH_AVATAR=avatar
|
||||
OAUTH_AUTOSUBMIT=1 # if APP_AUTH = OPENID autocréer les users non existant
|
||||
OAUTH_AUTOUPDATE=1 # if APP_AUTH = OPENID automodifier les users existant
|
||||
|
||||
|
|
3
Makefile
3
Makefile
|
@ -17,6 +17,9 @@ dockercomposeup:
|
|||
dockercomposedown:
|
||||
docker-compose stop
|
||||
|
||||
dockercomposeinit:
|
||||
docker-compose exec app bin/console d:f:l
|
||||
|
||||
dockercomposesh:
|
||||
docker-compose exec app /bin/sh
|
||||
|
||||
|
|
15
README.md
15
README.md
|
@ -10,11 +10,22 @@ Up
|
|||
make dockercomposeup
|
||||
```
|
||||
|
||||
Stop
|
||||
Init
|
||||
```
|
||||
make dockercomposestop
|
||||
make dockercomposeinit
|
||||
```
|
||||
|
||||
Down
|
||||
```
|
||||
make dockercomposedown
|
||||
```
|
||||
|
||||
Sh
|
||||
```
|
||||
make dockercomposesh
|
||||
```
|
||||
|
||||
|
||||
# KUBERNETES
|
||||
|
||||
Suppression Cluster
|
||||
|
|
|
@ -100,6 +100,7 @@
|
|||
}
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/doctrine-fixtures-bundle": "^3.4",
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"symfony/browser-kit": "6.3.*",
|
||||
"symfony/css-selector": "6.3.*",
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "6d4e45e1137c02bf343b5855dbbc822c",
|
||||
"content-hash": "d59ce92ced50b5b5ee85302929f17c01",
|
||||
"packages": [
|
||||
{
|
||||
"name": "brick/math",
|
||||
|
@ -7633,6 +7633,171 @@
|
|||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "doctrine/data-fixtures",
|
||||
"version": "1.6.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/data-fixtures.git",
|
||||
"reference": "4af35dadbfcf4b00abb2a217c4c8c8800cf5fcf4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/data-fixtures/zipball/4af35dadbfcf4b00abb2a217c4c8c8800cf5fcf4",
|
||||
"reference": "4af35dadbfcf4b00abb2a217c4c8c8800cf5fcf4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/deprecations": "^0.5.3 || ^1.0",
|
||||
"doctrine/persistence": "^1.3.3 || ^2.0 || ^3.0",
|
||||
"php": "^7.2 || ^8.0"
|
||||
},
|
||||
"conflict": {
|
||||
"doctrine/dbal": "<2.13",
|
||||
"doctrine/orm": "<2.12",
|
||||
"doctrine/phpcr-odm": "<1.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^11.0",
|
||||
"doctrine/dbal": "^2.13 || ^3.0",
|
||||
"doctrine/mongodb-odm": "^1.3.0 || ^2.0.0",
|
||||
"doctrine/orm": "^2.12",
|
||||
"ext-sqlite3": "*",
|
||||
"phpstan/phpstan": "^1.5",
|
||||
"phpunit/phpunit": "^8.5 || ^9.5 || ^10.0",
|
||||
"symfony/cache": "^5.0 || ^6.0",
|
||||
"vimeo/psalm": "^4.10 || ^5.9"
|
||||
},
|
||||
"suggest": {
|
||||
"alcaeus/mongo-php-adapter": "For using MongoDB ODM 1.3 with PHP 7 (deprecated)",
|
||||
"doctrine/mongodb-odm": "For loading MongoDB ODM fixtures",
|
||||
"doctrine/orm": "For loading ORM fixtures",
|
||||
"doctrine/phpcr-odm": "For loading PHPCR ODM fixtures"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Common\\DataFixtures\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jonathan Wage",
|
||||
"email": "jonwage@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Data Fixtures for all Doctrine Object Managers",
|
||||
"homepage": "https://www.doctrine-project.org",
|
||||
"keywords": [
|
||||
"database"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/data-fixtures/issues",
|
||||
"source": "https://github.com/doctrine/data-fixtures/tree/1.6.6"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://www.doctrine-project.org/sponsorship.html",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://www.patreon.com/phpdoctrine",
|
||||
"type": "patreon"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdata-fixtures",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-04-20T13:08:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/doctrine-fixtures-bundle",
|
||||
"version": "3.4.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/DoctrineFixturesBundle.git",
|
||||
"reference": "9ec3139c52a42e94c9fd1e95f8d2bca94326edfb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/DoctrineFixturesBundle/zipball/9ec3139c52a42e94c9fd1e95f8d2bca94326edfb",
|
||||
"reference": "9ec3139c52a42e94c9fd1e95f8d2bca94326edfb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/data-fixtures": "^1.3",
|
||||
"doctrine/doctrine-bundle": "^1.11|^2.0",
|
||||
"doctrine/orm": "^2.6.0",
|
||||
"doctrine/persistence": "^1.3.7|^2.0|^3.0",
|
||||
"php": "^7.1 || ^8.0",
|
||||
"symfony/config": "^3.4|^4.3|^5.0|^6.0",
|
||||
"symfony/console": "^3.4|^4.3|^5.0|^6.0",
|
||||
"symfony/dependency-injection": "^3.4.47|^4.3|^5.0|^6.0",
|
||||
"symfony/doctrine-bridge": "^3.4|^4.1|^5.0|^6.0",
|
||||
"symfony/http-kernel": "^3.4|^4.3|^5.0|^6.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^9",
|
||||
"phpstan/phpstan": "^1.4.10",
|
||||
"phpunit/phpunit": "^7.5.20 || ^8.5.26 || ^9.5.20",
|
||||
"symfony/phpunit-bridge": "^6.0.8",
|
||||
"vimeo/psalm": "^4.22"
|
||||
},
|
||||
"type": "symfony-bundle",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Bundle\\FixturesBundle\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Doctrine Project",
|
||||
"homepage": "https://www.doctrine-project.org"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony DoctrineFixturesBundle",
|
||||
"homepage": "https://www.doctrine-project.org",
|
||||
"keywords": [
|
||||
"Fixture",
|
||||
"persistence"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/DoctrineFixturesBundle/issues",
|
||||
"source": "https://github.com/doctrine/DoctrineFixturesBundle/tree/3.4.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://www.doctrine-project.org/sponsorship.html",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://www.patreon.com/phpdoctrine",
|
||||
"type": "patreon"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdoctrine-fixtures-bundle",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-05-02T15:12:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "masterminds/html5",
|
||||
"version": "2.8.0",
|
||||
|
|
|
@ -11,4 +11,5 @@ return [
|
|||
Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
|
||||
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
|
||||
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
|
||||
Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true],
|
||||
];
|
||||
|
|
|
@ -5,7 +5,7 @@ services:
|
|||
redis-master:
|
||||
image: redis:6-alpine
|
||||
volumes:
|
||||
- "./.data:/data"
|
||||
- "./.data:/data:rw"
|
||||
ports:
|
||||
- "6379:6379"
|
||||
|
||||
|
@ -15,7 +15,7 @@ services:
|
|||
links:
|
||||
- redis-master
|
||||
volumes:
|
||||
- "./.data:/data"
|
||||
- "./.data:/data:rw"
|
||||
|
||||
redis-sentinel:
|
||||
build:
|
||||
|
@ -62,7 +62,7 @@ services:
|
|||
- ./.env:/app/.env:delegated
|
||||
environment:
|
||||
PHP_FPM_MEMORY_LIMIT: 128m
|
||||
APP_ENV: PROD
|
||||
APP_ENV: dev
|
||||
|
||||
# Service hydra
|
||||
hydra:
|
||||
|
@ -82,8 +82,8 @@ services:
|
|||
LOG_LEAK_SENSITIVE_VALUES: "true"
|
||||
HYDRA_URLS_SELF_ISSUER: http://127.0.0.1:7080
|
||||
HYDRA_URLS_CONSENT: http://127.0.0.1:8080/hydra/consent
|
||||
HYDRA_URLS_LOGIN: http://127.0.0.1:8080/hydra/loginsql
|
||||
HYDRA_URLS_LOGOUT: http://127.0.0.1:8080/hydra/logoutsql
|
||||
HYDRA_URLS_LOGIN: http://127.0.0.1:8080/hydra/loginldap
|
||||
HYDRA_URLS_LOGOUT: http://127.0.0.1:8080/hydra/logoutldap
|
||||
HYDRA_URLS_ERROR: https://127.0.0.1:8080
|
||||
HYDRA_DSN: postgres://symfony:changeme@postgres:5432/hydra
|
||||
HYDRA_ALLOW_INSECURE: "yes"
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 936 B |
|
@ -102,13 +102,13 @@ class HydraController extends AbstractController
|
|||
|
||||
// S'il n'y a pas de challenge, on déclenche une bad request
|
||||
if (!$challenge) {
|
||||
return $this->redirect('app_login');
|
||||
return $this->redirectToRoute('app_login');
|
||||
}
|
||||
|
||||
// On vérifie que la requête d'identification provient bien de hydra
|
||||
$response = $this->apiservice->run('GET', $this->getParameter('hydraLoginchallenge').$challenge, null);
|
||||
if (!$response) {
|
||||
return $this->redirect('app_login');
|
||||
return $this->redirectToRoute('app_login');
|
||||
}
|
||||
|
||||
// si le challenge est validé par hydra, on le stocke en session pour l'utiliser par la suite et on redirige vers une route interne protégée qui va déclencher l'identification FranceConnect
|
||||
|
@ -148,6 +148,7 @@ class HydraController extends AbstractController
|
|||
$email = "$username@nomail.fr";
|
||||
$lastname = $username;
|
||||
$firstname = ' ';
|
||||
$firstname = 'noavatar.png';
|
||||
|
||||
// Rechercher l'utilisateur
|
||||
if (isset($userldap[$this->getParameter('ldapFirstname')])) {
|
||||
|
@ -162,9 +163,13 @@ class HydraController extends AbstractController
|
|||
$email = $userldap[$this->getParameter('ldapEmail')];
|
||||
}
|
||||
|
||||
if (isset($userldap[$this->getParameter('ldapAvatar')])) {
|
||||
$avatar = $userldap[$this->getParameter('ldapAvatar')];
|
||||
}
|
||||
|
||||
$response = $this->apiservice->run('PUT', $this->getParameter('hydraLoginchallengeaccept').$request->getSession()->get('hydraChallenge'), ['subject' => $email, 'acr' => 'string']);
|
||||
if (!$response || '200' != $response->code) {
|
||||
return $this->redirect('app_login');
|
||||
return $this->redirectToRoute('app_login');
|
||||
}
|
||||
|
||||
$datas = [
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
<?php
|
||||
|
||||
namespace App\DataFixtures;
|
||||
|
||||
use App\Service\LdapService;
|
||||
use App\Entity\User;
|
||||
use Doctrine\Bundle\FixturesBundle\Fixture;
|
||||
use Doctrine\Persistence\ObjectManager;
|
||||
use LasseRafn\InitialAvatarGenerator\InitialAvatar;
|
||||
use Symfony\Bundle\FrameworkBundle\Console\Application;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Output\BufferedOutput;
|
||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
|
||||
class AppFixtures extends Fixture
|
||||
{
|
||||
private $kernel;
|
||||
private $output;
|
||||
private $minio;
|
||||
private $colorbg;
|
||||
private $colorft;
|
||||
private $ldap;
|
||||
private $manager;
|
||||
|
||||
public function __construct(KernelInterface $kernel, LdapService $ldapservice)
|
||||
{
|
||||
$this->kernel = $kernel;
|
||||
$this->ldap = $ldapservice;
|
||||
$this->output = new ConsoleOutput();
|
||||
}
|
||||
|
||||
public function load(ObjectManager $manager): void
|
||||
{
|
||||
$this->manager = $manager;
|
||||
|
||||
// Reset autoincrement
|
||||
|
||||
// app:Init
|
||||
$this->writeln('app:Init');
|
||||
$application = new Application($this->kernel);
|
||||
$application->setAutoExit(false);
|
||||
$input = new ArrayInput(['command' => 'app:Init']);
|
||||
$boutput = new BufferedOutput();
|
||||
$application->run($input, $boutput);
|
||||
$manager->flush();
|
||||
|
||||
$this->writeln('LDAP');
|
||||
$baseorganisation = $this->ldap->getParameter('basedn');
|
||||
|
||||
// Purge de la strucutre annuaire
|
||||
$this->ldap->deleteByDN('ou=crous01,'.$baseorganisation, true);
|
||||
$this->ldap->deleteByDN('ou=crous02,'.$baseorganisation, true);
|
||||
|
||||
// Création de la structure
|
||||
$this->ldap->addOrganisation('ou=crous01,'.$baseorganisation);
|
||||
$this->ldap->addOrganisation('ou=users,ou=crous01,'.$baseorganisation);
|
||||
$this->ldap->addOrganisation('ou=crous02,'.$baseorganisation);
|
||||
$this->ldap->addOrganisation('ou=users,ou=crous02,'.$baseorganisation);
|
||||
|
||||
// Création user
|
||||
$this->submitUser('admin','NUO SSO','Administrateur','uid=admin,ou=users,ou=crous01,'.$baseorganisation);
|
||||
$this->submitUser('user001','001','User','uid=user001,ou=users,ou=crous01,'.$baseorganisation);
|
||||
$this->submitUser('user002','002','User','uid=user002,ou=users,ou=crous02,'.$baseorganisation);
|
||||
}
|
||||
|
||||
|
||||
private function submituser($username,$firstname,$lastname,$dn)
|
||||
{
|
||||
$user = new User();
|
||||
$user->setUsername($username);
|
||||
$user->setPassword($username);
|
||||
$user->setRoles(['ROLE_USER']);
|
||||
$user->setFirstname($firstname);
|
||||
$user->setLastname($lastname);
|
||||
$user->setEmail($username.'@noreply.fr');
|
||||
|
||||
$this->ldap->fixtureUser($user,$dn);
|
||||
|
||||
}
|
||||
|
||||
private function writeln($string)
|
||||
{
|
||||
$this->output->writeln(' <fg=yellow>></> <info>'.$string.'</info>');
|
||||
}
|
||||
|
||||
private function csv_to_array($csv, $delimiter = ';', $enclosure = '', $escape = '\\', $terminator = "\n")
|
||||
{
|
||||
$r = [];
|
||||
$rows = explode($terminator, trim($csv));
|
||||
|
||||
$names = array_shift($rows);
|
||||
$names = str_getcsv($names, $delimiter, $enclosure, $escape);
|
||||
$nc = count($names);
|
||||
foreach ($rows as $row) {
|
||||
if (trim($row)) {
|
||||
$values = str_getcsv($row, $delimiter, $enclosure, $escape);
|
||||
if (!$values) {
|
||||
$values = array_fill(0, $nc, null);
|
||||
}
|
||||
@$r[] = array_combine($names, $values);
|
||||
}
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
}
|
|
@ -347,6 +347,28 @@ class LdapService
|
|||
// == Function User==================================================================================================================================================
|
||||
// ==================================================================================================================================================================
|
||||
|
||||
public function fixtureUser(User $user,$dn)
|
||||
{
|
||||
$connection = $this->connect();
|
||||
|
||||
$attrs = [];
|
||||
$attrs['objectclass'] = $this->getObjectClassesUser();
|
||||
$this->fillAttributesUser($user, $attrs);
|
||||
|
||||
foreach ($attrs as $key => $value) {
|
||||
if (empty($value)) {
|
||||
unset($attrs[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$result = ldap_add($connection, $dn, $attrs);
|
||||
if (!$result) {
|
||||
$this->ldapError();
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function addUser(User $user)
|
||||
{
|
||||
$connection = $this->connect();
|
||||
|
@ -643,8 +665,6 @@ class LdapService
|
|||
$attrs['sn'] = $user->getLastname();
|
||||
$attrs['mail'] = $user->getEmail();
|
||||
$attrs['displayname'] = $user->getFirstname().' '.$user->getLastname();
|
||||
$attrs['telephonenumber'] = $user->getTelephonenumber();
|
||||
$attrs['postaladdress'] = $user->getPostaladress();
|
||||
$attrs['userpassword'] = $user->getPassword();
|
||||
}
|
||||
|
||||
|
|
12
symfony.lock
12
symfony.lock
|
@ -22,6 +22,18 @@
|
|||
"src/Repository/.gitignore"
|
||||
]
|
||||
},
|
||||
"doctrine/doctrine-fixtures-bundle": {
|
||||
"version": "3.4",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "3.0",
|
||||
"ref": "1f5514cfa15b947298df4d771e694e578d4c204d"
|
||||
},
|
||||
"files": [
|
||||
"src/DataFixtures/AppFixtures.php"
|
||||
]
|
||||
},
|
||||
"doctrine/doctrine-migrations-bundle": {
|
||||
"version": "3.2",
|
||||
"recipe": {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-6 h-6" style="width:25px; padding-right:5px">
|
||||
<path fill-rule="evenodd" d="M7.5 3.75A1.5 1.5 0 006 5.25v13.5a1.5 1.5 0 001.5 1.5h6a1.5 1.5 0 001.5-1.5V15a.75.75 0 011.5 0v3.75a3 3 0 01-3 3h-6a3 3 0 01-3-3V5.25a3 3 0 013-3h6a3 3 0 013 3V9A.75.75 0 0115 9V5.25a1.5 1.5 0 00-1.5-1.5h-6zm10.72 4.72a.75.75 0 011.06 0l3 3a.75.75 0 010 1.06l-3 3a.75.75 0 11-1.06-1.06l1.72-1.72H9a.75.75 0 010-1.5h10.94l-1.72-1.72a.75.75 0 010-1.06z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
|
||||
Login
|
||||
</a>
|
||||
{% endif %}
|
||||
|
@ -22,13 +23,18 @@
|
|||
|
||||
{% if app.user %}
|
||||
<div class="card mt-5" style="max-width:600px; margin:auto;">
|
||||
<div class="card-body">
|
||||
<b>Avatar</b> = {{ app.user.avatar }}<br>
|
||||
<div class="card-body d-flex">
|
||||
<div>
|
||||
<img src="{{ asset('images/' ~ app.user.avatar)}}" style="height:100px; background-color: #212529"/>
|
||||
</div>
|
||||
|
||||
<div class="ps-3">
|
||||
<b>login</b> = {{ app.user.username }}<br>
|
||||
<b>firstname</b> = {{ app.user.firstname }}<br>
|
||||
<b>lastname</b> = {{ app.user.lastname }}<br>
|
||||
<b>email</b> = {{ app.user.email }}<br>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
|
@ -30,8 +30,6 @@
|
|||
|
||||
{% block localscript %}
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$("#login_username").focus();
|
||||
});
|
||||
document.getElementById("login_username").focus();
|
||||
</script>
|
||||
{% endblock %}
|
Loading…
Reference in New Issue