Toggle navigation
Toggle navigation
This project
Loading...
Sign in
Зуев Егор
/
wiki.dev
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Snippets
Network
Create a new issue
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
Authored by
Dan Brown
2016-01-11 22:41:05 +0000
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
Commit
1c8c9e65c5379ed4b21b8f893f589df183fb5ff0
1c8c9e65
1 parent
14ca3176
Got LDAP auth working to a functional state
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
169 additions
and
39 deletions
app/Http/Controllers/Auth/AuthController.php
app/Http/routes.php
app/Providers/AuthServiceProvider.php
app/Providers/LdapUserProvider.php
app/Repos/UserRepo.php
app/Role.php
app/Services/LdapService.php
config/auth.php
database/migrations/2016_01_11_210908_add_external_auth_to_users.php
resources/views/auth/forms/login/ldap.blade.php
app/Http/Controllers/Auth/AuthController.php
View file @
1c8c9e6
...
...
@@ -2,6 +2,7 @@
namespace
BookStack\Http\Controllers\Auth
;
use
Illuminate\Contracts\Auth\Authenticatable
;
use
Illuminate\Http\Request
;
use
BookStack\Exceptions\SocialSignInException
;
use
BookStack\Exceptions\UserRegistrationException
;
...
...
@@ -31,6 +32,8 @@ class AuthController extends Controller
protected
$redirectPath
=
'/'
;
protected
$redirectAfterLogout
=
'/login'
;
protected
$username
=
'email'
;
protected
$socialAuthService
;
protected
$emailConfirmationService
;
...
...
@@ -48,6 +51,7 @@ class AuthController extends Controller
$this
->
socialAuthService
=
$socialAuthService
;
$this
->
emailConfirmationService
=
$emailConfirmationService
;
$this
->
userRepo
=
$userRepo
;
$this
->
username
=
config
(
'auth.method'
)
===
'standard'
?
'email'
:
'username'
;
parent
::
__construct
();
}
...
...
@@ -104,6 +108,24 @@ class AuthController extends Controller
return
$this
->
registerUser
(
$userData
);
}
/**
* Overrides the action when a user is authenticated.
* If the user authenticated but does not exist in the user table we create them.
* @param Request $request
* @param Authenticatable $user
* @return \Illuminate\Http\RedirectResponse
*/
protected
function
authenticated
(
Request
$request
,
Authenticatable
$user
)
{
if
(
!
$user
->
exists
)
{
$user
->
save
();
$this
->
userRepo
->
attachDefaultRole
(
$user
);
auth
()
->
login
(
$user
);
}
return
redirect
()
->
intended
(
$this
->
redirectPath
());
}
/**
* Register a new user after a registration callback.
* @param $socialDriver
...
...
@@ -232,7 +254,7 @@ class AuthController extends Controller
public
function
getLogin
()
{
$socialDrivers
=
$this
->
socialAuthService
->
getActiveDrivers
();
$authMethod
=
'standard'
;
// TODO - rewrite to use config.
$authMethod
=
config
(
'auth.method'
);
return
view
(
'auth/login'
,
[
'socialDrivers'
=>
$socialDrivers
,
'authMethod'
=>
$authMethod
]);
}
...
...
app/Http/routes.php
View file @
1c8c9e6
...
...
@@ -3,7 +3,7 @@
Route
::
get
(
'/test'
,
function
()
{
// TODO - remove this
$service
=
new
\BookStack\Services\LdapService
();
$service
->
getUserDetails
(
'ssmith'
);
dd
(
$service
->
getUserDetails
(
'ksmith'
)
);
});
// Authenticated routes...
...
...
app/Providers/AuthServiceProvider.php
View file @
1c8c9e6
...
...
@@ -25,7 +25,7 @@ class AuthServiceProvider extends ServiceProvider
public
function
register
()
{
Auth
::
provider
(
'ldap'
,
function
(
$app
,
array
$config
)
{
return
new
LdapUserProvider
(
$config
[
'model'
]);
return
new
LdapUserProvider
(
$config
[
'model'
]
,
$app
[
'BookStack\Services\LdapService'
]
);
});
}
}
...
...
app/Providers/LdapUserProvider.php
View file @
1c8c9e6
...
...
@@ -3,6 +3,8 @@
namespace
BookStack\Providers
;
use
BookStack\Role
;
use
BookStack\Services\LdapService
;
use
BookStack\User
;
use
Illuminate\Contracts\Auth\Authenticatable
;
use
Illuminate\Contracts\Auth\UserProvider
;
...
...
@@ -17,14 +19,21 @@ class LdapUserProvider implements UserProvider
*/
protected
$model
;
/**
* @var LdapService
*/
protected
$ldapService
;
/**
* LdapUserProvider constructor.
* @param $model
* @param LdapService $ldapService
*/
public
function
__construct
(
$model
)
public
function
__construct
(
$model
,
LdapService
$ldapService
)
{
$this
->
model
=
$model
;
$this
->
ldapService
=
$ldapService
;
}
/**
...
...
@@ -34,8 +43,7 @@ class LdapUserProvider implements UserProvider
*/
public
function
createModel
()
{
$class
=
'\\'
.
ltrim
(
$this
->
model
,
'\\'
);
$class
=
'\\'
.
ltrim
(
$this
->
model
,
'\\'
);
return
new
$class
;
}
...
...
@@ -91,16 +99,21 @@ class LdapUserProvider implements UserProvider
*/
public
function
retrieveByCredentials
(
array
$credentials
)
{
// TODO: Implement retrieveByCredentials() method.
// Get user via LDAP
$userDetails
=
$this
->
ldapService
->
getUserDetails
(
$credentials
[
'username'
]);
if
(
$userDetails
===
null
)
return
null
;
// Search current user base by looking up a uid
$model
=
$this
->
createModel
();
$currentUser
=
$model
->
newQuery
()
->
where
(
'external_auth_id'
,
$userDetails
[
'uid'
])
->
first
();
// If not exists create a new user instance with attached role
// but do not store it in the database yet
if
(
$currentUser
!==
null
)
return
$currentUser
;
//
$model
->
name
=
$userDetails
[
'name'
];
$model
->
external_auth_id
=
$userDetails
[
'uid'
];
return
$model
;
}
/**
...
...
@@ -112,6 +125,6 @@ class LdapUserProvider implements UserProvider
*/
public
function
validateCredentials
(
Authenticatable
$user
,
array
$credentials
)
{
// TODO: Implement validateCredentials() method.
return
$this
->
ldapService
->
validateUserCredentials
(
$user
,
$credentials
[
'username'
],
$credentials
[
'password'
]);
}
}
...
...
app/Repos/UserRepo.php
View file @
1c8c9e6
...
...
@@ -3,6 +3,7 @@
use
BookStack\Role
;
use
BookStack\User
;
use
Setting
;
class
UserRepo
{
...
...
@@ -56,7 +57,7 @@ class UserRepo
*/
public
function
attachDefaultRole
(
$user
)
{
$roleId
=
\
Setting
::
get
(
'registration-role'
);
$roleId
=
Setting
::
get
(
'registration-role'
);
if
(
$roleId
===
false
)
$roleId
=
$this
->
role
->
getDefault
()
->
id
;
$user
->
attachRoleId
(
$roleId
);
}
...
...
app/Role.php
View file @
1c8c9e6
...
...
@@ -7,7 +7,7 @@ use Illuminate\Database\Eloquent\Model;
class
Role
extends
Model
{
/**
* Sets the default role name for newly registed users.
* Sets the default role name for newly registe
re
d users.
* @var string
*/
protected
static
$default
=
'viewer'
;
...
...
app/Services/LdapService.php
View file @
1c8c9e6
...
...
@@ -2,56 +2,119 @@
use
BookStack\Exceptions\LdapException
;
use
Illuminate\Contracts\Auth\Authenticatable
;
class
LdapService
{
protected
$ldapConnection
;
/**
* Get the details of a user from LDAP using the given username.
* User found via configurable user filter.
* @param $userName
* @return array|null
* @throws LdapException
*/
public
function
getUserDetails
(
$userName
)
{
$ldapConnection
=
$this
->
getConnection
();
if
(
!
function_exists
(
'ldap_connect'
))
{
throw
new
LdapException
(
'LDAP PHP extension not installed'
);
// Find user
$userFilter
=
$this
->
buildFilter
(
config
(
'services.ldap.user_filter'
),
[
'user'
=>
$userName
]);
$baseDn
=
config
(
'services.ldap.base_dn'
);
$ldapSearch
=
ldap_search
(
$ldapConnection
,
$baseDn
,
$userFilter
,
[
'cn'
,
'uid'
,
'dn'
]);
$users
=
ldap_get_entries
(
$ldapConnection
,
$ldapSearch
);
if
(
$users
[
'count'
]
===
0
)
return
null
;
$user
=
$users
[
0
];
return
[
'uid'
=>
$user
[
'uid'
][
0
],
'name'
=>
$user
[
'cn'
][
0
],
'dn'
=>
$user
[
'dn'
]
];
}
/**
* @param Authenticatable $user
* @param string $username
* @param string $password
* @return bool
* @throws LdapException
*/
public
function
validateUserCredentials
(
Authenticatable
$user
,
$username
,
$password
)
{
$ldapUser
=
$this
->
getUserDetails
(
$username
);
if
(
$ldapUser
===
null
)
return
false
;
if
(
$ldapUser
[
'uid'
]
!==
$user
->
external_auth_id
)
return
false
;
$ldapServer
=
explode
(
':'
,
config
(
'services.ldap.server'
));
$ldapConnection
=
ldap_connect
(
$ldapServer
[
0
],
count
(
$ldapServer
)
>
1
?
$ldapServer
[
1
]
:
389
);
if
(
$ldapConnection
===
false
)
{
throw
new
LdapException
(
'Cannot connect to ldap server, Initial connection failed'
);
$ldapConnection
=
$this
->
getConnection
();
$ldapBind
=
@
ldap_bind
(
$ldapConnection
,
$ldapUser
[
'dn'
],
$password
);
return
$ldapBind
;
}
// Options
ldap_set_option
(
$ldapConnection
,
LDAP_OPT_PROTOCOL_VERSION
,
3
);
// TODO - make configurable
/**
* Bind the system user to the LDAP connection using the given credentials
* otherwise anonymous access is attempted.
* @param $connection
* @throws LdapException
*/
protected
function
bindSystemUser
(
$connection
)
{
$ldapDn
=
config
(
'services.ldap.dn'
);
$ldapPass
=
config
(
'services.ldap.pass'
);
$isAnonymous
=
(
$ldapDn
===
false
||
$ldapPass
===
false
);
if
(
$isAnonymous
)
{
$ldapBind
=
ldap_bind
(
$
ldapC
onnection
);
$ldapBind
=
ldap_bind
(
$
c
onnection
);
}
else
{
$ldapBind
=
ldap_bind
(
$
ldapC
onnection
,
$ldapDn
,
$ldapPass
);
$ldapBind
=
ldap_bind
(
$
c
onnection
,
$ldapDn
,
$ldapPass
);
}
if
(
!
$ldapBind
)
throw
new
LdapException
(
'LDAP access failed using '
.
$isAnonymous
?
' anonymous bind.'
:
' given dn & pass details'
);
}
// Find user
$userFilter
=
$this
->
buildFilter
(
config
(
'services.ldap.user_filter'
),
[
'user'
=>
$userName
]);
//dd($userFilter);
$baseDn
=
config
(
'services.ldap.base_dn'
);
$ldapSearch
=
ldap_search
(
$ldapConnection
,
$baseDn
,
$userFilter
);
$users
=
ldap_get_entries
(
$ldapConnection
,
$ldapSearch
);
/**
* Get the connection to the LDAP server.
* Creates a new connection if one does not exist.
* @return resource
* @throws LdapException
*/
protected
function
getConnection
()
{
if
(
$this
->
ldapConnection
!==
null
)
return
$this
->
ldapConnection
;
dd
(
$users
);
// Check LDAP extension in installed
if
(
!
function_exists
(
'ldap_connect'
))
{
throw
new
LdapException
(
'LDAP PHP extension not installed'
);
}
// Get port from server string if specified.
$ldapServer
=
explode
(
':'
,
config
(
'services.ldap.server'
));
$ldapConnection
=
ldap_connect
(
$ldapServer
[
0
],
count
(
$ldapServer
)
>
1
?
$ldapServer
[
1
]
:
389
);
if
(
$ldapConnection
===
false
)
{
throw
new
LdapException
(
'Cannot connect to ldap server, Initial connection failed'
);
}
// Set any required options
ldap_set_option
(
$ldapConnection
,
LDAP_OPT_PROTOCOL_VERSION
,
3
);
// TODO - make configurable
$this
->
ldapConnection
=
$ldapConnection
;
return
$this
->
ldapConnection
;
}
private
function
buildFilter
(
$filterString
,
$attrs
)
/**
* Build a filter string by injecting common variables.
* @param $filterString
* @param array $attrs
* @return string
*/
protected
function
buildFilter
(
$filterString
,
array
$attrs
)
{
$newAttrs
=
[];
foreach
(
$attrs
as
$key
=>
$attrText
)
{
$newKey
=
'${'
.
$key
.
'}'
;
$newKey
=
'${'
.
$key
.
'}'
;
$newAttrs
[
$newKey
]
=
$attrText
;
}
return
strtr
(
$filterString
,
$newAttrs
);
...
...
config/auth.php
View file @
1c8c9e6
...
...
@@ -70,7 +70,7 @@ return [
'providers'
=>
[
'users'
=>
[
'driver'
=>
env
(
'AUTH_METHOD'
,
'eloquent'
),
'model'
=>
Book
s
tack\User
::
class
,
'model'
=>
Book
S
tack\User
::
class
,
],
// 'users' => [
...
...
database/migrations/2016_01_11_210908_add_external_auth_to_users.php
0 → 100644
View file @
1c8c9e6
<?php
use
Illuminate\Database\Schema\Blueprint
;
use
Illuminate\Database\Migrations\Migration
;
class
AddExternalAuthToUsers
extends
Migration
{
/**
* Run the migrations.
*
* @return void
*/
public
function
up
()
{
Schema
::
table
(
'users'
,
function
(
Blueprint
$table
)
{
$table
->
string
(
'external_auth_id'
)
->
index
();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public
function
down
()
{
Schema
::
table
(
'users'
,
function
(
Blueprint
$table
)
{
$table
->
dropColumn
(
'external_auth_id'
);
});
}
}
resources/views/auth/forms/login/ldap.blade.php
View file @
1c8c9e6
<div
class=
"form-group"
>
<label
for=
"
email
"
>
Username
</label>
@include('form/text', ['name' => '
email
', 'tabindex' => 1])
<label
for=
"
username
"
>
Username
</label>
@include('form/text', ['name' => '
username
', 'tabindex' => 1])
</div>
<div
class=
"form-group"
>
...
...
Please
register
or
sign in
to post a comment