Merge "Security fixes"
This commit is contained in:
commit
661199b43f
44
app/Events/UserEmailUpdated.php
Normal file
44
app/Events/UserEmailUpdated.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php namespace App\Events;
|
||||
/**
|
||||
* Copyright 2020 OpenStack Foundation
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
/**
|
||||
* Class UserEmailUpdated
|
||||
* @package App\Events
|
||||
*/
|
||||
class UserEmailUpdated
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $user_id;
|
||||
|
||||
/**
|
||||
* UserEmailVerified constructor.
|
||||
* @param int $user_id
|
||||
*/
|
||||
public function __construct(int $user_id)
|
||||
{
|
||||
$this->user_id = $user_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getUserId(): int
|
||||
{
|
||||
return $this->user_id;
|
||||
}
|
||||
}
|
@ -11,13 +11,16 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\Auth\IUserService;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Redirect;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Http\Request as LaravelRequest;
|
||||
use models\exceptions\ValidationException;
|
||||
use OAuth2\Repositories\IClientRepository;
|
||||
|
||||
/**
|
||||
* Class ForgotPasswordController
|
||||
* @package App\Http\Controllers\Auth
|
||||
@ -29,24 +32,58 @@ final class ForgotPasswordController extends Controller
|
||||
*/
|
||||
private $user_service;
|
||||
|
||||
/**
|
||||
* @var IClientRepository
|
||||
*/
|
||||
private $client_repository;
|
||||
|
||||
/**
|
||||
* ForgotPasswordController constructor.
|
||||
* @param IClientRepository $client_repository
|
||||
* @param IUserService $user_service
|
||||
*/
|
||||
public function __construct(IUserService $user_service)
|
||||
public function __construct
|
||||
(
|
||||
IClientRepository $client_repository,
|
||||
IUserService $user_service
|
||||
)
|
||||
{
|
||||
$this->middleware('guest');
|
||||
$this->user_service = $user_service;
|
||||
$this->client_repository = $client_repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the form to request a password reset link.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @param LaravelRequest $request
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function showLinkRequestForm()
|
||||
public function showLinkRequestForm(LaravelRequest $request)
|
||||
{
|
||||
return view('auth.passwords.email');
|
||||
try {
|
||||
$params = [
|
||||
"redirect_uri" => '',
|
||||
"client_id" => '',
|
||||
];
|
||||
// check if we have explicit params at query string
|
||||
if ($request->has("redirect_uri") && $request->has("client_id")) {
|
||||
$redirect_uri = $request->get("redirect_uri");
|
||||
$client_id = $request->get("client_id");
|
||||
|
||||
$client = $this->client_repository->getClientById($client_id);
|
||||
if (is_null($client))
|
||||
throw new ValidationException("client does not exists");
|
||||
|
||||
if (!$client->isUriAllowed($redirect_uri))
|
||||
throw new ValidationException(sprintf("redirect_uri %s is not allowed on associated client", $redirect_uri));
|
||||
|
||||
$params['redirect_uri'] = $redirect_uri;
|
||||
$params['client_id'] = $client_id;
|
||||
}
|
||||
return view('auth.passwords.email', $params);
|
||||
} catch (\Exception $ex) {
|
||||
Log::warning($ex);
|
||||
}
|
||||
return view("auth.passwords.email_error");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -63,24 +100,44 @@ final class ForgotPasswordController extends Controller
|
||||
|
||||
if (!$validator->passes()) {
|
||||
return back()
|
||||
->withInput($request->only('email'))
|
||||
->withInput($request->only('email', 'client_id', 'redirect_uri'))
|
||||
->withErrors($validator);
|
||||
}
|
||||
|
||||
$this->user_service->requestPasswordReset($payload);
|
||||
|
||||
return $this->sendResetLinkResponse("Reset link sent");
|
||||
$params = [
|
||||
'client_id' => '',
|
||||
'redirect_uri' => '',
|
||||
];
|
||||
// check redirect uri with associated client
|
||||
if($request->has("redirect_uri") && $request->has("client_id")){
|
||||
$redirect_uri = $request->get("redirect_uri");
|
||||
$client_id = $request->get("client_id");
|
||||
$client = $this->client_repository->getClientById($client_id);
|
||||
|
||||
if(is_null($client))
|
||||
throw new ValidationException("client does not exists");
|
||||
|
||||
if(!$client->isUriAllowed($redirect_uri))
|
||||
throw new ValidationException(sprintf("redirect_uri %s is not allowed on associated client", $redirect_uri));
|
||||
|
||||
$params['client_id'] = $client_id;
|
||||
$params['redirect_uri'] = $redirect_uri;
|
||||
}
|
||||
catch (ValidationException $ex){
|
||||
|
||||
$params['status'] = 'Reset link sent';
|
||||
return back()->with($params);
|
||||
|
||||
} catch (ValidationException $ex) {
|
||||
Log::warning($ex);
|
||||
foreach ($ex->getMessages() as $message) {
|
||||
$validator->getMessageBag()->add('validation', $message);
|
||||
}
|
||||
return back()
|
||||
->withInput($request->only('email'))
|
||||
->withInput($request->only(['email', 'client_id', 'redirect_uri']))
|
||||
->withErrors($validator);
|
||||
}
|
||||
catch(\Exception $ex){
|
||||
} catch (\Exception $ex) {
|
||||
Log::warning($ex);
|
||||
}
|
||||
return view("auth.passwords.email_error");
|
||||
@ -107,20 +164,7 @@ final class ForgotPasswordController extends Controller
|
||||
*/
|
||||
protected function sendResetLinkResponse($response)
|
||||
{
|
||||
return back()->with('status', trans($response));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the response for a failed password reset link.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param string $response
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
|
||||
*/
|
||||
protected function sendResetLinkFailedResponse(LaravelRequest $request, $response)
|
||||
{
|
||||
return back()
|
||||
->withInput($request->only('email'))
|
||||
->withErrors(['email' => trans($response)]);
|
||||
}
|
||||
}
|
@ -93,7 +93,6 @@ final class RegisterController extends Controller
|
||||
|
||||
if ($oauth_auth_request->isValid()) {
|
||||
|
||||
|
||||
$redirect_uri = $oauth_auth_request->getRedirectUri();
|
||||
$client_id = $oauth_auth_request->getClientId();
|
||||
|
||||
@ -189,7 +188,6 @@ final class RegisterController extends Controller
|
||||
'redirect_uri' => '',
|
||||
];
|
||||
|
||||
|
||||
// check if we have a former oauth2 request
|
||||
if ($this->memento_service->exists()) {
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
* limitations under the License.
|
||||
**/
|
||||
use App\Events\OAuth2ClientLocked;
|
||||
use App\Events\UserEmailUpdated;
|
||||
use App\Events\UserLocked;
|
||||
use App\Events\UserPasswordResetRequestCreated;
|
||||
use App\Events\UserPasswordResetSuccessful;
|
||||
@ -78,14 +79,22 @@ final class EventServiceProvider extends ServiceProvider
|
||||
Mail::queue(new WelcomeNewUserEmail($user));
|
||||
if(!$user->isEmailVerified() && !$user->hasCreator())
|
||||
$user_service->sendVerificationEmail($user);
|
||||
});
|
||||
|
||||
Event::listen(UserEmailUpdated::class, function($event)
|
||||
{
|
||||
$repository = App::make(IUserRepository::class);
|
||||
$user = $repository->getById($event->getUserId());
|
||||
if(is_null($user)) return;
|
||||
if(! $user instanceof User) return;
|
||||
$user_service = App::make(IUserService::class);
|
||||
$user_service->sendVerificationEmail($user);
|
||||
});
|
||||
|
||||
Event::listen(UserPasswordResetRequestCreated::class, function($event){
|
||||
$repository = App::make(IUserPasswordResetRequestRepository::class);
|
||||
$request = $repository->find($event->getId());
|
||||
if(is_null($request)) return;
|
||||
|
||||
});
|
||||
|
||||
Event::listen(UserLocked::class, function($event){
|
||||
|
@ -230,11 +230,12 @@ final class UserService extends AbstractService implements IUserService
|
||||
{
|
||||
return $this->tx_service->transaction(function() use($payload) {
|
||||
$user = $this->user_repository->getByEmailOrName(trim($payload['email']));
|
||||
if(is_null($user))
|
||||
throw new EntityNotFoundException("user not found");
|
||||
if(is_null($user) || !$user->isEmailVerified())
|
||||
throw new EntityNotFoundException("User not found.");
|
||||
|
||||
$request = new UserPasswordResetRequest();
|
||||
$request->setOwner($user);
|
||||
|
||||
do{
|
||||
$token = $request->generateToken();
|
||||
$former_request = $this->request_reset_password_repository->getByToken($token);
|
||||
|
@ -11,17 +11,19 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
use App\Events\UserEmailUpdated;
|
||||
use App\libs\Auth\Factories\UserFactory;
|
||||
use App\libs\Auth\Repositories\IGroupRepository;
|
||||
use App\Services\AbstractService;
|
||||
use Auth\IUserNameGeneratorService;
|
||||
use Auth\Repositories\IUserRepository;
|
||||
use Auth\User;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use models\exceptions\EntityNotFoundException;
|
||||
use models\exceptions\ValidationException;
|
||||
use models\utils\IEntity;
|
||||
use OpenId\Services\IUserService;
|
||||
use phpDocumentor\Reflection\Types\Parent_;
|
||||
use Utils\Db\ITransactionService;
|
||||
use Utils\Services\ILogService;
|
||||
use Utils\Services\IServerConfigurationService;
|
||||
@ -225,6 +227,7 @@ final class UserService extends AbstractService implements IUserService
|
||||
if(is_null($user) || !$user instanceof User)
|
||||
throw new EntityNotFoundException("user not found");
|
||||
|
||||
$former_email = $user->getEmail();
|
||||
if(isset($payload["email"])){
|
||||
$former_user = $this->repository->getByEmailOrName(trim($payload["email"]));
|
||||
if(!is_null($former_user) && $former_user->getId() != $id)
|
||||
@ -249,6 +252,12 @@ final class UserService extends AbstractService implements IUserService
|
||||
}
|
||||
}
|
||||
|
||||
if($former_email != $user->getEmail()){
|
||||
Log::debug(sprintf("UserService::update use id %s - email changed old %s - email new %s", $id, $former_email , $user->getEmail()));
|
||||
$user->clearEmailVerification();
|
||||
Event::fire(new UserEmailUpdated($user->getId()));
|
||||
}
|
||||
|
||||
return $user;
|
||||
|
||||
});
|
||||
|
@ -151,6 +151,7 @@ class CustomAuthProvider implements UserProvider
|
||||
$user->setLastLoginDate(new \DateTime('now', new \DateTimeZone('UTC')));
|
||||
$user->setLoginFailedAttempt(0);
|
||||
$user->setActive(true);
|
||||
$user->clearResetPasswordRequests();
|
||||
|
||||
$auth_extensions = $this->auth_extension_service->getExtensions();
|
||||
|
||||
|
@ -45,8 +45,10 @@ final class UserFactory
|
||||
$user->setFirstName(trim($payload['first_name']));
|
||||
if(isset($payload['last_name']))
|
||||
$user->setLastName(trim($payload['last_name']));
|
||||
|
||||
if(isset($payload['email']))
|
||||
$user->setEmail(strtolower(trim($payload['email'])));
|
||||
|
||||
if(isset($payload['second_email']))
|
||||
$user->setSecondEmail(strtolower(trim($payload['second_email'])));
|
||||
if(isset($payload['third_email']))
|
||||
|
@ -11,6 +11,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
use App\Events\UserCreated;
|
||||
use App\Events\UserLocked;
|
||||
use App\libs\Auth\Models\IGroupSlugs;
|
||||
@ -33,6 +34,7 @@ use Illuminate\Auth\Passwords\CanResetPassword as CanResetPasswordTrait;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use App\Models\Utils\BaseEntity;
|
||||
use Doctrine\ORM\Mapping AS ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity(repositoryClass="App\Repositories\DoctrineUserRepository")
|
||||
* @ORM\Table(name="users")
|
||||
@ -557,7 +559,8 @@ class User extends BaseEntity
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isSuperAdmin():bool{
|
||||
public function isSuperAdmin(): bool
|
||||
{
|
||||
return $this->belongToGroup(IGroupSlugs::SuperAdminGroup);
|
||||
}
|
||||
|
||||
@ -565,7 +568,8 @@ class User extends BaseEntity
|
||||
* @param string $slug
|
||||
* @return bool
|
||||
*/
|
||||
public function belongToGroup(string $slug):bool{
|
||||
public function belongToGroup(string $slug): bool
|
||||
{
|
||||
$criteria = new Criteria();
|
||||
$criteria->where(Criteria::expr()->eq('slug', $slug));
|
||||
return $this->groups->matching($criteria)->count() > 0;
|
||||
@ -574,7 +578,8 @@ class User extends BaseEntity
|
||||
/**
|
||||
* @param Group $group
|
||||
*/
|
||||
public function addToGroup(Group $group){
|
||||
public function addToGroup(Group $group)
|
||||
{
|
||||
if ($this->groups->contains($group)) return;
|
||||
$this->groups->add($group);
|
||||
$group->addUser($this);
|
||||
@ -583,13 +588,15 @@ class User extends BaseEntity
|
||||
/**
|
||||
* @param Group $group
|
||||
*/
|
||||
public function removeFromGroup(Group $group){
|
||||
public function removeFromGroup(Group $group)
|
||||
{
|
||||
if (!$this->groups->contains($group)) return;
|
||||
$this->groups->removeElement($group);
|
||||
$group->removeUser($this);
|
||||
}
|
||||
|
||||
public function clearGroups():void{
|
||||
public function clearGroups(): void
|
||||
{
|
||||
$this->groups->clear();
|
||||
}
|
||||
|
||||
@ -622,7 +629,8 @@ class User extends BaseEntity
|
||||
/**
|
||||
* @param OpenIdTrustedSite $site
|
||||
*/
|
||||
public function addTrustedSite(OpenIdTrustedSite $site) {
|
||||
public function addTrustedSite(OpenIdTrustedSite $site)
|
||||
{
|
||||
if ($this->trusted_sites->contains($site)) return;
|
||||
$this->trusted_sites->add($site);
|
||||
$site->setOwner($this);
|
||||
@ -700,8 +708,7 @@ class User extends BaseEntity
|
||||
$active_scope_groups = $this->scope_groups->matching($criteria);
|
||||
|
||||
foreach ($active_scope_groups as $group) {
|
||||
foreach($group->getScopes() as $scope)
|
||||
{
|
||||
foreach ($group->getScopes() as $scope) {
|
||||
if (!isset($map[$scope->getId()]))
|
||||
$scopes[] = $scope;
|
||||
}
|
||||
@ -715,7 +722,8 @@ class User extends BaseEntity
|
||||
* @return bool
|
||||
* @throws ValidationException
|
||||
*/
|
||||
public function isGroupScopeAllowed(ApiScope $scope):bool{
|
||||
public function isGroupScopeAllowed(ApiScope $scope): bool
|
||||
{
|
||||
if (!$scope->isAssignedByGroups()) throw new ValidationException("scope is not assigned by groups!");
|
||||
$criteria = Criteria::create();
|
||||
$criteria->where(Criteria::expr()->eq('active', true));
|
||||
@ -726,6 +734,10 @@ class User extends BaseEntity
|
||||
return false;
|
||||
}
|
||||
|
||||
public function clearEmailVerification(){
|
||||
$this->email_verified = false;
|
||||
$this->email_verified_date = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
@ -735,7 +747,8 @@ class User extends BaseEntity
|
||||
return $this->email_verified;
|
||||
}
|
||||
|
||||
public function clearTrustedSites():void{
|
||||
public function clearTrustedSites(): void
|
||||
{
|
||||
$this->trusted_sites->clear();
|
||||
}
|
||||
|
||||
@ -760,11 +773,13 @@ class User extends BaseEntity
|
||||
/**
|
||||
* Get either a Gravatar URL or complete image tag for a specified email address.
|
||||
*/
|
||||
private function getGravatarUrl( ):string {
|
||||
private function getGravatarUrl(): string
|
||||
{
|
||||
$url = 'https://www.gravatar.com/avatar/';
|
||||
$url .= md5(strtolower(trim($this->email)));
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $password
|
||||
* @return bool
|
||||
@ -1236,7 +1251,8 @@ class User extends BaseEntity
|
||||
/**
|
||||
* @param UserAction $action
|
||||
*/
|
||||
public function addUserAction(UserAction $action){
|
||||
public function addUserAction(UserAction $action)
|
||||
{
|
||||
if ($this->actions->contains($action)) return;
|
||||
$this->actions->add($action);
|
||||
$action->setOwner($this);
|
||||
@ -1304,20 +1320,23 @@ SQL;
|
||||
/**
|
||||
* @param UserConsent $consent
|
||||
*/
|
||||
public function addConsent(UserConsent $consent){
|
||||
public function addConsent(UserConsent $consent)
|
||||
{
|
||||
if ($this->consents->contains($consent)) return;
|
||||
$this->consents->add($consent);
|
||||
$consent->setOwner($this);
|
||||
}
|
||||
|
||||
public function updateLastLoginDate():void{
|
||||
public function updateLastLoginDate(): void
|
||||
{
|
||||
$this->last_login_date = new \DateTime('now', new \DateTimeZone('UTC'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function updateLoginFailedAttempt():int {
|
||||
public function updateLoginFailedAttempt(): int
|
||||
{
|
||||
$this->login_failed_attempt = $this->login_failed_attempt + 1;
|
||||
return $this->login_failed_attempt;
|
||||
}
|
||||
@ -1343,6 +1362,10 @@ SQL;
|
||||
*/
|
||||
public function setEmail(string $email): void
|
||||
{
|
||||
if (!empty($this->email) && $email != $this->email) {
|
||||
//we are setting a new email
|
||||
$this->clearResetPasswordRequests();
|
||||
}
|
||||
$this->email = $email;
|
||||
}
|
||||
|
||||
@ -1365,7 +1388,8 @@ SQL;
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function verifyEmail(){
|
||||
public function verifyEmail()
|
||||
{
|
||||
if (!$this->email_verified) {
|
||||
$this->email_verified = true;
|
||||
$this->active = true;
|
||||
@ -1419,14 +1443,16 @@ SQL;
|
||||
/**
|
||||
* @param string $identifier
|
||||
*/
|
||||
public function setIdentifier(string $identifier){
|
||||
public function setIdentifier(string $identifier)
|
||||
{
|
||||
$this->identifier = $identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ORM\PostPersist
|
||||
*/
|
||||
public function inserted($args){
|
||||
public function inserted($args)
|
||||
{
|
||||
Event::fire(new UserCreated($this->getId(), $args));
|
||||
}
|
||||
|
||||
@ -1434,7 +1460,8 @@ SQL;
|
||||
* @param $name
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($name) {
|
||||
public function __get($name)
|
||||
{
|
||||
if ($name == "fullname")
|
||||
return $this->getFullName();
|
||||
|
||||
@ -1464,7 +1491,8 @@ SQL;
|
||||
/**
|
||||
* @param UserPasswordResetRequest $request
|
||||
*/
|
||||
public function addPasswordResetRequest(UserPasswordResetRequest $request){
|
||||
public function addPasswordResetRequest(UserPasswordResetRequest $request)
|
||||
{
|
||||
if ($this->reset_password_requests->contains($request)) return;
|
||||
$this->reset_password_requests->add($request);
|
||||
}
|
||||
@ -1488,14 +1516,16 @@ SQL;
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function hasCreator():bool{
|
||||
public function hasCreator(): bool
|
||||
{
|
||||
return $this->getCreatedById() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getCreatedById():int{
|
||||
public function getCreatedById(): int
|
||||
{
|
||||
try {
|
||||
return !is_null($this->created_by) ? $this->created_by->getId() : 0;
|
||||
} catch (\Exception $ex) {
|
||||
@ -1519,4 +1549,9 @@ SQL;
|
||||
$this->twitter_name = $twitter_name;
|
||||
}
|
||||
|
||||
public function clearResetPasswordRequests(): void
|
||||
{
|
||||
$this->reset_password_requests->clear();
|
||||
}
|
||||
|
||||
}
|
@ -26,6 +26,15 @@
|
||||
return true;
|
||||
});
|
||||
|
||||
$(document).ready(function($){
|
||||
|
||||
var redirect = $('#redirect_url');
|
||||
if(redirect.length > 0){
|
||||
var href = $(redirect).attr('href');
|
||||
setTimeout(function(){ window.location = href; }, 3000);
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
// End of closure.
|
||||
|
@ -20,6 +20,9 @@
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
{{ session('status') }}
|
||||
</div>
|
||||
@if($redirect_uri)
|
||||
<p>Now you will be redirected to <a id="redirect_url" name="redirect_url" href="{{$redirect_uri}}">{{$redirect_uri}}</a></p>
|
||||
@endif
|
||||
@endif
|
||||
@if ($errors->any())
|
||||
<div class="alert alert-danger alert-dismissible" role="alert">
|
||||
@ -48,6 +51,12 @@
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary btn-lg btn-block">{{ __('Send Password Reset Link') }}</button>
|
||||
</div>
|
||||
@if($redirect_uri)
|
||||
<input type="hidden" id="redirect_uri" name="redirect_uri" value="{{$redirect_uri}}"/>
|
||||
@endif
|
||||
@if($client_id)
|
||||
<input type="hidden" id="client_id" name="client_id" value="{{$client_id}}"/>
|
||||
@endif
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user